Another project
1use bone_types::{Aabb3, ChordHeightTolerance, Length, Parameter, Point3, Tolerance, Vec3};
2use serde::{Deserialize, Serialize};
3use uom::si::length::millimeter;
4
5use crate::KernelError;
6use crate::closest::ClosestPoint3;
7use crate::curve3::{Curve3, Curve3Kind};
8
9#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
10#[serde(deny_unknown_fields)]
11pub struct Line3 {
12 start: Point3,
13 end: Point3,
14}
15
16impl Line3 {
17 pub fn new(start: Point3, end: Point3, tolerance: Tolerance) -> Result<Self, KernelError> {
18 if (end - start).norm_mm() < tolerance.value() {
19 return Err(KernelError::DegenerateLine);
20 }
21 Ok(Self { start, end })
22 }
23
24 #[must_use]
25 pub const fn new_unchecked(start: Point3, end: Point3) -> Self {
26 Self { start, end }
27 }
28
29 #[must_use]
30 pub const fn start(self) -> Point3 {
31 self.start
32 }
33
34 #[must_use]
35 pub const fn end(self) -> Point3 {
36 self.end
37 }
38
39 #[must_use]
40 pub fn length_mm(self) -> f64 {
41 (self.end - self.start).norm_mm()
42 }
43
44 #[must_use]
45 pub fn as_kind(self) -> Curve3Kind {
46 Curve3Kind::Line(self)
47 }
48}
49
50impl Curve3 for Line3 {
51 fn evaluate(&self, t: Parameter) -> Point3 {
52 let (sx, sy, sz) = self.start.coords_mm();
53 let (ex, ey, ez) = self.end.coords_mm();
54 let u = t.value();
55 Point3::from_mm(sx + u * (ex - sx), sy + u * (ey - sy), sz + u * (ez - sz))
56 }
57
58 fn derivative(&self, _t: Parameter) -> Vec3 {
59 self.end - self.start
60 }
61
62 fn bounding_box(&self) -> Aabb3 {
63 Aabb3::from_corners(self.start, self.end)
64 }
65
66 fn closest_point(&self, p: Point3, _tolerance: Tolerance) -> ClosestPoint3 {
67 let d = self.end - self.start;
68 let v = p - self.start;
69 let len_sq = d.norm_squared_mm2();
70 let t = (v.dot_mm2(d) / len_sq).clamp(0.0, 1.0);
71 let point = self.evaluate(Parameter::new(t));
72 let dist_mm = (p - point).norm_mm();
73 ClosestPoint3::new(Parameter::new(t), point, Length::new::<millimeter>(dist_mm))
74 }
75
76 fn tessellate(&self, _tolerance: ChordHeightTolerance) -> Vec<Point3> {
77 vec![self.start, self.end]
78 }
79}
80
81impl core::fmt::Display for Line3 {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 write!(f, "line3{{ {} -> {} }}", self.start, self.end)
84 }
85}