检测点是否在SVG路径中 [英] Detecting wether a point is inside a SVG Path

查看:231
本文介绍了检测点是否在SVG路径中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图检测一个给定的点是否在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
pre>

通过以下两个函数,程序集中的Xcode和 EXC_BAD_ACCESS : get_y_inflections get_cubic_coefficients



编辑2: p>

我发布了新问题 containsPoint:问题。

解决方案

所以,因为我需要一个Polygon /从弯曲的路径插入我自己,我可能也有解决您的问题的方法:



这两个'Public'函数:
$ b $ p code $ 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;
诠释质量;
} 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 int 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);
休息;
case kCGPathElementAddLineToPoint:
CGPathAddLineToPoint(interpInfo-> path,NULL,element-> points [0] .x,element-> points [0] .y);
休息;
case kCGPathElementAddQuadCurveToPoint:{
int nr = interpInfo-> quality;
CGPoint缓冲区[nr];
pointsForQuadCurve(CGPathGetCurrentPoint(interpInfo->路径),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缓冲区[nr]; (CGPathGetCurrentPoint(interpInfo->路径),元素 - >点[0],元素 - >点[1],元素 - >点[2],缓冲区,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;



static CGPathRef CGPathCreatePolygonPath(CGPathRef path,int quality){
CGMutablePathRef newPath = CGPathCreateMutable();
InterpolationInfo info;
info.path = newPath;
info.quality = quality;
CGPathApply(path,& info,CGPathElementConvertToPolygon);
返回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);
返回returnValue;
}


I'm trying to detecting wether a given point is inside a closed SVG path in Objective-C. I'm having trouble figuring out how to do the math.

I have a path's coordinates and I'd like to determine wether a random point is inside or outside the path.

Here's an example of a path's coordinates:

"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:"

I'm aware of the CoreGraphics's containsPoint: method, but I'd like to avoid using this method.

How can I do this by writing my own method?

EDIT:

I'm trying to avoid containsPoint: because the function seems to crash on some coordinates / paths when using it. It looks quite random when it crashes and when it doesn't.

Here are some examples of paths where containsPoint: makes the app crash:

"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 breaks with and EXC_BAD_ACCESS in the assembly by the following two functions: get_y_inflections and get_cubic_coefficients.

EDIT 2:

I posted a new question about the containsPoint: problem.

解决方案

So, as i needed a Polygon/Interpolation from a Curved Path myself, i might have a solution for your problem as well:

The two 'Public' Functions:

CGPathRef CGPathCreatePolygonPath(CGPathRef path, int quality);

Creates an Path with only Line-Elements, quality is the number of segments a curve is split into

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

Does CGPathContainsPoint and Interpolation in one step, quality is again the number of segments a curve is split into.

Here is the implementation.

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

这篇关于检测点是否在SVG路径中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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