有一個n邊形,頂點爲p1,p2,...,pn;給定一個已知點p,判斷p在此多邊形內還是外。
預備知識: 兩線段相交的定義,如果一條線段的兩端分別處在另一條線段的兩端,則此兩線段相交
判斷2點在線段的兩側可以用向量的叉乘實現!
基本步驟:
1,過p點垂直向上作一條射線
2,判斷此射線與n邊形n條邊的交點
3,把所有交點相加,如果是奇數則說明在多邊形內,否則在多邊形外
思路非常的簡單,另外說明一下幾種特殊的情況:
1,射線與多邊形的頂點相交;比如射線過多邊形的Pi點,則如果Pi-1和Pi+1在此射線的異側,此交點可以算一個,如果此兩點在射線的同側,則此交點不計。此結論非常簡單,畫個圖應該就能明白了
2,p點在多邊形的某一條邊上;也認爲p在多邊形中
3,p不在多邊形的邊上,但p的射線與多邊形的某一條邊重合;比如與Pi,Pi+1線段重合,則如果Pi-1和Pi+2在射線的兩側,此情況也算一個交點,否則此情況不計交點。跟一種的情況類似,畫個圖應該明白了!
順便提一下點在平面細圖中的判斷
平面細圖就是有m個多邊形構成,但任何兩個多邊形都沒有邊的相交,只有頂點的重合
這樣相當於就是調用m次點在多邊形中的算法
以上實現是非常簡單了,偶最近在看並行算法方面的東東,因此本篇主要是爲並行算法作準備的
還可參考:http://www.cppblog.com/w2001/archive/2007/09/06/31694.html
判斷點是否處於多邊形內的三種方法
1. 叉乘判別法
(只適用於凸多邊形)
想象一個凸多邊形,其每一個邊都將整個2D屏幕劃分成爲左右兩邊,連接每一邊的第一個端點和要測試的點得到一個矢量v,將兩個2維矢量擴展成3維的,然後將該邊與v叉乘,判斷結果3維矢量中Z分量的符號是否發生變化,進而推導出點是否處於凸多邊形內外。這裏要注意的是,多邊形頂點究竟是左手序還是右手序,這對具體判斷方式有影響。
2. 面積判別法
(只適用於凸多邊形)
第四點分別與三角形的兩個點組成的面積分別設爲S1,S2,S3,只要S1+S2+S3>原來的三角形面積就不在三角形範圍中.可以使用海倫公式 。推廣一下是否可以得到面向凸多邊形的算法?(不確定)
3. 角度和判別法
(適用於任意多邊形)
double angle = 0;
realPointList::iterator iter1 = points.begin();
for (realPointList::iterator iter2 = (iter1 + 1); iter2 < points.end(); ++iter1, ++iter2)
{
double x1 = (*iter1).x - p.x;
double y1 = (*iter1).y - p.y;
double x2 = (*iter2).x - p.x;
double y2 = (*iter2).y - p.y;
angle += angle2D(x1, y1, x2, y2);
}
if (fabs(angle - span::PI2) < 0.01) return true;
else return false;
另外,可以使用bounding box來加速。
if (p.x < (*iter)->boundingBox.left ||
p.x > (*iter)->boundingBox.right ||
p.y < (*iter)->boundingBox.bottom ||
p.y > (*iter)->boundingBox.top) 。。。。。。
對於多邊形來說,計算bounding box非常的簡單。只需要把水平和垂直方向上的最大最小值找出來就可以了。
對於三角形:第四點分別與三角形的兩個點的交線組成的角度分別設爲j1,j2,j3,只要j1+j2+j3>360就不在三角形範圍中。
4. 水平/垂直交叉點數判別法
(適用於任意多邊形)
注意到如果從P作水平向左的射線的話,如果P在多邊形內部,那麼這條射線與多邊形的交點必爲奇數,如果P在多邊形外部,則交點個數必爲偶數(0也在內)。所以,我們可以順序考慮多邊形的每條邊,求出交點的總個數。還有一些特殊情況要考慮。假如考慮邊(P1,P2),
1)如果射線正好穿過P1或者P2,那麼這個交點會被算作2次,處理辦法是如果P的從座標與P1,P2中較小的縱座標相同,則直接忽略這種情況
2)如果射線水平,則射線要麼與其無交點,要麼有無數個,這種情況也直接忽略。
3)如果射線豎直,而P0的橫座標小於P1,P2的橫座標,則必然相交。
4)再判斷相交之前,先判斷P是否在邊(P1,P2)的上面,如果在,則直接得出結論:P再多邊形內部。
(引用 http://blog.sina.com.cn/s/blog_62986cd40100gjv2.html?retcode=0 )
實現:
語法:result=insidepolygon(Point *polygon,int N,Point p);
參數:
*polygon:
多邊形頂點數組
N: 多邊形頂點個數
p: 被判斷點
返回值: 0:點在多邊形內部;1:點在多邊形外部
注
意:
若p點在多邊形頂點或者邊上,返回值不確定,需另行判斷
需要 math.h
源程序:
#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x :
y)
typedef struct {
double x,y;
} Point;
int insidepolygon(Point *polygon,int N,Point p)
{
int
counter = 0;
int i;
double xinters;
Point p1,p2;
p1 = polygon[0];
for (i=1;i<=N;i++) {
p2 =
polygon[i % N];
if (p.y > MIN(p1.y,p2.y)) {
if (p.y <= MAX(p1.y,p2.y)) {
if (p.x <=
MAX(p1.x,p2.x)) {
if (p1.y != p2.y) {
xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
if (p1.x == p2.x || p.x <= xinters)
counter++;
}
}
}
}
p1 = p2;
}
if (counter % 2 == 0)
return(OUTSIDE);
else
return(INSIDE);
}
(引用:http://fengyan1974.blog.sohu.com/53913983.html)