我有一个允许用户绘制形状的代码,我正在使用UIBezierPath。但我需要看看形状是否自相交,例如:http://upload.wikimedia.org/wikipedia/commons/0/0f/Complex_polygon.svg 那它不是一个有效的形状。 我怎么能找到这个?
编辑: 我还没有解决这个问题。我保存数组中路径中的所有点之间的所有点。然后我遍历数组并尝试查找是否有任何线相交。但是它不起作用,有时它会说它有一个交叉点而不是。
我认为问题出在这个方法的某个地方。
-(BOOL)pathIntersects:(double *)x:(double *)y {
int count = pathPoints.count;
CGPoint p1, p2, p3, p4;
for (int a=0; a<count; a++) {
//Line 1
if (a+1<count) {
p1 = [[pathPoints objectAtIndex:a] CGPointValue];
p2 = [[pathPoints objectAtIndex:a+1] CGPointValue];
}else{
return NO;
}
for (int b=0; b<count; b++) {
//Line 2
if (b+1<count) {
p3 = [[pathPoints objectAtIndex:b] CGPointValue];
p4 = [[pathPoints objectAtIndex:b+1] CGPointValue];
}else{
return NO;
}
if (!CGPointEqualToPoint(p1, p3) && !CGPointEqualToPoint(p2, p3) && !CGPointEqualToPoint(p4, p1) && !CGPointEqualToPoint(p4, p2)
&& !CGPointEqualToPoint(p1, p2) && !CGPointEqualToPoint(p3, p4)) {
if (LineIntersect(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, x, y)) {
return YES;
}
}
}
}
return NO;
}
这是我发现看到两条线是否相交的代码,它在C中,但我应该工作。
int LineIntersect(
double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4,
double *x, double *y)
{
double mua,mub;
double denom,numera,numerb;
denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1);
numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
/* Are the line coincident? */
if (ABS(numera) < 0.00001 && ABS(numerb) < 0.00001 && ABS(denom) < 0.00001) {
*x = (x1 + x2) / 2;
*y = (y1 + y2) / 2;
return(TRUE);
}
/* Are the line parallel */
if (ABS(denom) < 0.00001) {
*x = 0;
*y = 0;
return(FALSE);
}
/* Is the intersection along the the segments */
mua = numera / denom;
mub = numerb / denom;
if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
*x = 0;
*y = 0;
return(FALSE);
}
*x = x1 + mua * (x2 - x1);
*y = y1 + mua * (y2 - y1);
return(TRUE);
}
答案 0 :(得分:3)
这取决于用户绘制的多边形的复杂程度以及路径中的点数。理想情况下,形状中的所有顶点都会有一个点,仅此而已。从UIBezierPath获取CGPath并使用GCPathApply将元素传递给函数,该函数将每个点添加到数组。遍历数组有两个for循环,一个嵌套在另一个循环中,它使用标准的线 - 线交叉测试后检查每个线段与每个线段。一旦找到交叉点,就从循环中断开。或者,如果这是一种方便的方法,则返回BOOL。这是最简单的方法。
编辑:这是一个线 - 线交叉函数的例子,它返回一个BOOL,告诉你两个段是否交叉。传递创建第一个分段的两个点,然后是构成第二个分段的两个点。它是从我在网上快速找到的一段源代码中匆匆修改过来的,但它确实有效。
CGPoint lineSegmentsIntersect(CGPoint L1P1, CGPoint L1P2, CGPoint L2P1, CGPoint L2P2)
{
float x1 = L1P1.x, x2 = L1P2.x, x3 = L2P1.x, x4 = L2P2.x;
float y1 = L1P1.y, y2 = L1P2.y, y3 = L2P1.y, y4 = L2P2.y;
float bx = x2 - x1;
float by = y2 - y1;
float dx = x4 - x3;
float dy = y4 - y3;
float b_dot_d_perp = bx * dy - by * dx;
if(b_dot_d_perp == 0) {
return NO;
}
float cx = x3 - x1;
float cy = y3 - y1;
float t = (cx * dy - cy * dx) / b_dot_d_perp;
if(t < 0 || t > 1) {
return NO;
}
float u = (cx * by - cy * bx) / b_dot_d_perp;
if(u < 0 || u > 1) {
return NO;
}
return YES;
}
你可以这样使用它。
if (lineSegmentsIntersect(lineOnePointOne,lineOnePointTwo,lineTwoPointOne,lineTwoPointTwo)){
//segments intersect
} else {
//segments did not intersect
}
由您来创建双循环来检查彼此之间的正确段。