diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index cc7e537c714..962edbe37f7 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -60,6 +60,8 @@ for automatic detection and protection of 1D-curves that lie at the intersection of three or more subdomains, extracted from labeled images. +- Added new meshing criterion `edge_min_size` to avoid subdividing sharp edges that are shorter than the prescribed size bound. + ### [Shape Detection](https://doc.cgal.org/5.6/Manual/packages.html#PkgShapeDetection) (breaking change, major changes) - **Breaking change**: The region growing part of the package have been reworked to fix design issues introduced with the handling `FaceGraph` models. diff --git a/Mesh_3/doc/Mesh_3/CGAL/Mesh_edge_criteria_3.h b/Mesh_3/doc/Mesh_3/CGAL/Mesh_edge_criteria_3.h deleted file mode 100644 index 3acbda1bd27..00000000000 --- a/Mesh_3/doc/Mesh_3/CGAL/Mesh_edge_criteria_3.h +++ /dev/null @@ -1,53 +0,0 @@ -namespace CGAL { - -/*! -\ingroup PkgMesh3MeshClasses - -The function object class `Mesh_edge_criteria_3` is a model of `MeshEdgeCriteria_3`. It -provides a bound for the size criterion. - -\cgalModels `MeshEdgeCriteria_3` - -\sa `MeshCriteria_3` -\sa `CGAL::Mesh_criteria_3` -\sa `MeshDomainField_3` - -*/ -template< typename Tr > -class Mesh_edge_criteria_3 { -public: - -/// \name Types -/// @{ - -/*! -Numerical type. -*/ -typedef Tr::Geom_traits::FT FT; - -/// @} - -/// \name Creation -/// @{ - -/*! -Returns an object to serve as criteria for edges. -The argument `length_bound` is an upper bound -for the length of the edges which are used to discretize the curves. -Note that if one parameter is set to 0, then its corresponding criteria is ignored. -*/ -Mesh_edge_criteria_3(const FT& length_bound); - -/*! -Returns an object to serve as criteria for edges. The type `SizingField` -must be a model of concept `MeshDomainField_3`. The behavior and semantic of the argument are the same -as above, except that the length -parameter is a functional instead of a constant. -*/ -template -Mesh_edge_criteria_3(const SizingField& length_bound); - -/// @} - -}; /* end Mesh_edge_criteria_3 */ -} /* end namespace CGAL */ diff --git a/Mesh_3/doc/Mesh_3/Concepts/MeshEdgeCriteria_3.h b/Mesh_3/doc/Mesh_3/Concepts/MeshEdgeCriteria_3.h index 29ad69bc395..4c044751069 100644 --- a/Mesh_3/doc/Mesh_3/Concepts/MeshEdgeCriteria_3.h +++ b/Mesh_3/doc/Mesh_3/Concepts/MeshEdgeCriteria_3.h @@ -50,6 +50,12 @@ Returns the value of the sizing field (i.e.\ the maximum edge length) at point ` */ FT sizing_field(const Point_3& p); +/*! +Returns the lower bound on edge length, set by the user. +The lower bound is ignored when its value is 0. +*/ +const FT& min_length_bound() const; + /// @} }; /* end MeshEdgeCriteria_3 */ diff --git a/Mesh_3/doc/Mesh_3/Doxyfile.in b/Mesh_3/doc/Mesh_3/Doxyfile.in index d3608c7b5a0..3c630018edc 100644 --- a/Mesh_3/doc/Mesh_3/Doxyfile.in +++ b/Mesh_3/doc/Mesh_3/Doxyfile.in @@ -20,7 +20,8 @@ INPUT += \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_cell_base_3.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Compact_mesh_cell_base_3.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_in_image.h \ - ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_on_image_bbox.h + ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_3/Detect_features_on_image_bbox.h \ + ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Mesh_edge_criteria_3.h PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Mesh Generation" HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg \ diff --git a/Mesh_3/include/CGAL/Mesh_criteria_3.h b/Mesh_3/include/CGAL/Mesh_criteria_3.h index 334e7c6e290..5358e813742 100644 --- a/Mesh_3/include/CGAL/Mesh_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_criteria_3.h @@ -72,7 +72,8 @@ public: Mesh_criteria_3_impl(const CGAL_NP_CLASS& np) :edge_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_size_param), parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::edge_sizing_field_param), - parameters::choose_parameter(parameters::get_parameter(np, internal_np::sizing_field_param), FT(DBL_MAX))))), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::sizing_field_param), FT(DBL_MAX)))), + parameters::choose_parameter(parameters::get_parameter(np, internal_np::edge_min_size_param), FT(0))), facet_criteria_(parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_angle_param), FT(0)), parameters::choose_parameter(parameters::get_parameter(np, internal_np::facet_size_param), parameters::choose_parameter(parameters::get_parameter_reference(np, internal_np::facet_sizing_field_param), @@ -255,6 +256,18 @@ typedef Mesh_cell_criteria_3 Cell_criteria; * upper bound for the lengths of curve edges. This parameter has to be set to a positive * value when 1-dimensional features protection is used.} * \cgalParamNEnd + * \cgalParamNBegin{edge_min_size} + * \cgalParamDescription{a desired uniform lower-bound for the lengths of curve edges. + * Only feature edges with a length larger than this bound will be refined. + * If a feature edge is too small with respect to this criterion, + * it will not be refined whether the other criteria are met or not.} + * \cgalParamExtra{If this criterion is applied during the meshing process, + * the feature protection algorithm correctness is not guaranteed anymore, + * and the output mesh may contain incorrect polyline features, + * or have missing polyline features.} + * \cgalParamExtra{Note this lower-bound may not be respected everywhere in the output mesh, + * to keep the feature graph valid.} + * \cgalParamNEnd * \cgalParamNBegin{facet_angle} * \cgalParamDescription{a lower bound for the angles (in degrees) of the * surface mesh facets.} diff --git a/Mesh_3/include/CGAL/Mesh_edge_criteria_3.h b/Mesh_3/include/CGAL/Mesh_edge_criteria_3.h index d45ff426f9f..8846555dc6b 100644 --- a/Mesh_3/include/CGAL/Mesh_edge_criteria_3.h +++ b/Mesh_3/include/CGAL/Mesh_edge_criteria_3.h @@ -85,43 +85,98 @@ namespace internal { } // end namespace internal } // end namespace Mesh_3 +/*! +\ingroup PkgMesh3MeshClasses + +The function object class `Mesh_edge_criteria_3` is a model of `MeshEdgeCriteria_3`. It +provides a bound for the size criterion. + +\cgalModels `MeshEdgeCriteria_3` + +\sa `MeshCriteria_3` +\sa `CGAL::Mesh_criteria_3` +\sa `MeshDomainField_3` + +*/ template < typename Tr > class Mesh_edge_criteria_3 { +private: typedef Mesh_edge_criteria_3 Self; + typedef typename Tr::Geom_traits Gt; public: - typedef typename Tr::Vertex::Index Index; - typedef typename Tr::Geom_traits Gt; - typedef typename Gt::FT FT; - typedef typename Tr::Bare_point Point_3; + /// \name Types + /// @{ + /*! + Numerical type. + */ + typedef typename Tr::Geom_traits::FT FT; + typedef typename Tr::Vertex::Index Index; + typedef typename Tr::Bare_point Point_3; - /// Constructors - Mesh_edge_criteria_3(const FT& value) + /// @} + + + /// \name Creation + /// @{ + /*! + * Returns an object to serve as criteria for edges. + * \param length_bound is an upper bound + * for the length of the edges which are used to discretize the curves. + * \param min_length_bound is a desired lower bound + * for the length of the edges which are used to discretize the curves. + * Only edges that are longer than this bound will be refined. Using + * this lower bound can be handy on some domains, but using it may + * break all the surface topology guarantees of the meshing algorithm. + * It is not guaranteed to be exactly respected in the output mesh. + * + * Note that if one parameter is set to 0, then its corresponding criterion is ignored. + */ + Mesh_edge_criteria_3(const FT& length_bound, + const FT& min_length_bound = 0) : p_size_(new Mesh_3::internal::Sizing_field_container< Mesh_constant_domain_field_3 , FT, Point_3, - Index>(value)) + Index>(length_bound)) + , min_length_bound_(min_length_bound) {} // Nb: SFINAE to avoid wrong matches with built-in numerical types // as int. - template < typename Sizing_field > + /*! + * @tparam SizingField a model of `MeshDomainField_3` + * + * Returns an object to serve as criteria for edges. + * The behavior and semantic of the argument are the same + * as above, except that the `length_bound` + * parameter is a functional instead of a constant. + */ + template < typename SizingField > Mesh_edge_criteria_3 ( - const Sizing_field& size, - std::enable_if_t::value>* = 0 + const SizingField& length_bound, + const FT& min_length_bound = 0 +#ifndef DOXYGEN_RUNNING + , std::enable_if_t::value>* = 0 +#endif ) + : min_length_bound_(min_length_bound) { - p_size_ = new Mesh_3::internal::Sizing_field_container(size); + Index>(length_bound); } + /// @} + +#ifndef DOXYGEN_RUNNING Mesh_edge_criteria_3(const Self& rhs) - : p_size_(rhs.p_size_->clone()) {} + : p_size_(rhs.p_size_->clone()) + , min_length_bound_(rhs.min_length_bound_) + {} /// Destructor ~Mesh_edge_criteria_3() @@ -133,6 +188,13 @@ public: FT sizing_field(const Point_3& p, const int dim, const Index& index) const { return (*p_size_)(p,dim,index); } +public: + const FT& min_length_bound() const + { + return min_length_bound_; + } +#endif + private: typedef Mesh_3::internal::Sizing_field_interface Sizing_field_interface; @@ -140,6 +202,7 @@ private: // A pointer to Sizing_field_interface to handle dynamic wrapping of // real Sizing_field type Sizing_field_interface* p_size_; + const FT min_length_bound_; }; } // end namespace CGAL diff --git a/Mesh_3/include/CGAL/make_mesh_3.h b/Mesh_3/include/CGAL/make_mesh_3.h index db1c8448811..79277f1643f 100644 --- a/Mesh_3/include/CGAL/make_mesh_3.h +++ b/Mesh_3/include/CGAL/make_mesh_3.h @@ -111,7 +111,7 @@ void init_c3t3_with_features(C3T3& c3t3, protect_edges(c3t3, domain, Sizing_field(criteria.edge_criteria_object()), - typename Edge_criteria::FT(), + criteria.edge_criteria_object().min_length_bound(), maximal_number_of_vertices, pointer_to_error_code #ifndef CGAL_NO_ATOMIC diff --git a/Mesh_3/test/Mesh_3/CMakeLists.txt b/Mesh_3/test/Mesh_3/CMakeLists.txt index 6914a7cc846..9d5103e9405 100644 --- a/Mesh_3/test/Mesh_3/CMakeLists.txt +++ b/Mesh_3/test/Mesh_3/CMakeLists.txt @@ -54,6 +54,7 @@ create_single_source_cgal_program( "test_mesh_3_issue_1554.cpp" ) create_single_source_cgal_program( "test_mesh_polyhedral_domain_with_features_deprecated.cpp" ) create_single_source_cgal_program( "test_meshing_with_one_step.cpp" ) create_single_source_cgal_program( "test_mesh_cell_base_3.cpp") +create_single_source_cgal_program( "test_min_edge_length.cpp") foreach(target test_boost_has_xxx @@ -84,6 +85,7 @@ foreach(target test_mesh_polyhedral_domain_with_features_deprecated test_mesh_cell_base_3 test_meshing_with_one_step + test_min_edge_length test_min_size_criteria ) if(TARGET ${target}) @@ -108,6 +110,7 @@ if(TARGET CGAL::TBB_support) test_mesh_3_issue_1554 test_mesh_polyhedral_domain_with_features_deprecated test_mesh_cell_base_3 + test_min_edge_length test_min_size_criteria ) if(TARGET ${target}) diff --git a/Mesh_3/test/Mesh_3/test_min_edge_length.cpp b/Mesh_3/test/Mesh_3/test_min_edge_length.cpp new file mode 100644 index 00000000000..5f65c365218 --- /dev/null +++ b/Mesh_3/test/Mesh_3/test_min_edge_length.cpp @@ -0,0 +1,85 @@ +#include + +#include +#include +#include +#include + +#include +#include + +#include + + +template +struct Tester +{ + // Domain + typedef CGAL::Polyhedral_mesh_domain_with_features_3 Mesh_domain; + + // Triangulation + typedef typename CGAL::Mesh_triangulation_3::type Tr; + + typedef CGAL::Mesh_complex_3_in_triangulation_3 C3t3; + + // Criteria + typedef CGAL::Mesh_criteria_3 Mesh_criteria; + + void operator()(const std::string fname, const std::string out_fname) + { + std::ifstream input(fname); + using namespace CGAL::parameters; + + Polyhedron polyhedron; + input >> polyhedron; + if (input.fail()) { + std::cerr << "Error: Cannot read file " << fname << std::endl; + return; + } + + if (!CGAL::is_triangle_mesh(polyhedron)) { + std::cerr << "Input geometry is not triangulated." << std::endl; + return; + } + + // Create domain + Mesh_domain domain(polyhedron); + + domain.detect_features(40); + + Sizing_field_with_aabb_tree sf(0.074, domain.aabb_tree(), domain); + + // Mesh criteria + Mesh_criteria criteria(edge_size = sf, + edge_min_size = 0.1, + facet_distance = 0.0074, + facet_angle = 25, + facet_size = 0.074, + cell_radius_edge_ratio = 3, + cell_size = 0.074); + + // Mesh generation + C3t3 c3t3 = CGAL::make_mesh_3(domain, criteria, no_perturb(), no_exude()); + + // Output + CGAL::dump_c3t3(c3t3, out_fname); + } +}; + +int main(int argc, char* argv[]) +{ + const std::string fname = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/dragknob.off"); + + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; + typedef CGAL::Surface_mesh Surface_mesh; + + std::cout << "Sequential test" << std::endl; + Tester()(fname, "out-dragknob-sequential"); + + std::cout << "Parallel test" << std::endl; + Tester()(fname, "out-dragknob-parallel"); + + return EXIT_SUCCESS; +} diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp index 3f5ff1d1f45..11e52ca9587 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp @@ -70,6 +70,7 @@ class Mesh_3_plugin : READ get_sharp_edges_angle_bound WRITE set_sharp_edges_angle_bound) Q_PROPERTY(double edges_sizing READ get_edges_sizing WRITE set_edges_sizing) + Q_PROPERTY(double edges_min_sizing READ get_edges_min_sizing WRITE set_edges_min_sizing) Q_PROPERTY(double facets_sizing READ get_facets_sizing WRITE set_facets_sizing) Q_PROPERTY(double approx READ get_approx WRITE set_approx) Q_PROPERTY(double tets_sizing READ get_tets_sizing WRITE set_tets_sizing) @@ -155,6 +156,7 @@ public Q_SLOTS: sharp_edges_angle_bound = v; } void set_edges_sizing(const double v) { edges_sizing = v; }; + void set_edges_min_sizing(const double v) { edges_min_sizing = v; }; void set_facets_sizing(const double v) { facets_sizing = v; }; void set_approx(const double v) { approx = v; }; void set_tets_sizing(const double v) { tets_sizing = v; }; @@ -167,6 +169,7 @@ public Q_SLOTS: double get_angle() { return angle; }; double get_sharp_edges_angle_bound() { return sharp_edges_angle_bound; } double get_edges_sizing() { return edges_sizing; }; + double get_edges_min_sizing() { return edges_min_sizing; }; double get_facets_sizing() { return facets_sizing; }; double get_approx() { return approx; }; double get_tets_sizing() { return tets_sizing; }; @@ -202,6 +205,7 @@ private: double approx; int approx_decimals; double edges_sizing; + double edges_min_sizing; double facets_sizing; double facets_min_sizing; double tets_sizing; @@ -422,6 +426,7 @@ void Mesh_3_plugin::set_defaults() { double diag = CGAL::sqrt((bbox.xmax()-bbox.xmin())*(bbox.xmax()-bbox.xmin()) + (bbox.ymax()-bbox.ymin())*(bbox.ymax()-bbox.ymin()) + (bbox.zmax()-bbox.zmin())*(bbox.zmax()-bbox.zmin())); facets_sizing = get_approximate(diag * 0.05, 2, sizing_decimals); edges_sizing = facets_sizing; + edges_min_sizing = 0.1 * facets_sizing; tets_sizing = facets_sizing; facets_min_sizing = 0.1 * facets_sizing; tets_min_sizing = 0.1 * tets_sizing; @@ -518,6 +523,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, ui.tetShape, SLOT(setEnabled(bool))); + //edge sizing connect(ui.protect, SIGNAL(toggled(bool)), ui.noEdgeSizing, @@ -538,6 +544,28 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, ui.edgeSizing, SLOT(setEnabled(bool))); + //edge min sizing + connect(ui.protect, + SIGNAL(toggled(bool)), + ui.noEdgeMinSizing, + SLOT(setEnabled(bool))); + + connect(ui.protect, + SIGNAL(toggled(bool)), + ui.noEdgeMinSizing, + SLOT(setChecked(bool))); + + connect(ui.noEdgeMinSizing, + SIGNAL(toggled(bool)), + ui.edgeMinSizingLabel, + SLOT(setEnabled(bool))); + + connect(ui.noEdgeMinSizing, + SIGNAL(toggled(bool)), + ui.edgeMinSizing, + SLOT(setEnabled(bool))); + + //sharp edges connect(ui.protect, SIGNAL(toggled(bool)), ui.sharpEdgesAngle, @@ -572,6 +600,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, ui.facetSizing->setValue(facets_sizing); ui.facetMinSizing->setValue(facets_min_sizing); ui.edgeSizing->setValue(edges_sizing); + ui.edgeMinSizing->setValue(edges_min_sizing); ui.tetSizing->setRange(diag * 10e-6, // min diag); // max @@ -610,8 +639,11 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, " automatically")); } ui.noEdgeSizing->setChecked(ui.protect->isChecked()); + ui.noEdgeMinSizing->setChecked(false); ui.edgeLabel->setEnabled(ui.noEdgeSizing->isChecked()); ui.edgeSizing->setEnabled(ui.noEdgeSizing->isChecked()); + ui.edgeMinSizingLabel->setEnabled(ui.noEdgeMinSizing->isChecked()); + ui.edgeMinSizing->setEnabled(ui.noEdgeMinSizing->isChecked()); const QString sharp_and_boundary("Sharp and Boundary edges"); const QString boundary_only("Boundary edges only"); @@ -677,6 +709,8 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, std::cerr << "sharp_edges_angle_bound: " << sharp_edges_angle_bound << '\n'; edges_sizing = !ui.noEdgeSizing->isChecked() ? DBL_MAX : ui.edgeSizing->value(); + edges_min_sizing = + !ui.noEdgeMinSizing->isChecked() ? 0. : ui.edgeMinSizing->value(); facets_sizing = !ui.noFacetSizing->isChecked() ? 0 : ui.facetSizing->value(); facets_min_sizing = !ui.noFacetMinSizing->isChecked() ? 0 : ui.facetMinSizing->value(); approx = !ui.noApprox->isChecked() ? 0 : ui.approx->value(); @@ -685,12 +719,23 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, tets_min_sizing = !ui.noTetMinSizing->isChecked() ? 0 : ui.tetMinSizing->value(); const int pe_ci = ui.protectEdges->currentIndex(); - protect_borders = ui.protect->isChecked() - && ( pe_ci == ui.protectEdges->findText(on_cube, Qt::MatchContains) - || pe_ci == ui.protectEdges->findText(boundary_only, Qt::MatchContains)); - protect_features = ui.protect->isChecked() - && ( pe_ci == ui.protectEdges->findText(triple_lines, Qt::MatchContains) - || pe_ci == ui.protectEdges->findText(sharp_and_boundary, Qt::MatchContains)); + if (items->which() == IMAGE_MESH_ITEMS) + { + protect_borders = ui.protect->isChecked() + && ( pe_ci == ui.protectEdges->findText(on_cube, Qt::MatchContains) + || pe_ci == ui.protectEdges->findText(boundary_only, Qt::MatchContains)); + protect_features = ui.protect->isChecked() + && ( pe_ci == ui.protectEdges->findText(triple_lines, Qt::MatchContains) + || pe_ci == ui.protectEdges->findText(sharp_and_boundary, Qt::MatchContains)); + } + else if (items->which() == POLYHEDRAL_MESH_ITEMS) + { + protect_borders = ui.protect->isChecked() + && ( pe_ci == ui.protectEdges->findText(sharp_and_boundary, Qt::MatchContains) + || pe_ci == ui.protectEdges->findText(boundary_only, Qt::MatchContains)); + protect_features = ui.protect->isChecked() + && ( pe_ci == ui.protectEdges->findText(sharp_edges, Qt::MatchContains)); + } const bool detect_connected_components = ui.detectComponents->isChecked(); const int manifold = (ui.manifoldCheckBox->isChecked() ? 1 : 0) + @@ -762,6 +807,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, tets_sizing, tets_min_sizing, edges_sizing, + edges_min_sizing, tets_shape, protect_features, protect_borders, @@ -782,6 +828,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, tets_sizing, tets_min_sizing, edges_sizing, + edges_min_sizing, tets_shape, protect_features, protect_borders, @@ -808,6 +855,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, tets_sizing, tets_min_sizing, edges_sizing, + edges_min_sizing, tets_shape, manifold, mesh_type == Mesh_type::SURFACE_ONLY); @@ -850,6 +898,7 @@ void Mesh_3_plugin::mesh_3(const Mesh_type mesh_type, tets_sizing, tets_min_sizing, edges_sizing, + edges_min_sizing, tets_shape, protect_features, protect_borders, diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp index 707313d3aa3..bfd480bceba 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.cpp @@ -44,6 +44,7 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, bool protect_borders, @@ -56,6 +57,7 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, std::cerr << "Meshing file \"" << qPrintable(filename) << "\"\n"; std::cerr << " angle: " << facet_angle << std::endl << " edge size bound: " << edge_size << std::endl + << " edge min size bound: " << edge_min_size << std::endl << " facets size bound: " << facet_sizing << std::endl << " approximation bound: " << facet_approx << std::endl; if (!surface_only) @@ -105,10 +107,12 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, "
    " "
  • Angle: %1
  • " "
  • Edge size bound: %2
  • " - "
  • Facets size bound: %3
  • " - "
  • Approximation bound: %4
  • ") + "
  • Edge min size bound: %3
  • " + "
  • Facets size bound: %4
  • " + "
  • Approximation bound: %5
  • ") .arg(facet_angle) .arg(edge_size) + .arg(edge_min_size) .arg(facet_sizing) .arg(facet_approx); if (!surface_only) @@ -126,6 +130,7 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, param.tet_min_sizing = tet_min_sizing; param.tet_shape = tet_shape; param.edge_sizing = edge_size; + param.edge_min_sizing = edge_min_size; param.manifold = manifold; param.protect_features = protect_features || protect_borders; param.use_sizing_field_with_aabb_tree = polylines.empty() && protect_features; @@ -147,6 +152,7 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, bool protect_borders, @@ -159,6 +165,7 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, std::cerr << "Meshing file \"" << qPrintable(filename) << "\"\n"; std::cerr << " angle: " << facet_angle << std::endl << " edge size bound: " << edge_size << std::endl + << " edge min size bound: " << edge_min_size << std::endl << " facets size bound: " << facet_sizing << std::endl << " approximation bound: " << facet_approx << std::endl; if (!surface_only) @@ -203,10 +210,12 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, "
      " "
    • Angle: %1
    • " "
    • Edge size bound: %2
    • " - "
    • Facets size bound: %3
    • " - "
    • Approximation bound: %4
    • ") + "
    • Edge min size bound :%3
    • " + "
    • Facets size bound: %4
    • " + "
    • Approximation bound: %5
    • ") .arg(facet_angle) .arg(edge_size) + .arg(edge_min_size) .arg(facet_sizing) .arg(facet_approx); if (!surface_only) @@ -224,6 +233,7 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, param.tet_min_sizing = tet_min_sizing; param.tet_shape = tet_shape; param.edge_sizing = edge_size; + param.edge_min_sizing = edge_min_size; param.manifold = manifold; param.protect_features = protect_features || protect_borders; param.use_sizing_field_with_aabb_tree = protect_features; @@ -246,6 +256,7 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, const int manifold, const bool surface_only) @@ -277,6 +288,7 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction, param.tet_min_sizing = tet_min_sizing; param.tet_shape = tet_shape; param.edge_sizing = edge_size; + param.edge_min_sizing = edge_min_size; param.manifold = manifold; param.detect_connected_components = false; // to avoid random values // in the debug displays @@ -306,6 +318,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, //detect_polylines const bool protect_borders,//polylines on bbox @@ -333,6 +346,7 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage, param.facet_min_sizing = facet_min_sizing; param.tet_min_sizing = tet_min_sizing; param.edge_sizing = edge_size; + param.edge_min_sizing = edge_min_size; param.tet_shape = tet_shape; param.manifold = manifold; param.image_3_ptr = pImage; @@ -343,10 +357,12 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage, "
        " "
      • Angle: %1
      • " "
      • Edge size bound: %2
      • " - "
      • Facets size bound: %3
      • " - "
      • Approximation bound: %4
      • ") + "
      • Edge min size bound: %3
      • " + "
      • Facets size bound: %4
      • " + "
      • Approximation bound: %5
      • ") .arg(facet_angle) .arg(edge_size) + .arg(edge_min_size) .arg(facet_sizing) .arg(facet_approx); if (!surface_only) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.h b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.h index 4bf500ea510..4a705ccd4eb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin_cgal_code.h @@ -31,6 +31,7 @@ Meshing_thread* cgal_code_mesh_3(QList pMeshes, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, bool protect_border, @@ -48,6 +49,7 @@ Meshing_thread* cgal_code_mesh_3(const QList pMeshes, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, bool protect_border, @@ -64,6 +66,7 @@ Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface* pfunction, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, const int manifold, const bool surface_only); @@ -79,6 +82,7 @@ Meshing_thread* cgal_code_mesh_3(const CGAL::Image_3* pImage, const double tet_sizing, const double tet_min_sizing, const double edge_size, + const double edge_min_size, const double tet_shape, bool protect_features, const bool protect_borders, diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h index 366b452f17b..65392c0366e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_function.h @@ -51,6 +51,7 @@ struct Mesh_parameters double tet_sizing; double tet_min_sizing; double edge_sizing; + double edge_min_sizing; bool protect_features; bool detect_connected_components; int manifold; @@ -110,8 +111,8 @@ private: void initialize(const Mesh_criteria& criteria, Mesh_fnt::Domain_tag); void initialize(const Mesh_criteria& criteria, Mesh_fnt::Labeled_image_domain_tag); - Edge_criteria edge_criteria(double b, Mesh_fnt::Domain_tag); - Edge_criteria edge_criteria(double b, Mesh_fnt::Polyhedral_domain_tag); + Edge_criteria edge_criteria(double b, double minb, Mesh_fnt::Domain_tag); + Edge_criteria edge_criteria(double b, double minb, Mesh_fnt::Polyhedral_domain_tag); void tweak_criteria(Mesh_criteria&, Mesh_fnt::Domain_tag) {} void tweak_criteria(Mesh_criteria&, Mesh_fnt::Polyhedral_domain_tag); @@ -139,6 +140,7 @@ log() const { return QStringList() << QString("edge max size: %1").arg(edge_sizing) + << QString("edge min size: %1").arg(edge_min_sizing) << QString("facet min angle: %1").arg(facet_angle) << QString("facet max size: %1").arg(facet_sizing) << QString("facet min size: %1").arg(facet_min_sizing) @@ -242,9 +244,9 @@ initialize(const Mesh_criteria& criteria, Mesh_fnt::Domain_tag) template < typename D_, typename Tag > typename Mesh_function::Edge_criteria Mesh_function:: -edge_criteria(double b, Mesh_fnt::Domain_tag) +edge_criteria(double b, double minb, Mesh_fnt::Domain_tag) { - return Edge_criteria(b); + return Edge_criteria(b, minb); } #include @@ -253,7 +255,7 @@ edge_criteria(double b, Mesh_fnt::Domain_tag) template < typename D_, typename Tag > typename Mesh_function::Edge_criteria Mesh_function:: -edge_criteria(double edge_size, Mesh_fnt::Polyhedral_domain_tag) +edge_criteria(double edge_size, double minb, Mesh_fnt::Polyhedral_domain_tag) { if(p_.use_sizing_field_with_aabb_tree) { typedef typename Domain::Surface_patch_index_set Set_of_patch_ids; @@ -281,9 +283,9 @@ edge_criteria(double edge_size, Mesh_fnt::Polyhedral_domain_tag) QSharedPointer(patches_ids_vector_p)); std::cerr << "Note: Mesh_3 is using a sizing field based on AABB tree.\n"; - return Edge_criteria(*sizing_field_ptr); + return Edge_criteria(*sizing_field_ptr, minb); } else { - return Edge_criteria(edge_size); + return Edge_criteria(edge_size, minb); } } @@ -297,7 +299,9 @@ launch() #endif // Create mesh criteria - Mesh_criteria criteria(edge_criteria(p_.edge_sizing, Tag()), + Mesh_criteria criteria(edge_criteria(p_.edge_sizing, + p_.edge_min_sizing, + Tag()), Facet_criteria(p_.facet_angle, p_.facet_sizing, p_.facet_approx, @@ -349,8 +353,9 @@ tweak_criteria(Mesh_criteria& c, Mesh_fnt::Polyhedral_domain_tag) { typedef CGAL::Mesh_3::Facet_topological_criterion_with_adjacency New_topo_adj_crit; - if((int(c.facet_criteria_object().topology()) & + if(((int(c.facet_criteria_object().topology()) & CGAL::FACET_VERTICES_ON_SAME_SURFACE_PATCH_WITH_ADJACENCY_CHECK) != 0) + && c.edge_criteria_object().min_length_bound() == 0) { c.add_facet_criterion(new New_topo_adj_crit(this->domain_)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui index e95fd891898..88ee87fc1be 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Meshing_dialog.ui @@ -10,7 +10,7 @@ 0 0 799 - 1231 + 1295 @@ -101,22 +101,15 @@ Sharp features - - + + - 60.00 + 0.0 - - - - - - - true - - + + @@ -134,15 +127,22 @@ - - + + - + 60.00 - - + + + + + + + true + + @@ -157,13 +157,6 @@ - - - - 0.0 - - - @@ -177,6 +170,33 @@ + + + + + + + + + + + Edge min size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + 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 49ed237c50c..6f6b2ef5178 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -337,6 +337,7 @@ CGAL_add_named_parameter_with_compatibility(features_detector_param_t, features_ CGAL_add_named_parameter_with_compatibility(input_features_param_t, input_features_param, input_features) CGAL_add_named_parameter_with_compatibility(edge_size_param_t, edge_size_param, edge_size) +CGAL_add_named_parameter_with_compatibility(edge_min_size_param_t, edge_min_size_param, edge_min_size) CGAL_add_named_parameter_with_compatibility_ref_only(edge_sizing_field_param_t, edge_sizing_field_param, edge_sizing_field) CGAL_add_named_parameter_with_compatibility(facet_angle_param_t, facet_angle_param, facet_angle) CGAL_add_named_parameter_with_compatibility(facet_size_param_t, facet_size_param, facet_size)