Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read half-edge geometry from geometry layer in most places #2275

Merged
merged 10 commits into from
Mar 20, 2024
5 changes: 1 addition & 4 deletions crates/fj-core/src/algorithms/approx/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
//!
//! See [`CycleApprox`].

use std::ops::Deref;

use fj_math::Segment;

use crate::{geometry::SurfaceGeometry, objects::Cycle, Core};
Expand All @@ -30,8 +28,7 @@ impl Approx for (&Cycle, &SurfaceGeometry) {
.half_edges()
.iter()
.map(|half_edge| {
(half_edge.deref(), surface)
.approx_with_cache(tolerance, cache, core)
(half_edge, surface).approx_with_cache(tolerance, cache, core)
})
.collect();

Expand Down
16 changes: 11 additions & 5 deletions crates/fj-core/src/algorithms/approx/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
//! approximations are usually used to build cycle approximations, and this way,
//! the caller doesn't have to deal with duplicate vertices.

use crate::{geometry::SurfaceGeometry, objects::HalfEdge, Core};
use crate::{
geometry::SurfaceGeometry, objects::HalfEdge, storage::Handle, Core,
};

use super::{
curve::CurveApproxCache, vertex::VertexApproxCache, Approx, ApproxPoint,
Tolerance,
};

impl Approx for (&HalfEdge, &SurfaceGeometry) {
impl Approx for (&Handle<HalfEdge>, &SurfaceGeometry) {
type Approximation = HalfEdgeApprox;
type Cache = HalfEdgeApproxCache;

Expand Down Expand Up @@ -44,7 +46,7 @@ impl Approx for (&HalfEdge, &SurfaceGeometry) {
let rest = {
let approx = (
half_edge.curve(),
half_edge.path(),
core.layers.geometry.of_half_edge(half_edge).path,
surface,
half_edge.boundary(),
)
Expand All @@ -55,8 +57,12 @@ impl Approx for (&HalfEdge, &SurfaceGeometry) {
);

approx.points.into_iter().map(|point| {
let point_surface =
half_edge.path().point_from_path_coords(point.local_form);
let point_surface = core
.layers
.geometry
.of_half_edge(half_edge)
.path
.point_from_path_coords(point.local_form);

ApproxPoint::new(point_surface, point.global_form)
})
Expand Down
2 changes: 1 addition & 1 deletion crates/fj-core/src/algorithms/approx/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl Approx for &Face {
exterior,
interiors,
color: self.region().get_color(core),
coord_handedness: self.coord_handedness(),
coord_handedness: self.coord_handedness(&core.layers.geometry),
}
}
}
Expand Down
12 changes: 8 additions & 4 deletions crates/fj-core/src/algorithms/bounding_volume/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ use fj_math::{Aabb, Vector};
use crate::{
geometry::{Geometry, SurfacePath},
objects::HalfEdge,
storage::Handle,
};

impl super::BoundingVolume<2> for HalfEdge {
fn aabb(&self, _: &Geometry) -> Option<Aabb<2>> {
match self.path() {
impl super::BoundingVolume<2> for Handle<HalfEdge> {
fn aabb(&self, geometry: &Geometry) -> Option<Aabb<2>> {
match geometry.of_half_edge(self).path {
SurfacePath::Circle(circle) => {
// Just calculate the AABB of the whole circle. This is not the
// most precise, but it should do for now.
Expand All @@ -22,7 +23,10 @@ impl super::BoundingVolume<2> for HalfEdge {
}
SurfacePath::Line(_) => {
let points = self.boundary().inner.map(|point_curve| {
self.path().point_from_path_coords(point_curve)
geometry
.of_half_edge(self)
.path
.point_from_path_coords(point_curve)
});

Some(Aabb::<2>::from_points(points))
Expand Down
6 changes: 3 additions & 3 deletions crates/fj-core/src/objects/kinds/cycle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use fj_math::{Scalar, Winding};

use crate::{
geometry::SurfacePath,
geometry::{Geometry, SurfacePath},
objects::{HalfEdge, ObjectSet},
storage::Handle,
};
Expand Down Expand Up @@ -29,7 +29,7 @@ impl Cycle {
/// Please note that this is not *the* winding of the cycle, only one of the
/// two possible windings, depending on the direction you look at the
/// surface that the cycle is defined on from.
pub fn winding(&self) -> Winding {
pub fn winding(&self, geometry: &Geometry) -> Winding {
// The cycle could be made up of one or two circles. If that is the
// case, the winding of the cycle is determined by the winding of the
// first circle.
Expand All @@ -43,7 +43,7 @@ impl Cycle {
let [a, b] = first.boundary().inner;
let edge_direction_positive = a < b;

let circle = match first.path() {
let circle = match geometry.of_half_edge(first).path {
SurfacePath::Circle(circle) => circle,
SurfacePath::Line(_) => unreachable!(
"Invalid cycle: less than 3 edges, but not all are circles"
Expand Down
5 changes: 3 additions & 2 deletions crates/fj-core/src/objects/kinds/face.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use fj_math::Winding;

use crate::{
geometry::Geometry,
objects::{Region, Surface},
storage::{Handle, HandleWrapper},
};
Expand Down Expand Up @@ -64,8 +65,8 @@ impl Face {
/// Faces *do* have an orientation, meaning they have definite front and
/// back sides. The front side is the side, where the face's exterior cycle
/// is wound counter-clockwise.
pub fn coord_handedness(&self) -> Handedness {
match self.region.exterior().winding() {
pub fn coord_handedness(&self, geometry: &Geometry) -> Handedness {
match self.region.exterior().winding(geometry) {
Winding::Ccw => Handedness::RightHanded,
Winding::Cw => Handedness::LeftHanded,
}
Expand Down
4 changes: 2 additions & 2 deletions crates/fj-core/src/operations/build/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub trait BuildHalfEdge {
core: &mut Core,
) -> Handle<HalfEdge> {
let half_edge = HalfEdge::new(
sibling.path(),
core.layers.geometry.of_half_edge(sibling).path,
sibling.boundary().reverse(),
sibling.curve().clone(),
start_vertex,
Expand All @@ -44,7 +44,7 @@ pub trait BuildHalfEdge {
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry {
path: sibling.path(),
path: core.layers.geometry.of_half_edge(sibling).path,
},
);

Expand Down
4 changes: 2 additions & 2 deletions crates/fj-core/src/operations/geometry/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl UpdateHalfEdgeGeometry for Handle<HalfEdge> {
update: impl FnOnce(SurfacePath) -> SurfacePath,
core: &mut Core,
) -> Self {
let path = update(self.path());
let path = update(core.layers.geometry.of_half_edge(self).path);

let half_edge = HalfEdge::new(
path,
Expand All @@ -73,7 +73,7 @@ impl UpdateHalfEdgeGeometry for Handle<HalfEdge> {
core: &mut Core,
) -> Self {
HalfEdge::new(
self.path(),
core.layers.geometry.of_half_edge(self).path,
update(self.boundary()),
self.curve().clone(),
self.start_vertex().clone(),
Expand Down
19 changes: 16 additions & 3 deletions crates/fj-core/src/operations/holes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ impl AddHole for Shell {
[Cycle::empty().add_joined_edges(
[(
entry.clone(),
entry.path(),
core.layers
.geometry
.of_half_edge(&entry)
.path,
entry.boundary(),
)],
core,
Expand Down Expand Up @@ -139,7 +142,10 @@ impl AddHole for Shell {
[Cycle::empty().add_joined_edges(
[(
entry.clone(),
entry.path(),
core.layers
.geometry
.of_half_edge(&entry)
.path,
entry.boundary(),
)],
core,
Expand All @@ -159,7 +165,14 @@ impl AddHole for Shell {
|region, core| {
region.add_interiors(
[Cycle::empty().add_joined_edges(
[(exit.clone(), exit.path(), exit.boundary())],
[(
exit.clone(),
core.layers
.geometry
.of_half_edge(exit)
.path,
exit.boundary(),
)],
core,
)],
core,
Expand Down
4 changes: 2 additions & 2 deletions crates/fj-core/src/operations/reverse/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl Reverse for Cycle {
.pairs()
.map(|(current, next)| {
let half_edge = HalfEdge::new(
current.path(),
core.layers.geometry.of_half_edge(current).path,
current.boundary().reverse(),
current.curve().clone(),
next.start_vertex().clone(),
Expand All @@ -25,7 +25,7 @@ impl Reverse for Cycle {
core.layers.geometry.define_half_edge(
half_edge.clone(),
HalfEdgeGeometry {
path: current.path(),
path: core.layers.geometry.of_half_edge(current).path,
},
);

Expand Down
2 changes: 1 addition & 1 deletion crates/fj-core/src/operations/reverse/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::ReverseCurveCoordinateSystems;

impl ReverseCurveCoordinateSystems for Handle<HalfEdge> {
fn reverse_curve_coordinate_systems(&self, core: &mut Core) -> Self {
let path = self.path().reverse();
let path = core.layers.geometry.of_half_edge(self).path.reverse();
let boundary = self.boundary().reverse();

let half_edge = HalfEdge::new(
Expand Down
14 changes: 9 additions & 5 deletions crates/fj-core/src/operations/split/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub trait SplitHalfEdge {
) -> [Handle<HalfEdge>; 2];
}

impl SplitHalfEdge for HalfEdge {
impl SplitHalfEdge for Handle<HalfEdge> {
fn split_half_edge(
&self,
point: impl Into<Point<1>>,
Expand All @@ -44,14 +44,14 @@ impl SplitHalfEdge for HalfEdge {
let [start, end] = self.boundary().inner;

let a = HalfEdge::new(
self.path(),
core.layers.geometry.of_half_edge(self).path,
[start, point],
self.curve().clone(),
self.start_vertex().clone(),
)
.insert(core);
let b = HalfEdge::new(
self.path(),
core.layers.geometry.of_half_edge(self).path,
[point, end],
self.curve().clone(),
Vertex::new().insert(core),
Expand All @@ -60,11 +60,15 @@ impl SplitHalfEdge for HalfEdge {

core.layers.geometry.define_half_edge(
a.clone(),
HalfEdgeGeometry { path: self.path() },
HalfEdgeGeometry {
path: core.layers.geometry.of_half_edge(self).path,
},
);
core.layers.geometry.define_half_edge(
b.clone(),
HalfEdgeGeometry { path: self.path() },
HalfEdgeGeometry {
path: core.layers.geometry.of_half_edge(self).path,
},
);

[a, b]
Expand Down
2 changes: 1 addition & 1 deletion crates/fj-core/src/operations/sweep/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl SweepCycle for Cycle {

top_edges.push((
top_edge,
bottom_half_edge.path(),
core.layers.geometry.of_half_edge(bottom_half_edge).path,
bottom_half_edge.boundary(),
));
}
Expand Down
9 changes: 7 additions & 2 deletions crates/fj-core/src/operations/sweep/half_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub trait SweepHalfEdge {
) -> (Face, Handle<HalfEdge>);
}

impl SweepHalfEdge for HalfEdge {
impl SweepHalfEdge for Handle<HalfEdge> {
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
Expand All @@ -59,7 +59,12 @@ impl SweepHalfEdge for HalfEdge {
) -> (Face, Handle<HalfEdge>) {
let path = path.into();

let surface = self.path().sweep_surface_path(surface, path, core);
let surface = core
.layers
.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
// the global vertices and edges.
Expand Down
5 changes: 4 additions & 1 deletion crates/fj-core/src/operations/sweep/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ impl SweepSketch for Sketch {
let region = {
// The following code assumes that the sketch is winded counter-
// clockwise. Let's check that real quick.
assert!(region.exterior().winding().is_ccw());
assert!(region
.exterior()
.winding(&core.layers.geometry)
.is_ccw());

let is_negative_sweep = {
let u = match core.layers.geometry.of_surface(&surface).u {
Expand Down
2 changes: 1 addition & 1 deletion crates/fj-core/src/operations/transform/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl TransformObject for Handle<HalfEdge> {
) -> Self {
// Don't need to transform the path, as that's defined in surface
// coordinates.
let path = self.path();
let path = core.layers.geometry.of_half_edge(self).path;
let boundary = self.boundary();
let curve = self
.curve()
Expand Down
14 changes: 9 additions & 5 deletions crates/fj-core/src/validate/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ impl Validate for Face {
&self,
_: &ValidationConfig,
errors: &mut Vec<ValidationError>,
_: &Geometry,
geometry: &Geometry,
) {
FaceValidationError::check_boundary(self, errors);
FaceValidationError::check_interior_winding(self, errors);
FaceValidationError::check_interior_winding(self, geometry, errors);
}
}

Expand Down Expand Up @@ -56,22 +56,26 @@ impl FaceValidationError {
// checks for `Cycle` to make sure that the cycle is closed properly.
}

fn check_interior_winding(face: &Face, errors: &mut Vec<ValidationError>) {
fn check_interior_winding(
face: &Face,
geometry: &Geometry,
errors: &mut Vec<ValidationError>,
) {
if face.region().exterior().half_edges().is_empty() {
// Can't determine winding, if the cycle has no edges. Sounds like a
// job for a different validation check.
return;
}

let exterior_winding = face.region().exterior().winding();
let exterior_winding = face.region().exterior().winding(geometry);

for interior in face.region().interiors() {
if interior.half_edges().is_empty() {
// Can't determine winding, if the cycle has no edges. Sounds
// like a job for a different validation check.
continue;
}
let interior_winding = interior.winding();
let interior_winding = interior.winding(geometry);

if exterior_winding == interior_winding {
errors.push(
Expand Down
Loading