diff --git a/Cargo.lock b/Cargo.lock index 75125075e..09dff2952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3513,6 +3513,13 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vertices-indices" +version = "0.1.0" +dependencies = [ + "fj", +] + [[package]] name = "walkdir" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index cd3864d13..26b18ba89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "models/spacer", "models/split", "models/star", + "models/vertices-indices", "tools/autolib", "tools/automator", 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 diff --git a/models/vertices-indices/Cargo.toml b/models/vertices-indices/Cargo.toml new file mode 100644 index 000000000..33aff7f9a --- /dev/null +++ b/models/vertices-indices/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "vertices-indices" +version = "0.1.0" +edition = "2021" + +[dependencies.fj] +path = "../../crates/fj" diff --git a/models/vertices-indices/src/lib.rs b/models/vertices-indices/src/lib.rs new file mode 100644 index 000000000..15050e57e --- /dev/null +++ b/models/vertices-indices/src/lib.rs @@ -0,0 +1,21 @@ +use fj::core::{ + objects::{Shell, Solid}, + operations::{ + build::{BuildShell, BuildSolid}, + insert::Insert, + update::UpdateSolid, + }, + services::Services, + storage::Handle, +}; + +pub fn model(services: &mut Services) -> Handle { + Solid::empty() + .add_shells([Shell::from_vertices_and_indices( + [[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]], + [[2, 1, 0], [0, 1, 3], [1, 2, 3], [2, 0, 3]], + services, + ) + .insert(services)]) + .insert(services) +} diff --git a/models/vertices-indices/src/main.rs b/models/vertices-indices/src/main.rs new file mode 100644 index 000000000..2587df58c --- /dev/null +++ b/models/vertices-indices/src/main.rs @@ -0,0 +1,8 @@ +use fj::{core::services::Services, handle_model}; + +fn main() -> fj::Result { + let mut services = Services::new(); + let model = vertices_indices::model(&mut services); + handle_model(model, services)?; + Ok(()) +}