贝塞尔曲线学习

1.贝塞尔曲线

以下公式中:

B(t)为t时间下 点的坐标;

P0为起点,Pn为终点,Pi为控制点

一阶贝塞尔曲线(线段):

一阶贝塞尔曲线公式

一阶贝塞尔曲线演示

意义:由 P0 至 P1 的连续点, 描述的一条线段

二阶贝塞尔曲线(抛物线):

二阶贝塞尔曲线公式

二阶贝塞尔曲线演示

原理:由 P0 至 P1 的连续点 Q0,描述一条线段。

由 P1 至 P2 的连续点 Q1,描述一条线段。 由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。 经验:P1-P0为曲线在P0处的切线。

三阶贝塞尔曲线:

三阶贝塞尔曲线公式

三阶贝塞尔曲线演示

通用公式:

通用贝塞尔曲线公式

高阶贝塞尔曲线:

4阶曲线:

四阶贝塞尔曲线演示

5阶曲线:

五阶贝塞尔曲线演示

1.1.生成贝塞尔曲线-迭代法

下面我们用代码来生成贝塞尔曲线,来展示如何贝塞尔曲线的生成原理:

package com.che.chechengwang.support.view.bezier;

import android.animation.FloatEvaluator;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PointF;

import android.util.AttributeSet;

import android.view.View;

import android.view.animation.LinearInterpolator;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Random;

/**

* 生成贝塞尔曲线-迭代法

*

* 作者:余天然 on 16/6/14 下午2:10

*/

public class BezierGenerater1 extends View {

private Paint paint;

private int centerX, centerY;

private List points;

private FloatEvaluator evaluator;

private float fraction;

private Map colors;

private List destPoints;

public BezierGenerater1(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

evaluator = new FloatEvaluator();

startAnim();

}

//初始化数据点和控制点的位置

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

centerX = w / 2;

centerY = h / 2;

points = new ArrayList<>();

points.add(new PointF(centerX - 150, centerY));

points.add(new PointF(centerX - 50, centerY - 300));

points.add(new PointF(centerX + 50, centerY + 300));

points.add(new PointF(centerX + 150, centerY));

colors = new HashMap<>();

for (int i = 0; i < points.size(); i++) {

colors.put(i, getRanColor());

}

destPoints = new ArrayList<>();

destPoints.add(points.get(0));

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//静态的

drawPoint(canvas, points, Color.BLACK);

drawLine(canvas, points, Color.GRAY);

//动态的

List subData = getSubData(points, fraction);

drawData(canvas, subData, fraction);

}

// 绘制数据点

private void drawPoint(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(20);

for (int i = 0; i < data.size(); i++) {

PointF pointF = data.get(i);

canvas.drawPoint(pointF.x, pointF.y, paint);

}

}

//绘制基准线

private void drawLine(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(4);

for (int i = 0; i < data.size() - 1; i++) {

PointF start = data.get(i);

PointF end = data.get(i + 1);

canvas.drawLine(start.x, start.y, end.x, end.y, paint);

}

}

//绘制路径

private void drawPath(Canvas canvas, List data) {

Path path = new Path();

PointF start = data.get(0);

path.moveTo(start.x, start.y);

for (int i = 1; i < data.size() - 1; i++) {

PointF point = data.get(i);

path.lineTo(point.x, point.y);

}

paint.setColor(Color.RED);

paint.setStrokeWidth(4);

canvas.drawPath(path, paint);

}

//迭代绘制集合

private void drawData(Canvas canvas, List data, float fraction) {

if (data.size() == 1) {

drawPoint(canvas, data, Color.BLACK);

destPoints.add(data.get(0));

drawPath(canvas, destPoints);

} else {

drawLine(canvas, data, colors.get(data.size() - 1));

//迭代

List subData = getSubData(data, fraction);

drawData(canvas, subData, fraction);

}

}

private void startAnim() {

ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

animator.setInterpolator(new LinearInterpolator());

animator.setDuration(5000);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

fraction = animation.getAnimatedFraction();

invalidate();

}

});

animator.start();

}

//生成随机颜色

private int getRanColor() {

return 0xff000000 | new Random().nextInt(0x00ffffff);

}

//获取子数据源

private List getSubData(List data, float fraction) {

List subData = new ArrayList<>();

for (int i = 0; i < data.size() - 1; i++) {

PointF start = data.get(i);

PointF end = data.get(i + 1);

float x = evaluator.evaluate(fraction, start.x, end.x);

float y = evaluator.evaluate(fraction, start.y, end.y);

subData.add(new PointF(x, y));

}

return subData;

}

}

1.2.生成贝塞尔曲线-De Casteljau算法

package com.che.chechengwang.support.view.bezier;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PointF;

import android.util.AttributeSet;

import android.view.View;

import android.view.animation.LinearInterpolator;

import java.util.ArrayList;

import java.util.List;

/**

* 生成贝塞尔曲线-De Casteljau算法

*

* 作者:余天然 on 16/6/14 下午2:10

*/

public class BezierGenerater2 extends View {

private Paint paint;

private int centerX, centerY;

private List points;

private float fraction;

private List destPoints;

public BezierGenerater2(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

}

//初始化数据点和控制点的位置

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

centerX = w / 2;

centerY = h / 2;

points = new ArrayList<>();

points.add(new PointF(centerX - 150, centerY));

points.add(new PointF(centerX - 50, centerY - 300));

points.add(new PointF(centerX + 50, centerY + 300));

points.add(new PointF(centerX + 150, centerY));

destPoints = new ArrayList<>();

destPoints.add(points.get(0));

startAnim();

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//静态的

drawPoint(canvas, points, Color.BLACK);

drawLine(canvas, points, Color.GRAY);

//动态的

drawPath(canvas, destPoints);

}

// 绘制数据点

private void drawPoint(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(20);

for (int i = 0; i < data.size(); i++) {

PointF pointF = data.get(i);

canvas.drawPoint(pointF.x, pointF.y, paint);

}

}

//绘制基准线

private void drawLine(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(4);

for (int i = 0; i < data.size() - 1; i++) {

PointF start = data.get(i);

PointF end = data.get(i + 1);

canvas.drawLine(start.x, start.y, end.x, end.y, paint);

}

}

//绘制路径

private void drawPath(Canvas canvas, List data) {

Path path = new Path();

PointF start = data.get(0);

path.moveTo(start.x, start.y);

for (int i = 1; i < data.size() - 1; i++) {

PointF point = data.get(i);

path.lineTo(point.x, point.y);

}

paint.setColor(Color.RED);

paint.setStrokeWidth(4);

canvas.drawPath(path, paint);

}

private void startAnim() {

ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

animator.setInterpolator(new LinearInterpolator());

animator.setDuration(5000);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

fraction = animation.getAnimatedFraction();

PointF pointF = deCasteljau(fraction, points);

destPoints.add(pointF);

invalidate();

}

});

animator.start();

}

//深复制

private List copyData(List points) {

List data = new ArrayList<>();

for (int i = 0; i < points.size(); i++) {

PointF point = points.get(i);

data.add(new PointF(point.x, point.y));

}

return data;

}

//De Casteljau算法

public PointF deCasteljau(float fraction, List points) {

List data = copyData(points);

final int n = data.size();

for (int i = 1; i <= n; i++) {

for (int j = 0; j < n - i; j++) {

data.get(j).x = (1 - fraction) * data.get(j).x + fraction * data.get(j + 1).x;

data.get(j).y = (1 - fraction) * data.get(j).y + fraction * data.get(j + 1).y;

}

}

return data.get(0);

}

}

1.3.二阶贝塞尔曲线

package com.che.chechengwang.support.view.bezier;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PointF;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

/**

* 二阶贝塞尔曲线

*

* 两个数据点和一个控制点

* 公式:B(t) = (1 - t)^2 * P0 + 2t * (1 - t) * P1 + t^2 * P2, t ∈ [0,1]

* 作者:余天然 on 16/6/14 上午10:27

*/

public class Bezier2 extends View {

private Paint paint;

private int centerX, centerY;

private PointF start, end, control;

public Bezier2(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

start = new PointF(0, 0);

end = new PointF(0, 0);

control = new PointF(0, 0);

}

//初始化数据点和控制点的位置

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

centerX = w / 2;

centerY = h / 2;

start.x = centerX - 200;

start.y = centerY;

end.x = centerX + 200;

end.y = centerY;

control.x = centerX;

control.y = centerY - 100;

}

//根据触摸位置更新控制点,并提示重绘

@Override

public boolean onTouchEvent(MotionEvent event) {

control.x = event.getX();

control.y = event.getY();

invalidate();

return true;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

drawPoint(canvas);

drawGuideLine(canvas);

drawBezierCurve(canvas);

}

// 绘制数据点和控制点

private void drawPoint(Canvas canvas) {

paint.setColor(Color.GRAY);

paint.setStrokeWidth(20);

canvas.drawPoint(start.x, start.y, paint);

canvas.drawPoint(end.x, end.y, paint);

canvas.drawPoint(control.x, control.y, paint);

}

//绘制辅助线

private void drawGuideLine(Canvas canvas) {

paint.setStrokeWidth(4);

canvas.drawLine(start.x, start.y, control.x, control.y, paint);

canvas.drawLine(control.x, control.y, end.x, end.y, paint);

}

//绘制贝塞尔曲线

private void drawBezierCurve(Canvas canvas) {

paint.setColor(Color.RED);

paint.setStrokeWidth(4);

Path path = new Path();

path.moveTo(start.x, start.y);

path.quadTo(control.x, control.y, end.x, end.y);

canvas.drawPath(path, paint);

}

}

1.4.三阶贝塞尔曲线

package com.che.chechengwang.support.view.bezier;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PointF;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import java.util.ArrayList;

import java.util.List;

/**

* 三阶贝塞尔曲线

*

* 2个数据点和2个控制点

* 公式:B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3 代

* 作者:余天然 on 16/6/14 上午10:27

*/

public class Bezier3 extends View {

private Paint paint;

private int centerX, centerY;

private List points;

public Bezier3(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.STROKE);

}

//初始化数据点和控制点的位置

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

centerX = w / 2;

centerY = h / 2;

points = new ArrayList<>();

points.add(new PointF(centerX - 150, centerY));

points.add(new PointF(centerX - 50, centerY - 300));

points.add(new PointF(centerX + 50, centerY + 300));

points.add(new PointF(centerX + 150, centerY));

}

//根据触摸位置更新控制点,并提示重绘

@Override

public boolean onTouchEvent(MotionEvent event) {

PointF control = new PointF(0, 0);

control.x = event.getX();

control.y = event.getY();

double distance1 = getDistance(control, points.get(1));

double distance2 = getDistance(control, points.get(2));

if (distance1 < distance2) {

points.set(1, control);

} else {

points.set(2, control);

}

invalidate();

return true;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

drawPoint(canvas, points, Color.BLACK);

drawLine(canvas, points, Color.GRAY);

drawBezierCurve(canvas);

}

// 绘制数据点

private void drawPoint(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(20);

for (int i = 0; i < data.size(); i++) {

PointF pointF = data.get(i);

canvas.drawPoint(pointF.x, pointF.y, paint);

}

}

//绘制基准线

private void drawLine(Canvas canvas, List data, int color) {

paint.setColor(color);

paint.setStrokeWidth(4);

for (int i = 0; i < data.size() - 1; i++) {

PointF start = data.get(i);

PointF end = data.get(i + 1);

canvas.drawLine(start.x, start.y, end.x, end.y, paint);

}

}

//绘制贝塞尔曲线

private void drawBezierCurve(Canvas canvas) {

paint.setColor(Color.RED);

paint.setStrokeWidth(4);

Path path = new Path();

path.moveTo(points.get(0).x, points.get(0).y);

path.cubicTo(points.get(1).x, points.get(1).y, points.get(2).x, points.get(2).y, points.get(3).x, points.get(3).y);

canvas.drawPath(path, paint);

}

//获取两点的距离

private double getDistance(PointF start, PointF end) {

return Math.sqrt((end.y - start.y) * (end.y - start.y) + (end.x - start.x) * (end.x - start.x));

}

}

1.5.用贝塞尔曲线拟合圆形

分成四段3阶贝塞尔曲线

每一段拟合90度扇形

贝塞尔曲线拟合90圆度

计算x1的值

计算过程:

由公式:B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3

显然,当t=0.5的时候,应该正好在45度的位置上,

于是: sin(pi/4) = 0.125(3x1 - 2) + 0.25(3 - 6x1 ) + 0.5(3x1 )

解出x1=0.55228475

也就是:

根据对称性,可得y1=x1;

2.自定义视图

贝塞尔曲线就是PS里面的魔棒工具,UI上的很多曲线,其实都是用贝塞尔曲线画的,既然如此,我们只需要知道UI是怎么画的,让她标注好数据点的位置,那我们就可以原样画出UI效果了。

贝塞尔曲线的用处,就是动态绘制平滑曲线!并且可以实时控制曲线状态,并可以通过改变控制点的状态实时让曲线进行平滑的状态变化。

2.1.气泡拖拽效果效果图:

这里写图片描述

这里写图片描述

上面的图是盗来的,因为我还不会在手机上录制gif,下面的我的demo的截图:

这里写图片描述

这里:

p1是初始圆的圆心,p2是拖动圆的圆心

X是p1p2线段的中点

AB:与p1p2线段垂直,长度为初始圆的直径

CD:与p1p2线段垂直,长度为拖动圆的直径

绘制流程:

1.绘制p1和p2的圆形

2.根据A,X,D绘制一条2阶贝塞尔曲线

3.根据B,X,C绘制另一条2阶贝塞尔曲线

4.设置path的模式为填充模式

package com.che.chechengwang.support.view.bezier;

import android.animation.FloatEvaluator;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PointF;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.OvershootInterpolator;

import com.che.chechengwang.support.view.bezier.PointUtil;

/**

* 贝塞尔曲线-气泡拖拽

*

* 二条2阶贝塞尔曲线

* 作者:余天然 on 16/6/14 上午10:27

*/

public class BezierDraggableFlag extends View {

private Paint paint;

private int raduis = 40;//气泡的半径

private double distance;//记录拉动的距离

private double raduisTmp;//临时的半径

private int maxDistance = 800;//拉断的距离

private PointF p1, p2;//圆心

private PointF pA, pB, pC, pD, pX;//控制点

private double distanceBackup;

private PointF p2Backup;

public BezierDraggableFlag(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

//初始化圆心的位置

private void init() {

paint = new Paint();

paint.setAntiAlias(true);

p1 = new PointF(600, 400);

p2 = new PointF(600, 400);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

p2.x = event.getX();

p2.y = event.getY();

distance = PointUtil.getDistance(p1, p2);

invalidate();

break;

case MotionEvent.ACTION_UP:

if (distance < maxDistance) {

p2Backup = new PointF(p2.x, p2.y);

distanceBackup = distance;

startAnim();

}

break;

}

return true;

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (distance < maxDistance) {

calculatePoint();

drawBefore(canvas);

} else {

drawAfter(canvas);

}

}

//计算控制点的位置

private void calculatePoint() {

double raduisScale = 1 - distance / maxDistance;

raduisTmp = raduis * raduisScale;

pA = PointUtil.getRotatePoint(p1, p2, raduisTmp, Math.PI / 2);

pB = PointUtil.getRotatePoint(p1, p2, raduisTmp, -Math.PI / 2);

pC = PointUtil.getRotatePoint(p2, p1, raduis, -Math.PI / 2);

pD = PointUtil.getRotatePoint(p2, p1, raduis, Math.PI / 2);

pX = PointUtil.getCenterPoint(p1, p2);

}

//拉断之后的绘制

private void drawAfter(Canvas canvas) {

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(4);

canvas.drawCircle(p2.x, p2.y, raduis, paint);

}

//拉断之前的绘制

private void drawBefore(Canvas canvas) {

//端点

// paint.setColor(Color.GRAY);

// paint.setStyle(Paint.Style.STROKE);

// paint.setStrokeWidth(20);

// canvas.drawPoint(p1.x, p1.y, paint);

// canvas.drawPoint(p2.x, p2.y, paint);

// canvas.drawPoint(pX.x, pX.y, paint);

//辅助线

paint.setColor(Color.GRAY);

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(4);

canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);

//文字

// paint.setColor(Color.BLACK);

// paint.setStyle(Paint.Style.FILL);

// paint.setStrokeWidth(2);

// paint.setTextSize(30);

// canvas.drawText("A", pA.x, pA.y, paint);

// canvas.drawText("B", pB.x, pB.y, paint);

// canvas.drawText("C", pC.x, pC.y, paint);

// canvas.drawText("D", pD.x, pD.y, paint);

// canvas.drawText("X", pX.x, pX.y, paint);

// canvas.drawText("p1", p1.x, p1.y, paint);

// canvas.drawText("p2", p2.x, p2.y, paint);

//圆形

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(4);

canvas.drawCircle(p1.x, p1.y, (float) raduisTmp, paint);

canvas.drawCircle(p2.x, p2.y, raduis, paint);

//贝塞尔曲线

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(4);

Path path = new Path();

path.moveTo(pA.x, pA.y);

path.quadTo(pX.x, pX.y, pD.x, pD.y);

path.lineTo(pC.x, pC.y);

path.quadTo(pX.x, pX.y, pB.x, pB.y);

path.lineTo(pA.x, pA.y);

canvas.drawPath(path, paint);

}

//放开之后,如果没有拉断,就恢复初始状态

private void startAnim() {

final FloatEvaluator evaluator = new FloatEvaluator();

ValueAnimator animator = ValueAnimator.ofFloat(0, 100);

animator.setInterpolator(new OvershootInterpolator());

animator.setDuration(100);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

float fraction = animation.getAnimatedFraction();

p2.x = evaluator.evaluate(fraction, p2Backup.x, p1.x);

p2.y = evaluator.evaluate(fraction, p2Backup.y, p1.y);

distance = evaluator.evaluate(fraction, distance, 0);

invalidate();

}

});

animator.start();

}

}

这里用到了一个工具类:

package com.che.chechengwang.support.view.bezier;

import android.graphics.PointF;

/**

* 点计算工具类

*

* 作者:余天然 on 16/6/15 下午2:33

*/

public class PointUtil {

//获取旋转后的点

public static PointF getRotatePoint(PointF p1, PointF p2, double raduis, double radians) {

double oldRadians = getPointDegree(p1, p2);

double newRadians = oldRadians + radians;

float x = (float) (raduis * Math.cos(newRadians));

float y = (float) (raduis * Math.sin(newRadians));

return new PointF(p1.x + x, p1.y + y);

}

//获取中间的点

public static PointF getCenterPoint(PointF p1, PointF p2) {

float x = (p1.x + p2.x) / 2;

float y = (p1.y + p2.y) / 2;

return new PointF(x, y);

}

//获取两点的角度-返回的是弧度制

public static double getPointDegree(PointF p1, PointF p2) {

double scale = (p2.y - p1.y) / (p2.x - p1.x);

return Math.atan(scale);

}

//获取两点的距离

public static double getDistance(PointF start, PointF end) {

return Math.sqrt((end.y - start.y) * (end.y - start.y) + (end.x - start.x) * (end.x - start.x));

}

}

2.2.指示器效果目标效果:

这里写图片描述

这个以后再来玩,其实有了上面的气泡拖拽效果,实现这个效果很简单的,有兴趣的朋友完全可以根据我上面的效果来实现它。

随便再给大家分享一个学习android自定义View相关知识的好网站:有心课堂-三杆火枪干掉自定义View,传递给你的不仅仅是技术!

菜鸟一枚,水平有限,欢迎大家指出博文中的不足之处,小鱼将不胜感激!@qq:630709658

参考目录:

java贝塞尔曲线_贝塞尔曲线学习相关推荐

  1. java 贝塞尔曲线_贝塞尔曲线:原理、自定义贝塞尔曲线View、使用!!!

    一.原理 转自:http://www.2cto.com/kf/201401/275838.html Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation Pr ...

  2. java实现曲线运动_贝塞尔曲线 --匀速贝塞尔曲线运动的实现

    二次贝塞尔曲线通常以如下方式构建,给定二维平面上的固定点P0,P1,P2,用B(t)表示该条曲线 用一个动画来演示,可以更加清楚的表明这条曲线的构建过程 如果t变量本身线形变化的话,这条贝塞尔曲线本身 ...

  3. 贝塞尔修正_贝塞尔修正背后的推理:n-1

    贝塞尔修正 A standard deviation seems like a simple enough concept. It's a measure of dispersion of data, ...

  4. python贝塞尔插值公式_贝塞尔函数、Jinc函数与图像插值算法

    Jinc函数插值是一种传统的图像插值算法,可以用来进行图像缩放(即Jinc Resize).在传统的非机器学习图像超分辨率/放大算法中,Jinc Resize是效果较为出众的算法.虽然在传统神经网络和 ...

  5. java.jpi在线_解析Kotlin-koans学习kotlin编程(一)

    源起 从C#转java,写了一段时间之后觉得超级啰嗦,借着Kotlin成为了android开发的官方语言的契机发现kotlin也许能成为c#转java的程序员的福音. 在学习kotlin的过程中发现了 ...

  6. java基础知识点_零基础学习Java语言,各个阶段需要掌握的知识点

    随社会的脚步的不断发展,Java技术在不断的与时俱进,这也是Java一直长盛不衰的原因之一.Java技术的学习,永远没有早晚之分,技不压身,对于21世纪的我们80后,90后,甚至00后,尤其适用! 那 ...

  7. c和java哪个好学_编程入门学习c++和Java哪个比较好

    编程入门学习c++和Java哪个比较好 发布时间:2020-04-25 16:54:41 来源:亿速云 阅读:231 作者:栢白 编程入门学习c++和Java哪个比较好?如今这些都是小白比较关心的,如 ...

  8. 大一java怎么学好_是否应该学习第二门语言,学那个比较合适。

    如果从尽快找工作的角度,我认为不需要学习第二门语言.计算机语言只是工具!尽快用自己已经掌握的语言向计算机世界更重要的问题进发,完成项目更重要.比如你说的Java Web.因为这将让你了解更多计算机世界 ...

  9. 光滑曲线_光滑曲线可求长定理证明

    同济大学<高等数学>(第七版)中对于光滑曲线求长以及可求长定理没有做出过多的讨论,只是以可求长为前提推导了长度公式. 若想严谨地证明存在性, 首先需要严格的定义. (1) 设 是一光滑的曲 ...

最新文章

  1. java中printnb方法_java打印技术---javax.print
  2. 银行办理业务观察者模式解析
  3. Spring-注入参数详解-[简化配置方式]
  4. element.onclick = fun与element onclick=fun()的区别
  5. c++别让异常逃离析构函数
  6. 数据库练习(二)三个数据库根据指定id获取name和存储数据库名称
  7. java excel 取值_java实现Excel 单元格取值工具类
  8. Error in mounted hook: “TypeError: Cannot read property ‘init‘ of undefined“
  9. C语言中强制转换问题
  10. 安装SPSS激活时提示could not create the Java virtual machine
  11. java文字淡入淡出显示特效,jQuery超酷文字淡入淡出显示特效
  12. QNX虚拟环境三 (内存 设备 调度 )
  13. 行程码是怎么知道你去过哪些地方的呢?
  14. 接口设计中,如何封装对json格式的数据签名
  15. manifest文件linux,MANIFEST 文件扩展名: 它是什么以及如何打开它?
  16. Restyle起来!
  17. Python机器学习:随机抽样函数sample()划分数据集
  18. PalmOS开发教程-13
  19. vue.js以及vue_devtools的网盘
  20. android横向滚轮特效,RecyclerView实现横向滚动效果

热门文章

  1. pytorch中的Variable()
  2. PF526系列高性能的二维码解码芯片
  3. 这场大数据+AI Meetup,一次性安排了大数据当下热门话题
  4. 监听input type=file 文件上传取消事件
  5. VB.NET下的事件和委托
  6. java 设置热键_Java设置全局热键——第三方包jintellitype实现
  7. 央行“超级网银”8月上线 抵制第三方支付
  8. Springmvc 后台接受String[] 问题
  9. 解析matplotlib.colors.LinearSegmentedColormap中的字典颜色分割,自定义colorbar
  10. 【JAE】JAE京东云擎部署首个Java应用