truck_geometry/specifieds/
hyperbola.rs

1use super::*;
2
3impl<P> UnitHyperbola<P> {
4    /// constructor
5    #[inline]
6    pub const fn new() -> UnitHyperbola<P> { UnitHyperbola(std::marker::PhantomData) }
7}
8
9impl ParametricCurve for UnitHyperbola<Point2> {
10    type Point = Point2;
11    type Vector = Vector2;
12    #[inline]
13    fn subs(&self, t: f64) -> Self::Point { Point2::new(f64::cosh(t), f64::sinh(t)) }
14    #[inline]
15    fn der(&self, t: f64) -> Self::Vector { Vector2::new(f64::sinh(t), f64::cosh(t)) }
16    #[inline]
17    fn der2(&self, t: f64) -> Self::Vector { Vector2::new(f64::cosh(t), f64::sinh(t)) }
18}
19
20impl ParametricCurve for UnitHyperbola<Point3> {
21    type Point = Point3;
22    type Vector = Vector3;
23    #[inline]
24    fn subs(&self, t: f64) -> Self::Point { Point3::new(f64::cosh(t), f64::sinh(t), 0.0) }
25    #[inline]
26    fn der(&self, t: f64) -> Self::Vector { Vector3::new(f64::sinh(t), f64::cosh(t), 0.0) }
27    #[inline]
28    fn der2(&self, t: f64) -> Self::Vector { Vector3::new(f64::cosh(t), f64::sinh(t), 0.0) }
29}
30
31impl<P> ParameterDivision1D for UnitHyperbola<P>
32where
33    UnitHyperbola<P>: ParametricCurve<Point = P>,
34    P: EuclideanSpace<Scalar = f64> + MetricSpace<Metric = f64> + HashGen<f64>,
35{
36    type Point = P;
37    fn parameter_division(&self, range: (f64, f64), tol: f64) -> (Vec<f64>, Vec<P>) {
38        algo::curve::parameter_division(self, range, tol)
39    }
40}
41
42impl SearchNearestParameter<D1> for UnitHyperbola<Point2> {
43    type Point = Point2;
44    fn search_nearest_parameter<H: Into<SPHint1D>>(
45        &self,
46        p: Point2,
47        _: H,
48        _: usize,
49    ) -> Option<f64> {
50        let a = -p.y;
51        let b = (p.y * p.y - p.x * p.x) / 4.0 + 1.0;
52        let c = -p.y;
53        let d = p.y * p.y / 4.0;
54        let y = solver::solve_quartic(a, b, c, d)
55            .into_iter()
56            .filter_map(|z| match z.im.so_small() {
57                true => Some(z.re),
58                false => None,
59            })
60            .min_by(|s, t| {
61                p.distance2(self.subs(*s))
62                    .partial_cmp(&p.distance2(self.subs(*t)))
63                    .unwrap()
64            })?;
65        Some(f64::asinh(y))
66    }
67}
68
69impl SearchNearestParameter<D1> for UnitHyperbola<Point3> {
70    type Point = Point3;
71    fn search_nearest_parameter<H: Into<SPHint1D>>(
72        &self,
73        p: Point3,
74        _: H,
75        _trials: usize,
76    ) -> Option<f64> {
77        UnitHyperbola::<Point2>::new().search_nearest_parameter(
78            Point2::new(p.x, p.y),
79            None,
80            _trials,
81        )
82    }
83}
84
85impl SearchParameter<D1> for UnitHyperbola<Point2> {
86    type Point = Point2;
87    fn search_parameter<H: Into<SPHint1D>>(&self, p: Point2, _: H, _: usize) -> Option<f64> {
88        let t = f64::asinh(p.y);
89        match p.near(&self.subs(t)) {
90            true => Some(t),
91            false => None,
92        }
93    }
94}
95
96impl SearchParameter<D1> for UnitHyperbola<Point3> {
97    type Point = Point3;
98    fn search_parameter<H: Into<SPHint1D>>(&self, p: Point3, _: H, _: usize) -> Option<f64> {
99        let t = f64::asinh(p.y);
100        match p.near(&self.subs(t)) {
101            true => Some(t),
102            false => None,
103        }
104    }
105}
106
107#[test]
108fn snp_test() {
109    let curve = UnitHyperbola::<Point2>::new();
110    let p = curve.subs(2.0);
111    let q = p + Vector2::new(-p.x, p.y);
112    let t = curve.search_nearest_parameter(q, None, 0).unwrap();
113    assert_near!(t, 2.0);
114}
115
116#[test]
117fn sp_test() {
118    let curve = UnitHyperbola::<Point2>::new();
119    let t = 100.0 * rand::random::<f64>() - 50.0;
120    let p = curve.subs(t);
121    assert_near!(curve.search_parameter(p, None, 0).unwrap(), t);
122
123    let q = Point2::new(-1.0, 0.0);
124    assert!(curve.search_parameter(q, None, 0).is_none());
125}