Android-多点绘制平滑曲线
来源:互联网 发布:outlook mac 下载 编辑:程序博客网 时间:2024/05/16 11:11
最近遇到个题,给定一系列坐标点,如何把它们绘制成一条平滑的曲线。
1 Catmull-Rom算法绘制曲线
首先来了解一下,样条曲线(Spline Curves),
是指给定一组控制点而得到一条曲线,曲线的大致形状由这些点予以控制,一般可分为插值样条和逼近样条两种,插值样条通常用于数字化绘图或动画的设计,逼近样条一般用来构造物体的表面。
而Catmull-Rom就是其中一种常用于绘制曲线的样条曲线算法,我们可以把它当成是一种特殊的贝塞尔曲线,一种能够经过所有控制点的曲线。
给定四个坐标点,P0,P1,P2,P3,同时再给定一个float值t(从P1移动到P2的同时,t从0变化到1),可以绘制P1到P2这段曲线的坐标点。
我们可以看到相关的计算公式:
根据公式我们可以转化成代码:
private PointF interpolatedPosition(PointF point0, PointF point1, PointF point2, PointF point3, float i) { float u3 = i * i * i; float u2 = i * i; float f1 = -0.5f * u3 + u2 - 0.5f * i; float f2 = 1.5f * u3 - 2.5f * u2 + 1.0f; float f3 = -1.5f * u3 + 2.0f * u2 + 0.5f * i; float f4 = 0.5f * u3 - 0.5f * u2; float x = point0.x * f1 + point1.x * f2 + point2.x * f3 + point3.x * f4; float y = point0.y * f1 + point1.y * f2 + point2.y * f3 + point3.y * f4; return new PointF(x, y); }
给定一系列坐标点:
mPointFList = new ArrayList<>(); mPointFList.add(new PointF(0, 500)); mPointFList.add(new PointF(100, 330)); mPointFList.add(new PointF(200, 280)); mPointFList.add(new PointF(300, 460)); mPointFList.add(new PointF(400, 560)); mPointFList.add(new PointF(500, 200)); mPointFList.add(new PointF(600, 300)); mPointFList.add(new PointF(700, 340));
效果图:
相关参考:
http://www.dxstudio.com/guide_content.aspx?id=70a2b2cf-193e-4019-859c-28210b1da81f
2 三阶贝塞尔曲线绘制
在Android开发中多用二阶或者三阶贝塞尔曲线来绘制曲线,但是大多数情况我们是基于两个点来绘制,当坐标点数量多起来的时候,我们遇到一个难题,如果使用多段贝塞尔曲线来绘制,如何处理两端曲线之间的连接,使得它们过度自然。
感谢郑航,看了他的文章之后,大概了解了如何实现。要使得连续两段的贝塞尔曲线的连接自然,我们需要使得接头处,前后两段曲线的曲线率相同。
如果我们要绘制P(i)到P(i+1)之间的曲线,那么我们就需要知道两个控制点A和B,那么现在根据上面的原理,我们已经可以得到这两个点。
A.x = P(i).x + (P(i + 1).x - P(i - 1).x) * a;
A.y = P(i).y + (P(i + 1).y - P(i - 1).y) * a;B.x = P(i + 1).x + (P(i + 2).x - P(i).x) * b;
B.y = P(i + 1).y + (P(i + 2).y - P(i).y) * b;
这里的值a和值b可以是任意正数。
我们用java代码来实现:
/** * 根据已知点获取第i个控制点的坐标 * @param pointFList * @param currentIndex * @param ctrlPointA * @param ctrlPointB */ private void getCtrlPoint(List<PointF> pointFList, int currentIndex, PointF ctrlPointA, PointF ctrlPointB) { ctrlPointA.x = pointFList.get(currentIndex).x + (pointFList.get(currentIndex + 1).x - pointFList.get(currentIndex - 1).x) * CTRL_VALUE_A; ctrlPointA.y = pointFList.get(currentIndex).y + (pointFList.get(currentIndex + 1).y - pointFList.get(currentIndex - 1).y) * CTRL_VALUE_A; ctrlPointB.x = pointFList.get(currentIndex + 1).x - (pointFList.get(currentIndex + 2).x - pointFList.get(currentIndex).x) * CTRL_VALUE_B; ctrlPointB.y = pointFList.get(currentIndex + 1).y - (pointFList.get(currentIndex + 2).y - pointFList.get(currentIndex).y) * CTRL_VALUE_B; }
上面我们讲到a和b的值可以是任意正数,但是它们是会影响到最后绘制出来的曲线的效果的。
我们可以对a和b的值取不同值,坐标点依然采用上面例子的数值,然后观察最后绘制出来的曲线图
1)a = b = 0.05f
2)a = b = 0.2f
3) a = b = 0.5f
可以看到,当a和b的值取0.2f的时候,我们通过贝塞尔曲线绘制出来的曲线,是比较平滑的,而且很接近通过样条曲线算法绘制的曲线。
相关参考:
http://www.zheng-hang.com/?id=43
两种方式绘制出来的曲线基本上是一致的,相信其实有更多更有效率的绘制方法,希望能继续补充~
代码demo: https://github.com/82367825/Polyline
- Android-多点绘制平滑曲线
- Android 系列 5.4徒手绘制平滑曲线
- 绘制平滑曲线
- MATLAB绘制平滑曲线
- matlab绘制平滑曲线
- Android 使用贝塞尔曲线将多点连成一条平滑的曲线
- Android贝塞尔曲线 多点
- 通过多点绘制光滑曲线 (as3.0
- 如何使用MATLAB绘制平滑曲线
- swing GeneralPath::cubicTo绘制平滑曲线
- QtCharts_动态图QSplineSeries 绘制平滑曲线
- Android 穿过点画平滑曲线
- 绘制多条平滑曲线(基于二次贝塞尔曲线)
- Android 曲线绘制Demo
- 使用JFreeChart在网页上绘制平滑曲线
- Matlab将散点绘制为平滑曲线的两种方法
- UGUI绘制过多点连续的平滑曲线
- Qt鼠标绘制平滑曲线解决方案(1)
- 清理微信浏览网站的缓存,Cookie
- 1012. 数字分类
- 编写可读代码的艺术读书整理
- HDU1056
- 前端经典总结(二)
- Android-多点绘制平滑曲线
- 2017夏天之哪凉快去哪里 之二
- Qt Creator使用记录
- Spring Boot 集成Swagger
- unity3d 使用Helios渲染360度全景视频
- 20170724_Linux常用基本命令
- exercise4
- es6学习
- VIM 打开文件跳转到底部