美文网首页
根据点串绘制圆滑贝塞尔曲线

根据点串绘制圆滑贝塞尔曲线

作者: halobear | 来源:发表于2019-06-27 14:33 被阅读0次

    - (UIBezierPath*)pathForPoints:(NSArray*)allPoints {

        UIBezierPath *path = [UIBezierPath bezierPath];

        CGFloatmLineSmoothness =0.18;

        CGFloatprePreviousPointX;

        CGFloatprePreviousPointY;

        CGFloatpreviousPointX;

        CGFloatpreviousPointY;

        CGFloatcurrentPointX;

        CGFloatcurrentPointY;

        CGFloatnextPointX;

        CGFloatnextPointY;

        for(inti =0; i < allPoints.count; i++) {

            CGPointcurrentPoint = [allPoints[i]CGPointValue];

            currentPointX = currentPoint.x;

            currentPointY = currentPoint.y;

            if(i >0) {

                CGPointprePoint = [allPoints[i-1]CGPointValue];

                previousPointX = prePoint.x;

                previousPointY = prePoint.y;

            }else{

                previousPointX = currentPointX;

                previousPointY = currentPointY;

            }

            if(i >1) {

                CGPointprePrePoint = [allPoints[i-2]CGPointValue];

                prePreviousPointX = prePrePoint.x;

                prePreviousPointY = prePrePoint.y;

            }

            if(i < allPoints.count-1) {

                CGPointnextPoint = [allPoints[i+1]CGPointValue];

                nextPointX = nextPoint.x;

                nextPointY = nextPoint.y;

            }else{

                nextPointX = currentPointX;

                nextPointY = currentPointY;

            }

            if(i ==0) {

                [pathmoveToPoint:currentPoint];

            }else{

                CGFloatfirstDiffX = (currentPointX - prePreviousPointX);

                CGFloatfirstDiffY = (currentPointY - prePreviousPointY);

                CGFloatsecondDiffX = (nextPointX - previousPointX);

                CGFloatsecondDiffY = (nextPointY - previousPointY);

                CGFloatfirstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);

                CGFloatfirstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);

                CGFloatsecondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);

                CGFloatsecondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);

                [pathaddCurveToPoint:CGPointMake(currentPointX, currentPointY)controlPoint1:CGPointMake(firstControlPointX, firstControlPointY)controlPoint2:CGPointMake(secondControlPointX, secondControlPointY)];//三次曲线

            }

            // 更新

            prePreviousPointX = previousPointX;

            prePreviousPointY = previousPointY;

            previousPointX = currentPointX;

            previousPointY = currentPointY;

            currentPointX = nextPointX;

            currentPointY = nextPointY;

        }

        returnpath;

    }

    - (UIBezierPath*)pathForPoints:(NSArray*)allPoints {

        UIBezierPath *path = [UIBezierPath bezierPath];

        //下面的方法效果更好,但是只支持4个点及以上情况

        if(allPoints.count<4) {

            [pathmoveToPoint:[allPoints[0]CGPointValue]];

            CGPointPrePonit;

            for(inti =0; i < allPoints.count; i++) {

                CGPointpoint = [allPoints[i]CGPointValue];

                point =CGPointMake(point.x, point.y);

                if(i ==0) {

                    PrePonit = point;

                }else{

                    CGPointNowPoint = [allPoints[i]CGPointValue];

                    [pathaddCurveToPoint:NowPointcontrolPoint1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y)controlPoint2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)];//三次曲线

                    PrePonit = NowPoint;

                }

            }

        }else{

            NSIntegergranularity =10;

            [pathmoveToPoint:[allPoints[0]CGPointValue]];

            [pathaddLineToPoint:[allPoints[1]CGPointValue]];

            for(intindex =3; index < allPoints.count; index++) {

                CGPointp0 = [allPoints[index -3]CGPointValue];

                CGPointp1 = [allPoints[index -2]CGPointValue];

                CGPointp2 = [allPoints[index -1]CGPointValue];

                CGPointp3 = [allPoints[index]CGPointValue];

                for(inti =1; i < granularity; i++) {

                    floatt = (float)i * (1.0/ granularity);

                    floattt = t * t;

                    floatttt = tt * t;

                    CGPointpi;

                    pi.x=0.5* (2* p1.x+(p2.x- p0.x) * t +(2* p0.x-5* p1.x+4*p2.x- p3.x) * tt + (3* p1.x- p0.x-3*p2.x+ p3.x) *ttt );

                    pi.y=0.5* (2* p1.y+(p2.y- p0.y) * t +(2* p0.y-5* p1.y+4*p2.y- p3.y) * tt + (3* p1.y- p0.y-3*p2.y+ p3.y) *ttt );

                    [pathaddLineToPoint:pi];

                }

                [pathaddLineToPoint:p2];

            }

            [pathaddLineToPoint:[allPoints[allPoints.count-1]CGPointValue]];

        }

        returnpath;

    }

    在这里采用的是Catmull-Rom插值技术实现的,其实就是一个比较特殊的贝塞尔曲线,如果想用这个方式进行插值,那么在这个曲线上最少要有4个点存在,因为这种方式只能在中间的两个点进行插值,例如有4个点分别是p0、p1、p2、p3依次在这个贝塞尔曲线上,那么我们积可以将值插到p1、p2之间,在上面的代码中可以看到变量t,t的范围是[0,1],当t=0到t=1变化,那么曲线就会从p1(t=0)到p2(t=1)运动,计算出来的点的切向量和这个点的周围两个起点和终点的切向量是平行的,那么如果想要使曲线更加的平滑,那么就要取到更多的点p0、p1、p2、p3、p4,这样就可以有两组分别是p0、p1、p2、p3和p1、p2、p3、p4,就能够在p1、p2和p2、p3之间进行插值,以此类推,使曲线更加的平滑

    相关文章

      网友评论

          本文标题:根据点串绘制圆滑贝塞尔曲线

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