diff --git a/crates/fj-core/src/algorithms/approx/edge.rs b/crates/fj-core/src/algorithms/approx/edge.rs index a52659fc0..b2db71cc1 100644 --- a/crates/fj-core/src/algorithms/approx/edge.rs +++ b/crates/fj-core/src/algorithms/approx/edge.rs @@ -340,7 +340,7 @@ mod tests { let mut services = Services::new(); let surface = services.objects.surfaces.xz_plane(); - let half_edge = HalfEdge::circle(1., &mut services); + let half_edge = HalfEdge::circle([0., 0.], 1., &mut services); let tolerance = 1.; let approx = (&half_edge, surface.deref()).approx(tolerance); diff --git a/crates/fj-core/src/geometry/curve.rs b/crates/fj-core/src/geometry/curve.rs index bb07226bd..fd93f4735 100644 --- a/crates/fj-core/src/geometry/curve.rs +++ b/crates/fj-core/src/geometry/curve.rs @@ -15,11 +15,6 @@ pub enum Curve { } impl Curve { - /// Build a circle from the given radius - pub fn circle_from_radius(radius: impl Into) -> Self { - Self::circle_from_center_and_radius(Point::origin(), radius) - } - /// Build a circle from the given radius pub fn circle_from_center_and_radius( center: impl Into>, diff --git a/crates/fj-core/src/objects/kinds/sketch.rs b/crates/fj-core/src/objects/kinds/sketch.rs index 69003e279..3baebb2a0 100644 --- a/crates/fj-core/src/objects/kinds/sketch.rs +++ b/crates/fj-core/src/objects/kinds/sketch.rs @@ -8,11 +8,6 @@ use crate::{ }; /// A 2-dimensional shape -/// -/// # Implementation Note -/// -/// The faces that make up the sketch must be in the same surface. This is not -/// currently validated. #[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct Sketch { regions: BTreeSet, @@ -26,6 +21,11 @@ impl Sketch { } } + /// Access the regions of the sketch + pub fn regions(&self) -> impl Iterator { + self.regions.iter() + } + /// Apply the regions of the sketch to some [`Surface`] pub fn faces( &self, diff --git a/crates/fj-core/src/operations/build/cycle.rs b/crates/fj-core/src/operations/build/cycle.rs index 2e97cf50d..9533ef2ef 100644 --- a/crates/fj-core/src/operations/build/cycle.rs +++ b/crates/fj-core/src/operations/build/cycle.rs @@ -1,9 +1,9 @@ -use fj_math::Point; +use fj_math::{Point, Scalar}; use itertools::Itertools; use crate::{ objects::{Cycle, HalfEdge}, - operations::{BuildHalfEdge, Insert}, + operations::{BuildHalfEdge, Insert, UpdateCycle}, services::Services, }; @@ -14,6 +14,17 @@ pub trait BuildCycle { Cycle::new([]) } + /// Build a circle + fn circle( + center: impl Into>, + radius: impl Into, + services: &mut Services, + ) -> Cycle { + let circle = + HalfEdge::circle(center, radius, services).insert(services); + Cycle::empty().add_half_edges([circle]) + } + /// Build a polygon fn polygon(points: Ps, services: &mut Services) -> Cycle where diff --git a/crates/fj-core/src/operations/build/edge.rs b/crates/fj-core/src/operations/build/edge.rs index c2fd80032..dc6efe436 100644 --- a/crates/fj-core/src/operations/build/edge.rs +++ b/crates/fj-core/src/operations/build/edge.rs @@ -49,8 +49,12 @@ pub trait BuildHalfEdge { } /// Create a circle - fn circle(radius: impl Into, services: &mut Services) -> HalfEdge { - let curve = Curve::circle_from_radius(radius); + fn circle( + center: impl Into>, + radius: impl Into, + services: &mut Services, + ) -> HalfEdge { + let curve = Curve::circle_from_center_and_radius(center, radius); let boundary = [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); diff --git a/crates/fj-core/src/operations/build/sketch.rs b/crates/fj-core/src/operations/build/sketch.rs index 111f06cc4..274438059 100644 --- a/crates/fj-core/src/operations/build/sketch.rs +++ b/crates/fj-core/src/operations/build/sketch.rs @@ -1,24 +1,10 @@ -use fj_math::Point; - -use crate::{ - geometry::region::Region, - objects::{Cycle, Sketch}, - operations::{BuildCycle, Insert}, - services::Services, -}; +use crate::objects::Sketch; /// Build a [`Sketch`] pub trait BuildSketch { - /// Build a polygon - fn polygon(points: Ps, services: &mut Services) -> Sketch - where - P: Into>, - Ps: IntoIterator, - Ps::IntoIter: Clone + ExactSizeIterator, - { - let exterior = Cycle::polygon(points, services).insert(services); - let region = Region::new(exterior, Vec::new(), None); - Sketch::new([region]) + /// Create a sketch with no regions + fn empty() -> Sketch { + Sketch::new([]) } } diff --git a/crates/fj-core/src/operations/mod.rs b/crates/fj-core/src/operations/mod.rs index 2331fa5ef..5f7bbd90f 100644 --- a/crates/fj-core/src/operations/mod.rs +++ b/crates/fj-core/src/operations/mod.rs @@ -19,6 +19,6 @@ pub use self::{ join::cycle::JoinCycle, update::{ cycle::UpdateCycle, edge::UpdateHalfEdge, face::UpdateFace, - shell::UpdateShell, solid::UpdateSolid, + shell::UpdateShell, sketch::UpdateSketch, solid::UpdateSolid, }, }; diff --git a/crates/fj-core/src/operations/update/mod.rs b/crates/fj-core/src/operations/update/mod.rs index 85f65f886..8928937cb 100644 --- a/crates/fj-core/src/operations/update/mod.rs +++ b/crates/fj-core/src/operations/update/mod.rs @@ -2,4 +2,5 @@ pub mod cycle; pub mod edge; pub mod face; pub mod shell; +pub mod sketch; pub mod solid; diff --git a/crates/fj-core/src/operations/update/sketch.rs b/crates/fj-core/src/operations/update/sketch.rs new file mode 100644 index 000000000..42f518cb8 --- /dev/null +++ b/crates/fj-core/src/operations/update/sketch.rs @@ -0,0 +1,55 @@ +use fj_math::{Point, Scalar}; + +use crate::{ + geometry::region::Region, + objects::{Cycle, Sketch}, + operations::{BuildCycle, Insert}, + services::Services, +}; + +/// Update a [`Sketch`] +pub trait UpdateSketch { + /// Add a region to the sketch + fn add_region(&self, region: Region) -> Self; + + /// Add a circle to the sketch + fn add_circle( + &self, + center: impl Into>, + radius: impl Into, + services: &mut Services, + ) -> Self; + + /// Add a polygon to the sketch + fn add_polygon(&self, points: Ps, services: &mut Services) -> Self + where + P: Into>, + Ps: IntoIterator, + Ps::IntoIter: Clone + ExactSizeIterator; +} + +impl UpdateSketch for Sketch { + fn add_region(&self, region: Region) -> Self { + Sketch::new(self.regions().cloned().chain([region])) + } + + fn add_circle( + &self, + center: impl Into>, + radius: impl Into, + services: &mut Services, + ) -> Self { + let exterior = Cycle::circle(center, radius, services).insert(services); + self.add_region(Region::new(exterior, [], None)) + } + + fn add_polygon(&self, points: Ps, services: &mut Services) -> Self + where + P: Into>, + Ps: IntoIterator, + Ps::IntoIter: Clone + ExactSizeIterator, + { + let exterior = Cycle::polygon(points, services).insert(services); + self.add_region(Region::new(exterior, [], None)) + } +} diff --git a/models/cuboid/src/lib.rs b/models/cuboid/src/lib.rs index 049c22244..db2657c55 100644 --- a/models/cuboid/src/lib.rs +++ b/models/cuboid/src/lib.rs @@ -2,7 +2,7 @@ use fj::{ core::{ algorithms::sweep::Sweep, objects::{Sketch, Solid}, - operations::{BuildSketch, Insert}, + operations::{BuildSketch, Insert, UpdateSketch}, services::Services, storage::Handle, }, @@ -12,16 +12,17 @@ use fj::{ pub fn cuboid(x: f64, y: f64, z: f64) -> Handle { let mut services = Services::new(); - let sketch = Sketch::polygon( - [ - [-x / 2., -y / 2.], - [x / 2., -y / 2.], - [x / 2., y / 2.], - [-x / 2., y / 2.], - ], - &mut services, - ) - .insert(&mut services); + let sketch = Sketch::empty() + .add_polygon( + [ + [-x / 2., -y / 2.], + [x / 2., -y / 2.], + [x / 2., y / 2.], + [-x / 2., y / 2.], + ], + &mut services, + ) + .insert(&mut services); let surface = services.objects.surfaces.xy_plane();