1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use argmin::core::ArgminFloat;
use nalgebra::{Const, OPoint, Point2};
use crate::{
contains::curve_contains_point::x_ray_intersection,
misc::FloatingPoint,
prelude::{BoundingBox, CurveIntersectionSolverOptions},
region::CompoundCurve,
};
use super::Contains;
impl<T: FloatingPoint + ArgminFloat> Contains<OPoint<T, Const<2>>> for CompoundCurve<T, Const<3>> {
type Option = Option<CurveIntersectionSolverOptions<T>>;
/// Determine if a point is inside a closed curve by ray casting method.
/// # Example
/// ```
/// use nalgebra::{Point2, Vector2};
/// use curvo::prelude::*;
/// use std::f64::consts::{PI, TAU};
/// let o = Point2::origin();
/// let dx = Vector2::x();
/// let dy = Vector2::y();
/// let compound = CompoundCurve::try_new(vec![
/// NurbsCurve2D::try_arc(&o, &dx, &dy, 1., 0., PI).unwrap(),
/// NurbsCurve2D::try_arc(&o, &dx, &dy, 1., PI, TAU).unwrap(),
/// ]).unwrap();
/// assert!(compound.contains(&Point2::new(0.0, 0.0), None).unwrap());
/// assert!(!compound.contains(&Point2::new(3.0, 0.), None).unwrap());
/// assert!(compound.contains(&Point2::new(1.0, 0.0), None).unwrap());
/// ```
fn contains(&self, point: &Point2<T>, option: Self::Option) -> anyhow::Result<bool> {
// anyhow::ensure!(self.is_closed(), "Curve must be closed");
let bb: BoundingBox<T, Const<2>> = self.into();
if !bb.contains(point) {
return Ok(false);
}
let on_boundary = self
.find_closest_point(point)
.map(|closest| {
let delta = closest - point;
let distance = delta.norm();
distance
< option
.as_ref()
.map(|opt| opt.minimum_distance)
.unwrap_or(T::from_f64(1e-6).unwrap())
})
.unwrap_or(false);
if on_boundary {
return Ok(true);
}
let size = bb.size();
let sx = size.x * T::from_f64(2.).unwrap();
let intersections: anyhow::Result<Vec<_>> = self
.spans()
.iter()
.map(|span| x_ray_intersection(span, point, sx, option.clone()))
.collect();
let count = intersections?.iter().map(|its| its.len()).sum::<usize>();
Ok(count % 2 == 1)
}
}