計算幾何入門

2021-07-26 12:42:23 字數 4058 閱讀 9813

以下內容由各位大神的部落格提取出來

向量。如果一條線段的端點是有次序之分的,我們把這種線段成為有向線段(directed segment)。如果有向線段p1p2的起點p1在座標原點,我們可以把它稱為向量(vector)p2。
設二維向量p = ( x1, y1 ),q = ( x2 , y2 ),則向量加法定義為: p + q = ( x1 + x2 , y1 + y2 ),同樣的,向量減法定義為: p - q = ( x1 - x2 , y1 - y2 )。顯然有性質 p + q = q + p,p - q = - ( q - p )。
計算向量叉積是與直線和線段相關演算法的核心部分。設向量p = ( x1, y1 ),q = ( x2, y2 ),則向量叉積定義為由(0,0)、p1、p2和p1+p2所組成的平行四邊形的帶符號的面積,即:p × q = x1*y2 - x2*y1,其結果是乙個標量。顯然有性質 p × q = - ( q × p ) 和 p × ( - q ) = - ( p × q )。一般在不加說明的情況下,本文下述演算法中所有的點都看作向量,兩點的加減法就是向量相加減,而點的乘法則看作向量叉積。叉積的乙個非常重要性質是可以通過它的符號判斷兩向量相互之間的順逆時針關係:

若 p × q > 0 , 則p在q的順時針方向。

若 p × q < 0 , 則p在q的逆時針方向。

若 p × q = 0 , 則p與q共線,但可能同向也可能反向。

折線段的拐向判斷方法可以直接由向量叉積的性質推出。對於有公共端點的線段p0p1和p1p2,通過計算(p2 - p0) × (p1 - p0)的符號便可以確定折線段的拐向:

若(p2 - p0) × (p1 - p0) > 0,則p0p1在p1點拐向右側後得到p1p2。

若(p2 - p0) × (p1 - p0) < 0,則p0p1在p1點拐向左側後得到p1p2。

若(p2 - p0) × (p1 - p0) = 0,則p0、p1、p2三點共線。

具體情況可參照下圖:

bool on-segment(int pi,int pj,int pk)
我們分兩步確定兩條線段是否相交:

1.快速排斥試驗:

設以線段 p1p2 為對角線的矩形為 r,設以線段 q1q2 為對角線的矩形為 t,若 r、t 不相交,則兩線段不可能相交

假設 p1 = (x1, y1), p2 = (x2, y2), q1 = (x3, y3), q2 = (x4, y4),設矩形 r 的 x 座標的最小邊界為 minrx = min(x1, x2),以此類推,將矩形表示為 r = (minrx, minry, maxrx, maxry) 的形式,若兩矩形相交,則相交的部分構成了乙個新的矩形 f,如圖所示,我們可以知道 f 的 minfx = max(minrx, mintx), minfy = max(minry, minty), maxfx = min(maxrx, maxtx), maxfy = min(maxry, maxtx),得到 f 的各個值之後,只要判斷矩形 f 是否成立就知道 r 和 t 到底有沒有相交了,若 minfx > maxfx 或 minfy > maxfy 則 f 無法構成,rt不相交,否則 rt相交。具體如圖所示:

2. 跨立試驗:

總的效果如下圖:

有了上面的基礎,這個演算法就很容易了。如果線段p1p2和直線q1q2相交,則p1p2跨立q1q2,即:( p1 - q1 ) × ( q2 - q1 ) * ( q2 - q1 ) × ( p2 - q1 ) >= 0。
只要判斷該點的橫座標和縱座標是否夾在矩形的左右邊和上下邊之間。
因為矩形是個凸集,所以只要判斷所有端點是否都在矩形中就可以了。
判斷點p是否在多邊形中是計算幾何中乙個非常基本但是十分重要的演算法。以點p為端點,向左(右)方作射線l,由於多邊形是有界的,所以射線l的左端一定在多邊形外,考慮沿著l從無窮遠處開始自左向右移動,遇到和多邊形的第乙個交點的時候,進入到了多邊形的內部,遇到第二個交點的時候,離開了多邊形,……所以很容易看出當l和多邊形的交點數目c是奇數的時候,p在多邊形內,是偶數的話p在多邊形外。

但是有些特殊情況要加以考慮。如圖下圖(a)(b)(c)(d)所示。在圖(a)中,l和多邊形的頂點相交,這時候交點只能計算乙個;在圖(b)中,l和多邊形頂點的交點不應被計算;在圖(c)和(d) 中,l和多邊形的一條邊重合,這條邊應該被忽略不計。如果l和多邊形的一條邊重合,這條邊應該被忽略不計。

為了統一起見,我們在計算射線l和多邊形的交點的時候,1。對於多邊形的水平邊不作考慮;2。對於多邊形的頂點和l相交的情況,如果該頂點是其所屬的邊上縱座標較大的頂點,則計數,否則忽略;3。對於p在多邊形邊上的情形,直接可判斷p屬於多邊行。

其中做射線l的方法是:設p'的縱座標和p相同,橫座標為正無窮大(很大的乙個正數),則p和p'就確定了射線l。

線段在多邊形內的乙個必要條件是線段的兩個端點都在多邊形內,但由於多邊形可能為凹,所以這不能成為判斷的充分條件。如果線段和多邊形的某條邊內交(兩線段內交是指兩線段相交且交點不在兩線段的端點),因為多邊形的邊的左右兩側分屬多邊形內外不同部分,所以線段一定會有一部分在多邊形外(見圖a)。於是我們得到線段在多邊形內的第二個必要條件:線段和多邊形的所有邊都不內交。

線段和多邊形交於線段的兩端點並不會影響線段是否在多邊形內;但是如果多邊形的某個頂點和線段相交,還必須判斷兩相鄰交點之間的線段是否包含於多邊形內部(反例見圖b)。

證明如下:

命題1:

如果線段和多邊形的兩相鄰交點p1 ,p2的中點p' 也在多邊形內,則p1, p2之間的所有點都在多邊形內。

證明:假設p1,p2之間含有不在多邊形內的點,不妨設該點為q,在p1, p'之間,因為多邊形是閉合曲線,所以其內外部之間有界,而p1屬於多邊行內部,q屬於多邊性外部,p'屬於多邊性內部,p1-q-p'完全連續,所以p1q和qp'一定跨越多邊形的邊界,因此在p1,p'之間至少還有兩個該線段和多邊形的交點,這和p1p2是相鄰兩交點矛盾,故命題成立。證畢。

由命題1直接可得出推論:

推論2:

設多邊形和線段pq的交點依次為p1,p2,……pn,其中pi和pi+1是相鄰兩交點,線段pq在多邊形內的充要條件是:p,q在多邊形內且對於i =1, 2,……, n-1,pi ,pi+1的中點也在多邊形內。

至此我們得出演算法如下:

if( 線端pq的端點不都在多邊形內 )

return

false;

點集pointset初始化為空;

for( 多邊形的每條邊s )

將pointset中的點按照x-y座標排序;

for() pointset中每兩個相鄰點 pointset[i] , pointset[i+1] )

return

true;

這個過程中的排序因為交點數目肯定遠小於多邊形的頂點數目n,所以最多是常數級的複雜度,幾乎可以忽略不計。因此演算法的時間複雜度也是o(n)。

計算幾何 一 入門須知

前言 計算幾何,雖然不少題都是板子來套,但我們應深知,借 來的板子遠不如自己消化理解後打的板子拓展性強。沒有學不會的演算法,只有不想學的acmer。最近比賽接連遇到不少較為基礎的計算幾何,因為沒有接觸這方面因此錯失ac,如今比賽 題目 安排較多,因此先簡單花一兩周入個門,以後再打算深入時,有了之前的...

計算幾何基礎入門(1)

平面最接近點對 二維凸包 最小覆蓋圓 模板 首先要知道兩個基礎知識 叉積與基礎運算子過載 二維叉積可以用來判斷點與點的位置關係與面積 三維叉積可算平面的法向量 這些模板都是二維的 我想想看能不能化為三維的題 空間最小點對 三維凸包 最小覆蓋球 例題 p4894 p3744 p2785 平面最接近點對...

計算幾何凸包入門詳解

講這個之前,先說一下我自己的看法 求凸包網上有很多種方法,個人覺得最好用最常用的就是graham掃瞄法,本篇博文我也就只講這一種演算法求解凸包。講這個問題之前我們必須要弄清楚何為凸包?我來口胡一下吧,很明顯凸包這個名詞就已經給了我們乙個重要的資訊,那就是這個東西它肯定是乙個凸多邊形。那除了是凸多邊形...