2012-09-12 79 views
3

我试图检测给定点是否在Objective-C中的封闭SVG路径内。我很难搞清楚如何做数学。检测点是否在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由以下两个功能:get_y_inflectionsget_cubic_coefficients

编辑2:

我发布了new question有关containsPoint:问题。

+0

我会推荐使用光线投射算法(请参阅Findus'答案中的链接)。 –

+0

为什么要避免使用'CGPathContainsPoint()'的特殊原因?此外,您似乎没有多边形,因为您的路径使用曲线。 –

+0

@JonathanCichon我想避免这种情况,因为当使用'CGPathContainsPoint()'时,函数似乎在一些坐标/路径上崩溃。当它崩溃时它看起来非常随机,当它不崩溃时它看起来很随机。 –

回答

1

所以,当我从曲线路径需要一个多边形/插值自己,我可能对您的问题以及解决方案:

两个“公共”功能:

CGPathRef CGPathCreatePolygonPath(CGPathRef path, int quality);

创建具有仅线路元素的路径,质量是一个曲线被分成

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

段的数量0

CGPathContainsPoint和Interpolation是否在一个步骤中,质量又是一条曲线分割成的段数。

这是实施。

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; 
} 
+0

这解决了问题!谢谢! –