您的位置:首页 > 其它

算法导论学习笔记(五)计算几何之寻找凸包

2016-09-02 18:53 357 查看
定义:点集Q的凸包是一个最小的凸多边形P,满足Q中的每个点都在P的边界上或在P的内部。

Graham扫描法

通过排序所有点,选择一个一定是凸包中的点作为基点,再在剩余点中按相对于基点的极角排序,最后依次遍历所有点,将不符合凸多边形定义的点去除,剩下的点集便是凸包中的点。

伪代码

GRAHAM-SCAN( Q)
Q.sort( 0, 1, 2..., n-1) with
(pi.y==pj.y)? (pi.x<pj.x) : (pi.y<pj.y)
//以p0点为原点,建立极坐标
Q.sort( 1, 2..., n-1) with
(pi.θ==pj.θ)? (pi.λ<pj.λ) : (pi.θ<pj.θ)
let S be an empty stack
PUSH( p0, S)
PUSH( p1, S)
PUSH( p2, S)
for i = 3 to n
while    pi makes a nonleft turn
POP( S)
PUSH( pi, S)
return S


代码实现

#include <cmath>
#include <algorithm>
const double ACCURACY = 0.0000001;
typedef struct Point
{
int x,y;
}VectorLine;
VectorLine operator- ( Point a, Point b)
{
VectorLine c;
c.x = a.x - b.x;
c.y = a.y - b.y;
return c;
}
bool cmpX( Point a, Point b )
{
if( a.x == b.x )
return a.y < b.y;
return a.x < b.x;
}
double getDistance( Point a, Point b )
{
return sqrt( pow(a.x-b.x,2.0) + pow(a.y-b.y,2.0) );
}
struct Node
{
Point point;
double degree;
double distance;
};
void setNode(Node &a, Point source )
{
double distance = getDistance( a.point, source );
double deltaY = (a.point).y - source.y;
double degree = asin( deltaY/distance );
a.distance = distance;
a.degree = degree;
}
bool cmpPoint( Node a, Node b )
{
return cmpX( a.point, b.point );
}
bool cmpDegree( Node a, Node b )
{
if( fabs( a.degree-b.degree ) < ACCURACY )
return a.distance < b.distance;
return a.degree < b.degree;
}
int getCrossProduct( VectorLine a, VectorLine b )
{
return a.x*b.y - a.y*b.x;
}
bool check( Point newPoint, Point oldPoint, Point sourcePoint )
{
VectorLine oldLine = oldPoint - sourcePoint;
VectorLine newLine = newPoint - sourcePoint;
return getCrossProduct( oldLine, newLine ) > 0;
}
int getConvexHull( Node *nodes, int sizeOfNodes, Point *convexHull )
{
//Graham's scan
std::sort( nodes, nodes+sizeOfNodes, cmpPoint );

for( int i=1; i<sizeOfNodes; i++ ) {
setNode(nodes[i],nodes[0].point);
}
std::sort( nodes+1, nodes+sizeOfNodes, cmpDegree );

int sizeOfStack = 0;
for( int i=0;i<std::min(3,sizeOfNodes);i++ ) {
convexHull[sizeOfStack++] = nodes[i].point;
}

for( int i=3;i<sizeOfNodes;i++ ) {
while( sizeOfStack > 2 &&
!check( nodes[i].point,
convexHull[sizeOfStack-1],
convexHull[sizeOfStack-2] )
) {

sizeOfStack--;
}
convexHull[sizeOfStack++] = nodes[i].point;
}
return sizeOfStack;
}


Jarvis步进法

将点设为有物理特性,利用一条可弯曲的射线,将一端放在一个最左边的点上,将射线方向设为180度,逆时针旋转,所遇见的第一个为下一个凸包点,然后依次挑选,直至点为第一个点时,所选出的点集为凸包。

伪代码

JARVIS( Q)
Q.sort( 0, 1, 2..., n-1) with
(pi.y==pj.y)? (pi.x<pj.x) : (pi.y<pj.y)
let nowPoint = 0 and nextPoint = -1
while nextPoint != 0
//以p0点为原点,建立极坐标
nextPoint in Q
//nextPoint为Q中极角最小的点
nowPoint = nextPoint
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: