diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 34dc13c28e..8680fd8261 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -5,9 +5,7 @@ //! approximations are usually used to build cycle approximations, and this way, //! the caller doesn't have to call with duplicate vertices. -use fj_math::{Point, Scalar}; - -use crate::objects::{Edge, GlobalVertex, SurfaceVertex, Vertex}; +use crate::objects::Edge; use super::{ curve::{CurveApprox, RangeOnCurve}, @@ -18,60 +16,7 @@ impl Approx for &Edge { type Approximation = EdgeApprox; fn approx(self, tolerance: super::Tolerance) -> Self::Approximation { - // The range is only used for circles right now. - let [a, b] = match self.vertices().get() { - Some(vertices) => vertices.map(|&vertex| vertex), - None => { - // Creating vertices from nothing, just for the sake of - // approximation is a bit weird. But this code is a temporary - // fallback anyway. It'll do for now, and it will likely be - // removed soon. - - let start_curve = Point::from([Scalar::ZERO]); - let end_curve = Point::from([Scalar::TAU]); - - // We're dealing with a circle here. Start and end are identical - // points, in global coordinates. - let vertex_global = { - let point_global = self - .global_form() - .curve() - .kind() - .point_from_curve_coords(start_curve); - - GlobalVertex::from_position(point_global) - }; - - let [start_surface, end_surface] = [start_curve, end_curve] - .map(|point_curve| { - let point_surface = self - .curve() - .kind() - .point_from_curve_coords(point_curve); - SurfaceVertex::new( - point_surface, - *self.curve().surface(), - vertex_global, - ) - }); - - let a = Vertex::new( - start_curve, - *self.curve(), - start_surface, - vertex_global, - ); - let b = Vertex::new( - end_curve, - *self.curve(), - end_surface, - vertex_global, - ); - - [a, b] - } - }; - + let [a, b] = self.vertices().get().map(|&vertex| vertex); let range = RangeOnCurve::new([a, b]); let first = ApproxPoint::new( diff --git a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs index 8d66b84918..3fe4c2341c 100644 --- a/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/curve_edge.rs @@ -42,14 +42,9 @@ impl CurveEdgeIntersection { } }; - let edge_vertices = match edge.vertices().get() { - Some(vertices) => vertices.map(|vertex| { - edge_curve_as_line.point_from_line_coords(vertex.position()) - }), - None => todo!( - "Curve-edge intersection does not support continuous edges" - ), - }; + let edge_vertices = edge.vertices().get().map(|vertex| { + edge_curve_as_line.point_from_line_coords(vertex.position()) + }); Segment::from_points(edge_vertices) }; diff --git a/crates/fj-kernel/src/algorithms/intersect/face_point.rs b/crates/fj-kernel/src/algorithms/intersect/face_point.rs index b9d28ceef0..ecfe494709 100644 --- a/crates/fj-kernel/src/algorithms/intersect/face_point.rs +++ b/crates/fj-kernel/src/algorithms/intersect/face_point.rs @@ -45,13 +45,13 @@ impl Intersect for (&Face, &Point<2>) { ); } (Some(RaySegmentIntersection::RayStartsOnOnFirstVertex), _) => { - let vertex = *edge.vertices().get_or_panic()[0]; + let vertex = *edge.vertices().get()[0]; return Some( FacePointIntersection::PointIsOnVertex(vertex) ); } (Some(RaySegmentIntersection::RayStartsOnSecondVertex), _) => { - let vertex = *edge.vertices().get_or_panic()[1]; + let vertex = *edge.vertices().get()[1]; return Some( FacePointIntersection::PointIsOnVertex(vertex) ); @@ -237,7 +237,7 @@ mod tests { .edge_iter() .copied() .find(|edge| { - let [a, b] = edge.vertices().get_or_panic(); + let [a, b] = edge.vertices().get(); a.global_form().position() == Point::from([0., 0., 0.]) && b.global_form().position() == Point::from([2., 0., 0.]) }) diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs b/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs index e996d182fb..c39f38e095 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_edge.rs @@ -22,7 +22,7 @@ impl Intersect for (&HorizontalRayToTheRight<2>, &Edge) { } }; - let points = edge.vertices().get_or_panic().map(|vertex| { + let points = edge.vertices().get().map(|vertex| { let point = vertex.position(); line.point_from_line_coords(point) }); diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index 8ea88bf56f..74c8ae43f5 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -216,7 +216,7 @@ mod tests { .edge_iter() .copied() .find(|edge| { - let [a, b] = edge.vertices().get_or_panic(); + let [a, b] = edge.vertices().get(); a.global_form().position() == Point::from([1., 0., 1.]) && b.global_form().position() == Point::from([1., 0., -1.]) }) diff --git a/crates/fj-kernel/src/algorithms/reverse/face.rs b/crates/fj-kernel/src/algorithms/reverse/face.rs index 436a436d97..75ec2ae0e0 100644 --- a/crates/fj-kernel/src/algorithms/reverse/face.rs +++ b/crates/fj-kernel/src/algorithms/reverse/face.rs @@ -8,10 +8,6 @@ use super::Reverse; impl Reverse for Face { fn reverse(self) -> Self { - if self.triangles().is_some() { - panic!("Reversing tri-rep faces is not supported"); - } - let surface = self.surface().reverse(); let exteriors = reverse_local_coordinates_in_cycle(self.exteriors()); diff --git a/crates/fj-kernel/src/algorithms/sweep/curve.rs b/crates/fj-kernel/src/algorithms/sweep/curve.rs index 19b8e9c0b5..7278b68455 100644 --- a/crates/fj-kernel/src/algorithms/sweep/curve.rs +++ b/crates/fj-kernel/src/algorithms/sweep/curve.rs @@ -8,10 +8,9 @@ impl Sweep for Curve { fn sweep( self, path: impl Into, - tolerance: impl Into, color: fj_interop::mesh::Color, ) -> Self::Swept { - self.global_form().sweep(path, tolerance, color) + self.global_form().sweep(path, color) } } @@ -21,7 +20,6 @@ impl Sweep for GlobalCurve { fn sweep( self, path: impl Into, - _: impl Into, _: fj_interop::mesh::Color, ) -> Self::Swept { Surface::SweptCurve(SweptCurve { diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs index 46f6d6148c..9300729bcd 100644 --- a/crates/fj-kernel/src/algorithms/sweep/edge.rs +++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs @@ -1,15 +1,11 @@ use fj_interop::mesh::Color; -use fj_math::{Line, Scalar, Transform, Triangle}; +use fj_math::{Line, Scalar}; use crate::{ - algorithms::{ - approx::{Approx, Tolerance}, - reverse::Reverse, - transform::TransformObject, - }, + algorithms::{reverse::Reverse, transform::TransformObject}, objects::{ - Curve, CurveKind, Cycle, Edge, Face, GlobalEdge, Surface, - SurfaceVertex, Vertex, VerticesOfEdge, + Curve, CurveKind, Cycle, Edge, Face, GlobalEdge, SurfaceVertex, Vertex, + VerticesOfEdge, }, }; @@ -18,223 +14,169 @@ use super::{Path, Sweep}; impl Sweep for Edge { type Swept = Face; - fn sweep( - self, - path: impl Into, - tolerance: impl Into, - color: Color, - ) -> Self::Swept { + fn sweep(self, path: impl Into, color: Color) -> Self::Swept { let path = path.into(); - let tolerance = tolerance.into(); - - if self.vertices().get().is_some() { - let face = - create_non_continuous_side_face(&self, path, tolerance, color); - return face; - } - - create_continuous_side_face(self, path, tolerance, color) - } -} -fn create_non_continuous_side_face( - edge: &Edge, - path: Path, - tolerance: Tolerance, - color: Color, -) -> Face { - let edge = if path.is_negative_direction() { - edge.reverse_including_curve() - } else { - *edge - }; - - let surface = edge.curve().sweep(path, tolerance, color); - - // We can't use the edge we're sweeping from as the bottom edge, as that is - // not defined in the right surface. Let's create a new bottom edge, by - // swapping the surface of the original. - let bottom_edge = { - let vertices = edge.vertices().get_or_panic(); - - let points_curve_and_surface = vertices.map(|vertex| { - (vertex.position(), [vertex.position().t, Scalar::ZERO]) - }); - - let curve = { - // Please note that creating a line here is correct, even if the - // global curve is a circle. Projected into the side surface, it is - // going to be a line either way. - let kind = CurveKind::Line(Line::from_points_with_line_coords( - points_curve_and_surface, - )); - - Curve::new(surface, kind, *edge.curve().global_form()) + let edge = if path.is_negative_direction() { + self.reverse_including_curve() + } else { + self }; - let vertices = { - let points_surface = points_curve_and_surface - .map(|(_, point_surface)| point_surface); - - // Can be cleaned up, once `zip` is stable: - // https://doc.rust-lang.org/std/primitive.array.html#method.zip - let [a_vertex, b_vertex] = vertices; - let [a_surface, b_surface] = points_surface; - let vertices_with_surface_points = - [(a_vertex, a_surface), (b_vertex, b_surface)]; + let surface = edge.curve().sweep(path, color); + + // We can't use the edge we're sweeping from as the bottom edge, as that + // is not defined in the right surface. Let's create a new bottom edge, + // by swapping the surface of the original. + let bottom_edge = { + let vertices = edge.vertices().get(); + + let points_curve_and_surface = vertices.map(|vertex| { + (vertex.position(), [vertex.position().t, Scalar::ZERO]) + }); + + let curve = { + // Please note that creating a line here is correct, even if the + // global curve is a circle. Projected into the side surface, it is + // going to be a line either way. + let kind = CurveKind::Line(Line::from_points_with_line_coords( + points_curve_and_surface, + )); + + Curve::new(surface, kind, *edge.curve().global_form()) + }; + + let vertices = { + let points_surface = points_curve_and_surface + .map(|(_, point_surface)| point_surface); + + // Can be cleaned up, once `zip` is stable: + // https://doc.rust-lang.org/std/primitive.array.html#method.zip + let [a_vertex, b_vertex] = vertices; + let [a_surface, b_surface] = points_surface; + let vertices_with_surface_points = + [(a_vertex, a_surface), (b_vertex, b_surface)]; + + let vertices = vertices_with_surface_points.map( + |(vertex, point_surface)| { + let surface_vertex = SurfaceVertex::new( + point_surface, + surface, + *vertex.global_form(), + ); + + Vertex::new( + vertex.position(), + curve, + surface_vertex, + *vertex.global_form(), + ) + }, + ); + VerticesOfEdge::from_vertices(vertices) + }; + + Edge::new(curve, vertices, *edge.global_form()) + }; - let vertices = - vertices_with_surface_points.map(|(vertex, point_surface)| { - let surface_vertex = SurfaceVertex::new( + let side_edges = bottom_edge + .vertices() + .get() + .map(|&vertex| (vertex, surface).sweep(path, color)); + + let top_edge = { + let bottom_vertices = bottom_edge.vertices().get(); + + let global_vertices = side_edges.map(|edge| { + let [_, vertex] = edge.vertices().get(); + *vertex.global_form() + }); + + let points_curve_and_surface = bottom_vertices.map(|vertex| { + (vertex.position(), [vertex.position().t, Scalar::ONE]) + }); + + let curve = { + let global = + bottom_edge.curve().global_form().translate(path.inner()); + + // Please note that creating a line here is correct, even if the + // global curve is a circle. Projected into the side surface, it + // is going to be a line either way. + let kind = CurveKind::Line(Line::from_points_with_line_coords( + points_curve_and_surface, + )); + + Curve::new(surface, kind, global) + }; + + let global = { + GlobalEdge::new( + *curve.global_form(), + VerticesOfEdge::from_vertices(global_vertices), + ) + }; + + let vertices = { + let surface_points = points_curve_and_surface + .map(|(_, point_surface)| point_surface); + + // Can be cleaned up, once `zip` is stable: + // https://doc.rust-lang.org/std/primitive.array.html#method.zip + let [a_vertex, b_vertex] = bottom_vertices; + let [a_surface, b_surface] = surface_points; + let [a_global, b_global] = global_vertices; + let vertices = [ + (a_vertex, a_surface, a_global), + (b_vertex, b_surface, b_global), + ]; + + vertices.map(|(vertex, point_surface, vertex_global)| { + let vertex_surface = SurfaceVertex::new( point_surface, surface, - *vertex.global_form(), + vertex_global, ); - Vertex::new( vertex.position(), curve, - surface_vertex, - *vertex.global_form(), + vertex_surface, + vertex_global, ) - }); - VerticesOfEdge::from_vertices(vertices) - }; - - Edge::new(curve, vertices, *edge.global_form()) - }; - - let side_edges = bottom_edge - .vertices() - .get_or_panic() - .map(|&vertex| (vertex, surface).sweep(path, tolerance, color)); - - let top_edge = { - let bottom_vertices = bottom_edge.vertices().get_or_panic(); - - let global_vertices = side_edges.map(|edge| { - let [_, vertex] = edge.vertices().get_or_panic(); - *vertex.global_form() - }); - - let points_curve_and_surface = bottom_vertices.map(|vertex| { - (vertex.position(), [vertex.position().t, Scalar::ONE]) - }); + }) + }; - let curve = { - let global = - bottom_edge.curve().global_form().translate(path.inner()); - - // Please note that creating a line here is correct, even if the - // global curve is a circle. Projected into the side surface, it is - // going to be a line either way. - let kind = CurveKind::Line(Line::from_points_with_line_coords( - points_curve_and_surface, - )); - - Curve::new(surface, kind, global) - }; - - let global = { - GlobalEdge::new( - *curve.global_form(), - VerticesOfEdge::from_vertices(global_vertices), - ) - }; - - let vertices = { - let surface_points = points_curve_and_surface - .map(|(_, point_surface)| point_surface); - - // Can be cleaned up, once `zip` is stable: - // https://doc.rust-lang.org/std/primitive.array.html#method.zip - let [a_vertex, b_vertex] = bottom_vertices; - let [a_surface, b_surface] = surface_points; - let [a_global, b_global] = global_vertices; - let vertices = [ - (a_vertex, a_surface, a_global), - (b_vertex, b_surface, b_global), - ]; - - vertices.map(|(vertex, point_surface, vertex_global)| { - let vertex_surface = - SurfaceVertex::new(point_surface, surface, vertex_global); - Vertex::new( - vertex.position(), - curve, - vertex_surface, - vertex_global, - ) - }) + Edge::new(curve, VerticesOfEdge::from_vertices(vertices), global) }; - Edge::new(curve, VerticesOfEdge::from_vertices(vertices), global) - }; + let cycle = { + let a = bottom_edge; + let [d, b] = side_edges; + let c = top_edge; - let cycle = { - let a = bottom_edge; - let [d, b] = side_edges; - let c = top_edge; + let mut edges = [a, b, c, d]; - let mut edges = [a, b, c, d]; + // Make sure that edges are oriented correctly. + let mut i = 0; + while i < edges.len() { + let j = (i + 1) % edges.len(); - // Make sure that edges are oriented correctly. - let mut i = 0; - while i < edges.len() { - let j = (i + 1) % edges.len(); + let [_, prev_last] = edges[i].vertices().get(); + let [next_first, _] = edges[j].vertices().get(); - let [_, prev_last] = edges[i].vertices().get_or_panic(); - let [next_first, _] = edges[j].vertices().get_or_panic(); + // Need to compare surface forms here, as the global forms might + // be coincident when sweeping circles, despite the vertices + // being different! + if prev_last.surface_form() != next_first.surface_form() { + edges[j] = edges[j].reverse(); + } - // Need to compare surface forms here, as the global forms might be - // coincident when sweeping circles, despite the vertices being - // different! - if prev_last.surface_form() != next_first.surface_form() { - edges[j] = edges[j].reverse(); + i += 1; } - i += 1; - } - - Cycle::new(surface, edges) - }; - - Face::new(surface).with_exteriors([cycle]).with_color(color) -} - -fn create_continuous_side_face( - edge: Edge, - path: Path, - tolerance: Tolerance, - color: Color, -) -> Face { - let translation = Transform::translation(path.inner()); - - // This is definitely the wrong surface, but it shouldn't matter. Since this - // code will hopefully soon be gone anyway (this is the last piece of code - // that prevents us from removing triangle representation), it hopefully - // won't start to matter at some point either. - let placeholder = Surface::xy_plane(); - - let cycle = Cycle::new(placeholder, [edge]); - let approx = cycle.approx(tolerance); - - let mut quads = Vec::new(); - for segment in approx.segments() { - let [v0, v1] = segment.points(); - let [v3, v2] = { - let segment = translation.transform_segment(&segment); - segment.points() + Cycle::new(surface, edges) }; - quads.push([v0, v1, v2, v3]); + Face::new(surface).with_exteriors([cycle]).with_color(color) } - - let mut side_face: Vec<(Triangle<3>, _)> = Vec::new(); - for [v0, v1, v2, v3] in quads { - side_face.push(([v0, v1, v2].into(), color)); - side_face.push(([v0, v2, v3].into(), color)); - } - - Face::from_triangles(side_face) } diff --git a/crates/fj-kernel/src/algorithms/sweep/face.rs b/crates/fj-kernel/src/algorithms/sweep/face.rs index f34f47fd17..e048ddc34a 100644 --- a/crates/fj-kernel/src/algorithms/sweep/face.rs +++ b/crates/fj-kernel/src/algorithms/sweep/face.rs @@ -1,9 +1,7 @@ use fj_interop::mesh::Color; use crate::{ - algorithms::{ - approx::Tolerance, reverse::Reverse, transform::TransformObject, - }, + algorithms::{reverse::Reverse, transform::TransformObject}, objects::{Face, Shell}, }; @@ -12,14 +10,8 @@ use super::{Path, Sweep}; impl Sweep for Face { type Swept = Shell; - fn sweep( - self, - path: impl Into, - tolerance: impl Into, - color: Color, - ) -> Self::Swept { + fn sweep(self, path: impl Into, color: Color) -> Self::Swept { let path = path.into(); - let tolerance = tolerance.into(); let mut faces = Vec::new(); @@ -32,7 +24,7 @@ impl Sweep for Face { for cycle in self.all_cycles() { for edge in cycle.edges() { - let face = edge.sweep(path, tolerance, color); + let face = edge.sweep(path, color); faces.push(face); } } diff --git a/crates/fj-kernel/src/algorithms/sweep/mod.rs b/crates/fj-kernel/src/algorithms/sweep/mod.rs index ba5fa5df2a..07d6d883f9 100644 --- a/crates/fj-kernel/src/algorithms/sweep/mod.rs +++ b/crates/fj-kernel/src/algorithms/sweep/mod.rs @@ -9,20 +9,13 @@ mod vertex; use fj_interop::mesh::Color; use fj_math::{Scalar, Vector}; -use super::approx::Tolerance; - /// Sweep an object along a path to create another object pub trait Sweep { /// The object that is created by sweeping the implementing object type Swept; /// Sweep the object along the given path - fn sweep( - self, - path: impl Into, - tolerance: impl Into, - color: Color, - ) -> Self::Swept; + fn sweep(self, path: impl Into, color: Color) -> Self::Swept; } /// A path to be used with [`Sweep`] diff --git a/crates/fj-kernel/src/algorithms/sweep/sketch.rs b/crates/fj-kernel/src/algorithms/sweep/sketch.rs index 62dd9ff40a..f701a548f4 100644 --- a/crates/fj-kernel/src/algorithms/sweep/sketch.rs +++ b/crates/fj-kernel/src/algorithms/sweep/sketch.rs @@ -1,27 +1,18 @@ use fj_interop::mesh::Color; -use crate::{ - algorithms::approx::Tolerance, - objects::{Sketch, Solid}, -}; +use crate::objects::{Sketch, Solid}; use super::{Path, Sweep}; impl Sweep for Sketch { type Swept = Solid; - fn sweep( - self, - path: impl Into, - tolerance: impl Into, - color: Color, - ) -> Self::Swept { + fn sweep(self, path: impl Into, color: Color) -> Self::Swept { let path = path.into(); - let tolerance = tolerance.into(); let mut shells = Vec::new(); for face in self.into_faces() { - let shell = face.sweep(path, tolerance, color); + let shell = face.sweep(path, color); shells.push(shell); } @@ -32,10 +23,9 @@ impl Sweep for Sketch { #[cfg(test)] mod tests { use fj_interop::mesh::Color; - use fj_math::{Point, Scalar, Vector}; + use fj_math::{Point, Vector}; use crate::{ - algorithms::approx::Tolerance, iter::ObjectIters, objects::{Face, Sketch, Surface}, }; @@ -144,8 +134,6 @@ mod tests { expected_surfaces: impl IntoIterator>; 3]>, expected_vertices: impl IntoIterator>>, ) -> anyhow::Result<()> { - let tolerance = Tolerance::from_scalar(Scalar::ONE)?; - let surface = Surface::xy_plane(); let face = Face::build(surface).polygon_from_points([ [0., 0.], @@ -154,7 +142,7 @@ mod tests { ]); let sketch = Sketch::new().with_faces([face]); - let solid = sketch.sweep(direction, tolerance, Color([255, 0, 0, 255])); + let solid = sketch.sweep(direction, Color([255, 0, 0, 255])); let expected_vertices: Vec<_> = expected_vertices .into_iter() diff --git a/crates/fj-kernel/src/algorithms/sweep/vertex.rs b/crates/fj-kernel/src/algorithms/sweep/vertex.rs index d9c405824f..75e74bad9c 100644 --- a/crates/fj-kernel/src/algorithms/sweep/vertex.rs +++ b/crates/fj-kernel/src/algorithms/sweep/vertex.rs @@ -1,12 +1,9 @@ use fj_interop::mesh::Color; use fj_math::{Line, Point, Scalar}; -use crate::{ - algorithms::approx::Tolerance, - objects::{ - Curve, CurveKind, Edge, GlobalCurve, GlobalEdge, GlobalVertex, Surface, - SurfaceVertex, SweptCurve, Vertex, VerticesOfEdge, - }, +use crate::objects::{ + Curve, CurveKind, Edge, GlobalCurve, GlobalEdge, GlobalVertex, Surface, + SurfaceVertex, SweptCurve, Vertex, VerticesOfEdge, }; use super::{Path, Sweep}; @@ -14,12 +11,7 @@ use super::{Path, Sweep}; impl Sweep for (Vertex, Surface) { type Swept = Edge; - fn sweep( - self, - path: impl Into, - tolerance: impl Into, - color: Color, - ) -> Self::Swept { + fn sweep(self, path: impl Into, color: Color) -> Self::Swept { let (vertex, surface) = self; let path = path.into(); @@ -68,7 +60,7 @@ impl Sweep for (Vertex, Surface) { // With that out of the way, let's start by creating the `GlobalEdge`, // as that is the most straight-forward part of this operations, and // we're going to need it soon anyway. - let edge_global = vertex.global_form().sweep(path, tolerance, color); + let edge_global = vertex.global_form().sweep(path, color); // Next, let's compute the surface coordinates of the two vertices of // the output `Edge`, as we're going to need these for the rest of this @@ -99,7 +91,7 @@ impl Sweep for (Vertex, Surface) { // And now the vertices. Again, nothing wild here. let vertices = { - let vertices_global = edge_global.vertices().get_or_panic(); + let vertices_global = edge_global.vertices().get(); // Can be cleaned up, once `zip` is stable: // https://doc.rust-lang.org/std/primitive.array.html#method.zip @@ -143,12 +135,7 @@ impl Sweep for (Vertex, Surface) { impl Sweep for GlobalVertex { type Swept = GlobalEdge; - fn sweep( - self, - path: impl Into, - _: impl Into, - _: Color, - ) -> Self::Swept { + fn sweep(self, path: impl Into, _: Color) -> Self::Swept { let a = self; let b = GlobalVertex::from_position(self.position() + path.into().inner()); diff --git a/crates/fj-kernel/src/algorithms/transform.rs b/crates/fj-kernel/src/algorithms/transform.rs index 11e11683f0..46ca2a1578 100644 --- a/crates/fj-kernel/src/algorithms/transform.rs +++ b/crates/fj-kernel/src/algorithms/transform.rs @@ -65,17 +65,6 @@ impl TransformObject for Edge { impl TransformObject for Face { fn transform(self, transform: &Transform) -> Self { - if let Some(triangles) = self.triangles() { - let mut target = Vec::new(); - - for (triangle, color) in triangles.clone() { - let triangle = transform.transform_triangle(&triangle); - target.push((triangle, color)); - } - - return Self::from_triangles(target); - } - let surface = self.surface().transform(transform); let exteriors = transform_cycles(self.exteriors(), transform); diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 7927b97115..2355c4c611 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -62,13 +62,6 @@ impl Triangulate for Face { mesh: &mut Mesh>, debug_info: &mut DebugInfo, ) { - if let Some(triangles) = self.triangles() { - for &(triangle, color) in triangles { - mesh.push_triangle(triangle, color); - } - return; - } - let surface = self.surface(); let approx = self.approx(tolerance.into()); diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index 2379091bb5..c066076a05 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -36,7 +36,36 @@ impl EdgeBuilder { Curve::new(self.surface, local, global) }; - let vertices = VerticesOfEdge::none(); + let vertices = { + let [a_curve, b_curve] = + [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); + + let global_vertex = GlobalVertex::from_position( + curve.global_form().kind().point_from_curve_coords(a_curve), + ); + + let surface_vertices = [a_curve, b_curve].map(|point_curve| { + let point_surface = + curve.kind().point_from_curve_coords(point_curve); + SurfaceVertex::new(point_surface, self.surface, global_vertex) + }); + + // Can be cleaned up, once `zip` is stable: + // https://doc.rust-lang.org/std/primitive.array.html#method.zip + let [a_surface, b_surface] = surface_vertices; + let vertices = [(a_curve, a_surface), (b_curve, b_surface)].map( + |(point_curve, surface_vertex)| { + Vertex::new( + point_curve, + curve, + surface_vertex, + global_vertex, + ) + }, + ); + + VerticesOfEdge::from_vertices(vertices) + }; Edge::from_curve_and_vertices(curve, vertices) } diff --git a/crates/fj-kernel/src/iter.rs b/crates/fj-kernel/src/iter.rs index e20b9fa3f8..59697bbe5a 100644 --- a/crates/fj-kernel/src/iter.rs +++ b/crates/fj-kernel/src/iter.rs @@ -181,10 +181,6 @@ impl<'r> ObjectIters<'r> for Edge { impl<'r> ObjectIters<'r> for Face { fn referenced_objects(&'r self) -> Vec<&'r dyn ObjectIters> { - if self.triangles().is_some() { - return Vec::new(); - } - let mut objects = vec![self.surface() as &dyn ObjectIters]; for cycle in self.all_cycles() { diff --git a/crates/fj-kernel/src/objects/cycle.rs b/crates/fj-kernel/src/objects/cycle.rs index 3589f8b7d2..8a438c3f79 100644 --- a/crates/fj-kernel/src/objects/cycle.rs +++ b/crates/fj-kernel/src/objects/cycle.rs @@ -51,8 +51,8 @@ impl Cycle { // https://doc.rust-lang.org/std/primitive.slice.html#method.array_windows let [a, b] = [&edges[0], &edges[1]]; - let [_, prev] = a.vertices().get_or_panic(); - let [next, _] = b.vertices().get_or_panic(); + let [_, prev] = a.vertices().get(); + let [next, _] = b.vertices().get(); assert_eq!( prev.surface_form(), @@ -64,8 +64,8 @@ impl Cycle { // Verify that the edges form a cycle if let Some(first) = edges.first() { if let Some(last) = edges.last() { - let [first, _] = first.vertices().get_or_panic(); - let [_, last] = last.vertices().get_or_panic(); + let [first, _] = first.vertices().get(); + let [_, last] = last.vertices().get(); assert_eq!( first.surface_form(), diff --git a/crates/fj-kernel/src/objects/edge.rs b/crates/fj-kernel/src/objects/edge.rs index d1cb7bbf38..add7ae0019 100644 --- a/crates/fj-kernel/src/objects/edge.rs +++ b/crates/fj-kernel/src/objects/edge.rs @@ -43,13 +43,12 @@ impl Edge { // It is perfectly fine for global forms of the the vertices to be // coincident (in 3D space). That would just mean, that ends of the edge // connect to each other. - if let Some([a, b]) = vertices.get() { - assert_ne!( - a.position(), - b.position(), - "Vertices of an edge must not be coincident on curve" - ); - } + let [a, b] = vertices.get(); + assert_ne!( + a.position(), + b.position(), + "Vertices of an edge must not be coincident on curve" + ); Self { curve, @@ -80,8 +79,9 @@ impl Edge { /// we can't do that, until #695 is addressed: /// pub fn reverse_including_curve(self) -> Self { - let vertices = VerticesOfEdge(self.vertices.get().map(|[a, b]| { - [ + let vertices = { + let VerticesOfEdge([a, b]) = self.vertices; + VerticesOfEdge([ Vertex::new( -b.position(), b.curve().reverse(), @@ -94,8 +94,8 @@ impl Edge { *a.surface_form(), *a.global_form(), ), - ] - })); + ]) + }; Self::from_curve_and_vertices(self.curve().reverse(), vertices) } @@ -126,14 +126,8 @@ impl Edge { impl fmt::Display for Edge { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.vertices().0 { - Some(vertices) => { - let [a, b] = vertices.map(|vertex| vertex.position()); - write!(f, "edge from {:?} to {:?}", a, b)? - } - None => write!(f, "continuous edge")?, - } - + let [a, b] = self.vertices().0.map(|vertex| vertex.position()); + write!(f, "edge from {:?} to {:?}", a, b)?; write!(f, " on {:?}", self.curve().global_form())?; Ok(()) @@ -180,41 +174,25 @@ impl GlobalEdge { /// This struct is generic over the actual vertex type used, but typically, `T` /// will either be [`Vertex`] or [`GlobalVertex`]. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct VerticesOfEdge(Option<[T; 2]>); +pub struct VerticesOfEdge([T; 2]); impl VerticesOfEdge { /// Construct an instance of `VerticesOfEdge` from two vertices pub fn from_vertices(vertices: [T; 2]) -> Self { - Self(Some(vertices)) - } - - /// Construct an instance of `VerticesOfEdge` without vertices - pub fn none() -> Self { - Self(None) + Self(vertices) } /// Access the vertices - pub fn get(&self) -> Option<[&T; 2]> { - self.0.as_ref().map(|vertices| { - // Can be cleaned up once `each_ref` is stable: - // https://doc.rust-lang.org/std/primitive.array.html#method.each_ref - let [a, b] = vertices; - [a, b] - }) - } - - /// Access the two vertices - /// - /// # Panics - /// - /// Panics, if the edge has no vertices. - pub fn get_or_panic(&self) -> [&T; 2] { - self.get().expect("Expected edge to have vertices") + pub fn get(&self) -> [&T; 2] { + // Can be cleaned up once `each_ref` is stable: + // https://doc.rust-lang.org/std/primitive.array.html#method.each_ref + let [a, b] = &self.0; + [a, b] } /// Iterate over the vertices pub fn iter(&self) -> impl Iterator { - self.0.iter().flatten() + self.0.iter() } /// Map each vertex using the provided function @@ -226,11 +204,11 @@ impl VerticesOfEdge { } /// Convert each vertex using the provided function - pub fn convert(self, f: F) -> Option<[U; 2]> + pub fn convert(self, f: F) -> [U; 2] where F: FnMut(T) -> U, { - self.0.map(|vertices| vertices.map(f)) + self.0.map(f) } } @@ -239,7 +217,8 @@ impl VerticesOfEdge { /// /// Makes sure that the local coordinates are still correct. pub fn reverse(self) -> Self { - Self(self.0.map(|[a, b]| [b, a])) + let Self([a, b]) = self; + Self([b, a]) } /// Convert this instance into its global variant diff --git a/crates/fj-kernel/src/objects/face.rs b/crates/fj-kernel/src/objects/face.rs index b6ded2be2b..e0ecec6b3c 100644 --- a/crates/fj-kernel/src/objects/face.rs +++ b/crates/fj-kernel/src/objects/face.rs @@ -1,7 +1,6 @@ use std::collections::{btree_set, BTreeSet}; use fj_interop::mesh::Color; -use fj_math::Triangle; use crate::builder::FaceBuilder; @@ -47,7 +46,10 @@ impl<'a> IntoIterator for &'a Faces { /// A face of a shape #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Face { - representation: Representation, + surface: Surface, + exteriors: Vec, + interiors: Vec, + color: Color, } impl Face { @@ -62,26 +64,10 @@ impl Face { /// This can be overridden using the `with_` methods. pub fn new(surface: Surface) -> Self { Self { - representation: Representation::BRep(BRep { - surface, - exteriors: Vec::new(), - interiors: Vec::new(), - color: Color::default(), - }), - } - } - - /// Construct an instance that uses triangle representation - /// - /// Triangle representation is obsolete, and only still present because - /// there is one last place in the kernel code that uses it. Don't add any - /// more of those places! - /// - /// See this issue for more context: - /// - pub fn from_triangles(triangles: TriRep) -> Self { - Self { - representation: Representation::TriRep(triangles), + surface, + exteriors: Vec::new(), + interiors: Vec::new(), + color: Color::default(), } } @@ -103,7 +89,7 @@ impl Face { "Cycles that bound a face must be in face's surface" ); - self.brep_mut().exteriors.push(cycle); + self.exteriors.push(cycle); } self @@ -127,7 +113,7 @@ impl Face { "Cycles that bound a face must be in face's surface" ); - self.brep_mut().interiors.push(cycle); + self.interiors.push(cycle); } self @@ -137,25 +123,25 @@ impl Face { /// /// Consumes the face and returns the updated instance. pub fn with_color(mut self, color: Color) -> Self { - self.brep_mut().color = color; + self.color = color; self } /// Access this face's surface pub fn surface(&self) -> &Surface { - &self.brep().surface + &self.surface } /// Access the cycles that bound the face on the outside pub fn exteriors(&self) -> impl Iterator + '_ { - self.brep().exteriors.iter() + self.exteriors.iter() } /// Access the cycles that bound the face on the inside /// /// Each of these cycles defines a hole in the face. pub fn interiors(&self) -> impl Iterator + '_ { - self.brep().interiors.iter() + self.interiors.iter() } /// Access all cycles of this face @@ -168,57 +154,6 @@ impl Face { /// Access the color of the face pub fn color(&self) -> Color { - self.brep().color - } - - /// Access triangles, if this face uses triangle representation - /// - /// Only some faces still use triangle representation. At some point, none - /// will. This method exists as a workaround, while the transition is still - /// in progress. - pub fn triangles(&self) -> Option<&TriRep> { - if let Representation::TriRep(triangles) = &self.representation { - return Some(triangles); - } - - None - } - - /// Access the boundary representation of the face - fn brep(&self) -> &BRep { - if let Representation::BRep(face) = &self.representation { - return face; - } - - // No code that still uses triangle representation is calling this - // method. - unreachable!() + self.color } - - /// Access the boundary representation of the face mutably - fn brep_mut(&mut self) -> &mut BRep { - if let Representation::BRep(face) = &mut self.representation { - return face; - } - - // No code that still uses triangle representation is calling this - // method. - unreachable!() - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -enum Representation { - BRep(BRep), - TriRep(TriRep), } - -#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -struct BRep { - surface: Surface, - exteriors: Vec, - interiors: Vec, - color: Color, -} - -type TriRep = Vec<(Triangle<3>, Color)>; diff --git a/crates/fj-operations/src/sweep.rs b/crates/fj-operations/src/sweep.rs index 451cbe6b1f..3e052421a1 100644 --- a/crates/fj-operations/src/sweep.rs +++ b/crates/fj-operations/src/sweep.rs @@ -25,7 +25,7 @@ impl Shape for fj::Sweep { let path = Vector::from(self.path()); let color = self.shape().color(); - let solid = sketch.into_inner().sweep(path, tolerance, Color(color)); + let solid = sketch.into_inner().sweep(path, Color(color)); solid.validate_with_config(config) }