多邊形點集排序--針對凸多邊形,按逆時針方向進行排序[轉]
http://www.cnblogs.com/loveclumsybaby/p/3420795.html
原文是C++下的,原文地址:http://www.cnblogs.com/dwdxdy/p/3230156.html
稍微的改了為C#的,呵呵
主要方法:
1 public static void ClockwiseSortPoints(List<Point3D> vPoints)
2 {
3 //計算重心
4 Point3D center = new Point3D();
5 double X = 0, Y = 0;
6 for (int i = 0; i < vPoints.Count; i++) {
7 X += vPoints[i].X;
8 Y += vPoints[i].Y;
9 }
10 center.X = (int)X / vPoints.Count;
11 center.Y = (int)Y / vPoints.Count;
12
13 //冒泡排序
14 for (int i = 0; i < vPoints.Count - 1; i++) {
15 for (int j = 0; j < vPoints.Count - i - 1; j++) {
16 if (PointCmp(vPoints[j], vPoints[j + 1], center)) {
17 Point3D tmp = vPoints[j];
18 vPoints[j] = vPoints[j + 1];
19 vPoints[j + 1] = tmp;
20 }
21 }
22 }
23 }
輔助方法:
1 //若點a大於點b,即點a在點b順時針方向,返回true,否則返回false
2 static bool PointCmp(Point3D a, Point3D b, Point3D center)
3 {
4 if (a.X >= 0 && b.X < 0)
5 return true;
6 if (a.X == 0 && b.X == 0)
7 return a.Y > b.Y;
8 //向量OA和向量OB的叉積
9 int det = Convert.ToInt32((a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y));
10 if (det < 0)
11 return true;
12 if (det > 0)
13 return false;
14 //向量OA和向量OB共線,以距離判斷大小
15 double d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);
16 double d2 = (b.X - center.X) * (b.X - center.Y) + (b.Y - center.Y) * (b.Y - center.Y);
17 return d1 > d2;
18 }
【計算幾何】多邊形點集排序
http://www.cnblogs.com/dwdxdy/p/3230156.html
問題描述:已知多邊形點集C={P1,P2,...,PN},其排列順序是雜亂,依次連接這N個點,無法形成確定的多邊形,需要對點集C進行排序后,再繪制多邊形。
點集排序過程中,關鍵在於如何定義點的大小關系。
以按逆時針排序為例,算法步驟如下:
定義:點A在點B的逆時針方向,則點A大於點B
1.計算點集的重心O,以重心作為逆時針旋轉的中心點。
2.計算點之間的大小關系。
大小關系的計算,可由兩種方法進行計算。
方法1:
以重心O作一條平行於X軸的單位向量OX,然后依次計算OPi和OX的夾角,根據夾角的大小,確定點之間的大小關系。
OPi和OX夾角越大,說明點Pi越小,如圖所示。
方法2:
根據向量叉積的定義,向量OPi和OPj的叉積大於0,則向量OPj在向量OPi的逆時針方向,即點Pj小於點Pi。
依據方法2,多邊形點集排序的代碼如下:
1 typedef struct Point
2 {
3 int x;
4 int y;
5 }Point;
6 //若點a大於點b,即點a在點b順時針方向,返回true,否則返回false
7 bool PointCmp(const Point &a,const Point &b,const Point ¢er)
8 {
9 if (a.x >= 0 && b.x < 0)
10 return true;
11 if (a.x == 0 && b.x == 0)
12 return a.y > b.y;
13 //向量OA和向量OB的叉積
14 int det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
15 if (det < 0)
16 return true;
17 if (det > 0)
18 return false;
19 //向量OA和向量OB共線,以距離判斷大小
20 int d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y);
21 int d2 = (b.x - center.x) * (b.x - center.y) + (b.y - center.y) * (b.y - center.y);
22 return d1 > d2;
23 }
24 void ClockwiseSortPoints(std::vector<Point> &vPoints)
25 {
26 //計算重心
27 cv::Point center;
28 double x = 0,y = 0;
29 for (int i = 0;i < vPoints.size();i++)
30 {
31 x += vPoints[i].x;
32 y += vPoints[i].y;
33 }
34 center.x = (int)x/vPoints.size();
35 center.y = (int)y/vPoints.size();
36
37 //冒泡排序
38 for(int i = 0;i < vPoints.size() - 1;i++)
39 {
40 for (int j = 0;j < vPoints.size() - i - 1;j++)
41 {
42 if (PointCmp(vPoints[j],vPoints[j+1],center))
43 {
44 cv::Point tmp = vPoints[j];
45 vPoints[j] = vPoints[j + 1];
46 vPoints[j + 1] = tmp;
47 }
48 }
49 }
50 }
參考資料:
http://blog.csdn.net/beyond071/article/details/5855171
http://stackoverflow.com/questions/6989100/sort-points-in-clockwise-order
c#凸多邊形算法學習
http://www.cnblogs.com/hopeless/archive/2009/08/03/1537436.html
#region 凸多邊形選擇
/**********************************************
尋找凸包的graham 掃描法
PointFSet為輸入的點集;
ch為輸出的凸包上的點集,按照逆時針方向排列;
n為PointFSet中的點的數目
len為輸出的凸包上的點的個數
**********************************************/
const double INF=1E200;
const double EP=1E-10;
// 返回兩點之間歐氏距離
public double distance(PointF p1, PointF p2)
{
return Math.Sqrt( (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
}
/******************************************************************************
r=multiplY(sp,ep,op),得到(sp-op)*(ep-op)的叉積
r>0:ep在矢量opsp的逆時針方向;
r=0:opspep三點共線;
r<0:ep在矢量opsp的順時針方向
*******************************************************************************/
//叉積就是2向量形成的平行四邊形的面積
public double multiplY(PointF sp,PointF ep,PointF op)
{
return((sp.X-op.X)*(ep.Y-op.Y)-(ep.X-op.X)*(sp.Y-op.Y));
}
bool cmp(PointF[] points, PointF a, PointF b)
{
// 如果三點在同一直線上,那么按相對於points[0]由近到遠排序
if (multiplY(points[0], a, b) == 0) return distance(points[0], a) < distance(points[0], b);
//如果三點不在同一直線上,那么a在b->points[0]的左側,也就是從下向上,從右向左排序
//按極角有小到大排序。
else return multiplY(points[0], a, b) > 0;
}
/// <summary>
///
/// </summary>
/// <param name="a"></param>
/// <param name="p"></param>
/// <param name="r"></param>
/// <returns></returns>
public int partition(PointF[] a, int p, int r)
{
int i=p,j=r+1,k;
double ang,dis;
PointF R,S;
k=(p+r)/2;//防止快排退化
R=a[p];
a[p]=a[k];
a[k]=R;
R=a[p];
dis=distance(R,a[0]);
while(true)
{
while(true)
{
++i;
if(i>r)
{
i=r;
break;
}
ang=multiplY(R,a[i],a[0]);
if(ang>0)
break;
else if(ang==0)
{
if(distance(a[i],a[0])>dis)
break;
}
}
while(true)
{
--j;
if(j<p)
{
j=p;
break;
}
ang=multiplY(R,a[j],a[0]);
if(ang<0)
break;
else if(ang==0)
{
if(distance(a[j],a[0])<dis)
break;
}
}
if(i>=j)break;
S=a[i];
a[i]=a[j];
a[j]=S;
}
a[p]=a[j];
a[j]=R;
return j;
}
/// <summary>
/// 按角度排序
/// </summary>
/// <param name="a"></param>
/// <param name="p"></param>
/// <param name="r"></param>
public void anglesort(PointF[] a,int p,int r)
{
if(p<r)
{
int q=partition(a,p,r);
anglesort(a,p,q-1);
anglesort(a,q+1,r);
}
}
/// <summary>
/// Graham_scan
/// </summary>
/// <param name="PointFSet"></param>
/// <param name="n"></param>
/// <returns></returns>
public PointF[] Graham_scan(PointF[] PointFSet,int n)
{
PointF[] ch = new PointF[n];
int len;
int i,k=0,top=2;
PointF tmp;
// 選取PointFSet中Y坐標最小的點PointFSet[k],如果這樣的點有多個,則取最左邊的一個
for (i = 1; i < n; i++)
{
if (PointFSet[i].Y < PointFSet[k].Y || (PointFSet[i].Y == PointFSet[k].Y) && (PointFSet[i].X < PointFSet[k].X))
{
k = i;
}
}
tmp=PointFSet[0];
PointFSet[0]=PointFSet[k];
PointFSet[k]=tmp; // 現在PointFSet中Y坐標最小的點在PointFSet[0]
/* 對頂點按照相對PointFSet[0]的極角從小到大進行排序,極角相同
的按照距離PointFSet[0]從近到遠進行排序 */
anglesort(PointFSet,1,n-1);
ch[0]=PointFSet[0];
ch[1]=PointFSet[1];
ch[2]=PointFSet[2];
for (i=3;i<n;i++)
{
while (multiplY(PointFSet[i],ch[top],ch[top-1])>0) top--;
ch[++top]=PointFSet[i];
}
len=top+1;
PointF[] temp = new PointF[len];
for (int j = 0; j < len; j++)
{
temp[j] = ch[j];
}
return temp;
}
#endregion 凸多邊形選擇