Merge pull request #2271 from hannobraun/geometry

Store `SurfacePath` of `HalfEdge` in geometry layer
This commit is contained in:
Hanno Braun 2024-03-18 13:54:49 +01:00 committed by GitHub
commit e3c061ac98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 195 additions and 21 deletions

View File

@ -3,14 +3,15 @@ use std::collections::BTreeMap;
use fj_math::Vector; use fj_math::Vector;
use crate::{ use crate::{
objects::{Objects, Surface}, objects::{HalfEdge, Objects, Surface},
storage::{Handle, HandleWrapper}, storage::{Handle, HandleWrapper},
}; };
use super::{GlobalPath, SurfaceGeometry}; use super::{GlobalPath, HalfEdgeGeometry, SurfaceGeometry};
/// Geometric data that is associated with topological objects /// Geometric data that is associated with topological objects
pub struct Geometry { pub struct Geometry {
half_edge: BTreeMap<Handle<HalfEdge>, HalfEdgeGeometry>,
surface: BTreeMap<HandleWrapper<Surface>, SurfaceGeometry>, surface: BTreeMap<HandleWrapper<Surface>, SurfaceGeometry>,
xy_plane: Handle<Surface>, xy_plane: Handle<Surface>,
@ -22,6 +23,7 @@ impl Geometry {
/// Create a new instance of `Geometry` /// Create a new instance of `Geometry`
pub fn new(objects: &Objects) -> Self { pub fn new(objects: &Objects) -> Self {
let mut self_ = Self { let mut self_ = Self {
half_edge: BTreeMap::new(),
surface: BTreeMap::new(), surface: BTreeMap::new(),
xy_plane: objects.surfaces.xy_plane(), xy_plane: objects.surfaces.xy_plane(),
@ -54,6 +56,14 @@ impl Geometry {
self_ self_
} }
pub(crate) fn define_half_edge_inner(
&mut self,
half_edge: Handle<HalfEdge>,
geometry: HalfEdgeGeometry,
) {
self.half_edge.insert(half_edge, geometry);
}
pub(crate) fn define_surface_inner( pub(crate) fn define_surface_inner(
&mut self, &mut self,
surface: Handle<Surface>, surface: Handle<Surface>,
@ -62,6 +72,21 @@ impl Geometry {
self.surface.insert(surface.into(), geometry); self.surface.insert(surface.into(), geometry);
} }
/// # Access the geometry of the provided half-edge
///
/// ## Panics
///
/// Panics, if the geometry of the half-edge is not defined.
pub fn of_half_edge(
&self,
half_edge: &Handle<HalfEdge>,
) -> HalfEdgeGeometry {
self.half_edge
.get(half_edge)
.copied()
.expect("Expected geometry of half-edge to be defined")
}
/// # Access the geometry of the provided surface /// # Access the geometry of the provided surface
/// ///
/// ## Panics /// ## Panics

View File

@ -0,0 +1,32 @@
use super::SurfacePath;
/// The geometry of a half-edge
#[derive(Copy, Clone)]
pub struct HalfEdgeGeometry {
/// # The path of the half-edge
///
/// ## Implementation Note
///
/// Currently, all curve-related geometry is defined locally, in terms of
/// the surface that the curve is on (or purely in 2D, if there is no
/// surface associated with this geometry). However, curves exist globally,
/// independently of surfaces. Half-edges in multiple surfaces can refer to
/// the same curve, and in fact, that is the whole reason for their
/// existence as a topological object.
///
/// This contradiction, globally defined curves but locally defined curve
/// geometry, is the reason that this curve geometry is defined right here,
/// associated with a locally existing half-edge. (And, I might add,
/// redundantly so, as multiple half-edges within the same surface context
/// can refer to the same curve.)
///
/// Instead, it should be possible to define curve geometry *either* locally
/// or globally. Then that respective definition can be associated with the
/// curve (and possibly, in addition, a surface). How exactly that is going
/// to work is up in the air.
///
/// The point of all this exposition is to clarify that this field doesn't
/// really belong here. It exists here for practical reasons that are,
/// hopefully, temporary.
pub path: SurfacePath,
}

View File

@ -2,12 +2,14 @@
mod boundary; mod boundary;
mod geometry; mod geometry;
mod half_edge;
mod path; mod path;
mod surface; mod surface;
pub use self::{ pub use self::{
boundary::{CurveBoundary, CurveBoundaryElement}, boundary::{CurveBoundary, CurveBoundaryElement},
geometry::Geometry, geometry::Geometry,
half_edge::HalfEdgeGeometry,
path::{GlobalPath, SurfacePath}, path::{GlobalPath, SurfacePath},
surface::SurfaceGeometry, surface::SurfaceGeometry,
}; };

View File

@ -1,14 +1,30 @@
//! Layer infrastructure for [`Geometry`] //! Layer infrastructure for [`Geometry`]
use crate::{ use crate::{
geometry::{Geometry, SurfaceGeometry}, geometry::{Geometry, HalfEdgeGeometry, SurfaceGeometry},
objects::Surface, objects::{HalfEdge, Surface},
storage::Handle, storage::Handle,
}; };
use super::{Command, Event, Layer}; use super::{Command, Event, Layer};
impl Layer<Geometry> { impl Layer<Geometry> {
/// Define the geometry of the provided half-edge
pub fn define_half_edge(
&mut self,
half_edge: Handle<HalfEdge>,
geometry: HalfEdgeGeometry,
) {
let mut events = Vec::new();
self.process(
DefineHalfEdge {
half_edge,
geometry,
},
&mut events,
);
}
/// Define the geometry of the provided surface /// Define the geometry of the provided surface
pub fn define_surface( pub fn define_surface(
&mut self, &mut self,
@ -20,6 +36,31 @@ impl Layer<Geometry> {
} }
} }
/// Define the geometry of a half-edge
pub struct DefineHalfEdge {
half_edge: Handle<HalfEdge>,
geometry: HalfEdgeGeometry,
}
impl Command<Geometry> for DefineHalfEdge {
type Result = ();
type Event = Self;
fn decide(
self,
_: &Geometry,
events: &mut Vec<Self::Event>,
) -> Self::Result {
events.push(self);
}
}
impl Event<Geometry> for DefineHalfEdge {
fn evolve(&self, state: &mut Geometry) {
state.define_half_edge_inner(self.half_edge.clone(), self.geometry);
}
}
/// Define the geometry of a surface /// Define the geometry of a surface
pub struct DefineSurface { pub struct DefineSurface {
surface: Handle<Surface>, surface: Handle<Surface>,

View File

@ -2,7 +2,7 @@ use fj_interop::ext::ArrayExt;
use fj_math::{Arc, Point, Scalar}; use fj_math::{Arc, Point, Scalar};
use crate::{ use crate::{
geometry::{CurveBoundary, SurfacePath}, geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
objects::{Curve, HalfEdge, Vertex}, objects::{Curve, HalfEdge, Vertex},
operations::insert::Insert, operations::insert::Insert,
storage::Handle, storage::Handle,
@ -33,13 +33,22 @@ pub trait BuildHalfEdge {
start_vertex: Handle<Vertex>, start_vertex: Handle<Vertex>,
core: &mut Core, core: &mut Core,
) -> Handle<HalfEdge> { ) -> Handle<HalfEdge> {
HalfEdge::new( let half_edge = HalfEdge::new(
sibling.path(), sibling.path(),
sibling.boundary().reverse(), sibling.boundary().reverse(),
sibling.curve().clone(), sibling.curve().clone(),
start_vertex, start_vertex,
) )
.insert(core) .insert(core);
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry {
path: sibling.path(),
},
);
half_edge
} }
/// Create an arc /// Create an arc
@ -65,7 +74,12 @@ pub trait BuildHalfEdge {
let boundary = let boundary =
[arc.start_angle, arc.end_angle].map(|coord| Point::from([coord])); [arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));
HalfEdge::unjoined(path, boundary, core).insert(core) let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
/// Create a circle /// Create a circle
@ -78,7 +92,12 @@ pub trait BuildHalfEdge {
let boundary = let boundary =
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord])); [Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
HalfEdge::unjoined(path, boundary, core).insert(core) let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
/// Create a line segment /// Create a line segment
@ -93,7 +112,12 @@ pub trait BuildHalfEdge {
boundary.zip_ext(points_surface), boundary.zip_ext(points_surface),
); );
HalfEdge::unjoined(path, boundary, core).insert(core) let half_edge = HalfEdge::unjoined(path, boundary, core).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
} }

View File

@ -1,7 +1,7 @@
use fj_math::Point; use fj_math::Point;
use crate::{ use crate::{
geometry::{CurveBoundary, SurfacePath}, geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
objects::HalfEdge, objects::HalfEdge,
operations::insert::Insert, operations::insert::Insert,
storage::Handle, storage::Handle,
@ -35,13 +35,19 @@ impl UpdateHalfEdgeGeometry for Handle<HalfEdge> {
) -> Self { ) -> Self {
let path = update(self.path()); let path = update(self.path());
HalfEdge::new( let half_edge = HalfEdge::new(
path, path,
self.boundary(), self.boundary(),
self.curve().clone(), self.curve().clone(),
self.start_vertex().clone(), self.start_vertex().clone(),
) )
.insert(core) .insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
fn update_boundary( fn update_boundary(

View File

@ -4,10 +4,11 @@ use fj_math::Point;
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
geometry::{CurveBoundary, SurfacePath}, geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
objects::{Cycle, HalfEdge}, objects::{Cycle, HalfEdge},
operations::{ operations::{
build::BuildHalfEdge, build::BuildHalfEdge,
insert::Insert,
update::{UpdateCycle, UpdateHalfEdge}, update::{UpdateCycle, UpdateHalfEdge},
}, },
storage::Handle, storage::Handle,
@ -88,12 +89,20 @@ impl JoinCycle for Cycle {
.into_iter() .into_iter()
.circular_tuple_windows() .circular_tuple_windows()
.map(|((prev_half_edge, _, _), (half_edge, path, boundary))| { .map(|((prev_half_edge, _, _), (half_edge, path, boundary))| {
HalfEdge::unjoined(path, boundary, core) let half_edge = HalfEdge::unjoined(path, boundary, core)
.update_curve(|_, _| half_edge.curve().clone(), core) .update_curve(|_, _| half_edge.curve().clone(), core)
.update_start_vertex( .update_start_vertex(
|_, _| prev_half_edge.start_vertex().clone(), |_, _| prev_half_edge.start_vertex().clone(),
core, core,
) )
.insert(core);
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry { path },
);
half_edge
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.add_half_edges(half_edges, core) self.add_half_edges(half_edges, core)

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
geometry::HalfEdgeGeometry,
objects::{Cycle, HalfEdge}, objects::{Cycle, HalfEdge},
operations::{derive::DeriveFrom, insert::Insert}, operations::{derive::DeriveFrom, insert::Insert},
Core, Core,
@ -12,14 +13,23 @@ impl Reverse for Cycle {
.half_edges() .half_edges()
.pairs() .pairs()
.map(|(current, next)| { .map(|(current, next)| {
HalfEdge::new( let half_edge = HalfEdge::new(
current.path(), current.path(),
current.boundary().reverse(), current.boundary().reverse(),
current.curve().clone(), current.curve().clone(),
next.start_vertex().clone(), next.start_vertex().clone(),
) )
.insert(core) .insert(core)
.derive_from(current, core) .derive_from(current, core);
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry {
path: current.path(),
},
);
half_edge
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
geometry::HalfEdgeGeometry,
objects::HalfEdge, objects::HalfEdge,
operations::{derive::DeriveFrom, insert::Insert}, operations::{derive::DeriveFrom, insert::Insert},
storage::Handle, storage::Handle,
@ -12,13 +13,19 @@ impl ReverseCurveCoordinateSystems for Handle<HalfEdge> {
let path = self.path().reverse(); let path = self.path().reverse();
let boundary = self.boundary().reverse(); let boundary = self.boundary().reverse();
HalfEdge::new( let half_edge = HalfEdge::new(
path, path,
boundary, boundary,
self.curve().clone(), self.curve().clone(),
self.start_vertex().clone(), self.start_vertex().clone(),
) )
.insert(core) .insert(core)
.derive_from(self, core) .derive_from(self, core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
} }

View File

@ -1,6 +1,7 @@
use fj_math::Point; use fj_math::Point;
use crate::{ use crate::{
geometry::HalfEdgeGeometry,
objects::{HalfEdge, Vertex}, objects::{HalfEdge, Vertex},
operations::insert::Insert, operations::insert::Insert,
storage::Handle, storage::Handle,
@ -57,6 +58,15 @@ impl SplitHalfEdge for HalfEdge {
) )
.insert(core); .insert(core);
core.layers.geometry.define_half_edge(
a.clone(),
HalfEdgeGeometry { path: self.path() },
);
core.layers.geometry.define_half_edge(
b.clone(),
HalfEdgeGeometry { path: self.path() },
);
[a, b] [a, b]
} }
} }

View File

@ -1,7 +1,8 @@
use fj_math::Transform; use fj_math::Transform;
use crate::{ use crate::{
objects::HalfEdge, operations::insert::Insert, storage::Handle, Core, geometry::HalfEdgeGeometry, objects::HalfEdge, operations::insert::Insert,
storage::Handle, Core,
}; };
use super::{TransformCache, TransformObject}; use super::{TransformCache, TransformObject};
@ -26,6 +27,13 @@ impl TransformObject for Handle<HalfEdge> {
.clone() .clone()
.transform_with_cache(transform, core, cache); .transform_with_cache(transform, core, cache);
HalfEdge::new(path, boundary, curve, start_vertex).insert(core) let half_edge =
HalfEdge::new(path, boundary, curve, start_vertex).insert(core);
core.layers
.geometry
.define_half_edge(half_edge.clone(), HalfEdgeGeometry { path });
half_edge
} }
} }