Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add point in polygon test using winding counting method #173

Merged
merged 3 commits into from
Mar 24, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add point in poly using winding counter method
kurtlawrence authored and sebcrozet committed Mar 24, 2024
commit 4982631363e5996b3a9b521192ee2ac91ad879c0
2 changes: 1 addition & 1 deletion src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ pub use self::median::median;
pub use self::point_cloud_support_point::{
point_cloud_support_point, point_cloud_support_point_id,
};
pub use self::point_in_poly2d::point_in_poly2d;
pub use self::point_in_poly2d::{point_in_poly2d, point_in_poly2d_winding};
pub use self::sdp_matrix::{SdpMatrix2, SdpMatrix3};

pub use self::array::{Array1, Array2, DefaultStorage};
102 changes: 102 additions & 0 deletions src/utils/point_in_poly2d.rs
Original file line number Diff line number Diff line change
@@ -25,3 +25,105 @@ pub fn point_in_poly2d(pt: &Point2<Real>, poly: &[Point2<Real>]) -> bool {
true
}
}

/// Tests if the given point is inside of a polygon with arbitrary orientation, using a counting
/// winding strategy.
///
/// This handles concave polygons.
pub fn point_in_poly2d_winding(pt: &Point2<Real>, poly: &[Point2<Real>]) -> bool {
if poly.is_empty() {
return false;
}

let mut winding = 0i32;
for (i, a) in poly.iter().enumerate() {
let b = poly[(i + 1) % poly.len()];
let seg_dir = b - a;
let dpt = pt - a;
let perp = dpt.perp(&seg_dir);
let w = match (dpt.y > 0.0, b.y > pt.y) {
(true, true) if perp < 0.0 => 1,
(false, false) if perp > 0.0 => -1,
_ => 0,
};
winding += w;
}
winding != 0
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn point_in_poly2d_concave() {
let poly = [
[615.4741821289063, 279.4120788574219],
[617.95947265625, 281.8973693847656],
[624.1727294921875, 288.73193359375],
[626.6580200195313, 292.4598693847656],
[634.7352294921875, 302.40106201171875],
[637.8418579101563, 306.7503356933594],
[642.8124389648438, 312.96356201171875],
[652.7536010742188, 330.98193359375],
[654.6176147460938, 334.7098693847656],
[661.4521484375, 349.0003356933594],
[666.4227294921875, 360.18414306640625],
[670.1506958007813, 367.6400451660156],
[675.1212768554688, 381.30914306640625],
[678.2279052734375, 391.2503356933594],
[681.33447265625, 402.43414306640625],
[683.81982421875, 414.23931884765625],
[685.0624389648438, 422.3165283203125],
[685.6837768554688, 431.0150146484375],
[686.3051147460938, 442.8201904296875],
[685.6837768554688, 454.0040283203125],
[683.81982421875, 460.83856201171875],
[679.4705200195313, 470.77972412109375],
[674.4999389648438, 480.720947265625],
[670.1506958007813, 486.93414306640625],
[662.073486328125, 497.49664306640625],
[659.5881958007813, 499.36065673828125],
[653.3749389648438, 503.70989990234375],
[647.7830200195313, 506.1951904296875],
[642.8124389648438, 507.43780517578125],
[631.6286010742188, 508.05914306640625],
[621.0661010742188, 508.05914306640625],
[605.5330200195313, 508.05914306640625],
[596.2131958007813, 508.05914306640625],
[586.893310546875, 508.05914306640625],
[578.8161010742188, 508.05914306640625],
[571.3602294921875, 506.1951904296875],
[559.5551147460938, 499.36065673828125],
[557.0697631835938, 497.49664306640625],
[542.1580200195313, 484.4488525390625],
[534.7021484375, 476.37164306640625],
[532.8381958007813, 473.8863525390625],
[527.2462768554688, 466.43048095703125],
[522.2756958007813, 450.89739990234375],
[521.6543579101563, 444.06280517578125],
[521.0330200195313, 431.6363525390625],
[521.6543579101563, 422.93780517578125],
[523.518310546875, 409.26873779296875],
[527.2462768554688, 397.46356201171875],
[532.8381958007813, 385.6584167480469],
[540.9154052734375, 373.23193359375],
[547.1286010742188, 365.77606201171875],
[559.5551147460938, 354.59222412109375],
[573.2241821289063, 342.165771484375],
[575.70947265625, 339.68048095703125],
[584.4080200195313, 331.603271484375],
[597.455810546875, 317.3128356933594],
[601.8051147460938, 311.7209167480469],
[607.39697265625, 303.6437072753906],
[611.7462768554688, 296.1878356933594],
[614.2315673828125, 288.1106262207031],
[615.4741821289063, 280.65472412109375],
[615.4741821289063, 279.4120788574219],
]
.map(Point2::from);
let pt = Point2::from([596.0181884765625, 427.9162902832031]);
assert!(!point_in_poly2d(&pt, &poly));
assert!(point_in_poly2d_winding(&pt, &poly));
}
}