convex hull - Graham's scam Algorithm version-0.1

input:a finite set of two dimentional points P (the number of points n is more than 2)

output: the convex hull of P

Pesudo:

1, sort P in Lexgrahical order

2, construct the upper hull UHLL:

1‘ add two points on UHLL

2‘ for i=3 to  n

add P[i] on UHLL

While( UHLL.Length > 2 && the last 3 points of UHLL do not make a right turn)

delete the middle point of the last 3 points of UHLL

3, construct the lower hull LHLL:

1‘ add two points on LHLL

2‘ for i=3 to  n

add P[i] on LHLL

While( LHLL.Length > 2 && the last 3 points of LHLL do not make a right turn)

delete the middle point of the last 3 points of LHLL

4, delete the first and last point of LHULL

5, merge UHLL and LHULL to  convex hull of P CHULL

6, output CHULL

------------------------------------------------------------------------------------------------------------

next is objectarx implementation( with visual studio 2010 + AutoCAD 2013 x64 +object 2013):

first, get the point set:

 1 /********************************************************************************/
 2 /* get points in selection set                                                  */
 3 /* reference: http://www.theswamp.org/index.php?topic=30971.msg365170#msg365170 */
 4 /********************************************************************************/
 5 void CModifyEnt::getPoints(AcGePoint3dArray &vec)
 6 {
 7     AcDbObjectIdArray ids;
 8     CResbufPtr pFilter (acutBuildList(RTDXF0,ACRX_T("POINT,LINE,LWPOLYLINE"),NULL));
 9     CSelectionSet sset;
10     sset.userSelect(pFilter);
11     sset.asArray(ids);
12     if (ids.length() < 3)
13     {
14         acutPrintf(L"there must be more than 3 entities!");
15         return;
16     }
17     for(int i = 0 ; i < ids.length(); i++)
18     {
19         AcDbEntityPointer pEnt(ids[i],AcDb::kForRead);
20         if(pEnt.openStatus() == eOk )
21         {
22             if(pEnt->isA() == AcDbPoint::desc())
23             {
24                 AcDbPoint *pPoint = AcDbPoint::cast(pEnt);
25                 if(pPoint)
26                 {
27                     vec.append(pPoint->position());
28                 }
29             }
30             else if(pEnt->isA() == AcDbLine::desc())
31             {
32                 AcDbLine *pLine = AcDbLine::cast(pEnt);
33                 if(pLine)
34                 {
35                     vec.append(pLine->startPoint());
36                     vec.append(pLine->endPoint());
37                 }
38             }
39             else if(pEnt->isA() == AcDbPolyline::desc())
40             {
41                 AcDbPolyline *pLine = AcDbPolyline::cast(pEnt);
42                 if(pLine)
43                 {
44                     for(unsigned int i = 0 ; i < pLine->numVerts() ; i++)
45                     {
46                         AcGePoint3d pt;
47                         pLine->getPointAt(i,pt);
48                         vec.append(pt);
49                     }
50                 }
51             }
52         }
53     }
54 }

second, sort points:

 1 void CCalculation::insertion_sort(AcGePoint3dArray &points)
 2 {
 3     int p;
 4     int k;
 5     AcGePoint3d current_element;
 6
 7     int length = points.length();
 8     for ( p = 1; p < length; p++ )
 9     {
10         current_element = points.at(p);
11         k = p - 1;
12         while( k >= 0 && isLessOrEqual(current_element, points.at(k)))
13         {
14             points.at(k+1) = points.at(k);
15             k--;
16         }
17         points.at(k+1) = current_element;
18     }
19 }

in this method, there is a method called "isLessOrEqual" to compare two point in lexicographical order:

 1 bool CCalculation::isLessOrEqual(AcGePoint3d &p1, AcGePoint3d &p2)
 2 {
 3     if (p1.x == p2.x)
 4     {
 5         if (p1.y == p2.y)
 6         {
 7             return p1.z <= p2.z;
 8         }
 9         else
10         {
11             return p1.y < p2.y;
12         }
13     }
14     else
15     {
16         return p1.x < p2.x;
17     }
18 }

then construct the upper hull:

 1 void CCalculation::constructUpper()
 2 {
 3     this->m_upperHull.removeAll();
 4     this->m_upperHull.append(this->m_points.at(0));
 5     this->m_upperHull.append(this->m_points.at(1));
 6
 7     int k;
 8     AcGeVector3d v1, v2;
 9     for (int i=2; i < this->m_points.length(); i++)
10     {
11         this->m_upperHull.append(this->m_points.at(i));
12
13         while(this->m_upperHull.length() > 2)
14         {
15             k = this->m_upperHull.length() - 1;//the last point of current hull‘s index
16
17             v1 = this->m_upperHull.at(k) - this->m_upperHull.at(k-2);
18             v2 = this->m_upperHull.at(k-1) - this->m_upperHull.at(k-2);
19
20             if(CCalculation::isRightTurn(v1,v2))
21                 break;
22
23             this->m_upperHull.removeAt(k-1);
24         }
25     }
26 }

then construct the lower hull:

 1 void CCalculation::constructLower()
 2 {
 3     this->m_lowerHull.removeAll();
 4     this->m_lowerHull.append(this->m_points.at(0));
 5     this->m_lowerHull.append(this->m_points.at(1));
 6
 7     int k;
 8     AcGeVector3d v1, v2;
 9     for (int i=2; i < this->m_points.length(); i++)
10     {
11         this->m_lowerHull.append(this->m_points.at(i));
12
13         while(this->m_lowerHull.length() > 2)
14         {
15             k = this->m_lowerHull.length() - 1;//the last point of current hull‘s index
16
17             v1 = this->m_lowerHull.at(k) - this->m_lowerHull.at(k-2);
18             v2 = this->m_lowerHull.at(k-1) - this->m_lowerHull.at(k-2);
19
20             if(CCalculation::isLeftTurn(v1,v2))
21                 break;
22
23             this->m_lowerHull.removeAt(k-1);
24         }
25     }
26 }

in this method, there are three methods:

isRightTurn( if two vectors are in right turn order);

1 bool  CCalculation::isRightTurn(AcGeVector3d &p1, AcGeVector3d &p2)
2 {
3     return     crossProduction(p1, p2).z > 0;
4 }

isLeftTurn( if two vectors are in left turn order);

1 bool  CCalculation::isLeftTurn(AcGeVector3d &p1, AcGeVector3d &p2)
2 {
3     return     crossProduction(p1, p2).z < 0;
4 }

crossProduction(calculate two vectors‘ cross production):

then construct the convex hull:

 1 AcGePoint3dArray CCalculation::getConvexHull()
 2 {
 3     this->initPoints();
 4     this->constructUpper();
 5     this->constructLower();
 6
 7     this->m_convexHull.removeAll();
 8     for (int i=0; i < this->m_upperHull.length(); i++)
 9     {
10        this->m_convexHull.append(this->m_upperHull[i]);
11     }
12
13     for (int i = this->m_lowerHull.length() - 2; i >=0 ; i--)
14     {
15         this->m_convexHull.append(this->m_lowerHull[i]);
16     }
17
18     return this->m_convexHull;
19 }

the CCalculation.h:

 1 class CCalculation
 2 {
 3 public:
 4     CCalculation(void);
 5     ~CCalculation(void);
 6
 7     static bool isLessOrEqual(AcGePoint3d &p1, AcGePoint3d &p2);
 8     static void insertion_sort(AcGePoint3dArray &points);
 9     static AcGeVector3d crossProduction(AcGeVector3d &p1, AcGeVector3d &p2);
10     static bool isRightTurn(AcGeVector3d &, AcGeVector3d &);
11     static bool isLeftTurn(AcGeVector3d &, AcGeVector3d &);
12     static void getPoints(AcGePoint3dArray &points);
13     void initPoints();
14     AcGePoint3dArray getUpperHull();
15     AcGePoint3dArray getLowerHull();
16     AcGePoint3dArray getConvexHull();
17 private:
18     AcGePoint3dArray m_points;//selected points
19     AcGePoint3dArray m_upperHull;//upper hull
20     AcGePoint3dArray m_lowerHull;//lower hull
21     AcGePoint3dArray m_convexHull;//convex hull
22
23     void constructUpper();
24     void constructLower();
25     void constructConveHull();
26 };

the CCalculation.cpp:

  1 /********************************************************************************/
  2 /* get points in selection set                                                  */
  3 /* reference: http://www.theswamp.org/index.php?topic=30971.msg365170#msg365170 */
  4 /********************************************************************************/
  5 void CCalculation::getPoints(AcGePoint3dArray &points)
  6 {
  7     AcDbObjectIdArray ids;
  8     CResbufPtr pFilter (acutBuildList(RTDXF0,ACRX_T("POINT,LINE,LWPOLYLINE"),NULL));
  9     CSelectionSet sset;
 10     sset.userSelect(pFilter);
 11     sset.asArray(ids);
 12     if (ids.length() < 3)
 13     {
 14         acutPrintf(L"there must be more than 3 entities!");
 15         return;
 16     }
 17     for(int i = 0 ; i < ids.length(); i++)
 18     {
 19         AcDbEntityPointer pEnt(ids[i],AcDb::kForRead);
 20         if(pEnt.openStatus() == eOk )
 21         {
 22             if(pEnt->isA() == AcDbPoint::desc())
 23             {
 24                 AcDbPoint *pPoint = AcDbPoint::cast(pEnt);
 25                 if(pPoint)
 26                 {
 27                     points.append(pPoint->position());
 28                 }
 29             }
 30             else if(pEnt->isA() == AcDbLine::desc())
 31             {
 32                 AcDbLine *pLine = AcDbLine::cast(pEnt);
 33                 if(pLine)
 34                 {
 35                     points.append(pLine->startPoint());
 36                     points.append(pLine->endPoint());
 37                 }
 38             }
 39             else if(pEnt->isA() == AcDbPolyline::desc())
 40             {
 41                 AcDbPolyline *pLine = AcDbPolyline::cast(pEnt);
 42                 if(pLine)
 43                 {
 44                     for(unsigned int i = 0 ; i < pLine->numVerts() ; i++)
 45                     {
 46                         AcGePoint3d pt;
 47                         pLine->getPointAt(i,pt);
 48                         points.append(pt);
 49                     }
 50                 }
 51             }
 52         }
 53     }
 54 }
 55
 56 void CCalculation::initPoints()
 57 {
 58     CCalculation::getPoints(this->m_points);
 59     CCalculation::insertion_sort(this->m_points);
 60 }
 61
 62 bool CCalculation::isLessOrEqual(AcGePoint3d &p1, AcGePoint3d &p2)
 63 {
 64     if (p1.x == p2.x)
 65     {
 66         if (p1.y == p2.y)
 67         {
 68             return p1.z <= p2.z;
 69         }
 70         else
 71         {
 72             return p1.y < p2.y;
 73         }
 74     }
 75     else
 76     {
 77         return p1.x < p2.x;
 78     }
 79 }
 80
 81 void CCalculation::insertion_sort(AcGePoint3dArray &points)
 82 {
 83     int p;
 84     int k;
 85     AcGePoint3d current_element;
 86
 87     int length = points.length();
 88     for ( p = 1; p < length; p++ )
 89     {
 90         current_element = points.at(p);
 91         k = p - 1;
 92         while( k >= 0 && isLessOrEqual(current_element, points.at(k)))
 93         {
 94             points.at(k+1) = points.at(k);
 95             k--;
 96         }
 97         points.at(k+1) = current_element;
 98     }
 99 }
100
101 AcGeVector3d CCalculation::crossProduction(AcGeVector3d &p1, AcGeVector3d &p2)
102 {
103      return AcGeVector3d((p1.y*p2.z - p1.z*p2.y), (p1.z*p2.x - p1.x*p2.z), (p1.x*p2.y - p1.y*p2.x));
104 }
105
106 bool  CCalculation::isRightTurn(AcGeVector3d &p1, AcGeVector3d &p2)
107 {
108     return     crossProduction(p1, p2).z > 0;
109 }
110
111 bool  CCalculation::isLeftTurn(AcGeVector3d &p1, AcGeVector3d &p2)
112 {
113     return     crossProduction(p1, p2).z < 0;
114 }
115
116 void CCalculation::constructUpper()
117 {
118     this->m_upperHull.removeAll();
119     this->m_upperHull.append(this->m_points.at(0));
120     this->m_upperHull.append(this->m_points.at(1));
121
122     int k;
123     AcGeVector3d v1, v2;
124     for (int i=2; i < this->m_points.length(); i++)
125     {
126         this->m_upperHull.append(this->m_points.at(i));
127
128         while(this->m_upperHull.length() > 2)
129         {
130             k = this->m_upperHull.length() - 1;//the last point of current hull‘s index
131
132             v1 = this->m_upperHull.at(k) - this->m_upperHull.at(k-2);
133             v2 = this->m_upperHull.at(k-1) - this->m_upperHull.at(k-2);
134
135             if(CCalculation::isRightTurn(v1,v2))
136                 break;
137
138             this->m_upperHull.removeAt(k-1);
139         }
140     }
141 }
142
143 void CCalculation::constructLower()
144 {
145     this->m_lowerHull.removeAll();
146     this->m_lowerHull.append(this->m_points.at(0));
147     this->m_lowerHull.append(this->m_points.at(1));
148
149     int k;
150     AcGeVector3d v1, v2;
151     for (int i=2; i < this->m_points.length(); i++)
152     {
153         this->m_lowerHull.append(this->m_points.at(i));
154
155         while(this->m_lowerHull.length() > 2)
156         {
157             k = this->m_lowerHull.length() - 1;//the last point of current hull‘s index
158
159             v1 = this->m_lowerHull.at(k) - this->m_lowerHull.at(k-2);
160             v2 = this->m_lowerHull.at(k-1) - this->m_lowerHull.at(k-2);
161
162             if(CCalculation::isLeftTurn(v1,v2))
163                 break;
164
165             this->m_lowerHull.removeAt(k-1);
166         }
167     }
168 }
169
170
171
172 AcGePoint3dArray CCalculation::getUpperHull()
173 {
174     this->constructUpper();
175     return this->m_upperHull;
176 }
177
178 AcGePoint3dArray CCalculation::getLowerHull()
179 {
180     this->constructLower();
181     return this->m_lowerHull;
182 }
183
184 AcGePoint3dArray CCalculation::getConvexHull()
185 {
186     this->initPoints();
187     this->constructUpper();
188     this->constructLower();
189
190     this->m_convexHull.removeAll();
191     for (int i=0; i < this->m_upperHull.length(); i++)
192     {
193        this->m_convexHull.append(this->m_upperHull[i]);
194     }
195
196     for (int i = this->m_lowerHull.length() - 2; i >=0 ; i--)
197     {
198         this->m_convexHull.append(this->m_lowerHull[i]);
199     }
200
201     return this->m_convexHull;
202 }

the getPoints method use two class(reference http://www.theswamp.org/index.php?topic=30971.msg365170#msg365170):

ResbufPtr.h:

 1 #pragma once
 2 #include "StdAfx.h"
 3 // Chuck Gabriel @ TheSwamp
 4
 5 class CResbufPtr {
 6     resbuf* pHead; // Maintain a pointer to the head of the resource chain for de-allocation
 7     resbuf* pBuffer;
 8 public:
 9     CResbufPtr(resbuf* ptr) : pHead(ptr), pBuffer(ptr) {}
10     ~CResbufPtr() {
11         acutRelRb(pHead); // release the buffer
12         pHead = pBuffer = 0;
13     }
14     resbuf* operator->() { return pBuffer; }  // so you can do things like buf->resval.rstring
15     operator resbuf*() { return pBuffer; } // so you can pass the smart pointer to functions that expect a resbuf*
16     bool isNull() { return pBuffer == 0; } // null pointer check
17     void start() { pBuffer = pHead; } // in case you need to return to the head of the resource chain
18     void next() { pBuffer = pBuffer->rbnext; } // try to move the pointer to the next item in the resource chain
19 };

SelectionSet.h

 1 #pragma once
 2 #include "arxHeaders.h"
 3
 4 class CSelectionSet
 5 {
 6     ads_name ssname;
 7 public:
 8     CSelectionSet(void);
 9     ~CSelectionSet(void);
10     bool isNull();
11     Acad::PromptStatus userSelect(const resbuf *pFilter);
12     Acad::ErrorStatus asArray(AcDbObjectIdArray &setIds);
13 };

SelectionSet.cpp

 1 #include "StdAfx.h"
 2 #include "SelectionSet.h"
 3
 4
 5 CSelectionSet::CSelectionSet(void)
 6 {
 7     ssname[0] = 0L;
 8     ssname[1] = 0L;
 9 }
10
11 CSelectionSet::~CSelectionSet(void)
12 {
13     acedSSFree(ssname);
14 }
15
16
17 bool CSelectionSet::isNull()
18 {
19     return ssname[0] == 0L && ssname[1] == 0L;
20 }
21
22 Acad::PromptStatus CSelectionSet::userSelect(const resbuf *pFilter)
23 {
24     acedSSFree(ssname);
25     return (Acad::PromptStatus) acedSSGet(NULL,NULL,NULL,pFilter,ssname);
26 }
27
28 Acad::ErrorStatus CSelectionSet::asArray( AcDbObjectIdArray &setIds )
29 {
30     if(this->isNull())
31         return Acad::eNullPtr;
32     long sslength;
33     ads_name ent;
34     acedSSLength(ssname,&sslength);
35     for (long i = 0; i < sslength; i++)
36     {
37         AcDbObjectId oId;
38         acedSSName(ssname, i, ent);
39         if(acdbGetObjectId(oId, ent) == eOk)
40             setIds.append(oId);
41         else
42             return Acad::eNullObjectId;
43     }
44     return eOk;
45 }

the demo:

Done!

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

references:

1. http://www.theswamp.org/index.php?topic=30971.msg365170#msg365170

2. Computational Geometry - Algorithms and Applications(Mark de Berg · Otfried Cheong & Marc van Kreveld · Mark Overmars)

3. http://en.wikipedia.org/wiki/Graham_scan

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

convex hull - Graham's scam Algorithm version-0.1

时间: 2024-10-14 01:10:14

convex hull - Graham's scam Algorithm version-0.1的相关文章

凸包(Convex Hull)构造算法——Graham扫描法

凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个钉子,然后用一根绷紧的橡皮筋它们都圈起来,这根橡皮筋的形状就是所谓的凸包. 计算凸包的一个著名算法是Graham Scan法,它的时间复杂度与所采用的排序算法时间复杂度相同,通常采用线性对数算法,因此为\( O\left(N\mathrm{log}\left(N\right)\right) \).

[算法课][分治]寻找凸包 (Convex Hull)

凸包问题是算法中经典的题目了,最近算法课讲分治问题时提到了Convex Hull,算法导论的书上也花了篇幅讨论了Convex Hull的求解,主要是Graham方法. 为了能更好地理解分治和Graham这两种解法,我决定自己动手把代码写一遍. 然而,在写之前,我发现我大一学的用行列式求解由三个点围城的三角形面积已经忘得差不多了,现在补充一下: 利用这个计算结果来判断点p3在p1p2直线的左侧还是右侧 下面是分治算法求解: #include <iostream> #include <alg

zoj 3871 Convex Hull(凸包)

题目链接:zoj 3871 Convex Hull 枚举每条边,计算出有多少情况下为凸包的边界,即有多少点在该边的左边. #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <complex> #include <algorithm> using namespace std; typedef pair<int,int&g

Computational Geometry PA1 Convex Hull (凸包)

题目链接:http://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=710 CG2015 PA1-1 Convex Hull (凸包) Description (描述) After learning Chapter 1, you must have mastered the convex hull very well. Yes, convex hull is at the kernel of computational geometry and serv

python库skimage 绘制二值图像的凸壳(convex hull)

二值图像的凸壳指的是包围输入二值图像白色区域的最小的凸多边形的像素集合. skimage中的函数 from skimage.morphology import convex_hull_image chull = convex_hull_image(image) 完整代码: """ =========== Convex Hull =========== The convex hull of a binary image is the set of pixels included

OpenCV Tutorials &mdash;&mdash; Convex Hull

凸包 找到物体的轮廓之后,再找其凸包   void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true ) Parameters: points – Input 2D point set, stored in std::vector or Mat. hull – Output convex hull. It is either an integer vector

Hdu 3662 3D Convex Hull(三维凸包)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3662 思路:三维凸包模板. #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define PR 1e-8 #define N 510 using namespace std; struct TPoint { doub

opencv笔记(二十四)——得到轮廓之后找到凸包convex hull

当我们得到一张轮廓之后,我们可以对其运用convexHull方法,寻找该轮廓的凸包. 一个轮廓可以有无数个包围它的外壳,而其中表面积最小的一个外壳,就是凸包. void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true ) points是一个contour. vector<Point>类型或者Mat类型 hull是输出,也是一个点集vector<Poin

Monotone Chain Convex Hull(单调链凸包)

1 Monotone Chain Convex Hull(单调链凸包)算法伪代码: 2 //输入:一个在平面上的点集P 3 //点集 P 按 先x后y 的递增排序 4 //m 表示共a[i=0...m]个点,ans为要求的点; 5 struct P 6 { 7 int x,y; 8 friend int operator < (P a, P b) 9 { 10 if((a.x<b.x) || (a.x==b.x && a.y<b.y)) 11 return 1; 12 r