diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs index 06d049cc2..76d839a07 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_face.rs @@ -188,8 +188,8 @@ mod tests { let face = { let mut face = PartialFace::default(); face.exterior.write().surface = surface; - face.update_exterior_as_polygon(exterior); - face.add_interior_polygon(interior); + face.update_exterior_as_polygon_from_points(exterior); + face.add_interior_polygon_from_points(interior); face.build(&mut services.objects) }; diff --git a/crates/fj-kernel/src/algorithms/intersect/face_face.rs b/crates/fj-kernel/src/algorithms/intersect/face_face.rs index adf9a5496..a8ba4668a 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_face.rs @@ -95,7 +95,7 @@ mod tests { .map(|surface| { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon(points); + face.update_exterior_as_polygon_from_points(points); face.build(&mut services.objects) }); @@ -124,7 +124,7 @@ mod tests { let [a, b] = surfaces.clone().map(|surface| { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon(points); + face.update_exterior_as_polygon_from_points(points); face.build(&mut services.objects) }); diff --git a/crates/fj-kernel/src/algorithms/intersect/face_point.rs b/crates/fj-kernel/src/algorithms/intersect/face_point.rs index 7e2c74c9f..c7192eb2e 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_point.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_point.rs @@ -149,7 +149,11 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([[0., 0.], [1., 1.], [0., 2.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [1., 1.], + [0., 2.], + ]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -166,7 +170,11 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([[0., 0.], [2., 1.], [0., 2.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [2., 1.], + [0., 2.], + ]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -186,7 +194,11 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([[4., 2.], [0., 4.], [0., 0.]]); + face.update_exterior_as_polygon_from_points([ + [4., 2.], + [0., 4.], + [0., 0.], + ]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -206,7 +218,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [0., 0.], [2., 1.], [3., 0.], @@ -231,7 +243,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [0., 0.], [2., 1.], [3., 1.], @@ -256,7 +268,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [0., 0.], [2., 1.], [3., 1.], @@ -282,7 +294,11 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([[0., 0.], [2., 0.], [0., 1.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [2., 0.], + [0., 1.], + ]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -312,7 +328,11 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([[0., 0.], [1., 0.], [0., 1.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [1., 0.], + [0., 1.], + ]); let face = face .build(&mut services.objects) .insert(&mut services.objects); diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index cb9572487..3391e7a18 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -167,7 +167,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.yz_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -190,7 +190,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.yz_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -216,7 +216,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.yz_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -239,7 +239,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.yz_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -274,7 +274,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.yz_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -308,7 +308,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], @@ -333,7 +333,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-1., -1.], [1., -1.], [1., 1.], diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index 799803854..65d0f298f 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -116,7 +116,7 @@ mod tests { let mut bottom = PartialFace::default(); bottom.exterior.write().surface = Partial::from(surface.clone()); - bottom.update_exterior_as_polygon(TRIANGLE); + bottom.update_exterior_as_polygon_from_points(TRIANGLE); let bottom = bottom .build(&mut services.objects) .insert(&mut services.objects) @@ -124,7 +124,7 @@ mod tests { let mut top = PartialFace::default(); top.exterior.write().surface = Partial::from(surface.translate(UP, &mut services.objects)); - top.update_exterior_as_polygon(TRIANGLE); + top.update_exterior_as_polygon_from_points(TRIANGLE); let top = top .build(&mut services.objects) .insert(&mut services.objects); @@ -169,14 +169,14 @@ mod tests { bottom.exterior.write().surface = Partial::from( surface.clone().translate(DOWN, &mut services.objects), ); - bottom.update_exterior_as_polygon(TRIANGLE); + bottom.update_exterior_as_polygon_from_points(TRIANGLE); let bottom = bottom .build(&mut services.objects) .insert(&mut services.objects) .reverse(&mut services.objects); let mut top = PartialFace::default(); top.exterior.write().surface = Partial::from(surface); - top.update_exterior_as_polygon(TRIANGLE); + top.update_exterior_as_polygon_from_points(TRIANGLE); let top = top .build(&mut services.objects) .insert(&mut services.objects); diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 695c7aad0..c252bb7fc 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -99,7 +99,7 @@ mod tests { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(services.objects.surfaces.xy_plane()); - face.update_exterior_as_polygon([a, b, c, d]); + face.update_exterior_as_polygon_from_points([a, b, c, d]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -136,8 +136,8 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface.clone()); - face.update_exterior_as_polygon([a, b, c, d]); - face.add_interior_polygon([e, f, g, h]); + face.update_exterior_as_polygon_from_points([a, b, c, d]); + face.add_interior_polygon_from_points([e, f, g, h]); let face = face .build(&mut services.objects) .insert(&mut services.objects); @@ -196,7 +196,7 @@ mod tests { let surface = services.objects.surfaces.xy_plane(); let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface.clone()); - face.update_exterior_as_polygon([a, b, c, d, e]); + face.update_exterior_as_polygon_from_points([a, b, c, d, e]); let face = face .build(&mut services.objects) .insert(&mut services.objects); diff --git a/crates/fj-kernel/src/builder/cycle.rs b/crates/fj-kernel/src/builder/cycle.rs index da31da187..68749a828 100644 --- a/crates/fj-kernel/src/builder/cycle.rs +++ b/crates/fj-kernel/src/builder/cycle.rs @@ -1,6 +1,7 @@ use fj_math::Point; use crate::{ + builder::SurfaceBuilder, objects::HalfEdge, partial::{Partial, PartialCycle}, }; @@ -9,17 +10,6 @@ use super::HalfEdgeBuilder; /// Builder API for [`PartialCycle`] pub trait CycleBuilder { - /// Create a cycle as a polygonal chain from the provided points - fn update_as_polygon_from_points( - &mut self, - points: impl IntoIterator>>, - ) -> Vec>; - - /// Update cycle to be a polygon - /// - /// Will update each half-edge in the cycle to be a line segment. - fn update_as_polygon(&mut self); - /// Add a new half-edge to the cycle /// /// Creates a half-edge and adds it to the cycle. The new half-edge is @@ -43,31 +33,35 @@ pub trait CycleBuilder { &mut self, point: impl Into>, ) -> Partial; -} -impl CycleBuilder for PartialCycle { + /// Update cycle as a polygon from the provided points fn update_as_polygon_from_points( &mut self, points: impl IntoIterator>>, - ) -> Vec> { - let mut half_edges = Vec::new(); - - for point in points { - let half_edge = self.add_half_edge_from_point_to_start(point); - half_edges.push(half_edge); - } - - self.update_as_polygon(); + ) -> Vec>; - half_edges - } + /// Update cycle as a polygon + /// + /// Will update each half-edge in the cycle to be a line segment. + fn update_as_polygon(&mut self); - fn update_as_polygon(&mut self) { - for half_edge in &mut self.half_edges { - half_edge.write().update_as_line_segment(); - } - } + /// Update cycle as a triangle, from global (3D) points + /// + /// Uses the three points to infer a plane that is used as the surface. + /// + /// # Implementation Note + /// + /// This method is probably just temporary, and will be generalized into a + /// "update as polygon from global points" method sooner or later. For now, + /// I didn't want to deal with the question of how to infer the surface, and + /// how to handle points that don't fit that surface. + fn update_as_triangle_from_global_points( + &mut self, + points: [impl Into>; 3], + ) -> [Partial; 3]; +} +impl CycleBuilder for PartialCycle { fn add_half_edge(&mut self) -> Partial { let mut new_half_edge = Partial::::new(); @@ -129,4 +123,46 @@ impl CycleBuilder for PartialCycle { half_edge } + + fn update_as_polygon_from_points( + &mut self, + points: impl IntoIterator>>, + ) -> Vec> { + let mut half_edges = Vec::new(); + + for point in points { + let half_edge = self.add_half_edge_from_point_to_start(point); + half_edges.push(half_edge); + } + + self.update_as_polygon(); + + half_edges + } + + fn update_as_polygon(&mut self) { + for half_edge in &mut self.half_edges { + half_edge.write().update_as_line_segment(); + } + } + + fn update_as_triangle_from_global_points( + &mut self, + points_global: [impl Into>; 3], + ) -> [Partial; 3] { + let points_surface = self + .surface + .write() + .update_as_plane_from_points(points_global); + let mut edges = self.update_as_polygon_from_points(points_surface); + + // None of the following should panic, as we just created a polygon from + // three points, so we should have exactly three edges. + let c = edges.pop().unwrap(); + let b = edges.pop().unwrap(); + let a = edges.pop().unwrap(); + assert!(edges.pop().is_none()); + + [a, b, c] + } } diff --git a/crates/fj-kernel/src/builder/face.rs b/crates/fj-kernel/src/builder/face.rs index bc1c49ee9..fb5e74f61 100644 --- a/crates/fj-kernel/src/builder/face.rs +++ b/crates/fj-kernel/src/builder/face.rs @@ -9,28 +9,59 @@ use super::CycleBuilder; /// Builder API for [`PartialFace`] pub trait FaceBuilder { - /// Update the [`PartialFace`] with an exterior polygon - fn update_exterior_as_polygon( + /// Update the face exterior as a polygon from the provided points + fn update_exterior_as_polygon_from_points( &mut self, points: impl IntoIterator>>, ) -> Vec>; - /// Update the [`PartialFace`] with an interior polygon - fn add_interior_polygon( + /// Update the face exterior as a polygon + fn update_exterior_as_polygon(&mut self); + + /// Update the face exterior as a triangle, from 3D points + /// + /// Uses the three points to infer a plane that is used as the surface. + /// + /// # Implementation Note + /// + /// This method is probably just temporary, and will be generalized into a + /// "update as polygon from global points" method sooner or later. For now, + /// I didn't want to deal with the question of how to infer the surface, and + /// how to handle points that don't fit that surface. + fn update_exterior_as_triangle_from_global_points( + &mut self, + points: [impl Into>; 3], + ) -> [Partial; 3]; + + /// Add an interior polygon, from the provided points + fn add_interior_polygon_from_points( &mut self, points: impl IntoIterator>>, ); } impl FaceBuilder for PartialFace { - fn update_exterior_as_polygon( + fn update_exterior_as_polygon_from_points( &mut self, points: impl IntoIterator>>, ) -> Vec> { self.exterior.write().update_as_polygon_from_points(points) } - fn add_interior_polygon( + fn update_exterior_as_polygon(&mut self) { + self.exterior.write().update_as_polygon() + } + + fn update_exterior_as_triangle_from_global_points( + &mut self, + points_global: [impl Into>; 3], + ) -> [Partial; 3] { + self.exterior + .write() + .update_as_triangle_from_global_points(points_global) + } + + fn add_interior_polygon_from_points( &mut self, points: impl IntoIterator>>, ) { diff --git a/crates/fj-kernel/src/builder/shell.rs b/crates/fj-kernel/src/builder/shell.rs index c673449b4..073d12fa1 100644 --- a/crates/fj-kernel/src/builder/shell.rs +++ b/crates/fj-kernel/src/builder/shell.rs @@ -55,7 +55,7 @@ impl ShellBuilder for PartialShell { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon([ + face.update_exterior_as_polygon_from_points([ [-h, -h], [h, -h], [h, h], diff --git a/crates/fj-kernel/src/builder/sketch.rs b/crates/fj-kernel/src/builder/sketch.rs index 1436ad2cd..57ca036fb 100644 --- a/crates/fj-kernel/src/builder/sketch.rs +++ b/crates/fj-kernel/src/builder/sketch.rs @@ -25,7 +25,7 @@ impl SketchBuilder for PartialSketch { ) { let mut face = PartialFace::default(); face.exterior.write().surface = surface.into(); - face.update_exterior_as_polygon(points); + face.update_exterior_as_polygon_from_points(points); self.faces.extend([Partial::from_partial(face)]); } diff --git a/crates/fj-kernel/src/validate/face.rs b/crates/fj-kernel/src/validate/face.rs index 893683beb..0effcee19 100644 --- a/crates/fj-kernel/src/validate/face.rs +++ b/crates/fj-kernel/src/validate/face.rs @@ -122,8 +122,16 @@ mod tests { let valid = { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon([[0., 0.], [3., 0.], [0., 3.]]); - face.add_interior_polygon([[1., 1.], [1., 2.], [2., 1.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [3., 0.], + [0., 3.], + ]); + face.add_interior_polygon_from_points([ + [1., 1.], + [1., 2.], + [2., 1.], + ]); face.build(&mut services.objects) }; @@ -154,8 +162,16 @@ mod tests { let valid = { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon([[0., 0.], [3., 0.], [0., 3.]]); - face.add_interior_polygon([[1., 1.], [1., 2.], [2., 1.]]); + face.update_exterior_as_polygon_from_points([ + [0., 0.], + [3., 0.], + [0., 3.], + ]); + face.add_interior_polygon_from_points([ + [1., 1.], + [1., 2.], + [2., 1.], + ]); face.build(&mut services.objects) }; let invalid = { diff --git a/crates/fj-operations/src/sketch.rs b/crates/fj-operations/src/sketch.rs index 61318cce6..4cd863d8e 100644 --- a/crates/fj-operations/src/sketch.rs +++ b/crates/fj-operations/src/sketch.rs @@ -64,7 +64,7 @@ impl Shape for fj::Sketch { let mut face = PartialFace::default(); face.exterior.write().surface = Partial::from(surface); - face.update_exterior_as_polygon(points); + face.update_exterior_as_polygon_from_points(points); face.color = Some(Color(self.color())); face