mirror of https://codeberg.org/topola/topola.git
Explain in comments how to point-in-polygon checking method works
This commit is contained in:
parent
fc3857072c
commit
36004b155b
|
|
@ -53,35 +53,55 @@ impl<T: Copy> From<Vector2<T>> for [T; 2] {
|
||||||
macro_rules! impl_inside_polygon {
|
macro_rules! impl_inside_polygon {
|
||||||
($type:ty) => {
|
($type:ty) => {
|
||||||
impl Vector2<$type> {
|
impl Vector2<$type> {
|
||||||
// Checks if the point (px, py) is inside a polygon using the ray-casting
|
// Checks if the point is inside a polygon by casting a ray to the
|
||||||
// algorithm. Division is not used to avoid integer truncation errors.
|
// right. Division is not used to avoid integer truncation errors.
|
||||||
pub fn inside_polygon(&self, polygon: &[Vector2<$type>]) -> bool {
|
pub fn inside_polygon(&self, polygon: &[Vector2<$type>]) -> bool {
|
||||||
let mut inside = false;
|
let mut inside = false;
|
||||||
let n = polygon.len();
|
let n = polygon.len();
|
||||||
let px = self.x;
|
|
||||||
let py = self.y;
|
|
||||||
|
|
||||||
|
// `self` is `v0`.
|
||||||
|
|
||||||
|
// `v1` is the previous vertex.
|
||||||
let mut v1 = &polygon[n - 1];
|
let mut v1 = &polygon[n - 1];
|
||||||
|
|
||||||
|
// `v2` is the current vertex.
|
||||||
for v2 in polygon.iter() {
|
for v2 in polygon.iter() {
|
||||||
let dy = v2.y - v1.y;
|
let dx12 = v2.x - v1.x;
|
||||||
let zero = 0 as $type;
|
let dy12 = v2.y - v1.y;
|
||||||
|
|
||||||
if dy != zero && (py > v1.y) != (py > v2.y) {
|
// First, check if the line of the horizontal rightward ray
|
||||||
let dx = v2.x - v1.x;
|
// cast to actually crosses the vertical span of the current
|
||||||
let t = py - v1.y;
|
// `(v1, v2)` edge.
|
||||||
let s = px - v1.x;
|
if dy12 != (0 as $type) && (self.y > v1.y) != (self.y > v2.y) {
|
||||||
|
let dx01 = self.x - v1.x;
|
||||||
|
let dy01 = self.y - v1.y;
|
||||||
|
|
||||||
let crosses = if dy > zero {
|
// Now check if the (v1, v2) edge is actually on the
|
||||||
s * dy < dx * t
|
// right side of the ray and not on the left.
|
||||||
|
//
|
||||||
|
// This just compares the X coordinate of `self` (`v0`)
|
||||||
|
// to the X coordinate of the intersection between the
|
||||||
|
// horizontal rightward ray and the current `(v1, v2)` edge:
|
||||||
|
//
|
||||||
|
// `self.x < v1.x + (self.y - v1.y) * (dx12 / dy12)`
|
||||||
|
//
|
||||||
|
// but is algebraically simplified and rewritten to not
|
||||||
|
// use division.
|
||||||
|
let crosses = if dy12 > (0 as $type) {
|
||||||
|
dx01 * dy12 < dx12 * dy01
|
||||||
} else {
|
} else {
|
||||||
s * dy > dx * t
|
dx01 * dy12 > dx12 * dy01
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Even-odd rule: flip whether the point is inside or
|
||||||
|
// outside upon each detected crossing.
|
||||||
if crosses {
|
if crosses {
|
||||||
inside = !inside;
|
inside = !inside;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make the current vertex previous for the next loop
|
||||||
|
// iteration.
|
||||||
v1 = v2;
|
v1 = v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue