From caf6991d467c73b8aba29aebcb8b6ea6a9323a82 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 21 Dec 2023 21:17:12 +0100 Subject: [PATCH] Add `BuildShell::from_vertices_and_indices` --- crates/fj-core/src/operations/build/shell.rs | 102 ++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/crates/fj-core/src/operations/build/shell.rs b/crates/fj-core/src/operations/build/shell.rs index d77a4e435..0d4012c7e 100644 --- a/crates/fj-core/src/operations/build/shell.rs +++ b/crates/fj-core/src/operations/build/shell.rs @@ -1,13 +1,19 @@ +use std::collections::BTreeMap; + +use fj_interop::ext::ArrayExt; use fj_math::Point; use crate::{ - objects::{Face, Shell}, + geometry::CurveBoundary, + objects::{Curve, Face, HalfEdge, Shell, Surface, Vertex}, operations::{ - build::{BuildFace, Polygon}, + build::{BuildFace, BuildHalfEdge, BuildSurface, Polygon}, insert::{Insert, IsInserted, IsInsertedNo, IsInsertedYes}, join::JoinCycle, reverse::ReverseCurveCoordinateSystems, - update::{UpdateCycle, UpdateFace, UpdateRegion}, + update::{ + UpdateCycle, UpdateFace, UpdateHalfEdge, UpdateRegion, UpdateShell, + }, }, services::Services, }; @@ -23,6 +29,96 @@ pub trait BuildShell { Shell::new([]) } + /// Build a polyhedron by specifying its vertices and indices + fn from_vertices_and_indices( + vertices: impl IntoIterator>>, + indices: impl IntoIterator, + services: &mut Services, + ) -> Shell { + let vertices = vertices + .into_iter() + .enumerate() + .map(|(index, position)| { + let vertex = Vertex::new().insert(services); + let position = position.into(); + + (index, (vertex, position)) + }) + .collect::>(); + + let mut curves = BTreeMap::new(); + + let faces = indices + .into_iter() + .map(|indices| { + let [(a, a_pos), (b, b_pos), (c, c_pos)] = indices + .map(|index| vertices.get(&index).expect("Invalid index")); + + let (surface, _) = Surface::plane_from_points( + [a_pos, b_pos, c_pos].map(Clone::clone), + ); + let surface = surface.insert(services); + + let curves_and_boundaries = + [[a, b], [b, c], [c, a]].map(|vertices| { + let vertices = vertices.map(Clone::clone); + let vertices = CurveBoundary::::from(vertices); + + curves + .get(&vertices.clone().reverse()) + .cloned() + .unwrap_or_else(|| { + let curve = Curve::new().insert(services); + let boundary = + CurveBoundary::>::from([ + [0.], + [1.], + ]); + + curves.insert( + vertices, + (curve.clone(), boundary), + ); + + (curve, boundary.reverse()) + }) + }); + + let half_edges = { + let vertices = [a, b, c].map(Clone::clone); + let [a, b, c] = [[0., 0.], [1., 0.], [0., 1.]]; + vertices + .zip_ext([[a, b], [b, c], [c, a]]) + .zip_ext(curves_and_boundaries) + .map(|((vertex, positions), (curve, boundary))| { + HalfEdge::line_segment( + positions, + Some(boundary.reverse().inner), + services, + ) + .update_start_vertex(|_| vertex) + .update_curve(|_| curve) + .insert(services) + }) + }; + + Face::unbound(surface, services) + .update_region(|region| { + region + .update_exterior(|cycle| { + cycle + .add_half_edges(half_edges) + .insert(services) + }) + .insert(services) + }) + .insert(services) + }) + .collect::>(); + + Shell::empty().add_faces(faces) + } + /// Build a tetrahedron from the provided points /// /// Accepts 4 points, naturally. For the purposes of the following