mirror of
https://github.com/hannobraun/Fornjot
synced 2025-09-01 15:06:42 +00:00
Merge pull request #2321 from hannobraun/surface
Define special surface to represent 2D space
This commit is contained in:
commit
73fd64f4c6
@ -14,6 +14,8 @@ pub struct Geometry {
|
||||
half_edge: BTreeMap<Handle<HalfEdge>, HalfEdgeGeom>,
|
||||
surface: BTreeMap<Handle<Surface>, SurfaceGeom>,
|
||||
|
||||
space_2d: Handle<Surface>,
|
||||
|
||||
xy_plane: Handle<Surface>,
|
||||
xz_plane: Handle<Surface>,
|
||||
yz_plane: Handle<Surface>,
|
||||
@ -26,6 +28,8 @@ impl Geometry {
|
||||
half_edge: BTreeMap::new(),
|
||||
surface: BTreeMap::new(),
|
||||
|
||||
space_2d: topology.surfaces.space_2d(),
|
||||
|
||||
xy_plane: topology.surfaces.xy_plane(),
|
||||
xz_plane: topology.surfaces.xz_plane(),
|
||||
yz_plane: topology.surfaces.yz_plane(),
|
||||
@ -69,6 +73,10 @@ impl Geometry {
|
||||
surface: Handle<Surface>,
|
||||
geometry: SurfaceGeom,
|
||||
) {
|
||||
if surface == self.space_2d {
|
||||
panic!("Attempting to define geometry for 2D space");
|
||||
}
|
||||
|
||||
if self.surface.contains_key(&surface)
|
||||
&& (surface == self.xy_plane
|
||||
|| surface == self.xz_plane
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::topology::Sketch;
|
||||
use crate::topology::{Sketch, Topology};
|
||||
|
||||
/// Build a [`Sketch`]
|
||||
///
|
||||
@ -7,8 +7,8 @@ use crate::topology::Sketch;
|
||||
/// [module-level documentation]: super
|
||||
pub trait BuildSketch {
|
||||
/// Create a sketch with no regions
|
||||
fn empty() -> Sketch {
|
||||
Sketch::new([])
|
||||
fn empty(topology: &Topology) -> Sketch {
|
||||
Sketch::new(topology.surfaces.space_2d(), [])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ impl ReplaceCurve for Sketch {
|
||||
}
|
||||
|
||||
if replacement_happened {
|
||||
ReplaceOutput::Updated(Sketch::new(regions))
|
||||
ReplaceOutput::Updated(Sketch::new(self.surface().clone(), regions))
|
||||
} else {
|
||||
ReplaceOutput::Original(self.clone())
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ impl ReplaceHalfEdge for Sketch {
|
||||
}
|
||||
|
||||
if replacement_happened {
|
||||
ReplaceOutput::Updated(Sketch::new(regions))
|
||||
ReplaceOutput::Updated(Sketch::new(self.surface().clone(), regions))
|
||||
} else {
|
||||
ReplaceOutput::Original(self.clone())
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ impl ReplaceVertex for Sketch {
|
||||
}
|
||||
|
||||
if replacement_happened {
|
||||
ReplaceOutput::Updated(Sketch::new(regions))
|
||||
ReplaceOutput::Updated(Sketch::new(self.surface().clone(), regions))
|
||||
} else {
|
||||
ReplaceOutput::Original(self.clone())
|
||||
}
|
||||
@ -317,7 +317,7 @@ impl ReplaceVertex for Handle<Sketch> {
|
||||
}
|
||||
|
||||
if replacement_happened {
|
||||
ReplaceOutput::Updated(Sketch::new(regions))
|
||||
ReplaceOutput::Updated(Sketch::new(self.surface().clone(), regions))
|
||||
} else {
|
||||
ReplaceOutput::Original(self.clone())
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ impl UpdateSketch for Sketch {
|
||||
{
|
||||
let regions = regions.into_iter().map(|region| region.insert(core));
|
||||
let regions = self.regions().iter().cloned().chain(regions);
|
||||
Sketch::new(regions)
|
||||
Sketch::new(self.surface().clone(), regions)
|
||||
}
|
||||
|
||||
fn update_region<T, R>(
|
||||
@ -69,6 +69,6 @@ impl UpdateSketch for Sketch {
|
||||
}),
|
||||
)
|
||||
.expect("Region not found");
|
||||
Sketch::new(regions)
|
||||
Sketch::new(self.surface().clone(), regions)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
topology::{Cycle, ObjectSet},
|
||||
};
|
||||
|
||||
/// A single, continuous 2d region, may contain holes
|
||||
/// A single, continuous 2d region; may contain holes
|
||||
///
|
||||
/// Interior cycles must have the opposite winding of the exterior cycle,
|
||||
/// meaning on the front side of the region, they must appear clockwise. This
|
||||
|
@ -1,22 +1,32 @@
|
||||
use crate::{
|
||||
storage::Handle,
|
||||
topology::{ObjectSet, Region},
|
||||
topology::{ObjectSet, Region, Surface},
|
||||
};
|
||||
|
||||
/// A 2-dimensional shape
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Sketch {
|
||||
surface: Handle<Surface>,
|
||||
regions: ObjectSet<Region>,
|
||||
}
|
||||
|
||||
impl Sketch {
|
||||
/// Construct an empty instance of `Sketch`
|
||||
pub fn new(regions: impl IntoIterator<Item = Handle<Region>>) -> Self {
|
||||
pub fn new(
|
||||
surface: Handle<Surface>,
|
||||
regions: impl IntoIterator<Item = Handle<Region>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
surface,
|
||||
regions: regions.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the surface of the sketch
|
||||
pub fn surface(&self) -> &Handle<Surface> {
|
||||
&self.surface
|
||||
}
|
||||
|
||||
/// Access the regions of the sketch
|
||||
pub fn regions(&self) -> &ObjectSet<Region> {
|
||||
&self.regions
|
||||
|
@ -50,6 +50,8 @@ impl Topology {
|
||||
pub struct Surfaces {
|
||||
store: Store<Surface>,
|
||||
|
||||
space_2d: Handle<Surface>,
|
||||
|
||||
xy_plane: Handle<Surface>,
|
||||
xz_plane: Handle<Surface>,
|
||||
yz_plane: Handle<Surface>,
|
||||
@ -66,6 +68,15 @@ impl Surfaces {
|
||||
self.store.insert(handle, surface);
|
||||
}
|
||||
|
||||
/// Access the surface representing 2D space
|
||||
///
|
||||
/// Every other surface is a 2D subspace within a 3D space. This surface is
|
||||
/// special, in that it represents the 2D space which is not located in a 3D
|
||||
/// space.
|
||||
pub fn space_2d(&self) -> Handle<Surface> {
|
||||
self.space_2d.clone()
|
||||
}
|
||||
|
||||
/// Access the xy-plane
|
||||
pub fn xy_plane(&self) -> Handle<Surface> {
|
||||
self.xy_plane.clone()
|
||||
@ -86,6 +97,9 @@ impl Default for Surfaces {
|
||||
fn default() -> Self {
|
||||
let mut store: Store<Surface> = Store::new();
|
||||
|
||||
let space_2d = store.reserve();
|
||||
store.insert(space_2d.clone(), Surface::new());
|
||||
|
||||
let xy_plane = store.reserve();
|
||||
store.insert(xy_plane.clone(), Surface::new());
|
||||
|
||||
@ -97,6 +111,7 @@ impl Default for Surfaces {
|
||||
|
||||
Self {
|
||||
store,
|
||||
space_2d,
|
||||
xy_plane,
|
||||
xz_plane,
|
||||
yz_plane,
|
||||
|
@ -137,14 +137,21 @@ mod tests {
|
||||
|
||||
let region = <Region as BuildRegion>::circle([0., 0.], 1., &mut core)
|
||||
.insert(&mut core);
|
||||
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
||||
let valid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![region.clone()],
|
||||
)
|
||||
.insert(&mut core);
|
||||
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||
|
||||
let shared_cycle = region.exterior();
|
||||
let invalid_sketch = Sketch::new(vec![
|
||||
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
||||
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
||||
]);
|
||||
let invalid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![
|
||||
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
||||
Region::new(shared_cycle.clone(), vec![]).insert(&mut core),
|
||||
],
|
||||
);
|
||||
assert_contains_err!(
|
||||
core,
|
||||
invalid_sketch,
|
||||
@ -165,7 +172,11 @@ mod tests {
|
||||
&mut core,
|
||||
)
|
||||
.insert(&mut core);
|
||||
let valid_sketch = Sketch::new(vec![region.clone()]).insert(&mut core);
|
||||
let valid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![region.clone()],
|
||||
)
|
||||
.insert(&mut core);
|
||||
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||
|
||||
let exterior = region.exterior();
|
||||
@ -173,10 +184,12 @@ mod tests {
|
||||
exterior.half_edges().iter().cloned().collect();
|
||||
let interior = Cycle::new(cloned_edges).insert(&mut core);
|
||||
|
||||
let invalid_sketch =
|
||||
Sketch::new(vec![
|
||||
let invalid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![
|
||||
Region::new(exterior.clone(), vec![interior]).insert(&mut core)
|
||||
]);
|
||||
],
|
||||
);
|
||||
assert_contains_err!(
|
||||
core,
|
||||
invalid_sketch,
|
||||
@ -195,10 +208,10 @@ mod tests {
|
||||
let valid_outer_circle = HalfEdge::circle([0., 0.], 1., &mut core);
|
||||
let valid_exterior =
|
||||
Cycle::new(vec![valid_outer_circle.clone()]).insert(&mut core);
|
||||
let valid_sketch =
|
||||
Sketch::new(vec![
|
||||
Region::new(valid_exterior.clone(), vec![]).insert(&mut core)
|
||||
]);
|
||||
let valid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![Region::new(valid_exterior.clone(), vec![]).insert(&mut core)],
|
||||
);
|
||||
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||
|
||||
let invalid_outer_circle = HalfEdge::from_sibling(
|
||||
@ -208,10 +221,12 @@ mod tests {
|
||||
);
|
||||
let invalid_exterior =
|
||||
Cycle::new(vec![invalid_outer_circle.clone()]).insert(&mut core);
|
||||
let invalid_sketch =
|
||||
Sketch::new(vec![
|
||||
let invalid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![
|
||||
Region::new(invalid_exterior.clone(), vec![]).insert(&mut core)
|
||||
]);
|
||||
],
|
||||
);
|
||||
assert_contains_err!(
|
||||
core,
|
||||
invalid_sketch,
|
||||
@ -238,20 +253,20 @@ mod tests {
|
||||
|
||||
let valid_interior =
|
||||
Cycle::new(vec![cw_inner_circle.clone()]).insert(&mut core);
|
||||
let valid_sketch = Sketch::new(vec![Region::new(
|
||||
exterior.clone(),
|
||||
vec![valid_interior],
|
||||
)
|
||||
.insert(&mut core)]);
|
||||
let valid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![Region::new(exterior.clone(), vec![valid_interior])
|
||||
.insert(&mut core)],
|
||||
);
|
||||
valid_sketch.validate_and_return_first_error(&core.layers.geometry)?;
|
||||
|
||||
let invalid_interior =
|
||||
Cycle::new(vec![inner_circle.clone()]).insert(&mut core);
|
||||
let invalid_sketch = Sketch::new(vec![Region::new(
|
||||
exterior.clone(),
|
||||
vec![invalid_interior],
|
||||
)
|
||||
.insert(&mut core)]);
|
||||
let invalid_sketch = Sketch::new(
|
||||
core.layers.topology.surfaces.space_2d(),
|
||||
vec![Region::new(exterior.clone(), vec![invalid_interior])
|
||||
.insert(&mut core)],
|
||||
);
|
||||
assert_contains_err!(
|
||||
core,
|
||||
invalid_sketch,
|
||||
|
@ -16,7 +16,7 @@ pub fn model(size: impl Into<Vector<3>>, core: &mut fj::core::Core) -> Solid {
|
||||
let bottom_surface = core.layers.topology.surfaces.xy_plane();
|
||||
let sweep_path = Vector::from([Scalar::ZERO, Scalar::ZERO, z]);
|
||||
|
||||
Sketch::empty()
|
||||
Sketch::empty(&core.layers.topology)
|
||||
.add_regions(
|
||||
[Region::polygon(
|
||||
[
|
||||
|
@ -20,7 +20,7 @@ pub fn model(
|
||||
let bottom_surface = core.layers.topology.surfaces.xy_plane();
|
||||
let sweep_path = Vector::from([0., 0., height]);
|
||||
|
||||
Sketch::empty()
|
||||
Sketch::empty(&core.layers.topology)
|
||||
.add_regions(
|
||||
[Region::circle(Point::origin(), outer, core).add_interiors(
|
||||
[Cycle::circle(Point::origin(), inner, core).reverse(core)],
|
||||
|
@ -43,7 +43,7 @@ pub fn model(
|
||||
let bottom_surface = core.layers.topology.surfaces.xy_plane();
|
||||
let sweep_path = Vector::from([0., 0., h]);
|
||||
|
||||
Sketch::empty()
|
||||
Sketch::empty(&core.layers.topology)
|
||||
.add_regions(
|
||||
[Region::polygon(outer_points, core).add_interiors(
|
||||
[Cycle::polygon(inner_points, core).reverse(core)],
|
||||
|
Loading…
x
Reference in New Issue
Block a user