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

Lift limitation when inferring surface as plane #1556

Merged
merged 14 commits into from
Feb 2, 2023
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/builder/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl CycleBuilder for PartialCycle {
) -> [Partial<HalfEdge>; 3] {
let points_global = points_global.map(Into::into);

let points_surface = self
let (points_surface, _) = self
.surface
.write()
.update_as_plane_from_points(points_global);
Expand Down
82 changes: 48 additions & 34 deletions crates/fj-kernel/src/builder/face.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::VecDeque;
use std::{array, collections::VecDeque};

use fj_interop::ext::ArrayExt;

Expand All @@ -12,7 +12,7 @@ use super::{CycleBuilder, HalfEdgeBuilder, ObjectArgument, SurfaceBuilder};

/// Builder API for [`PartialFace`]
pub trait FaceBuilder {
/// Connect the face to another face at the provided half-edges
/// Connect the face to other faces at the provided half-edges
///
/// Assumes that the provided half-edges, once translated into local
/// equivalents of this face, will not form a cycle.
Expand All @@ -26,7 +26,7 @@ pub trait FaceBuilder {
where
O: ObjectArgument<Partial<HalfEdge>>;

/// Connect the face to another face at the provided half-edges
/// Connect the face to other faces at the provided half-edges
///
/// Assumes that the provided half-edges, once translated into local
/// equivalents of this face, form a cycle.
Expand Down Expand Up @@ -109,38 +109,52 @@ impl FaceBuilder for PartialFace {

fn update_surface_as_plane(&mut self) -> Partial<Surface> {
let mut exterior = self.exterior.write();
let mut vertices = exterior.half_edges.iter().map(|half_edge| {
let [vertex, _] = &half_edge.read().vertices;
vertex.1.clone()
});

let vertices = {
let array = [
vertices.next().expect("Expected exactly three vertices"),
vertices.next().expect("Expected exactly three vertices"),
vertices.next().expect("Expected exactly three vertices"),
];

assert!(
vertices.next().is_none(),
"Expected exactly three vertices"
);

array
let mut vertices = exterior
.half_edges
.iter()
.map(|half_edge| {
let [(_, surface_vertex), _] = &half_edge.read().vertices;
let global_position = surface_vertex
.read()
.global_form
.read()
.position
.expect("Need global position to infer plane");

(surface_vertex.clone(), global_position)
})
.collect::<VecDeque<_>>();

let (first_three_vertices, surface) = {
let first_three_vertices = array::from_fn(|_| {
vertices
.pop_front()
.expect("Expected at least three vertices")
});

let first_three_points_global =
first_three_vertices.each_ref_ext().map(|(_, point)| *point);

let (first_three_points_surface, surface) = exterior
.surface
.write()
.update_as_plane_from_points(first_three_points_global);

let first_three_vertices = first_three_vertices
.zip_ext(first_three_points_surface)
.map(|((vertex, _), point_global)| (vertex, point_global));

(first_three_vertices, surface)
};
let points = vertices.each_ref_ext().map(|vertex| {
vertex
.read()
.global_form
.read()
.position
.expect("Need global position to infer plane")
});

let points_surface =
exterior.surface.write().update_as_plane_from_points(points);

for (mut surface_vertex, point) in vertices.zip_ext(points_surface) {
let rest_of_vertices =
vertices.into_iter().map(|(vertex, point_global)| {
let point_surface = surface.project_global_point(point_global);
(vertex, point_surface)
});

for (mut surface_vertex, point) in
first_three_vertices.into_iter().chain(rest_of_vertices)
{
surface_vertex.write().position = Some(point);
}

Expand Down
13 changes: 8 additions & 5 deletions crates/fj-kernel/src/builder/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait SurfaceBuilder: Sized {
fn update_as_plane_from_points(
&mut self,
points: [impl Into<Point<3>>; 3],
) -> [Point<2>; 3];
) -> ([Point<2>; 3], SurfaceGeometry);
}

impl SurfaceBuilder for PartialSurface {
Expand All @@ -29,16 +29,19 @@ impl SurfaceBuilder for PartialSurface {
fn update_as_plane_from_points(
&mut self,
points: [impl Into<Point<3>>; 3],
) -> [Point<2>; 3] {
) -> ([Point<2>; 3], SurfaceGeometry) {
let [a, b, c] = points.map(Into::into);

let (u, u_coords) = GlobalPath::line_from_points([a, b]);
let v = c - a;

self.geometry = Some(SurfaceGeometry { u, v });
let geometry = SurfaceGeometry { u, v };
self.geometry = Some(geometry);

let [a, b] = u_coords.map(|point| point.t);
[[a, Scalar::ZERO], [b, Scalar::ZERO], [a, Scalar::ONE]]
.map(Point::from)
let points = [[a, Scalar::ZERO], [b, Scalar::ZERO], [a, Scalar::ONE]]
.map(Point::from);

(points, geometry)
}
}
13 changes: 12 additions & 1 deletion crates/fj-kernel/src/geometry/surface.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The geometry that defines a surface

use fj_math::{Line, Point, Transform, Vector};
use fj_math::{Line, Plane, Point, Transform, Vector};

use super::path::GlobalPath;

Expand Down Expand Up @@ -39,6 +39,17 @@ impl SurfaceGeometry {
Line::from_origin_and_direction(self.u.origin(), self.v)
}

/// Project the global point into the surface
pub fn project_global_point(&self, point: impl Into<Point<3>>) -> Point<2> {
let GlobalPath::Line(line) = self.u else {
todo!("Projecting point into non-plane surface is not supported")
};

let plane =
Plane::from_parametric(line.origin(), line.direction(), self.v);
plane.project_point(point)
}

/// Transform the surface geometry
#[must_use]
pub fn transform(self, transform: &Transform) -> Self {
Expand Down