diff --git a/crates/fj-kernel/src/algorithms/approx/curves.rs b/crates/fj-kernel/src/algorithms/approx/curves.rs index 11b0c6e29..ce42b7abb 100644 --- a/crates/fj-kernel/src/algorithms/approx/curves.rs +++ b/crates/fj-kernel/src/algorithms/approx/curves.rs @@ -2,7 +2,10 @@ use std::cmp::max; use fj_math::{Circle, Point, Scalar}; -use crate::{local::Local, objects::Curve}; +use crate::{ + local::Local, + objects::{CurveKind, GlobalCurve}, +}; use super::Tolerance; @@ -21,13 +24,13 @@ use super::Tolerance; /// The `approximate_between` methods of the curves then need to make sure to /// only return points in between those vertices, not the vertices themselves. pub fn approx_curve( - curve: &Curve<3>, + curve: &GlobalCurve, tolerance: Tolerance, out: &mut Vec>>, ) { - match curve { - Curve::Circle(curve) => approx_circle(curve, tolerance, out), - Curve::Line(_) => {} + match curve.kind() { + CurveKind::Circle(curve) => approx_circle(curve, tolerance, out), + CurveKind::Line(_) => {} } } diff --git a/crates/fj-kernel/src/algorithms/approx/cycles.rs b/crates/fj-kernel/src/algorithms/approx/cycles.rs index ebf2e1f87..8793c9cda 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycles.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycles.rs @@ -21,17 +21,13 @@ impl CycleApprox { for edge in cycle.edges() { let mut edge_points = Vec::new(); - approx_curve( - edge.curve().global_form(), - tolerance, - &mut edge_points, - ); + approx_curve(edge.curve().global(), tolerance, &mut edge_points); approx_edge(*edge.vertices(), &mut edge_points); points.extend(edge_points.into_iter().map(|point| { let local = edge .curve() - .local_form() + .kind() .point_from_curve_coords(*point.local_form()); Local::new(local, *point.global_form()) })); diff --git a/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs index 855e044ca..0ea06df95 100644 --- a/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersection/curve_edge.rs @@ -1,10 +1,10 @@ use fj_math::{Point, Segment}; -use crate::objects::{Curve, Edge}; +use crate::objects::{CurveKind, Edge}; use super::LineSegmentIntersection; -/// The intersection between a [`Curve`] and an [`Edge`], in curve coordinates +/// The intersection between a curve and an [`Edge`], in curve coordinates #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum CurveEdgeIntersection { /// The curve and edge intersect at a point @@ -26,17 +26,17 @@ impl CurveEdgeIntersection { /// # Panics /// /// Currently, only intersections between lines and line segments can be - /// computed. Panics, if a different type of [`Curve`] or [`Edge`] is + /// computed. Panics, if a different type of curve or [`Edge`] is /// passed. - pub fn compute(curve: &Curve<2>, edge: &Edge) -> Option { + pub fn compute(curve: &CurveKind<2>, edge: &Edge) -> Option { let curve_as_line = match curve { - Curve::Line(line) => line, + CurveKind::Line(line) => line, _ => todo!("Curve-edge intersection only supports lines"), }; let edge_as_segment = { - let edge_curve_as_line = match edge.curve().local_form() { - Curve::Line(line) => line, + let edge_curve_as_line = match edge.curve().kind() { + CurveKind::Line(line) => line, _ => { todo!("Curve-edge intersection only supports line segments") } @@ -76,14 +76,14 @@ impl CurveEdgeIntersection { mod tests { use fj_math::Point; - use crate::objects::{Curve, Edge, Surface}; + use crate::objects::{CurveKind, Edge, Surface}; use super::CurveEdgeIntersection; #[test] fn compute_edge_in_front_of_curve_origin() { let surface = Surface::xy_plane(); - let curve = Curve::u_axis(); + let curve = CurveKind::u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[1., -1.], [1., 1.]]); @@ -100,7 +100,7 @@ mod tests { #[test] fn compute_edge_behind_curve_origin() { let surface = Surface::xy_plane(); - let curve = Curve::u_axis(); + let curve = CurveKind::u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., -1.], [-1., 1.]]); @@ -117,7 +117,7 @@ mod tests { #[test] fn compute_edge_parallel_to_curve() { let surface = Surface::xy_plane(); - let curve = Curve::u_axis(); + let curve = CurveKind::u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., -1.], [1., -1.]]); @@ -129,7 +129,7 @@ mod tests { #[test] fn compute_edge_on_curve() { let surface = Surface::xy_plane(); - let curve = Curve::u_axis(); + let curve = CurveKind::u_axis(); let edge = Edge::build() .line_segment_from_points(&surface, [[-1., 0.], [1., 0.]]); diff --git a/crates/fj-kernel/src/algorithms/intersection/curve_face.rs b/crates/fj-kernel/src/algorithms/intersection/curve_face.rs index 05a5245e8..54f2117f4 100644 --- a/crates/fj-kernel/src/algorithms/intersection/curve_face.rs +++ b/crates/fj-kernel/src/algorithms/intersection/curve_face.rs @@ -4,10 +4,10 @@ use fj_math::Point; use crate::{ algorithms::intersection::CurveEdgeIntersection, - objects::{Curve, Face}, + objects::{CurveKind, Face}, }; -/// The intersections between a [`Curve`] and a [`Face`], in curve coordinates +/// The intersections between a curve and a [`Face`], in curve coordinates #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct CurveFaceIntersectionList { intervals: Vec, @@ -27,8 +27,8 @@ impl CurveFaceIntersectionList { Self { intervals } } - /// Compute the intersections between a [`Curve`] and a [`Face`] - pub fn compute(curve: &Curve<2>, face: &Face) -> Self { + /// Compute the intersections between a curve and a [`Face`] + pub fn compute(curve: &CurveKind<2>, face: &Face) -> Self { let edges = face.all_cycles().flat_map(|cycle| { let edges: Vec<_> = cycle.edges().cloned().collect(); edges @@ -142,13 +142,13 @@ pub type CurveFaceIntersection = [Point<1>; 2]; mod tests { use fj_math::{Line, Point, Vector}; - use crate::objects::{Curve, Face, Surface}; + use crate::objects::{CurveKind, Face, Surface}; use super::CurveFaceIntersectionList; #[test] fn compute() { - let curve = Curve::Line(Line { + let curve = CurveKind::Line(Line { origin: Point::from([-3., 0.]), direction: Vector::from([1., 0.]), }); diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 820cca925..9ac88e289 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -1,15 +1,15 @@ use fj_math::{Line, Point, Scalar, Vector}; -use crate::objects::{Curve, Surface}; +use crate::objects::{CurveKind, Surface}; /// The intersection between two surfaces #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct SurfaceSurfaceIntersection { /// The intersection curves, in the coordinates of the input surfaces - pub local_intersection_curves: [Curve<2>; 2], + pub local_intersection_curves: [CurveKind<2>; 2], /// The intersection curve, in global coordinates - pub global_intersection_curve: Curve<3>, + pub global_intersection_curve: CurveKind<3>, } impl SurfaceSurfaceIntersection { @@ -50,7 +50,7 @@ impl SurfaceSurfaceIntersection { let curve_a = project_line_into_plane(&line, &a_parametric); let curve_b = project_line_into_plane(&line, &b_parametric); - let curve_global = Curve::Line(Line { origin, direction }); + let curve_global = CurveKind::Line(Line { origin, direction }); Some(Self { local_intersection_curves: [curve_a, curve_b], @@ -70,7 +70,7 @@ impl PlaneParametric { pub fn extract_from_surface(surface: &Surface) -> Self { let Surface::SweptCurve(surface) = surface; let line = match surface.curve { - Curve::Line(line) => line, + CurveKind::Line(line) => line, _ => todo!("Only plane-plane intersection is currently supported."), }; @@ -111,7 +111,7 @@ impl PlaneConstantNormal { fn project_line_into_plane( line: &Line<3>, plane: &PlaneParametric, -) -> Curve<2> { +) -> CurveKind<2> { let line_origin_relative_to_plane = line.origin - plane.origin; let line_origin_in_plane = Vector::from([ plane @@ -134,7 +134,7 @@ fn project_line_into_plane( direction: line_direction_in_plane, }; - Curve::Line(line) + CurveKind::Line(line) } #[cfg(test)] @@ -143,7 +143,7 @@ mod tests { use crate::{ algorithms::TransformObject, - objects::{Curve, Surface}, + objects::{CurveKind, Surface}, }; use super::SurfaceSurfaceIntersection; @@ -163,9 +163,9 @@ mod tests { None, ); - let expected_xy = Curve::u_axis(); - let expected_xz = Curve::u_axis(); - let expected_global = Curve::x_axis(); + let expected_xy = CurveKind::u_axis(); + let expected_xz = CurveKind::u_axis(); + let expected_global = CurveKind::x_axis(); assert_eq!( SurfaceSurfaceIntersection::compute(&xy, &xz), diff --git a/crates/fj-kernel/src/algorithms/reverse.rs b/crates/fj-kernel/src/algorithms/reverse.rs index 54513b3c8..95d25f287 100644 --- a/crates/fj-kernel/src/algorithms/reverse.rs +++ b/crates/fj-kernel/src/algorithms/reverse.rs @@ -1,9 +1,6 @@ use fj_math::{Circle, Line, Point, Vector}; -use crate::{ - local::Local, - objects::{Curve, Cycle, Edge, Face}, -}; +use crate::objects::{Curve, CurveKind, Cycle, Edge, Face}; /// Reverse the direction of a face pub fn reverse_face(face: &Face) -> Face { @@ -28,25 +25,25 @@ fn reverse_local_coordinates_in_cycle<'r>( cycles.into_iter().map(|cycle| { let edges = cycle.edges().map(|edge| { let curve = { - let local = match edge.curve().local_form() { - Curve::Circle(Circle { center, a, b }) => { + let local = match edge.curve().kind() { + CurveKind::Circle(Circle { center, a, b }) => { let center = Point::from([center.u, -center.v]); let a = Vector::from([a.u, -a.v]); let b = Vector::from([b.u, -b.v]); - Curve::Circle(Circle { center, a, b }) + CurveKind::Circle(Circle { center, a, b }) } - Curve::Line(Line { origin, direction }) => { + CurveKind::Line(Line { origin, direction }) => { let origin = Point::from([origin.u, -origin.v]); let direction = Vector::from([direction.u, -direction.v]); - Curve::Line(Line { origin, direction }) + CurveKind::Line(Line { origin, direction }) } }; - Local::new(local, *edge.curve().global_form()) + Curve::new(local, *edge.curve().global()) }; Edge::new(curve, *edge.vertices()) diff --git a/crates/fj-kernel/src/algorithms/sweep.rs b/crates/fj-kernel/src/algorithms/sweep.rs index 7515d9e0f..e525c8683 100644 --- a/crates/fj-kernel/src/algorithms/sweep.rs +++ b/crates/fj-kernel/src/algorithms/sweep.rs @@ -3,10 +3,9 @@ use fj_math::{Point, Scalar, Transform, Triangle, Vector}; use crate::{ iter::ObjectIters, - local::Local, objects::{ - Curve, Cycle, Edge, Face, GlobalVertex, Sketch, Solid, Surface, Vertex, - VerticesOfEdge, + Curve, CurveKind, Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, + Solid, Surface, Vertex, VerticesOfEdge, }, }; @@ -140,12 +139,13 @@ fn create_non_continuous_side_face( let [a, b] = [&vertices[0], &vertices[1]]; let curve = { - let local = Curve::line_from_points([a.0, b.0]); + let local = CurveKind::line_from_points([a.0, b.0]); let global = [a, b].map(|vertex| vertex.1.position()); - let global = Curve::line_from_points(global); + let global = + GlobalCurve::from_kind(CurveKind::line_from_points(global)); - Local::new(local, global) + Curve::new(local, global) }; let vertices = VerticesOfEdge::from_vertices([ diff --git a/crates/fj-kernel/src/algorithms/transform.rs b/crates/fj-kernel/src/algorithms/transform.rs index c187f0aba..13c7c98e3 100644 --- a/crates/fj-kernel/src/algorithms/transform.rs +++ b/crates/fj-kernel/src/algorithms/transform.rs @@ -1,10 +1,8 @@ use fj_math::{Transform, Vector}; -use crate::{ - local::Local, - objects::{ - Curve, Cycle, Edge, Face, GlobalVertex, Sketch, Solid, Surface, Vertex, - }, +use crate::objects::{ + Curve, Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, Solid, + Surface, Vertex, }; /// Transform an object @@ -34,14 +32,12 @@ pub trait TransformObject: Sized { } } -impl TransformObject for Curve<3> { +impl TransformObject for Curve { fn transform(self, transform: &Transform) -> Self { - match self { - Self::Circle(curve) => { - Self::Circle(transform.transform_circle(&curve)) - } - Self::Line(curve) => Self::Line(transform.transform_line(&curve)), - } + // Don't need to transform `self.kind`, as that's in local form. + let global = self.global().transform(transform); + + Curve::new(*self.kind(), global) } } @@ -54,9 +50,9 @@ impl TransformObject for Cycle { impl TransformObject for Edge { fn transform(self, transform: &Transform) -> Self { - let curve = Local::new( - *self.curve().local_form(), - self.curve().global_form().transform(transform), + let curve = Curve::new( + *self.curve().kind(), + self.curve().global().transform(transform), ); let vertices = @@ -93,6 +89,13 @@ impl TransformObject for Face { } } +impl TransformObject for GlobalCurve { + fn transform(self, transform: &Transform) -> Self { + let kind = self.kind().transform(transform); + GlobalCurve::from_kind(kind) + } +} + impl TransformObject for GlobalVertex { fn transform(self, transform: &Transform) -> Self { let position = transform.transform_point(&self.position()); diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index bfe587928..fd3947e38 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -1,8 +1,8 @@ use fj_math::{Circle, Line, Point, Scalar, Vector}; -use crate::{ - local::Local, - objects::{Curve, Edge, GlobalVertex, Surface, Vertex, VerticesOfEdge}, +use crate::objects::{ + Curve, CurveKind, Edge, GlobalCurve, GlobalVertex, Surface, Vertex, + VerticesOfEdge, }; /// API for building an [`Edge`] @@ -11,19 +11,19 @@ pub struct EdgeBuilder; impl EdgeBuilder { /// Create a circle from the given radius pub fn circle_from_radius(&self, radius: Scalar) -> Edge { - let curve_local = Curve::Circle(Circle { + let curve_local = CurveKind::Circle(Circle { center: Point::origin(), a: Vector::from([radius, Scalar::ZERO]), b: Vector::from([Scalar::ZERO, radius]), }); - let curve_canonical = Curve::Circle(Circle { + let curve_global = GlobalCurve::from_kind(CurveKind::Circle(Circle { center: Point::origin(), a: Vector::from([radius, Scalar::ZERO, Scalar::ZERO]), b: Vector::from([Scalar::ZERO, radius, Scalar::ZERO]), - }); + })); Edge::new( - Local::new(curve_local, curve_canonical), + Curve::new(curve_local, curve_global), VerticesOfEdge::none(), ) } @@ -41,11 +41,12 @@ impl EdgeBuilder { GlobalVertex::from_position(position) }); - let curve_local = Curve::Line(Line::from_points(points)); - let curve_canonical = { + let curve_local = CurveKind::Line(Line::from_points(points)); + let curve_global = { let points = global_vertices.map(|global_vertex| global_vertex.position()); - Curve::Line(Line::from_points(points)) + let kind = CurveKind::Line(Line::from_points(points)); + GlobalCurve::from_kind(kind) }; let vertices = { @@ -57,7 +58,7 @@ impl EdgeBuilder { }; Edge::new( - Local::new(curve_local, curve_canonical), + Curve::new(curve_local, curve_global), VerticesOfEdge::from_vertices(vertices), ) } diff --git a/crates/fj-kernel/src/iter.rs b/crates/fj-kernel/src/iter.rs index 66d338213..34f222325 100644 --- a/crates/fj-kernel/src/iter.rs +++ b/crates/fj-kernel/src/iter.rs @@ -3,7 +3,8 @@ use std::collections::VecDeque; use crate::objects::{ - Curve, Cycle, Edge, Face, GlobalVertex, Sketch, Solid, Surface, Vertex, + Curve, Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, Solid, + Surface, Vertex, }; /// Access iterators over all objects of a shape, or part of it @@ -15,7 +16,7 @@ pub trait ObjectIters<'r> { fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters>; /// Iterate over all curves - fn curve_iter(&'r self) -> Iter<&'r Curve<3>> { + fn curve_iter(&'r self) -> Iter<&'r Curve> { let mut iter = Iter::empty(); for object in self.referenced_objects() { @@ -58,6 +59,17 @@ pub trait ObjectIters<'r> { iter } + /// Iterate over all global curves + fn global_curve_iter(&'r self) -> Iter<&'r GlobalCurve> { + let mut iter = Iter::empty(); + + for object in self.referenced_objects() { + iter = iter.with(object.global_curve_iter()); + } + + iter + } + /// Iterate over all global vertices fn global_vertex_iter(&'r self) -> Iter<&'r GlobalVertex> { let mut iter = Iter::empty(); @@ -114,12 +126,12 @@ pub trait ObjectIters<'r> { } } -impl<'r> ObjectIters<'r> for Curve<3> { +impl<'r> ObjectIters<'r> for Curve { fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters> { - Vec::new() + vec![self.global() as &dyn ObjectIters] } - fn curve_iter(&'r self) -> Iter<&'r Curve<3>> { + fn curve_iter(&'r self) -> Iter<&'r Curve> { Iter::from_object(self) } } @@ -142,7 +154,7 @@ impl<'r> ObjectIters<'r> for Cycle { impl<'r> ObjectIters<'r> for Edge { fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters> { - let mut objects = vec![self.curve().global_form() as &dyn ObjectIters]; + let mut objects = vec![self.curve() as &dyn ObjectIters]; for vertex in self.vertices().iter() { objects.push(vertex); @@ -176,6 +188,16 @@ impl<'r> ObjectIters<'r> for Face { } } +impl<'r> ObjectIters<'r> for GlobalCurve { + fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters> { + Vec::new() + } + + fn global_curve_iter(&'r self) -> Iter<&'r GlobalCurve> { + Iter::from_object(self) + } +} + impl<'r> ObjectIters<'r> for GlobalVertex { fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters> { Vec::new() @@ -297,26 +319,12 @@ impl Iterator for Iter { #[cfg(test)] mod tests { use crate::objects::{ - Curve, Cycle, Edge, Face, GlobalVertex, Sketch, Solid, Surface, Vertex, + CurveKind, Cycle, Edge, Face, GlobalCurve, GlobalVertex, Sketch, Solid, + Surface, Vertex, }; use super::ObjectIters as _; - #[test] - fn curve() { - let object = Curve::x_axis(); - - assert_eq!(1, object.curve_iter().count()); - assert_eq!(0, object.cycle_iter().count()); - assert_eq!(0, object.edge_iter().count()); - assert_eq!(0, object.face_iter().count()); - assert_eq!(0, object.global_vertex_iter().count()); - assert_eq!(0, object.sketch_iter().count()); - assert_eq!(0, object.solid_iter().count()); - assert_eq!(0, object.surface_iter().count()); - assert_eq!(0, object.vertex_iter().count()); - } - #[test] fn cycle() { let object = Cycle::build(Surface::xy_plane()).polygon_from_points([ @@ -325,10 +333,10 @@ mod tests { [0., 1.], ]); - assert_eq!(3, object.curve_iter().count()); assert_eq!(1, object.cycle_iter().count()); assert_eq!(3, object.edge_iter().count()); assert_eq!(0, object.face_iter().count()); + assert_eq!(3, object.global_curve_iter().count()); assert_eq!(3, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -343,10 +351,10 @@ mod tests { [[0., 0.], [1., 0.]], ); - assert_eq!(1, object.curve_iter().count()); assert_eq!(0, object.cycle_iter().count()); assert_eq!(1, object.edge_iter().count()); assert_eq!(0, object.face_iter().count()); + assert_eq!(1, object.global_curve_iter().count()); assert_eq!(2, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -363,10 +371,10 @@ mod tests { [0., 1.], ]); - assert_eq!(3, object.curve_iter().count()); assert_eq!(1, object.cycle_iter().count()); assert_eq!(3, object.edge_iter().count()); assert_eq!(1, object.face_iter().count()); + assert_eq!(3, object.global_curve_iter().count()); assert_eq!(3, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -374,14 +382,29 @@ mod tests { assert_eq!(6, object.vertex_iter().count()); } + #[test] + fn global_curve() { + let object = GlobalCurve::from_kind(CurveKind::x_axis()); + + assert_eq!(0, object.cycle_iter().count()); + assert_eq!(0, object.edge_iter().count()); + assert_eq!(0, object.face_iter().count()); + assert_eq!(1, object.global_curve_iter().count()); + assert_eq!(0, object.global_vertex_iter().count()); + assert_eq!(0, object.sketch_iter().count()); + assert_eq!(0, object.solid_iter().count()); + assert_eq!(0, object.surface_iter().count()); + assert_eq!(0, object.vertex_iter().count()); + } + #[test] fn global_vertex() { let object = GlobalVertex::from_position([0., 0., 0.]); - assert_eq!(0, object.curve_iter().count()); assert_eq!(0, object.cycle_iter().count()); assert_eq!(0, object.edge_iter().count()); assert_eq!(0, object.face_iter().count()); + assert_eq!(0, object.global_curve_iter().count()); assert_eq!(1, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -399,10 +422,10 @@ mod tests { ]); let object = Sketch::new().with_faces([face]); - assert_eq!(3, object.curve_iter().count()); assert_eq!(1, object.cycle_iter().count()); assert_eq!(3, object.edge_iter().count()); assert_eq!(1, object.face_iter().count()); + assert_eq!(3, object.global_curve_iter().count()); assert_eq!(3, object.global_vertex_iter().count()); assert_eq!(1, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -414,10 +437,10 @@ mod tests { fn solid() { let object = Solid::build().cube_from_edge_length(1.); - assert_eq!(18, object.curve_iter().count()); assert_eq!(6, object.cycle_iter().count()); assert_eq!(20, object.edge_iter().count()); assert_eq!(6, object.face_iter().count()); + assert_eq!(18, object.global_curve_iter().count()); assert_eq!(8, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(1, object.solid_iter().count()); @@ -429,10 +452,10 @@ mod tests { fn surface() { let object = Surface::xy_plane(); - assert_eq!(0, object.curve_iter().count()); assert_eq!(0, object.cycle_iter().count()); assert_eq!(0, object.edge_iter().count()); assert_eq!(0, object.face_iter().count()); + assert_eq!(0, object.global_curve_iter().count()); assert_eq!(0, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); @@ -445,10 +468,10 @@ mod tests { let global_vertex = GlobalVertex::from_position([0., 0., 0.]); let object = Vertex::new([0.], global_vertex); - assert_eq!(0, object.curve_iter().count()); assert_eq!(0, object.cycle_iter().count()); assert_eq!(0, object.edge_iter().count()); assert_eq!(0, object.face_iter().count()); + assert_eq!(0, object.global_curve_iter().count()); assert_eq!(1, object.global_vertex_iter().count()); assert_eq!(0, object.sketch_iter().count()); assert_eq!(0, object.solid_iter().count()); diff --git a/crates/fj-kernel/src/local.rs b/crates/fj-kernel/src/local.rs index 0a65eb471..45784afe4 100644 --- a/crates/fj-kernel/src/local.rs +++ b/crates/fj-kernel/src/local.rs @@ -2,8 +2,6 @@ use fj_math::Point; -use crate::objects::Curve; - /// A wrapper around the local and global forms of a type /// /// The local form is whatever representation of the value that is most @@ -50,10 +48,6 @@ pub trait LocalForm { type GlobalForm; } -impl LocalForm for Curve<2> { - type GlobalForm = Curve<3>; -} - impl LocalForm for Point<1> { type GlobalForm = Point<3>; } diff --git a/crates/fj-kernel/src/objects/curve.rs b/crates/fj-kernel/src/objects/curve.rs index e808dd039..64ec45f4a 100644 --- a/crates/fj-kernel/src/objects/curve.rs +++ b/crates/fj-kernel/src/objects/curve.rs @@ -1,6 +1,46 @@ -use std::fmt; +use fj_math::{Circle, Line, Point, Transform, Vector}; -use fj_math::{Circle, Line, Point, Vector}; +/// A curve, defined in local surface coordinates +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct Curve { + kind: CurveKind<2>, + global: GlobalCurve, +} + +impl Curve { + /// Construct a new instance of `Curve` + pub fn new(kind: CurveKind<2>, global: GlobalCurve) -> Self { + Self { kind, global } + } + + /// Access the kind of this curve + pub fn kind(&self) -> &CurveKind<2> { + &self.kind + } + + /// Access the global form of this curve + pub fn global(&self) -> &GlobalCurve { + &self.global + } +} + +/// A curve, defined in global (3D) coordinates +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct GlobalCurve { + kind: CurveKind<3>, +} + +impl GlobalCurve { + /// Construct a `GlobalCurve` from a [`CurveKind<3>`] + pub fn from_kind(kind: CurveKind<3>) -> Self { + Self { kind } + } + + /// Access the kind of this curve + pub fn kind(&self) -> &CurveKind<3> { + &self.kind + } +} /// A one-dimensional shape /// @@ -16,7 +56,7 @@ use fj_math::{Circle, Line, Point, Vector}; /// Typically, only `2` or `3` make sense, which means the curve is defined on /// a surface or in a space, respectively. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum Curve { +pub enum CurveKind { /// A circle Circle(Circle), @@ -24,7 +64,7 @@ pub enum Curve { Line(Line), } -impl Curve { +impl CurveKind { /// Construct a line from two points pub fn line_from_points(points: [impl Into>; 2]) -> Self { Self::Line(Line::from_points(points)) @@ -70,7 +110,7 @@ impl Curve { } } -impl Curve<2> { +impl CurveKind<2> { /// Construct a `Curve` that represents the u-axis pub fn u_axis() -> Self { Self::Line(Line { @@ -88,7 +128,7 @@ impl Curve<2> { } } -impl Curve<3> { +impl CurveKind<3> { /// Construct a `Curve` that represents the x-axis pub fn x_axis() -> Self { Self::Line(Line { @@ -112,13 +152,17 @@ impl Curve<3> { direction: Vector::unit_z(), }) } -} -impl fmt::Display for Curve { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// Transform the surface + #[must_use] + pub fn transform(self, transform: &Transform) -> Self { match self { - Self::Circle(curve) => write!(f, "{:?}", curve), - Self::Line(curve) => write!(f, "{:?}", curve), + CurveKind::Circle(curve) => { + CurveKind::Circle(transform.transform_circle(&curve)) + } + CurveKind::Line(curve) => { + CurveKind::Line(transform.transform_line(&curve)) + } } } } diff --git a/crates/fj-kernel/src/objects/edge.rs b/crates/fj-kernel/src/objects/edge.rs index a294f43d8..5acf0f229 100644 --- a/crates/fj-kernel/src/objects/edge.rs +++ b/crates/fj-kernel/src/objects/edge.rs @@ -1,13 +1,13 @@ use std::fmt; -use crate::{builder::EdgeBuilder, local::Local}; +use crate::builder::EdgeBuilder; use super::{Curve, Vertex}; /// An edge of a shape #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Edge { - curve: Local>, + curve: Curve, vertices: VerticesOfEdge, } @@ -18,7 +18,7 @@ impl Edge { } /// Create a new instance - pub fn new(curve: Local>, vertices: VerticesOfEdge) -> Self { + pub fn new(curve: Curve, vertices: VerticesOfEdge) -> Self { Self { curve, vertices } } @@ -27,7 +27,7 @@ impl Edge { /// The edge can be a segment of the curve that is bounded by two vertices, /// or if the curve is continuous (i.e. connects to itself), the edge could /// be defined by the whole curve, and have no bounding vertices. - pub fn curve(&self) -> &Local> { + pub fn curve(&self) -> &Curve { &self.curve } @@ -51,7 +51,7 @@ impl fmt::Display for Edge { None => write!(f, "continuous edge")?, } - write!(f, " on {}", self.curve().global_form())?; + write!(f, " on {:?}", self.curve().global())?; Ok(()) } diff --git a/crates/fj-kernel/src/objects/mod.rs b/crates/fj-kernel/src/objects/mod.rs index 48cb55b5c..61ac43142 100644 --- a/crates/fj-kernel/src/objects/mod.rs +++ b/crates/fj-kernel/src/objects/mod.rs @@ -14,7 +14,7 @@ mod surface; mod vertex; pub use self::{ - curve::Curve, + curve::{Curve, CurveKind, GlobalCurve}, cycle::Cycle, edge::{Edge, VerticesOfEdge}, face::Face, diff --git a/crates/fj-kernel/src/objects/surface.rs b/crates/fj-kernel/src/objects/surface.rs index a6e33252e..a911d0096 100644 --- a/crates/fj-kernel/src/objects/surface.rs +++ b/crates/fj-kernel/src/objects/surface.rs @@ -1,8 +1,6 @@ use fj_math::{Line, Point, Transform, Vector}; -use crate::algorithms::TransformObject; - -use super::Curve; +use super::CurveKind; /// A two-dimensional shape #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] @@ -15,7 +13,7 @@ impl Surface { /// Construct a `Surface` that represents the xy-plane pub fn xy_plane() -> Self { Self::SweptCurve(SweptCurve { - curve: Curve::x_axis(), + curve: CurveKind::x_axis(), path: Vector::unit_y(), }) } @@ -23,7 +21,7 @@ impl Surface { /// Construct a `Surface` that represents the xz-plane pub fn xz_plane() -> Self { Self::SweptCurve(SweptCurve { - curve: Curve::x_axis(), + curve: CurveKind::x_axis(), path: Vector::unit_z(), }) } @@ -31,7 +29,7 @@ impl Surface { /// Construct a `Surface` that represents the yz-plane pub fn yz_plane() -> Self { Self::SweptCurve(SweptCurve { - curve: Curve::y_axis(), + curve: CurveKind::y_axis(), path: Vector::unit_z(), }) } @@ -40,7 +38,7 @@ impl Surface { pub fn plane_from_points(points: [impl Into>; 3]) -> Self { let [a, b, c] = points.map(Into::into); - let curve = Curve::Line(Line::from_points([a, b])); + let curve = CurveKind::Line(Line::from_points([a, b])); let path = c - a; Self::SweptCurve(SweptCurve { curve, path }) @@ -83,7 +81,7 @@ impl Surface { #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct SweptCurve { /// The curve that this surface was swept from - pub curve: Curve<3>, + pub curve: CurveKind<3>, /// The path that the curve was swept along pub path: Vector<3>, @@ -138,14 +136,14 @@ mod tests { use fj_math::{Line, Point, Vector}; use pretty_assertions::assert_eq; - use crate::objects::Curve; + use crate::objects::CurveKind; use super::SweptCurve; #[test] fn reverse() { let original = SweptCurve { - curve: Curve::Line(Line { + curve: CurveKind::Line(Line { origin: Point::from([1., 0., 0.]), direction: Vector::from([0., 2., 0.]), }), @@ -155,7 +153,7 @@ mod tests { let reversed = original.reverse(); let expected = SweptCurve { - curve: Curve::Line(Line { + curve: CurveKind::Line(Line { origin: Point::from([1., 0., 0.]), direction: Vector::from([0., 2., 0.]), }), @@ -167,7 +165,7 @@ mod tests { #[test] fn point_from_surface_coords() { let swept = SweptCurve { - curve: Curve::Line(Line { + curve: CurveKind::Line(Line { origin: Point::from([1., 1., 1.]), direction: Vector::from([0., 2., 0.]), }), @@ -183,7 +181,7 @@ mod tests { #[test] fn vector_from_surface_coords() { let swept = SweptCurve { - curve: Curve::Line(Line { + curve: CurveKind::Line(Line { origin: Point::from([1., 0., 0.]), direction: Vector::from([0., 2., 0.]), }), diff --git a/crates/fj-kernel/src/objects/vertex.rs b/crates/fj-kernel/src/objects/vertex.rs index cc779f293..eacf355e5 100644 --- a/crates/fj-kernel/src/objects/vertex.rs +++ b/crates/fj-kernel/src/objects/vertex.rs @@ -61,7 +61,7 @@ pub struct GlobalVertex { } impl GlobalVertex { - /// Construct a `Vertex` from a point + /// Construct a `GlobalVertex` from a point pub fn from_position(position: impl Into>) -> Self { let position = position.into(); Self { position } diff --git a/crates/fj-kernel/src/validation/coherence.rs b/crates/fj-kernel/src/validation/coherence.rs index d584f06ba..9608d6360 100644 --- a/crates/fj-kernel/src/validation/coherence.rs +++ b/crates/fj-kernel/src/validation/coherence.rs @@ -19,7 +19,7 @@ pub fn validate_edge( for vertex in edge.vertices().iter() { let local = vertex.position(); let local_as_global = - edge.curve().global_form().point_from_curve_coords(local); + edge.curve().global().kind().point_from_curve_coords(local); let global = vertex.global().position(); let distance = (local_as_global - global).magnitude(); diff --git a/crates/fj-kernel/src/validation/mod.rs b/crates/fj-kernel/src/validation/mod.rs index aebcc2084..66d682def 100644 --- a/crates/fj-kernel/src/validation/mod.rs +++ b/crates/fj-kernel/src/validation/mod.rs @@ -130,8 +130,10 @@ mod tests { use fj_math::{Point, Scalar}; use crate::{ - local::Local, - objects::{Curve, Edge, GlobalVertex, Vertex, VerticesOfEdge}, + objects::{ + Curve, CurveKind, Edge, GlobalCurve, GlobalVertex, Vertex, + VerticesOfEdge, + }, validation::{validate, ValidationConfig, ValidationError}, }; @@ -141,9 +143,10 @@ mod tests { let b = Point::from([1., 0., 0.]); let curve = { - let curve_local = Curve::line_from_points([[0., 0.], [1., 0.]]); - let curve_canonical = Curve::line_from_points([a, b]); - Local::new(curve_local, curve_canonical) + let curve_local = CurveKind::line_from_points([[0., 0.], [1., 0.]]); + let curve_global = + GlobalCurve::from_kind(CurveKind::line_from_points([a, b])); + Curve::new(curve_local, curve_global) }; let a = GlobalVertex::from_position(a); diff --git a/crates/fj-operations/src/difference_2d.rs b/crates/fj-operations/src/difference_2d.rs index 46ce9e2c9..bc5aae3f2 100644 --- a/crates/fj-operations/src/difference_2d.rs +++ b/crates/fj-operations/src/difference_2d.rs @@ -2,8 +2,7 @@ use fj_interop::{debug::DebugInfo, mesh::Color}; use fj_kernel::{ algorithms::Tolerance, iter::ObjectIters, - local::Local, - objects::{Cycle, Edge, Face, Sketch}, + objects::{Curve, Cycle, Edge, Face, GlobalCurve, Sketch}, validation::{validate, Validated, ValidationConfig, ValidationError}, }; use fj_math::Aabb; @@ -94,16 +93,16 @@ fn add_cycle(cycle: Cycle, reverse: bool) -> Cycle { let mut edges = Vec::new(); for edge in cycle.edges() { let curve_local = if reverse { - edge.curve().local_form().reverse() + edge.curve().kind().reverse() } else { - *edge.curve().local_form() + *edge.curve().kind() }; - let curve_global = if reverse { - edge.curve().global_form().reverse() + let curve_global = GlobalCurve::from_kind(if reverse { + edge.curve().global().kind().reverse() } else { - *edge.curve().global_form() - }; + *edge.curve().global().kind() + }); let vertices = if reverse { edge.vertices().reverse() @@ -111,7 +110,7 @@ fn add_cycle(cycle: Cycle, reverse: bool) -> Cycle { *edge.vertices() }; - let edge = Edge::new(Local::new(curve_local, curve_global), vertices); + let edge = Edge::new(Curve::new(curve_local, curve_global), vertices); edges.push(edge); }