版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/OOFFrankDura/article/details/81639592
综述
3D Vornoi和Powerdiagram的例子比较少。这里给出一些方法。
说明
这里给出两个版本
版本一
使用一般的RT完成
(注意在add_point中最后一个参数带权重则为powerdiagram,如果为0就为Voronoidiagram)
支持Delaunay三角的顶点输出
支持显示所有Voronoi顶点输出
(一般使用推荐使用版本一)
版本二
使用LCC map完成,数据查询更为方便,但是数据结构较难组织
支持Delaunay三角的顶点输出
支持显示所有Voronoi顶点输出
支持显示所有有限空间划分的顶点输出
更新
2018.8.14
2018.8.16 提供了一种更为普遍的方法
有网友和我交流问“3D powerdiagram”是否可以这样组织(通过三角正则化求对偶)?
事实上是不能的。
因为LCC没有Weighted_Point的类型,也就是说不支持。
所以还是要使用:
CGAL::Exact_predicates_inexact_constructions_kernel
下的
Weighted_Point;
环境
clion
maxos
代码
版本一代码
//作者:SDU窦志扬
//日期:2018/8/16
//联络:[email protected]
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Regular_triangulation_3.h>
#include <CGAL/Weighted_point_3.h>
#include <GLUT/glut.h>
#include <CGAL/bounding_box.h>
#include <fstream>
#include<iostream>
#include<set>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Regular_triangulation_3<K> Regular_triangulation;
typedef K::Vector_3 Vector;
typedef K::Point_3 Point;
typedef K::Weighted_point_3 Wp;
typedef K::Point_3 Point;
typedef CGAL::Regular_triangulation_3<K> Rt;
using namespace std;
vector<Regular_triangulation::Weighted_point> wpoints;
vector<Point> points;
vector<double> X, Y, Z;
set<Point> Voronoi_vert;
void add_point(double x, double y, double z , double w){
wpoints.push_back( Wp(Point(x,y,z), w) );
points.push_back(Point(x,y,z) );
X.push_back(x);
Y.push_back(y);
Z.push_back(z);
}
void display(void)
{
add_point(100+0, 100+0,100+0,0); //左中
add_point(100+100,100+0,100+0,0);
add_point(100+0,100+0,100+400,0); //目标点
add_point(100+0, 100+200,100+0,0);
add_point(300+0, 70+200,100+0,0);
add_point(20+0, 19+200,80+0,0);
add_point(100+0, 100+200,100+0,0);
add_point(100+10, 100+20,100+20,000);
Regular_triangulation rt(wpoints.begin(), wpoints.end());
rt.is_valid();
Regular_triangulation::Edge_iterator eit;
Regular_triangulation::Point_iterator pit;
//遍历Delaunay的所有边,绘制Delaunay图的对偶图,即Voronoi图
cout << "====all points in rt====" << endl;
for (auto vit = rt.vertices_begin(); vit != rt.vertices_end(); ++vit){
cout << vit->point() << endl;
}
cout << "==== Voronoi vert ====" << endl;
Rt::Finite_edges_iterator fei;
for (fei = rt.finite_edges_begin(); fei != rt.finite_edges_end(); fei++)
{
//遍历每个边
auto face = rt.incident_facets(*fei);
auto face_start = face;
//找到与边相邻的面(更准确的,遍历每个邻接面)
do {
CGAL::Object dualedge = rt.dual(*face);
//找到面对应的边
if (CGAL::object_cast<Rt::Segment>(&dualedge))
{
Point source = CGAL::object_cast<Rt::Segment>(&dualedge)->source();
Point target = CGAL::object_cast<Rt::Segment>(&dualedge)->target();
Voronoi_vert.insert(source);
Voronoi_vert.insert(target);
} else if (CGAL::object_cast<Rt::Ray>(&dualedge))//如果这条边是射线,则绘制射线
{
Point target = CGAL::object_cast<Rt::Ray>(&dualedge)->source();
Voronoi_vert.insert(target);
}
++face;
} while (face_start != face);
}
}
int main(int argc, char *argv[]) {
display();
set<Point>::iterator iter=Voronoi_vert.begin();
while(iter!=Voronoi_vert.end())
{
cout<<*iter<<endl;
++iter;
}
return 0;
}
版本二代码
/*
* 作者:窦志扬
* 日期:2018年8月13日
* 联络:[email protected]
* 院校:山东大学
* */
#include <CGAL/Linear_cell_complex_for_combinatorial_map.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_3_to_lcc.h>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC_3;
typedef LCC_3::Dart_handle Dart_handle;
typedef LCC_3::Point Point;
typedef CGAL::Delaunay_triangulation_3<LCC_3::Traits> Triangulation;
using namespace std;
void remove_the_infinite_volume(LCC_3 &alcc, Dart_handle adart)
{
/*
* 该方法参考cgal 方法
* */
std::stack<Dart_handle> toremove;
LCC_3::size_type mark_toremove=alcc.get_new_mark();
toremove.push(adart);
CGAL::mark_cell<LCC_3,3>(alcc, adart, mark_toremove);
//首先记录需要去除的无限区域
for (LCC_3::Dart_of_cell_range<3>::iterator
it=alcc.darts_of_cell<3>(adart).begin(),
itend=alcc.darts_of_cell<3>(adart).end(); it!=itend; ++it)
{
if ( !alcc.is_marked(alcc.beta(it,3), mark_toremove) )
{
CGAL::mark_cell<LCC_3,3>(alcc, alcc.beta(it,3), mark_toremove);
toremove.push(alcc.beta(it,3));
}
}
while( !toremove.empty() )
{
Dart_handle tem = toremove.top();
alcc.remove_cell<3>(tem);
toremove.pop();
}
CGAL_assertion(alcc.is_without_boundary(1) && alcc.is_without_boundary(2));
std::cout<<"Voronoi subdvision, only finite volumes:"<<std::endl<<" ";
alcc.display_characteristics(std::cout) << ", valid="
<< alcc.is_valid()
<< std::endl; std::cout<<"Voronoi剖分中所有的有限空间点: "<< endl;
for (LCC_3::Vertex_attribute_const_range::iterator
v=alcc.vertex_attributes().begin(),
vend=alcc.vertex_attributes().end();
v!=vend; ++v)
std::cout <<"v "<< alcc.point_of_vertex_attribute(v) << endl;
std::cout<<std::endl;
}
template<typename LCC, typename TR>
void transform_dart_to_their_dual(LCC& alcc, LCC& adual,
std::map<typename TR::Cell_handle,
typename LCC::Dart_handle>& assoc)
{
typename LCC::Dart_range::iterator it1=alcc.darts().begin();
typename LCC::Dart_range::iterator it2=adual.darts().begin();
std::map<typename LCC::Dart_handle, typename LCC::Dart_handle> dual;
for ( ; it1!=alcc.darts().end(); ++it1, ++it2 )
{
dual[it1]=it2;
}
for ( typename std::map<typename TR::Cell_handle, typename LCC::Dart_handle>
::iterator it=assoc.begin(), itend=assoc.end(); it!=itend; ++it)
{
assoc[it->first]=dual[it->second];
}
}
template<typename LCC, typename TR>
void set_geometry_of_dual(LCC& alcc, TR& tr,
std::map<typename TR::Cell_handle,
typename LCC::Dart_handle>& assoc)
{
for ( typename std::map<typename TR::Cell_handle, typename LCC::Dart_handle>
::iterator it=assoc.begin(), itend=assoc.end(); it!=itend; ++it)
{
if ( !tr.is_infinite(it->first) )
alcc.set_vertex_attribute
(it->second,alcc.create_vertex_attribute(tr.dual(it->first)));
else
alcc.set_vertex_attribute(it->second,alcc.create_vertex_attribute());
}
}
int main()
{
char*input1 = "/Users/frankdura/Desktop/222.txt";
vector<Point> boundaryPoints; //装载边界点
ifstream in_boundary(input1);
Point p;
while (in_boundary >> p){ //读入边界点
cout << p << endl;
boundaryPoints.push_back(p);
}
cout << "read in vertexs: " << boundaryPoints.size() << endl;
in_boundary.close();
//请输入您的剖分点
Triangulation T;//用于三角剖分
T.insert(boundaryPoints.begin(), boundaryPoints.end());
LCC_3 lcc;
std::map<Triangulation::Cell_handle,
LCC_3::Dart_handle > vol_to_dart;
Dart_handle dh=CGAL::import_from_triangulation_3<LCC_3, Triangulation>
(lcc, T, &vol_to_dart);
std::cout<<"Delaunay triangulation :"<<std::endl<<" ";
lcc.display_characteristics(std::cout) << ", valid="
<< lcc.is_valid() << std::endl;
CGAL::set_ascii_mode(std::cout);
std::cout<<"狄洛尼三角剖分顶点: "<< endl;
for (LCC_3::Vertex_attribute_const_range::iterator
v=lcc.vertex_attributes().begin(),
vend=lcc.vertex_attributes().end();
v!=vend; ++v)
std::cout << lcc.point_of_vertex_attribute(v) << "\n\r";
std::cout<<std::endl;
cout <<"end"<< endl;
LCC_3 dual_lcc;
Dart_handle ddh=lcc.dual(dual_lcc, dh);
// Here, dual_lcc is the 3D Voronoi diagram.
CGAL_assertion(dual_lcc.is_without_boundary());
transform_dart_to_their_dual<LCC_3,Triangulation>
(lcc, dual_lcc, vol_to_dart);
set_geometry_of_dual<LCC_3,Triangulation>(dual_lcc, T, vol_to_dart);
// 5) Display the dual_lcc characteristics.
std::cout<<"Voronoi剖分信息 :"<<std::endl<<" ";
dual_lcc.display_characteristics(std::cout) << ", valid="
<< dual_lcc.is_valid()
<< std::endl;
std::cout<<"Voronoi剖分中所有点: "<< endl;
for (LCC_3::Vertex_attribute_const_range::iterator
v=dual_lcc.vertex_attributes().begin(),
vend=dual_lcc.vertex_attributes().end();
v!=vend; ++v)
std::cout <<"v " <<dual_lcc.point_of_vertex_attribute(v) << endl;
remove_the_infinite_volume(dual_lcc, ddh);
return EXIT_SUCCESS;
}