簡體   English   中英

三次貝塞爾曲線在iOS和JavaScript中有所不同

[英]cubic bezier cuve different in ios and javascript

背景:

在我的應用程序中,我必須沿着用戶點擊屏幕的點繪制一條曲線。 我在下面的博客中找到了該博客,該博客解釋了如何根據貝塞爾曲線的路徑點計算控制點。

樣條插值-規模創新

該示例使用javascript,我將其調整為適用於iOS。 以下是我在應用程序中使用的代碼

void (^calculateAndAddControlPoints)(CGPoint firstPoint, CGPoint secondPoint, CGPoint thirdPoint) = ^void (CGPoint firstPoint, CGPoint secondPoint, CGPoint thirdPoint)
{
    CGPoint controlPoint1;
    CGPoint controlPoint2;

    CGFloat distance12 = sqrt(pow(firstPoint.x-secondPoint.x, 2) + pow(firstPoint.y-secondPoint.y, 2));
    CGFloat distance23 = sqrt(pow(secondPoint.x-thirdPoint.x, 2) + pow(secondPoint.y-thirdPoint.y, 2));
    CGFloat scallingFactor12 = (tension * distance12) / (distance12 + distance23);
    CGFloat scallingFactor23 = tension - scallingFactor12;

    controlPoint1.x = secondPoint.x - (scallingFactor12 * (thirdPoint.x - firstPoint.x));
    controlPoint1.y = secondPoint.y - (scallingFactor12 * (thirdPoint.y - firstPoint.y));
    controlPoint2.x = secondPoint.x + (scallingFactor23 * (thirdPoint.x - firstPoint.x));
    controlPoint2.y = secondPoint.y + (scallingFactor23 * (thirdPoint.y - firstPoint.y));

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:controlPoint1];
    [path addLineToPoint:controlPoint2];
    [path stroke];

    [controlPoints addObject:[NSValue valueWithCGPoint:controlPoint1]];
    [controlPoints addObject:[NSValue valueWithCGPoint:controlPoint2]];
};
NSUInteger curvePointsCount = [curvePoints count];
if (_closed) {
    NSValue *lastPoint = [curvePoints lastObject];
    [curvePoints addObject:curvePoints[0]];
    [curvePoints addObject:curvePoints[1]];
    [curvePoints insertObject:lastPoint atIndex:0];
    for (NSInteger i=0; i < curvePointsCount; ++i) {
        calculateAndAddControlPoints([curvePoints[i + 0] CGPointValue],
                                     [curvePoints[i + 1] CGPointValue],
                                     [curvePoints[i + 2] CGPointValue]);
    }
    [controlPoints addObject:controlPoints[0]];
    [controlPoints addObject:controlPoints[1]];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:[curvePoints[1] CGPointValue]];
    for (NSInteger i=1; i < curvePointsCount + 1; ++i) {
        [path addCurveToPoint:[curvePoints[i + 1] CGPointValue]
                controlPoint1:[controlPoints[2 * i + 0] CGPointValue]
                controlPoint2:[controlPoints[2 * i + 1] CGPointValue]];
    }
    [path stroke];
} else {
    for (NSInteger i=0; i < curvePointsCount - 2; ++i) {
        calculateAndAddControlPoints([curvePoints[i + 0] CGPointValue],
                                     [curvePoints[i + 1] CGPointValue],
                                     [curvePoints[i + 2] CGPointValue]);
    }

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:[curvePoints[0] CGPointValue]];
    [path addQuadCurveToPoint:[curvePoints[1] CGPointValue]
                 controlPoint:[controlPoints[0] CGPointValue]];

    for (NSInteger i=1; i < curvePointsCount - 2; ++i) {
        [path addCurveToPoint:[curvePoints[i + 1] CGPointValue]
                controlPoint1:[controlPoints[2 * i + 0] CGPointValue]
                controlPoint2:[controlPoints[2 * i + 1] CGPointValue]];
    }

    [path moveToPoint:[curvePoints[curvePointsCount - 2] CGPointValue]];
    [path addQuadCurveToPoint:[curvePoints[curvePointsCount - 1] CGPointValue]
                 controlPoint:[controlPoints[[controlPoints count] - 1] CGPointValue]];
    [path stroke];
}

問題:

iOS中的輸出與JavaScript中的輸出不同,因為您可以看到下面的曲線在路徑點附近不平滑。 白線是實際曲線線,黃線是連接控制點的線,紅點是曲線點。

iOS輸出

這就是javascript中相同曲線的外觀。

JavaScript輸出

使用的曲線點:(100,100),(300,100),(300,300),(100,300)

生成的控制點:(50,150),(150,50),(250,50),(350,150),(350,250),(250,350),(150,350),(50, 250)

為什么我在iOS中找不到圈,如何解決?

解:

事實證明我在正確地計算控制點,但錯誤地將它們映射到曲線點。 感謝@gabbler我現在修復了它,下面是繪制曲線的正確循環

for (NSInteger i=1; i < curvePointsCount + 1; ++i) {
    [_bezierPath moveToPoint:[curvePoints[i] CGPointValue]];
    [_bezierPath addCurveToPoint:[curvePoints[i + 1] CGPointValue]
            controlPoint1:[controlPoints[2 * i - 1] CGPointValue]
            controlPoint2:[controlPoints[2 * i + 0] CGPointValue]];
}

當您添加從(100,100)到(300,100)的曲線時,控制點應為(150,50)和(250,50),在代碼中,控制點應改為(350,150)和(250,50),指定正確的控制點應使其起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM