美文网首页高级UI自定义view
Android 使用贝塞尔曲线将多点连成一条平滑的曲线

Android 使用贝塞尔曲线将多点连成一条平滑的曲线

作者: fxzou | 来源:发表于2018-12-05 17:32 被阅读176次

    本文主要讲解怎么用贝塞尔曲线将多点连成一条平滑的曲线,若不了解贝塞尔曲线的同学可以查看这里

    先看效果

    不带辅助线
    带辅助线

    确定控制点

    使用贝塞尔曲线,我们就要先找出它的控制点,笔者Google后发现了此篇文章,文章中列出了找出控制点的公式

    找出控制点

    注意:
    1.公式中的当前点是线段的起点,文中的当前点指的是线段的终点
    2.公式中的a,b代表曲线的弯曲指数,越大代表曲线越弯,一般设置0.16

    从公式中可以发现,确定当前点的控制点,需要用到当前点的前两个点和下一个点四个点,那么当当前点是第一个点,第二个点和最后一个点时,我们就无法获取到全部点,那篇文章中又指出


    找出控制点

    第二种方法过于复杂,文中使用的是第一中方法,即用当前点的值表示无法获取到的点的值,
    下面列出代码:

        private void measurePath() {
            //保存曲线路径
            mPath = new Path();
            //保存辅助线路径
            mAssistPath = new Path();
            float prePreviousPointX = Float.NaN;
            float prePreviousPointY = Float.NaN;
            float previousPointX = Float.NaN;
            float previousPointY = Float.NaN;
            float currentPointX = Float.NaN;
            float currentPointY = Float.NaN;
            float nextPointX;
            float nextPointY;
    
            final int lineSize = mPointList.size();
            for (int valueIndex = 0; valueIndex < lineSize; ++valueIndex) {
                if (Float.isNaN(currentPointX)) {
                    Point point = mPointList.get(valueIndex);
                    currentPointX = point.x;
                    currentPointY = point.y;
                }
                if (Float.isNaN(previousPointX)) {
                    //是否是第一个点
                    if (valueIndex > 0) {
                        Point point = mPointList.get(valueIndex - 1);
                        previousPointX = point.x;
                        previousPointY = point.y;
                    } else {
                        //是的话就用当前点表示上一个点
                        previousPointX = currentPointX;
                        previousPointY = currentPointY;
                    }
                }
    
                if (Float.isNaN(prePreviousPointX)) {
                    //是否是前两个点
                    if (valueIndex > 1) {
                        Point point = mPointList.get(valueIndex - 2);
                        prePreviousPointX = point.x;
                        prePreviousPointY = point.y;
                    } else {
                        //是的话就用当前点表示上上个点
                        prePreviousPointX = previousPointX;
                        prePreviousPointY = previousPointY;
                    }
                }
    
                // 判断是不是最后一个点了
                if (valueIndex < lineSize - 1) {
                    Point point = mPointList.get(valueIndex + 1);
                    nextPointX = point.x;
                    nextPointY = point.y;
                } else {
                    //是的话就用当前点表示下一个点
                    nextPointX = currentPointX;
                    nextPointY = currentPointY;
                }
    
                if (valueIndex == 0) {
                    // 将Path移动到开始点
                    mPath.moveTo(currentPointX, currentPointY);
                    mAssistPath.moveTo(currentPointX, currentPointY);
                } else {
                    // 求出控制点坐标
                    final float firstDiffX = (currentPointX - prePreviousPointX);
                    final float firstDiffY = (currentPointY - prePreviousPointY);
                    final float secondDiffX = (nextPointX - previousPointX);
                    final float secondDiffY = (nextPointY - previousPointY);
                    final float firstControlPointX = previousPointX + (lineSmoothness * firstDiffX);
                    final float firstControlPointY = previousPointY + (lineSmoothness * firstDiffY);
                    final float secondControlPointX = currentPointX - (lineSmoothness * secondDiffX);
                    final float secondControlPointY = currentPointY - (lineSmoothness * secondDiffY);
                    //画出曲线
                    mPath.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
                            currentPointX, currentPointY);
                    //将控制点保存到辅助路径上
                    mAssistPath.lineTo(firstControlPointX, firstControlPointY);
                    mAssistPath.lineTo(secondControlPointX, secondControlPointY);
                    mAssistPath.lineTo(currentPointX, currentPointY);
                }
    
                // 更新值,
                prePreviousPointX = previousPointX;
                prePreviousPointY = previousPointY;
                previousPointX = currentPointX;
                previousPointY = currentPointY;
                currentPointX = nextPointX;
                currentPointY = nextPointY;
            }
            mPathMeasure = new PathMeasure(mPath, false);
        }
    

    参考博客 http://blog.csdn.net/u011102153/article/details/52039794 部分源码拷贝了该项目的源码
    完整代码 https://github.com/zFxiang/BezierDemo
    笔者还属于学习阶段,若文中有错误,还请赐教

    相关文章

      网友评论

        本文标题:Android 使用贝塞尔曲线将多点连成一条平滑的曲线

        本文链接:https://www.haomeiwen.com/subject/adpwcqtx.html