diff --git a/crates/fj-core/src/operations/build/edge.rs b/crates/fj-core/src/operations/build/edge.rs index dc6efe436..0fdda9d55 100644 --- a/crates/fj-core/src/operations/build/edge.rs +++ b/crates/fj-core/src/operations/build/edge.rs @@ -3,7 +3,7 @@ use fj_math::{Arc, Point, Scalar}; use crate::{ geometry::curve::Curve, - objects::{GlobalEdge, HalfEdge, Surface, Vertex}, + objects::{GlobalEdge, HalfEdge, Vertex}, operations::Insert, services::Services, }; @@ -75,18 +75,6 @@ pub trait BuildHalfEdge { HalfEdge::unjoined(curve, boundary, services) } - - /// Create a line segment from global points - fn line_segment_from_global_points( - points_global: [impl Into>; 2], - surface: &Surface, - boundary: Option<[Point<1>; 2]>, - services: &mut Services, - ) -> HalfEdge { - let points_surface = points_global - .map(|point| surface.geometry().project_global_point(point)); - HalfEdge::line_segment(points_surface, boundary, services) - } } impl BuildHalfEdge for HalfEdge {} diff --git a/crates/fj-core/src/operations/build/face.rs b/crates/fj-core/src/operations/build/face.rs index 91b02bfbc..5c8f0c810 100644 --- a/crates/fj-core/src/operations/build/face.rs +++ b/crates/fj-core/src/operations/build/face.rs @@ -1,11 +1,12 @@ +use std::array; + use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex}, operations::{ - BuildCycle, BuildHalfEdge, BuildSurface, Insert, IsInserted, - IsInsertedNo, + BuildCycle, BuildRegion, BuildSurface, Insert, IsInserted, IsInsertedNo, }, services::Services, storage::Handle, @@ -25,29 +26,24 @@ pub trait BuildFace { points: [impl Into>; 3], services: &mut Services, ) -> Polygon<3> { - let [a, b, c] = points.map(Into::into); - - let surface = Surface::plane_from_points([a, b, c]).insert(services); - let (exterior, edges, vertices) = { - let half_edges = [[a, b], [b, c], [c, a]].map(|points| { - let half_edge = HalfEdge::line_segment_from_global_points( - points, &surface, None, services, - ); + let (surface, points_surface) = Surface::plane_from_points(points); + let surface = surface.insert(services); - half_edge.insert(services) - }); - let vertices = half_edges - .each_ref_ext() - .map(|half_edge| half_edge.start_vertex().clone()); + let face = Face::polygon(surface, points_surface, services); - let cycle = Cycle::new(half_edges.clone()).insert(services); + let edges = { + let mut half_edges = face.region().exterior().half_edges().cloned(); + assert_eq!(half_edges.clone().count(), 3); - (cycle, half_edges, vertices) + array::from_fn(|_| half_edges.next()).map(|half_edge| { + half_edge + .expect("Just asserted that there are three half-edges") + }) }; - - let region = Region::new(exterior, [], None).insert(services); - - let face = Face::new(surface, region); + let vertices = + edges.each_ref_ext().map(|half_edge: &Handle| { + half_edge.start_vertex().clone() + }); Polygon { face, @@ -55,6 +51,21 @@ pub trait BuildFace { vertices, } } + + /// Build a polygon + fn polygon( + surface: Handle, + points: Ps, + services: &mut Services, + ) -> Face + where + P: Into>, + Ps: IntoIterator, + Ps::IntoIter: Clone + ExactSizeIterator, + { + let region = Region::polygon(points, services).insert(services); + Face::new(surface, region) + } } impl BuildFace for Face {} diff --git a/crates/fj-core/src/operations/build/surface.rs b/crates/fj-core/src/operations/build/surface.rs index bd7bab739..9e74f0fd2 100644 --- a/crates/fj-core/src/operations/build/surface.rs +++ b/crates/fj-core/src/operations/build/surface.rs @@ -1,4 +1,4 @@ -use fj_math::Point; +use fj_math::{Point, Scalar}; use crate::{ geometry::{curve::GlobalPath, surface::SurfaceGeometry}, @@ -8,15 +8,26 @@ use crate::{ /// Build a [`Surface`] pub trait BuildSurface { /// Build a plane from the provided points - fn plane_from_points(points: [impl Into>; 3]) -> Surface { + fn plane_from_points( + points: [impl Into>; 3], + ) -> (Surface, [Point<2>; 3]) { let [a, b, c] = points.map(Into::into); - let geometry = SurfaceGeometry { - u: GlobalPath::line_from_points([a, b]).0, - v: c - a, + let (u, u_line) = GlobalPath::line_from_points([a, b]); + let v = c - a; + + let geometry = SurfaceGeometry { u, v }; + let surface = Surface::new(geometry); + + let points_surface = { + let [a, b] = + u_line.map(|point| Point::from([point.t, Scalar::ZERO])); + let c = Point::from([a.u, Scalar::ONE]); + + [a, b, c] }; - Surface::new(geometry) + (surface, points_surface) } } diff --git a/crates/fj-core/src/validate/mod.rs b/crates/fj-core/src/validate/mod.rs index ea8ea3c45..27c8f601c 100644 --- a/crates/fj-core/src/validate/mod.rs +++ b/crates/fj-core/src/validate/mod.rs @@ -99,23 +99,23 @@ impl Default for ValidationConfig { #[derive(Clone, Debug, thiserror::Error)] pub enum ValidationError { /// `Cycle` validation error - #[error("`Cycle` validation error:\n {0}")] + #[error("`Cycle` validation error")] Cycle(#[from] CycleValidationError), /// `Face` validation error - #[error("`Face` validation error\n {0}")] + #[error("`Face` validation error")] Face(#[from] FaceValidationError), /// `HalfEdge` validation error - #[error("`HalfEdge` validation error\n {0}")] + #[error("`HalfEdge` validation error")] HalfEdge(#[from] HalfEdgeValidationError), /// `Shell` validation error - #[error("`Shell` validation error\n {0}")] + #[error("`Shell` validation error")] Shell(#[from] ShellValidationError), /// `Solid` validation error - #[error("`Solid` validation error\n {0}")] + #[error("`Solid` validation error")] Solid(#[from] SolidValidationError), }