贝塞尔曲线、Path、PathMeasure理解在Android中

 1. 贝塞尔曲线在数学上的理解
   3 点确定一断曲线,对于二阶贝塞尔曲线
   在t 时间内,
   从p0 到  q
   从q  到 p1 上的点的连线,对应的切线,就是
   贝塞尔曲线的轨迹
   效果图:

上面是我对贝塞尔曲线立即在数学中,可能理解是错误的,Android开发中不用去管什么公式, 用api就行了

 2. Adroid贝塞尔曲线绘制
2.1. 二阶绘制
2.2. 三阶绘制

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.denganzhi.cusomerwidget.canvas.PathActivity">

    <com.denganzhi.cusomerwidget.canvas.PathView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.denganzhi.cusomerwidget.canvas.PathView>

</LinearLayout>

Java代码实现:

public class PathView extends View {
    public PathView(Context context) {
        super(context);
    }
 Paint paint=null;
    public PathView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint=new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 6. 贝塞尔曲线api
        Path path6=new Path();
        path6.moveTo(100,400);
        // 二阶贝塞尔曲线1
        path6.quadTo(250,200,400,400);
        // 二阶贝塞尔曲线2, 起点是上一个曲线的结束点
        path6.quadTo(500,500,600,400);

        // 三阶贝塞尔曲线,4个点
        Path path7=new Path();
        path7.moveTo(100,400);
        path7.cubicTo(200,100,300,250,400,300);
        canvas.drawPath(path6,paint);
        canvas.drawPath(path7,paint);
  }
}

 3. PathMeasure 计算轨迹路径长度:

3.1.  getLength计算轨迹长度

  //    PathMeasure  测量工具类
        // 600  实际长度 path
        PathMeasure pathMeasure1=new PathMeasure(path8,false);
        // 800 绘制图形 闭合以后的长度
      //  PathMeasure pathMeasure2=new PathMeasure(path8,true);
     //   Log.e("denganzhi","length1:"+pathMeasure1.getLength());
        float length1= pathMeasure1.getLength();
        // path  可以绘制多条路径,
        boolean nextCouner=  pathMeasure1.nextContour(); //获取下一个路径,可能没有
        // 获取第二条路径长度
        float length2= pathMeasure1.getLength();
        Log.e("denganzhi","第一个条路径长度:"+length1+ "nextCounter "+ nextCouner+  "第二条路径长度:"+length2);
      // 第一个条路径长度:600.0nextCounter true第二条路径长度:160.0
        paint.setColor(Color.BLACK);
        canvas.drawPath(path8,paint);

  输出 : E/denganzhi: 第一个条路径长度:600.0nextCounter true第二条路径长度:160.0 

3.2.  getSegment截取轨迹,存入新path中

  //    PathMeasure   用于测量path路径长度
        canvas.translate(100,100);
        Path path8=new Path();
        //  默认其实点是0,0
        path8.lineTo(0,200);
        path8.lineTo(200,200);
        path8.lineTo(200,0);
        RectF rect8=new RectF(10,10,50,50);
        // 600  实际长度 path
        PathMeasure pathMeasure1=new PathMeasure(path8,false);
        // 800 绘制图形 闭合以后的长度
        float length1= pathMeasure1.getLength();
        paint.setColor(Color.BLACK);
        canvas.drawPath(path8,paint);

         // 路径截取
        Path dst= new Path();
        paint.setColor(Color.RED);
        //  dst 的起始点 dst.moveTo(x,x);   是否为上一个节点结束点,是否保存连续性
        pathMeasure1.getSegment(0,400,dst,false);
        canvas.drawPath(dst,paint);

 红色部分为截取部分重新绘制

 3.3. getPosTan 获取某一段长度终点的坐标,以及切线(?)

  //    PathMeasure   用于测量path路径长度
        canvas.translate(100,100);
        Path path8=new Path();
        //  默认其实点是0,0
        path8.lineTo(0,200);
        path8.lineTo(200,200);
        path8.lineTo(200,0);
        RectF rect8=new RectF(10,10,50,50);
        path8.addRect(rect8, Path.Direction.CCW);
        paint.setColor(Color.BLACK);
        canvas.drawPath(path8,paint);
   float[] pos=new float[2];
        float[] tan= new float[2];  // tan=y/x
        pathMeasure9.getPosTan(pathMeasure9.getLength()/4,pos,tan);
// postionx: 3.051759E-5 positiony: 50.0 tanx:-1.0 tany: 6.473757E-7
                Log.e("denganzhi","postionx: "+pos[0]+" positiony: "+ pos[1] +" tanx:" +tan[0] + " tany: " + tan[1]);
        canvas.drawPath(path9,paint);

输出: E/denganzhi: postionx: 3.051759E-5 positiony: 50.0 tanx:-1.0 tany: 6.473757E-7 

 综合代码 :PathView

package com.denganzhi.cusomerwidget.canvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by Administrator on 2020/3/15.
 */

public class PathView extends View {
    public PathView(Context context) {
        super(context);
    }

    Paint paint=null;
    public PathView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint=new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 6. 贝塞尔曲线api
        Path path6=new Path();
        path6.moveTo(100,400);
        // 二阶贝塞尔曲线1
        path6.quadTo(250,200,400,400);
        // 二阶贝塞尔曲线2, 起点是上一个曲线的结束点
        path6.quadTo(500,500,600,400);

        // 三阶贝塞尔曲线,4个点
        Path path7=new Path();
        path7.moveTo(100,400);
        path7.cubicTo(200,100,300,250,400,300);
//        canvas.drawPath(path6,paint);
//        canvas.drawPath(path7,paint);


     //    PathMeasure   用于测量path路径长度
        canvas.translate(100,100);
        Path path8=new Path();
        //  默认其实点是0,0
        path8.lineTo(0,200);
        path8.lineTo(200,200);
        path8.lineTo(200,0);
        RectF rect8=new RectF(10,10,50,50);
        path8.addRect(rect8, Path.Direction.CCW);

        //    PathMeasure  测量工具类
        // 600  实际长度 path
        PathMeasure pathMeasure1=new PathMeasure(path8,false);
        // 800 绘制图形 闭合以后的长度
        //  PathMeasure pathMeasure2=new PathMeasure(path8,true);
        //   Log.e("denganzhi","length1:"+pathMeasure1.getLength());
        float length1= pathMeasure1.getLength();
        // path  可以绘制多条路径,
        //    boolean nextCouner=  pathMeasure1.nextContour(); //获取下一个路径,可能没有
        // 获取第二条路径长度
        //  float length2= pathMeasure1.getLength();
        //  Log.e("denganzhi","第一个条路径长度:"+length1+ "nextCounter "+ nextCouner+  "第二条路径长度:"+length2);
        // 第一个条路径长度:600.0nextCounter true第二条路径长度:160.0
        paint.setColor(Color.BLACK);
        canvas.drawPath(path8,paint);


         // 路径截取
        Path dst= new Path();
        paint.setColor(Color.RED);
        //  dst 的起始点 dst.moveTo(x,x);   是否为上一个节点结束点,是否保存连续性
        pathMeasure1.getSegment(0,400,dst,false);
       // canvas.drawPath(dst,paint);




        // 获取某一段长度的坐标,切线
        Path path9=new Path();
        path9.addCircle(0,0,50,Path.Direction.CW);
        PathMeasure pathMeasure9=new PathMeasure(path9,false);

        float[] pos=new float[2];
        float[] tan= new float[2];  // tan=y/x
        pathMeasure9.getPosTan(pathMeasure9.getLength()/4,pos,tan);
// postionx: 3.051759E-5 positiony: 50.0 tanx:-1.0 tany: 6.473757E-7
                Log.e("denganzhi","postionx: "+pos[0]+" positiony: "+ pos[1] +" tanx:" +tan[0] + " tany: " + tan[1]);
        canvas.drawPath(path9,paint);


    }
}
发布了91 篇原创文章 · 获赞 90 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/104882679