14

CALyerAnimation @"StrokeStart" および @"strokeEnd" でアニメーション化している多くの UIBezierPath があります。

アニメーションがすべてのパスで同じ速度になることを願っているので、パスの長さを次のように使用すると思います。

距離 / 時間 = 速度

パスの「長さ」を計算する方法はありますか?

ありがとう

シャニ

4

1 に答える 1

9

ベジエ パスの長さは数値的に積分することで計算できますが、パスを線形セグメントに分割することではるかに簡単に計算できます。セグメントが十分に小さい場合、特にアニメーション化しようとしている場合は、近似誤差は無視できるはずです。

四角形曲線の関数を示しますが、三次曲線のソリューションも簡単に組み込むことができます。

- (float) bezierCurveLengthFromStartPoint: (CGPoint) start toEndPoint: (CGPoint) end withControlPoint: (CGPoint) control
{
    const int kSubdivisions = 50;
    const float step = 1.0f/(float)kSubdivisions;

    float totalLength = 0.0f;
    CGPoint prevPoint = start;

    // starting from i = 1, since for i = 0 calulated point is equal to start point
    for (int i = 1; i <= kSubdivisions; i++)
    {
        float t = i*step;

        float x = (1.0 - t)*(1.0 - t)*start.x + 2.0*(1.0 - t)*t*control.x + t*t*end.x;
        float y = (1.0 - t)*(1.0 - t)*start.y + 2.0*(1.0 - t)*t*control.y + t*t*end.y;

        CGPoint diff = CGPointMake(x - prevPoint.x, y - prevPoint.y);

        totalLength += sqrtf(diff.x*diff.x + diff.y*diff.y); // Pythagorean

        prevPoint = CGPointMake(x, y);
    }

    return totalLength;
}

編集

パス コントロール ポイントにアクセスできない場合 (たとえば、アークを使用してパスを作成したとします) は、CGPathApply関数を使用して基になるベジエ曲線にいつでもアクセスできます。

- (void) testPath
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointZero];
    [path addQuadCurveToPoint:CGPointMake(1, 1) controlPoint:CGPointMake(-2, 2)];

    CGPathRef p = path.CGPath;

    CGPathApply(p, nil, pathFunction);
}

void pathFunction(void *info, const CGPathElement *element)
{
    if (element->type == kCGPathElementAddQuadCurveToPoint)
    {
        CGPoint p;
        p = element->points[0]; // control point
        NSLog(@"%lg %lg", p.x, p.y);

        p = element->points[1]; // end point
        NSLog(@"%lg %lg", p.x, p.y);
    }
    // check other cases as well!
}

パスの開始点は提供されませんが、自分で簡単に追跡できることに注意してください。

于 2012-08-19T07:37:57.260 に答える