初始历程
关于Bezier
**线性公式
给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
且其等同于线性插值。
二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。
三次方公式
P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
现代的成象系统,如PostScript、Asymptote和Metafont,运用了以贝兹样条组成的三次贝兹曲线,用来描绘曲线轮廓。
一般参数公式
阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:
如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。
用平常话来说,阶的贝兹曲线,即双阶贝兹曲线之间的插值。
公式说明
1.开始于P0并结束于Pn的曲线,即所谓的端点插值法属性。
2.曲线是直线的充分必要条件是所有的控制点都位在曲线上。同样的,贝塞尔曲线是直线的充分必要条件是控制点共线。
3.曲线的起始点(结束点)相切于贝塞尔多边形的第一节(最后一节)。
4.一条曲线可在任意点切割成两条或任意多条子曲线,每一条子曲线仍是贝塞尔曲线。
5.一些看似简单的曲线(如圆)无法以贝塞尔曲线精确的描述,或分段成贝塞尔曲线(虽然当每个内部控制点对单位圆上的外部控制点水平或垂直的的距离为时,分成四段的贝兹曲线,可以小于千分之一的最大半径误差近似于圆)。
6.位于固定偏移量的曲线(来自给定的贝塞尔曲线),又称作偏移曲线(假平行于原来的曲线,如两条铁轨之间的偏移)无法以贝兹曲线精确的形成(某些琐屑实例除外)。无论如何,现存的启发法通常可为实际用途中给出近似值。**
public class BezierView extends View {
List<Point> mPointsToDraw;
Point mStart = new Point(), mControll = new Point(),
mEmd = new Point();
Random mRandom = new Random();
Path mPath;
Paint mPaint;
public BezierView(Context context) {
this(context, null);
}
public BezierView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BezierView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPointsToDraw != null) {
canvas.drawText("control point one Cordinate:(" + mControll.x + "," + mControll.y + ")", 10, 50, mPaint);
canvas.drawText("end Cordinate:(" + mEmd.x + "," + mEmd.y + ")", 10, 110, mPaint);
Point s = mPointsToDraw.get(0);
mPath.reset();
mPath.moveTo(s.x, s.y);
for (int i = 1; i < mPointsToDraw.size(); i++) {
mPath.lineTo(mPointsToDraw.get(i).x, mPointsToDraw.get(i).y);
}
canvas.drawPath(mPath, mPaint);
}
}
private void init() {
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(2);
mPaint.setTextSize(25);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mPointsToDraw != null) {
mPointsToDraw.clear();
}
mStart.x = event.getX();
mStart.y = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mControll.x = (mRandom.nextInt(getWidth()) * mRandom.nextFloat());
mControll.y = (mRandom.nextInt(getHeight()) * mRandom.nextFloat());
break;
case MotionEvent.ACTION_UP:
mEmd.x = event.getX();
mEmd.y = event.getY();
mPointsToDraw = calculatePointConic(mStart, mControll, mEmd);
invalidate();
break;
}
return super.onTouchEvent(event);
}
private List<Point> calculatePointConic(Point start, Point con, Point end) {
List<Point> points = new ArrayList<>();
float tempX,tempY;
for (float i = 0; i <= 1; i += 0.001) {
tempX =(1-i)*(1-i)*start.x+2*i*(1-i)*con.x+i*i*end.x;
tempY =(1-i)*(1-i)*start.y+2*i*(1-i)*con.y+i*i*end.y;
Point temp = new Point(tempX, tempY);
points.add(temp);
}
return points;
}
public static class Point {
public float x;
public float y;
public Point() {
this(0f, 0f);
}
public Point(float x, float y) {
this.x = x;
this.y = y;
}
}
}
Main3Activity
public class Main3Activity extends Activity {
BezierView mBezierView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
mBezierView = (BezierView) findViewById(R.id.bezier);
mBezierView.setFocusable(true);
mBezierView.setFadingEdgeLength(20);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mBezierView.onTouchEvent(event);
return super.onTouchEvent(event);
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ycation.yin.Main3Activity">
<com.ycation.yin.hello.BezierView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/bezier"
/>
</RelativeLayout>