new version of the cdt_3 plugin: can take a colorized surface_mesh as input

This commit is contained in:
Laurent Rineau 2024-07-29 20:10:01 +02:00
parent 20e2fa76ad
commit cae4cbfd98
11 changed files with 170 additions and 85 deletions

View File

@ -59,6 +59,7 @@
#include <optional>
#include <unordered_map>
#include <ranges>
#include <vector>
#if __has_include(<format>)
# include <format>
# include <concepts>
@ -71,6 +72,51 @@ namespace CGAL {
#ifndef DOXYGEN_RUNNING
template <typename Range_of_segments>
auto segment_soup_to_polylines_point_type_aux(const Range_of_segments& segment_soup) {
for(auto [a, b]: segment_soup) {
return a;
}
}
template <typename Range_of_segments>
auto segment_soup_to_polylines(const Range_of_segments& segment_soup) {
using Point = decltype(segment_soup_to_polylines_point_type_aux(segment_soup));
std::vector<std::vector<Point>> polylines;
using Graph = boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS, Point>;
using Map2v = std::map<Point, typename Graph::vertex_descriptor>;
Graph graph;
Map2v map2v;
auto get_v = [&](const Point& p) {
auto it = map2v.find(p);
if(it != map2v.end()) return it->second;
auto v = boost::add_vertex(p, graph);
map2v.emplace(p, v);
return v;
};
for(auto [a, b]: segment_soup) {
auto va = get_v(a);
auto vb = get_v(b);
boost::add_edge(va, vb, graph);
}
struct Polylines_visitor
{
Graph& graph;
std::vector<std::vector<Point>>& polylines;
void start_new_polyline() { polylines.emplace_back(); }
void add_node(typename Graph::vertex_descriptor vd) { polylines.back().push_back(graph[vd]); }
void end_polyline() {}
};
Polylines_visitor visitor{graph, polylines};
CGAL::split_graph_into_polylines(graph, visitor);
return polylines;
}
template <class K>
typename K::Boolean
does_first_triangle_intersect_second_triangle_interior(const typename K::Triangle_3& t1,
@ -571,34 +617,108 @@ public:
auto mesh_vp_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
get(CGAL::vertex_point, mesh));
[[maybe_unused]] /* TODO */
auto mesh_face_patch_map = parameters::choose_parameter(parameters::get_parameter(np, internal_np::face_patch),
boost::identity_property_map{});
auto mesh_face_patch_map = parameters::get_parameter(np, internal_np::face_patch);
using vertex_descriptor = typename boost::graph_traits<PolygonMesh>::vertex_descriptor;
std::vector<std::vector<std::pair<vertex_descriptor, vertex_descriptor>>> patch_edges;
auto v_selected_map = get(CGAL::dynamic_vertex_property_t<bool>{}, mesh);
int number_of_patches = 0;
constexpr bool has_face_patch_map = !std::is_same_v<decltype(mesh_face_patch_map), CGAL::internal_np::Param_not_found>;
if constexpr (has_face_patch_map) {
int max_patch_id = 0;
for(auto f : faces(mesh)) {
max_patch_id = (std::max)(max_patch_id, get(mesh_face_patch_map, f));
}
for(auto f : faces(mesh)) {
if(get(mesh_face_patch_map, f) < 0) {
put(mesh_face_patch_map, f, max_patch_id++);
}
}
number_of_patches = 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 {
number_of_patches = num_faces(mesh);
}
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);
hint_ch = vh->cell();
put(tr_vertex_map, v, vh);
}
struct {
decltype(tr_vertex_map)* vertex_map;
Vertex_handle operator()(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v) const {
return get(*vertex_map, v);
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);
cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false,
face_index ? *face_index : -1);
}
}
} transform_function{&tr_vertex_map};
} else {
for(auto f : faces(mesh)) {
auto face_vertices = vertices_around_face(halfedge(f, mesh), mesh);
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);
auto begin = boost::make_transform_iterator(face_vertices.begin(), transform_function);
auto end = boost::make_transform_iterator(face_vertices.end(), transform_function);
cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false);
cdt_impl.insert_constrained_face(CGAL::make_range(begin, end), false);
}
}
cdt_impl.restore_Delaunay();
cdt_impl.restore_constrained_Delaunay();

View File

@ -13,6 +13,6 @@ int main(int argc, char **argv)
CGAL_Lab app(argc, argv,
"CGAL Lab (3D Constrained Delaunay Triangulations)",
"Polyhedron_3 demo",
QStringList() << "Viewer" << "CDT_3");
QStringList() << "IO_surface_meshes" << "CDT_3");
return app.try_exec();
}

View File

@ -29,7 +29,7 @@ add_dependencies(CGALlab_compile_all_plugins CGALlab_all_plugins)
add_file_dependencies( ${moc_file_name} "${CMAKE_CURRENT_SOURCE_DIR}/${plugin_implementation_base_name}.cpp" )
endif()
add_library(${plugin_name} MODULE ${option} ${moc_file_name} ${plugin_implementation_base_name}.cpp ${other_sources})
qt_add_plugin(${plugin_name} SHARED ${option} ${moc_file_name} ${plugin_implementation_base_name}.cpp ${other_sources})
set_property(TARGET ${plugin_name}
PROPERTY LIBRARY_OUTPUT_DIRECTORY
"${CGAL_LAB_DEMO_PLUGINS_DIR}")

View File

@ -408,7 +408,7 @@ if(CGAL_Qt6_FOUND AND Qt6_FOUND)
add_to_cached_list(CGAL_EXECUTABLE_TARGETS CGAL_Mesh_3)
add_executable(CGAL_CDT_3 CGAL_Lab_CDT_3.cpp)
add_dependencies(CGAL_CDT_3 CDT_3 Viewer)
add_dependencies(CGAL_CDT_3 CDT_3 IO_surface_meshes)
target_link_libraries(CGAL_CDT_3 PRIVATE cgal_lab)
add_to_cached_list(CGAL_EXECUTABLE_TARGETS CGAL_CDT_3)

View File

@ -49,7 +49,7 @@
#include <QSequentialIterable>
#include <QDir>
#include <QJSValue>
#include <QLoggingCategory>
#include <CGAL/Three/Three.h>
#include <CGAL/Three/CGAL_Lab_plugin_interface.h>
@ -543,6 +543,8 @@ void MainWindow::setMenus(QString name, QString parentName, QAction* a )
}
}
QLoggingCategory qlog_cgallab_plugins("cgal.lab.plugins");
bool MainWindow::load_plugin(QString fileName, bool blacklisted)
{
if(fileName.contains("plugin") && QLibrary::isLibrary(fileName)) {
@ -563,9 +565,8 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted)
return true;
}
}
QDebug qdebug = qDebug();
if(verbose)
qdebug << "### Loading \"" << fileName.toUtf8().data() << "\"... ";
qCDebug(qlog_cgallab_plugins) << "### Loading \"" << fileName.toUtf8().data() << "\"... ";
QPluginLoader loader;
loader.setFileName(fileinfo.absoluteFilePath());
QJsonArray keywords = loader.metaData().value("MetaData").toObject().value("Keywords").toArray();
@ -595,7 +596,7 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted)
bool init2 = initIOPlugin(obj);
if (!init1 && !init2)
{
pluginsStatus_map[name] = QString("Not for this program.");
pluginsStatus_map[name] = QString("ERROR: Not for this program.");
}
else{
QJSValue objectValue =
@ -607,12 +608,16 @@ bool MainWindow::load_plugin(QString fileName, bool blacklisted)
}
else if(!do_load)
{
pluginsStatus_map[name]="Wrong Keywords.";
pluginsStatus_map[name]="ERROR: Wrong Keywords.";
ignored_map[name] = true;
}
else{
pluginsStatus_map[name] = loader.errorString();
pluginsStatus_map[name] = "ERROR: " + loader.errorString();
}
if(verbose && pluginsStatus_map[name].startsWith("ERROR")) {
qCDebug(qlog_cgallab_plugins) << " plugin " << name << ": " << pluginsStatus_map[name]
<< "\n plugin keywords: " << s_keywords
<< "\n app keywords: " << accepted_keywords;
}
PathNames_map[name].push_back(fileinfo.absoluteDir().absolutePath());
return true;

View File

@ -44,22 +44,24 @@ class CDT_3_plugin : public QObject, public CGAL_Lab_plugin_interface
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::CGAL_Lab_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0")
Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0" FILE "cdt_3_plugin.json")
QAction* actionCDT;
CGAL::Three::Scene_interface* scene;
void cdt_3()
{
Scene_surface_mesh_item* item =
Scene_surface_mesh_item* mesh_item =
qobject_cast<Scene_surface_mesh_item*>(scene->item(scene->mainSelectionIndex()));
if(!item)
if(!mesh_item)
return;
auto* mesh = item->face_graph();
auto* mesh = mesh_item->face_graph();
if(!mesh)
return;
using CDT = CGAL::Constrained_Delaunay_triangulation_3<EPICK>;
CDT cdt = CGAL::make_constrained_Delaunay_triangulation_3(*mesh);
auto patch_id_pmap = mesh->property_map<SMesh::Face_index, int>("f:patch_id");
auto cdt = patch_id_pmap
? CGAL::make_constrained_Delaunay_triangulation_3(*mesh, CGAL::parameters::face_patch_map(*patch_id_pmap))
: CGAL::make_constrained_Delaunay_triangulation_3(*mesh);
const auto& cdt_tr = cdt.triangulation();
auto triangulation_item = std::make_unique<Scene_c3t3_item>();
auto& item_tr = triangulation_item->triangulation();
@ -68,10 +70,11 @@ class CDT_3_plugin : public QObject, public CGAL_Lab_plugin_interface
item_tr.set_infinite_vertex(inf_v);
triangulation_item->triangulation_changed();
triangulation_item->setParent(item->parent());
triangulation_item->setName("CDT of " + item->name());
triangulation_item->setParent(mesh_item->parent());
triangulation_item->setName("CDT of " + mesh_item->name());
triangulation_item->show_intersection(false);
scene->addItem(triangulation_item.release());
mesh_item->setVisible(false);
}
public:

View File

@ -22,7 +22,7 @@ cgal_lab_plugin(nef_io_plugin Nef_io_plugin KEYWORDS Viewer)
target_link_libraries(nef_io_plugin PUBLIC scene_nef_polyhedron_item)
cgal_lab_plugin(off_plugin OFF_io_plugin
KEYWORDS Viewer Mesh_3 PointSetProcessing Classification PMP)
KEYWORDS Viewer Mesh_3 PointSetProcessing Classification PMP IO_surface_meshes)
target_link_libraries(off_plugin PUBLIC scene_polygon_soup_item scene_points_with_normal_item scene_surface_mesh_item)
cgal_lab_plugin(off_to_nef_plugin OFF_to_nef_io_plugin KEYWORDS Viewer)
@ -34,10 +34,10 @@ target_link_libraries(polylines_io_plugin PUBLIC scene_polylines_item)
cgal_lab_plugin(wkt_plugin WKT_io_plugin KEYWORDS Viewer PointSetProcessing Mesh_3)
target_link_libraries(wkt_plugin PUBLIC scene_polylines_item)
cgal_lab_plugin(stl_plugin STL_io_plugin KEYWORDS Viewer PMP)
cgal_lab_plugin(stl_plugin STL_io_plugin KEYWORDS Viewer PMP IO_surface_meshes)
target_link_libraries(stl_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item)
cgal_lab_plugin(surf_io_plugin Surf_io_plugin KEYWORDS Viewer PMP)
cgal_lab_plugin(surf_io_plugin Surf_io_plugin KEYWORDS Viewer PMP IO_surface_meshes)
target_link_libraries(surf_io_plugin PUBLIC scene_surface_mesh_item)
cgal_lab_plugin(lcc_io_plugin lcc_io_plugin KEYWORDS Viewer)
@ -79,7 +79,7 @@ endif()
cgal_lab_plugin(xyz_plugin XYZ_io_plugin KEYWORDS Viewer PointSetProcessing Classification)
target_link_libraries(xyz_plugin PUBLIC scene_points_with_normal_item)
cgal_lab_plugin(ply_plugin PLY_io_plugin KEYWORDS Viewer PointSetProcessing Classification PMP)
cgal_lab_plugin(ply_plugin PLY_io_plugin KEYWORDS Viewer PointSetProcessing Classification PMP IO_surface_meshes)
target_link_libraries(ply_plugin PUBLIC scene_points_with_normal_item scene_polygon_soup_item scene_surface_mesh_item scene_textured_item)
if (TARGET CGAL::LASLIB_support)
cgal_lab_plugin(las_plugin LAS_io_plugin KEYWORDS Viewer PointSetProcessing Classification)

View File

@ -65,7 +65,7 @@ if(TARGET CGAL::Eigen3_support)
qt6_wrap_ui(remeshPlanarPatchesUI_FILES Remesh_planar_patches_dialog.ui)
cgal_lab_plugin(remesh_planar_patches_plugin Remesh_planar_patches_plugin
${remeshPlanarPatchesUI_FILES} KEYWORDS PMP)
${remeshPlanarPatchesUI_FILES} KEYWORDS PMP CDT_3)
target_link_libraries(remesh_planar_patches_plugin PUBLIC scene_surface_mesh_item CGAL::Eigen3_support)
if(CGAL_ENABLE_TESTING AND NOT CMAKE_VS_MSBUILD_COMMAND)

View File

@ -57,7 +57,7 @@ class CGAL_Lab_remesh_planar_patches_plugin :
{
Q_OBJECT
Q_INTERFACES(CGAL::Three::CGAL_Lab_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0" FILE "isotropic_remeshing_plugin.json")
Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0" FILE "remesh_planar_patches_plugin.json")
typedef Scene_surface_mesh_item::Face_graph Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;

View File

@ -147,7 +147,8 @@ CGAL_add_cdt3_from_local_off_test(error_mesh-p_not_equal_0-min2)
include(./Thingi10k-CDT.cmake)
add_test(NAME "execution of cdt_3_from_off_CGAL_DEBUG_CDT_3 3torus" COMMAND cdt_3_from_off_CGAL_DEBUG_CDT_3 ${CGAL_DATA_DIR}/meshes/3torus.off)
cgal_setup_test_properties("execution of cdt_3_from_off_CGAL_DEBUG_CDT_3" cdt_3_from_off_CGAL_DEBUG_CDT_3)
cgal_add_compilation_test(cdt_3_from_off_CGAL_DEBUG_CDT_3)
cgal_setup_test_properties("execution of cdt_3_from_off_CGAL_DEBUG_CDT_3 3torus" cdt_3_from_off_CGAL_DEBUG_CDT_3)
get_directory_property(all_tests TESTS)
foreach(test ${all_tests})

View File

@ -339,44 +339,6 @@ int main(int argc, char* argv[])
}
}
template <typename Range_of_segments>
auto segment_soup_to_polylines(Range_of_segments&& segment_soup) {
using Point = decltype([&](){ using std::begin; auto [a, b] = *begin(segment_soup); return a; } ());
std::vector<std::vector<Point>> polylines;
using Graph = boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS, Point>;
using Map2v = std::map<Point, typename Graph::vertex_descriptor>;
Graph graph;
Map2v map2v;
auto get_v = [&](const Point& p) {
auto it = map2v.find(p);
if(it != map2v.end()) return it->second;
auto v = boost::add_vertex(p, graph);
map2v.emplace(p, v);
return v;
};
for(auto [a, b]: segment_soup) {
auto va = get_v(a);
auto vb = get_v(b);
boost::add_edge(va, vb, graph);
}
struct Polylines_visitor
{
Graph& graph;
std::vector<std::vector<Point>>& polylines;
void start_new_polyline() { polylines.emplace_back(); }
void add_node(typename Graph::vertex_descriptor vd) { polylines.back().push_back(graph[vd]); }
void end_polyline() {}
};
Polylines_visitor visitor{graph, polylines};
CGAL::split_graph_into_polylines(graph, visitor);
return polylines;
}
int go(Mesh mesh, CDT_options options) {
CDT cdt;
cdt.debug_Steiner_points(options.verbose > 0);
@ -709,16 +671,10 @@ int go(Mesh mesh, CDT_options options) {
for(auto& polyline: polylines) {
assert(polyline.front() == polyline.back());
polyline.pop_back();
if(face_index) {
cdt.insert_constrained_face(
polyline | std::views::transform([&](vertex_descriptor v) { return get(tr_vertex_pmap, v); }),
false,
*face_index);
} else {
face_index = cdt.insert_constrained_face(
polyline | std::views::transform([&](vertex_descriptor v) { return get(tr_vertex_pmap, v); }),
false);
}
cdt.insert_constrained_face(
polyline | std::views::transform([&](vertex_descriptor v) { return get(tr_vertex_pmap, v); }),
false,
face_index ? *face_index : -1);
}
}
} else {