Path基础之PathMearsure详解

PathMeasure路径测量,用来测量path的工具类。

很重要:一定要看注释,一定要看注释,一定要看注释,O(∩_∩)O哈哈~。

PathMeasure常用方法

一、PathMeasure关联Path
PathMeasure需要关联一个已经创建好的Path,两种方式:
构造方法:
PathMeasure pathMeasure = new PathMeasure(path, false);
或者是:使用PathMeasure的setPath
pathMeasure.setPath(path, false);

重点说下他们两个的参数forceClosed:在测量的时候是否将终点和起点相连进行测试,最终会影响到后面的pathMeasure.getLength()的测量结果。
具体的测试结果在如下的代码注释中有,需要认真去看注释。

另外讲解**pathMeasure.getLength()**获取Path的长度。

Path path = new Path();
path.moveTo(-100, -100);
path.lineTo(100, -100);
path.lineTo(100, 100);
path.lineTo(-100, 100);


// pathMeasure需要关联一个创建好的path, forceClosed会影响Path的测量结果
// 两种方式,一种是在构造方法中直接关联,另一种是调用pathMeasure.setPath
// PathMeasure pathMeasure = new PathMeasure(path, false);
PathMeasure pathMeasure = new PathMeasure();
//pathMeasure.setPath(path, false);
// 测量出来path的结果是600
//LogUtils.d(TAG, "forceClosed:false" + "====Path的长度:" + pathMeasure.getLength());
// 测量出来结果是800
pathMeasure.setPath(path, true);
LogUtils.d(TAG, "forceClosed:true" + "====Path的长度:" + pathMeasure.getLength());

path.lineTo(-200, 100);
// 如果Path进行了调整,需要重新调用setPath方法进行关联
pathMeasure.setPath(path, true);
LogUtils.d(TAG, "forceClosed:true" + "====Path的长度:" + pathMeasure.getLength());

canvas.drawPath(path, mPaint);

Path基础之PathMearsure详解_第1张图片
二、PathMeasure的getSegment()

获取Path的片段
startD:截取片段的开始位置距离Path的起点的长度
stopD:截取片段的结束位置距离Path的起点的长度
dst:截取的片段存入的目标Path
startWithMoveTo:保持截取得到的Path第一个点位置不变

boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

下面具体的操作就可以看到startWithMoveTo:true和false的具体区别

Path path = new Path();
path.addRect(new RectF(-200, -200, 200, 200), Path.Direction.CW);
Path dstPath = new Path();
dstPath.lineTo(-200,-200);

PathMeasure pathMeasure = new PathMeasure(path, false);
// 截取一部分存入dst中,并且使用moveTo保持截取得到的Path第一个点位置不变。
//pathMeasure.getSegment(200, 1000, dstPath, false);
pathMeasure.getSegment(200, 1000, dstPath, true);

canvas.drawPath(path, mPaint);
canvas.drawPath(dstPath, mCoorPaint);

startWithMoveTo:为true,可以看到片段开始位置的起点坐标是没有改变的,
仍然是(0, 200)
Path基础之PathMearsure详解_第2张图片
startWithMoveTo:为false,可以看到片段开始位置的起点坐标已经被改变,
坐标为(-200, -200)
Path基础之PathMearsure详解_第3张图片
三、PathMeasure的nextContour():调转到下一个Path。
从具体的测试结果可以看出来pathMeasure.getLength()获取的长度并不是下图绘制的那样,获取的是所有Path加在一起的长度,而是获取的当前Path的长度。

Path path = new Path();
path.addRect(-200, -200, 200, 200, Path.Direction.CW);
path.addOval(new RectF(-300, -300, 300, 300), Path.Direction.CW);

PathMeasure pathMeasure = new PathMeasure(path, true);

// 长度是1600,我们发现path的长度只包含了矩形的周长
// 因为pathMeasure.getLength()只会获取当前Path的长度
LogUtils.d(TAG, "Path的长度:" + pathMeasure.getLength());

// 跳转到下一个Path,也就是椭圆
pathMeasure.nextContour();
// 长度1884.1941,就是椭圆的周长2*R*PI
LogUtils.d(TAG, "Path的长度:" + pathMeasure.getLength());


canvas.drawPath(path, mPaint);

Path基础之PathMearsure详解_第4张图片
四、PathMeasure的getPosTan
distance:距离Path起点的长度0 <= distance <= getLength()
pos[]:distance长度在曲线上当前位置的切点坐标,x:pos[0],y:pos[1]
tan[]:distance长度在曲线上当前位置的邻边和对边的tan值,
邻边:tan[0],
对边:tan[1]

boolean getPosTan(float distance, float pos[], float tan[])
Path path = new Path();
path.addOval(new RectF(-300, -300, 300, 300), Path.Direction.CW);

PathMeasure pathMeasure = new PathMeasure(path, true);
pathMeasure.getPosTan(200, pos, tan);
// pos[0]:235.72583==>pos[1]:185.56221
LogUtils.d(TAG, "pos[0]:" + pos[0] + "==>pos[1]:" + pos[1]);
// tan[0]:-0.6185407==>tan[1]:0.7857528
LogUtils.d(TAG, "tan[0]:" + tan[0] + "==>tan[1]:" + tan[1]);


canvas.drawPath(path, mPaint);

tan的值我们可以查阅下面这张图,帮助理解tan[0]和tan[1]具体意思。
我们看到30o的时候,tan[0] = √3 / 2,tan[1] = 1/2
Path基础之PathMearsure详解_第5张图片

  • 利用getPosTan实现一个例子
    一个箭头跟着圆环旋转

第一种方式,然后利用Matrix的旋转、平移方法去修改旋转角度,旋转点

// 重置path
mPath.reset();
// mPath.addOval(mRectF, Path.Direction.CW);
mPath.addCircle(0,0,300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);

// 修改chgValue的值,每次切点才会移动
chgValue += 0.01;
if (chgValue >= 1) {
	chgValue = 0;
}


PathMeasure pathMeasure = new PathMeasure(mPath, true);
pathMeasure.getPosTan(pathMeasure.getLength() * chgValue, pos, tan);
// pos[0]:235.72583==>pos[1]:185.56221
LogUtils.d(TAG, "pos[0]:" + pos[0] + "==>pos[1]:" + pos[1]);
// tan[0]:-0.6185407==>tan[1]:0.7857528
LogUtils.d(TAG, "tan[0]:" + tan[0] + "==>tan[1]:" + tan[1]);

// 计算出当前切线去X轴的夹角度数
double degree = Math.atan2(tan[1], tan[0]) * 180 / Math.PI;
LogUtils.d(TAG, "旋转角度:" + degree);

// 一定需要将mMatrix重置
mMatrix.reset();
// 修改旋转角度
mMatrix.postRotate((float) degree, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);
// 将当前图片的绘制中心移动到跟切点重合
mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2, pos[1] - mBitmap.getHeight() / 2);
canvas.drawBitmap(mBitmap, mMatrix, mPaint);

invalidate();

第二种方式,利用
利用pathMeasure.getMatrix方法直接将旋转角度和旋转点保存在Matrix中。

// 重置path
mPath.reset();
// mPath.addOval(mRectF, Path.Direction.CW);
mPath.addCircle(0, 0, 300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);

// 修改chgValue的值,每次切点才会移动
chgValue += 0.01;
if (chgValue >= 1) {
	chgValue = 0;
}

PathMeasure pathMeasure = new PathMeasure(mPath, false);
// 根据两个标志,直接将旋转角度和旋转位置保存在Matrix中
// 就是将pos信息和tan信息保存在mMatrix中
pathMeasure.getMatrix(
		pathMeasure.getLength() * chgValue,
		mMatrix,
		PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG
);
// 修正图片旋转中心坐标为图片的中心
mMatrix.preTranslate(-mBitmap.getWidth()/2,-mBitmap.getHeight()/2);
canvas.drawBitmap(mBitmap, mMatrix, mPaint);

invalidate();

Path基础之PathMearsure详解_第6张图片

例子

本文例子的Github地址

你可能感兴趣的:(android,Android学习总结,PathMeasure,Path的测量类,Path)