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

Add BuildFace::polygon, clean up BuildFace::triangle #1912

Merged
merged 9 commits into from
Jun 27, 2023
14 changes: 1 addition & 13 deletions crates/fj-core/src/operations/build/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use fj_math::{Arc, Point, Scalar};

use crate::{
geometry::curve::Curve,
objects::{GlobalEdge, HalfEdge, Surface, Vertex},
objects::{GlobalEdge, HalfEdge, Vertex},
operations::Insert,
services::Services,
};
Expand Down Expand Up @@ -75,18 +75,6 @@ pub trait BuildHalfEdge {

HalfEdge::unjoined(curve, boundary, services)
}

/// Create a line segment from global points
fn line_segment_from_global_points(
points_global: [impl Into<Point<3>>; 2],
surface: &Surface,
boundary: Option<[Point<1>; 2]>,
services: &mut Services,
) -> HalfEdge {
let points_surface = points_global
.map(|point| surface.geometry().project_global_point(point));
HalfEdge::line_segment(points_surface, boundary, services)
}
}

impl BuildHalfEdge for HalfEdge {}
53 changes: 32 additions & 21 deletions crates/fj-core/src/operations/build/face.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::array;

use fj_interop::ext::ArrayExt;
use fj_math::Point;

use crate::{
objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex},
operations::{
BuildCycle, BuildHalfEdge, BuildSurface, Insert, IsInserted,
IsInsertedNo,
BuildCycle, BuildRegion, BuildSurface, Insert, IsInserted, IsInsertedNo,
},
services::Services,
storage::Handle,
Expand All @@ -25,36 +26,46 @@ pub trait BuildFace {
points: [impl Into<Point<3>>; 3],
services: &mut Services,
) -> Polygon<3> {
let [a, b, c] = points.map(Into::into);

let surface = Surface::plane_from_points([a, b, c]).insert(services);
let (exterior, edges, vertices) = {
let half_edges = [[a, b], [b, c], [c, a]].map(|points| {
let half_edge = HalfEdge::line_segment_from_global_points(
points, &surface, None, services,
);
let (surface, points_surface) = Surface::plane_from_points(points);
let surface = surface.insert(services);

half_edge.insert(services)
});
let vertices = half_edges
.each_ref_ext()
.map(|half_edge| half_edge.start_vertex().clone());
let face = Face::polygon(surface, points_surface, services);

let cycle = Cycle::new(half_edges.clone()).insert(services);
let edges = {
let mut half_edges = face.region().exterior().half_edges().cloned();
assert_eq!(half_edges.clone().count(), 3);

(cycle, half_edges, vertices)
array::from_fn(|_| half_edges.next()).map(|half_edge| {
half_edge
.expect("Just asserted that there are three half-edges")
})
};

let region = Region::new(exterior, [], None).insert(services);

let face = Face::new(surface, region);
let vertices =
edges.each_ref_ext().map(|half_edge: &Handle<HalfEdge>| {
half_edge.start_vertex().clone()
});

Polygon {
face,
edges,
vertices,
}
}

/// Build a polygon
fn polygon<P, Ps>(
surface: Handle<Surface>,
points: Ps,
services: &mut Services,
) -> Face
where
P: Into<Point<2>>,
Ps: IntoIterator<Item = P>,
Ps::IntoIter: Clone + ExactSizeIterator,
{
let region = Region::polygon(points, services).insert(services);
Face::new(surface, region)
}
}

impl BuildFace for Face {}
Expand Down
23 changes: 17 additions & 6 deletions crates/fj-core/src/operations/build/surface.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fj_math::Point;
use fj_math::{Point, Scalar};

use crate::{
geometry::{curve::GlobalPath, surface::SurfaceGeometry},
Expand All @@ -8,15 +8,26 @@ use crate::{
/// Build a [`Surface`]
pub trait BuildSurface {
/// Build a plane from the provided points
fn plane_from_points(points: [impl Into<Point<3>>; 3]) -> Surface {
fn plane_from_points(
points: [impl Into<Point<3>>; 3],
) -> (Surface, [Point<2>; 3]) {
let [a, b, c] = points.map(Into::into);

let geometry = SurfaceGeometry {
u: GlobalPath::line_from_points([a, b]).0,
v: c - a,
let (u, u_line) = GlobalPath::line_from_points([a, b]);
let v = c - a;

let geometry = SurfaceGeometry { u, v };
let surface = Surface::new(geometry);

let points_surface = {
let [a, b] =
u_line.map(|point| Point::from([point.t, Scalar::ZERO]));
let c = Point::from([a.u, Scalar::ONE]);

[a, b, c]
};

Surface::new(geometry)
(surface, points_surface)
}
}

Expand Down
10 changes: 5 additions & 5 deletions crates/fj-core/src/validate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,23 @@ impl Default for ValidationConfig {
#[derive(Clone, Debug, thiserror::Error)]
pub enum ValidationError {
/// `Cycle` validation error
#[error("`Cycle` validation error:\n {0}")]
#[error("`Cycle` validation error")]
Cycle(#[from] CycleValidationError),

/// `Face` validation error
#[error("`Face` validation error\n {0}")]
#[error("`Face` validation error")]
Face(#[from] FaceValidationError),

/// `HalfEdge` validation error
#[error("`HalfEdge` validation error\n {0}")]
#[error("`HalfEdge` validation error")]
HalfEdge(#[from] HalfEdgeValidationError),

/// `Shell` validation error
#[error("`Shell` validation error\n {0}")]
#[error("`Shell` validation error")]
Shell(#[from] ShellValidationError),

/// `Solid` validation error
#[error("`Solid` validation error\n {0}")]
#[error("`Solid` validation error")]
Solid(#[from] SolidValidationError),
}

Expand Down