truck_geometry/specifieds/
hyperbola.rs1use super::*;
2
3impl<P> UnitHyperbola<P> {
4 #[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}