diff --git a/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs index 0ea06df95..22841cb67 100644 --- a/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs @@ -76,18 +76,18 @@ impl CurveEdgeIntersection { mod tests { use fj_math::Point; - use crate::objects::{CurveKind, Edge, Surface}; + use crate::objects::{Curve, Edge, Surface}; use super::CurveEdgeIntersection; #[test] fn compute_edge_in_front_of_curve_origin() { let surface = Surface::xy_plane(); - let curve = CurveKind::u_axis(); + let curve = Curve::build(surface).u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[1., -1.], [1., 1.]]); - let intersection = CurveEdgeIntersection::compute(&curve, &edge); + let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge); assert_eq!( intersection, @@ -100,11 +100,11 @@ mod tests { #[test] fn compute_edge_behind_curve_origin() { let surface = Surface::xy_plane(); - let curve = CurveKind::u_axis(); + let curve = Curve::build(surface).u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., -1.], [-1., 1.]]); - let intersection = CurveEdgeIntersection::compute(&curve, &edge); + let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge); assert_eq!( intersection, @@ -117,11 +117,11 @@ mod tests { #[test] fn compute_edge_parallel_to_curve() { let surface = Surface::xy_plane(); - let curve = CurveKind::u_axis(); + let curve = Curve::build(surface).u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., -1.], [1., -1.]]); - let intersection = CurveEdgeIntersection::compute(&curve, &edge); + let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge); assert!(intersection.is_none()); } @@ -129,11 +129,11 @@ mod tests { #[test] fn compute_edge_on_curve() { let surface = Surface::xy_plane(); - let curve = CurveKind::u_axis(); + let curve = Curve::build(surface).u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., 0.], [1., 0.]]); - let intersection = CurveEdgeIntersection::compute(&curve, &edge); + let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge); assert_eq!( intersection, diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 9ac88e289..46122ee73 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -143,7 +143,7 @@ mod tests { use crate::{ algorithms::TransformObject, - objects::{CurveKind, Surface}, + objects::{Curve, Surface}, }; use super::SurfaceSurfaceIntersection; @@ -163,15 +163,17 @@ mod tests { None, ); - let expected_xy = CurveKind::u_axis(); - let expected_xz = CurveKind::u_axis(); - let expected_global = CurveKind::x_axis(); + let expected_xy = Curve::build(xy).u_axis(); + let expected_xz = Curve::build(xz).u_axis(); assert_eq!( SurfaceSurfaceIntersection::compute(&xy, &xz), Some(SurfaceSurfaceIntersection { - local_intersection_curves: [expected_xy, expected_xz], - global_intersection_curve: expected_global, + local_intersection_curves: [ + *expected_xy.kind(), + *expected_xz.kind() + ], + global_intersection_curve: *expected_xy.global().kind(), }) ); } diff --git a/crates/fj-kernel/src/builder/curve.rs b/crates/fj-kernel/src/builder/curve.rs new file mode 100644 index 000000000..6909c4d07 --- /dev/null +++ b/crates/fj-kernel/src/builder/curve.rs @@ -0,0 +1,77 @@ +use fj_math::{Line, Point, Vector}; + +use crate::objects::{Curve, CurveKind, GlobalCurve, Surface}; + +/// API for building a [`Curve`] +pub struct CurveBuilder { + surface: Surface, +} + +impl CurveBuilder { + /// Construct a new instance of [`CurveBuilder`] + /// + /// Also see [`Curve::build`]. + pub fn new(surface: Surface) -> Self { + Self { surface } + } + + /// Create a line that represents the u-axis on the surface + pub fn u_axis(&self) -> Curve { + let a = Point::origin(); + let b = a + Vector::unit_u(); + + self.line_from_points([a, b]) + } + + /// Create a line that represents the v-axis on the surface + pub fn v_axis(&self) -> Curve { + let a = Point::origin(); + let b = a + Vector::unit_v(); + + self.line_from_points([a, b]) + } + + /// Create a line from the given points + pub fn line_from_points(&self, points: [impl Into>; 2]) -> Curve { + let points = points.map(Into::into); + + let local = Line::from_points(points); + let global = Line::from_points( + points.map(|point| self.surface.point_from_surface_coords(point)), + ); + + Curve::new( + CurveKind::Line(local), + GlobalCurve::from_kind(CurveKind::Line(global)), + ) + } +} + +/// API for building a [`GlobalCurve`] +pub struct GlobalCurveBuilder; + +impl GlobalCurveBuilder { + /// Create a line that represents the x-axis + pub fn x_axis(&self) -> GlobalCurve { + GlobalCurve::from_kind(CurveKind::x_axis()) + } + + /// Create a line that represents the y-axis + pub fn y_axis(&self) -> GlobalCurve { + GlobalCurve::from_kind(CurveKind::y_axis()) + } + + /// Create a line that represents the z-axis + pub fn z_axis(&self) -> GlobalCurve { + GlobalCurve::from_kind(CurveKind::z_axis()) + } + + /// Create a line from the given points + pub fn line_from_points( + &self, + points: [impl Into>; 2], + ) -> GlobalCurve { + let line = Line::from_points(points); + GlobalCurve::from_kind(CurveKind::Line(line)) + } +} diff --git a/crates/fj-kernel/src/builder/mod.rs b/crates/fj-kernel/src/builder/mod.rs index 9edf20fac..b056530a7 100644 --- a/crates/fj-kernel/src/builder/mod.rs +++ b/crates/fj-kernel/src/builder/mod.rs @@ -1,11 +1,13 @@ //! API for building objects +mod curve; mod cycle; mod edge; mod face; mod solid; pub use self::{ + curve::{CurveBuilder, GlobalCurveBuilder}, cycle::CycleBuilder, edge::EdgeBuilder, face::{FaceBuilder, FacePolygon}, diff --git a/crates/fj-kernel/src/iter.rs b/crates/fj-kernel/src/iter.rs index 34f222325..53c5575c4 100644 --- a/crates/fj-kernel/src/iter.rs +++ b/crates/fj-kernel/src/iter.rs @@ -319,8 +319,8 @@ impl Iterator for Iter { #[cfg(test)] mod tests { use crate::objects::{ - CurveKind, Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, Solid, - Surface, Vertex, + Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, Solid, Surface, + Vertex, }; use super::ObjectIters as _; @@ -384,7 +384,7 @@ mod tests { #[test] fn global_curve() { - let object = GlobalCurve::from_kind(CurveKind::x_axis()); + let object = GlobalCurve::build().x_axis(); assert_eq!(0, object.cycle_iter().count()); assert_eq!(0, object.edge_iter().count()); diff --git a/crates/fj-kernel/src/objects/curve.rs b/crates/fj-kernel/src/objects/curve.rs index 64ec45f4a..6dc85daa1 100644 --- a/crates/fj-kernel/src/objects/curve.rs +++ b/crates/fj-kernel/src/objects/curve.rs @@ -1,5 +1,9 @@ use fj_math::{Circle, Line, Point, Transform, Vector}; +use crate::builder::{CurveBuilder, GlobalCurveBuilder}; + +use super::Surface; + /// A curve, defined in local surface coordinates #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Curve { @@ -8,6 +12,11 @@ pub struct Curve { } impl Curve { + /// Build a curve using [`CurveBuilder`] + pub fn build(surface: Surface) -> CurveBuilder { + CurveBuilder::new(surface) + } + /// Construct a new instance of `Curve` pub fn new(kind: CurveKind<2>, global: GlobalCurve) -> Self { Self { kind, global } @@ -31,6 +40,11 @@ pub struct GlobalCurve { } impl GlobalCurve { + /// Build a curve using [`GlobalCurveBuilder`] + pub fn build() -> GlobalCurveBuilder { + GlobalCurveBuilder + } + /// Construct a `GlobalCurve` from a [`CurveKind<3>`] pub fn from_kind(kind: CurveKind<3>) -> Self { Self { kind } @@ -110,24 +124,6 @@ impl CurveKind { } } -impl CurveKind<2> { - /// Construct a `Curve` that represents the u-axis - pub fn u_axis() -> Self { - Self::Line(Line { - origin: Point::origin(), - direction: Vector::unit_u(), - }) - } - - /// Construct a `Curve` that represents the v-axis - pub fn v_axis() -> Self { - Self::Line(Line { - origin: Point::origin(), - direction: Vector::unit_v(), - }) - } -} - impl CurveKind<3> { /// Construct a `Curve` that represents the x-axis pub fn x_axis() -> Self {