Android之贝塞尔曲线(Bezier)
2016-07-27 11:32
666 查看
初始历程
给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
![](https://img-blog.csdn.net/20161024182547024)
且其等同于线性插值。
二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
![](https://img-blog.csdn.net/20161024182607614)
TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。
三次方公式
P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
![](https://img-blog.csdn.net/20161024182628634)
现代的成象系统,如PostScript、Asymptote和Metafont,运用了以贝兹样条组成的三次贝兹曲线,用来描绘曲线轮廓。
一般参数公式
阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:
![](https://img-blog.csdn.net/20161024182654852)
如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。
用平常话来说,阶的贝兹曲线,即双阶贝兹曲线之间的插值。
公式说明
1.开始于P0并结束于Pn的曲线,即所谓的端点插值法属性。
2.曲线是直线的充分必要条件是所有的控制点都位在曲线上。同样的,贝塞尔曲线是直线的充分必要条件是控制点共线。
3.曲线的起始点(结束点)相切于贝塞尔多边形的第一节(最后一节)。
4.一条曲线可在任意点切割成两条或任意多条子曲线,每一条子曲线仍是贝塞尔曲线。
5.一些看似简单的曲线(如圆)无法以贝塞尔曲线精确的描述,或分段成贝塞尔曲线(虽然当每个内部控制点对单位圆上的外部控制点水平或垂直的的距离为时,分成四段的贝兹曲线,可以小于千分之一的最大半径误差近似于圆)。
6.位于固定偏移量的曲线(来自给定的贝塞尔曲线),又称作偏移曲线(假平行于原来的曲线,如两条铁轨之间的偏移)无法以贝兹曲线精确的形成(某些琐屑实例除外)。无论如何,现存的启发法通常可为实际用途中给出近似值。**
关于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>
相关文章推荐
- Android--px(像素)和dp、sp之间的相互转化
- Android 实时视频采集/编码/传输/解码/播放—方案调研
- 解决Android Webview 重定向无法 goback 的方法
- Android Studio中debug模式下使用release签名
- Android 更改一个更新
- Android设备的唯一标识
- 安卓开发之,教你使用反射+注解
- Android开源项目——设置图文居中的按钮 IconButton
- Android 属性拷贝,属性复制的工具类
- android项目管理activity的类
- Android Studio 使用Gradle多渠道打包
- android 环境配置
- android fragment 使用以及嵌套使用 底部菜单和顶部菜单
- Android 开始一个activity的同时保留导航
- android删除私密信息
- Android源码解析Activity#setContentView()方法
- 新手Android学习笔记 05——IllegalStateException非法异常之一
- 新手Android学习笔记 05——IllegalStateException非法异常之一
- android studio radioGroup radiobutton使用listactivity演示
- 动态修改actionBar返回键颜色