use geo_types::Coord;
use crate::algorithm::orientation::{COLLINEAR, LEFT, index};
use crate::geom::location::{BOUNDARY, EXTERIOR, INTERIOR};
pub(crate) struct RayCrossingCounter {
p: Coord<f64>,
crossing_count: i32,
is_point_on_segment: bool,
}
impl RayCrossingCounter {
pub(crate) fn locate_point_in_ring_coordinate_coordinates(
p: Coord<f64>,
ring: &[Coord<f64>],
) -> i32 {
let mut counter = RayCrossingCounter::new(p);
for i in 1..ring.len() {
let p1 = ring[i];
let p2 = ring[i - 1];
counter.count_segment(p1, p2);
if counter.is_on_segment() {
return counter.get_location();
}
}
counter.get_location()
}
pub(crate) fn new(p: Coord<f64>) -> Self {
Self {
p,
crossing_count: 0,
is_point_on_segment: false,
}
}
pub(crate) fn count_segment(&mut self, p1: Coord<f64>, p2: Coord<f64>) {
if p1.x < self.p.x && p2.x < self.p.x {
return;
}
if self.p.x == p2.x && self.p.y == p2.y {
self.is_point_on_segment = true;
return;
}
if p1.y == self.p.y && p2.y == self.p.y {
let mut minx = p1.x;
let mut maxx = p2.x;
if minx > maxx {
minx = p2.x;
maxx = p1.x;
}
if self.p.x >= minx && self.p.x <= maxx {
self.is_point_on_segment = true;
}
return;
}
if ((p1.y > self.p.y) && (p2.y <= self.p.y)) || ((p2.y > self.p.y) && (p1.y <= self.p.y)) {
let mut orient = index(p1, p2, self.p);
if orient == COLLINEAR {
self.is_point_on_segment = true;
return;
}
if p2.y < p1.y {
orient = -orient;
}
if orient == LEFT {
self.crossing_count += 1;
}
}
}
#[allow(dead_code)]
pub(crate) fn get_count(&self) -> i32 {
self.crossing_count
}
pub(crate) fn is_on_segment(&self) -> bool {
self.is_point_on_segment
}
pub(crate) fn get_location(&self) -> i32 {
if self.is_point_on_segment {
return BOUNDARY;
}
if (self.crossing_count % 2) == 1 {
return INTERIOR;
}
EXTERIOR
}
#[allow(dead_code)]
pub(crate) fn is_point_in_polygon(&self) -> bool {
self.get_location() != EXTERIOR
}
}