fj_kernel/geometry/
curve.rs

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