mirror of https://github.com/CGAL/cgal
add missing precondition check for soup + always assert in debug
This commit is contained in:
parent
45e9662fd4
commit
0064ea9f3e
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_self_intersections.h>
|
||||||
|
|
||||||
#include <CGAL/Compact_container.h>
|
#include <CGAL/Compact_container.h>
|
||||||
|
|
||||||
|
|
@ -589,25 +590,23 @@ public:
|
||||||
|
|
||||||
#ifndef DOXYGEN_RUNNING
|
#ifndef DOXYGEN_RUNNING
|
||||||
template <typename PolygonMesh, typename CGAL_NP_TEMPLATE_PARAMETERS>
|
template <typename PolygonMesh, typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||||
bool preconditions_verified(const PolygonMesh& mesh, const CGAL_NP_CLASS& np)
|
bool preconditions_verified_mesh(const PolygonMesh& mesh, const CGAL_NP_CLASS& np)
|
||||||
{
|
{
|
||||||
bool verified = true;
|
|
||||||
if(CGAL::is_triangle_mesh(mesh))
|
if(CGAL::is_triangle_mesh(mesh))
|
||||||
{
|
return !CGAL::Polygon_mesh_processing::does_self_intersect(mesh, np);
|
||||||
verified = verified && !CGAL::Polygon_mesh_processing::does_self_intersect(mesh);
|
PolygonMesh trimesh;
|
||||||
CGAL_precondition_msg(verified,
|
CGAL::copy_face_graph(mesh, trimesh, np);
|
||||||
"Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects");
|
bool OK = CGAL::Polygon_mesh_processing::triangulate_faces(trimesh, np);
|
||||||
}
|
if (!OK) return false;
|
||||||
else
|
return !CGAL::Polygon_mesh_processing::does_self_intersect(trimesh);
|
||||||
{
|
}
|
||||||
PolygonMesh trimesh;
|
|
||||||
CGAL::copy_face_graph(mesh, trimesh, np);
|
template <typename PointRange, typename PolygonRange, typename CGAL_NP_TEMPLATE_PARAMETERS>
|
||||||
CGAL::Polygon_mesh_processing::triangulate_faces(trimesh, np);
|
bool preconditions_verified_soup(const PointRange& points,
|
||||||
verified = verified && !CGAL::Polygon_mesh_processing::does_self_intersect(trimesh);
|
const PolygonRange& polygons,
|
||||||
CGAL_precondition_msg(verified,
|
const CGAL_NP_CLASS& np)
|
||||||
"Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects");
|
{
|
||||||
}
|
return CGAL::Polygon_mesh_processing::does_polygon_soup_self_intersect(points, polygons, np);
|
||||||
return verified;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -625,119 +624,120 @@ public:
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
const bool check_preconditions =
|
const bool check_preconditions =
|
||||||
parameters::choose_parameter(parameters::get_parameter(np, internal_np::check_preconditions), false);
|
parameters::choose_parameter(parameters::get_parameter(np, internal_np::check_preconditions), false);
|
||||||
if(!check_preconditions || preconditions_verified(mesh, np))
|
|
||||||
{
|
|
||||||
auto mesh_vp_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
|
|
||||||
get(CGAL::vertex_point, mesh));
|
|
||||||
|
|
||||||
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
CGAL_precondition_msg(check_preconditions || preconditions_verified_mesh(mesh, np), "Conforming_constrained_Delaunay_triangulation_3: mesh self-intersects");
|
||||||
std::vector<std::vector<std::pair<vertex_descriptor, vertex_descriptor>>> patch_edges;
|
|
||||||
|
|
||||||
auto v_selected_map = get(CGAL::dynamic_vertex_property_t<bool>{}, mesh);
|
if(check_preconditions && !preconditions_verified_mesh(mesh, np)) return;
|
||||||
|
|
||||||
int number_of_patches = 0;
|
auto mesh_vp_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
|
||||||
constexpr bool has_face_patch_map = !parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::face_patch_t>::value;
|
get(CGAL::vertex_point, mesh));
|
||||||
|
|
||||||
if constexpr (has_face_patch_map) {
|
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
|
||||||
auto mesh_face_patch_map = parameters::get_parameter(np, internal_np::face_patch);
|
std::vector<std::vector<std::pair<vertex_descriptor, vertex_descriptor>>> patch_edges;
|
||||||
using Patch_id_type = CGAL::cpp20::remove_cvref_t<decltype(get(mesh_face_patch_map, *faces(mesh).first))>;
|
|
||||||
Patch_id_type max_patch_id{0};
|
|
||||||
for(auto f : faces(mesh)) {
|
|
||||||
max_patch_id = (std::max)(max_patch_id, get(mesh_face_patch_map, f));
|
|
||||||
}
|
|
||||||
number_of_patches = static_cast<int>(max_patch_id + 1);
|
|
||||||
patch_edges.resize(number_of_patches);
|
|
||||||
for(auto h : halfedges(mesh)) {
|
|
||||||
if(is_border(h, mesh))
|
|
||||||
continue;
|
|
||||||
auto f = face(h, mesh);
|
|
||||||
auto patch_id = get(mesh_face_patch_map, f);
|
|
||||||
auto opp = opposite(h, mesh);
|
|
||||||
if(is_border(opp, mesh) || patch_id != get(mesh_face_patch_map, face(opp, mesh))) {
|
|
||||||
auto va = source(h, mesh);
|
|
||||||
auto vb = target(h, mesh);
|
|
||||||
patch_edges[patch_id].emplace_back(va, vb);
|
|
||||||
put(v_selected_map, va, true);
|
|
||||||
put(v_selected_map, vb, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
auto v_selected_map = get(CGAL::dynamic_vertex_property_t<bool>{}, mesh);
|
||||||
number_of_patches = num_faces(mesh);
|
|
||||||
|
int number_of_patches = 0;
|
||||||
|
constexpr bool has_face_patch_map = !parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::face_patch_t>::value;
|
||||||
|
|
||||||
|
if constexpr (has_face_patch_map) {
|
||||||
|
auto mesh_face_patch_map = parameters::get_parameter(np, internal_np::face_patch);
|
||||||
|
using Patch_id_type = CGAL::cpp20::remove_cvref_t<decltype(get(mesh_face_patch_map, *faces(mesh).first))>;
|
||||||
|
Patch_id_type max_patch_id{0};
|
||||||
|
for(auto f : faces(mesh)) {
|
||||||
|
max_patch_id = (std::max)(max_patch_id, get(mesh_face_patch_map, f));
|
||||||
}
|
}
|
||||||
|
number_of_patches = static_cast<int>(max_patch_id + 1);
|
||||||
using Vertex_handle = typename Triangulation::Vertex_handle;
|
patch_edges.resize(number_of_patches);
|
||||||
using Cell_handle = typename Triangulation::Cell_handle;
|
for(auto h : halfedges(mesh)) {
|
||||||
auto tr_vertex_map = get(CGAL::dynamic_vertex_property_t<Vertex_handle>(), mesh);
|
if(is_border(h, mesh))
|
||||||
Cell_handle hint_ch{};
|
continue;
|
||||||
for(auto v : vertices(mesh)) {
|
auto f = face(h, mesh);
|
||||||
if constexpr(has_face_patch_map) {
|
auto patch_id = get(mesh_face_patch_map, f);
|
||||||
if(false == get(v_selected_map, v)) continue;
|
auto opp = opposite(h, mesh);
|
||||||
}
|
if(is_border(opp, mesh) || patch_id != get(mesh_face_patch_map, face(opp, mesh))) {
|
||||||
auto p = get(mesh_vp_map, v);
|
auto va = source(h, mesh);
|
||||||
auto vh = cdt_impl.insert(p, hint_ch, false);
|
auto vb = target(h, mesh);
|
||||||
vh->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::CORNER);
|
patch_edges[patch_id].emplace_back(va, vb);
|
||||||
hint_ch = vh->cell();
|
put(v_selected_map, va, true);
|
||||||
put(tr_vertex_map, v, vh);
|
put(v_selected_map, vb, true);
|
||||||
}
|
|
||||||
|
|
||||||
cdt_impl.add_bbox_points_if_not_dimension_3();
|
|
||||||
|
|
||||||
struct {
|
|
||||||
decltype(tr_vertex_map)* vertex_map;
|
|
||||||
auto operator()(vertex_descriptor v) const { return get(*vertex_map, v); }
|
|
||||||
} tr_vertex_fct{&tr_vertex_map};
|
|
||||||
|
|
||||||
if constexpr(has_face_patch_map) {
|
|
||||||
for(int i = 0; i < number_of_patches; ++i) {
|
|
||||||
auto& edges = patch_edges[i];
|
|
||||||
if(edges.empty())
|
|
||||||
continue;
|
|
||||||
auto polylines = segment_soup_to_polylines(edges);
|
|
||||||
while(true) {
|
|
||||||
const auto non_closed_polylines_begin =
|
|
||||||
std::partition(polylines.begin(), polylines.end(),
|
|
||||||
[](const auto& polyline) { return polyline.front() == polyline.back(); });
|
|
||||||
if(non_closed_polylines_begin == polylines.end())
|
|
||||||
break;
|
|
||||||
edges.clear();
|
|
||||||
for(auto it = non_closed_polylines_begin; it != polylines.end(); ++it) {
|
|
||||||
auto& polyline = *it;
|
|
||||||
for(auto it = polyline.begin(), end = polyline.end() - 1; it != end; ++it) {
|
|
||||||
edges.emplace_back(*it, *(it + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
polylines.erase(non_closed_polylines_begin, polylines.end());
|
|
||||||
auto other_polylines = segment_soup_to_polylines(edges);
|
|
||||||
polylines.insert(polylines.end(), std::make_move_iterator(other_polylines.begin()),
|
|
||||||
std::make_move_iterator(other_polylines.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<int> face_index;
|
|
||||||
for(auto& polyline : polylines) {
|
|
||||||
CGAL_assertion(polyline.front() == polyline.back());
|
|
||||||
polyline.pop_back();
|
|
||||||
auto begin = boost::make_transform_iterator(polyline.begin(), tr_vertex_fct);
|
|
||||||
auto end = boost::make_transform_iterator(polyline.end(), tr_vertex_fct);
|
|
||||||
face_index = cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false,
|
|
||||||
face_index ? *face_index : -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(auto f : faces(mesh)) {
|
|
||||||
auto face_vertices = vertices_around_face(halfedge(f, mesh), mesh);
|
|
||||||
|
|
||||||
auto begin = boost::make_transform_iterator(face_vertices.begin(), tr_vertex_fct);
|
|
||||||
auto end = boost::make_transform_iterator(face_vertices.end(), tr_vertex_fct);
|
|
||||||
|
|
||||||
cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cdt_impl.restore_Delaunay();
|
} else {
|
||||||
cdt_impl.restore_constrained_Delaunay();
|
number_of_patches = num_faces(mesh);
|
||||||
// std::cerr << cdt_3_format("cdt_impl: {} vertices, {} cells\n", cdt_impl.number_of_vertices(),
|
|
||||||
// cdt_impl.number_of_cells());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using Vertex_handle = typename Triangulation::Vertex_handle;
|
||||||
|
using Cell_handle = typename Triangulation::Cell_handle;
|
||||||
|
auto tr_vertex_map = get(CGAL::dynamic_vertex_property_t<Vertex_handle>(), mesh);
|
||||||
|
Cell_handle hint_ch{};
|
||||||
|
for(auto v : vertices(mesh)) {
|
||||||
|
if constexpr(has_face_patch_map) {
|
||||||
|
if(false == get(v_selected_map, v)) continue;
|
||||||
|
}
|
||||||
|
auto p = get(mesh_vp_map, v);
|
||||||
|
auto vh = cdt_impl.insert(p, hint_ch, false);
|
||||||
|
vh->ccdt_3_data().set_vertex_type(CDT_3_vertex_type::CORNER);
|
||||||
|
hint_ch = vh->cell();
|
||||||
|
put(tr_vertex_map, v, vh);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdt_impl.add_bbox_points_if_not_dimension_3();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
decltype(tr_vertex_map)* vertex_map;
|
||||||
|
auto operator()(vertex_descriptor v) const { return get(*vertex_map, v); }
|
||||||
|
} tr_vertex_fct{&tr_vertex_map};
|
||||||
|
|
||||||
|
if constexpr(has_face_patch_map) {
|
||||||
|
for(int i = 0; i < number_of_patches; ++i) {
|
||||||
|
auto& edges = patch_edges[i];
|
||||||
|
if(edges.empty())
|
||||||
|
continue;
|
||||||
|
auto polylines = segment_soup_to_polylines(edges);
|
||||||
|
while(true) {
|
||||||
|
const auto non_closed_polylines_begin =
|
||||||
|
std::partition(polylines.begin(), polylines.end(),
|
||||||
|
[](const auto& polyline) { return polyline.front() == polyline.back(); });
|
||||||
|
if(non_closed_polylines_begin == polylines.end())
|
||||||
|
break;
|
||||||
|
edges.clear();
|
||||||
|
for(auto it = non_closed_polylines_begin; it != polylines.end(); ++it) {
|
||||||
|
auto& polyline = *it;
|
||||||
|
for(auto it = polyline.begin(), end = polyline.end() - 1; it != end; ++it) {
|
||||||
|
edges.emplace_back(*it, *(it + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
polylines.erase(non_closed_polylines_begin, polylines.end());
|
||||||
|
auto other_polylines = segment_soup_to_polylines(edges);
|
||||||
|
polylines.insert(polylines.end(), std::make_move_iterator(other_polylines.begin()),
|
||||||
|
std::make_move_iterator(other_polylines.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> face_index;
|
||||||
|
for(auto& polyline : polylines) {
|
||||||
|
CGAL_assertion(polyline.front() == polyline.back());
|
||||||
|
polyline.pop_back();
|
||||||
|
auto begin = boost::make_transform_iterator(polyline.begin(), tr_vertex_fct);
|
||||||
|
auto end = boost::make_transform_iterator(polyline.end(), tr_vertex_fct);
|
||||||
|
face_index = cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false,
|
||||||
|
face_index ? *face_index : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(auto f : faces(mesh)) {
|
||||||
|
auto face_vertices = vertices_around_face(halfedge(f, mesh), mesh);
|
||||||
|
|
||||||
|
auto begin = boost::make_transform_iterator(face_vertices.begin(), tr_vertex_fct);
|
||||||
|
auto end = boost::make_transform_iterator(face_vertices.end(), tr_vertex_fct);
|
||||||
|
|
||||||
|
cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cdt_impl.restore_Delaunay();
|
||||||
|
cdt_impl.restore_constrained_Delaunay();
|
||||||
|
// std::cerr << cdt_3_format("cdt_impl: {} vertices, {} cells\n", cdt_impl.number_of_vertices(),
|
||||||
|
// cdt_impl.number_of_cells());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -754,6 +754,13 @@ public:
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// cstr... (polygon soup)
|
// cstr... (polygon soup)
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
const bool check_preconditions =
|
||||||
|
parameters::choose_parameter(parameters::get_parameter(np, internal_np::check_preconditions), false);
|
||||||
|
|
||||||
|
CGAL_precondition_msg(check_preconditions || preconditions_verified_soup(points, polygons, np), "Conforming_constrained_Delaunay_triangulation_3: polygon soup self-intersects");
|
||||||
|
|
||||||
|
if(check_preconditions && !preconditions_verified_soup(points, polygons, np)) return;
|
||||||
|
|
||||||
|
|
||||||
using PointRange_const_iterator = typename PointRange::const_iterator;
|
using PointRange_const_iterator = typename PointRange::const_iterator;
|
||||||
using PointRange_value_type = typename std::iterator_traits<PointRange_const_iterator>::value_type;
|
using PointRange_value_type = typename std::iterator_traits<PointRange_const_iterator>::value_type;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ bool does_polygon_soup_self_intersect(const PointRange& points,
|
||||||
// otherwise, we need to triangulate the polygons beforehand
|
// otherwise, we need to triangulate the polygons beforehand
|
||||||
using Polygon = CGAL::cpp20::remove_cvref_t<decltype(*polygons.begin())>;
|
using Polygon = CGAL::cpp20::remove_cvref_t<decltype(*polygons.begin())>;
|
||||||
std::vector<Polygon> triangles(polygons.begin(), polygons.end());
|
std::vector<Polygon> triangles(polygons.begin(), polygons.end());
|
||||||
triangulate_polygons(points, triangles, np);
|
bool OK = triangulate_polygons(points, triangles, np);
|
||||||
|
|
||||||
|
if (!OK) return false;
|
||||||
|
|
||||||
return does_triangle_soup_self_intersect<ConcurrencyTag>(points, triangles, np);
|
return does_triangle_soup_self_intersect<ConcurrencyTag>(points, triangles, np);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue