计算几何之多边形
最近解決一個多邊形帶洞的問題,需要判斷多邊形的頂點順序,順便復習下計算幾何的一些基礎知識。。
判斷頂點順序需要計算多邊形的面積,面積有正負之分,符號決定了順時針CW還是逆時針CCW。計算面積兩種思路:
- 直角梯形的思路
- 向量叉乘
直角梯形思路
任何一個邊p0p1,兩個頂點向x軸投垂線,構成了直角梯形。它的面積是
(p1.x – p0.x) * (p1.y + p2.y) / 2.0
面積符號受deltaX,averageY影響。二者綜合影響。
下圖中,多邊形面積等于所有邊與x軸構成直角梯形面積總和。N個頂點,則N個邊的面積之和,尤其注意首尾頂點(n-1, 0)的 這個線段的面積需要考慮進去。。
上圖中,多邊形頂點順序為順時針ABCDEFG,
TopAreas是AB,BC,CD,DE 與x軸構成的梯形,面積都大于0;
BottomAreas是EF,FG,GA與x軸構成的梯形,deltax為負,面積都小于0;最終多邊形面積為正。
因此
這種方式下,多邊形頂點順序為逆時針,則面積為負值;順時針時候,面積為正值。
向量叉乘的方式
向量叉乘
最經簡單的例子,
unit_x(1, 0, 0) cross unit_y(0, 1, 0) = unit_z(0, 0, 1)
叉乘的右手法則:右手四指,從a開始以不超過180的轉角握向b,大拇指的指向就是叉乘結果向量的方向。
2D向量叉乘的物理意義:a向量叉乘b向量的模,代表|b|*sin為高,a為底的三角形面積。面積可以有符號,叉乘向量是z軸正向時,面積為正,否則為負。
多邊形的面積計算,多邊形每個邊兩個端點跟原點組成一系列三角形,它們的面積有正負,所面積之和就是多邊形的面積。
右圖中,多邊形是逆時針方向,ABCDEFG
第一個三角形:ABP面積為負,為什么呢?AP.cross(BP) 向量的方向是z軸負方向。
最后一個三角形GAP,面積為正,why?GP.cross(AP) 向量的方向是z軸正方向。
結論
多邊形頂點順序為逆時針時,計算的面積為正;順時針時,面積為負值。
代碼
// http://www.cnblogs.com/void/archive/2011/04/17/2018729.html bool IsPolygonClockWise(const std::vector<Point_Double>& vPolygon) {// compute area of a contour/polygonint n = vPolygon.size();double A = 0.0;for(int p=n-1,q=0; q<n; p=q++){A+= vPolygon[p].x * vPolygon[q].y - vPolygon[q].x * vPolygon[p].y;}double Area = A * 0.5;// we want a counter-clockwise polygon in Vif ( 0.0 < Area ){return false;}else{return true;} }// http://csharphelper.com/blog/2014/07/calculate-the-area-of-a-polygon-in-c/ bool IsPolygonClockWise_WhenYUp(TXMapPoint* polygon, int count) {double rst = 0.0;#if 1// first point must be equal to last point.for (int i = 0; i < count; i++){int next = (i + 1) % count;double dx = polygon[next].x - polygon[i].x;double dy = polygon[next].y + polygon[i].y;rst += (dx * dy);// overflow issue.// rst += ( (polygon[next].x - polygon[i].x) * (polygon[next].y + polygon[i].y) / 2.0 );} #else// bad version// 沒有計算首尾兩個點構成的面積。。。for (int i = 1; i <count; i++){double dx = (polygon[i].x - polygon[i - 1].x);double ay = (polygon[i].y + polygon[i - 1].y);rst += (dx * ay);} #endifif (rst >= 0){return true;}else{return false;} }踩過的坑
地圖中坐標很大,如果使用int存儲,計算面積的時候有越界的可能。越界后結果為負數,也會影響到最終的計算結果。
- 第一種方式計算量更加少
- 第二種方式有點冗余,循環中每次的計算結果中有可以抵消的部分
- 第二種優化的結果與第一種正好差一個符號
OpenGL模板測試渲染任意凹多邊形
如下圖,多邊形1234567。A,D,F區域組成了多邊形,且這三個區域都是由奇數個三角形覆蓋;其他區域由偶數個,或者0個三角形覆蓋。如圖中右邊的列表,B由123,134兩個三角形覆蓋。
選擇任意一點P作為基準點,分別渲染P12,P23,P34,P45,P56,P67,P71 三角形。多邊形內部的區域被填充了奇數次,外部的區域被填充了偶數次。
OpenGL渲染凹多邊形的思路:借助幀緩沖區,兩次渲染多邊形的三角形列表。
點評
- 技術雖有點過時了,這種技術適應任何復雜帶洞的多邊形渲染。
- 相比較直接凹多邊形三角化后渲染,重疊地方的被多次柵格化,性能消耗較大。opengl渲染的步驟,頂點處理,柵格化,片段處理,然后裁剪測試,alpha測試,模板測試(幀緩沖區),深度測試(深度緩沖區)。
ref:http://glprogramming.com/red/chapter14.html#name13
總結
- 上一篇: 【Deodex】Samsung S5/S
- 下一篇: 跨平台移动框架iMAG开发入门