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