Another project
1use bone_types::{Length, Parameter, Point2, Tolerance, UnitVec2, Vec2};
2use uom::si::length::millimeter;
3
4use crate::KernelError;
5use crate::aabb::Aabb2;
6use crate::closest::ClosestPoint2;
7use crate::curvature::Curvature;
8use crate::curve2::{Curve2, Curve2Kind};
9
10#[derive(Copy, Clone, Debug, PartialEq)]
11pub struct Line2 {
12 start: Point2,
13 end: Point2,
14}
15
16impl Line2 {
17 pub fn new(start: Point2, end: Point2, 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 start(self) -> Point2 {
26 self.start
27 }
28
29 #[must_use]
30 pub const fn end(self) -> Point2 {
31 self.end
32 }
33
34 #[must_use]
35 pub fn length(self) -> Length {
36 (self.end - self.start).norm()
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 unit_direction(self) -> UnitVec2 {
46 let (dx, dy) = (self.end - self.start).coords_mm();
47 let len = (dx * dx + dy * dy).sqrt();
48 UnitVec2::new_unchecked(dx / len, dy / len)
49 }
50}
51
52impl Curve2 for Line2 {
53 fn evaluate(&self, t: Parameter) -> Point2 {
54 let (sx, sy) = self.start.coords_mm();
55 let (ex, ey) = self.end.coords_mm();
56 let u = t.value();
57 Point2::from_mm(sx + u * (ex - sx), sy + u * (ey - sy))
58 }
59
60 fn derivative(&self, _t: Parameter) -> Vec2 {
61 self.end - self.start
62 }
63
64 fn tangent(&self, _t: Parameter) -> UnitVec2 {
65 self.unit_direction()
66 }
67
68 fn curvature(&self, _t: Parameter) -> Curvature {
69 Curvature::ZERO
70 }
71
72 fn bounding_box(&self) -> Aabb2 {
73 Aabb2::from_corners(self.start, self.end)
74 }
75
76 fn closest_point(&self, p: Point2, _tolerance: Tolerance) -> ClosestPoint2 {
77 let d = self.end - self.start;
78 let v = p - self.start;
79 let len_sq = d.norm_squared_mm2();
80 let t = (v.dot_mm2(d) / len_sq).clamp(0.0, 1.0);
81 let point = self.evaluate(Parameter::new(t));
82 let dist_mm = (p - point).norm_mm();
83 ClosestPoint2::new(Parameter::new(t), point, Length::new::<millimeter>(dist_mm))
84 }
85
86 fn as_kind(&self) -> Curve2Kind {
87 Curve2Kind::Line(*self)
88 }
89}
90
91impl core::fmt::Display for Line2 {
92 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
93 write!(f, "line2{{ {} -> {} }}", self.start, self.end)
94 }
95}