安卓杂记(四)利用自定义的PolyBezier()函数将一系列散点绘制成光滑曲线(二)
2015-01-27 21:44
351 查看
上一节讲到如何利用canvas画出两点之间的贝塞尔曲线,那么如何连接多点于一条光滑曲线呢?
所谓众里寻他千百度,那人却在灯火阑珊处,大浪淘沙般,谜底终呼之欲出——PolyBezier()函数。
以绘制图1中曲线为例,该曲线由两段构成,p0~p3段和p4~p7段,不难看出
p3=p4,即前段曲线的终点是后段曲线的起点。
![](http://img.blog.csdn.net/20150127220137341?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanNjOTQxMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
在lpPoints结构中会顺序存储p0,p1,p2,p3(p4),p5,p6,p7七个点。
其中p0,p3(p4),p7是已知的,也就是在鼠标绘图过程中p0,p3(p4),p7都是鼠标经过点,已知需要根据这3点反求控制点p1,p2,p5,p6.
这里可用两端Bezier曲线连续的条件,即p1p0连线即为曲线在p0处切线,p2p3连线为p3处切线,p4p5为p4处切线,p6p7为p7处切线,两段曲线连续(这里用的是一阶连续条件)必然要求p2p3与p4p5在一条线上。端点处可令其倒数为0,即可算得控制点。
根据条件可算得
p1.x=p0.x;
p1.y=p0.y;
p2.x=(p0.x+4*p3.x-p7.x)/4;
p2.y=(p0.y+4*p3.y-p7.y)/4;
p5.x=(4*p3.x+p7.x-p0.x)/4;
p5.y=(4*p3.y+p7.y-p0.y)/4;
p6.x=p7.x;
p6.y=p7.y;//一阶倒在端点处为0
所得公式即为PolyBezier的精髓。
然而,在Android中并不提供此函数,需要我们自己定义,好在我们获得了上述公式。
可以每次获取三个点,即p0, p3, p7,因p1与p0的横纵坐标相同,权且不与理会。故只需算出p2即可。利用算得的p2坐标,画出p0与p3之间的贝塞尔曲线。更新p0, p3, p7,即获取一点p11, 令p0 = p3, p3 = p7, p7 = p11,重新绘制p0与p3之间的贝塞尔曲线。直到p7为最后一个点,因p3与p7之间的贝塞尔曲线未画,故可以反过来,令交换p0与p7的值,就可以重复上述步骤。
代码示例如下:
那具体如何运用呢,下一节将会用一个实例示之。
所谓众里寻他千百度,那人却在灯火阑珊处,大浪淘沙般,谜底终呼之欲出——PolyBezier()函数。
三.PolyBezier()函数详解
由图形学知识知道一段Bezier曲线由4个控制点p0,p1,p2,p3决定,该曲线经过p0和p3点,即该曲线起于p0点,终于p3点。一条经过鼠标点击点的曲线就可以由多段的Bezier曲线连续而成。以绘制图1中曲线为例,该曲线由两段构成,p0~p3段和p4~p7段,不难看出
p3=p4,即前段曲线的终点是后段曲线的起点。
在lpPoints结构中会顺序存储p0,p1,p2,p3(p4),p5,p6,p7七个点。
其中p0,p3(p4),p7是已知的,也就是在鼠标绘图过程中p0,p3(p4),p7都是鼠标经过点,已知需要根据这3点反求控制点p1,p2,p5,p6.
这里可用两端Bezier曲线连续的条件,即p1p0连线即为曲线在p0处切线,p2p3连线为p3处切线,p4p5为p4处切线,p6p7为p7处切线,两段曲线连续(这里用的是一阶连续条件)必然要求p2p3与p4p5在一条线上。端点处可令其倒数为0,即可算得控制点。
根据条件可算得
p1.x=p0.x;
p1.y=p0.y;
p2.x=(p0.x+4*p3.x-p7.x)/4;
p2.y=(p0.y+4*p3.y-p7.y)/4;
p5.x=(4*p3.x+p7.x-p0.x)/4;
p5.y=(4*p3.y+p7.y-p0.y)/4;
p6.x=p7.x;
p6.y=p7.y;//一阶倒在端点处为0
所得公式即为PolyBezier的精髓。
然而,在Android中并不提供此函数,需要我们自己定义,好在我们获得了上述公式。
可以每次获取三个点,即p0, p3, p7,因p1与p0的横纵坐标相同,权且不与理会。故只需算出p2即可。利用算得的p2坐标,画出p0与p3之间的贝塞尔曲线。更新p0, p3, p7,即获取一点p11, 令p0 = p3, p3 = p7, p7 = p11,重新绘制p0与p3之间的贝塞尔曲线。直到p7为最后一个点,因p3与p7之间的贝塞尔曲线未画,故可以反过来,令交换p0与p7的值,就可以重复上述步骤。
代码示例如下:
private void polyBezier(Point numList[], int count, Canvas can, Paint mPaint){ float startX, startY, conX, conY; Path tempPath = new Path(); Paint tmpPaint = new Paint(mPaint); tmpPaint.setStrokeWidth(1); float medX = numList[0].x;
float medY = numList[0].y; float endX = numList[1].x; float endY = numList[1].y; for(int i = 2; i < count ; i++){ startX = medX; startY = medY; medX = endX; medY = endY; endX = numList[i].x;; endY = numList[i].y; conX = (startX + 4 * medX - endX) / 4.0f; conY = (startY + 4 * medY - endY) / 4.0f; tempPath.moveTo(startX, startY); tempPath.quadTo(conX, conY, medX, medY); can.drawPath(tempPath, tmpPaint); if (i == count - 1){ conX = (4 * medX + endX - startX) / 4.0f; conY = (4 * medY + endY - startY) / 4.0f; tempPath.moveTo(medX, medY); tempPath.quadTo(conX, conY, endX, endY); can.drawPath(tempPath, tmpPaint); } } }
那具体如何运用呢,下一节将会用一个实例示之。
相关文章推荐
- 安卓杂记(三)利用自定义的PolyBezier()函数将一系列散点绘制成光滑曲线(一)
- 安卓杂记(三)利用自定义的PolyBezier()函数将一系列散点绘制成光滑曲线(一)
- 安卓杂记(四)利用自定义的PolyBezier()函数将一系列散点绘制成光滑曲线(二)
- MATLAB利用散点进行函数曲线拟合
- (作业)自定义视图(UIView绘制任意函数曲线)
- 利用自定义数据集运算函数实现字符串的特殊转化
- 用JFreeChart绘制光滑曲线(二) 简单实现
- 利用rundll32.exe来运行自定义的dll导出函数
- SQL里利用自定义函数Group By 数据得到字符串
- 用 ATL ActiveX 绘制任意平面函数的曲线
- 在asp中利用vml绘制曲线图
- 利用自定义消息处理函数的WPARAM或LPARAM参数传递指针
- sql server 中利用自定义函数分隔字符串
- 极简单的绘制曲线的函数
- 绘制正弦函数曲线
- 自定义ORM系列(一)利用attribute实现简单的reader=>entity和reader=>List<entity>映射
- 为何在自定义消息处理函数中无法利用wParam或lParam传
- 利用自定义消息处理函数的WPARAM或LPARAM参数传递指针
- 用ATL ActiveX 绘制任意平面函数的曲线
- Sql Server中利用自定义函数完成单据流水号的设计