获得CGPath总长度 [英] Get CGPath total length

查看:91
本文介绍了获得CGPath总长度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有许多UIBezierPath,我用CALyerAnimation @StrokeStart和@strokeEnd进行动画制作。

I have many UIBezierPath that I am animating with CALyerAnimation @"StrokeStart" and @"strokeEnd".

我希望动画的速度与所有动画相同路径所以我认为我可以使用路径的长度:

I wish that the animation will have the same speed for all the paths so I thougt I might use the length of the path in :


DISTANCE / TIME = SPEED

DISTANCE / TIME = SPEED

有没有办法计算路径长度?

Is there a way to calculate the path "length" ?

谢谢

Shani

推荐答案

虽然你可以通过数字积分计算Bezier路径的长度,但它可以完成通过将路径分成线性段更容易。如果片段足够小,则可以忽略近似误差,尤其是您只是想要为其设置动画。

While you can calculate Bezier path's length by integrating it numerically, it can be done much easier by dividing path into linear segments. If the segments are small enough the approximation error should be neglectable, especially that you are just trying to animate it.

我将向您展示四条曲线的功能,但是你也可以很容易地将立方曲线的解决方案合并:

I'll show you function for quad curves, but you can easily incorporate the solution for cubic curves as well:

- (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 函数访问基础贝塞尔曲线:

If you don't have access to path control points (say you created path using arcs) you can always access underlying Bezier curves using CGPathApply function:

- (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!
}

请注意,它不提供路径的起点,但很容易跟踪它自己。

Note that it doesn't provide the path's start point, but it's easy to keep track of it on your own.

这篇关于获得CGPath总长度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆