Android之贝塞尔曲线(Bezier)

初始历程

关于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>

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值