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

Fix all known GlobalVertex duplication issues #1238

Merged
merged 15 commits into from
Oct 19, 2022
5 changes: 3 additions & 2 deletions crates/fj-kernel/src/algorithms/sweep/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use crate::{
storage::Handle,
};

use super::Sweep;
use super::{Sweep, SweepCache};

impl Sweep for Handle<Curve> {
type Swept = Handle<Surface>;

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
_: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
match self.surface().u() {
Expand Down
15 changes: 8 additions & 7 deletions crates/fj-kernel/src/algorithms/sweep/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ use crate::{
path::SurfacePath,
};

use super::Sweep;
use super::{Sweep, SweepCache};

impl Sweep for (HalfEdge, Color) {
type Swept = Face;

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
let (edge, color) = self;
let path = path.into();

let surface = edge.curve().clone().sweep(path, objects);
let surface =
edge.curve().clone().sweep_with_cache(path, cache, objects);

// We can't use the edge we're sweeping from as the bottom edge, as that
// is not defined in the right surface. Let's create a new bottom edge,
Expand Down Expand Up @@ -82,10 +84,9 @@ impl Sweep for (HalfEdge, Color) {
HalfEdge::new(vertices, edge.global_form().clone())
};

let side_edges = bottom_edge
.vertices()
.clone()
.map(|vertex| (vertex, surface.clone()).sweep(path, objects));
let side_edges = bottom_edge.vertices().clone().map(|vertex| {
(vertex, surface.clone()).sweep_with_cache(path, cache, objects)
});

let top_edge = {
let bottom_vertices = bottom_edge.vertices();
Expand Down
8 changes: 5 additions & 3 deletions crates/fj-kernel/src/algorithms/sweep/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use crate::{
path::GlobalPath,
};

use super::Sweep;
use super::{Sweep, SweepCache};

impl Sweep for Face {
type Swept = Shell;

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
let path = path.into();
Expand Down Expand Up @@ -64,7 +65,8 @@ impl Sweep for Face {
half_edge.clone()
};

let face = (half_edge, self.color()).sweep(path, objects);
let face = (half_edge, self.color())
.sweep_with_cache(path, cache, objects);

faces.push(face);
}
Expand Down
29 changes: 27 additions & 2 deletions crates/fj-kernel/src/algorithms/sweep/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ mod face;
mod sketch;
mod vertex;

use std::collections::BTreeMap;

use fj_math::Vector;

use crate::objects::Objects;
use crate::{
objects::{GlobalVertex, Objects},
storage::{Handle, ObjectId},
};

/// Sweep an object along a path to create another object
pub trait Sweep {
pub trait Sweep: Sized {
/// The object that is created by sweeping the implementing object
type Swept;

Expand All @@ -20,5 +25,25 @@ pub trait Sweep {
self,
path: impl Into<Vector<3>>,
objects: &Objects,
) -> Self::Swept {
let mut cache = SweepCache::default();
self.sweep_with_cache(path, &mut cache, objects)
}

/// Sweep the object along the given path, using the provided cache
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept;
}

/// A cache used for sweeping
///
/// See [`Sweep`].
#[derive(Default)]
pub struct SweepCache {
/// Cache for global vertices
pub global_vertex: BTreeMap<ObjectId, Handle<GlobalVertex>>,
}
7 changes: 4 additions & 3 deletions crates/fj-kernel/src/algorithms/sweep/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ use fj_math::Vector;

use crate::objects::{Objects, Sketch, Solid};

use super::Sweep;
use super::{Sweep, SweepCache};

impl Sweep for Sketch {
type Swept = Solid;

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
let path = path.into();

let mut shells = Vec::new();
for face in self.into_faces() {
let shell = face.sweep(path, objects);
let shell = face.sweep_with_cache(path, cache, objects);
shells.push(shell);
}

Expand Down
26 changes: 19 additions & 7 deletions crates/fj-kernel/src/algorithms/sweep/vertex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ use crate::{
storage::Handle,
};

use super::Sweep;
use super::{Sweep, SweepCache};

impl Sweep for (Vertex, Handle<Surface>) {
type Swept = HalfEdge;

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
let (vertex, surface) = self;
Expand Down Expand Up @@ -57,8 +58,10 @@ impl Sweep for (Vertex, Handle<Surface>) {
// With that out of the way, let's start by creating the `GlobalEdge`,
// as that is the most straight-forward part of this operations, and
// we're going to need it soon anyway.
let (edge_global, vertices_global) =
vertex.global_form().clone().sweep(path, objects);
let (edge_global, vertices_global) = vertex
.global_form()
.clone()
.sweep_with_cache(path, cache, objects);

// Next, let's compute the surface coordinates of the two vertices of
// the output `Edge`, as we're going to need these for the rest of this
Expand Down Expand Up @@ -120,16 +123,25 @@ impl Sweep for (Vertex, Handle<Surface>) {
impl Sweep for Handle<GlobalVertex> {
type Swept = (GlobalEdge, [Handle<GlobalVertex>; 2]);

fn sweep(
fn sweep_with_cache(
self,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
objects: &Objects,
) -> Self::Swept {
let curve = GlobalCurve::new(objects);

let a = self.clone();
let b =
GlobalVertex::from_position(self.position() + path.into(), objects);
let b = cache
.global_vertex
.entry(self.id())
.or_insert_with(|| {
GlobalVertex::from_position(
self.position() + path.into(),
objects,
)
})
.clone();

let vertices = [a, b];
let global_edge = GlobalEdge::new(curve, vertices.clone());
Expand Down
31 changes: 22 additions & 9 deletions crates/fj-kernel/src/objects/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ impl HalfEdge {

let curve = a.curve();

let (vertices_in_normalized_order, _) = VerticesInNormalizedOrder::new(
[&a, &b].map(|vertex| vertex.global_form().clone()),
);

// Make sure `curve` and `vertices` match `global_form`.
assert_eq!(
curve.global_form().id(),
Expand All @@ -47,10 +51,15 @@ impl HalfEdge {
the half-edge's global form"
);
assert_eq!(
&VerticesInNormalizedOrder::new(
[&a, &b].map(|vertex| vertex.global_form().clone())
),
global_form.vertices(),
vertices_in_normalized_order
.access_in_normalized_order()
.clone()
.map(|global_vertex| global_vertex.id()),
global_form
.vertices()
.access_in_normalized_order()
.clone()
.map(|global_vertex| global_vertex.id()),
"The global forms of a half-edge's vertices must match the \
vertices of the half-edge's global form"
);
Expand Down Expand Up @@ -130,7 +139,7 @@ impl GlobalEdge {
vertices: [Handle<GlobalVertex>; 2],
) -> Self {
let curve = curve.into();
let vertices = VerticesInNormalizedOrder::new(vertices);
let (vertices, _) = VerticesInNormalizedOrder::new(vertices);
Self { curve, vertices }
}

Expand Down Expand Up @@ -166,10 +175,14 @@ pub struct VerticesInNormalizedOrder([Handle<GlobalVertex>; 2]);
impl VerticesInNormalizedOrder {
/// Construct a new instance of `VerticesInNormalizedOrder`
///
/// The provided vertices can be in any order.
pub fn new([a, b]: [Handle<GlobalVertex>; 2]) -> Self {
let vertices = if a < b { [a, b] } else { [b, a] };
Self(vertices)
/// The provided vertices can be in any order. The returned `bool` value
/// indicates whether the normalization changed the order of the vertices.
pub fn new([a, b]: [Handle<GlobalVertex>; 2]) -> (Self, bool) {
if a < b {
(Self([a, b]), false)
} else {
(Self([b, a]), true)
}
}

/// Access the vertices
Expand Down
14 changes: 12 additions & 2 deletions crates/fj-kernel/src/partial/maybe_partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use fj_math::Point;

use crate::{
objects::{
Curve, GlobalCurve, GlobalEdge, HalfEdge, Objects, Surface,
SurfaceVertex, Vertex,
Curve, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, Objects,
Surface, SurfaceVertex, Vertex,
},
storage::Handle,
};
Expand Down Expand Up @@ -102,6 +102,16 @@ impl MaybePartial<GlobalEdge> {
}
}
}

/// Access the vertices
pub fn vertices(&self) -> Option<&[Handle<GlobalVertex>; 2]> {
match self {
Self::Full(full) => {
Some(full.vertices().access_in_normalized_order())
}
Self::Partial(partial) => partial.vertices.as_ref(),
}
}
}

impl MaybePartial<HalfEdge> {
Expand Down
Loading