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

Make GlobalEdge undirected #1155

Merged
merged 6 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions crates/fj-kernel/src/algorithms/reverse/edge.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::objects::{GlobalEdge, HalfEdge};
use crate::objects::HalfEdge;

use super::Reverse;

Expand All @@ -12,18 +12,7 @@ impl Reverse for HalfEdge {
HalfEdge::new(
self.curve().clone(),
vertices,
self.global_form().clone().reverse(),
self.global_form().clone(),
)
}
}

impl Reverse for GlobalEdge {
fn reverse(self) -> Self {
let vertices = {
let &[a, b] = self.vertices();
[b, a]
};

GlobalEdge::new(self.curve().clone(), vertices)
}
}
19 changes: 12 additions & 7 deletions crates/fj-kernel/src/algorithms/sweep/vertex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ impl Sweep for (Vertex, 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 = vertex.global_form().sweep(path, stores);
let (edge_global, vertices_global) =
vertex.global_form().sweep(path, stores);

// 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 @@ -87,15 +88,13 @@ impl Sweep for (Vertex, Surface) {

// And now the vertices. Again, nothing wild here.
let vertices = {
let vertices_global = edge_global.vertices();

// Can be cleaned up, once `zip` is stable:
// https://doc.rust-lang.org/std/primitive.array.html#method.zip
let [a_surface, b_surface] = points_surface;
let [a_global, b_global] = vertices_global;
let vertices_surface =
[(a_surface, a_global), (b_surface, b_global)].map(
|(point_surface, &vertex_global)| {
|(point_surface, vertex_global)| {
SurfaceVertex::new(
point_surface,
surface,
Expand All @@ -110,7 +109,7 @@ impl Sweep for (Vertex, Surface) {
let [a_global, b_global] = vertices_global;
let vertices = [(a_surface, a_global), (b_surface, b_global)];

vertices.map(|(vertex_surface, &vertex_global)| {
vertices.map(|(vertex_surface, vertex_global)| {
Vertex::new(
[vertex_surface.position().v],
curve.clone(),
Expand All @@ -127,15 +126,21 @@ impl Sweep for (Vertex, Surface) {
}

impl Sweep for GlobalVertex {
type Swept = GlobalEdge;
type Swept = (GlobalEdge, [GlobalVertex; 2]);

fn sweep(self, path: impl Into<Vector<3>>, stores: &Stores) -> Self::Swept {
let curve = GlobalCurve::new(stores);

let a = self;
let b = GlobalVertex::from_position(self.position() + path.into());

GlobalEdge::new(curve, [a, b])
let vertices = [a, b];
let global_edge = GlobalEdge::new(curve, vertices);

// The vertices of the returned `GlobalEdge` are in normalized order,
// which means the order can't be relied upon by the caller. Return the
// ordered vertices in addition.
(global_edge, vertices)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/algorithms/transform/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl TransformObject for GlobalEdge {
fn transform(self, transform: &Transform, stores: &Stores) -> Self {
let curve = self.curve().clone().transform(transform, stores);
let vertices = self
.vertices()
.vertices_in_normalized_order()
.map(|vertex| vertex.transform(transform, stores));

Self::new(curve, vertices)
Expand Down
61 changes: 55 additions & 6 deletions crates/fj-kernel/src/objects/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ impl HalfEdge {
the half-edge's global form"
);
assert_eq!(
&vertices.clone().map(|vertex| *vertex.global_form()),
global_form.vertices(),
&normalize_vertex_order(
vertices.clone().map(|vertex| *vertex.global_form())
),
global_form.vertices_in_normalized_order(),
"The global forms of a half-edge's vertices must match the \
vertices of the half-edge's global form"
);
Expand Down Expand Up @@ -108,6 +110,11 @@ impl fmt::Display for HalfEdge {
}

/// An edge, defined in global (3D) coordinates
///
/// In contract to [`HalfEdge`], `GlobalEdge` is undirected, meaning it has no
/// defined direction, and its vertices have no defined order. This means it can
/// be used to determine whether two [`HalfEdge`]s map to the same `GlobalEdge`,
/// regardless of their direction.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct GlobalEdge {
curve: HandleWrapper<GlobalCurve>,
Expand All @@ -116,11 +123,16 @@ pub struct GlobalEdge {

impl GlobalEdge {
/// Create a new instance
///
/// The order of `vertices` is irrelevant. Two `GlobalEdge`s with the same
/// `curve` and `vertices` will end up being equal, regardless of the order
/// of `vertices` here.
pub fn new(
curve: impl Into<HandleWrapper<GlobalCurve>>,
vertices: [GlobalVertex; 2],
) -> Self {
let curve = curve.into();
let vertices = normalize_vertex_order(vertices);
Self { curve, vertices }
}

Expand All @@ -135,10 +147,47 @@ impl GlobalEdge {

/// Access the vertices that bound the edge on the curve
///
/// An edge has either two bounding vertices or none. The latter is possible
/// if the edge's curve is continuous (i.e. connects to itself), and defines
/// the whole edge.
pub fn vertices(&self) -> &[GlobalVertex; 2] {
/// As the name indicates, the order of the returned vertices is normalized
/// and might not match the order of the vertices that were passed to
/// [`GlobalEdge::new`]. You must not rely on the vertices being in any
/// specific order.
pub fn vertices_in_normalized_order(&self) -> &[GlobalVertex; 2] {
&self.vertices
}
}

fn normalize_vertex_order([a, b]: [GlobalVertex; 2]) -> [GlobalVertex; 2] {
if a < b {
[a, b]
} else {
[b, a]
}
}

#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;

use crate::{objects::Surface, partial::HasPartial, stores::Stores};

use super::HalfEdge;

#[test]
fn global_edge_equality() {
let stores = Stores::new();

let surface = Surface::xy_plane();

let a = [0., 0.];
let b = [1., 0.];

let a_to_b = HalfEdge::partial()
.as_line_segment_from_points(surface, [a, b])
.build(&stores);
let b_to_a = HalfEdge::partial()
.as_line_segment_from_points(surface, [b, a])
.build(&stores);

assert_eq!(a_to_b.global_form(), b_to_a.global_form());
}
}
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/partial/objects/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ impl From<&GlobalEdge> for PartialGlobalEdge {
fn from(global_edge: &GlobalEdge) -> Self {
Self {
curve: Some(global_edge.curve().clone().into()),
vertices: Some(*global_edge.vertices()),
vertices: Some(*global_edge.vertices_in_normalized_order()),
}
}
}