diff --git a/crates/fj-core/src/algorithms/approx/curve.rs b/crates/fj-core/src/algorithms/approx/curve.rs index de4ca250f..7f4c679a0 100644 --- a/crates/fj-core/src/algorithms/approx/curve.rs +++ b/crates/fj-core/src/algorithms/approx/curve.rs @@ -5,8 +5,8 @@ use std::collections::BTreeMap; use fj_math::Point; use crate::{ - geometry::{CurveBoundary, GlobalPath, SurfacePath}, - objects::{Curve, Surface}, + geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath}, + objects::Curve, storage::{Handle, HandleWrapper}, Core, }; @@ -17,7 +17,7 @@ impl Approx for ( &Handle, SurfacePath, - &Surface, + &SurfaceGeometry, CurveBoundary>, ) { @@ -51,7 +51,7 @@ impl Approx fn approx_curve( path: &SurfacePath, - surface: &Surface, + surface: &SurfaceGeometry, boundary: CurveBoundary>, tolerance: impl Into, core: &mut Core, @@ -62,63 +62,63 @@ fn approx_curve( // This will probably all be unified eventually, as `SurfacePath` and // `GlobalPath` grow APIs that are better suited to implementing this code // in a more abstract way. - let points = - match (path, surface.geometry().u) { - (SurfacePath::Circle(_), GlobalPath::Circle(_)) => { - todo!( + let points = match (path, surface.u) { + (SurfacePath::Circle(_), GlobalPath::Circle(_)) => { + todo!( "Approximating a circle on a curved surface not supported yet." ) + } + (SurfacePath::Circle(_), GlobalPath::Line(_)) => { + (path, boundary) + .approx_with_cache(tolerance, &mut (), core) + .into_iter() + .map(|(point_curve, point_surface)| { + // We're throwing away `point_surface` here, which is a + // bit weird, as we're recomputing it later (outside of + // this function). + // + // It should be fine though: + // + // 1. We're throwing this version away, so there's no + // danger of inconsistency between this and the later + // version. + // 2. This version should have been computed using the + // same path and parameters and the later version + // will be, so they should be the same anyway. + // 3. Not all other cases handled in this function have + // a surface point available, so it needs to be + // computed later anyway, in the general case. + + let point_global = + surface.point_from_surface_coords(point_surface); + (point_curve, point_global) + }) + .collect() + } + (SurfacePath::Line(line), _) => { + let range_u = + CurveBoundary::from(boundary.inner.map(|point_curve| { + [path.point_from_path_coords(point_curve).u] + })); + + let approx_u = (surface.u, range_u).approx_with_cache( + tolerance, + &mut (), + core, + ); + + let mut points = Vec::new(); + for (u, _) in approx_u { + let t = (u.t - line.origin().u) / line.direction().u; + let point_surface = path.point_from_path_coords([t]); + let point_global = + surface.point_from_surface_coords(point_surface); + points.push((u, point_global)); } - (SurfacePath::Circle(_), GlobalPath::Line(_)) => { - (path, boundary) - .approx_with_cache(tolerance, &mut (), core) - .into_iter() - .map(|(point_curve, point_surface)| { - // We're throwing away `point_surface` here, which is a - // bit weird, as we're recomputing it later (outside of - // this function). - // - // It should be fine though: - // - // 1. We're throwing this version away, so there's no - // danger of inconsistency between this and the later - // version. - // 2. This version should have been computed using the - // same path and parameters and the later version - // will be, so they should be the same anyway. - // 3. Not all other cases handled in this function have - // a surface point available, so it needs to be - // computed later anyway, in the general case. - - let point_global = surface - .geometry() - .point_from_surface_coords(point_surface); - (point_curve, point_global) - }) - .collect() - } - (SurfacePath::Line(line), _) => { - let range_u = - CurveBoundary::from(boundary.inner.map(|point_curve| { - [path.point_from_path_coords(point_curve).u] - })); - - let approx_u = (surface.geometry().u, range_u) - .approx_with_cache(tolerance, &mut (), core); - - let mut points = Vec::new(); - for (u, _) in approx_u { - let t = (u.t - line.origin().u) / line.direction().u; - let point_surface = path.point_from_path_coords([t]); - let point_global = surface - .geometry() - .point_from_surface_coords(point_surface); - points.push((u, point_global)); - } - - points - } - }; + + points + } + }; let points = points .into_iter() @@ -183,14 +183,14 @@ impl CurveApproxCache { #[cfg(test)] mod tests { - use std::{f64::consts::TAU, ops::Deref}; + use std::f64::consts::TAU; use pretty_assertions::assert_eq; use crate::{ algorithms::approx::{Approx, ApproxPoint}, geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath}, - objects::{Curve, Surface}, + objects::Curve, operations::insert::Insert, Core, }; @@ -203,10 +203,10 @@ mod tests { let (surface_path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); - let surface = core.layers.objects.surfaces.xz_plane(); + let surface = core.layers.objects.surfaces.xz_plane().geometry(); let tolerance = 1.; - let approx = (&curve, surface_path, surface.deref(), boundary) + let approx = (&curve, surface_path, &surface, boundary) .approx(tolerance, &mut core); assert_eq!(approx.points, vec![]); @@ -220,10 +220,10 @@ mod tests { let (surface_path, boundary) = SurfacePath::line_from_points([[1., 1.], [2., 1.]]); let boundary = CurveBoundary::from(boundary); - let surface = Surface::new(SurfaceGeometry { + let surface = SurfaceGeometry { u: GlobalPath::circle_from_radius(1.), v: [0., 0., 1.].into(), - }); + }; let tolerance = 1.; let approx = (&curve, surface_path, &surface, boundary) @@ -243,10 +243,10 @@ mod tests { ([TAU], [TAU, 1.]), ]); let boundary = CurveBoundary::from([[0.], [TAU]]); - let surface = Surface::new(SurfaceGeometry { + let surface = SurfaceGeometry { u: global_path, v: [0., 0., 1.].into(), - }); + }; let tolerance = 1.; let approx = (&curve, surface_path, &surface, boundary) @@ -259,7 +259,7 @@ mod tests { let point_surface = surface_path.point_from_path_coords(point_local); let point_global = - surface.geometry().point_from_surface_coords(point_surface); + surface.point_from_surface_coords(point_surface); ApproxPoint::new(point_local, point_global) }) .collect::>(); @@ -274,10 +274,10 @@ mod tests { let surface_path = SurfacePath::circle_from_center_and_radius([0., 0.], 1.); let boundary = CurveBoundary::from([[0.], [TAU]]); - let surface = core.layers.objects.surfaces.xz_plane(); + let surface = core.layers.objects.surfaces.xz_plane().geometry(); let tolerance = 1.; - let approx = (&curve, surface_path, surface.deref(), boundary) + let approx = (&curve, surface_path, &surface, boundary) .approx(tolerance, &mut core); let expected_approx = (&surface_path, boundary) @@ -287,7 +287,7 @@ mod tests { let point_surface = surface_path.point_from_path_coords(point_local); let point_global = - surface.geometry().point_from_surface_coords(point_surface); + surface.point_from_surface_coords(point_surface); ApproxPoint::new(point_local, point_global) }) .collect::>(); diff --git a/crates/fj-core/src/algorithms/approx/cycle.rs b/crates/fj-core/src/algorithms/approx/cycle.rs index e14f884d2..cfa546d7b 100644 --- a/crates/fj-core/src/algorithms/approx/cycle.rs +++ b/crates/fj-core/src/algorithms/approx/cycle.rs @@ -6,17 +6,14 @@ use std::ops::Deref; use fj_math::Segment; -use crate::{ - objects::{Cycle, Surface}, - Core, -}; +use crate::{geometry::SurfaceGeometry, objects::Cycle, Core}; use super::{ edge::{HalfEdgeApprox, HalfEdgeApproxCache}, Approx, ApproxPoint, Tolerance, }; -impl Approx for (&Cycle, &Surface) { +impl Approx for (&Cycle, &SurfaceGeometry) { type Approximation = CycleApprox; type Cache = HalfEdgeApproxCache; diff --git a/crates/fj-core/src/algorithms/approx/edge.rs b/crates/fj-core/src/algorithms/approx/edge.rs index 961944c0c..88decf722 100644 --- a/crates/fj-core/src/algorithms/approx/edge.rs +++ b/crates/fj-core/src/algorithms/approx/edge.rs @@ -5,17 +5,14 @@ //! approximations are usually used to build cycle approximations, and this way, //! the caller doesn't have to deal with duplicate vertices. -use crate::{ - objects::{HalfEdge, Surface}, - Core, -}; +use crate::{geometry::SurfaceGeometry, objects::HalfEdge, Core}; use super::{ curve::CurveApproxCache, vertex::VertexApproxCache, Approx, ApproxPoint, Tolerance, }; -impl Approx for (&HalfEdge, &Surface) { +impl Approx for (&HalfEdge, &SurfaceGeometry) { type Approximation = HalfEdgeApprox; type Cache = HalfEdgeApproxCache; @@ -33,9 +30,8 @@ impl Approx for (&HalfEdge, &Surface) { { Some(position) => position, None => { - let position_global = surface - .geometry() - .point_from_surface_coords(start_position_surface); + let position_global = + surface.point_from_surface_coords(start_position_surface); cache .start_position .insert(edge.start_vertex().clone(), position_global) diff --git a/crates/fj-core/src/algorithms/approx/face.rs b/crates/fj-core/src/algorithms/approx/face.rs index cbdb5f2a2..fa07879b1 100644 --- a/crates/fj-core/src/algorithms/approx/face.rs +++ b/crates/fj-core/src/algorithms/approx/face.rs @@ -91,12 +91,12 @@ impl Approx for &Face { // it have nothing to do with its curvature. let exterior = - (self.region().exterior().deref(), self.surface().deref()) + (self.region().exterior().deref(), &self.surface().geometry()) .approx_with_cache(tolerance, cache, core); let mut interiors = BTreeSet::new(); for cycle in self.region().interiors() { - let cycle = (cycle.deref(), self.surface().deref()) + let cycle = (cycle.deref(), &self.surface().geometry()) .approx_with_cache(tolerance, cache, core); interiors.insert(cycle); } diff --git a/crates/fj-core/src/algorithms/approx/mod.rs b/crates/fj-core/src/algorithms/approx/mod.rs index ad9ba4bf8..983368a6d 100644 --- a/crates/fj-core/src/algorithms/approx/mod.rs +++ b/crates/fj-core/src/algorithms/approx/mod.rs @@ -19,7 +19,7 @@ use std::{ use fj_math::Point; -use crate::{objects::Surface, Core}; +use crate::Core; pub use self::tolerance::{InvalidTolerance, Tolerance}; @@ -79,19 +79,6 @@ impl ApproxPoint { } } -impl ApproxPoint<2> { - /// Create an instance of `ApproxPoint` from a surface point - pub fn from_surface_point( - point_surface: impl Into>, - surface: &Surface, - ) -> Self { - let point_surface = point_surface.into(); - let point_global = - surface.geometry().point_from_surface_coords(point_surface); - ApproxPoint::new(point_surface, point_global) - } -} - impl Eq for ApproxPoint {} impl PartialEq for ApproxPoint { diff --git a/crates/fj-core/src/operations/sweep/cycle.rs b/crates/fj-core/src/operations/sweep/cycle.rs index 6b7c4b092..b64ec1860 100644 --- a/crates/fj-core/src/operations/sweep/cycle.rs +++ b/crates/fj-core/src/operations/sweep/cycle.rs @@ -2,7 +2,8 @@ use fj_interop::Color; use fj_math::Vector; use crate::{ - objects::{Cycle, Face, Surface}, + geometry::SurfaceGeometry, + objects::{Cycle, Face}, operations::{ build::BuildCycle, join::JoinCycle, sweep::half_edge::SweepHalfEdge, }, @@ -37,7 +38,7 @@ pub trait SweepCycle { /// operation is called in, and therefore falls outside of its scope. fn sweep_cycle( &self, - surface: &Surface, + surface: &SurfaceGeometry, color: Option, path: impl Into>, cache: &mut SweepCache, @@ -48,7 +49,7 @@ pub trait SweepCycle { impl SweepCycle for Cycle { fn sweep_cycle( &self, - surface: &Surface, + surface: &SurfaceGeometry, color: Option, path: impl Into>, cache: &mut SweepCache, diff --git a/crates/fj-core/src/operations/sweep/half_edge.rs b/crates/fj-core/src/operations/sweep/half_edge.rs index 6b1e6d3d1..00bae3ace 100644 --- a/crates/fj-core/src/operations/sweep/half_edge.rs +++ b/crates/fj-core/src/operations/sweep/half_edge.rs @@ -2,7 +2,8 @@ use fj_interop::{ext::ArrayExt, Color}; use fj_math::{Point, Scalar, Vector}; use crate::{ - objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex}, + geometry::SurfaceGeometry, + objects::{Cycle, Face, HalfEdge, Region, Vertex}, operations::{ build::{BuildCycle, BuildHalfEdge}, insert::Insert, @@ -37,7 +38,7 @@ pub trait SweepHalfEdge { fn sweep_half_edge( &self, end_vertex: Handle, - surface: &Surface, + surface: &SurfaceGeometry, color: Option, path: impl Into>, cache: &mut SweepCache, @@ -49,7 +50,7 @@ impl SweepHalfEdge for HalfEdge { fn sweep_half_edge( &self, end_vertex: Handle, - surface: &Surface, + surface: &SurfaceGeometry, color: Option, path: impl Into>, cache: &mut SweepCache, diff --git a/crates/fj-core/src/operations/sweep/path.rs b/crates/fj-core/src/operations/sweep/path.rs index 06bf9b9ae..f4f57cde4 100644 --- a/crates/fj-core/src/operations/sweep/path.rs +++ b/crates/fj-core/src/operations/sweep/path.rs @@ -23,7 +23,7 @@ pub trait SweepSurfacePath { /// fn sweep_surface_path( &self, - surface: &Surface, + surface: &SurfaceGeometry, path: impl Into>, ) -> Surface; } @@ -31,10 +31,10 @@ pub trait SweepSurfacePath { impl SweepSurfacePath for SurfacePath { fn sweep_surface_path( &self, - surface: &Surface, + surface: &SurfaceGeometry, path: impl Into>, ) -> Surface { - match surface.geometry().u { + match surface.u { GlobalPath::Circle(_) => { // Sweeping a `Curve` creates a `Surface`. The u-axis of that // `Surface` is a `GlobalPath`, which we are computing below. @@ -60,24 +60,18 @@ impl SweepSurfacePath for SurfacePath { let u = match self { SurfacePath::Circle(circle) => { - let center = surface - .geometry() - .point_from_surface_coords(circle.center()); - let a = - surface.geometry().vector_from_surface_coords(circle.a()); - let b = - surface.geometry().vector_from_surface_coords(circle.b()); + let center = surface.point_from_surface_coords(circle.center()); + let a = surface.vector_from_surface_coords(circle.a()); + let b = surface.vector_from_surface_coords(circle.b()); let circle = Circle::new(center, a, b); GlobalPath::Circle(circle) } SurfacePath::Line(line) => { - let origin = - surface.geometry().point_from_surface_coords(line.origin()); - let direction = surface - .geometry() - .vector_from_surface_coords(line.direction()); + let origin = surface.point_from_surface_coords(line.origin()); + let direction = + surface.vector_from_surface_coords(line.direction()); let line = Line::from_origin_and_direction(origin, direction); diff --git a/crates/fj-core/src/operations/sweep/region.rs b/crates/fj-core/src/operations/sweep/region.rs index 88600bd57..78cd701d0 100644 --- a/crates/fj-core/src/operations/sweep/region.rs +++ b/crates/fj-core/src/operations/sweep/region.rs @@ -2,6 +2,7 @@ use fj_interop::Color; use fj_math::Vector; use crate::{ + geometry::SurfaceGeometry, objects::{Cycle, Face, Region, Surface}, operations::{ insert::Insert, reverse::Reverse, transform::TransformObject, @@ -54,7 +55,7 @@ impl SweepRegion for Region { let top_exterior = sweep_cycle( self.exterior(), - surface, + &surface.geometry(), color, &mut faces, path, @@ -68,7 +69,7 @@ impl SweepRegion for Region { .map(|bottom_cycle| { sweep_cycle( bottom_cycle, - surface, + &surface.geometry(), color, &mut faces, path, @@ -95,7 +96,7 @@ impl SweepRegion for Region { fn sweep_cycle( bottom_cycle: &Cycle, - bottom_surface: &Surface, + bottom_surface: &SurfaceGeometry, color: Option, faces: &mut Vec, path: Vector<3>, diff --git a/crates/fj-core/src/validate/shell.rs b/crates/fj-core/src/validate/shell.rs index b9b9b45f0..25764efe2 100644 --- a/crates/fj-core/src/validate/shell.rs +++ b/crates/fj-core/src/validate/shell.rs @@ -4,7 +4,7 @@ use fj_math::{Point, Scalar}; use crate::{ geometry::{CurveBoundary, SurfaceGeometry}, - objects::{Curve, HalfEdge, Shell, Surface, Vertex}, + objects::{Curve, HalfEdge, Shell, Vertex}, queries::{ AllHalfEdgesWithSurface, BoundingVerticesOfHalfEdge, SiblingOfHalfEdge, }, @@ -95,9 +95,9 @@ impl ShellValidationError { fn compare_curve_coords( edge_a: &Handle, - surface_a: &Handle, + surface_a: &SurfaceGeometry, edge_b: &Handle, - surface_b: &Handle, + surface_b: &SurfaceGeometry, config: &ValidationConfig, mismatches: &mut Vec, ) { @@ -115,12 +115,10 @@ impl ShellValidationError { let b_surface = edge_b.path().point_from_path_coords(point_curve); - let a_global = surface_a - .geometry() - .point_from_surface_coords(a_surface); - let b_global = surface_b - .geometry() - .point_from_surface_coords(b_surface); + let a_global = + surface_a.point_from_surface_coords(a_surface); + let b_global = + surface_b.point_from_surface_coords(b_surface); let distance = (a_global - b_global).magnitude(); @@ -141,17 +139,17 @@ impl ShellValidationError { compare_curve_coords( edge_a, - surface_a, + &surface_a.geometry(), edge_b, - surface_b, + &surface_b.geometry(), config, &mut mismatches, ); compare_curve_coords( edge_b, - surface_b, + &surface_b.geometry(), edge_a, - surface_a, + &surface_a.geometry(), config, &mut mismatches, ); @@ -237,9 +235,9 @@ impl ShellValidationError { // `distinct_min_distance`, that's a problem. if distances( half_edge_a.clone(), - surface_a.clone(), + &surface_a.geometry(), half_edge_b.clone(), - surface_b.clone(), + &surface_b.geometry(), ) .all(|d| d < config.distinct_min_distance) { @@ -361,13 +359,13 @@ impl fmt::Display for CoincidentHalfEdgeVertices { /// Returns an [`Iterator`] of the distance at each sample. fn distances( edge_a: Handle, - surface_a: Handle, + surface_a: &SurfaceGeometry, edge_b: Handle, - surface_b: Handle, + surface_b: &SurfaceGeometry, ) -> impl Iterator { fn sample( percent: f64, - (edge, surface): (&Handle, SurfaceGeometry), + (edge, surface): (&Handle, &SurfaceGeometry), ) -> Point<3> { let [start, end] = edge.boundary().inner; let path_coords = start + (end - start) * percent; @@ -384,8 +382,8 @@ fn distances( let mut distances = Vec::new(); for i in 0..sample_count { let percent = i as f64 * step; - let sample1 = sample(percent, (&edge_a, surface_a.geometry())); - let sample2 = sample(1.0 - percent, (&edge_b, surface_b.geometry())); + let sample1 = sample(percent, (&edge_a, surface_a)); + let sample2 = sample(1.0 - percent, (&edge_b, surface_b)); distances.push(sample1.distance_to(&sample2)) } distances.into_iter()