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
时间: 2024-10-12 00:50:24