我正在尝试检测给定点是否在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
打破:get_y_inflections
和get_cubic_coefficients
。
编辑2:
我发布了关于containsPoint:
问题的new question。
答案 0 :(得分:1)
因此,由于我自己需要从弯曲路径进行多边形/插值,我也可以为您的问题找到解决方案:
两个“公共”功能:
CGPathRef CGPathCreatePolygonPath(CGPathRef path, int quality);
创建仅包含线元素的路径,质量是曲线分割为的段数
BOOL CGPathContainsPointInterpolated(CGPathRef path, const CGAffineTransform *m, CGPoint point, bool eoFill, int quality);
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;
}