mirror of
https://github.com/hannobraun/Fornjot
synced 2025-05-03 17:38:27 +00:00
Merge pull request #2288 from hannobraun/geometry
Complete migration of `HalfEdge` boundary to geometry layer
This commit is contained in:
commit
5d3bab7c3a
@ -5,7 +5,10 @@ use std::collections::BTreeMap;
|
||||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath},
|
||||
geometry::{
|
||||
CurveBoundary, GlobalPath, HalfEdgeGeometry, SurfaceGeometry,
|
||||
SurfacePath,
|
||||
},
|
||||
objects::Curve,
|
||||
storage::Handle,
|
||||
Core,
|
||||
@ -13,14 +16,7 @@ use crate::{
|
||||
|
||||
use super::{Approx, ApproxPoint, Tolerance};
|
||||
|
||||
impl Approx
|
||||
for (
|
||||
&Handle<Curve>,
|
||||
SurfacePath,
|
||||
&SurfaceGeometry,
|
||||
CurveBoundary<Point<1>>,
|
||||
)
|
||||
{
|
||||
impl Approx for (&Handle<Curve>, &HalfEdgeGeometry, &SurfaceGeometry) {
|
||||
type Approximation = CurveApprox;
|
||||
type Cache = CurveApproxCache;
|
||||
|
||||
@ -30,20 +26,20 @@ impl Approx
|
||||
cache: &mut Self::Cache,
|
||||
core: &mut Core,
|
||||
) -> Self::Approximation {
|
||||
let (curve, surface_path, surface, boundary) = self;
|
||||
let (curve, half_edge, surface) = self;
|
||||
|
||||
match cache.get(curve, boundary) {
|
||||
match cache.get(curve, half_edge.boundary) {
|
||||
Some(approx) => approx,
|
||||
None => {
|
||||
let approx = approx_curve(
|
||||
&surface_path,
|
||||
&half_edge.path,
|
||||
surface,
|
||||
boundary,
|
||||
half_edge.boundary,
|
||||
tolerance,
|
||||
core,
|
||||
);
|
||||
|
||||
cache.insert(curve.clone(), boundary, approx)
|
||||
cache.insert(curve.clone(), half_edge.boundary, approx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,7 +183,10 @@ mod tests {
|
||||
|
||||
use crate::{
|
||||
algorithms::approx::{Approx, ApproxPoint},
|
||||
geometry::{CurveBoundary, GlobalPath, SurfaceGeometry, SurfacePath},
|
||||
geometry::{
|
||||
CurveBoundary, GlobalPath, HalfEdgeGeometry, SurfaceGeometry,
|
||||
SurfacePath,
|
||||
},
|
||||
objects::Curve,
|
||||
operations::insert::Insert,
|
||||
Core,
|
||||
@ -198,14 +197,15 @@ mod tests {
|
||||
let mut core = Core::new();
|
||||
|
||||
let curve = Curve::new().insert(&mut core);
|
||||
let (surface_path, boundary) =
|
||||
let (path, boundary) =
|
||||
SurfacePath::line_from_points([[1., 1.], [2., 1.]]);
|
||||
let boundary = CurveBoundary::from(boundary);
|
||||
let half_edge = HalfEdgeGeometry { path, boundary };
|
||||
let surface = core.layers.geometry.xz_plane();
|
||||
|
||||
let tolerance = 1.;
|
||||
let approx = (&curve, surface_path, &surface, boundary)
|
||||
.approx(tolerance, &mut core);
|
||||
let approx =
|
||||
(&curve, &half_edge, &surface).approx(tolerance, &mut core);
|
||||
|
||||
assert_eq!(approx.points, vec![]);
|
||||
}
|
||||
@ -215,17 +215,18 @@ mod tests {
|
||||
let mut core = Core::new();
|
||||
|
||||
let curve = Curve::new().insert(&mut core);
|
||||
let (surface_path, boundary) =
|
||||
let (path, boundary) =
|
||||
SurfacePath::line_from_points([[1., 1.], [2., 1.]]);
|
||||
let boundary = CurveBoundary::from(boundary);
|
||||
let half_edge = HalfEdgeGeometry { path, boundary };
|
||||
let surface = SurfaceGeometry {
|
||||
u: GlobalPath::circle_from_radius(1.),
|
||||
v: [0., 0., 1.].into(),
|
||||
};
|
||||
|
||||
let tolerance = 1.;
|
||||
let approx = (&curve, surface_path, &surface, boundary)
|
||||
.approx(tolerance, &mut core);
|
||||
let approx =
|
||||
(&curve, &half_edge, &surface).approx(tolerance, &mut core);
|
||||
|
||||
assert_eq!(approx.points, vec![]);
|
||||
}
|
||||
@ -236,26 +237,26 @@ mod tests {
|
||||
|
||||
let global_path = GlobalPath::circle_from_radius(1.);
|
||||
let curve = Curve::new().insert(&mut core);
|
||||
let surface_path = SurfacePath::line_from_points_with_coords([
|
||||
let path = SurfacePath::line_from_points_with_coords([
|
||||
([0.], [0., 1.]),
|
||||
([TAU], [TAU, 1.]),
|
||||
]);
|
||||
let boundary = CurveBoundary::from([[0.], [TAU]]);
|
||||
let half_edge = HalfEdgeGeometry { path, boundary };
|
||||
let surface = SurfaceGeometry {
|
||||
u: global_path,
|
||||
v: [0., 0., 1.].into(),
|
||||
};
|
||||
|
||||
let tolerance = 1.;
|
||||
let approx = (&curve, surface_path, &surface, boundary)
|
||||
.approx(tolerance, &mut core);
|
||||
let approx =
|
||||
(&curve, &half_edge, &surface).approx(tolerance, &mut core);
|
||||
|
||||
let expected_approx = (global_path, boundary)
|
||||
.approx(tolerance, &mut core)
|
||||
.into_iter()
|
||||
.map(|(point_local, _)| {
|
||||
let point_surface =
|
||||
surface_path.point_from_path_coords(point_local);
|
||||
let point_surface = path.point_from_path_coords(point_local);
|
||||
let point_global =
|
||||
surface.point_from_surface_coords(point_surface);
|
||||
ApproxPoint::new(point_local, point_global)
|
||||
@ -269,21 +270,20 @@ mod tests {
|
||||
let mut core = Core::new();
|
||||
|
||||
let curve = Curve::new().insert(&mut core);
|
||||
let surface_path =
|
||||
SurfacePath::circle_from_center_and_radius([0., 0.], 1.);
|
||||
let path = SurfacePath::circle_from_center_and_radius([0., 0.], 1.);
|
||||
let boundary = CurveBoundary::from([[0.], [TAU]]);
|
||||
let half_edge = HalfEdgeGeometry { path, boundary };
|
||||
let surface = core.layers.geometry.xz_plane();
|
||||
|
||||
let tolerance = 1.;
|
||||
let approx = (&curve, surface_path, &surface, boundary)
|
||||
.approx(tolerance, &mut core);
|
||||
let approx =
|
||||
(&curve, &half_edge, &surface).approx(tolerance, &mut core);
|
||||
|
||||
let expected_approx = (&surface_path, boundary)
|
||||
let expected_approx = (&path, boundary)
|
||||
.approx(tolerance, &mut core)
|
||||
.into_iter()
|
||||
.map(|(point_local, _)| {
|
||||
let point_surface =
|
||||
surface_path.point_from_path_coords(point_local);
|
||||
let point_surface = path.point_from_path_coords(point_local);
|
||||
let point_global =
|
||||
surface.point_from_surface_coords(point_surface);
|
||||
ApproxPoint::new(point_local, point_global)
|
||||
|
@ -50,9 +50,8 @@ impl Approx for (&Handle<HalfEdge>, &SurfaceGeometry) {
|
||||
let rest = {
|
||||
let approx = (
|
||||
half_edge.curve(),
|
||||
core.layers.geometry.of_half_edge(half_edge).path,
|
||||
&core.layers.geometry.of_half_edge(half_edge),
|
||||
surface,
|
||||
half_edge.boundary(),
|
||||
)
|
||||
.approx_with_cache(
|
||||
tolerance,
|
||||
|
@ -22,11 +22,10 @@ impl super::BoundingVolume<2> for Handle<HalfEdge> {
|
||||
})
|
||||
}
|
||||
SurfacePath::Line(_) => {
|
||||
let points = self.boundary().inner.map(|point_curve| {
|
||||
geometry
|
||||
.of_half_edge(self)
|
||||
.path
|
||||
.point_from_path_coords(point_curve)
|
||||
let geometry = geometry.of_half_edge(self);
|
||||
|
||||
let points = geometry.boundary.inner.map(|point_curve| {
|
||||
geometry.path.point_from_path_coords(point_curve)
|
||||
});
|
||||
|
||||
Some(Aabb::<2>::from_points(points))
|
||||
|
@ -40,10 +40,12 @@ impl Cycle {
|
||||
.next()
|
||||
.expect("Invalid cycle: expected at least one edge");
|
||||
|
||||
let [a, b] = first.boundary().inner;
|
||||
let geometry = geometry.of_half_edge(first);
|
||||
|
||||
let [a, b] = geometry.boundary.inner;
|
||||
let edge_direction_positive = a < b;
|
||||
|
||||
let circle = match geometry.of_half_edge(first).path {
|
||||
let circle = match geometry.path {
|
||||
SurfacePath::Circle(circle) => circle,
|
||||
SurfacePath::Line(_) => unreachable!(
|
||||
"Invalid cycle: less than 3 edges, but not all are circles"
|
||||
|
@ -1,7 +1,4 @@
|
||||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
geometry::CurveBoundary,
|
||||
objects::{Curve, Vertex},
|
||||
storage::Handle,
|
||||
};
|
||||
@ -35,30 +32,19 @@ use crate::{
|
||||
/// [`Shell`]: crate::objects::Shell
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HalfEdge {
|
||||
boundary: CurveBoundary<Point<1>>,
|
||||
curve: Handle<Curve>,
|
||||
start_vertex: Handle<Vertex>,
|
||||
}
|
||||
|
||||
impl HalfEdge {
|
||||
/// Create an instance of `Edge`
|
||||
pub fn new(
|
||||
boundary: impl Into<CurveBoundary<Point<1>>>,
|
||||
curve: Handle<Curve>,
|
||||
start_vertex: Handle<Vertex>,
|
||||
) -> Self {
|
||||
pub fn new(curve: Handle<Curve>, start_vertex: Handle<Vertex>) -> Self {
|
||||
Self {
|
||||
boundary: boundary.into(),
|
||||
curve,
|
||||
start_vertex,
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the boundary points of the edge on the curve
|
||||
pub fn boundary(&self) -> CurveBoundary<Point<1>> {
|
||||
self.boundary
|
||||
}
|
||||
|
||||
/// Access the curve of the edge
|
||||
pub fn curve(&self) -> &Handle<Curve> {
|
||||
&self.curve
|
||||
|
@ -2,7 +2,7 @@ use fj_interop::ext::ArrayExt;
|
||||
use fj_math::{Arc, Point, Scalar};
|
||||
|
||||
use crate::{
|
||||
geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
|
||||
geometry::{HalfEdgeGeometry, SurfacePath},
|
||||
objects::{Curve, HalfEdge, Vertex},
|
||||
operations::{geometry::UpdateHalfEdgeGeometry, insert::Insert},
|
||||
storage::Handle,
|
||||
@ -16,14 +16,11 @@ use crate::{
|
||||
/// [module-level documentation]: super
|
||||
pub trait BuildHalfEdge {
|
||||
/// Create a half-edge that is not joined to a sibling
|
||||
fn unjoined(
|
||||
boundary: impl Into<CurveBoundary<Point<1>>>,
|
||||
core: &mut Core,
|
||||
) -> HalfEdge {
|
||||
fn unjoined(core: &mut Core) -> HalfEdge {
|
||||
let curve = Curve::new().insert(core);
|
||||
let start_vertex = Vertex::new().insert(core);
|
||||
|
||||
HalfEdge::new(boundary, curve, start_vertex)
|
||||
HalfEdge::new(curve, start_vertex)
|
||||
}
|
||||
|
||||
/// Create a half-edge from its sibling
|
||||
@ -35,13 +32,9 @@ pub trait BuildHalfEdge {
|
||||
let mut geometry = core.layers.geometry.of_half_edge(sibling);
|
||||
geometry.boundary = geometry.boundary.reverse();
|
||||
|
||||
HalfEdge::new(
|
||||
sibling.boundary().reverse(),
|
||||
sibling.curve().clone(),
|
||||
start_vertex,
|
||||
)
|
||||
.insert(core)
|
||||
.set_geometry(geometry, &mut core.layers.geometry)
|
||||
HalfEdge::new(sibling.curve().clone(), start_vertex)
|
||||
.insert(core)
|
||||
.set_geometry(geometry, &mut core.layers.geometry)
|
||||
}
|
||||
|
||||
/// Create an arc
|
||||
@ -67,7 +60,7 @@ pub trait BuildHalfEdge {
|
||||
let boundary =
|
||||
[arc.start_angle, arc.end_angle].map(|coord| Point::from([coord]));
|
||||
|
||||
let half_edge = HalfEdge::unjoined(boundary, core).insert(core);
|
||||
let half_edge = HalfEdge::unjoined(core).insert(core);
|
||||
core.layers.geometry.define_half_edge(
|
||||
half_edge.clone(),
|
||||
HalfEdgeGeometry {
|
||||
@ -89,7 +82,7 @@ pub trait BuildHalfEdge {
|
||||
let boundary =
|
||||
[Scalar::ZERO, Scalar::TAU].map(|coord| Point::from([coord]));
|
||||
|
||||
let half_edge = HalfEdge::unjoined(boundary, core).insert(core);
|
||||
let half_edge = HalfEdge::unjoined(core).insert(core);
|
||||
core.layers.geometry.define_half_edge(
|
||||
half_edge.clone(),
|
||||
HalfEdgeGeometry {
|
||||
@ -113,15 +106,13 @@ pub trait BuildHalfEdge {
|
||||
boundary.zip_ext(points_surface),
|
||||
);
|
||||
|
||||
HalfEdge::unjoined(boundary, core)
|
||||
.insert(core)
|
||||
.set_geometry(
|
||||
HalfEdgeGeometry {
|
||||
path,
|
||||
boundary: boundary.into(),
|
||||
},
|
||||
&mut core.layers.geometry,
|
||||
)
|
||||
HalfEdge::unjoined(core).insert(core).set_geometry(
|
||||
HalfEdgeGeometry {
|
||||
path,
|
||||
boundary: boundary.into(),
|
||||
},
|
||||
&mut core.layers.geometry,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,11 +68,7 @@ impl AddHole for Shell {
|
||||
[Cycle::empty().add_joined_edges(
|
||||
[(
|
||||
entry.clone(),
|
||||
core.layers
|
||||
.geometry
|
||||
.of_half_edge(&entry)
|
||||
.path,
|
||||
entry.boundary(),
|
||||
core.layers.geometry.of_half_edge(&entry),
|
||||
)],
|
||||
core,
|
||||
)],
|
||||
@ -142,11 +138,7 @@ impl AddHole for Shell {
|
||||
[Cycle::empty().add_joined_edges(
|
||||
[(
|
||||
entry.clone(),
|
||||
core.layers
|
||||
.geometry
|
||||
.of_half_edge(&entry)
|
||||
.path,
|
||||
entry.boundary(),
|
||||
core.layers.geometry.of_half_edge(&entry),
|
||||
)],
|
||||
core,
|
||||
)],
|
||||
@ -167,11 +159,7 @@ impl AddHole for Shell {
|
||||
[Cycle::empty().add_joined_edges(
|
||||
[(
|
||||
exit.clone(),
|
||||
core.layers
|
||||
.geometry
|
||||
.of_half_edge(exit)
|
||||
.path,
|
||||
exit.boundary(),
|
||||
core.layers.geometry.of_half_edge(exit),
|
||||
)],
|
||||
core,
|
||||
)],
|
||||
|
@ -1,10 +1,9 @@
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use fj_math::Point;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
geometry::{CurveBoundary, HalfEdgeGeometry, SurfacePath},
|
||||
geometry::HalfEdgeGeometry,
|
||||
objects::{Cycle, HalfEdge},
|
||||
operations::{
|
||||
build::BuildHalfEdge,
|
||||
@ -22,9 +21,7 @@ pub trait JoinCycle {
|
||||
#[must_use]
|
||||
fn add_joined_edges<Es>(&self, edges: Es, core: &mut Core) -> Self
|
||||
where
|
||||
Es: IntoIterator<
|
||||
Item = (Handle<HalfEdge>, SurfacePath, CurveBoundary<Point<1>>),
|
||||
>,
|
||||
Es: IntoIterator<Item = (Handle<HalfEdge>, HalfEdgeGeometry)>,
|
||||
Es::IntoIter: Clone + ExactSizeIterator;
|
||||
|
||||
/// Join the cycle to another
|
||||
@ -81,26 +78,21 @@ pub trait JoinCycle {
|
||||
impl JoinCycle for Cycle {
|
||||
fn add_joined_edges<Es>(&self, edges: Es, core: &mut Core) -> Self
|
||||
where
|
||||
Es: IntoIterator<
|
||||
Item = (Handle<HalfEdge>, SurfacePath, CurveBoundary<Point<1>>),
|
||||
>,
|
||||
Es: IntoIterator<Item = (Handle<HalfEdge>, HalfEdgeGeometry)>,
|
||||
Es::IntoIter: Clone + ExactSizeIterator,
|
||||
{
|
||||
let half_edges = edges
|
||||
.into_iter()
|
||||
.circular_tuple_windows()
|
||||
.map(|((prev_half_edge, _, _), (half_edge, path, boundary))| {
|
||||
HalfEdge::unjoined(boundary, core)
|
||||
.map(|((prev_half_edge, _), (half_edge, geometry))| {
|
||||
HalfEdge::unjoined(core)
|
||||
.update_curve(|_, _| half_edge.curve().clone(), core)
|
||||
.update_start_vertex(
|
||||
|_, _| prev_half_edge.start_vertex().clone(),
|
||||
core,
|
||||
)
|
||||
.insert(core)
|
||||
.set_geometry(
|
||||
HalfEdgeGeometry { path, boundary },
|
||||
&mut core.layers.geometry,
|
||||
)
|
||||
.set_geometry(geometry, &mut core.layers.geometry)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.add_half_edges(half_edges, core)
|
||||
|
@ -18,7 +18,6 @@ impl Reverse for Cycle {
|
||||
geometry.boundary = geometry.boundary.reverse();
|
||||
|
||||
HalfEdge::new(
|
||||
current.boundary().reverse(),
|
||||
current.curve().clone(),
|
||||
next.start_vertex().clone(),
|
||||
)
|
||||
|
@ -13,13 +13,10 @@ impl ReverseCurveCoordinateSystems for Handle<HalfEdge> {
|
||||
geometry.path = geometry.path.reverse();
|
||||
geometry.boundary = geometry.boundary.reverse();
|
||||
|
||||
let half_edge = HalfEdge::new(
|
||||
geometry.boundary,
|
||||
self.curve().clone(),
|
||||
self.start_vertex().clone(),
|
||||
)
|
||||
.insert(core)
|
||||
.derive_from(self, core);
|
||||
let half_edge =
|
||||
HalfEdge::new(self.curve().clone(), self.start_vertex().clone())
|
||||
.insert(core)
|
||||
.derive_from(self, core);
|
||||
|
||||
core.layers
|
||||
.geometry
|
||||
|
@ -37,7 +37,7 @@ impl SplitEdge for Shell {
|
||||
let point = point.into();
|
||||
|
||||
let sibling = self
|
||||
.get_sibling_of(half_edge)
|
||||
.get_sibling_of(half_edge, &core.layers.geometry)
|
||||
.expect("Expected half-edge and its sibling to be part of shell");
|
||||
|
||||
let [half_edge_a, half_edge_b] = half_edge.split_half_edge(point, core);
|
||||
|
@ -42,36 +42,24 @@ impl SplitHalfEdge for Handle<HalfEdge> {
|
||||
) -> [Handle<HalfEdge>; 2] {
|
||||
let point = point.into();
|
||||
|
||||
let [start, end] = self.boundary().inner;
|
||||
let geometry = core.layers.geometry.of_half_edge(self);
|
||||
let [start, end] = geometry.boundary.inner;
|
||||
|
||||
let a = HalfEdge::new(
|
||||
[start, point],
|
||||
self.curve().clone(),
|
||||
self.start_vertex().clone(),
|
||||
)
|
||||
.insert(core)
|
||||
.derive_from(self, core)
|
||||
.set_geometry(
|
||||
core.layers
|
||||
.geometry
|
||||
.of_half_edge(self)
|
||||
.with_boundary([start, point]),
|
||||
&mut core.layers.geometry,
|
||||
);
|
||||
let b = HalfEdge::new(
|
||||
[point, end],
|
||||
self.curve().clone(),
|
||||
Vertex::new().insert(core),
|
||||
)
|
||||
.insert(core)
|
||||
.derive_from(self, core)
|
||||
.set_geometry(
|
||||
core.layers
|
||||
.geometry
|
||||
.of_half_edge(self)
|
||||
.with_boundary([point, end]),
|
||||
&mut core.layers.geometry,
|
||||
);
|
||||
let a =
|
||||
HalfEdge::new(self.curve().clone(), self.start_vertex().clone())
|
||||
.insert(core)
|
||||
.derive_from(self, core)
|
||||
.set_geometry(
|
||||
geometry.with_boundary([start, point]),
|
||||
&mut core.layers.geometry,
|
||||
);
|
||||
let b = HalfEdge::new(self.curve().clone(), Vertex::new().insert(core))
|
||||
.insert(core)
|
||||
.derive_from(self, core)
|
||||
.set_geometry(
|
||||
geometry.with_boundary([point, end]),
|
||||
&mut core.layers.geometry,
|
||||
);
|
||||
|
||||
[a, b]
|
||||
}
|
||||
|
@ -77,8 +77,7 @@ impl SweepCycle for Cycle {
|
||||
|
||||
top_edges.push((
|
||||
top_edge,
|
||||
core.layers.geometry.of_half_edge(bottom_half_edge).path,
|
||||
bottom_half_edge.boundary(),
|
||||
core.layers.geometry.of_half_edge(bottom_half_edge),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -59,12 +59,8 @@ impl SweepHalfEdge for Handle<HalfEdge> {
|
||||
) -> (Face, Handle<HalfEdge>) {
|
||||
let path = path.into();
|
||||
|
||||
let surface = core
|
||||
.layers
|
||||
.geometry
|
||||
.of_half_edge(self)
|
||||
.path
|
||||
.sweep_surface_path(surface, path, core);
|
||||
let geometry = core.layers.geometry.of_half_edge(self);
|
||||
let surface = geometry.path.sweep_surface_path(surface, path, core);
|
||||
|
||||
// Next, we need to define the boundaries of the face. Let's start with
|
||||
// the global vertices and edges.
|
||||
@ -86,7 +82,7 @@ impl SweepHalfEdge for Handle<HalfEdge> {
|
||||
|
||||
// Let's figure out the surface coordinates of the edge vertices.
|
||||
let surface_points = {
|
||||
let [a, b] = self.boundary().inner;
|
||||
let [a, b] = geometry.boundary.inner;
|
||||
|
||||
[
|
||||
[a.t, Scalar::ZERO],
|
||||
@ -104,7 +100,7 @@ impl SweepHalfEdge for Handle<HalfEdge> {
|
||||
|
||||
// Now, the boundaries of each edge.
|
||||
let boundaries = {
|
||||
let [a, b] = self.boundary().inner;
|
||||
let [a, b] = geometry.boundary.inner;
|
||||
let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
|
||||
|
||||
[[a, b], [c, d], [b, a], [d, c]]
|
||||
|
@ -13,7 +13,6 @@ impl TransformObject for Handle<HalfEdge> {
|
||||
core: &mut Core,
|
||||
cache: &mut TransformCache,
|
||||
) -> Self {
|
||||
let boundary = self.boundary();
|
||||
let curve = self
|
||||
.curve()
|
||||
.clone()
|
||||
@ -23,8 +22,7 @@ impl TransformObject for Handle<HalfEdge> {
|
||||
.clone()
|
||||
.transform_with_cache(transform, core, cache);
|
||||
|
||||
let half_edge =
|
||||
HalfEdge::new(boundary, curve, start_vertex).insert(core);
|
||||
let half_edge = HalfEdge::new(curve, start_vertex).insert(core);
|
||||
|
||||
core.layers.geometry.define_half_edge(
|
||||
half_edge.clone(),
|
||||
|
@ -38,7 +38,6 @@ impl UpdateHalfEdge for HalfEdge {
|
||||
T: Insert<Inserted = Handle<Curve>>,
|
||||
{
|
||||
HalfEdge::new(
|
||||
self.boundary(),
|
||||
update(self.curve(), core)
|
||||
.insert(core)
|
||||
.derive_from(self.curve(), core),
|
||||
@ -55,7 +54,6 @@ impl UpdateHalfEdge for HalfEdge {
|
||||
T: Insert<Inserted = Handle<Vertex>>,
|
||||
{
|
||||
HalfEdge::new(
|
||||
self.boundary(),
|
||||
self.curve().clone(),
|
||||
update(self.start_vertex(), core)
|
||||
.insert(core)
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
geometry::Geometry,
|
||||
objects::{HalfEdge, Shell},
|
||||
storage::Handle,
|
||||
};
|
||||
@ -8,7 +9,12 @@ use super::BoundingVerticesOfHalfEdge;
|
||||
/// Queries related to the sibling of a [`HalfEdge`]
|
||||
pub trait SiblingOfHalfEdge {
|
||||
/// Indicate whether the provided half-edges are siblings
|
||||
fn are_siblings(&self, a: &Handle<HalfEdge>, b: &Handle<HalfEdge>) -> bool;
|
||||
fn are_siblings(
|
||||
&self,
|
||||
a: &Handle<HalfEdge>,
|
||||
b: &Handle<HalfEdge>,
|
||||
geometry: &Geometry,
|
||||
) -> bool;
|
||||
|
||||
/// Retrieve the sibling of this half-edge
|
||||
///
|
||||
@ -18,13 +24,20 @@ pub trait SiblingOfHalfEdge {
|
||||
fn get_sibling_of(
|
||||
&self,
|
||||
half_edge: &Handle<HalfEdge>,
|
||||
geometry: &Geometry,
|
||||
) -> Option<Handle<HalfEdge>>;
|
||||
}
|
||||
|
||||
impl SiblingOfHalfEdge for Shell {
|
||||
fn are_siblings(&self, a: &Handle<HalfEdge>, b: &Handle<HalfEdge>) -> bool {
|
||||
fn are_siblings(
|
||||
&self,
|
||||
a: &Handle<HalfEdge>,
|
||||
b: &Handle<HalfEdge>,
|
||||
geometry: &Geometry,
|
||||
) -> bool {
|
||||
let same_curve = a.curve().id() == b.curve().id();
|
||||
let same_boundary = a.boundary() == b.boundary().reverse();
|
||||
let same_boundary = geometry.of_half_edge(a).boundary
|
||||
== geometry.of_half_edge(b).boundary.reverse();
|
||||
let same_vertices = {
|
||||
let Some(a_vertices) = self.bounding_vertices_of_half_edge(a)
|
||||
else {
|
||||
@ -44,11 +57,12 @@ impl SiblingOfHalfEdge for Shell {
|
||||
fn get_sibling_of(
|
||||
&self,
|
||||
half_edge: &Handle<HalfEdge>,
|
||||
geometry: &Geometry,
|
||||
) -> Option<Handle<HalfEdge>> {
|
||||
for face in self.faces() {
|
||||
for cycle in face.region().all_cycles() {
|
||||
for h in cycle.half_edges() {
|
||||
if self.are_siblings(half_edge, h) {
|
||||
if self.are_siblings(half_edge, h, geometry) {
|
||||
return Some(h.clone());
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ impl Validate for Shell {
|
||||
ShellValidationError::check_curve_coordinates(
|
||||
self, geometry, config, errors,
|
||||
);
|
||||
ShellValidationError::check_half_edge_pairs(self, errors);
|
||||
ShellValidationError::check_half_edge_pairs(self, geometry, errors);
|
||||
ShellValidationError::check_half_edge_coincidence(
|
||||
self, geometry, config, errors,
|
||||
);
|
||||
@ -112,7 +112,7 @@ impl ShellValidationError {
|
||||
// we have right now are circles, 3 would be enough to check
|
||||
// for coincidence. But the first and last might be
|
||||
// identical, so let's add an extra one.
|
||||
let [a, d] = edge_a.boundary().inner;
|
||||
let [a, d] = geometry.of_half_edge(edge_a).boundary.inner;
|
||||
let b = a + (d - a) * 1. / 3.;
|
||||
let c = a + (d - a) * 2. / 3.;
|
||||
|
||||
@ -177,14 +177,18 @@ impl ShellValidationError {
|
||||
}
|
||||
|
||||
/// Check that each half-edge is part of a pair
|
||||
fn check_half_edge_pairs(shell: &Shell, errors: &mut Vec<ValidationError>) {
|
||||
fn check_half_edge_pairs(
|
||||
shell: &Shell,
|
||||
geometry: &Geometry,
|
||||
errors: &mut Vec<ValidationError>,
|
||||
) {
|
||||
let mut unmatched_half_edges = BTreeMap::new();
|
||||
|
||||
for face in shell.faces() {
|
||||
for cycle in face.region().all_cycles() {
|
||||
for half_edge in cycle.half_edges() {
|
||||
let curve = half_edge.curve().clone();
|
||||
let boundary = half_edge.boundary();
|
||||
let boundary = geometry.of_half_edge(half_edge).boundary;
|
||||
let vertices =
|
||||
cycle.bounding_vertices_of_half_edge(half_edge).expect(
|
||||
"`half_edge` came from `cycle`, must exist there",
|
||||
@ -200,7 +204,8 @@ impl ShellValidationError {
|
||||
// currently looking at. Let's make sure the logic
|
||||
// we use here to determine that matches the
|
||||
// "official" definition.
|
||||
assert!(shell.are_siblings(half_edge, sibling));
|
||||
assert!(shell
|
||||
.are_siblings(half_edge, sibling, geometry));
|
||||
}
|
||||
None => {
|
||||
// If this half-edge has a sibling, we haven't seen
|
||||
@ -238,7 +243,7 @@ impl ShellValidationError {
|
||||
continue;
|
||||
}
|
||||
|
||||
if shell.are_siblings(half_edge_a, half_edge_b) {
|
||||
if shell.are_siblings(half_edge_a, half_edge_b, geometry) {
|
||||
// If the half-edges are siblings, they are allowed to be
|
||||
// coincident. Must be, in fact. There's another validation
|
||||
// check that takes care of that.
|
||||
@ -257,8 +262,11 @@ impl ShellValidationError {
|
||||
.all(|d| d < config.distinct_min_distance)
|
||||
{
|
||||
let boundaries = Box::new(CoincidentHalfEdgeBoundaries {
|
||||
boundaries: [half_edge_a, half_edge_b]
|
||||
.map(|half_edge| half_edge.boundary()),
|
||||
boundaries: [half_edge_a, half_edge_b].map(
|
||||
|half_edge| {
|
||||
geometry.of_half_edge(half_edge).boundary
|
||||
},
|
||||
),
|
||||
});
|
||||
let curves = Box::new(CoincidentHalfEdgeCurves {
|
||||
curves: [half_edge_a, half_edge_b]
|
||||
@ -384,7 +392,7 @@ fn distances(
|
||||
(edge, surface): (&Handle<HalfEdge>, &SurfaceGeometry),
|
||||
geometry: &Geometry,
|
||||
) -> Point<3> {
|
||||
let [start, end] = edge.boundary().inner;
|
||||
let [start, end] = geometry.of_half_edge(edge).boundary.inner;
|
||||
let path_coords = start + (end - start) * percent;
|
||||
let surface_coords = geometry
|
||||
.of_half_edge(edge)
|
||||
@ -454,7 +462,6 @@ mod tests {
|
||||
geometry.boundary.reverse();
|
||||
|
||||
[HalfEdge::new(
|
||||
half_edge.boundary().reverse(),
|
||||
half_edge.curve().clone(),
|
||||
half_edge.start_vertex().clone(),
|
||||
)
|
||||
|
@ -46,7 +46,7 @@ impl ValidationCheck<Cycle> for AdjacentHalfEdgesNotConnected {
|
||||
) -> impl Iterator<Item = Self> {
|
||||
object.half_edges().pairs().filter_map(|(first, second)| {
|
||||
let end_pos_of_first_half_edge = {
|
||||
let [_, end] = first.boundary().inner;
|
||||
let [_, end] = geometry.of_half_edge(first).boundary.inner;
|
||||
geometry
|
||||
.of_half_edge(first)
|
||||
.path
|
||||
|
Loading…
Reference in New Issue
Block a user