展平CGPath [英] Flattening a CGPath

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

问题描述

简而言之,我正在寻找与NSBezierPath的 -bezierPathByFlatteningPath 相同的东西,可以在iOS上使用。对我而言,这是直接处理CGPath的函数还是UIBezierPath上的方法,对我来说都没有关系,因为可以轻松地将两者相互转换。 CGPath参考和< href = https://developer.apple.com/library/ios/documentation/uikit/reference/UIBezierPath_class/Reference/Reference.html rel = nofollow> UIBezierPath类参考表示存在任何这样的函数或方法。

Simply put, I'm looking for an equivalent to NSBezierPath's -bezierPathByFlatteningPath that can be used on iOS. It doesn't matter to me whether this is a function dealing directly with a CGPath or a method on UIBezierPath, because the two can easily be converted back and forth. Neither the CGPath Reference nor the UIBezierPath Class Reference indicate the presence of any such function or method.

另外:我知道CGPath的 CGPathApply 函数,而且我俩都没有时间以及通过在 CGPathApplierFunction 中遍历路径元素来实现我自己的展平算法的技能。我正在寻找对此的现有解决方案-应用程序函数,UIBezierPath上的类别等。肯定存在。

Also: I'm aware of CGPath's CGPathApply function, and I lack both the time and the skill-set to implement my own flattening algorithm by iterating over the path's elements in a CGPathApplierFunction. I'm looking for an existing solution to this—an applier function, a category on UIBezierPath, etc. Surely one exists.

推荐答案

Erica Sadun提供了一组有用的函数来处理UIBezierPath和CGPathRef。

Erica Sadun provides a set of useful functions to deal with UIBezierPath and CGPathRef.

此代码用于这本书

她没有提供CGPathRef展平的实现,但是可以使用轻松实现可以在此处找到的函数:
https://github.com/erica/iOS-Drawing/blob/master/C05/Quartz%20Book%20Pack/Bezier/BezierFunctions.m

She does not provide an implementation of a CGPathRef flattening, but it can be easily done using functions that can be found here: https://github.com/erica/iOS-Drawing/blob/master/C05/Quartz%20Book%20Pack/Bezier/BezierFunctions.m

特别是,这些函数将有助于离散非线性贝塞尔曲线段:

Particulary, these functions will help discretize the non linear Bezier segments:

float CubicBezier(float t, float start, float c1, float c2, float end)
float QuadBezier(float t, float start, float c1, float end)
CGPoint CubicBezierPoint(CGFloat t, CGPoint start, CGPoint c1, CGPoint c2, CGPoint end);
CGPoint QuadBezierPoint(CGFloat t, CGPoint start, CGPoint c1, CGPoint end);

因此,基本上,初始化一个空的CGMutablePathRef,并对原始路径中的每个CGPath元素进行复制如果它是线性的,或者根据Bezier细分的程度离散化。

So basically, initialize an empty CGMutablePathRef, and for each CGPath element in the original path, either copy it if it's linear, or discretize it according to the degree of the Bezier segment.

您可能还希望应用 Ramer–Douglas–Peucker算法可以删除不必要的点。

You may also want to apply the Ramer–Douglas–Peucker algorithm to remove unnecessary points.

您还可以直接使用:-(NSArray *)interpolatedPathPoints 返回可以使用的点的NSArray建立路径的近似值。该算法很幼稚,因此在例如三次Bezier路径为线性(如果控制点对齐)的情况下,您必须简化结果;像以前一样,Ramer–Douglas–Peucker算法可以完成这项工作。

You could also directly use: - (NSArray *) interpolatedPathPoints which returns an NSArray of points which can be used to build an approximation of the path. The algorithm is naive, so you have to simplify the result in the case, e.g , where a cubic Bezier path would be linear (if the control points are aligned); just as before, Ramer–Douglas–Peucker algorithm does the job.

这里是实际离散化的样子。代码不是自包含的,您必须使用所有依赖项。

Here is what the actual discretization looks like. Code is not self contained, you'll have to use all dependencies.

- (NSArray *) interpolatedPathPoints
{
    NSMutableArray *points = [NSMutableArray array];
    BezierElement *current = nil;
    int overkill = 3;
    for (BezierElement *element in self.elements)
    {
        switch (element.elementType)
        {
            case kCGPathElementMoveToPoint:
            case kCGPathElementAddLineToPoint:
                [points addObject:[NSValue valueWithCGPoint:element.point]];
                current = element;
                break;
            case kCGPathElementCloseSubpath:
                current = nil;
                break;
            case kCGPathElementAddCurveToPoint:
            {
                for (int i = 1; i < NUMBER_OF_BEZIER_SAMPLES * overkill; i++)
                {
                    CGFloat percent = (CGFloat) i / (CGFloat) (NUMBER_OF_BEZIER_SAMPLES * overkill);
                    CGPoint p = CubicBezierPoint(percent, current.point, element.controlPoint1, element.controlPoint2, element.point);
                    [points addObject:[NSValue valueWithCGPoint:p]];
                }
                [points addObject:[NSValue valueWithCGPoint:element.point]];
                current = element;
                break;
            }
            case kCGPathElementAddQuadCurveToPoint:
            {
                for (int i = 1; i < NUMBER_OF_BEZIER_SAMPLES * overkill; i++)
                {
                    CGFloat percent = (CGFloat) i / (CGFloat) (NUMBER_OF_BEZIER_SAMPLES * overkill);
                    CGPoint p = QuadBezierPoint(percent, current.point, element.controlPoint1, element.point);
                    [points addObject:[NSValue valueWithCGPoint:p]];
                }
                [points addObject:[NSValue valueWithCGPoint:element.point]];
                current = element;
                break;
            }
        }
    }
    return points;
}

代码属于Erica Sadun。完整的实现请参见此处: https://github.com/erica/iOS-Drawing

Code belongs to Erica Sadun. See here for the complete implementation: https://github.com/erica/iOS-Drawing

Rob Napier还在 iOS 6突破极限,第26章
精美文本布局。他并没有试图展平完整的UIBezierPath,只有一条定义了四个点的立方贝塞尔曲线路径,但实际上这是同一件事(离散贝塞尔曲线路径)
另外,您可能会发现本文很有趣: http://robnapier.net/faster-bezier

Rob Napier also wrote about Bezier curves in iOS 6 Pushing the limits, Chapter 26 Fancy Text Layout. He was not trying to flatten a full UIBezierPath, only one cubic Bezier path defined with four points, but really that's exactly the same thing (discretizing a Bezier path) Also, you may find this article interesting: http://robnapier.net/faster-bezier

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

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