网格划分算法搞砸了 Triangulation_vertex_base_with_id_2

Meshing algorithms mess up Triangulation_vertex_base_with_id_2

我正在尝试将 Delaunay_mesher_2::refine_mesh 应用于一组编号的顶点(即顶点 class 是 Triangulation_vertex_base_with_id_2)。我希望在此过程中创建的任何顶点都应该有 id()==0。然而事实并非如此。相反,ID 具有各种 positive/negative 值。

我尝试使用 Triangulation_vertex_base_with_info_2,但结果是一样的。

我的代码大致是这样工作的:

using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using Vb = CGAL::Triangulation_vertex_base_with_id_2<K>;
using Fb = CGAL::Delaunay_mesh_face_base_2<K>;
using Tds = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using CDT_Tag = CGAL::Exact_intersections_tag;
using CDT = CGAL::Constrained_Delaunay_triangulation_2<K, Tds, CDT_Tag>;
using Criteria = CGAL::Delaunay_mesh_size_criteria_2<CDT>;
CDT cdt;
CGAL::Delaunay_mesher_2<CDT, Criteria> mesher(cdt, Criteria(0.125, 0.5));
... // Add some points and constraints.
static const CDT::Point INFINITE_POINT = { 1e100, 1e100 };
std::vector<CDT::Point> seeds = { INFINITE_POINT };
mesher.set_seeds(seeds.begin(), seeds.end());
mesher.refine_mesh();

for (auto vertices_iter = cdt.finite_vertices_begin();
     vertices_iter != cdt.finite_vertices_end();
     ++vertices_iter) {
  // do something with vertices_iter->id().
}

id 不是由任何算法设置的。它只为您提供了根据需要进行设置的可能性。

我认为这是 CGAL 中的某种错误(可能是未定义的行为,因为每次的结果都不同)。很难确定它来自哪里,但 GCC 中的 UB sanitizer 说至少有一些地方取消引用了空指针。

作为一种解决方法,可以使用 Vertex_handle 通过 CGAL::Unique_hash_mapint 的映射。

CGAL::Triangulation_vertex_base_with_id_2<K>的default-constructor没有初始化id成员:

template < typename GT,
           typename Vb = Triangulation_vertex_base_2<GT> >
class Triangulation_vertex_base_with_id_2
  : public Vb
{
  int _id;

public:

  // [...]

  Triangulation_vertex_base_with_id_2()
    : Vb() {}

也就是说_iddefault-initialized:

Explanation

Default initialization is performed in three situations: [...]

  1. when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.

然后阅读下一段:

The effects of default initialization are:

  • if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
  • if T is an array type, every element of the array is default-initialized;
  • otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.

此处的子对象 _id 如果类型为 int,因此它不是 class 或数组。这就是它没有被初始化的原因。该值将是内存中的任何垃圾。