From b52eefe3a1374bb1c42a3dd22d30cf6413d1546d Mon Sep 17 00:00:00 2001 From: Pierre Anquez Date: Sat, 5 Apr 2025 07:04:36 +0200 Subject: [PATCH 1/3] fix(Exception): add OpenGeodeResultException --- include/geode/basic/assert.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/geode/basic/assert.hpp b/include/geode/basic/assert.hpp index 4e8cb422e..ed54728c2 100644 --- a/include/geode/basic/assert.hpp +++ b/include/geode/basic/assert.hpp @@ -98,6 +98,12 @@ namespace geode using OpenGeodeException::OpenGeodeException; }; + class OpenGeodeResultException : public OpenGeodeException + { + public: + using OpenGeodeException::OpenGeodeException; + }; + void opengeode_basic_api geode_assertion_failed( std::string_view condition, std::string_view message, std::string_view file, @@ -144,5 +150,12 @@ namespace geode __VA_ARGS__ \ } +#define OPENGEODE_RESULT_EXCEPTION( condition, ... ) \ + if( ABSL_PREDICT_FALSE( !( condition ) ) ) \ + throw geode::OpenGeodeResultException \ + { \ + __VA_ARGS__ \ + } + #define OPENGEODE_RESEARCH( condition, ... ) \ OPENGEODE_EXCEPTION( condition, __VA_ARGS__ ) From d802e66a1a288ccc809310c6c51cedcb0af2644f Mon Sep 17 00:00:00 2001 From: Pierre Anquez Date: Sat, 5 Apr 2025 07:13:24 +0200 Subject: [PATCH 2/3] more --- src/geode/basic/assert.cpp | 5 +++++ src/geode/geometry/basic_objects/segment.cpp | 7 ++----- tests/basic/test-assert.cpp | 9 +++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/geode/basic/assert.cpp b/src/geode/basic/assert.cpp index ddb538343..b2642d002 100644 --- a/src/geode/basic/assert.cpp +++ b/src/geode/basic/assert.cpp @@ -51,6 +51,11 @@ namespace geode Logger::critical( "OpenGeodeDataException: ", exception.what(), "\n", exception.stack_trace() ); } + catch( const OpenGeodeResultException& exception ) + { + Logger::critical( "OpenGeodeResultException: ", exception.what(), + "\n", exception.stack_trace() ); + } catch( const OpenGeodeException& exception ) { Logger::critical( "OpenGeodeException: ", exception.what(), "\n", diff --git a/src/geode/geometry/basic_objects/segment.cpp b/src/geode/geometry/basic_objects/segment.cpp index 0ad156505..46b49bde7 100644 --- a/src/geode/geometry/basic_objects/segment.cpp +++ b/src/geode/geometry/basic_objects/segment.cpp @@ -55,12 +55,9 @@ namespace geode GenericSegment< PointType, dimension >::direction() const { Vector< dimension > direction{ vertices_[0], vertices_[1] }; - if( direction.length() < GLOBAL_EPSILON ) - { - DEBUG( direction.length() ); - } OPENGEODE_EXCEPTION( direction.length() > GLOBAL_EPSILON, - "[Segment::direction] Segment length too small" ); + "[Segment::direction] Segment length too small (", + direction.length(), ")" ); return direction; } template < typename PointType, index_t dimension > diff --git a/tests/basic/test-assert.cpp b/tests/basic/test-assert.cpp index 16d59d0d5..eb7b68059 100644 --- a/tests/basic/test-assert.cpp +++ b/tests/basic/test-assert.cpp @@ -185,6 +185,15 @@ void test_exception() { geode::geode_lippincott(); } + + try + { + throw geode::OpenGeodeResultException{ "Bad ", "result" }; + } + catch( ... ) + { + geode::geode_lippincott(); + } } void test() From 51f8eaf4bb4789b5ecdaec555e6a04dba7045b9d Mon Sep 17 00:00:00 2001 From: Pierre Anquez Date: Fri, 11 Apr 2025 17:16:52 +0200 Subject: [PATCH 3/3] fix(Model): add API function to fix model surface non-manifold vertices --- .../detail/surface_mesh_validity_fix.hpp | 41 +++++++ .../io/geode/geode_section_input.hpp | 2 + src/geode/model/CMakeLists.txt | 2 + .../detail/surface_mesh_validity_fix.cpp | 115 ++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 include/geode/model/helpers/detail/surface_mesh_validity_fix.hpp create mode 100644 src/geode/model/helpers/detail/surface_mesh_validity_fix.cpp diff --git a/include/geode/model/helpers/detail/surface_mesh_validity_fix.hpp b/include/geode/model/helpers/detail/surface_mesh_validity_fix.hpp new file mode 100644 index 000000000..ce8b5e5e0 --- /dev/null +++ b/include/geode/model/helpers/detail/surface_mesh_validity_fix.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 - 2025 Geode-solutions + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#pragma once + +#include + +namespace geode +{ + FORWARD_DECLARATION_DIMENSION_CLASS( Surface ); +} // namespace geode + +namespace geode +{ + namespace detail + { + template < typename Model > + void repair_non_manifold_vertices( + Model& model, const Surface< Model::dim >& surface ); + } // namespace detail +} // namespace geode \ No newline at end of file diff --git a/include/geode/model/representation/io/geode/geode_section_input.hpp b/include/geode/model/representation/io/geode/geode_section_input.hpp index f72bb61e0..777e33e90 100644 --- a/include/geode/model/representation/io/geode/geode_section_input.hpp +++ b/include/geode/model/representation/io/geode/geode_section_input.hpp @@ -23,6 +23,8 @@ #pragma once +#include + #include #include #include diff --git a/src/geode/model/CMakeLists.txt b/src/geode/model/CMakeLists.txt index 6feb0cddf..f4dbb1892 100644 --- a/src/geode/model/CMakeLists.txt +++ b/src/geode/model/CMakeLists.txt @@ -44,6 +44,7 @@ add_geode_library( "helpers/detail/mappings_merger.cpp" "helpers/detail/split_along_surface_mesh_borders.cpp" "helpers/detail/split_along_block_mesh_borders.cpp" + "helpers/detail/surface_mesh_validity_fix.cpp" "mixin/builder/blocks_builder.cpp" "mixin/builder/block_collections_builder.cpp" "mixin/builder/component_registry_builder.cpp" @@ -172,6 +173,7 @@ add_geode_library( "helpers/detail/mappings_merger.hpp" "helpers/detail/split_along_surface_mesh_borders.hpp" "helpers/detail/split_along_block_mesh_borders.hpp" + "helpers/detail/surface_mesh_validity_fix.hpp" "mixin/core/detail/components_storage.hpp" "mixin/core/detail/count_relationships.hpp" "mixin/core/detail/mesh_storage.hpp" diff --git a/src/geode/model/helpers/detail/surface_mesh_validity_fix.cpp b/src/geode/model/helpers/detail/surface_mesh_validity_fix.cpp new file mode 100644 index 000000000..e3ba96cc6 --- /dev/null +++ b/src/geode/model/helpers/detail/surface_mesh_validity_fix.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019 - 2025 Geode-solutions + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include + +namespace geode +{ + namespace detail + { + template < typename Model > + void repair_non_manifold_vertices( + Model& model, const Surface< Model::dim >& surface ) + { + const auto& mesh = surface.mesh(); + typename Model::Builder model_builder{ model }; + auto mesh_builder = + model_builder.surface_mesh_builder( surface.id() ); + absl::FixedArray< PolygonsAroundVertex > polygons_around_vertices( + mesh.nb_vertices() ); + for( const auto p : Range{ mesh.nb_polygons() } ) + { + for( const auto v : LRange{ mesh.nb_polygon_vertices( p ) } ) + { + polygons_around_vertices[mesh.polygon_vertex( { p, v } )] + .emplace_back( p, v ); + } + } + absl::flat_hash_map< index_t, std::vector< index_t > > mappings; + for( const auto v : Range{ mesh.nb_vertices() } ) + { + auto polygons_around = mesh.polygons_around_vertex( v ); + const auto& polygon_vertices = polygons_around_vertices[v]; + auto nb_polygons_around = polygons_around.size(); + if( nb_polygons_around == polygon_vertices.size() ) + { + continue; + } + std::vector< index_t > new_values; + PolygonsAroundVertex total_polygons; + while( nb_polygons_around != polygon_vertices.size() ) + { + for( auto&& polygon : polygons_around ) + { + total_polygons.emplace_back( std::move( polygon ) ); + } + const auto new_vertex_id = + mesh_builder->create_point( mesh.point( v ) ); + mesh_builder->replace_vertex( v, new_vertex_id ); + for( const auto& polygon_vertex : polygon_vertices ) + { + if( absl::c_find( total_polygons, polygon_vertex ) + == total_polygons.end() ) + { + mesh_builder->associate_polygon_vertex_to_vertex( + polygon_vertex, v ); + break; + } + } + new_values.push_back( new_vertex_id ); + polygons_around = mesh.polygons_around_vertex( v ); + nb_polygons_around += polygons_around.size(); + } + mappings.try_emplace( v, std::move( new_values ) ); + } + for( const auto& [old_vertex, new_vertices] : mappings ) + { + const auto unique_vertex = model.unique_vertex( + { surface.component_id(), old_vertex } ); + for( const auto new_vertex : new_vertices ) + { + model_builder.set_unique_vertex( + { surface.component_id(), new_vertex }, unique_vertex ); + } + } + } + + template void opengeode_model_api + repair_non_manifold_vertices< Section >( + Section&, const Surface2D& ); + template void opengeode_model_api repair_non_manifold_vertices< BRep >( + BRep&, const Surface3D& ); + } // namespace detail +} // namespace geode \ No newline at end of file