From 2af0830937042b502a22838bdadf4135d35127fa Mon Sep 17 00:00:00 2001 From: Arnaud Botella Date: Fri, 26 Jun 2026 10:21:01 +0200 Subject: [PATCH 1/4] fix(Raytracing): better handle edge cases --- src/geode/mesh/helpers/ray_tracing.cpp | 34 ++++++++++++++------------ 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/geode/mesh/helpers/ray_tracing.cpp b/src/geode/mesh/helpers/ray_tracing.cpp index cdd73a3ec..73da49c22 100644 --- a/src/geode/mesh/helpers/ray_tracing.cpp +++ b/src/geode/mesh/helpers/ray_tracing.cpp @@ -330,7 +330,6 @@ namespace geode { distance *= -1.; } - std::lock_guard< std::mutex > lock{ mutex_ }; results_.emplace_back( edge_id, distance, result.second, std::move( intersection_result ) ); } @@ -359,7 +358,6 @@ namespace geode OwnerSegment2D segment_; mutable std::vector< EdgeDistance > results_; mutable bool are_results_sorted_{ false }; - std::mutex mutex_; }; RayTracing2D::RayTracing2D( @@ -521,14 +519,13 @@ namespace geode { distance *= -1.; } - std::lock_guard< std::mutex > lock{ mutex_ }; results_.emplace_back( polygon_id, distance, result.second, std::move( intersection_result ) ); break; } for( const auto e2 : LRange{ 3 } ) { - auto [ray_edge_distance, point, _] = + auto [ray_edge_distance, ray_point, _] = segment_segment_distance( Segment3D{ segment_ }, { triangle.vertices()[e2].get(), triangle.vertices()[( e2 + 1 ) % 3].get() } ); @@ -536,23 +533,29 @@ namespace geode { continue; } - if( Vector3D{ origin_, point }.dot( segment_.direction() ) - < 0 ) + const Vector3D origin_target{ origin_, ray_point }; + auto distance = origin_target.length(); + if( origin_target.dot( segment_.direction() ) < 0 ) { - ray_edge_distance *= -1.; + distance *= -1.; } - std::lock_guard< std::mutex > lock{ mutex_ }; - results_.emplace_back( polygon_id, ray_edge_distance, - result.second, std::move( point ) ); + results_.emplace_back( + polygon_id, distance, result.second, ray_point ); } - const auto [distance, __, triangle_point] = + const auto [triangle_distance, ray_point, _] = segment_triangle_distance( segment_, triangle ); - if( distance < GLOBAL_EPSILON ) + if( triangle_distance > GLOBAL_EPSILON ) { - std::lock_guard< std::mutex > lock{ mutex_ }; - results_.emplace_back( - polygon_id, distance, result.second, triangle_point ); + continue; + } + const Vector3D origin_target{ origin_, ray_point }; + auto distance = origin_target.length(); + if( origin_target.dot( segment_.direction() ) < 0 ) + { + distance *= -1.; } + results_.emplace_back( + polygon_id, distance, result.second, ray_point ); break; } return false; @@ -581,7 +584,6 @@ namespace geode OwnerSegment3D segment_; mutable std::vector< PolygonDistance > results_; mutable bool are_results_sorted_{ false }; - std::mutex mutex_; }; RayTracing3D::RayTracing3D( From 3ddf8b6b664f5934425b4cd7c73b6f2147c3c43d Mon Sep 17 00:00:00 2001 From: Arnaud Botella Date: Fri, 26 Jun 2026 10:55:22 +0200 Subject: [PATCH 2/4] fix test --- tests/mesh/test-ray-tracing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mesh/test-ray-tracing.cpp b/tests/mesh/test-ray-tracing.cpp index ba551bac3..2c02b872e 100644 --- a/tests/mesh/test-ray-tracing.cpp +++ b/tests/mesh/test-ray-tracing.cpp @@ -115,7 +115,7 @@ void test_ray_parallel() geode::OpenGeodeMeshException::test( result->polygon == 0, "Ray edge wrong polygon" ); geode::OpenGeodeMeshException::test( - result->distance == 0, "Ray edge wrong distance" ); + result->distance == 1, "Ray edge wrong distance" ); } void test() From 3e0f26f048204ba5e8e066753c8ef697e8037498 Mon Sep 17 00:00:00 2001 From: Arnaud Botella Date: Fri, 26 Jun 2026 10:59:19 +0200 Subject: [PATCH 3/4] tidy --- include/geode/mesh/helpers/ray_tracing.hpp | 4 +-- src/geode/mesh/helpers/ray_tracing.cpp | 42 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/geode/mesh/helpers/ray_tracing.hpp b/include/geode/mesh/helpers/ray_tracing.hpp index d8ccf6a01..e157249cc 100644 --- a/include/geode/mesh/helpers/ray_tracing.hpp +++ b/include/geode/mesh/helpers/ray_tracing.hpp @@ -84,7 +84,7 @@ namespace geode const InfiniteLine2D& infinite_line ); RayTracing2D( const EdgedCurve2D& mesh, const Point2D& origin, - const OwnerSegment2D& segment ); + OwnerSegment2D segment ); RayTracing2D( RayTracing2D&& other ) noexcept; ~RayTracing2D(); @@ -139,7 +139,7 @@ namespace geode const InfiniteLine3D& infinite_line ); RayTracing3D( const SurfaceMesh3D& mesh, const Point3D& origin, - const OwnerSegment3D& segment ); + OwnerSegment3D segment ); RayTracing3D( RayTracing3D&& other ) noexcept; ~RayTracing3D(); diff --git a/src/geode/mesh/helpers/ray_tracing.cpp b/src/geode/mesh/helpers/ray_tracing.cpp index 73da49c22..2fc017ebc 100644 --- a/src/geode/mesh/helpers/ray_tracing.cpp +++ b/src/geode/mesh/helpers/ray_tracing.cpp @@ -46,7 +46,7 @@ namespace auto bbox_with_line = bbox; bbox_with_line.add_point( line.origin() ); const auto diagonal = bbox_with_line.diagonal(); - return line.origin() - line.direction() * diagonal.length(); + return line.origin() - ( line.direction() * diagonal.length() ); } template < geode::index_t dimension, typename Line > @@ -56,7 +56,7 @@ namespace auto bbox_with_line = bbox; bbox_with_line.add_point( line.origin() ); const auto diagonal = bbox_with_line.diagonal(); - return line.origin() + line.direction() * diagonal.length(); + return line.origin() + ( line.direction() * diagonal.length() ); } bool test_vertex_mode( const geode::EdgedCurve2D& mesh, @@ -258,8 +258,8 @@ namespace geode Impl( const EdgedCurve2D& mesh, const Point2D& origin, - const OwnerSegment2D& segment ) - : mesh_( mesh ), origin_( origin ), segment_{ segment } + OwnerSegment2D segment ) + : mesh_( mesh ), origin_( origin ), segment_{ std::move( segment ) } { } @@ -330,8 +330,8 @@ namespace geode { distance *= -1.; } - results_.emplace_back( edge_id, distance, result.second, - std::move( intersection_result ) ); + results_.emplace_back( + edge_id, distance, result.second, intersection_result ); } return false; } @@ -375,8 +375,8 @@ namespace geode RayTracing2D::RayTracing2D( const EdgedCurve2D& mesh, const Point2D& origin, - const OwnerSegment2D& segment ) - : impl_{ mesh, origin, segment } + OwnerSegment2D segment ) + : impl_{ mesh, origin, std::move( segment ) } { } @@ -446,8 +446,8 @@ namespace geode Impl( const SurfaceMesh3D& mesh, const Point3D& origin, - const OwnerSegment3D& segment ) - : mesh_( mesh ), origin_( origin ), segment_{ segment } + OwnerSegment3D segment ) + : mesh_( mesh ), origin_( origin ), segment_{ std::move( segment ) } { } @@ -491,14 +491,14 @@ namespace geode bool compute( index_t polygon_id ) { - const auto& p0 = + const auto& point0 = mesh_.point( mesh_.polygon_vertex( { polygon_id, 0 } ) ); - for( const auto e : + for( const auto edge : LRange{ 1, mesh_.nb_polygon_edges( polygon_id ) - 1 } ) { const auto edge_vertices = - mesh_.polygon_edge_vertices( { polygon_id, e } ); - const Triangle3D triangle{ p0, + mesh_.polygon_edge_vertices( { polygon_id, edge } ); + const Triangle3D triangle{ point0, mesh_.point( edge_vertices.front() ), mesh_.point( edge_vertices.back() ) }; const auto result = segment_triangle_intersection_detection( @@ -523,12 +523,12 @@ namespace geode std::move( intersection_result ) ); break; } - for( const auto e2 : LRange{ 3 } ) + for( const auto edge2 : LRange{ 3 } ) { - auto [ray_edge_distance, ray_point, _] = - segment_segment_distance( Segment3D{ segment_ }, - { triangle.vertices()[e2].get(), - triangle.vertices()[( e2 + 1 ) % 3].get() } ); + auto [ray_edge_distance, ray_point, + _] = segment_segment_distance( Segment3D{ segment_ }, + { triangle.vertices()[edge2].get(), + triangle.vertices()[( edge2 + 1 ) % 3].get() } ); if( ray_edge_distance > GLOBAL_EPSILON ) { continue; @@ -601,8 +601,8 @@ namespace geode RayTracing3D::RayTracing3D( const SurfaceMesh3D& mesh, const Point3D& origin, - const OwnerSegment3D& segment ) - : impl_{ mesh, origin, segment } + OwnerSegment3D segment ) + : impl_{ mesh, origin, std::move( segment ) } { } From 713115cd5d5239da129d3dcbaa0db21369939f34 Mon Sep 17 00:00:00 2001 From: Arnaud Botella Date: Fri, 26 Jun 2026 12:11:37 +0200 Subject: [PATCH 4/4] tidy2 --- include/geode/mesh/helpers/ray_tracing.hpp | 10 +- src/geode/mesh/helpers/ray_tracing.cpp | 6 +- tests/mesh/test-ray-tracing.cpp | 173 +++++++++++---------- 3 files changed, 101 insertions(+), 88 deletions(-) diff --git a/include/geode/mesh/helpers/ray_tracing.hpp b/include/geode/mesh/helpers/ray_tracing.hpp index e157249cc..9ee7fdbf1 100644 --- a/include/geode/mesh/helpers/ray_tracing.hpp +++ b/include/geode/mesh/helpers/ray_tracing.hpp @@ -48,6 +48,8 @@ namespace geode { class opengeode_mesh_api RayTracing2D { + OPENGEODE_DISABLE_COPY( RayTracing2D ); + public: struct EdgeDistance { @@ -60,7 +62,7 @@ namespace geode : edge{ edge_in }, distance{ distance_in }, position{ position_in }, - point{ std::move( point_in ) } + point{ point_in } { } @@ -86,6 +88,7 @@ namespace geode const Point2D& origin, OwnerSegment2D segment ); RayTracing2D( RayTracing2D&& other ) noexcept; + RayTracing2D& operator=( RayTracing2D&& other ) noexcept; ~RayTracing2D(); [[nodiscard]] std::optional< EdgeDistance > closest_edge() const; @@ -103,6 +106,8 @@ namespace geode class opengeode_mesh_api RayTracing3D { + OPENGEODE_DISABLE_COPY( RayTracing3D ); + public: struct PolygonDistance { @@ -115,7 +120,7 @@ namespace geode : polygon{ polygon_in }, distance{ distance_in }, position{ position_in }, - point{ std::move( point_in ) } + point{ point_in } { } @@ -141,6 +146,7 @@ namespace geode const Point3D& origin, OwnerSegment3D segment ); RayTracing3D( RayTracing3D&& other ) noexcept; + RayTracing3D& operator=( RayTracing3D&& other ) noexcept; ~RayTracing3D(); [[nodiscard]] std::optional< PolygonDistance > closest_polygon() const; diff --git a/src/geode/mesh/helpers/ray_tracing.cpp b/src/geode/mesh/helpers/ray_tracing.cpp index 2fc017ebc..94231ed49 100644 --- a/src/geode/mesh/helpers/ray_tracing.cpp +++ b/src/geode/mesh/helpers/ray_tracing.cpp @@ -382,6 +382,8 @@ namespace geode RayTracing2D::RayTracing2D( RayTracing2D&& ) noexcept = default; + RayTracing2D& RayTracing2D::operator=( RayTracing2D&& ) noexcept = default; + RayTracing2D::~RayTracing2D() = default; std::optional< RayTracing2D::EdgeDistance > @@ -520,7 +522,7 @@ namespace geode distance *= -1.; } results_.emplace_back( polygon_id, distance, result.second, - std::move( intersection_result ) ); + intersection_result ); break; } for( const auto edge2 : LRange{ 3 } ) @@ -608,6 +610,8 @@ namespace geode RayTracing3D::RayTracing3D( RayTracing3D&& ) noexcept = default; + RayTracing3D& RayTracing3D::operator=( RayTracing3D&& ) noexcept = default; + RayTracing3D::~RayTracing3D() = default; std::optional< RayTracing3D::PolygonDistance > diff --git a/tests/mesh/test-ray-tracing.cpp b/tests/mesh/test-ray-tracing.cpp index 2c02b872e..f2b788566 100644 --- a/tests/mesh/test-ray-tracing.cpp +++ b/tests/mesh/test-ray-tracing.cpp @@ -34,96 +34,99 @@ #include -void test_ray_inside() +namespace { - geode::Logger::info( "Test ray inside" ); - auto mesh = geode::SurfaceMesh3D::create(); - auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); - builder->create_point( geode::Point3D{ { -1, -1, 1 } } ); - builder->create_point( geode::Point3D{ { 1, -1, 1 } } ); - builder->create_point( geode::Point3D{ { 0, 1, 1 } } ); - builder->create_point( geode::Point3D{ { -1, -1, 2 } } ); - builder->create_point( geode::Point3D{ { 1, -1, 2 } } ); - builder->create_point( geode::Point3D{ { 0, 1, 2 } } ); - builder->create_polygon( { 0, 1, 2 } ); - builder->create_polygon( { 3, 4, 5 } ); + void test_ray_inside() + { + geode::Logger::info( "Test ray inside" ); + auto mesh = geode::SurfaceMesh3D::create(); + auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); + builder->create_point( geode::Point3D{ { -1, -1, 1 } } ); + builder->create_point( geode::Point3D{ { 1, -1, 1 } } ); + builder->create_point( geode::Point3D{ { 0, 1, 1 } } ); + builder->create_point( geode::Point3D{ { -1, -1, 2 } } ); + builder->create_point( geode::Point3D{ { 1, -1, 2 } } ); + builder->create_point( geode::Point3D{ { 0, 1, 2 } } ); + builder->create_polygon( { 0, 1, 2 } ); + builder->create_polygon( { 3, 4, 5 } ); - const auto aabb = geode::create_aabb_tree( *mesh ); - const geode::Vector3D direction{ { 0, 0, 1 } }; - const geode::Point3D origin{ { 0, 0, 0 } }; - const geode::Ray3D ray{ direction, origin }; - geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; - aabb.compute_ray_element_bbox_intersections( ray, tracing ); - const auto result = tracing.closest_polygon(); - geode::OpenGeodeMeshException::test( - result.has_value(), "Ray inside no result" ); - geode::OpenGeodeMeshException::test( - result->polygon == 0, "Ray inside wrong polygon" ); - geode::OpenGeodeMeshException::test( - result->distance == 1, "Ray inside wrong distance" ); -} + const auto aabb = geode::create_aabb_tree( *mesh ); + const geode::Vector3D direction{ { 0, 0, 1 } }; + const geode::Point3D origin{ { 0, 0, 0 } }; + const geode::Ray3D ray{ direction, origin }; + geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; + aabb.compute_ray_element_bbox_intersections( ray, tracing ); + const auto result = tracing.closest_polygon(); + geode::OpenGeodeMeshException::test( + result.has_value(), "Ray inside no result" ); + geode::OpenGeodeMeshException::test( + result->polygon == 0, "Ray inside wrong polygon" ); + geode::OpenGeodeMeshException::test( + result->distance == 1, "Ray inside wrong distance" ); + } -void test_ray_edge() -{ - geode::Logger::info( "Test ray edge" ); - auto mesh = geode::SurfaceMesh3D::create(); - auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); - builder->create_point( geode::Point3D{ { 1, -1, 0 } } ); - builder->create_point( geode::Point3D{ { 1, 1, 0 } } ); - builder->create_point( geode::Point3D{ { 1, 0, -1 } } ); - builder->create_point( geode::Point3D{ { 1, 0, 3 } } ); - builder->create_polygon( { 0, 1, 2 } ); - builder->create_polygon( { 1, 0, 3 } ); - builder->compute_polygon_adjacencies(); + void test_ray_edge() + { + geode::Logger::info( "Test ray edge" ); + auto mesh = geode::SurfaceMesh3D::create(); + auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); + builder->create_point( geode::Point3D{ { 1, -1, 0 } } ); + builder->create_point( geode::Point3D{ { 1, 1, 0 } } ); + builder->create_point( geode::Point3D{ { 1, 0, -1 } } ); + builder->create_point( geode::Point3D{ { 1, 0, 3 } } ); + builder->create_polygon( { 0, 1, 2 } ); + builder->create_polygon( { 1, 0, 3 } ); + builder->compute_polygon_adjacencies(); - const auto aabb = geode::create_aabb_tree( *mesh ); - const geode::Vector3D direction{ { 1, 0, 0 } }; - const geode::Point3D origin{ { 0, 0, 1 } }; - const geode::Ray3D ray{ direction, origin }; - geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; - aabb.compute_ray_element_bbox_intersections( ray, tracing ); - const auto result = tracing.closest_polygon(); - geode::OpenGeodeMeshException::test( - result.has_value(), "Ray edge no result" ); - geode::OpenGeodeMeshException::test( - result->polygon == 1, "Ray edge wrong polygon" ); - geode::OpenGeodeMeshException::test( - result->distance == 1, "Ray edge wrong distance" ); - geode::OpenGeodeMeshException::test( - tracing.all_intersections().size() == 1, - "Wrong size for ray tracing result for case edge" ); -} + const auto aabb = geode::create_aabb_tree( *mesh ); + const geode::Vector3D direction{ { 1, 0, 0 } }; + const geode::Point3D origin{ { 0, 0, 1 } }; + const geode::Ray3D ray{ direction, origin }; + geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; + aabb.compute_ray_element_bbox_intersections( ray, tracing ); + const auto result = tracing.closest_polygon(); + geode::OpenGeodeMeshException::test( + result.has_value(), "Ray edge no result" ); + geode::OpenGeodeMeshException::test( + result->polygon == 1, "Ray edge wrong polygon" ); + geode::OpenGeodeMeshException::test( + result->distance == 1, "Ray edge wrong distance" ); + geode::OpenGeodeMeshException::test( + tracing.all_intersections().size() == 1, + "Wrong size for ray tracing result for case edge" ); + } -void test_ray_parallel() -{ - geode::Logger::info( "Test ray parallel" ); - auto mesh = geode::SurfaceMesh3D::create(); - auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); - builder->create_point( geode::Point3D{ { -1, -1, 0 } } ); - builder->create_point( geode::Point3D{ { -1, 1, 0 } } ); - builder->create_point( geode::Point3D{ { -2, 0, 0 } } ); - builder->create_polygon( { 0, 1, 2 } ); - const auto aabb = geode::create_aabb_tree( *mesh ); - const geode::Vector3D direction{ { -1, 0, 0 } }; - const geode::Point3D origin{ { 0, 0, 0 } }; - const geode::Ray3D ray{ direction, origin }; - geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; - aabb.compute_ray_element_bbox_intersections( ray, tracing ); - const auto result = tracing.closest_polygon(); - geode::OpenGeodeMeshException::test( - result.has_value(), "Ray edge no result" ); - geode::OpenGeodeMeshException::test( - result->polygon == 0, "Ray edge wrong polygon" ); - geode::OpenGeodeMeshException::test( - result->distance == 1, "Ray edge wrong distance" ); -} + void test_ray_parallel() + { + geode::Logger::info( "Test ray parallel" ); + auto mesh = geode::SurfaceMesh3D::create(); + auto builder = geode::SurfaceMeshBuilder3D::create( *mesh ); + builder->create_point( geode::Point3D{ { -1, -1, 0 } } ); + builder->create_point( geode::Point3D{ { -1, 1, 0 } } ); + builder->create_point( geode::Point3D{ { -2, 0, 0 } } ); + builder->create_polygon( { 0, 1, 2 } ); + const auto aabb = geode::create_aabb_tree( *mesh ); + const geode::Vector3D direction{ { -1, 0, 0 } }; + const geode::Point3D origin{ { 0, 0, 0 } }; + const geode::Ray3D ray{ direction, origin }; + geode::RayTracing3D tracing{ *mesh, aabb.bounding_box(), ray }; + aabb.compute_ray_element_bbox_intersections( ray, tracing ); + const auto result = tracing.closest_polygon(); + geode::OpenGeodeMeshException::test( + result.has_value(), "Ray edge no result" ); + geode::OpenGeodeMeshException::test( + result->polygon == 0, "Ray edge wrong polygon" ); + geode::OpenGeodeMeshException::test( + result->distance == 1, "Ray edge wrong distance" ); + } -void test() -{ - geode::OpenGeodeMeshLibrary::initialize(); - test_ray_inside(); - test_ray_edge(); - test_ray_parallel(); -} + void test() + { + geode::OpenGeodeMeshLibrary::initialize(); + test_ray_inside(); + test_ray_edge(); + test_ray_parallel(); + } +} // namespace OPENGEODE_TEST( "ray-tracing" ) \ No newline at end of file