3

特定のポイントがObjective-Cの閉じたSVGパス内にあるかどうかを検出しようとしています。私は数学のやり方を理解するのに苦労しています。

パスの座標があり、ランダムなポイントがパスの内側にあるか外側にあるかを確認したいと思います。

パスの座標の例を次に示します。

"M673 460 c2 0 4 -1 5 -2 1 -1 2 -2 2 -4 0 -2 0 -3 0 -3 0 0 -3 1 -5 1 -3 1 -5 2 -5 3 0 1 0 3 0 4 1 0 2 1 3 1z:"

CoreGraphicsのメソッドを知っていますがcontainsPoint:、このメソッドの使用は避けたいと思います。

独自のメソッドを作成してこれを行うにはどうすればよいですか?

編集:

containsPoint:関数を使用すると、一部の座標/パスで関数がクラッシュするように見えるため、回避しようとしています。クラッシュしたときとクラッシュしなかったときは、かなりランダムに見えます。

containsPoint:アプリがクラッシュするパスの例を次に示します。

"M661 446 c1 -1 3 -1 4 -1 1 -1 2 -2 2 -4 0 -2 0 -2 -2 -2 0 1 -2 1 -3 1 -2 0 -3 1 -3 2 0 1 0 2 0 3 0 0 1 1 2 1z" 
"M535 460 c0 0 1 -1 1 -2 1 -2 0 -3 -1 -3 0 0 -1 0 -2 1 0 1 0 2 0 3 1 0 1 1 2 1z" 

XcodeはEXC_BAD_ACCESS、次の2つの関数によってアセンブリで中断されます。get_y_inflectionsおよびget_cubic_coefficients

編集2:

問題について新しい質問を投稿しましたcontainsPoint:

4

1 に答える 1

1

したがって、曲線パスからのポリゴン/補間が必要だったので、問題の解決策もあるかもしれません:

2 つの「公開」機能:

CGPathRef CGPathCreatePolygonPath(CGPathRef path, int quality);

線要素のみでパスを作成します。品質は曲線が分割されるセグメントの数です

BOOL CGPathContainsPointInterpolated(CGPathRef path, const CGAffineTransform *m, CGPoint point, bool eoFill, int quality);

CGPathContainsPoint と Interpolation を 1 つのステップで実行しますか? 品質は、曲線が分割されるセグメントの数です。

これが実装です。

typedef struct {
    CGMutablePathRef path;
    int quality;
} InterpolationInfo;

static inline float cubeInterp(float t, float p0, float p1, float p2, float p3) {
    return powf(1-t, 3)*p0 + 3*powf(1-t, 2)*t*p1 + 3*(1-t)*powf(t, 2)*p2 + powf(t, 3)*p3;
}

static void pointsForCubeCurve(CGPoint cp0, CGPoint cp1, CGPoint cp2, CGPoint ep, CGPoint *buffer, int numberPoints) {
    for (int i = 0; i<numberPoints; i++) {
        float t = (i+1)/(float)numberPoints;
        buffer[i] = CGPointMake(cubeInterp(t, cp0.x, cp1.x, cp2.x, ep.x), cubeInterp(t, cp0.y, cp1.y, cp2.y, ep.y));
    }
}

static inline float quadInterp(float t, float p0, float p1, float p2) {
    return powf(1-t, 2)*p0 + 2*(1-t)*t*p1 + powf(t, 2)*p2;
}

static void pointsForQuadCurve(CGPoint cp0, CGPoint cp, CGPoint ep, CGPoint *buffer, int numberPoints) {
    for (int i = 0; i<numberPoints; i++) {
        float t = (i+1)/(float)numberPoints;
        buffer[i] = CGPointMake(quadInterp(t, cp0.x, cp.x, ep.x), quadInterp(t, cp0.x, cp.x, ep.x));
    }
}

static void CGPathElementConvertToPolygon(void *info, const CGPathElement *element) {
    InterpolationInfo *interpInfo = info;
    switch (element->type) {
        case kCGPathElementMoveToPoint:
            CGPathMoveToPoint(interpInfo->path, NULL, element->points[0].x, element->points[0].y);
            break;
        case kCGPathElementAddLineToPoint:
            CGPathAddLineToPoint(interpInfo->path, NULL, element->points[0].x, element->points[0].y);
            break;
        case kCGPathElementAddQuadCurveToPoint: {
            int nr = interpInfo->quality;
            CGPoint buffer[nr];
            pointsForQuadCurve(CGPathGetCurrentPoint(interpInfo->path), element->points[0], element->points[1], buffer, nr);
            for (int i = 0; i<nr; i++) {
                CGPathAddLineToPoint(interpInfo->path, NULL, buffer[i].x, buffer[i].y);
            }
            break;
        }
        case kCGPathElementAddCurveToPoint: {
            int nr = interpInfo->quality;
            CGPoint buffer[nr];
            pointsForCubeCurve(CGPathGetCurrentPoint(interpInfo->path), element->points[0], element->points[1], element->points[2], buffer, nr);
            for (int i = 0; i<nr; i++) {
                CGPathAddLineToPoint(interpInfo->path, NULL, buffer[i].x, buffer[i].y);
            }
            break;
        }
        case kCGPathElementCloseSubpath:
            CGPathCloseSubpath(interpInfo->path);
            break;
        default:
            break;
    }
}

static CGPathRef CGPathCreatePolygonPath(CGPathRef path, int quality) {
    CGMutablePathRef newPath = CGPathCreateMutable();
    InterpolationInfo info;
    info.path = newPath;
    info.quality = quality;
    CGPathApply(path, &info, CGPathElementConvertToPolygon);
    return newPath;
}

static BOOL CGPathContainsPointInterpolated(CGPathRef path, const CGAffineTransform *m, CGPoint point, bool eoFill, int quality) {
    CGPathRef polygon = CGPathCreatePolygonPath(path, quality);
    BOOL returnValue = CGPathContainsPoint(polygon, m, point, eoFill);
    CGPathRelease(polygon);
    return returnValue;
}
于 2012-09-21T19:21:15.567 に答える