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

Replace problematic Edge constructor with a simpler one #627

Merged
merged 9 commits into from
May 25, 2022
Merged
12 changes: 9 additions & 3 deletions crates/fj-kernel/src/shape/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ mod tests {

use crate::{
geometry::{Curve, Surface},
shape::{Handle, Shape, ValidationError, ValidationResult},
shape::{Handle, LocalForm, Shape, ValidationError, ValidationResult},
topology::{Cycle, Edge, Face, Vertex},
};

Expand Down Expand Up @@ -382,18 +382,24 @@ mod tests {
let a = Vertex::builder(&mut other).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut other).build_from_point([2., 0., 0.])?;

let a = LocalForm::new(Point::from([1.]), a);
let b = LocalForm::new(Point::from([2.]), b);

// Shouldn't work. Nothing has been added to `shape`.
let err = shape
.insert(Edge::new(curve.clone(), Some([a.clone(), b.clone()])))
.unwrap_err();
assert!(err.missing_curve(&curve));
assert!(err.missing_vertex(&a));
assert!(err.missing_vertex(&b));
assert!(err.missing_vertex(&a.canonical()));
assert!(err.missing_vertex(&b.canonical()));

let curve = shape.add_curve()?;
let a = Vertex::builder(&mut shape).build_from_point([1., 0., 0.])?;
let b = Vertex::builder(&mut shape).build_from_point([2., 0., 0.])?;

let a = LocalForm::new(Point::from([1.]), a);
let b = LocalForm::new(Point::from([2.]), b);

// Everything has been added to `shape` now. Should work!
shape.insert(Edge::new(curve, Some([a, b])))?;

Expand Down
23 changes: 16 additions & 7 deletions crates/fj-kernel/src/shape/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use crate::{
topology::{Cycle, Edge, Face, Vertex},
};

use super::{validate::Validate, Handle, Mapping, Shape, ValidationResult};
use super::{
validate::Validate, Handle, LocalForm, Mapping, Shape, ValidationError,
ValidationResult,
};

/// Marker trait for geometric and topological objects
pub trait Object:
Expand Down Expand Up @@ -116,12 +119,18 @@ impl Object for Edge<3> {

// Can be cleaned up using `try_map`, once that is stable:
// https://doc.rust-lang.org/std/primitive.array.html#method.try_map
let vertices = self.vertices.map(|vertices| {
vertices.map(|vertex| {
let vertex = vertex.canonical();
vertex.get().merge_into(Some(vertex), shape, mapping)
})
});
let vertices: Option<[Result<_, ValidationError>; 2]> =
self.vertices.map(|vertices| {
vertices.map(|vertex| {
let canonical = vertex.canonical();
let canonical = canonical.get().merge_into(
Some(canonical),
shape,
mapping,
)?;
Ok(LocalForm::new(*vertex.local(), canonical))
})
});
let vertices = match vertices {
Some([a, b]) => Some([a?, b?]),
None => None,
Expand Down
9 changes: 8 additions & 1 deletion crates/fj-kernel/src/topology/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use fj_math::{Circle, Line, Point, Scalar, Vector};

use crate::{
geometry::{Curve, Surface},
shape::{Handle, Shape, ValidationResult},
shape::{Handle, LocalForm, Shape, ValidationResult},
};

use super::{Cycle, Edge, Face, Vertex};
Expand Down Expand Up @@ -85,6 +85,13 @@ impl<'r> EdgeBuilder<'r> {
let curve = self.shape.insert(Curve::Line(Line::from_points(
vertices.clone().map(|vertex| vertex.get().point()),
)))?;

let [a, b] = vertices;
let vertices = [
LocalForm::new(Point::from([0.]), a),
LocalForm::new(Point::from([1.]), b),
];

let edge = self.shape.insert(Edge::new(curve, Some(vertices)))?;

Ok(edge)
Expand Down
33 changes: 1 addition & 32 deletions crates/fj-kernel/src/topology/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,11 @@ pub struct Edge<const D: usize> {

impl Edge<3> {
/// Construct an instance of `Edge`
///
/// # Implementation Note
///
/// This method accepts two `Handle<Vertex>`, and projects them onto the
/// curve, to create the local representation that is stored in `Edge`. This
/// could lead to incorrect results, as the caller could provide vertices
/// that don't actually lie on `curve`.
///
/// The good news is, that whole thing seems to be unnecessary. Or rather,
/// this whole method seems to be unnecessary. I reviewed all the call
/// sites, and in all cases, there seems to be a better way to construct the
/// `Edge`, without using this constructor.
///
/// Ideally, we'd just fix all those call sites and remove this method, to
/// completely avoid the potential for any bugs to occur here. Problem is,
/// some of those call sites can't be fixed easily, without building further
/// infrastructure. Here's one such piece of infrastructure, for which an
/// issue already exists:
/// <https://github.com/hannobraun/Fornjot/issues/399>
pub fn new(
curve: Handle<Curve<3>>,
vertices: Option<[Handle<Vertex>; 2]>,
vertices: Option<[LocalForm<Point<1>, Vertex>; 2]>,
) -> Self {
let curve = LocalForm::canonical_only(curve);

let vertices = vertices.map(|vertices| {
vertices.map(|canonical| {
let local = curve
.canonical()
.get()
.point_to_curve_coords(canonical.get().point())
.local();
LocalForm::new(local, canonical)
})
});

Self { curve, vertices }
}

Expand Down
17 changes: 10 additions & 7 deletions crates/fj-operations/src/difference_2d.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use fj_interop::debug::DebugInfo;
use fj_kernel::{
algorithms::Tolerance,
shape::{Handle, Shape, ValidationError, ValidationResult},
shape::{Handle, LocalForm, Shape, ValidationError, ValidationResult},
topology::{Cycle, Edge, Face},
};
use fj_math::Aabb;
Expand Down Expand Up @@ -103,14 +103,17 @@ fn add_cycle(
let curve = if reverse { curve.reverse() } else { curve };
let curve = shape.insert(curve)?;

let vertices = edge.vertices.clone().map(|vs| {
let mut vs = vs.map(|vertex| vertex.canonical());

let vertices = edge.vertices.clone().map(|[a, b]| {
if reverse {
vs.reverse();
// Switch `a` and `b`, but make sure the local forms are still
// correct, after we reversed the curve above.
[
LocalForm::new(-(*b.local()), b.canonical()),
LocalForm::new(-(*a.local()), a.canonical()),
]
} else {
[a, b]
}

vs
});

let edge = shape.merge(Edge::new(curve, vertices))?;
Expand Down