From 1bc458d5b0dfb4efd97be490addd6522f13386a1 Mon Sep 17 00:00:00 2001 From: BenPinet Date: Mon, 2 Mar 2026 16:59:58 +0100 Subject: [PATCH 1/2] feat(IspointInside): check if a point is inside a polygon --- include/geode/geometry/is_point_inside.hpp | 42 +++++++++++ src/geode/geometry/CMakeLists.txt | 2 + src/geode/geometry/is_point_inside.cpp | 84 ++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 include/geode/geometry/is_point_inside.hpp create mode 100644 src/geode/geometry/is_point_inside.cpp diff --git a/include/geode/geometry/is_point_inside.hpp b/include/geode/geometry/is_point_inside.hpp new file mode 100644 index 000000000..6892b5163 --- /dev/null +++ b/include/geode/geometry/is_point_inside.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 - 2026 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 +#include +#include + +namespace geode +{ + /*! + * Find if point is inside a polygon. + * @param[in] point The point to rotate. + * @param[in] axis Axis for the rotation (not null but not necessary + * normalized). + * @param[in] angle Rotation angle expresses in radians. + */ + [[nodiscard]] bool opengeode_geometry_api is_point_inside_polygon( + const Point2D& point, absl::Span< const Point2D > polygon_points ); + +} // namespace geode \ No newline at end of file diff --git a/src/geode/geometry/CMakeLists.txt b/src/geode/geometry/CMakeLists.txt index 973cc2456..b70775c6e 100644 --- a/src/geode/geometry/CMakeLists.txt +++ b/src/geode/geometry/CMakeLists.txt @@ -47,6 +47,7 @@ add_geode_library( "information.cpp" "intersection.cpp" "intersection_detection.cpp" + "is_point_inside.cpp" "mensuration.cpp" "nn_search.cpp" "normal_frame_transform.cpp" @@ -86,6 +87,7 @@ add_geode_library( "information.hpp" "intersection.hpp" "intersection_detection.hpp" + "is_point_inside.hpp" "mensuration.hpp" "nn_search.hpp" "normal_frame_transform.hpp" diff --git a/src/geode/geometry/is_point_inside.cpp b/src/geode/geometry/is_point_inside.cpp new file mode 100644 index 000000000..929e89eb9 --- /dev/null +++ b/src/geode/geometry/is_point_inside.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 - 2026 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 + +namespace +{ + double is_left( const geode::Point2D& p0, + const geode::Point2D& p1, + const geode::Point2D& p2 ) + { + return ( p1.value( 0 ) - p0.value( 0 ) ) + * ( p2.value( 1 ) - p0.value( 1 ) ) + - ( p2.value( 0 ) - p0.value( 0 ) ) + * ( p1.value( 1 ) - p0.value( 1 ) ); + } +} // namespace + +namespace geode +{ + bool opengeode_geometry_api is_point_inside_polygon( + const Point2D& point, absl::Span< const Point2D > polygon_points ) + { + double widing_number{ 0 }; + DEBUG( "is_point_inside_polygon" ); + SDEBUG( point ); + for( const auto polygon_vertex : + geode::Range{ 0, polygon_points.size() } ) + { + const auto v0 = polygon_points[polygon_vertex]; + const auto next_polygon_vertex = + ( polygon_vertex + 1 ) % polygon_points.size(); + const auto v1 = polygon_points[next_polygon_vertex]; + SDEBUG( v0 ); + SDEBUG( v1 ); + if( v0.value( 1 ) <= point.value( 1 ) ) + { + if( v1.value( 1 ) > point.value( 1 ) ) + { + if( is_left( v0, v1, point ) > 0 ) + { + DEBUG( "widing_number++" ); + widing_number++; + } + } + } + else + { + if( v1.value( 1 ) <= point.value( 1 ) ) + { + if( is_left( v0, v1, point ) < 0 ) + { + DEBUG( "widing_number--" ); + widing_number--; + } + } + } + } + DEBUG( widing_number ); + return widing_number != 0; + } +} // namespace geode \ No newline at end of file From 15b4e2c0f8c1112faffde656c9d0223a322f878f Mon Sep 17 00:00:00 2001 From: Pierre Anquez Date: Mon, 2 Mar 2026 21:38:16 +0100 Subject: [PATCH 2/2] PR review --- include/geode/geometry/is_point_inside.hpp | 15 +++--- src/geode/geometry/is_point_inside.cpp | 53 ++++++++++------------ 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/include/geode/geometry/is_point_inside.hpp b/include/geode/geometry/is_point_inside.hpp index 6892b5163..a928e9a38 100644 --- a/include/geode/geometry/is_point_inside.hpp +++ b/include/geode/geometry/is_point_inside.hpp @@ -23,20 +23,23 @@ #pragma once -#include #include -#include + +namespace geode +{ + FORWARD_DECLARATION_DIMENSION_CLASS( Point ); + FORWARD_DECLARATION_DIMENSION_CLASS( Polygon ); + ALIAS_2D( Point ); + ALIAS_2D( Polygon ); +} // namespace geode namespace geode { /*! * Find if point is inside a polygon. * @param[in] point The point to rotate. - * @param[in] axis Axis for the rotation (not null but not necessary - * normalized). - * @param[in] angle Rotation angle expresses in radians. */ [[nodiscard]] bool opengeode_geometry_api is_point_inside_polygon( - const Point2D& point, absl::Span< const Point2D > polygon_points ); + const Point2D& point, const Polygon2D& polygon ); } // namespace geode \ No newline at end of file diff --git a/src/geode/geometry/is_point_inside.cpp b/src/geode/geometry/is_point_inside.cpp index 929e89eb9..ac9db7c91 100644 --- a/src/geode/geometry/is_point_inside.cpp +++ b/src/geode/geometry/is_point_inside.cpp @@ -23,62 +23,57 @@ #include -#include +#include +#include namespace { - double is_left( const geode::Point2D& p0, + bool is_left( const geode::Point2D& p0, const geode::Point2D& p1, const geode::Point2D& p2 ) { return ( p1.value( 0 ) - p0.value( 0 ) ) - * ( p2.value( 1 ) - p0.value( 1 ) ) - - ( p2.value( 0 ) - p0.value( 0 ) ) - * ( p1.value( 1 ) - p0.value( 1 ) ); + * ( p2.value( 1 ) - p0.value( 1 ) ) + - ( p2.value( 0 ) - p0.value( 0 ) ) + * ( p1.value( 1 ) - p0.value( 1 ) ) + > 0; } } // namespace namespace geode { - bool opengeode_geometry_api is_point_inside_polygon( - const Point2D& point, absl::Span< const Point2D > polygon_points ) + bool is_point_inside_polygon( + const Point2D& point, const Polygon2D& polygon ) { - double widing_number{ 0 }; - DEBUG( "is_point_inside_polygon" ); - SDEBUG( point ); - for( const auto polygon_vertex : - geode::Range{ 0, polygon_points.size() } ) + double winding_number{ 0 }; + const auto& vertices = polygon.vertices(); + for( const auto polygon_vertex : geode::Range{ polygon.nb_vertices() } ) { - const auto v0 = polygon_points[polygon_vertex]; - const auto next_polygon_vertex = - ( polygon_vertex + 1 ) % polygon_points.size(); - const auto v1 = polygon_points[next_polygon_vertex]; - SDEBUG( v0 ); - SDEBUG( v1 ); - if( v0.value( 1 ) <= point.value( 1 ) ) + const auto& v0 = vertices[polygon_vertex]; + const auto& next_polygon_vertex = + ( polygon_vertex + 1 ) % vertices.size(); + const auto& v1 = vertices[next_polygon_vertex]; + if( v0.get().value( 1 ) <= point.value( 1 ) ) { - if( v1.value( 1 ) > point.value( 1 ) ) + if( v1.get().value( 1 ) > point.value( 1 ) ) { - if( is_left( v0, v1, point ) > 0 ) + if( is_left( v0, v1, point ) ) { - DEBUG( "widing_number++" ); - widing_number++; + winding_number++; } } } else { - if( v1.value( 1 ) <= point.value( 1 ) ) + if( v1.get().value( 1 ) <= point.value( 1 ) ) { - if( is_left( v0, v1, point ) < 0 ) + if( !is_left( v0, v1, point ) ) { - DEBUG( "widing_number--" ); - widing_number--; + winding_number--; } } } } - DEBUG( widing_number ); - return widing_number != 0; + return winding_number != 0; } } // namespace geode \ No newline at end of file