Skip to content

Commit

Permalink
Merge pull request #1556 from hannobraun/builder
Browse files Browse the repository at this point in the history
Lift limitation when inferring surface as plane
  • Loading branch information
hannobraun authored Feb 2, 2023
2 parents 49279d6 + 2cd0b50 commit 30337ef
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 41 deletions.
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

0 comments on commit 30337ef

Please sign in to comment.