DECL
DECL结构是比较通用的来表示几何的数据结构
主要包括三种数据结构:
1.点 vertex
2.半边 edge
3.面 face
点
存储点的位置以及任意一条由该点为起点向量的半边
半边
其中几何边由两条半边组成
这也是一种表示方式
面
存储一个面的外边界和内边界,如果外边界或者内边界不存在那么直接等于nullptr
像下面这种情况内部空洞需要用一个vector来存储了
通用的表达方式
数据结构简单实现(不包括具体操作)
template<typename type = float, size_t dim = DIM3> struct VertexDCEL {
Vector<float, dim> point;// 1.Coordinates EdgeDCEL<type, dim>* incident_edge = nullptr;// 2.以point任意为起点的半边 VertexDCEL(Vector<type, dim>& _point) :point(_point) {
} //...... }; template<typename type = float, size_t dim = DIM3> struct EdgeDCEL {
//1.起始点 VertexDCEL<type, dim>* origin = nullptr; //2.与该半边相关联的三条半边 EdgeDCEL<type, dim>* twin = nullptr; EdgeDCEL<type, dim>* next = nullptr; EdgeDCEL<type, dim>* prev = nullptr; //3.该半边对应的面 FaceDCEL<type, dim>* incident_face = nullptr; int id = -1; EdgeDCEL() :id(-1) {
} EdgeDCEL(VertexDCEL<type, dim>* _origin) :origin(_origin) {
id++; } VertexDCEL<type, dim>* destination() {
return twin->origin; } //...... }; template<typename type = float, size_t dim = DIM3> struct FaceDCEL {
EdgeDCEL<type, dim>* outer = nullptr; std::vector< EdgeDCEL<type, dim>*>inner;//可能会有空洞 void print()//只输出外边界 {
if (outer) {
auto edge_ptr = outer; auto next_ptr = outer->next; edge_ptr->origin->print(); while (next_ptr != edge_ptr) {
next_ptr->origin->print(); next_ptr = next_ptr->next; } } } //...... }; template<typename type, size_t dim = DIM3> class PolygonDCEL {
typedef Vector<type, dim> VetorNf; std::vector< VertexDCEL<type, dim>* > vertex_list; std::vector< EdgeDCEL<type, dim>* > edge_list; std::vector< FaceDCEL<type, dim>* > face_list; //保存空的边,没有组成面->边集合 EdgeDCEL<type, dim>* empty_edge = new EdgeDCEL<type, dim>(); public: explicit PolygonDCEL(std::vector< VetorNf>&); bool split(VertexDCEL<type, dim>* _v1, VertexDCEL<type, dim>* _v2); bool join(VertexDCEL<type, dim>* _v1, VertexDCEL<type, dim>* _v2); std::vector<VertexDCEL<type, dim>*> getVertexList(); std::vector<FaceDCEL<type, dim>*> getFaceList(); std::vector<EdgeDCEL<type, dim>*> getEdgeList(); VertexDCEL<type, dim>* getVertex(VectorNf&); void getEdgesWithSamefaceAndGivenOrigins(VertexDCEL<type, dim>* _v1, VertexDCEL<type, dim>* _v2, EdgeDCEL<type, dim>** edge_leaving_v1, EdgeDCEL<type, dim>** edge_leaving_v2); };
构造简单多边形的函数
template<typename type, size_t dim> inline PolygonDCEL<type, dim>::PolygonDCEL(std::vector<VetorNf>& _points) {
int size = _points.size(); if (size < 3) return; //1.根据所给点,创建vertex for (size_t y = 0; i < _points.size(); ++i) {
vertex_list.push_back(new VertexDCEL<type, dim>(_points[i])); } //2.根据创建vertex,创建半边 for (size_t i = 0; i <= vertex_list.size() - 2; ++i) {
auto hfedge = new EdgeDCEL<type, dim>(vertex_list[i]); vertex_list[i]->incident_dege = hfedge; auto edge_twin = new EdgeDCEL<type, dim>(vertex_list[i + 1]); hfedge->twin = edge_twin; edge_twin->twin = hfedge; edge_list.push_back(hfedge); edge_list.push_back(edge_twin); } //最后一条边 auto hfedge = new EdgeDCEL<type, dim>(vertex_list.back()); vertex_list[vertex_list.size() - 1]->incident_dege = hfedge; auto edge_twin = new EdgeDCEL<type, dim>(vertex_list.front()); hfedge->twin = edge_twin; edge_twin->twin = hfedge; edge_list.push_back(hfedge); edge_list.push_back(edge_twin); //设置next,prev指针 //edge_list里面是根据半边的顺序存储,所以注意是每隔2个处理一次 for (size_t i = 2; i <= edge_list.size() - 3; ++i) {
if (i % 2 == 0)//设置半边 {
edge_list[i]->prev = edge_list[i - 2]; edge_list[i]->next = edge_list[i + 2]; } else//设置twin半边 {
edge_list[i]->prev = edge_list[i + 2]; edge_list[i]->next = edge_list[i - 2]; } } edge_list[0]->prev = edge_list[edge_list.size() - 2]; edge_list[0]->next = edge_list[2]; edge_list[1]->prev = edge_list[3]; edge_list[1]->next = edge_list[edge_list.size() - 1]; edge_list[edge_list.size() - 2]->prev = edge_list[edge_list.size() - 4]; edge_list[edge_list.size() - 2]->next = edge_list[0]; edge_list[edge_list.size() - 1]->prev = edge_list[1]; edge_list[edge_list.size() - 1]->next = edge_list[edge_list.size() - 3]; //3.新建face FaceDCEL<type, dim>* f1 = new FaceDCEL<type, dim>();//简单多边形的内半边 FaceDCEL<type, dim>* f2 = new FaceDCEL<type, dim>();//简单多边形的外半边 f1->outer = edge_list[0]; f2->inner.push_back(edge_list[1]); //设置整个内部face f1外边界的半边对应incident_face f1->outer->incident_face = f1; EdgeDCEL<type, dim>* edge = f1->outer->next; while (edge!= f1->outer) {
edge->incident_face = f1; edge = edge->next; } //设置整个外部face f2内边界的半边对应incident_face f2->inner[0]->incident_face = f2; edge = f2->inner[0]->next; while (edge != f2->inner[0]) {
edge->incident_face = f2; edge = edge->next; } }
重要操作一 找到一个vertex的所有出度边
template<typename type, size_t dim> inline void PolygonDCEL<type, dim>::getEdgesWithSamefaceAndGivenOrigins(VertexDCEL<type, dim>* _v1, VertexDCEL<type, dim>* _v2, EdgeDCEL<type, dim>** edge_leaving_v1, EdgeDCEL<type, dim>** edge_leaving_v2) {
std::vector<EdgeDCEL<type, dim>*> edges_with_v1_ori, edges_with_v2_ori; auto v1_inci_edge = _v1->incident_edge; edges_with_v1_ori.push_back(v1_inci_edge); auto next_edge = v1_inci_edge->twin->next; while (next_edge != v1_inci_edge) {
edges_with_v1_ori.push_back(next_edge); next_edge = next_edge->twin->next; } auto v2_inci_edge = _v2->incident_edge; edges_with_v2_ori.push_back(v2_inci_edge); auto next_edge = v2_inci_edge->twin->next; while (next_edge != v2_inci_edge) {
edges_with_v2_ori.push_back(next_edge); next_edge = next_edge->twin->next; } //edges_with_v1_ori与edges_with_v2_ori里面存的半边对应的incident_face是不一样的 for (auto& ev1 : edges_with_v1_ori) {
for (auto& ev2 : edges_with_v2_ori) {
if (ev1->incident_face->outer != nullptr) {
//找内部的面 if (ev1->incident_face == ev2->incident_face) {
//找相同的内部面 //这两条半边必定是相反的方向!!!!可以根据其遍历两个部分 **edge_leaving_v1 = ev1; *edge_leaving_v2 = ev2; return; } } } } }
重要操作二 split
template<typename type, size_t dim> inline bool PolygonDCEL<type, dim>::split(VertexDCEL<type, dim>* _v1, VertexDCEL<type, dim>* _v2) {
EdgeDCEL<type, dim>* edge_oriV1; EdgeDCEL<type, dim>* edge_oriV2; getEdgesWithSamefaceAndGivenOrigins(_v1, _v2, &edge_oriV1, &edge_oriV2); if (edge_oriV1->id == -1 || edge_oriV2->id == -1) return false; //判断是否是邻边 if (edge_oriV1->next->origin == _v2 || edge_oriV1->prev->origin == _v2) return false; //创建新对边 auto half_edge1 = new EdgeDCEL<type, dim>(_v1); auto half_edge2 = new EdgeDCEL<type, dim>(_v2); //设置新半边 half_edge1->twin = half_edge2; half_edge2->twin = half_edge1; half_edge1->next = edge_oriV2; half_edge2->next = edge_oriV1; half_edge1->next->prev = half_edge1; half_edge2->next->prev = half_edge2; half_edge1->prev = edge_oriV1->prev; half_edge2->prev = edge_oriV2->prev; half_edge1->prev->next = half_edge1; half_edge2->prev->next = half_edge2; //新建两个面,并删除旧的面,设置面 FaceDCEL<type, dim>* new_face1 = new FaceDCEL<type, dim>(); new_face1->outer = half_edge1; half_edge1->incident_face = new_face1; auto temp_edge = half_edge1->next; while (temp_edge != half_edge1) {
temp_edge->incident_face = new_face1; temp_edge = temp_edge->next; } FaceDCEL<type, dim>* new_face2 = new FaceDCEL<type, dim>(); new_face2->outer = half_edge2; half_edge2->incident_face = new_face2; temp_edge = half_edge2->next; while (temp_edge != half_edge2) {
temp_edge->incident_face = new_face2; temp_edge = temp_edge->next; } face_list.push_back(new_face1); face_list.push_back(new_face2); //删除原先的面 FaceDCEL<type, dim>* previous_face = edge_oriV1->incident_face; auto itr = std::find(face_list.begin(), face_list.end(), previous_face); if (itr != face_list.end()) {
face_list.erase(itr); delete previous_face; } return true; }
单调多边形
正例
反例
单调多边形拆分
vertex种类
1.开始顶点
2.结束顶点
3.普通顶点
4.分裂顶点
5.合并顶点
开始顶点与结束顶点是一对,面向多边形内部的角度是锐角
普通顶点,两个端点是上下一侧
分裂顶点和合并顶点是需要实际操作的,单调多边形拆分主要是拆这两个顶点
分裂顶点是与多边形上边内部点相连内对角线,进行拆分。
合并顶点是与多边形下 边内部点相连内对角线,进行拆分。
Plane sweep algorithm
伪代码
辅助顶点
如何去决定内对角线应该和谁相连呢?
对于不同vertex不同的操作
start vertex
end顶点
翻译:
如果边的辅助点的类别在这个顶点结束是一个归并顶点(helper(ei)->merge vertex),那么我们可以在这个辅助点和当前顶点之间添加一条对角线
从T中删除顶点的端点
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/81047.html