From a11d7353e41627dc49eb95b649e9eb1977bd0e14 Mon Sep 17 00:00:00 2001 From: Pierre Anquez Date: Sat, 26 Sep 2026 14:55:58 +0200 Subject: [PATCH 1/2] perf(Intersections): use the parallel AABB self intersections Surface and model self-intersection checks give the AABB a const test and use the returned pairs. The has-intersection checks no longer stop at the first hit: the full search now runs in parallel. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../intersections/model_intersections.cpp | 98 +++++++++++++------ .../intersections/surface_intersections.cpp | 62 ++++-------- 2 files changed, 83 insertions(+), 77 deletions(-) diff --git a/src/geode/inspector/inspection/criterion/intersections/model_intersections.cpp b/src/geode/inspector/inspection/criterion/intersections/model_intersections.cpp index 86f32e36..782b9b59 100644 --- a/src/geode/inspector/inspection/criterion/intersections/model_intersections.cpp +++ b/src/geode/inspector/inspection/criterion/intersections/model_intersections.cpp @@ -51,15 +51,11 @@ namespace { struct ComponentOverlap { - bool operator()( - geode::index_t first_component, geode::index_t second_component ) + [[nodiscard]] bool operator()( geode::index_t /*first_component*/, + geode::index_t /*second_component*/ ) const { - component_pairs.emplace_back( first_component, second_component ); - return false; + return true; } - - std::vector< std::pair< geode::index_t, geode::index_t > > - component_pairs; }; [[nodiscard]] absl::InlinedVector< geode::PolygonVertices, 1 > @@ -205,6 +201,12 @@ namespace { } + [[nodiscard]] bool self_intersect( + geode::index_t p1_id, geode::index_t p2_id ) const + { + return p1_id != p2_id && polygons_intersect( p1_id, p2_id ); + } + protected: [[nodiscard]] bool polygons_intersect( geode::index_t p1_id, geode::index_t p2_id ) const @@ -609,6 +611,12 @@ namespace return false; } + [[nodiscard]] bool self_intersect( + geode::index_t e1_id, geode::index_t e2_id ) const + { + return e1_id != e2_id && lines_intersect( e1_id, e2_id ); + } + private: bool lines_intersect( geode::index_t p1_id, geode::index_t p2_id ) const { @@ -626,6 +634,25 @@ namespace const geode::EdgedCurve< dimension >& mesh2_; const bool same_line_{ false }; }; + + template < typename Action > + class SelfIntersectionTest + { + public: + explicit SelfIntersectionTest( const Action& action ) + : action_( action ) + { + } + + [[nodiscard]] bool operator()( + geode::index_t element1, geode::index_t element2 ) const + { + return action_.self_intersect( element1, element2 ); + } + + private: + const Action& action_; + }; } // namespace namespace geode @@ -785,17 +812,19 @@ namespace geode for( const auto& surface : model_.active_surfaces() ) { tasks.emplace_back( async::spawn( [this, &surface] { - Action surfaces_intersection_action{ model_, surface.id(), - surface.id() }; - surfaces_model_tree_ - .mesh_trees_[surfaces_model_tree_.mesh_tree_ids_.at( - surface.id() )] - .compute_self_element_bbox_intersections( - surfaces_intersection_action ); + const Action surfaces_intersection_action{ model_, + surface.id(), surface.id() }; + const auto intersecting_elements = + surfaces_model_tree_ + .mesh_trees_[surfaces_model_tree_.mesh_tree_ids_.at( + surface.id() )] + .compute_self_element_bbox_intersections( + SelfIntersectionTest< Action >{ + surfaces_intersection_action } ); IntersectionsResult result; const auto surface_id = surface.component_id(); for( const auto& [polygon1, polygon2] : - surfaces_intersection_action.intersecting_elements() ) + intersecting_elements ) { result.emplace_back( ComponentMeshElement{ surface_id, polygon1 }, @@ -804,10 +833,11 @@ namespace geode return result; } ) ); } - ComponentOverlap surfaces_overlap; - surfaces_model_tree_.components_tree_ - .compute_self_element_bbox_intersections( surfaces_overlap ); - for( const auto& components : surfaces_overlap.component_pairs ) + const auto surfaces_overlap = + surfaces_model_tree_.components_tree_ + .compute_self_element_bbox_intersections( + ComponentOverlap{} ); + for( const auto& components : surfaces_overlap ) { tasks.emplace_back( async::spawn( [this, &components] { const auto surface_uuid1 = @@ -865,17 +895,20 @@ namespace geode for( const auto& line : model_.active_lines() ) { tasks.emplace_back( async::spawn( [this, &line] { - LineLineIntersection lines_intersection_action{ model_, - line.id(), line.id() }; - lines_model_tree_ - .mesh_trees_[lines_model_tree_.mesh_tree_ids_.at( - line.id() )] - .compute_self_element_bbox_intersections( - lines_intersection_action ); + const LineLineIntersection lines_intersection_action{ + model_, line.id(), line.id() + }; + const auto intersecting_elements = + lines_model_tree_ + .mesh_trees_[lines_model_tree_.mesh_tree_ids_.at( + line.id() )] + .compute_self_element_bbox_intersections( + SelfIntersectionTest< + LineLineIntersection< Model > >{ + lines_intersection_action } ); IntersectionsResult result; const auto line_id = line.component_id(); - for( const auto& [edge1, edge2] : - lines_intersection_action.intersecting_elements() ) + for( const auto& [edge1, edge2] : intersecting_elements ) { result.emplace_back( ComponentMeshElement{ line_id, edge1 }, @@ -884,10 +917,11 @@ namespace geode return result; } ) ); } - ComponentOverlap lines_overlap; - lines_model_tree_.components_tree_ - .compute_self_element_bbox_intersections( lines_overlap ); - for( const auto& components : lines_overlap.component_pairs ) + const auto lines_overlap = + lines_model_tree_.components_tree_ + .compute_self_element_bbox_intersections( + ComponentOverlap{} ); + for( const auto& components : lines_overlap ) { tasks.emplace_back( async::spawn( [this, &components] { const auto line_uuid1 = diff --git a/src/geode/inspector/inspection/criterion/intersections/surface_intersections.cpp b/src/geode/inspector/inspection/criterion/intersections/surface_intersections.cpp index 49cba349..d370066c 100644 --- a/src/geode/inspector/inspection/criterion/intersections/surface_intersections.cpp +++ b/src/geode/inspector/inspection/criterion/intersections/surface_intersections.cpp @@ -41,55 +41,28 @@ namespace class PolygonPolygonIntersection { public: - PolygonPolygonIntersection( const geode::SurfaceMesh< dimension >& mesh, - bool stop_at_first_intersection ) - : mesh_( mesh ), - stop_at_first_intersection_{ stop_at_first_intersection } + explicit PolygonPolygonIntersection( + const geode::SurfaceMesh< dimension >& mesh ) + : mesh_( mesh ) { } - std::vector< std::pair< geode::index_t, geode::index_t > > - intersecting_polygons() - { - return std::move( intersecting_polygons_ ); - } - - bool operator()( geode::index_t p1_id, geode::index_t p2_id ) + [[nodiscard]] bool operator()( + geode::index_t p1_id, geode::index_t p2_id ) const { if( p1_id == p2_id ) { return false; } - const auto p1_vertices = this->mesh().polygon_vertices( p1_id ); - const auto p2_vertices = this->mesh().polygon_vertices( p2_id ); - if( geode::detail::polygons_intersection_detection< - geode::SurfaceMesh< dimension > >( - mesh_, p1_vertices, p2_vertices ) ) - { - this->emplace( p1_id, p2_id ); - return stop_at_first_intersection_; - } - return false; - } - - protected: - void emplace( geode::index_t p1_id, geode::index_t p2_id ) - { - std::lock_guard< std::mutex > lock( mutex_ ); - intersecting_polygons_.emplace_back( p1_id, p2_id ); - } - - const geode::SurfaceMesh< dimension >& mesh() const - { - return mesh_; + const auto p1_vertices = mesh_.polygon_vertices( p1_id ); + const auto p2_vertices = mesh_.polygon_vertices( p2_id ); + return geode::detail::polygons_intersection_detection< + geode::SurfaceMesh< dimension > >( + mesh_, p1_vertices, p2_vertices ); } private: const geode::SurfaceMesh< dimension >& mesh_; - bool stop_at_first_intersection_; - std::vector< std::pair< geode::index_t, geode::index_t > > - intersecting_polygons_; - std::mutex mutex_; }; } // namespace @@ -106,7 +79,7 @@ namespace geode bool mesh_has_self_intersections() const { - const auto intersections = intersecting_polygons( true ); + const auto intersections = intersecting_polygons(); if( intersections.empty() ) { return false; @@ -117,7 +90,7 @@ namespace geode InspectionIssues< std::pair< index_t, index_t > > intersecting_elements() const { - const auto intersections = intersecting_polygons( false ); + const auto intersections = intersecting_polygons(); InspectionIssues< std::pair< index_t, index_t > > issues{ "intersections between polygons" }; @@ -132,14 +105,13 @@ namespace geode } private: - std::vector< std::pair< index_t, index_t > > intersecting_polygons( - bool stop_at_first_intersection ) const + std::vector< std::pair< index_t, index_t > > + intersecting_polygons() const { const auto surface_aabb = create_aabb_tree( mesh_ ); - PolygonPolygonIntersection< dimension > action{ mesh_, - stop_at_first_intersection }; - surface_aabb.compute_self_element_bbox_intersections( action ); - return action.intersecting_polygons(); + const PolygonPolygonIntersection< dimension > action{ mesh_ }; + return surface_aabb.compute_self_element_bbox_intersections( + action ); } private: From 23a84b99f93b3ac4d85b56dc4e6c2367af0fecd7 Mon Sep 17 00:00:00 2001 From: panquez <32702237+panquez@users.noreply.github.com> Date: Sat, 26 Sep 2026 12:56:50 +0000 Subject: [PATCH 2/2] Apply prepare changes --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 725ab31e..5dacfaee 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -14,6 +14,7 @@ Checks: > -misc-no-recursion, -misc-include-cleaner, -misc-const-correctness, + -modernize-use-scoped-lock, -modernize-use-trailing-return-type, -portability-avoid-pragma-once, -readability-use-anyofallof,