fj_core/geometry/
path.rs

1//! Paths through 2D and 3D space
2//!
3//! See [`SurfacePath`] and [`GlobalPath`].
4
5use fj_math::{Circle, Line, Point, Scalar, Transform, Vector};
6
7/// A path through surface (2D) space
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
9pub enum SurfacePath {
10    /// A circle
11    Circle(Circle<2>),
12
13    /// A line
14    Line(Line<2>),
15}
16
17impl SurfacePath {
18    /// Build a circle from the given radius
19    pub fn circle_from_center_and_radius(
20        center: impl Into<Point<2>>,
21        radius: impl Into<Scalar>,
22    ) -> Self {
23        Self::Circle(Circle::from_center_and_radius(center, radius))
24    }
25
26    /// Build a line that represents the u-axis of the surface its on
27    pub fn u_axis() -> Self {
28        let a = Point::origin();
29        let b = a + Vector::unit_u();
30
31        let (self_, _) = Self::line_from_points([a, b]);
32        self_
33    }
34
35    /// Build a line that represents the v-axis of the surface its on
36    pub fn v_axis() -> Self {
37        let a = Point::origin();
38        let b = a + Vector::unit_v();
39
40        let (self_, _) = Self::line_from_points([a, b]);
41        self_
42    }
43
44    /// Construct a line from two points
45    ///
46    /// Also returns the coordinates of the points on the path.
47    pub fn line_from_points(
48        points: [impl Into<Point<2>>; 2],
49    ) -> (Self, [Point<1>; 2]) {
50        let (line, coords) = Line::from_points(points);
51        (Self::Line(line), coords)
52    }
53
54    /// Create a line from two points that include line coordinates
55    pub fn line_from_points_with_coords(
56        points: [(impl Into<Point<1>>, impl Into<Point<2>>); 2],
57    ) -> Self {
58        Self::Line(Line::from_points_with_line_coords(points))
59    }
60
61    /// Convert a point on the path into surface coordinates
62    pub fn point_from_path_coords(
63        &self,
64        point: impl Into<Point<1>>,
65    ) -> Point<2> {
66        match self {
67            Self::Circle(circle) => circle.point_from_circle_coords(point),
68            Self::Line(line) => line.point_from_line_coords(point),
69        }
70    }
71
72    /// Create a new path that is the reverse of this one
73    #[must_use]
74    pub fn reverse(self) -> Self {
75        match self {
76            Self::Circle(circle) => Self::Circle(circle.reverse()),
77            Self::Line(line) => Self::Line(line.reverse()),
78        }
79    }
80}
81
82/// A path through global (3D) space
83#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
84pub enum GlobalPath {
85    /// A circle
86    Circle(Circle<3>),
87
88    /// A line
89    Line(Line<3>),
90}
91
92impl GlobalPath {
93    /// Construct a `GlobalPath` that represents the x-axis
94    pub fn x_axis() -> Self {
95        Self::Line(Line::from_origin_and_direction(
96            Point::origin(),
97            Vector::unit_x(),
98        ))
99    }
100
101    /// Construct a `GlobalPath` that represents the y-axis
102    pub fn y_axis() -> Self {
103        Self::Line(Line::from_origin_and_direction(
104            Point::origin(),
105            Vector::unit_y(),
106        ))
107    }
108
109    /// Construct a `GlobalPath` that represents the z-axis
110    pub fn z_axis() -> Self {
111        Self::Line(Line::from_origin_and_direction(
112            Point::origin(),
113            Vector::unit_z(),
114        ))
115    }
116
117    /// Build a circle from the given radius
118    pub fn circle_from_radius(radius: impl Into<Scalar>) -> Self {
119        let radius = radius.into();
120
121        Self::Circle(Circle::from_center_and_radius(Point::origin(), radius))
122    }
123
124    /// Construct a line from two points
125    ///
126    /// Also returns the coordinates of the points on the path.
127    pub fn line_from_points(
128        points: [impl Into<Point<3>>; 2],
129    ) -> (Self, [Point<1>; 2]) {
130        let (line, coords) = Line::from_points(points);
131        (Self::Line(line), coords)
132    }
133
134    /// Access the origin of the path's coordinate system
135    pub fn origin(&self) -> Point<3> {
136        match self {
137            Self::Circle(circle) => circle.center() + circle.a(),
138            Self::Line(line) => line.origin(),
139        }
140    }
141
142    /// Convert a point on the path into global coordinates
143    pub fn point_from_path_coords(
144        &self,
145        point: impl Into<Point<1>>,
146    ) -> Point<3> {
147        match self {
148            Self::Circle(circle) => circle.point_from_circle_coords(point),
149            Self::Line(line) => line.point_from_line_coords(point),
150        }
151    }
152
153    /// Convert a vector on the path into global coordinates
154    pub fn vector_from_path_coords(
155        &self,
156        vector: impl Into<Vector<1>>,
157    ) -> Vector<3> {
158        match self {
159            Self::Circle(circle) => circle.vector_from_circle_coords(vector),
160            Self::Line(line) => line.vector_from_line_coords(vector),
161        }
162    }
163
164    /// Transform the path
165    #[must_use]
166    pub fn transform(self, transform: &Transform) -> Self {
167        match self {
168            Self::Circle(curve) => {
169                Self::Circle(transform.transform_circle(&curve))
170            }
171            Self::Line(curve) => Self::Line(transform.transform_line(&curve)),
172        }
173    }
174}