diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs deleted file mode 100644 index 21d4d05df..000000000 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ /dev/null @@ -1,332 +0,0 @@ -//! Curve approximation -//! -//! Since curves are infinite (even circles have an infinite coordinate space, -//! even though they connect to themselves in global coordinates), a range must -//! be provided to approximate them. The approximation then returns points -//! within that range. -//! -//! The boundaries of the range are not included in the approximation. This is -//! done, to give the caller (who knows the boundary anyway) more options on how -//! to further process the approximation. - -use std::collections::BTreeMap; - -use crate::{ - geometry::path::{GlobalPath, SurfacePath}, - objects::{Curve, GlobalCurve, Surface}, - storage::{Handle, ObjectId}, -}; - -use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance}; - -impl Approx for (&Handle, &Surface, Handle, RangeOnPath) { - type Approximation = CurveApprox; - type Cache = CurveCache; - - fn approx_with_cache( - self, - tolerance: impl Into, - cache: &mut Self::Cache, - ) -> Self::Approximation { - let (curve, surface, global_curve, range) = self; - - let global_curve_approx = match cache.get(global_curve.clone(), range) { - Some(approx) => approx, - None => { - let approx = - approx_global_curve(curve, surface, range, tolerance); - cache.insert(global_curve, range, approx) - } - }; - - CurveApprox::empty().with_points( - global_curve_approx.points.into_iter().map(|point| { - let point_surface = - curve.path().point_from_path_coords(point.local_form); - - ApproxPoint::new(point_surface, point.global_form) - .with_source((curve.clone(), point.local_form)) - }), - ) - } -} - -fn approx_global_curve( - curve: &Curve, - surface: &Surface, - range: RangeOnPath, - tolerance: impl Into, -) -> GlobalCurveApprox { - // There are different cases of varying complexity. Circles are the hard - // part here, as they need to be approximated, while lines don't need to be. - // - // 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 (curve.path(), surface.geometry().u) { - (SurfacePath::Circle(_), GlobalPath::Circle(_)) => { - todo!( - "Approximating a circle on a curved surface not supported yet." - ) - } - (SurfacePath::Circle(_), GlobalPath::Line(_)) => { - (curve.path(), range) - .approx_with_cache(tolerance, &mut ()) - .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 = - RangeOnPath::from(range.boundary.map(|point_curve| { - [curve.path().point_from_path_coords(point_curve).u] - })); - - let approx_u = (surface.geometry().u, range_u) - .approx_with_cache(tolerance, &mut ()); - - let mut points = Vec::new(); - for (u, _) in approx_u { - let t = (u.t - line.origin().u) / line.direction().u; - let point_surface = curve.path().point_from_path_coords([t]); - let point_global = - surface.geometry().point_from_surface_coords(point_surface); - points.push((u, point_global)); - } - - points - } - }; - - let points = points - .into_iter() - .map(|(point_curve, point_global)| { - ApproxPoint::new(point_curve, point_global) - }) - .collect(); - GlobalCurveApprox { points } -} - -/// An approximation of a [`Curve`] -#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct CurveApprox { - /// The points that approximate the curve - pub points: Vec>, -} - -impl CurveApprox { - /// Create an empty instance of `CurveApprox` - pub fn empty() -> Self { - Self { points: Vec::new() } - } - - /// Add points to the approximation - pub fn with_points( - mut self, - points: impl IntoIterator>, - ) -> Self { - self.points.extend(points); - self - } -} - -/// A cache for results of an approximation -#[derive(Default)] -pub struct CurveCache { - inner: BTreeMap<(ObjectId, RangeOnPath), GlobalCurveApprox>, -} - -impl CurveCache { - /// Create an empty cache - pub fn new() -> Self { - Self::default() - } - - /// Insert the approximation of a [`GlobalCurve`] - pub fn insert( - &mut self, - handle: Handle, - range: RangeOnPath, - approx: GlobalCurveApprox, - ) -> GlobalCurveApprox { - self.inner.insert((handle.id(), range), approx.clone()); - approx - } - - /// Access the approximation for the given [`GlobalCurve`], if available - pub fn get( - &self, - handle: Handle, - range: RangeOnPath, - ) -> Option { - if let Some(approx) = self.inner.get(&(handle.id(), range)) { - return Some(approx.clone()); - } - if let Some(approx) = self.inner.get(&(handle.id(), range.reverse())) { - // If we have a cache entry for the reverse range, we need to use - // that too! - return Some(approx.clone().reverse()); - } - - None - } -} - -/// An approximation of a [`GlobalCurve`] -#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct GlobalCurveApprox { - /// The points that approximate the curve - pub points: Vec>, -} - -impl GlobalCurveApprox { - /// Reverse the order of the approximation - pub fn reverse(mut self) -> Self { - self.points.reverse(); - self - } -} - -#[cfg(test)] -mod tests { - use std::{f64::consts::TAU, ops::Deref}; - - use pretty_assertions::assert_eq; - - use crate::{ - algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint}, - builder::{CurveBuilder, SurfaceBuilder}, - geometry::path::GlobalPath, - insert::Insert, - objects::GlobalCurve, - partial::{PartialCurve, PartialObject, PartialSurface}, - services::Services, - }; - - use super::CurveApprox; - - #[test] - fn approx_line_on_flat_surface() { - let mut services = Services::new(); - - let surface = services.objects.surfaces.xz_plane(); - let mut curve = PartialCurve::default(); - curve.update_as_line_from_points([[1., 1.], [2., 1.]]); - let curve = curve - .build(&mut services.objects) - .insert(&mut services.objects); - let global_curve = GlobalCurve.insert(&mut services.objects); - let range = RangeOnPath::from([[0.], [1.]]); - - let approx = (&curve, surface.deref(), global_curve, range).approx(1.); - - assert_eq!(approx, CurveApprox::empty()); - } - - #[test] - fn approx_line_on_curved_surface_but_not_along_curve() { - let mut services = Services::new(); - - let surface = PartialSurface::from_axes( - GlobalPath::circle_from_radius(1.), - [0., 0., 1.], - ) - .build(&mut services.objects) - .insert(&mut services.objects); - let mut curve = PartialCurve::default(); - curve.update_as_line_from_points([[1., 1.], [1., 2.]]); - let curve = curve - .build(&mut services.objects) - .insert(&mut services.objects); - let global_curve = GlobalCurve.insert(&mut services.objects); - let range = RangeOnPath::from([[0.], [1.]]); - - let approx = (&curve, surface.deref(), global_curve, range).approx(1.); - - assert_eq!(approx, CurveApprox::empty()); - } - - #[test] - fn approx_line_on_curved_surface_along_curve() { - let mut services = Services::new(); - - let path = GlobalPath::circle_from_radius(1.); - let surface = PartialSurface::from_axes(path, [0., 0., 1.]) - .build(&mut services.objects) - .insert(&mut services.objects); - let mut curve = PartialCurve::default(); - curve.update_as_line_from_points([[0., 1.], [1., 1.]]); - let curve = curve - .build(&mut services.objects) - .insert(&mut services.objects); - let global_curve = GlobalCurve.insert(&mut services.objects); - - let range = RangeOnPath::from([[0.], [TAU]]); - let tolerance = 1.; - - let approx = - (&curve, surface.deref(), global_curve, range).approx(tolerance); - - let expected_approx = (path, range) - .approx(tolerance) - .into_iter() - .map(|(point_local, _)| { - let point_surface = - curve.path().point_from_path_coords(point_local); - let point_global = - surface.geometry().point_from_surface_coords(point_surface); - ApproxPoint::new(point_surface, point_global) - }) - .collect::>(); - assert_eq!(approx.points, expected_approx); - } - - #[test] - fn approx_circle_on_flat_surface() { - let mut services = Services::new(); - - let surface = services.objects.surfaces.xz_plane(); - let mut curve = PartialCurve::default(); - curve.update_as_circle_from_radius(1.); - let curve = curve - .build(&mut services.objects) - .insert(&mut services.objects); - let global_curve = GlobalCurve.insert(&mut services.objects); - - let range = RangeOnPath::from([[0.], [TAU]]); - let tolerance = 1.; - let approx = - (&curve, surface.deref(), global_curve, range).approx(tolerance); - - let expected_approx = (curve.path(), range) - .approx(tolerance) - .into_iter() - .map(|(_, point_surface)| { - let point_global = - surface.geometry().point_from_surface_coords(point_surface); - ApproxPoint::new(point_surface, point_global) - }) - .collect::>(); - assert_eq!(approx.points, expected_approx); - } -} diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 02c404311..5b8b54da0 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -7,12 +7,13 @@ use fj_math::Segment; use crate::objects::{Cycle, Surface}; use super::{ - curve::CurveCache, edge::HalfEdgeApprox, Approx, ApproxPoint, Tolerance, + edge::{EdgeCache, HalfEdgeApprox}, + Approx, ApproxPoint, Tolerance, }; impl Approx for (&Cycle, &Surface) { type Approximation = CycleApprox; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 9d3226b24..db834a594 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -5,20 +5,19 @@ //! approximations are usually used to build cycle approximations, and this way, //! the caller doesn't have to call with duplicate vertices. +use std::collections::BTreeMap; + use crate::{ - objects::{HalfEdge, Surface}, - storage::Handle, + geometry::path::{GlobalPath, SurfacePath}, + objects::{Curve, GlobalEdge, HalfEdge, Surface}, + storage::{Handle, ObjectId}, }; -use super::{ - curve::{CurveApprox, CurveCache}, - path::RangeOnPath, - Approx, ApproxPoint, Tolerance, -}; +use super::{path::RangeOnPath, Approx, ApproxPoint, Tolerance}; impl Approx for (&Handle, &Surface) { type Approximation = HalfEdgeApprox; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, @@ -35,29 +34,52 @@ impl Approx for (&Handle, &Surface) { half_edge.start_vertex().global_form().position(), ) .with_source((half_edge.clone(), half_edge.boundary()[0])); - let curve_approx = ( - half_edge.curve(), - surface, - half_edge.global_form().curve().clone(), - range, - ) - .approx_with_cache(tolerance, cache); - HalfEdgeApprox { - first, - curve_approx, - } + let points = { + let approx = match cache.get(half_edge.global_form().clone(), range) + { + Some(approx) => approx, + None => { + let approx = approx_edge( + half_edge.curve(), + surface, + range, + tolerance, + ); + cache.insert(half_edge.global_form().clone(), range, approx) + } + }; + + approx + .points + .into_iter() + .map(|point| { + let point_surface = half_edge + .curve() + .path() + .point_from_path_coords(point.local_form); + + ApproxPoint::new(point_surface, point.global_form) + .with_source(( + half_edge.curve().clone(), + point.local_form, + )) + }) + .collect() + }; + + HalfEdgeApprox { first, points } } } /// An approximation of an [`HalfEdge`] #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct HalfEdgeApprox { - /// The point that approximates the first vertex of the curve + /// The point that approximates the first vertex of the edge pub first: ApproxPoint<2>, - /// The approximation of the edge's curve - pub curve_approx: CurveApprox, + /// The approximation of the edge + pub points: Vec>, } impl HalfEdgeApprox { @@ -66,8 +88,283 @@ impl HalfEdgeApprox { let mut points = Vec::new(); points.push(self.first.clone()); - points.extend(self.curve_approx.points.clone()); + points.extend(self.points.iter().cloned()); points } } + +fn approx_edge( + curve: &Curve, + surface: &Surface, + range: RangeOnPath, + tolerance: impl Into, +) -> GlobalEdgeApprox { + // There are different cases of varying complexity. Circles are the hard + // part here, as they need to be approximated, while lines don't need to be. + // + // 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 (curve.path(), surface.geometry().u) { + (SurfacePath::Circle(_), GlobalPath::Circle(_)) => { + todo!( + "Approximating a circle on a curved surface not supported yet." + ) + } + (SurfacePath::Circle(_), GlobalPath::Line(_)) => { + (curve.path(), range) + .approx_with_cache(tolerance, &mut ()) + .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 = + RangeOnPath::from(range.boundary.map(|point_curve| { + [curve.path().point_from_path_coords(point_curve).u] + })); + + let approx_u = (surface.geometry().u, range_u) + .approx_with_cache(tolerance, &mut ()); + + let mut points = Vec::new(); + for (u, _) in approx_u { + let t = (u.t - line.origin().u) / line.direction().u; + let point_surface = curve.path().point_from_path_coords([t]); + let point_global = + surface.geometry().point_from_surface_coords(point_surface); + points.push((u, point_global)); + } + + points + } + }; + + let points = points + .into_iter() + .map(|(point_curve, point_global)| { + ApproxPoint::new(point_curve, point_global) + }) + .collect(); + GlobalEdgeApprox { points } +} + +/// A cache for results of an approximation +#[derive(Default)] +pub struct EdgeCache { + inner: BTreeMap<(ObjectId, RangeOnPath), GlobalEdgeApprox>, +} + +impl EdgeCache { + /// Create an empty cache + pub fn new() -> Self { + Self::default() + } + + /// Insert the approximation of a [`GlobalEdge`] + pub fn insert( + &mut self, + handle: Handle, + range: RangeOnPath, + approx: GlobalEdgeApprox, + ) -> GlobalEdgeApprox { + self.inner.insert((handle.id(), range), approx.clone()); + approx + } + + /// Access the approximation for the given [`GlobalEdge`], if available + pub fn get( + &self, + handle: Handle, + range: RangeOnPath, + ) -> Option { + if let Some(approx) = self.inner.get(&(handle.id(), range)) { + return Some(approx.clone()); + } + if let Some(approx) = self.inner.get(&(handle.id(), range.reverse())) { + // If we have a cache entry for the reverse range, we need to use + // that too! + return Some(approx.clone().reverse()); + } + + None + } +} + +/// An approximation of a [`GlobalEdge`] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct GlobalEdgeApprox { + /// The points that approximate the edge + pub points: Vec>, +} + +impl GlobalEdgeApprox { + /// Reverse the order of the approximation + pub fn reverse(mut self) -> Self { + self.points.reverse(); + self + } +} + +#[cfg(test)] +mod tests { + use std::{f64::consts::TAU, ops::Deref}; + + use pretty_assertions::assert_eq; + + use crate::{ + algorithms::approx::{path::RangeOnPath, Approx, ApproxPoint}, + builder::{HalfEdgeBuilder, SurfaceBuilder}, + geometry::path::GlobalPath, + insert::Insert, + partial::{PartialHalfEdge, PartialObject, PartialSurface}, + services::Services, + }; + + #[test] + fn approx_line_on_flat_surface() { + let mut services = Services::new(); + + let surface = services.objects.surfaces.xz_plane(); + let half_edge = { + let mut half_edge = PartialHalfEdge::default(); + + half_edge.update_as_line_segment_from_points([[1., 1.], [2., 1.]]); + half_edge.infer_vertex_positions_if_necessary(&surface.geometry()); + + half_edge + .build(&mut services.objects) + .insert(&mut services.objects) + }; + + let tolerance = 1.; + let approx = (&half_edge, surface.deref()).approx(tolerance); + + assert_eq!(approx.points, Vec::new()); + } + + #[test] + fn approx_line_on_curved_surface_but_not_along_curve() { + let mut services = Services::new(); + + let surface = PartialSurface::from_axes( + GlobalPath::circle_from_radius(1.), + [0., 0., 1.], + ) + .build(&mut services.objects) + .insert(&mut services.objects); + let half_edge = { + let mut half_edge = PartialHalfEdge::default(); + + half_edge.update_as_line_segment_from_points([[1., 1.], [2., 1.]]); + half_edge.infer_vertex_positions_if_necessary(&surface.geometry()); + + half_edge + .build(&mut services.objects) + .insert(&mut services.objects) + }; + + let tolerance = 1.; + let approx = (&half_edge, surface.deref()).approx(tolerance); + + assert_eq!(approx.points, Vec::new()); + } + + #[test] + fn approx_line_on_curved_surface_along_curve() { + let mut services = Services::new(); + + let path = GlobalPath::circle_from_radius(1.); + let range = RangeOnPath::from([[0.], [TAU]]); + + let surface = PartialSurface::from_axes(path, [0., 0., 1.]) + .build(&mut services.objects) + .insert(&mut services.objects); + let half_edge = { + let mut half_edge = PartialHalfEdge::default(); + + half_edge.update_as_line_segment_from_points([[0., 1.], [1., 1.]]); + + half_edge.vertices[0].0 = Some(range.boundary[0]); + half_edge.vertices[1].0 = Some(range.boundary[1]); + + half_edge.infer_vertex_positions_if_necessary(&surface.geometry()); + + half_edge + .build(&mut services.objects) + .insert(&mut services.objects) + }; + + let tolerance = 1.; + let approx = (&half_edge, surface.deref()).approx(tolerance); + + let expected_approx = (path, range) + .approx(tolerance) + .into_iter() + .map(|(point_local, _)| { + let point_surface = half_edge + .curve() + .path() + .point_from_path_coords(point_local); + let point_global = + surface.geometry().point_from_surface_coords(point_surface); + ApproxPoint::new(point_surface, point_global) + }) + .collect::>(); + assert_eq!(approx.points, expected_approx); + } + + #[test] + fn approx_circle_on_flat_surface() { + let mut services = Services::new(); + + let surface = services.objects.surfaces.xz_plane(); + let half_edge = { + let mut half_edge = PartialHalfEdge::default(); + + half_edge.update_as_circle_from_radius(1.); + half_edge.infer_vertex_positions_if_necessary(&surface.geometry()); + + half_edge + .build(&mut services.objects) + .insert(&mut services.objects) + }; + + let tolerance = 1.; + let approx = (&half_edge, surface.deref()).approx(tolerance); + + let expected_approx = + (half_edge.curve().path(), RangeOnPath::from([[0.], [TAU]])) + .approx(tolerance) + .into_iter() + .map(|(_, point_surface)| { + let point_global = surface + .geometry() + .point_from_surface_coords(point_surface); + ApproxPoint::new(point_surface, point_global) + }) + .collect::>(); + assert_eq!(approx.points, expected_approx); + } +} diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index aa99ea0a9..d9baff01c 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -12,12 +12,12 @@ use crate::{ }; use super::{ - curve::CurveCache, cycle::CycleApprox, Approx, ApproxPoint, Tolerance, + cycle::CycleApprox, edge::EdgeCache, Approx, ApproxPoint, Tolerance, }; impl Approx for &FaceSet { type Approximation = BTreeSet; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, @@ -65,7 +65,7 @@ impl Approx for &FaceSet { impl Approx for &Face { type Approximation = FaceApprox; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index 85dcb1d0a..cc8ae0208 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -1,6 +1,5 @@ //! Approximation of objects -pub mod curve; pub mod cycle; pub mod edge; pub mod face; diff --git a/crates/fj-kernel/src/algorithms/approx/shell.rs b/crates/fj-kernel/src/algorithms/approx/shell.rs index f3262c1d2..0b9e3601d 100644 --- a/crates/fj-kernel/src/algorithms/approx/shell.rs +++ b/crates/fj-kernel/src/algorithms/approx/shell.rs @@ -4,11 +4,11 @@ use std::collections::BTreeSet; use crate::objects::Shell; -use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance}; +use super::{edge::EdgeCache, face::FaceApprox, Approx, Tolerance}; impl Approx for &Shell { type Approximation = BTreeSet; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, diff --git a/crates/fj-kernel/src/algorithms/approx/sketch.rs b/crates/fj-kernel/src/algorithms/approx/sketch.rs index 4cf8e89df..873257a01 100644 --- a/crates/fj-kernel/src/algorithms/approx/sketch.rs +++ b/crates/fj-kernel/src/algorithms/approx/sketch.rs @@ -4,11 +4,11 @@ use std::collections::BTreeSet; use crate::objects::Sketch; -use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance}; +use super::{edge::EdgeCache, face::FaceApprox, Approx, Tolerance}; impl Approx for &Sketch { type Approximation = BTreeSet; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, diff --git a/crates/fj-kernel/src/algorithms/approx/solid.rs b/crates/fj-kernel/src/algorithms/approx/solid.rs index 2077c5666..4aff45ecb 100644 --- a/crates/fj-kernel/src/algorithms/approx/solid.rs +++ b/crates/fj-kernel/src/algorithms/approx/solid.rs @@ -4,11 +4,11 @@ use std::collections::BTreeSet; use crate::objects::Solid; -use super::{curve::CurveCache, face::FaceApprox, Approx, Tolerance}; +use super::{edge::EdgeCache, face::FaceApprox, Approx, Tolerance}; impl Approx for &Solid { type Approximation = BTreeSet; - type Cache = CurveCache; + type Cache = EdgeCache; fn approx_with_cache( self, diff --git a/crates/fj-kernel/src/algorithms/sweep/vertex.rs b/crates/fj-kernel/src/algorithms/sweep/vertex.rs index 4bf5f662a..05ae32dcd 100644 --- a/crates/fj-kernel/src/algorithms/sweep/vertex.rs +++ b/crates/fj-kernel/src/algorithms/sweep/vertex.rs @@ -2,7 +2,7 @@ use fj_math::Vector; use crate::{ insert::Insert, - objects::{GlobalCurve, GlobalEdge, GlobalVertex, Objects}, + objects::{GlobalEdge, GlobalVertex, Objects}, services::Service, storage::Handle, }; @@ -18,8 +18,6 @@ impl Sweep for Handle { cache: &mut SweepCache, objects: &mut Service, ) -> Self::Swept { - let curve = GlobalCurve.insert(objects); - let a = self.clone(); let b = cache .global_vertex @@ -30,8 +28,7 @@ impl Sweep for Handle { .clone(); let vertices = [a, b]; - let global_edge = - GlobalEdge::new(curve, vertices.clone()).insert(objects); + let global_edge = GlobalEdge::new(vertices.clone()).insert(objects); // The vertices of the returned `GlobalEdge` are in normalized order, // which means the order can't be relied upon by the caller. Return the diff --git a/crates/fj-kernel/src/algorithms/transform/curve.rs b/crates/fj-kernel/src/algorithms/transform/curve.rs index 27489c417..b12f0c1d8 100644 --- a/crates/fj-kernel/src/algorithms/transform/curve.rs +++ b/crates/fj-kernel/src/algorithms/transform/curve.rs @@ -1,7 +1,7 @@ use fj_math::Transform; use crate::{ - objects::{Curve, GlobalCurve, Objects}, + objects::{Curve, Objects}, services::Service, }; @@ -21,18 +21,3 @@ impl TransformObject for Curve { Self::new(path) } } - -impl TransformObject for GlobalCurve { - fn transform_with_cache( - self, - _: &Transform, - _: &mut Service, - _: &mut TransformCache, - ) -> Self { - // `GlobalCurve` doesn't contain any internal geometry. If it did, that - // would just be redundant with the geometry of other objects, and this - // other geometry is already being transformed by other implementations - // of this trait. - self - } -} diff --git a/crates/fj-kernel/src/algorithms/transform/edge.rs b/crates/fj-kernel/src/algorithms/transform/edge.rs index 4c5b7b242..1b3be7b98 100644 --- a/crates/fj-kernel/src/algorithms/transform/edge.rs +++ b/crates/fj-kernel/src/algorithms/transform/edge.rs @@ -43,15 +43,11 @@ impl TransformObject for GlobalEdge { objects: &mut Service, cache: &mut TransformCache, ) -> Self { - let curve = self - .curve() - .clone() - .transform_with_cache(transform, objects, cache); let vertices = self.vertices().access_in_normalized_order().map(|vertex| { vertex.transform_with_cache(transform, objects, cache) }); - Self::new(curve, vertices) + Self::new(vertices) } } diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs index eacb8d1eb..a740408b3 100644 --- a/crates/fj-kernel/src/builder/edge.rs +++ b/crates/fj-kernel/src/builder/edge.rs @@ -223,9 +223,6 @@ impl HalfEdgeBuilder for PartialHalfEdge { other: &Partial, surface: &SurfaceGeometry, ) { - let global_curve = other.read().global_form.read().curve.clone(); - self.global_form.write().curve = global_curve; - self.curve.write().path = other.read().curve.read().path.as_ref().and_then(|path| { // We have information about the other edge's surface available. diff --git a/crates/fj-kernel/src/geometry/path.rs b/crates/fj-kernel/src/geometry/path.rs index f84b143b2..cf85a2d73 100644 --- a/crates/fj-kernel/src/geometry/path.rs +++ b/crates/fj-kernel/src/geometry/path.rs @@ -4,12 +4,9 @@ //! //! # Implementation Note //! -//! This is a bit of an in-between module. It is closely associated with curves -//! ([`Curve`]/[`GlobalCurve`]) and [`Surface`]s, but paths are not really -//! objects themselves, as logically speaking, they are owned and not referenced -//! (practically speaking, all objects are owned and not referenced, but that is -//! an implementation detail; see [#1021] for context on where things are -//! going). +//! This is a bit of an in-between module. It is closely associated with +//! [`Curve`] and [`Surface`]s, but paths are not really objects themselves, as +//! logically speaking, they are owned and not referenced. //! //! On the other hand, the types in this module don't follow the general style //! of types in `fj-math`. @@ -18,9 +15,7 @@ //! move to `fj-math`, maybe something else entirely will happen. //! //! [`Curve`]: crate::objects::Curve -//! [`GlobalCurve`]: crate::objects::GlobalCurve //! [`Surface`]: crate::objects::Surface -//! [#1021]: https://github.com/hannobraun/Fornjot/issues/1021 use fj_math::{Circle, Line, Point, Scalar, Transform, Vector}; diff --git a/crates/fj-kernel/src/insert.rs b/crates/fj-kernel/src/insert.rs index 98831ad34..8cd1d03bc 100644 --- a/crates/fj-kernel/src/insert.rs +++ b/crates/fj-kernel/src/insert.rs @@ -4,8 +4,8 @@ use crate::{ objects::{ - Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, - Objects, Shell, Sketch, Solid, Surface, SurfaceVertex, + Curve, Cycle, Face, GlobalEdge, GlobalVertex, HalfEdge, Objects, Shell, + Sketch, Solid, Surface, SurfaceVertex, }, services::{Service, ServiceObjectsExt}, storage::Handle, @@ -37,7 +37,6 @@ impl_insert!( Curve, curves; Cycle, cycles; Face, faces; - GlobalCurve, global_curves; GlobalEdge, global_edges; GlobalVertex, global_vertices; HalfEdge, half_edges; diff --git a/crates/fj-kernel/src/objects/full/curve.rs b/crates/fj-kernel/src/objects/full/curve.rs index 4bce36c06..c291ce6ff 100644 --- a/crates/fj-kernel/src/objects/full/curve.rs +++ b/crates/fj-kernel/src/objects/full/curve.rs @@ -17,7 +17,3 @@ impl Curve { self.path } } - -/// A curve, defined in global (3D) coordinates -#[derive(Clone, Copy, Debug)] -pub struct GlobalCurve; diff --git a/crates/fj-kernel/src/objects/full/edge.rs b/crates/fj-kernel/src/objects/full/edge.rs index c25653416..0f5025e13 100644 --- a/crates/fj-kernel/src/objects/full/edge.rs +++ b/crates/fj-kernel/src/objects/full/edge.rs @@ -1,11 +1,9 @@ -use std::fmt; - use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ - objects::{Curve, GlobalCurve, GlobalVertex, SurfaceVertex}, - storage::{Handle, HandleWrapper}, + objects::{Curve, GlobalVertex, SurfaceVertex}, + storage::Handle, }; /// A directed edge, defined in a surface's 2D space @@ -95,16 +93,6 @@ impl HalfEdge { } } -impl fmt::Display for HalfEdge { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let [a, b] = self.boundary(); - write!(f, "edge from {a:?} to {b:?}")?; - write!(f, " on {:?}", self.global_form().curve())?; - - Ok(()) - } -} - /// An undirected edge, defined in global (3D) coordinates /// /// In contrast to [`HalfEdge`], `GlobalEdge` is undirected, meaning it has no @@ -116,7 +104,6 @@ impl fmt::Display for HalfEdge { /// between [`HalfEdge`] and `GlobalEdge`. #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct GlobalEdge { - curve: HandleWrapper, vertices: VerticesInNormalizedOrder, } @@ -126,19 +113,10 @@ impl GlobalEdge { /// The order of `vertices` is irrelevant. Two `GlobalEdge`s with the same /// `curve` and `vertices` will end up being equal, regardless of the order /// of `vertices` here. - pub fn new( - curve: impl Into>, - vertices: [Handle; 2], - ) -> Self { - let curve = curve.into(); + pub fn new(vertices: [Handle; 2]) -> Self { let (vertices, _) = VerticesInNormalizedOrder::new(vertices); - Self { curve, vertices } - } - - /// Access the curve that defines the edge's geometry - pub fn curve(&self) -> &Handle { - &self.curve + Self { vertices } } /// Access the vertices that bound the edge on the curve diff --git a/crates/fj-kernel/src/objects/mod.rs b/crates/fj-kernel/src/objects/mod.rs index 9fe7e2f9d..e957c10ab 100644 --- a/crates/fj-kernel/src/objects/mod.rs +++ b/crates/fj-kernel/src/objects/mod.rs @@ -79,7 +79,7 @@ mod stores; pub use self::{ full::{ - curve::{Curve, GlobalCurve}, + curve::Curve, cycle::{Cycle, HalfEdgesOfCycle}, edge::{GlobalEdge, HalfEdge, VerticesInNormalizedOrder}, face::{Face, FaceSet, Handedness}, diff --git a/crates/fj-kernel/src/objects/object.rs b/crates/fj-kernel/src/objects/object.rs index 2bf627d87..869403ea3 100644 --- a/crates/fj-kernel/src/objects/object.rs +++ b/crates/fj-kernel/src/objects/object.rs @@ -2,8 +2,8 @@ use std::any::Any; use crate::{ objects::{ - Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, - Objects, Shell, Sketch, Solid, Surface, SurfaceVertex, + Curve, Cycle, Face, GlobalEdge, GlobalVertex, HalfEdge, Objects, Shell, + Sketch, Solid, Surface, SurfaceVertex, }, storage::{Handle, ObjectId}, validate::{Validate, ValidationError}, @@ -111,7 +111,6 @@ object!( Curve, "curve", curves; Cycle, "cycle", cycles; Face, "face", faces; - GlobalCurve, "global curve", global_curves; GlobalEdge, "global edge", global_edges; GlobalVertex, "global vertex", global_vertices; HalfEdge, "half-edge", half_edges; diff --git a/crates/fj-kernel/src/objects/stores.rs b/crates/fj-kernel/src/objects/stores.rs index 73e3c7df8..bcb2dcd88 100644 --- a/crates/fj-kernel/src/objects/stores.rs +++ b/crates/fj-kernel/src/objects/stores.rs @@ -6,8 +6,8 @@ use crate::{ }; use super::{ - Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Shell, - Sketch, Solid, Surface, SurfaceVertex, + Curve, Cycle, Face, GlobalEdge, GlobalVertex, HalfEdge, Shell, Sketch, + Solid, Surface, SurfaceVertex, }; /// The available object stores @@ -22,9 +22,6 @@ pub struct Objects { /// Store for [`Face`]s pub faces: Store, - /// Store for [`GlobalCurve`]s - pub global_curves: Store, - /// Store for [`GlobalEdge`]s pub global_edges: Store, diff --git a/crates/fj-kernel/src/partial/mod.rs b/crates/fj-kernel/src/partial/mod.rs index f6209de04..cb6469170 100644 --- a/crates/fj-kernel/src/partial/mod.rs +++ b/crates/fj-kernel/src/partial/mod.rs @@ -16,7 +16,7 @@ mod wrapper; pub use self::{ objects::{ - curve::{MaybeSurfacePath, PartialCurve, PartialGlobalCurve}, + curve::{MaybeSurfacePath, PartialCurve}, cycle::PartialCycle, edge::{PartialGlobalEdge, PartialHalfEdge}, face::PartialFace, diff --git a/crates/fj-kernel/src/partial/objects/curve.rs b/crates/fj-kernel/src/partial/objects/curve.rs index 7f3174d40..baa43c241 100644 --- a/crates/fj-kernel/src/partial/objects/curve.rs +++ b/crates/fj-kernel/src/partial/objects/curve.rs @@ -2,7 +2,7 @@ use fj_math::Scalar; use crate::{ geometry::path::SurfacePath, - objects::{Curve, GlobalCurve, Objects}, + objects::{Curve, Objects}, partial::{FullToPartialCache, PartialObject}, services::Service, }; @@ -61,19 +61,3 @@ impl From for MaybeSurfacePath { Self::Defined(path) } } - -/// A partial [`GlobalCurve`] -#[derive(Clone, Debug, Default)] -pub struct PartialGlobalCurve; - -impl PartialObject for PartialGlobalCurve { - type Full = GlobalCurve; - - fn from_full(_: &Self::Full, _: &mut FullToPartialCache) -> Self { - Self - } - - fn build(self, _: &mut Service) -> Self::Full { - GlobalCurve - } -} diff --git a/crates/fj-kernel/src/partial/objects/edge.rs b/crates/fj-kernel/src/partial/objects/edge.rs index ada1c7338..ffaece70d 100644 --- a/crates/fj-kernel/src/partial/objects/edge.rs +++ b/crates/fj-kernel/src/partial/objects/edge.rs @@ -5,8 +5,7 @@ use fj_math::Point; use crate::{ objects::{ - Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects, - SurfaceVertex, + Curve, GlobalEdge, GlobalVertex, HalfEdge, Objects, SurfaceVertex, }, partial::{FullToPartialCache, Partial, PartialObject}, services::Service, @@ -84,7 +83,6 @@ impl Default for PartialHalfEdge { let global_form = Partial::from_partial(PartialGlobalEdge { vertices: global_vertices, - ..Default::default() }); Self { @@ -98,9 +96,6 @@ impl Default for PartialHalfEdge { /// A partial [`GlobalEdge`] #[derive(Clone, Debug, Default)] pub struct PartialGlobalEdge { - /// The curve that defines the edge's geometry - pub curve: Partial, - /// The vertices that bound the edge on the curve pub vertices: [Partial; 2], } @@ -113,7 +108,6 @@ impl PartialObject for PartialGlobalEdge { cache: &mut FullToPartialCache, ) -> Self { Self { - curve: Partial::from_full(global_edge.curve().clone(), cache), vertices: global_edge .vertices() .access_in_normalized_order() @@ -122,9 +116,7 @@ impl PartialObject for PartialGlobalEdge { } fn build(self, objects: &mut Service) -> Self::Full { - let curve = self.curve.build(objects); let vertices = self.vertices.map(|vertex| vertex.build(objects)); - - GlobalEdge::new(curve, vertices) + GlobalEdge::new(vertices) } } diff --git a/crates/fj-kernel/src/partial/traits.rs b/crates/fj-kernel/src/partial/traits.rs index 2b14305c3..33da816c3 100644 --- a/crates/fj-kernel/src/partial/traits.rs +++ b/crates/fj-kernel/src/partial/traits.rs @@ -36,7 +36,6 @@ impl_trait!( Curve, PartialCurve; Cycle, PartialCycle; Face, PartialFace; - GlobalCurve, PartialGlobalCurve; GlobalEdge, PartialGlobalEdge; GlobalVertex, PartialGlobalVertex; HalfEdge, PartialHalfEdge; diff --git a/crates/fj-kernel/src/validate/curve.rs b/crates/fj-kernel/src/validate/curve.rs index 250eaea47..2f40a7820 100644 --- a/crates/fj-kernel/src/validate/curve.rs +++ b/crates/fj-kernel/src/validate/curve.rs @@ -1,4 +1,4 @@ -use crate::objects::{Curve, GlobalCurve}; +use crate::objects::Curve; use super::{Validate, ValidationConfig, ValidationError}; @@ -10,12 +10,3 @@ impl Validate for Curve { ) { } } - -impl Validate for GlobalCurve { - fn validate_with_config( - &self, - _: &ValidationConfig, - _: &mut Vec, - ) { - } -} diff --git a/crates/fj-kernel/src/validate/edge.rs b/crates/fj-kernel/src/validate/edge.rs index 224512fc9..811358843 100644 --- a/crates/fj-kernel/src/validate/edge.rs +++ b/crates/fj-kernel/src/validate/edge.rs @@ -1,7 +1,7 @@ use fj_math::{Point, Scalar}; use crate::{ - objects::{GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Surface}, + objects::{GlobalEdge, GlobalVertex, HalfEdge, Surface}, storage::Handle, }; @@ -30,25 +30,6 @@ impl Validate for GlobalEdge { /// [`HalfEdge`] validation failed #[derive(Clone, Debug, thiserror::Error)] pub enum HalfEdgeValidationError { - /// [`HalfEdge`]'s [`GlobalCurve`]s do not match - #[error( - "Global form of `HalfEdge`'s `Curve` does not match `GlobalCurve` of \n\ - the `HalfEdge`'s `GlobalEdge`\n\ - - `GlobalCurve` from `Curve`: {global_curve_from_curve:#?}\n\ - - `GlobalCurve` from `GlobalEdge`: {global_curve_from_global_form:#?}\n\ - - `HalfEdge`: {half_edge:#?}", - )] - GlobalCurveMismatch { - /// The [`GlobalCurve`] from the [`HalfEdge`]'s `Curve` - global_curve_from_curve: Handle, - - /// The [`GlobalCurve`] from the [`HalfEdge`]'s global form - global_curve_from_global_form: Handle, - - /// The half-edge - half_edge: HalfEdge, - }, - /// [`HalfEdge`]'s [`GlobalVertex`] objects do not match #[error( "Global forms of `HalfEdge` vertices do not match vertices of \n\