Merge remote-tracking branch 'cgal/6.0.x-branch' into 'cgal/master'

This commit is contained in:
Sébastien Loriot 2025-07-31 15:19:07 +02:00
commit 8e0f2d6f73
12 changed files with 96 additions and 51 deletions

View File

@ -622,7 +622,7 @@ bool are_holes_and_boundary_pairwise_disjoint
Topology_traits; Topology_traits;
typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits> typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits>
Polygon_set_2; Polygon_set_2;
typedef typename Polygon_set_2::Size Size; // typedef typename Polygon_set_2::Size Size;
typedef typename Traits_2::Polygon_2 Polygon_2; typedef typename Traits_2::Polygon_2 Polygon_2;
typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2;
typedef typename Polygon_with_holes_2::Hole_const_iterator typedef typename Polygon_with_holes_2::Hole_const_iterator
@ -676,7 +676,7 @@ bool are_holes_and_boundary_pairwise_disjoint
Polygon_set_2 gps(traits); Polygon_set_2 gps(traits);
// check for 2D intersections of holes (holes must be disjoint except for // check for 2D intersections of holes (holes must be disjoint except for
// vertices) // vertices)
Size num_of_holes = 0; // Size num_of_holes = 0;
// functors for creating a pwh needed for inserting pgns into the arrangement // functors for creating a pwh needed for inserting pgns into the arrangement
// quickly // quickly
Construct_polygon_with_holes_2 construct_pwh_functor = Construct_polygon_with_holes_2 construct_pwh_functor =
@ -700,7 +700,7 @@ bool are_holes_and_boundary_pairwise_disjoint
// traits.Construct_polygon_with_holes_2 (hole); // traits.Construct_polygon_with_holes_2 (hole);
// Polygon_with_holes_2 empty_pwh(hole); // Polygon_with_holes_2 empty_pwh(hole);
gps.insert(empty_pwh); gps.insert(empty_pwh);
num_of_holes++; // num_of_holes++;
} }
} }
/* not good - doesn't work if intersection at vertices is legal. /* not good - doesn't work if intersection at vertices is legal.

View File

@ -34,6 +34,13 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QKeyCombination> #include <QKeyCombination>
#ifndef APIENTRY
#define APIENTRY QT_APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
class QTabWidget; class QTabWidget;
class QImage; class QImage;
class QOpenGLFramebufferObject; class QOpenGLFramebufferObject;

View File

@ -49,7 +49,7 @@ else()
endif() endif()
find_package(Boost QUIET OPTIONAL_COMPONENTS filesystem system) find_package(Boost QUIET OPTIONAL_COMPONENTS filesystem system)
if(Boost_FILESYSTEM_FOUND) if(Boost_FILESYSTEM_FOUND AND Boost_SYSTEM_FOUND)
qt6_wrap_ui( imgUI_FILES Image_res_dialog.ui raw_image.ui) qt6_wrap_ui( imgUI_FILES Image_res_dialog.ui raw_image.ui)
cgal_lab_plugin(io_image_plugin Io_image_plugin cgal_lab_plugin(io_image_plugin Io_image_plugin
Volume_plane_intersection.cpp Volume_plane_intersection.cpp

View File

@ -646,6 +646,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
{ {
using CGAL::parameters::choose_parameter; using CGAL::parameters::choose_parameter;
using CGAL::parameters::get_parameter; using CGAL::parameters::get_parameter;
using parameters::is_default_parameter;
typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
@ -702,6 +703,9 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
CGAL_precondition(is_triangle_mesh(tmesh)); CGAL_precondition(is_triangle_mesh(tmesh));
// constrain extremities of constrained edges // constrain extremities of constrained edges
if constexpr (!is_default_parameter<NamedParameters, internal_np::edge_is_constrained_t>::value ||
!is_default_parameter<NamedParameters, internal_np::vertex_is_constrained_t>::value)
{
for(face_descriptor f : face_range) for(face_descriptor f : face_range)
{ {
if(f == boost::graph_traits<TriangleMesh>::null_face()) if(f == boost::graph_traits<TriangleMesh>::null_face())
@ -720,6 +724,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
} }
} }
} }
}
// @todo maybe using a priority queue handling the more almost degenerate elements first should be used // @todo maybe using a priority queue handling the more almost degenerate elements first should be used
std::unordered_set<halfedge_descriptor> edges_to_collapse; std::unordered_set<halfedge_descriptor> edges_to_collapse;
@ -813,7 +818,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
const edge_descriptor e = edge(h, tmesh); const edge_descriptor e = edge(h, tmesh);
CGAL_assertion(!get(ecm, edge(h, tmesh))); CGAL_assertion(!get(ecm, edge(h, tmesh)));
CGAL_assertion(!get(vcm, source(h, tmesh)) && !get(vcm, target(h, tmesh))); CGAL_assertion(!get(vcm, source(h, tmesh)) || !get(vcm, target(h, tmesh)));
#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA
std::cout << " treat needle: " << e std::cout << " treat needle: " << e

View File

@ -50,7 +50,7 @@ public:
virtual void append(const Property_array_base<Index>& other) = 0; virtual void append(const Property_array_base<Index>& other) = 0;
virtual void reserve(std::size_t n) = 0; virtual void resize(std::size_t n) = 0;
virtual void shrink_to_fit() = 0; virtual void shrink_to_fit() = 0;
@ -89,7 +89,6 @@ public:
Property_array(const std::vector<bool>& active_indices, const T& default_value) : Property_array(const std::vector<bool>& active_indices, const T& default_value) :
m_data(), m_active_indices(active_indices), m_default_value(default_value) { m_data(), m_active_indices(active_indices), m_default_value(default_value) {
m_data.reserve(active_indices.capacity());
m_data.resize(active_indices.size(), m_default_value); m_data.resize(active_indices.size(), m_default_value);
} }
@ -124,7 +123,7 @@ public:
m_data.insert(m_data.end(), other.m_data.begin(), other.m_data.end()); m_data.insert(m_data.end(), other.m_data.begin(), other.m_data.end());
} }
virtual void reserve(std::size_t n) override { virtual void resize(std::size_t n) override {
CGAL_precondition(m_active_indices.size() == n); CGAL_precondition(m_active_indices.size() == n);
m_data.resize(n, m_default_value); m_data.resize(n, m_default_value);
}; };
@ -248,6 +247,7 @@ class Property_container {
std::multimap<std::string, std::shared_ptr<Property_array_base<Index>>> m_properties; std::multimap<std::string, std::shared_ptr<Property_array_base<Index>>> m_properties;
std::vector<bool> m_active_indices{}; std::vector<bool> m_active_indices{};
bool m_has_deleted_elements = false;
public: public:
@ -258,6 +258,7 @@ public:
Property_container(const Property_container<Index>& other) { Property_container(const Property_container<Index>& other) {
m_active_indices = other.m_active_indices; m_active_indices = other.m_active_indices;
m_has_deleted_elements = other.m_has_deleted_elements;
for (auto [name, array] : other.m_properties) { for (auto [name, array] : other.m_properties) {
// todo: this could probably be made faster using emplace_hint // todo: this could probably be made faster using emplace_hint
@ -273,6 +274,7 @@ public:
// This is not exactly an assignment as existing unique properties are kept. // This is not exactly an assignment as existing unique properties are kept.
Property_container<Index>& operator=(const Property_container<Index>& other) { Property_container<Index>& operator=(const Property_container<Index>& other) {
m_active_indices = other.m_active_indices; m_active_indices = other.m_active_indices;
m_has_deleted_elements = other.m_has_deleted_elements;
for (auto [name, array] : other.m_properties) { for (auto [name, array] : other.m_properties) {
// search if property already exists // search if property already exists
@ -295,6 +297,7 @@ public:
// This is not exactly an assignment as existing unique properties are kept. // This is not exactly an assignment as existing unique properties are kept.
Property_container<Index>& operator=(Property_container<Index>&& other) { Property_container<Index>& operator=(Property_container<Index>&& other) {
m_active_indices = std::move(other.m_active_indices); m_active_indices = std::move(other.m_active_indices);
m_has_deleted_elements = other.m_has_deleted_elements;
for (auto [name, array] : other.m_properties) { for (auto [name, array] : other.m_properties) {
// search if property already exists // search if property already exists
@ -312,7 +315,7 @@ public:
} }
// The moved-from property map should retain all of its properties, but contain 0 elements // The moved-from property map should retain all of its properties, but contain 0 elements
other.reserve(0); other.resize(0);
return *this; return *this;
} }
@ -441,16 +444,15 @@ public:
}*/ }*/
public: public:
void resize(std::size_t n) {
void reserve(std::size_t n) {
m_active_indices.resize(n); m_active_indices.resize(n);
for (auto [name, array] : m_properties) for (auto [name, array] : m_properties)
array->reserve(n); array->resize(n);
}
void resize(std::size_t n) {
reserve(n);
std::fill(m_active_indices.begin(), m_active_indices.end(), true); std::fill(m_active_indices.begin(), m_active_indices.end(), true);
m_has_deleted_elements = false;
} }
[[nodiscard]] std::size_t size() const { return std::count(m_active_indices.begin(), m_active_indices.end(), true); } [[nodiscard]] std::size_t size() const { return std::count(m_active_indices.begin(), m_active_indices.end(), true); }
@ -460,8 +462,11 @@ public:
Index emplace_back() { Index emplace_back() {
// Expand the storage and return the last element // Expand the storage and return the last element
reserve(capacity() + 1); m_active_indices.push_back(true);
m_active_indices.back() = true;
for (auto [name, array] : m_properties)
array->resize(capacity());
auto first_new_index = Index(capacity() - 1); auto first_new_index = Index(capacity() - 1);
reset(first_new_index); reset(first_new_index);
return first_new_index; return first_new_index;
@ -469,6 +474,9 @@ public:
Index emplace() { Index emplace() {
if (!m_has_deleted_elements)
return emplace_back();
// If there are empty slots, return the index of one of them and mark it as full // If there are empty slots, return the index of one of them and mark it as full
auto first_unused = std::find_if(m_active_indices.begin(), m_active_indices.end(), [](bool used) { return !used; }); auto first_unused = std::find_if(m_active_indices.begin(), m_active_indices.end(), [](bool used) { return !used; });
if (first_unused != m_active_indices.end()) { if (first_unused != m_active_indices.end()) {
@ -478,20 +486,27 @@ public:
return index; return index;
} }
m_has_deleted_elements = false;
return emplace_back(); return emplace_back();
} }
Index emplace_group_back(std::size_t n) { Index emplace_group_back(std::size_t n) {
// Expand the storage and return the start of the new region // Expand the storage and return the start of the new region
reserve(capacity() + n); m_active_indices.resize(capacity() + n, true);
for (auto it = m_active_indices.end() - n; it < m_active_indices.end(); ++it)
*it = true; for (auto [name, array] : m_properties)
array->resize(capacity());
return Index(capacity() - n); return Index(capacity() - n);
} }
Index emplace_group(std::size_t n) { Index emplace_group(std::size_t n) {
if (!m_has_deleted_elements)
return emplace_group_back(n);
auto search_start = m_active_indices.begin(); auto search_start = m_active_indices.begin();
while (search_start != m_active_indices.end()) { while (search_start != m_active_indices.end()) {
@ -544,6 +559,7 @@ public:
void erase(Index i) { void erase(Index i) {
m_active_indices[i] = false; m_active_indices[i] = false;
m_has_deleted_elements = true;
for (auto [name, array]: m_properties) for (auto [name, array]: m_properties)
array->reset(i); array->reset(i);
} }
@ -606,7 +622,7 @@ public:
if (it != range.second) if (it != range.second)
array->append(*it->second.get()); array->append(*it->second.get());
else else
array->reserve(m_active_indices.size()); array->resize(m_active_indices.size());
} }
} }

View File

@ -41,11 +41,6 @@ void test_element_access() {
auto& integers = properties.add_property("integers", 5); auto& integers = properties.add_property("integers", 5);
// Reserve space for 100 elements
properties.reserve(100);
assert(properties.capacity() == 100);
assert(properties.size() == 0);
// Newly emplaced elements should go at the front // Newly emplaced elements should go at the front
assert(properties.emplace() == 0); assert(properties.emplace() == 0);
assert(properties.emplace() == 1); assert(properties.emplace() == 1);
@ -61,7 +56,6 @@ void test_element_access() {
auto& floats = properties.add_property("floats", 6.0f); auto& floats = properties.add_property("floats", 6.0f);
// The new property array should already be of the right size // The new property array should already be of the right size
assert(floats.capacity() == 100);
assert(properties.size() == 3); assert(properties.size() == 3);
// Pre-existing elements should contain the default value // Pre-existing elements should contain the default value
@ -87,9 +81,8 @@ void test_element_access() {
// Erase an element, and the size should be reduced // Erase an element, and the size should be reduced
properties.erase(1); properties.erase(1);
assert(properties.size() == 2); assert(properties.size() == 2);
assert(properties.capacity() == 100);
assert(properties.active_list().size() == 2); assert(properties.active_list().size() == 2);
assert(properties.inactive_list().size() == 98); assert(properties.inactive_list().size() == 1);
// A newly emplaced element should take the empty slot // A newly emplaced element should take the empty slot
assert(properties.emplace() == 1); assert(properties.emplace() == 1);

View File

@ -26,6 +26,11 @@ namespace SMP = CGAL::Surface_mesh_parameterization;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
#ifdef CGAL_SMP_USE_SUITESPARSE_SOLVERS
std::cout << "Using SuiteSparse" << std::endl;
#else
std::cout << "Using Eigen3" << std::endl;
#endif
const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/head.off"); const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/head.off");
SurfaceMesh sm; SurfaceMesh sm;

View File

@ -34,14 +34,12 @@ if(TARGET CGAL::Eigen3_support)
target_link_libraries(square_border_parameterizer PRIVATE CGAL::Eigen3_support) target_link_libraries(square_border_parameterizer PRIVATE CGAL::Eigen3_support)
create_single_source_cgal_program( "iterative_authalic_parameterizer.cpp" ) create_single_source_cgal_program( "iterative_authalic_parameterizer.cpp" )
target_link_libraries(iterative_authalic_parameterizer PRIVATE CGAL::Eigen3_support) target_link_libraries(iterative_authalic_parameterizer PRIVATE CGAL::Eigen3_support)
if(SuiteSparse_FOUND) if(TARGET SuiteSparse::UMFPACK)
target_link_libraries(ARAP_parameterization PRIVATE ${SuiteSparse_LIBRARIES}) target_link_libraries(ARAP_parameterization PRIVATE SuiteSparse::UMFPACK)
target_link_libraries(orbifold PRIVATE ${SuiteSparse_LIBRARIES}) target_link_libraries(orbifold PRIVATE PRIVATE SuiteSparse::UMFPACK)
if(SuiteSparse_UMFPACK_FOUND OR TARGET SuiteSparse::umfpack)
target_compile_definitions(ARAP_parameterization PRIVATE EIGEN_DONT_ALIGN_STATICALLY CGAL_SMP_USE_SUITESPARSE_SOLVERS) target_compile_definitions(ARAP_parameterization PRIVATE EIGEN_DONT_ALIGN_STATICALLY CGAL_SMP_USE_SUITESPARSE_SOLVERS)
target_compile_definitions(orbifold PRIVATE EIGEN_DONT_ALIGN_STATICALLY CGAL_SMP_USE_SUITESPARSE_SOLVERS) target_compile_definitions(orbifold PRIVATE EIGEN_DONT_ALIGN_STATICALLY CGAL_SMP_USE_SUITESPARSE_SOLVERS)
endif() endif()
endif()
else() else()
message("NOTICE: The examples require Eigen 3.1 (or greater), and will not be compiled.") message("NOTICE: The examples require Eigen 3.1 (or greater), and will not be compiled.")

View File

@ -6,11 +6,24 @@ project(Surface_mesh_parameterization_Tests)
# Find CGAL # Find CGAL
find_package(CGAL REQUIRED) find_package(CGAL REQUIRED)
find_package(UMFPACK QUIET NO_MODULE)
if(TARGET SuiteSparse::UMFPACK)
message(STATUS "Orbifold Tutte Embeddings will use UmfPackLU")
else()
message(STATUS "NOTICE: Examples will be compiled without the SuiteSparse library and UmfPack. Try setting CMAKE_PREFIX_PATH to your SuiteSparse installation.")
endif()
find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater) find_package(Eigen3 3.1.0 QUIET) #(requires 3.1.0 or greater)
include(CGAL_Eigen3_support) include(CGAL_Eigen3_support)
if(TARGET CGAL::Eigen3_support) if(TARGET CGAL::Eigen3_support)
create_single_source_cgal_program("extensive_parameterization_test.cpp") create_single_source_cgal_program("extensive_parameterization_test.cpp")
target_link_libraries(extensive_parameterization_test PRIVATE CGAL::Eigen3_support) target_link_libraries(extensive_parameterization_test PRIVATE CGAL::Eigen3_support)
if(TARGET SuiteSparse::UMFPACK)
target_link_libraries(extensive_parameterization_test PRIVATE SuiteSparse::UMFPACK)
target_compile_definitions(extensive_parameterization_test PRIVATE EIGEN_DONT_ALIGN_STATICALLY CGAL_SMP_USE_SUITESPARSE_SOLVERS)
endif()
else() else()
message("NOTICE: The tests require Eigen 3.1 (or greater), and will not be compiled.") message("NOTICE: The tests require Eigen 3.1 (or greater), and will not be compiled.")
endif() endif()

View File

@ -78,6 +78,11 @@ typedef boost::graph_traits<SM_Seam_mesh>::halfedge_descriptor SM_SE_halfedge
int main(int, char**) int main(int, char**)
{ {
#ifdef CGAL_SMP_USE_SUITESPARSE_SOLVERS
std::cout << "Using SuiteSparse" << std::endl;
#else
std::cout << "Using Eigen3" << std::endl;
#endif
std::cout.precision(17); std::cout.precision(17);
CGAL::IO::set_pretty_mode(std::cout); CGAL::IO::set_pretty_mode(std::cout);

View File

@ -75,7 +75,7 @@ circumcenter is not supposed to be computed
by the constructor `Construct_weighted_circumcenter_3` of the traits by the constructor `Construct_weighted_circumcenter_3` of the traits
class, hence the returned point has no weight. class, hence the returned point has no weight.
*/ */
const Point_3& weighted_circumcenter(const Traits& gt = Traits()) const; Point_3 weighted_circumcenter(const Traits& gt = Traits()) const;
/// @} /// @}

View File

@ -665,6 +665,9 @@ public:
{ {
CGAL_precondition(dimension() >= 2); CGAL_precondition(dimension() >= 2);
if(the_facet_is_in_its_cz)
*the_facet_is_in_its_cz = false;
std::vector<Cell_handle> cells; std::vector<Cell_handle> cells;
cells.reserve(32); cells.reserve(32);
std::vector<Facet> facets; std::vector<Facet> facets;