多边形点集排序--针对凸多边形,按逆时针方向进行排序[转]
多边形点集排序--针对凸多边形,按逆时针方向进行排序[转]
http://www.cnblogs.com/loveclumsybaby/p/3420795.html
原文是C++下的,原文地址:http://www.cnblogs.com/dwdxdy/p/3230156.html
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 凸多边形选择