Skip to content

Commit

Permalink
Merge pull request #2275 from hannobraun/geometry
Browse files Browse the repository at this point in the history
Read half-edge geometry from geometry layer in most places
  • Loading branch information
hannobraun authored Mar 20, 2024
2 parents ae74321 + ecc7f26 commit ee15b60
Show file tree
Hide file tree
Showing 20 changed files with 117 additions and 58 deletions.
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

0 comments on commit ee15b60

Please sign in to comment.