使用Graham扫描法求二维凸包的一个程序
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cstdio>
using namespace std;
includeall.h
#include "includeall.h"
typedef struct node{//一维链表使用的
double x, y, z;
struct node * next;
}Node; class Link{//有头节点的链表类
private: public:
Node * data=NULL;
private:
void init()//初始化链表
{
this->data=NULL;
this->data=new Node;
this->data->x=this->data->y=this->data->z=0.0;
this->data->next=NULL;
} void destroy()//清除链表占用的空间,包括头节点,所以之后链表不能再继续使用
{
this->clear();
delete this->data;
this->data=NULL;
} void check()//检验链表是否有效
{
if(this->data==NULL)
{
cout<<"链表未正确初始化或已经被销毁"<<endl;
exit();
}
} public: void add(double x,double y,double z)//增加一个节点
{
this->check();
Node * tmp=new Node;
tmp->x=x;tmp->y=y;tmp->z=z;
tmp->next=this->data->next;
this->data->next=tmp;
} void del(Node * prev)//删除一个节点
{
this->check();
Node * tmp=prev->next;
prev->next=prev->next->next;
delete tmp;
} void insert(Node * prev,double x,double y,double z)//在某个元素的后面插入一个节点
{
this->check();
Node * tmp=new Node;
tmp->x=x;tmp->y=y;tmp->z=z;
tmp->next=prev->next;
prev->next=tmp;
} int count()//统计链表中节点的数目
{
this->check();
int i=;
Node * tmp=this->data->next;;
while(tmp!=NULL)
{
tmp=tmp->next;
++i;
}
return i;
} Node * pointOfSpecificElement(int n)//获取指向特定第几个元素的指针
{
Node * tmp=this->data;
while(tmp!=NULL)
{
if(n<=) break;
--n;
tmp=tmp->next;
}
return tmp;
} void clear()//清空链表中的所有元素,不包括头节点
{
this->check();
while(!this->empty())
{
this->del(this->data);
}
} void copy(Link * link,int n=)//将参数链表中从第n个开始的元素拷贝增加到this链表,头节点作为第0个
{
Node * tmp=link->pointOfSpecificElement(n);
while(tmp!=NULL)
{
this->add(tmp->x,tmp->y,tmp->z);
tmp=tmp->next;
}
} bool empty()//链表是否为空
{
this->check();
return (this->data->next==NULL);
} Link()
{
this->init();
}
virtual ~Link()
{
this->destroy();
}
};
Link.class.h
int RightOrLeft(double x1,double y1,double x2,double y2,double x3,double y3)//判断第三个点在前两个点连成的直线的哪个位置,-1 左边,0,直线上,1 右边
{
int result;
if(x1-x2<0.000001 && x1-x2>-0.000001 && y1-y2<0.000001 && y1-y2>-0.000001)
{
return ;
}
double X=(y3-y1)*(x2-x1)/(y2-y1)+x1; if(X-x3<-0.000001)
{
result=;
}
else if(X-x3>0.000001)
{
result=-;
}
else{
result=;
}
if(y2-y1<-0.000001)
{
result=-result;
}
return result;
} /*
*该函数对link的所有点进行二维凸包运算
*link中的每个节点保存了一个点的三维坐标,二维凸包运输只会选取其中的两个坐标进行运算
*具体选取哪两个坐标由该函数的type参数决定
*type的合法取值为 3 5 6,取三代表选取yz坐标(3的二进制为011),取5代表选取xz坐标,取6代表选取xy坐标
*执行完凸包运算之后,link中的节点将被修改,所以如有必要,应该手动在调用该函数之前备份参数链表
*运算执行完之后,link的节点的z坐标将被清零,xy坐标将依据type的取值,对应于原始链表的某两个坐标
*
*/
void convelHull(Link * link,int type=)//对link中的元素进行二维凸包运算,执行后link中只有x,y值有效
{
if(link->count()<)
{
printf("Warning: no node in link\n");
return;
//exit(-1);
}
Link * link_tmp=new Link();
{//对利用link的某两个坐标构造link_tmp
Node * tmp=link->pointOfSpecificElement();
if(type==)
{
while(tmp!=NULL)
{
//此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
link_tmp->add(tmp->y,tmp->z,0.0);
//进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp=tmp->next;
}
}
else if(type==)
{
while(tmp!=NULL)
{
//此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
link_tmp->add(tmp->x,tmp->z,0.0);
//进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp=tmp->next;
}
}
else if(type==)
{
while(tmp!=NULL)
{
//此处将link的三维坐标系的某两个映射到函数内使用的link_tmp中,之后的操作将对link_tmp的x,y成员进行操作
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//可以在此处修改需要对原始的link链表中的哪两个坐标进行凸包运算
link_tmp->add(tmp->x,tmp->y,0.0);
//进行凸包运算之后,link的z坐标将被清零,例如此处,link的xy坐标分别对应原始的xz坐标
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tmp=tmp->next;
}
}
else{
printf("参数不符合规范\n");
exit(-);
}
}//link_tmp已经构造完成
{//将link_tmp中y坐标最小的点放到链表的第一个位置
Node * tmp=link_tmp->pointOfSpecificElement();
Node * tmp2=tmp;
while(tmp!=NULL && tmp->next!=NULL)
{
if(tmp->next->y<tmp2->next->y)
{
tmp2=tmp;
}
tmp=tmp->next;
}//tmp2指向y坐标最小的节点的前一个节点
link_tmp->add(tmp2->next->x,tmp2->next->y,tmp2->next->z);
link_tmp->del(tmp2);
}//y坐标最小的元素已经是链表的第一个节点
Node trans;//保存此时平移的距离,以便于最后把它们平移回来
{//所有点平移,使link_tmp第一个节点的坐标是坐标原点
trans.x=link_tmp->pointOfSpecificElement()->x;
trans.y=link_tmp->pointOfSpecificElement()->y;
//trans.z=link_tmp->pointOfSpecificElement(1)->z;
Node * tmp=link_tmp->pointOfSpecificElement();
while(tmp!=NULL)
{
tmp->x-=trans.x;
tmp->y-=trans.y;
//tmp->z-=trans.z;
tmp=tmp->next;
}
}//所有点的平移完成
{//从第二个点开始按与第一个点的距离从小到大排序
Node * tmp1=link_tmp->pointOfSpecificElement();
Node * tmp2=tmp1->next;
while(tmp2!=NULL)
{
//使用z成员保存其到原点的距离
tmp2->z=sqrt((tmp2->x* tmp2->x)+(tmp2->y*tmp2->y));
tmp2=tmp2->next;
}
tmp2=tmp1->next;
//int count=0;
while(tmp2!=NULL && tmp2->next!=NULL)
{//保证只有第一个点在坐标原点
if(tmp2->next->z==0.0)
{
link_tmp->del(tmp2);
//++count;
continue;
}
tmp2=tmp2->next;
}
//printf("去重次数:%d\n",count);
/*if(link_tmp->count()<3)
{
printf("对链表进行去重操作之后导致链表中剩余元素不足三个,无法进行后续运算\n");
exit(-1);
}*/
tmp2=tmp1->next->next;
while(tmp2!=NULL)
{
Node * minDis=tmp2;
Node * tmp3=tmp2;
while(tmp3!=NULL)
{
if(tmp3->z-minDis->z<-0.000001)
{
minDis=tmp3;
}
tmp3=tmp3->next;
}
if(minDis!=tmp2)
{
Node tmp;
tmp.x=minDis->x;
tmp.y=minDis->y;
tmp.z=minDis->z;
minDis->x=tmp2->x;
minDis->y=tmp2->y;
minDis->z=tmp2->z;
tmp2->x=tmp.x;
tmp2->y=tmp.y;
tmp2->z=tmp.z;
}
tmp2=tmp2->next;
}
}//按照距离排序完成
/*{//输出排序完的点的顺序
Node * tmp=link_tmp->pointOfSpecificElement(1);
printf("距离排序后的点(%d):\n",link_tmp->count());
while(tmp!=NULL)
{
printf("%.10f %.10f %.10f\n",tmp->x+trans.x,tmp->y+trans.y,tmp->z);
tmp=tmp->next;
}
}*/
{//从第二个点开始按与第一个点的幅角从小到大排序
Node * tmp1=link_tmp->pointOfSpecificElement();
Node * tmp2=tmp1->next;
while(tmp2!=NULL)
{
//使用z成员保存其幅角
tmp2->z=acos((tmp2->x/tmp2->z));
tmp2=tmp2->next;
}
tmp2=tmp1->next;
while(tmp2!=NULL)
{
Node * tmp3=tmp2->next;
Node * tmp4=tmp1->next;
while(tmp3!=NULL)
{
if(tmp4->next->z-tmp4->z<-0.000001)
{
Node tmp;
tmp.x=tmp4->x;
tmp.y=tmp4->y;
tmp.z=tmp4->z;
tmp4->x=tmp4->next->x;
tmp4->y=tmp4->next->y;
tmp4->z=tmp4->next->z;
tmp4->next->x=tmp.x;
tmp4->next->y=tmp.y;
tmp4->next->z=tmp.z;
}
tmp4=tmp4->next;
tmp3=tmp3->next;
}
tmp2=tmp2->next;
}
}//按照幅角排序完成
/*{//输出排序完的点的顺序
Node * tmp=link_tmp->pointOfSpecificElement(1);
printf("幅角排序后的点(%d):\n",link_tmp->count());
while(tmp!=NULL)
{
printf("%.10f %.10f %.10f\n",tmp->x+trans.x,tmp->y+trans.y,tmp->z);
tmp=tmp->next;
}
}*/
{//对其进行求凸包运算
Link * stk_tmp=new Link();
Node * tmp=link_tmp->pointOfSpecificElement();
stk_tmp->add(tmp->x,tmp->y,0.0);
tmp=tmp->next;
if(tmp!=NULL) stk_tmp->add(tmp->x,tmp->y,0.0);
if(link_tmp->count()>=)
{
Node * stkTop=stk_tmp->pointOfSpecificElement();//指向栈顶元素
Node * stkNext=stkTop->next;//指向栈顶的下一个元素
Node * current=tmp->next;//指向当前点
//int count1=0,count2=0;
while()
{
if(RightOrLeft(stkNext->x,stkNext->y,stkTop->x,stkTop->y,current->x,current->y)==)
{
//++count1;
stk_tmp->del(stk_tmp->pointOfSpecificElement());
stkTop=stk_tmp->pointOfSpecificElement();
stkNext=stkTop->next;
}
else{
//++count2;
stk_tmp->add(current->x,current->y,0.0);
//cout<<"入栈"<<current->x+trans.x<<" "<<current->y+trans.y<<endl;
stkTop=stk_tmp->pointOfSpecificElement();
stkNext=stkTop->next;
if(current->next==NULL) break;
else{
current=current->next;
}
}
}//end of while
}
//printf("入栈次数:%d\n",count2);
//printf("出栈次数:%d\n",count1);
//现在栈 stk_tmp中保存有凸包上的点
{//对凸包上的点平移到原位置
Node * tmp=stk_tmp->pointOfSpecificElement();
while(tmp!=NULL)
{
tmp->x+=trans.x;
tmp->y+=trans.y;
//tmp->z+=trans.z;
tmp=tmp->next;
}
}//平移到原位置完成
delete link_tmp;
link->clear();
link->copy(stk_tmp);
delete stk_tmp;
}//凸包运算完成
}// end of function convelHull
convelHull.func.h
#include "includeall.h"
#include "Link.class.h"
#include "convelHull.func.h" char * filename1=(char *)"./data/凸包问题输入.asc";
char * filename2 = (char *)"./data/tubao_out.asc";
void constructBody(Link * link,char * filename)//由点云文件构造点云模型
{
FILE * fp;
if (fp = fopen(filename, "r"), fp == NULL)
{
cout << "文件打开失败,文件路径:" << filename << endl;
exit();
}
fseek(fp,,SEEK_SET);
float x,y,z;
int count=;
while(!feof(fp))
{
fscanf(fp,"%f %f %f\n",&x,&y,&z); ++count;
if(count>=)
{
link->add(x*,y*,z*);
count=;
}
}
fclose(fp);
}
void saveToFile(Link * link,char * filename)//将一个链表中的内容保存到指定的文件中
{
FILE * fp=NULL;
if(fp=fopen(filename,"w"),fp==NULL) exit();
Node * tmp=link->data->next;
while(tmp!=NULL)
{
fprintf(fp,"%.5f %.5f %.5f\n",tmp->x,tmp->y,tmp->z);
tmp=tmp->next;
}
fclose(fp);
} int main()
{
Link * link=new Link(); /* link->add(0,0,-1);
link->add(0,0,0);
link->add(0,0,1);
link->add(0,0,2); link->add(-1,0,-1);
link->add(-1,0,0);
link->add(-1,0,1);
link->add(-1,0,2); link->add(-2,0,-1);
link->add(-2,0,0);
link->add(-2,0,1);
link->add(-2,0,2); link->add(1,0,-1);
link->add(1,0,0);
link->add(1,0,1);
link->add(1,0,2); link->add(2,0,-1);
link->add(2,0,0);
link->add(2,0,1);
link->add(2,0,2); link->add(-2,0,-2);
link->add(-1,0,-2);
link->add(0,0,-2);
link->add(1,0,-2);
link->add(2,0,-2);
link->add(3,0,-2);
link->add(5,0,0);
link->add(-5,0,0); */ /* link->add(0,0,0);
link->add(1,0,1);
link->add(2,0,2);
link->add(3,0,3);
link->add(4,0,4);
link->add(5,0,5);
link->add(6,0,6);
*/
//constructBody(link,filename1);
link->add(,,);
link->add(,,);
link->add(,,);
Node * tmp=link->pointOfSpecificElement();
printf("未进行凸包运算的点(%d):\n",link->count());
while(tmp!=NULL)
{
printf("%f %f %f\n",tmp->x,tmp->y,tmp->z);
tmp=tmp->next;
}
printf("\n");
convelHull(link,);
saveToFile(link,filename2);
tmp=link->pointOfSpecificElement();
printf("进行过凸包运算的点(%d):\n",link->count());
while(tmp!=NULL)
{
printf("%f %f %f\n",tmp->x,tmp->y,tmp->z);
tmp=tmp->next;
}
printf("\n");
printf("test: %d\n",RightOrLeft(,,,,-,));
printf("test: %d\n",RightOrLeft(,,-,,,));
printf("test: %d\n",RightOrLeft(,,-,-,-,));
printf("test: %d\n",RightOrLeft(,,,-,,-));
return ;
}
main.cpp
就当是记录一下,程序写得不完美
使用Graham扫描法求二维凸包的一个程序的更多相关文章
- Andrew算法求二维凸包-学习笔记
凸包的概念 首先,引入凸包的概念: (有点窄的时候...图片右边可能会被吞,拉开图片看就可以了) 大概长这个样子: 那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包) Andrew算 ...
- Codeforces Gym 100286A. Aerodynamics 计算几何 求二维凸包面积
Problem A. AerodynamicsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/co ...
- 【计算几何】二维凸包——Graham's Scan法
凸包 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内.右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包. 一组平面上的点, ...
- (模板)poj1113(graham扫描法求凸包)
题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code ...
- Luogu P2742 模板-二维凸包
Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...
- 计算几何 二维凸包问题 Andrew算法
凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...
- poj 2079 Triangle (二维凸包旋转卡壳)
Triangle Time Limit: 3000MS Memory Limit: 30000KB 64bit IO Format: %I64d & %I64u Submit Stat ...
- poj 2187 Beauty Contest(二维凸包旋转卡壳)
D - Beauty Contest Time Limit:3000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u ...
- luogu P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
题解: 二维凸包裸题 按照x坐标为第一关键字,y坐标为第二关键字排序 然后相邻判断叉积用单调队列搞过去 正反都做一次就好了 代码: #include <bits/stdc++.h> usi ...
随机推荐
- ArcGIS API for Silverlight开发入门准备
原文:ArcGIS API for Silverlight开发入门准备 微软的Silverlight提供了跨浏览器和跨平台开发环境,在Web中可用于创建和展现富互联网应用(RIA,Rich Inter ...
- LightOj1203 - Guarding Bananas(凸包求多边形中的最小角)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1203 题意:给你一个点集,求凸包中最小的角:模板题,但是刚开始的时候模板带错了,错的我 ...
- [转]android自动弹出软键盘(输入键盘)
转自:http://www.devdiv.com/home.php?mod=space&uid=65729&do=blog&id=11847 很多应用中对于一个界面比如进入搜索 ...
- event.pageY和event.pageX
event.pageY 属性返回鼠标指针的位置,相对于文档的上边缘. 提示:该事件属性通常与 event.pageX属性一起使用.(简写:e.pageY(或者e.pageX)) 实例: drag 首先 ...
- 详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(完)——法线变换
前面两节内容已经说完了所有的三种变换.也就是说我们现在程序里面既不需要glLookAt(),也不需要gluPerspective(),这些矩阵我们都可以自己写.然后,再用glMultMatrix()来 ...
- 第三篇 Replication:事务复制-发布服务器
本篇文章是SQL Server Replication系列的第三篇,详细内容请参考原文. 发布服务器是所有复制数据的源头.每一个发布服务器上可以定义多个发布.每一个发布包含一组项目(项目在同一个数据库 ...
- Unity插件研究院之ResourceChecker
这个插件是我在国外网站逛论坛发现的,试用了一下非常好用,是一个轻量级的插件就一个类.开发中尤其是和美术合作的时候,可能你会发现Project视图中有很多没有用到的资源,但是你又不敢删除,因为你不知道那 ...
- MongoDB是?
MongoDB是? MongoDB是一个基于分布式文件存储的数据库 由C++编写 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当 ...
- javaEE开发案例——购物车
一.页面 流程:登录页面(login.jsp)——>购物大厅页面(hall.jsp)——>购物车页面(showMyCart.jsp)——>订单页面(myorder.jsp)——> ...
- bootstrap学习之二-组件
一.bootstrap字体图标 以span的形式出现,通常可以用于一个button或者其他元素的内文本, <span class="glyphicon glyphicon-sort-b ...