diff --git a/Lab/demo/Lab/Plugins/IO/Polylines_io_plugin.cpp b/Lab/demo/Lab/Plugins/IO/Polylines_io_plugin.cpp index b737f8f3710a..b1700f6461ca 100644 --- a/Lab/demo/Lab/Plugins/IO/Polylines_io_plugin.cpp +++ b/Lab/demo/Lab/Plugins/IO/Polylines_io_plugin.cpp @@ -62,7 +62,10 @@ class CGAL_Lab_polylines_io_plugin : } QString name() const override{ return "polylines_io_plugin"; } - QString nameFilters() const override{ return "Polylines files (*.polylines.txt);; CGAL Polylines files (*.cgal)"; } + QString nameFilters() const override + { + return "Polylines files (*.polylines.txt);; CGAL Polylines files (*.cgal);; Txt polylines files (*.txt)"; + } bool canLoad(QFileInfo fileinfo) const override; QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; @@ -135,7 +138,9 @@ bool CGAL_Lab_polylines_io_plugin::canLoad(QFileInfo fileinfo) const{ QList CGAL_Lab_polylines_io_plugin:: -load(QFileInfo fileinfo, bool& ok, bool add_to_scene){ +load(QFileInfo fileinfo, bool& ok, bool add_to_scene) +{ + using Pt = Scene_polylines_item::Point_3; // Open file std::ifstream ifs(fileinfo.filePath().toUtf8()); @@ -158,42 +163,78 @@ load(QFileInfo fileinfo, bool& ok, bool add_to_scene){ std::list > polylines; QStringList polylines_metadata; - int counter = 0; - std::size_t n; - while(ifs >> n) { - ++counter; - std::vector new_polyline; - polylines.push_back(new_polyline); - std::vector&polyline = polylines.back(); - polyline.reserve(n); - while(n--){ - Scene_polylines_item::Point_3 p; - ifs >> p; - polyline.push_back(p); - if(!ifs.good()) + + QString extension = fileinfo.completeSuffix(); + if(extension == "polylines.txt" || extension == "cgal") + { + std::size_t n; + while(ifs >> n) { + ++counter; + std::vector new_polyline; + polylines.push_back(new_polyline); + std::vector&polyline = polylines.back(); + polyline.reserve(n); + while(n--){ + Scene_polylines_item::Point_3 p; + ifs >> p; + polyline.push_back(p); + if(!ifs.good()) + { + ok = false; + return QList(); + } + } + std::string line_remainder; + std::getline(ifs, line_remainder); + QString metadata(line_remainder.c_str()); + if(!metadata.isEmpty() && metadata[0].isSpace()) { + metadata.remove(0, 1); + } + polylines_metadata << metadata; + if(!metadata.isEmpty()) { + std::cerr << " (metadata: \"" << qPrintable(metadata) << "\")\n"; + } else { + } + if(ifs.bad() || ifs.fail()) { ok = false; return QList(); } } - std::string line_remainder; - std::getline(ifs, line_remainder); - QString metadata(line_remainder.c_str()); - if(!metadata.isEmpty() && metadata[0].isSpace()) { - metadata.remove(0, 1); - } - polylines_metadata << metadata; - if(!metadata.isEmpty()) { - std::cerr << " (metadata: \"" << qPrintable(metadata) << "\")\n"; - } else { - } - if(ifs.bad() || ifs.fail()) + } + else if (extension == "txt") + { + std::string line; + while (std::getline(ifs, line)) { - ok = false; - return QList(); + ++counter; + //each line is : "x1, y1, z1, x2, y2, z2" + std::istringstream tokenizer(line); + + std::array p_s; //point p as string + std::getline(tokenizer, p_s[0], ','); + std::getline(tokenizer, p_s[1], ','); + std::getline(tokenizer, p_s[2], ','); + + std::array q_s; //point q as string + std::getline(tokenizer, q_s[0], ','); + std::getline(tokenizer, q_s[1], ','); + std::getline(tokenizer, q_s[2]); + if (tokenizer) + { + Pt p(std::stod(p_s[0]), std::stod(p_s[1]), std::stod(p_s[2])); + Pt q(std::stod(q_s[0]), std::stod(q_s[1]), std::stod(q_s[2])); + polylines.push_back({ p, q }); + } + else + { + std::cerr << "Error reading line " << line << std::endl; + // There were fewer colons then expected in the line + } } } + if(counter == 0) { ok = false; diff --git a/Lab/demo/Lab/Plugins/Operations_on_polyhedra/CMakeLists.txt b/Lab/demo/Lab/Plugins/Operations_on_polyhedra/CMakeLists.txt index 8e60e5f29d96..0d8724ef5e46 100644 --- a/Lab/demo/Lab/Plugins/Operations_on_polyhedra/CMakeLists.txt +++ b/Lab/demo/Lab/Plugins/Operations_on_polyhedra/CMakeLists.txt @@ -4,6 +4,7 @@ cgal_lab_plugin(clip_polyhedron_plugin Clip_polyhedron_plugin ${clip_polyhedronUI_FILES}) target_link_libraries( clip_polyhedron_plugin PRIVATE scene_surface_mesh_item scene_basic_objects + scene_selection_item scene_movable_sm_item) cgal_lab_plugin(point_set_from_vertices_plugin diff --git a/Lab/demo/Lab/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp b/Lab/demo/Lab/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp index b26e60c5d824..228e4718262f 100644 --- a/Lab/demo/Lab/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp +++ b/Lab/demo/Lab/Plugins/Operations_on_polyhedra/Clip_polyhedron_plugin.cpp @@ -6,12 +6,15 @@ #include #include "Scene_surface_mesh_item.h" #include "Scene_plane_item.h" +#include "Scene_polyhedron_selection_item.h" #include #include #include #include +#include #include #include +#include #include "Plugins/AABB_tree/Scene_movable_sm_item.h" #include @@ -79,22 +82,26 @@ class Scene_clipping_plane_item : public Scene_plane_item class Q_DECL_EXPORT Clip_cgal_lab_plugin : public QObject, - public CGAL::Three::CGAL_Lab_plugin_interface + public CGAL_Lab_plugin_helper { Q_OBJECT Q_INTERFACES(CGAL::Three::CGAL_Lab_plugin_interface) Q_PLUGIN_METADATA(IID "com.geometryfactory.CGALLab.PluginInterface/1.0") + public : // Adds an action to the menu and configures the widget void init(QMainWindow* mw, CGAL::Three::Scene_interface* scene_interface, - Messages_interface* mi) { + Messages_interface* mi) + { //get the references this->scene = scene_interface; + this->mw = mw; this->messages = mi; plane = nullptr; clipper_item = nullptr; original_clipper = nullptr; + //creates and link the actions actionClipPolyhedra = new QAction("Clip Polyhedra With Plane", mw); actionClipPolyhedra->setProperty("subMenuName","Polygon Mesh Processing/Corefinement"); @@ -254,13 +261,13 @@ public Q_SLOTS: if(sm_item) { CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()), - plane->plane(), - CGAL::parameters::clip_volume( - ui_widget.close_checkBox->isChecked()). - throw_on_self_intersection(true). - use_compact_clipper( - !ui_widget.coplanarCheckBox->isChecked()) - .allow_self_intersections(ui_widget.do_not_modify_CheckBox->isChecked())); + plane->plane(), + CGAL::parameters::clip_volume( + ui_widget.close_checkBox->isChecked()). + throw_on_self_intersection(true). + use_compact_clipper( + !ui_widget.coplanarCheckBox->isChecked()) + .allow_self_intersections(ui_widget.do_not_modify_CheckBox->isChecked())); } } catch(const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) @@ -399,28 +406,81 @@ public Q_SLOTS: for(Scene_item* item : polyhedra) { Scene_surface_mesh_item *sm_item = qobject_cast(item); - if(!ui_widget.do_not_modify_CheckBox->isChecked() && CGAL::Polygon_mesh_processing::does_self_intersect(*sm_item->face_graph())) + if(sm_item != nullptr + && !ui_widget.do_not_modify_CheckBox->isChecked() + && CGAL::Polygon_mesh_processing::does_self_intersect(*sm_item->face_graph())) { CGAL::Three::Three::warning(tr("%1 has not been clipped because it has self intersections.").arg(sm_item->name())); continue; } + + bool clip_volume_param = ui_widget.close_checkBox->isChecked(); + if (sm_item != nullptr + && ui_widget.close_checkBox->isChecked() + && !CGAL::is_closed(*sm_item->face_graph())) + { + CGAL::Three::Three::warning(tr("Clip volume has been forced to false because %1 is not closed.").arg(sm_item->name())); + } + if (ui_widget.clip_radioButton->isChecked()) { if(sm_item) { - try { - CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()), - clipper, - CGAL::parameters::clip_volume( - ui_widget.close_checkBox->isChecked()). - throw_on_self_intersection(true). - use_compact_clipper( - !ui_widget.coplanarCheckBox->isChecked()), - CGAL::parameters::do_not_modify(ui_widget.do_not_modify_CheckBox->isChecked())); + Scene_polyhedron_selection_item* selection = nullptr; + for (int id : scene->selectionIndices()) + { + Scene_polyhedron_selection_item* tmp + = qobject_cast(scene->item(id)); + if (tmp != nullptr && tmp->polyhedron_item() == sm_item) + { + selection = tmp; + break; + } } - catch(const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) + + if (selection == nullptr) { - CGAL::Three::Three::warning(tr("The requested operation is not possible due to the presence of self-intersections in the region handled.")); + try { + CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()), + clipper, + CGAL::parameters::clip_volume(clip_volume_param). + throw_on_self_intersection(true). + use_compact_clipper( + !ui_widget.coplanarCheckBox->isChecked()), + CGAL::parameters::do_not_modify(ui_widget.do_not_modify_CheckBox->isChecked())); + } + catch(const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) + { + CGAL::Three::Three::warning(tr("The requested operation is not possible due to the presence of self-intersections in the region handled.")); + } + } + else + { + try + { + bool success = CGAL::Polygon_mesh_processing::clip(*(sm_item->face_graph()), + clipper, + CGAL::parameters::clip_volume(clip_volume_param) + .edge_is_constrained_map(selection->constrained_edges_pmap()) + .constrain_intersection_edges(false) + .throw_on_self_intersection(true) + .use_compact_clipper(!ui_widget.coplanarCheckBox->isChecked()) + , CGAL::parameters::use_compact_clipper(!ui_widget.coplanarCheckBox->isChecked()) + .do_not_modify(ui_widget.do_not_modify_CheckBox->isChecked())); + + if (!success) + CGAL::Three::Three::warning(tr("clip() did not fully succeed")); + + selection->setKeepSelectionValid(Scene_polyhedron_selection_item::Edge); + selection->polyhedron_item()->invalidateOpenGLBuffers(); + Q_EMIT selection->polyhedron_item()->itemChanged(); + selection->invalidateOpenGLBuffers(); + selection->setKeepSelectionValid(Scene_polyhedron_selection_item::None); + } + catch (const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) + { + CGAL::Three::Three::warning(tr("The requested operation is not possible due to the presence of self-intersections in the region handled.")); + } } } } diff --git a/Lab/demo/Lab/Plugins/PMP/Selection_plugin.cpp b/Lab/demo/Lab/Plugins/PMP/Selection_plugin.cpp index 6daad328b43c..fc283d16ae00 100644 --- a/Lab/demo/Lab/Plugins/PMP/Selection_plugin.cpp +++ b/Lab/demo/Lab/Plugins/PMP/Selection_plugin.cpp @@ -1,4 +1,4 @@ - #include +#include #include #include @@ -31,6 +31,11 @@ #include #include #include +#include + +#include +#include +#include #include typedef Scene_surface_mesh_item Scene_face_graph_item; @@ -144,13 +149,27 @@ class CGAL_Lab_selection_plugin : else if(action == actionSelection) return qobject_cast(scene->item(scene->mainSelectionIndex())) || qobject_cast(scene->item(scene->mainSelectionIndex())); + else if (action == actionSelectPolylines) + { + bool polylines_found = false; + bool facegraph_found = false; + for (const auto index : scene->selectionIndices()) + { + if (!polylines_found && qobject_cast(scene->item(index))) + polylines_found = true; + if (!facegraph_found && qobject_cast(scene->item(index))) + facegraph_found = true; + } + return polylines_found && facegraph_found; + } return false; } void print_message(QString message) { CGAL::Three::Three::information(message); } QList actions() const override { return QList() << actionSelection - << actionSelfIntersection; + << actionSelfIntersection + << actionSelectPolylines; } using CGAL_Lab_io_plugin_interface::init; @@ -164,6 +183,11 @@ class CGAL_Lab_selection_plugin : actionSelfIntersection->setProperty("subMenuName", "Polygon Mesh Processing"); connect(actionSelfIntersection, SIGNAL(triggered()), this, SLOT(on_actionSelfIntersection_triggered())); + actionSelectPolylines = new QAction(tr("Select polylines"), mw); + actionSelectPolylines->setObjectName("actionSelectPolylines"); + actionSelectPolylines->setProperty("subMenuName", "Polygon Mesh Processing"); + connect(actionSelectPolylines, SIGNAL(triggered()), this, SLOT(on_actionSelectPolylines_triggered())); + actionSelection = new QAction( QString("Surface Mesh Selection") , mw); @@ -265,6 +289,7 @@ class CGAL_Lab_selection_plugin : public Q_SLOTS: void on_actionSelfIntersection_triggered(); + void on_actionSelectPolylines_triggered(); void connectItem(Scene_polyhedron_selection_item* new_item) { @@ -1291,7 +1316,8 @@ void filter_operations() private: Messages_interface* messages; QAction* actionSelection; - QAction *actionSelfIntersection; + QAction* actionSelfIntersection; + QAction* actionSelectPolylines; QDockWidget* dock_widget; Ui::Selection ui_widget; @@ -1399,6 +1425,138 @@ void CGAL_Lab_selection_plugin::on_actionSelfIntersection_triggered() QMessageBox::information(mw, tr("No self intersection"), tr("None of the selected surfaces self-intersect.")); } + +void CGAL_Lab_selection_plugin::on_actionSelectPolylines_triggered() +{ + //todo : would it work with non-triangulated surfaces? + Scene_face_graph_item* facegraph_item = nullptr; + Scene_polylines_item* polylines_item = nullptr; + + for (Scene_interface::Item_id index : scene->selectionIndices()) + { + Scene_face_graph_item* tmp_item = + qobject_cast(scene->item(index)); + if (tmp_item) + facegraph_item = tmp_item; + else + { + Scene_polylines_item* tmp_item2 = + qobject_cast(scene->item(index)); + if (tmp_item2) + polylines_item = tmp_item2; + } + } + + const auto& tm = *facegraph_item->face_graph(); + if (!is_triangle_mesh(tm)) + { + QMessageBox::warning(mw, "Non triangle mesh", "Selection of edges works only on a triangulated surface."); + return; + } + + //check for existing selection for the same polyhedral surface + Scene_polyhedron_selection_item* selection_item = nullptr; + bool should_add = true; + const auto selection_item_found = selection_item_map.find(facegraph_item); + if (selection_item_found != selection_item_map.end()) + { + if (QMessageBox::question(mw, "Question", "Only one Selection Item can be associated to an item at once, " + "and one already exists. Would you like to keep it and add polylines ? (If not, this item will be skipped.)") + == QMessageBox::Yes) + { + selection_item = selection_item_found->second; + should_add = false; + } + } + if(should_add) + { + selection_item = new Scene_polyhedron_selection_item(facegraph_item, mw); + } + + //add selection edges + namespace PMP = CGAL::Polygon_mesh_processing; + using AABB_face_graph_primitive = CGAL::AABB_face_graph_triangle_primitive; + using AABB_face_graph_traits = CGAL::AABB_traits_3; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + const auto& features = polylines_item->polylines; + CGAL::AABB_tree tree; + + PMP::build_AABB_tree(tm, tree); + + auto locate_vertex = [&](const Point_3& p)->vertex_descriptor + { +// const double tol = 1e-5; //todo : make tolerance depend on bbox size + + if (!CGAL::do_overlap(tree.bbox(), p.bbox())) + return SMesh::null_vertex(); + + auto ploc = PMP::locate_with_AABB_tree(p, tree, tm); + + const face_descriptor f = ploc.first; + double w0 = ploc.second[0];//source(halfedge(f, tm), tm) + double w1 = ploc.second[1];//target(halfedge(f, tm), tm) + double w2 = ploc.second[2];//target(next(halfedge(f, tm), tm), tm) + + // if(CGAL::abs(w0) < tol) w0 = 0.; + // if(CGAL::abs(w1) < tol) w1 = 0.; + // if(CGAL::abs(w2) < tol) w2 = 0.; + + if (w0 > w1 && w0 > w2) return source(halfedge(f, tm), tm); + else if (w1 > w0 && w1 > w2) return target(halfedge(f, tm), tm); + else if (w2 > w0 && w2 > w1) return target(next(halfedge(f, tm), tm), tm); + + std::cerr << "ERROR : Can't locate vertex at " << p << std::endl; + return SMesh::null_vertex(); + }; + + unsigned int count_edges_added = 0; + unsigned int count_edges_not_found = 0; + + // add edges to selection + for(const Scene_polylines_item::Polyline& polyline : features) + { + if (polyline.empty()) + continue; + for(std::size_t i = 0; i < polyline.size() - 1; ++i) + { + vertex_descriptor v = locate_vertex(polyline[i]); + vertex_descriptor w = locate_vertex(polyline[i+1]); + + if (v == SMesh::null_vertex() || w == SMesh::null_vertex()) + { + ++count_edges_not_found; + continue; + } + + auto he_ok = halfedge(v, w, tm); + if(he_ok.second) + { + auto e = edge(he_ok.first, tm); + selection_item->selected_edges.insert(e); + ++count_edges_added; + } + else + { + ++count_edges_not_found; + continue; + } + } + } + std::cout << "edges added to selection : " << count_edges_added << std::endl; + std::cout << "edges not found : " << count_edges_not_found << std::endl; + + selection_item->invalidateOpenGLBuffers(); + selection_item->setName(tr("%1 (selection) ").arg(polylines_item->name())); + if (should_add) + connectItem(selection_item); + scene->itemChanged(facegraph_item); + + QApplication::restoreOverrideCursor(); +} + + //Q_EXPORT_PLUGIN2(CGAL_Lab_selection_plugin, CGAL_Lab_selection_plugin) #include "Selection_plugin.moc" diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h index 954623718216..0701ea0f526b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/clip.h @@ -477,8 +477,13 @@ generic_clip_impl( typedef OR_property_map Ecm1; typedef Corefinement::Ecm_bind Ecm_in; - Algo_ecm1 algo_ecm1 = get(CGAL::dynamic_edge_property_t(), tm1); + Algo_ecm1 algo_ecm1 = get(CGAL::dynamic_edge_property_t(), tm1, false); Ecm1 ecm1 = Ecm1(algo_ecm1, choose_parameter(get_parameter(np1, internal_np::edge_is_constrained))); + //TODO: HERE is seems hard to use the flag, it is even invalid right now if the user ecm is not empty! + //const bool mark_inter_edges = + // choose_parameter(get_parameter(np, internal_np::constrain_intersection_edges), true); + bool mark_inter_edges = true; + Ecm2 ecm2; // Face index point maps @@ -510,7 +515,7 @@ generic_clip_impl( Ob ob(tm1, tm2, vpm1, vpm2, algo_ecm1, fid_map1, use_compact_clipper); Corefinement::Intersection_of_triangle_meshes - functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in,&tm2), &tm2); + functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in,&tm2,mark_inter_edges), &tm2); functor(CGAL::Emptyset_iterator(), false, true); } @@ -619,6 +624,16 @@ clip(TriangleMesh& tm, internal::generic_clip_impl(tm, clipper, np_tm, np_c); return true; } + typedef typename internal_np::Lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters1, + Corefinement::No_mark//default + > ::type Ecm; + + const bool mark_inter_edges = + parameters::choose_parameter(parameters::get_parameter(np_tm, internal_np::constrain_intersection_edges), true); + + Ecm ecm = parameters::choose_parameter(parameters::get_parameter(np_tm, internal_np::edge_is_constrained)); const bool clip_volume = parameters::choose_parameter(parameters::get_parameter(np_tm, internal_np::clip_volume), false); @@ -626,7 +641,9 @@ clip(TriangleMesh& tm, if(clip_volume && is_closed(tm)) return corefine_and_compute_intersection(tm, clipper, tm, np_tm, np_c); return corefine_and_compute_intersection(tm, clipper, tm, - np_tm.use_bool_op_to_clip_surface(true), + np_tm.use_bool_op_to_clip_surface(true) + .constrain_intersection_edges(mark_inter_edges) + .edge_is_constrained_map(ecm), np_c); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h index f2e21ce70a57..9ce77fce58ed 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h @@ -476,7 +476,11 @@ corefine_and_compute_boolean_operations( Ecm_in ecm_in(tm1,tm2,ecm1,ecm2); Edge_mark_map_tuple ecms_out(ecm_out_0, ecm_out_1, ecm_out_2, ecm_out_3); + const bool mark_inter_edges = + choose_parameter(get_parameter(np1, internal_np::constrain_intersection_edges), true); Ob ob(tm1, tm2, vpm1, vpm2, fid_map1, fid_map2, ecm_in, vpm_out_tuple, ecms_out, uv, output); + if (!choose_parameter(get_parameter(np1, internal_np::constrain_intersection_edges), true)) + ob.do_not_mark_intersection_edges(); // special case used for clipping open meshes if (choose_parameter(get_parameter(np1, internal_np::use_bool_op_to_clip_surface), false)) @@ -491,7 +495,7 @@ corefine_and_compute_boolean_operations( } Corefinement::Intersection_of_triangle_meshes - functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in)); + functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm_in, nullptr, mark_inter_edges)); functor(CGAL::Emptyset_iterator(), throw_on_self_intersection, true); @@ -808,10 +812,16 @@ corefine( TriangleMesh& tm1, typedef Corefinement::Ecm_bind Ecm; + const bool mark_inter_edges = + choose_parameter(get_parameter(np1, internal_np::constrain_intersection_edges), true); + if (&tm1==&tm2) { - Corefinement::mark_all_edges(tm1, ecm1); - Corefinement::mark_all_edges(tm2, ecm2); + if (!mark_inter_edges) + { + Corefinement::mark_all_edges(tm1, ecm1); + Corefinement::mark_all_edges(tm2, ecm2); + } return; } @@ -835,7 +845,7 @@ corefine( TriangleMesh& tm1, Ob ob; Ecm ecm(tm1,tm2,ecm1,ecm2); Corefinement::Intersection_of_triangle_meshes - functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm,const_mesh_ptr), const_mesh_ptr); + functor(tm1, tm2, vpm1, vpm2, Algo_visitor(uv,ob,ecm,const_mesh_ptr, mark_inter_edges), const_mesh_ptr); // Fill non-manifold feature maps if provided functor.set_non_manifold_feature_map_1(parameters::get_parameter(np1, internal_np::non_manifold_feature_map)); @@ -914,7 +924,8 @@ autorefine( TriangleMesh& tm, Corefinement::No_mark//default > ::type Ecm; Ecm ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); - + const bool mark_inter_edges = + choose_parameter(get_parameter(np, internal_np::constrain_intersection_edges), true); // User visitor typedef typename internal_np::Lookup_named_param_def < internal_np::visitor_t, @@ -931,7 +942,7 @@ autorefine( TriangleMesh& tm, Ob ob; Corefinement::Intersection_of_triangle_meshes - functor(tm, vpm, Algo_visitor(uv,ob,ecm) ); + functor(tm, vpm, Algo_visitor(uv,ob,ecm,nullptr,mark_inter_edges) ); functor(CGAL::Emptyset_iterator(), true); } @@ -1011,7 +1022,8 @@ autorefine_and_remove_self_intersections( TriangleMesh& tm, Corefinement::No_mark//default > ::type Ecm; Ecm ecm = choose_parameter(get_parameter(np, internal_np::edge_is_constrained)); - + const bool mark_inter_edges = + choose_parameter(get_parameter(np, internal_np::constrain_intersection_edges), true); // User visitor typedef typename internal_np::Lookup_named_param_def < internal_np::visitor_t, @@ -1032,7 +1044,7 @@ autorefine_and_remove_self_intersections( TriangleMesh& tm, Ob ob(tm, vpm, fid_map, ecm); Corefinement::Intersection_of_triangle_meshes - functor(tm, vpm, Algo_visitor(uv,ob,ecm) ); + functor(tm, vpm, Algo_visitor(uv,ob,ecm,nullptr,mark_inter_edges) ); functor(CGAL::Emptyset_iterator(), true); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h index dc23ff6a462b..bbf81c0b5f46 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Face_graph_output_builder.h @@ -531,6 +531,8 @@ class Face_graph_output_builder // output meshes const std::array, 4>& requested_output; + //bool mark intersection edges + bool mark_inter_edges = true; // input meshes closed ? bool is_tm1_closed; bool is_tm2_closed; @@ -2315,7 +2317,8 @@ class Face_graph_output_builder ) CGAL_COREF_FUNCTION_CALL(operation) #undef CGAL_COREF_FUNCTION_CALL_DEF - mark_edges(out_edge_mark_maps, shared_edges, operation); + if (mark_inter_edges) + mark_edges(out_edge_mark_maps, shared_edges, operation); } Edge_map disconnected_patches_edge_to_tm2_edge; @@ -2324,9 +2327,10 @@ class Face_graph_output_builder if ( inplace_operation_tm1!=NONE ) { // mark intersection edges in tm1 (using output constrained edge map) - mark_edges(out_edge_mark_maps, - mesh_to_intersection_edges[&tm1], - inplace_operation_tm1); + if (mark_inter_edges) + mark_edges(out_edge_mark_maps, + mesh_to_intersection_edges[&tm1], + inplace_operation_tm1); CGAL_assertion( *requested_output[inplace_operation_tm1] == &tm1 ); @@ -2335,9 +2339,10 @@ class Face_graph_output_builder user_visitor.in_place_operations(inplace_operation_tm1, inplace_operation_tm2); // mark intersection edges in tm2 (using output constrained edge map) - mark_edges(out_edge_mark_maps, - mesh_to_intersection_edges[&tm2], - inplace_operation_tm2); + if (mark_inter_edges) + mark_edges(out_edge_mark_maps, + mesh_to_intersection_edges[&tm2], + inplace_operation_tm2); // operation in tm1 with removal (and optionally inside-out) delayed // First backup the border edges of patches to be used @@ -2624,9 +2629,10 @@ class Face_graph_output_builder user_visitor.in_place_operation(inplace_operation_tm2); // mark intersection edges in tm2 (using output constrained edge map) - mark_edges(out_edge_mark_maps, - mesh_to_intersection_edges[&tm2], - inplace_operation_tm2); + if (mark_inter_edges) + mark_edges(out_edge_mark_maps, + mesh_to_intersection_edges[&tm2], + inplace_operation_tm2); /// handle the operation updating only tm2 CGAL_assertion( *requested_output[inplace_operation_tm2] == &tm2 ); @@ -2661,6 +2667,11 @@ class Face_graph_output_builder patches_of_tm2); } } + + void do_not_mark_intersection_edges() + { + mark_inter_edges = false; + } }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h index 6b2964e8ae67..a08ff508a05a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/Visitor.h @@ -514,6 +514,7 @@ class Surface_intersection_visitor_for_corefinement{ EdgeMarkMapBind marks_on_edges; bool input_with_coplanar_faces; TriangleMesh* const_mesh_ptr; + bool mark_inter_edges; template void call_put(Ecm_bind& ecm, @@ -543,13 +544,14 @@ class Surface_intersection_visitor_for_corefinement{ // visitor public functions public: Surface_intersection_visitor_for_corefinement( - UserVisitor& uv, OutputBuilder& o, const EdgeMarkMapBind& emm, TriangleMesh* const_mesh_ptr=nullptr) + UserVisitor& uv, OutputBuilder& o, const EdgeMarkMapBind& emm, TriangleMesh* const_mesh_ptr, bool mark_inter_edges) : number_coplanar_vertices(0) , user_visitor(uv) , output_builder(o) , marks_on_edges(emm) , input_with_coplanar_faces(false) , const_mesh_ptr(const_mesh_ptr) + , mark_inter_edges(mark_inter_edges) {} @@ -1283,7 +1285,8 @@ class Surface_intersection_visitor_for_corefinement{ std::tie(h, is_face_border) = halfedge(vi,vn, tm); if (is_face_border) { - call_put(marks_on_edges,tm,edge(h,tm),true); + if (mark_inter_edges) + call_put(marks_on_edges,tm,edge(h,tm),true); output_builder.set_edge_per_polyline(tm,std::make_pair(id, id_n),h); } else @@ -1312,8 +1315,8 @@ class Surface_intersection_visitor_for_corefinement{ { halfedge_descriptor nh = Euler::split_face(a[0].first, a[1].first, tm); new_faces.push_back(face(opposite(nh, tm), tm)); - - call_put(marks_on_edges,tm,edge(nh,tm),true); + if (mark_inter_edges) + call_put(marks_on_edges,tm,edge(nh,tm),true); output_builder.set_edge_per_polyline(tm,std::make_pair(a[0].second, a[1].second),nh); } @@ -1517,7 +1520,8 @@ class Surface_intersection_visitor_for_corefinement{ //is defined as one of them defines an adjacent face //CGAL_assertion(it_poly_hedge!=edge_to_hedge.end()); if( it_poly_hedge!=edge_to_hedge.end() ){ - call_put(marks_on_edges,tm,edge(it_poly_hedge->second,tm),true); + if (mark_inter_edges) + call_put(marks_on_edges,tm,edge(it_poly_hedge->second,tm),true); output_builder.set_edge_per_polyline(tm,node_id_pair,it_poly_hedge->second); } else{ @@ -1527,7 +1531,8 @@ class Surface_intersection_visitor_for_corefinement{ it_poly_hedge=edge_to_hedge.find(opposite_pair); CGAL_assertion( it_poly_hedge!=edge_to_hedge.end() ); - call_put(marks_on_edges,tm,edge(it_poly_hedge->second,tm),true); + if (mark_inter_edges) + call_put(marks_on_edges,tm,edge(it_poly_hedge->second,tm),true); output_builder.set_edge_per_polyline(tm,opposite_pair,it_poly_hedge->second); } } @@ -1630,7 +1635,8 @@ class Surface_intersection_visitor_for_corefinement{ } if (did_break) continue; std::pair edge_pair(node_id,node_id_of_first); - call_put(marks_on_edges,tm,edge(hedge,tm),true); + if (mark_inter_edges) + call_put(marks_on_edges,tm,edge(hedge,tm),true); output_builder.set_edge_per_polyline(tm,edge_pair,hedge); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h index 2e82c4fae1b0..f31af78b0ce9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/face_graph_utils.h @@ -1681,7 +1681,7 @@ void remove_patches(TriangleMesh& tm, const boost::dynamic_bitset<>& patches_to_remove, PatchContainer& patches, - const EdgeMarkMap& edge_mark_map) + EdgeMarkMap& edge_mark_map) { typedef boost::graph_traits GT; typedef typename GT::face_descriptor face_descriptor; @@ -1767,7 +1767,7 @@ void compute_inplace_operation( const VertexPointMap1& vpm1, const VertexPointMap2& vpm2, EdgeMarkMapIn1& edge_mark_map_in1, - const EdgeMarkMapIn2& edge_mark_map_in2, + EdgeMarkMapIn2& edge_mark_map_in2, EdgeMarkMapOut1& edge_mark_map_out1, std::unordered_map< typename boost::graph_traits::edge_descriptor, @@ -1874,9 +1874,9 @@ void compute_inplace_operation( bool reverse_patch_orientation_tm2, const VertexPointMap1& vpm1, const VertexPointMap2& vpm2, - const EdgeMarkMapIn1& edge_mark_map_in1, - const EdgeMarkMapIn2& edge_mark_map_in2, - const EdgeMarkMapOut1& edge_mark_map_out1, + EdgeMarkMapIn1& edge_mark_map_in1, + EdgeMarkMapIn2& edge_mark_map_in2, + EdgeMarkMapOut1& edge_mark_map_out1, const IntersectionPolylines& polylines, UserVisitor& user_visitor) { diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 305527636c1c..9e0c34c8fff6 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -115,6 +115,7 @@ CGAL_add_named_parameter(allow_move_functor_t, allow_move_functor, allow_move_fu CGAL_add_named_parameter(throw_on_self_intersection_t, throw_on_self_intersection, throw_on_self_intersection) CGAL_add_named_parameter(clip_volume_t, clip_volume, clip_volume) CGAL_add_named_parameter(use_compact_clipper_t, use_compact_clipper, use_compact_clipper) +CGAL_add_named_parameter(constrain_intersection_edges_t, constrain_intersection_edges, constrain_intersection_edges) CGAL_add_named_parameter(output_iterator_t, output_iterator, output_iterator) CGAL_add_named_parameter(erase_all_duplicates_t, erase_all_duplicates, erase_all_duplicates) CGAL_add_named_parameter(require_same_orientation_t, require_same_orientation, require_same_orientation)