Предисловие: С сегодняшнего дня Xiaoyi начал делиться знаниями о CGAL, в основном потому, что библиотека vtk не соответствует потребностям.Если у моих друзей такие же потребности, как у меня, то давайте учиться вместе.
Основное содержание: эта статья включена в колонку [Серия CGAL], в основном объясняющая создание, доступ, проверку и другой контент, связанный с Surface_Mesh в рамках CGAL! Основная цель состоит в том, что после понимания принципа построения Surface_Mesh его можно преобразовать с другими типами данных и преобразовать между различными библиотеками.
Спасибо за ваши лайки + внимание, Сяойи будет продолжать делиться и вместе добиваться прогресса!
Оглавление
Получить все точки Surface_Mesh
Получите связанные точки точек, ребер и граней Surface_Mesh
Ядро CGAL
Когда мы изучаем библиотеку CGAL, мы должны сначала понять концепцию ядра, которая в основном определяет три вида точности ядра:
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
Для подробного объяснения ядра вы можете использовать следующую ссылку, чтобы узнать о нем:
Surface_Mesh
Чтобы понять Surface_Mesh, вам сначала нужно понять такие понятия, как BGL (библиотека Boost Graph) и половина ребра (half edge) в CGAL. Ссылки ниже приведены для справки:
CGAL 5.5.2 - Структура данных Halfedge: Руководство пользователя
CGAL 5.5.2 - CGAL и графическая библиотека Boost: руководство пользователя
CGAL 5.5.2 — Поверхностные сетки: руководство пользователя
Новая сетка
структура данных:
Surface_mesh::Vertex_index
Surface_mesh::Halfedge_index
Surface_mesh::Face_index
Surface_mesh::Edge_index
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
Mesh m;
// Add the points as vertices
vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));
m.add_face(u,v,w);
int num = num_faces(m); //结果num = 1
return 0;
}
В это время создается новая сетка, состоящая из поверхностей, состоящих из u, v и w.
проверить ориентацию
face_descriptor f = m.add_face(u,v,x);
num = num_faces(m); //结果num = 1
Вопрос: Добавляются две грани, почему получается только одна грань?
Причина: Неправильная ориентация.
if(f == Mesh::null_face())
{
std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
f = m.add_face(u,x,v);
num = num_faces(m);//num = 2
}
См. CGAL 5.5.2 — Поверхностные сетки: Руководство пользователя
Проверить на самопересечение
Во многих алгоритмах требуется, чтобы входная сетка была несамопересекающейся моделью. Теперь давайте проверим, является ли приведенная выше модель самопересекающейся, следующим образом.
Mesh m;
// Add the points as vertices
vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));
m.add_face(u,v,w);
int num = num_faces(m);
face_descriptor f = m.add_face(u,v,x);
num = num_faces(m);
if(f == Mesh::null_face())
{
std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
f = m.add_face(u,x,v);
num = num_faces(m);
//结果intersect = true; 即当前模型为自相交模型
bool intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
assert(f != Mesh::null_face());
}
Замените u,x,v на v,x,w и снова посмотрите на результат самопересечения.
Mesh m;
// Add the points as vertices
vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor w = m.add_vertex(K::Point_3(1,1,0));
vertex_descriptor x = m.add_vertex(K::Point_3(1,0,0));
m.add_face(u,v,w);
int num = num_faces(m);
face_descriptor f = m.add_face(u,v,x);
num = num_faces(m);
if(f == Mesh::null_face())
{
std::cerr<<"The face could not be added because of an orientation error."<<std::endl;
f = m.add_face(v, x, w);
num = num_faces(m);
bool intersect = CGAL::Polygon_mesh_processing::does_self_intersect(m);
//结果 intersect = false;
assert(f != Mesh::null_face());
}
диапазоны и итераторы
Получить все точки Surface_Mesh
#include <vector>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
Mesh m;
// u x
// +------------+
// | |
// | |
// | f |
// | |
// | |
// +------------+
// v w
// Add the points as vertices
vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));
vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));
/* face_descriptor f = */ m.add_face(u,v,w,x);
{
std::cout << "all vertices " << std::endl;
// The vertex iterator type is a nested type of the Vertex_range
Mesh::Vertex_range::iterator vb, ve;
Mesh::Vertex_range r = m.vertices();
// The iterators can be accessed through the C++ range API
vb = r.begin();
ve = r.end();
// or the boost Range API
vb = boost::begin(r);
ve = boost::end(r);
// or with boost::tie, as the CGAL range derives from std::pair
for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb){
std::cout << *vb << std::endl;
}
// Instead of the classical for loop one can use
// the boost macro for a range
for(vertex_descriptor vd : m.vertices()){
std::cout << vd << std::endl;
}
// or the C++11 for loop. Note that there is a ':' and not a ',' as in BOOST_FOREACH
for(vertex_descriptor vd : m.vertices()){
std::cout << vd << std::endl;
}
}
return 0;
}
Получите связанные точки точек, ребер и граней Surface_Mesh
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <vector>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
Mesh m;
// u x
// +------------+
// | |
// | |
// | f |
// | |
// | |
// +------------+
// v w
// Add the points as vertices
vertex_descriptor u = m.add_vertex(K::Point_3(0,1,0));
vertex_descriptor v = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor w = m.add_vertex(K::Point_3(1,0,0));
vertex_descriptor x = m.add_vertex(K::Point_3(1,1,0));
face_descriptor f = m.add_face(u,v,w,x);
{
std::cout << "vertices around vertex " << v << std::endl;
CGAL::Vertex_around_target_circulator<Mesh> vbegin(m.halfedge(v),m), done(vbegin);
do {
std::cout << *vbegin++ << std::endl;
} while(vbegin != done);
}
{
std::cout << "vertices around face " << f << std::endl;
CGAL::Vertex_around_face_iterator<Mesh> vbegin, vend;
for(boost::tie(vbegin, vend) = vertices_around_face(m.halfedge(f), m);
vbegin != vend;
++vbegin){
std::cout << *vbegin << std::endl;
}
}
// or the same again, but directly with a range based loop
for(vertex_descriptor vd : vertices_around_face(m.halfedge(f), m)){
std::cout << vd << std::endl;
}
return 0;
}
Кроме того: vertices_around_target получает связанные точки, такие как линии и точки.
halfedges_round_target и halfedges_around_face
Faces_round_target и Faces_round_face
Атрибуты
Получить информацию о точке и координаты
#include <string>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef Mesh::Vertex_index vertex_descriptor;
typedef Mesh::Face_index face_descriptor;
int main()
{
Mesh m;
vertex_descriptor v0 = m.add_vertex(K::Point_3(0,2,0));
vertex_descriptor v1 = m.add_vertex(K::Point_3(2,2,0));
vertex_descriptor v2 = m.add_vertex(K::Point_3(0,0,0));
vertex_descriptor v3 = m.add_vertex(K::Point_3(2,0,0));
vertex_descriptor v4 = m.add_vertex(K::Point_3(1,1,0));
m.add_face(v3, v1, v4);
m.add_face(v0, v4, v1);
m.add_face(v0, v2, v4);
m.add_face(v2, v3, v4);
// give each vertex a name, the default is empty
Mesh::Property_map<vertex_descriptor,std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name","");
assert(created);
// add some names to the vertices
name[v0] = "hello";
name[v2] = "world";
{
// You get an existing property, and created will be false
Mesh::Property_map<vertex_descriptor,std::string> name;
bool created;
boost::tie(name, created) = m.add_property_map<vertex_descriptor,std::string>("v:name", "");
assert(! created);
}
// You can't get a property that does not exist
Mesh::Property_map<face_descriptor,std::string> gnus;
bool found;
boost::tie(gnus, found) = m.property_map<face_descriptor,std::string>("v:gnus");
assert(! found);
// retrieve the point property for which exists a convenience function
Mesh::Property_map<vertex_descriptor, K::Point_3> location = m.points();
for(vertex_descriptor vd : m.vertices()) {
std::cout << name[vd] << " @ " << location[vd] << std::endl;
}
std::vector<std::string> props = m.properties<vertex_descriptor>();
for(std::string p : props){
std::cout << p << std::endl;
}
// delete the string property again
m.remove_property_map(name);
return 0;
}
Другой метод обхода
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <iostream>
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point_3;
namespace My {
struct Mesh: public CGAL::Surface_mesh<Point_3> {
typedef CGAL::Surface_mesh<Point_3> Base;
std::string name;
};
} // namespace My
#define CGAL_GRAPH_TRAITS_INHERITANCE_CLASS_NAME My::Mesh
#define CGAL_GRAPH_TRAITS_INHERITANCE_BASE_CLASS_NAME CGAL::Surface_mesh<::Point_3>
#include <CGAL/boost/graph/graph_traits_inheritance_macros.h>
int main()
{
My::Mesh mesh;
CGAL::make_triangle(Point_3(0,0,0), Point_3(1,0,0), Point_3(1,1,1), mesh);
typedef boost::graph_traits<My::Mesh>::vertex_descriptor vertex_descriptor;
typedef boost::property_map<My::Mesh,CGAL::vertex_point_t>::type Point_property_map;
Point_property_map ppm = get(CGAL::vertex_point, mesh);
for(vertex_descriptor vd : vertices(mesh)){
if (vd != boost::graph_traits<My::Mesh>::null_vertex()){
std::cout << vd << " at " << get(ppm, vd) << std::endl;
}
}
std::cout << CGAL::Polygon_mesh_processing::bbox(mesh) << std::endl;
return 0;
}
Спасибо за ваши лайки + внимание, Сяойи будет продолжать делиться и вместе добиваться прогресса!