码迷,mamicode.com
首页 > 其他好文 > 详细

使用Graham扫描法求二维凸包的一个程序

时间:2015-11-08 15:09:35      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

技术分享
  1 #include "includeall.h"
  2 #include "Link.class.h"
  3 
  4 int RightOrLeft(float x1,float y1,float x2,float y2,float x3,float y3)//判断第三个点在前两个点连成的直线的哪个位置,-1 左边,0,直线上,1 右边
  5 {
  6     float X=(y3-y1)*(x2-x1)/(y2-y1)+x1;
  7     if(X<x3)
  8     {
  9         return 1;
 10     }
 11     else if(X>x3)
 12     {
 13         return -1;
 14     }
 15     else{
 16         return 0;
 17     }
 18 }
 19 
 20 
 21 /*
 22 *该函数对link的所有点进行二维凸包运算
 23 *link中的每个节点保存了一个点的三维坐标,二维凸包运输只会选取其中的两个坐标进行运算
 24 *具体选取哪两个坐标由该函数的type参数决定
 25 *type的合法取值为 3 5 6,取三代表选取yz坐标(3的二进制为011),取5代表选取xz坐标,取6代表选取xy坐标
 26 *执行完凸包运算之后,link中的节点将被修改,所以如有必要,应该手动在调用该函数之前备份参数链表
 27 *运算执行完之后,link的节点的z坐标将被清零,xy坐标将依据type的取值,对应于原始链表的某两个坐标
 28 *
 29 */
 30 void convelHull(Link * link,int type=5)//对link中的元素进行二维凸包运算,执行后link中只有x,y值有效
 31 {
 32     if(link->count()<3)
 33     {
 34         printf("待求凸包的链表中至少有三个元素\n");
 35         exit(-1);
 36     }
 37     Link * link_tmp=new Link();
 38     {//对利用link的某两个坐标构造link_tmp
 39         Node * tmp=link->pointOfSpecificElement(1);
 40         if(type==3)
 41         {
 42             while(tmp!=NULL)
 43             {
 44                 //此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
 45                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 46                 //可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
 47                 link_tmp->add(tmp->y,tmp->z,0.0);
 48                 //进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
 49                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 50                 tmp=tmp->next;
 51             }
 52         }
 53         else if(type==5)
 54         {
 55             while(tmp!=NULL)
 56             {
 57                 //此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
 58                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 59                 //可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
 60                 link_tmp->add(tmp->x,tmp->z,0.0);
 61                 //进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
 62                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 63                 tmp=tmp->next;
 64             }
 65         }
 66         else if(type==6)
 67         {
 68             while(tmp!=NULL)
 69             {
 70                 //此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
 71                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 72                 //可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
 73                 link_tmp->add(tmp->x,tmp->y,0.0);
 74                 //进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
 75                 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 76                 tmp=tmp->next;
 77             }
 78         }
 79         else{
 80             printf("参数不符合规范\n");
 81             exit(-1);
 82         }
 83     }//link_tmp已经构造完成
 84     {//将link_tmp中y坐标最小的点放到链表的第一个位置
 85         Node * tmp=link_tmp->pointOfSpecificElement(0);
 86         Node * tmp2=tmp;
 87         while(tmp!=NULL && tmp->next!=NULL)
 88         {
 89             if(tmp->next->y<tmp2->next->y)
 90             {
 91                 tmp2=tmp;
 92             }
 93             tmp=tmp->next;
 94         }//tmp2指向y坐标最小的节点的前一个节点
 95         link_tmp->add(tmp2->next->x,tmp2->next->y,tmp2->next->z);
 96         link_tmp->del(tmp2);
 97     }//y坐标最小的元素已经是链表的第一个节点
 98     Node trans;//保存此时平移的距离,以便于最后把它们平移回来
 99     {//所有点平移,使link_tmp第一个节点的坐标是坐标原点
100         trans.x=link_tmp->pointOfSpecificElement(1)->x;
101         trans.y=link_tmp->pointOfSpecificElement(1)->y;
102         //trans.z=link_tmp->pointOfSpecificElement(1)->z;
103         Node * tmp=link_tmp->pointOfSpecificElement(1);
104         while(tmp!=NULL)
105         {
106             tmp->x-=trans.x;
107             tmp->y-=trans.y;
108             //tmp->z-=trans.z;
109             tmp=tmp->next;
110         }
111     }//所有点的平移完成
112     
113     {//从第二个点开始按与第一个点的距离从小到大排序
114         Node * tmp1=link_tmp->pointOfSpecificElement(0);
115         Node * tmp2=tmp1->next;
116         while(tmp2!=NULL)
117         {
118             //使用z成员保存其到原点的距离
119             tmp2->z=sqrt((tmp2->x* tmp2->x)+(tmp2->y*tmp2->y));
120             tmp2=tmp2->next;
121         }
122         tmp2=tmp1->next;
123         while(tmp2!=NULL && tmp2->next!=NULL)
124         {//保证只有第一个点在坐标原点
125             if(tmp2->next->z==0.0)
126             {
127                 link_tmp->del(tmp2);
128                 continue;
129             }
130             tmp2=tmp2->next;
131         }
132         if(link_tmp->count()<3)
133         {
134             printf("对链表进行去重操作之后导致链表中剩余元素不足三个,无法进行后续运算\n");
135             exit(-1);
136         }
137         tmp2=tmp1->next->next;
138         while(tmp2!=NULL)
139         {
140             Node * minDis=tmp2;
141             Node * tmp3=tmp2;
142             while(tmp3!=NULL)
143             {
144                 if(tmp3->z<minDis->z)
145                 {
146                     minDis=tmp3;
147                 }
148                 tmp3=tmp3->next;
149             }
150             if(minDis!=tmp2)
151             {
152                 Node tmp;
153                 tmp.x=minDis->x;
154                 tmp.y=minDis->y;
155                 tmp.z=minDis->z;
156                 minDis->x=tmp2->x;
157                 minDis->y=tmp2->y;
158                 minDis->z=tmp2->z;
159                 tmp2->x=tmp.x;
160                 tmp2->y=tmp.y;
161                 tmp2->z=tmp.z;
162             }
163             tmp2=tmp2->next;
164         }
165     }//按照距离排序完成
166     {//从第二个点开始按与第一个点的幅角从小到大排序
167         Node * tmp1=link_tmp->pointOfSpecificElement(1);
168         Node * tmp2=tmp1->next;
169         while(tmp2!=NULL)
170         {
171             //使用z成员保存其幅角
172             tmp2->z=acos((tmp2->x/tmp2->z));
173             tmp2=tmp2->next;
174         }
175         tmp2=tmp1->next;
176         while(tmp2!=NULL)
177         {
178             Node * minAng=tmp2;
179             Node * tmp3=tmp2;
180             while(tmp3!=NULL)
181             {
182                 if(tmp3->z<minAng->z)
183                 {
184                     minAng=tmp3;
185                 }
186                 tmp3=tmp3->next;
187             }
188             if(minAng!=tmp2)
189             {
190                 Node tmp;
191                 tmp.x=minAng->x;
192                 tmp.y=minAng->y;
193                 tmp.z=minAng->z;
194                 minAng->x=tmp2->x;
195                 minAng->y=tmp2->y;
196                 minAng->z=tmp2->z;
197                 tmp2->x=tmp.x;
198                 tmp2->y=tmp.y;
199                 tmp2->z=tmp.z;
200             }
201             tmp2=tmp2->next;
202         }
203     }//按照幅角排序完成
204     {//对其进行求凸包运算
205         Link * stk_tmp=new Link();
206         Node * tmp=link_tmp->pointOfSpecificElement(1);
207         stk_tmp->add(tmp->x,tmp->y,0.0);
208         tmp=tmp->next;
209         stk_tmp->add(tmp->x,tmp->y,0.0);
210         Node * stkTop=stk_tmp->pointOfSpecificElement(1);//指向栈顶元素
211         Node * stkNext=stkTop->next;//指向栈顶的下一个元素
212         Node * current=tmp->next;//指向当前点
213         while(1)
214         {
215             if(RightOrLeft(stkNext->x,stkNext->y,stkTop->x,stkTop->y,current->x,current->y)==1)
216             {
217                 stk_tmp->del(stk_tmp->pointOfSpecificElement(0));
218                 stkTop=stk_tmp->pointOfSpecificElement(1);
219                 stkNext=stkTop->next;
220             }
221             else{
222                 stk_tmp->add(current->x,current->y,0.0);
223                 stkTop=stk_tmp->pointOfSpecificElement(1);
224                 stkNext=stkTop->next;
225                 if(current->next==NULL) break;
226                 else{
227                     current=current->next;
228                 }
229             }
230         }//end of while
231         //现在栈 stk_tmp中保存有凸包上的点
232         {//对凸包上的点平移到原位置
233             Node * tmp=stk_tmp->pointOfSpecificElement(1);
234             while(tmp!=NULL)
235             {
236                 tmp->x+=trans.x;
237                 tmp->y+=trans.y;
238                 //tmp->z+=trans.z;
239                 tmp=tmp->next;
240             }
241         }//平移到原位置完成
242         delete link_tmp;
243         link->clear();
244         link->copy(stk_tmp);
245         delete stk_tmp;
246     }//凸包运算完成
247 }// end of function convelHull
248 int main()
249 {
250     Link * link=new Link();
251     link->add(0,1,0);
252     link->add(0,1,1);
253     link->add(1,1,0);
254     link->add(1,1,1);
255     link->add(2,1,2);
256     link->add(5,1,1);
257     
258     Node * tmp=link->pointOfSpecificElement(1);
259     printf("未进行凸包运算的点(%d):\n",link->count());
260     while(tmp!=NULL)
261     {
262         printf("%f %f %f\n",tmp->x,tmp->y,tmp->z);
263         tmp=tmp->next;
264     }
265     printf("\n");
266     convelHull(link,5);
267      tmp=link->pointOfSpecificElement(1);
268     printf("进行过凸包运算的点(%d):\n",link->count());
269     while(tmp!=NULL)
270     {
271         printf("%f %f %f\n",tmp->x,tmp->y,tmp->z);
272         tmp=tmp->next;
273     }
274     printf("\n");
275     return 0;
276 }
main.cpp
技术分享
  1 #include "includeall.h"
  2 typedef struct node{//一维链表使用的
  3     float x, y, z;
  4     struct node * next;
  5 }Node;
  6 
  7 class Link{//有头节点的链表类
  8 private:
  9 
 10 public:
 11     Node * data=NULL;
 12 private:
 13     void init()//初始化链表
 14     {
 15         this->data=NULL;
 16         this->data=new Node;
 17         this->data->x=this->data->y=this->data->z=0.0;
 18         this->data->next=NULL;
 19     }
 20     
 21     void destroy()//清除链表占用的空间,包括头节点,所以之后链表不能再继续使用
 22     {
 23         this->clear();
 24         delete this->data;
 25         this->data=NULL;
 26     }
 27     
 28     void check()//检验链表是否有效
 29     {
 30         if(this->data==NULL)
 31         {
 32             cout<<"链表未正确初始化或已经被销毁"<<endl;
 33             exit(0);
 34         }
 35     }
 36     
 37 public:
 38 
 39     void add(float x,float y,float z)//增加一个节点
 40     {
 41         this->check();
 42         Node * tmp=new Node;
 43         tmp->x=x;tmp->y=y;tmp->z=z;
 44         tmp->next=this->data->next;
 45         this->data->next=tmp;
 46     }
 47     
 48     void del(Node * prep)//删除一个节点
 49     {
 50         this->check();
 51         Node * tmp=prep->next;
 52         prep->next=prep->next->next;
 53         delete tmp;
 54     }
 55     
 56     int count()//统计链表中节点的数目
 57     {
 58         this->check();
 59         int i=0;
 60         Node * tmp=this->data->next;;
 61         while(tmp!=NULL)
 62         {
 63             tmp=tmp->next;
 64             ++i;
 65         }
 66         return i;
 67     }
 68     
 69     Node * pointOfSpecificElement(int n)//获取指向特定第几个元素的指针
 70     {
 71         Node * tmp=this->data;
 72         while(tmp!=NULL)
 73         {
 74             if(n<=0) break;
 75             --n;
 76             tmp=tmp->next;
 77         }
 78         return tmp;
 79     }
 80     
 81     void clear()//清空链表中的所有元素,不包括头节点
 82     {
 83         this->check();
 84         while(!this->empty())
 85         {
 86             this->del(this->data);
 87         }
 88     }
 89     
 90     void copy(Link * link,int n=1)//将参数链表中从第n个开始的元素拷贝增加到this链表,头节点作为第0个
 91     {
 92         Node * tmp=link->pointOfSpecificElement(n);
 93         while(tmp!=NULL)
 94         {
 95             this->add(tmp->x,tmp->y,tmp->z);
 96             tmp=tmp->next;
 97         }
 98     }
 99     
100     
101     bool empty()//链表是否为空
102     {
103         this->check();
104         return (this->data->next==NULL);
105     }
106     
107     Link()
108     {
109         this->init();
110     }
111     virtual ~Link()
112     {
113         this->destroy();
114     }
115 };
Link.class.h

 

使用Graham扫描法求二维凸包的一个程序

标签:

原文地址:http://www.cnblogs.com/zhanghaha/p/4947130.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!