mirror of
https://github.com/hannobraun/Fornjot
synced 2025-02-07 15:55:53 +00:00
Merge pull request #1599 from hannobraun/surface
Start moving reference to `Surface` from `Cycle` to `Face`
This commit is contained in:
commit
0fd4db69dc
@ -2,17 +2,15 @@
|
||||
//!
|
||||
//! See [`CycleApprox`].
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use fj_math::Segment;
|
||||
|
||||
use crate::objects::Cycle;
|
||||
use crate::objects::{Cycle, Surface};
|
||||
|
||||
use super::{
|
||||
curve::CurveCache, edge::HalfEdgeApprox, Approx, ApproxPoint, Tolerance,
|
||||
};
|
||||
|
||||
impl Approx for &Cycle {
|
||||
impl Approx for (&Cycle, &Surface) {
|
||||
type Approximation = CycleApprox;
|
||||
type Cache = CurveCache;
|
||||
|
||||
@ -21,13 +19,13 @@ impl Approx for &Cycle {
|
||||
tolerance: impl Into<Tolerance>,
|
||||
cache: &mut Self::Cache,
|
||||
) -> Self::Approximation {
|
||||
let (cycle, surface) = self;
|
||||
let tolerance = tolerance.into();
|
||||
|
||||
let half_edges = self
|
||||
let half_edges = cycle
|
||||
.half_edges()
|
||||
.map(|half_edge| {
|
||||
(half_edge, self.surface().deref())
|
||||
.approx_with_cache(tolerance, cache)
|
||||
(half_edge, surface).approx_with_cache(tolerance, cache)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! See [`FaceApprox`].
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::{collections::BTreeSet, ops::Deref};
|
||||
|
||||
use fj_interop::mesh::Color;
|
||||
|
||||
@ -87,11 +87,13 @@ impl Approx for &Face {
|
||||
// would need to provide its own approximation, as the edges that bound
|
||||
// it have nothing to do with its curvature.
|
||||
|
||||
let exterior = self.exterior().approx_with_cache(tolerance, cache);
|
||||
let exterior = (self.exterior().deref(), self.surface().deref())
|
||||
.approx_with_cache(tolerance, cache);
|
||||
|
||||
let mut interiors = BTreeSet::new();
|
||||
for cycle in self.interiors() {
|
||||
let cycle = cycle.approx_with_cache(tolerance, cache);
|
||||
let cycle = (cycle.deref(), self.surface().deref())
|
||||
.approx_with_cache(tolerance, cache);
|
||||
interiors.insert(cycle);
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,10 @@ mod tests {
|
||||
];
|
||||
|
||||
let face = {
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior
|
||||
.write()
|
||||
|
@ -93,7 +93,10 @@ mod tests {
|
||||
services.objects.surfaces.xz_plane(),
|
||||
]
|
||||
.map(|surface| {
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface);
|
||||
face.exterior.write().update_as_polygon_from_points(points);
|
||||
|
||||
@ -122,7 +125,10 @@ mod tests {
|
||||
services.objects.surfaces.xz_plane(),
|
||||
];
|
||||
let [a, b] = surfaces.clone().map(|surface| {
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface);
|
||||
face.exterior.write().update_as_polygon_from_points(points);
|
||||
|
||||
|
@ -148,9 +148,13 @@ mod tests {
|
||||
fn point_is_outside_face() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[1., 1.],
|
||||
@ -169,9 +173,13 @@ mod tests {
|
||||
fn ray_hits_vertex_while_passing_outside() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[2., 1.],
|
||||
@ -193,9 +201,13 @@ mod tests {
|
||||
fn ray_hits_vertex_at_cycle_seam() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[4., 2.],
|
||||
[0., 4.],
|
||||
@ -217,9 +229,13 @@ mod tests {
|
||||
fn ray_hits_vertex_while_staying_inside() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[2., 1.],
|
||||
@ -242,9 +258,13 @@ mod tests {
|
||||
fn ray_hits_parallel_edge_and_leaves_face_at_vertex() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[2., 1.],
|
||||
@ -267,9 +287,13 @@ mod tests {
|
||||
fn ray_hits_parallel_edge_and_does_not_leave_face_there() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[2., 1.],
|
||||
@ -293,9 +317,13 @@ mod tests {
|
||||
fn point_is_coincident_with_edge() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[2., 0.],
|
||||
@ -326,9 +354,13 @@ mod tests {
|
||||
fn point_is_coincident_with_vertex() {
|
||||
let mut services = Services::new();
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
[1., 0.],
|
||||
|
@ -163,9 +163,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.yz_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.yz_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -186,9 +190,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.yz_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.yz_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -212,9 +220,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.yz_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.yz_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -235,9 +247,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.yz_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.yz_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -269,9 +285,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.yz_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.yz_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -303,9 +323,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
@ -328,9 +352,13 @@ mod tests {
|
||||
|
||||
let ray = HorizontalRayToTheRight::from([0., 0., 0.]);
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[-1., -1.],
|
||||
[1., -1.],
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
insert::Insert,
|
||||
objects::{Face, Objects},
|
||||
partial::{FullToPartialCache, Partial, PartialFace, PartialObject},
|
||||
services::Service,
|
||||
storage::Handle,
|
||||
};
|
||||
@ -10,24 +9,13 @@ use super::Reverse;
|
||||
|
||||
impl Reverse for Handle<Face> {
|
||||
fn reverse(self, objects: &mut Service<Objects>) -> Self {
|
||||
let mut cache = FullToPartialCache::default();
|
||||
|
||||
let exterior = Partial::from_full(
|
||||
self.exterior().clone().reverse(objects),
|
||||
&mut cache,
|
||||
);
|
||||
let exterior = self.exterior().clone().reverse(objects);
|
||||
let interiors = self
|
||||
.interiors()
|
||||
.map(|cycle| {
|
||||
Partial::from_full(cycle.clone().reverse(objects), &mut cache)
|
||||
})
|
||||
.map(|cycle| cycle.clone().reverse(objects))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let face = PartialFace {
|
||||
exterior,
|
||||
interiors,
|
||||
color: Some(self.color()),
|
||||
};
|
||||
face.build(objects).insert(objects)
|
||||
Face::new(self.surface().clone(), exterior, interiors, self.color())
|
||||
.insert(objects)
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,14 @@ impl Sweep for (Handle<HalfEdge>, &Surface, Color) {
|
||||
// A face (and everything in it) is defined on a surface. A surface can
|
||||
// be created by sweeping a curve, so let's sweep the curve of the edge
|
||||
// we're sweeping.
|
||||
face.exterior.write().surface = Partial::from(
|
||||
(edge.curve().clone(), surface)
|
||||
.sweep_with_cache(path, cache, objects),
|
||||
);
|
||||
{
|
||||
let surface = Partial::from(
|
||||
(edge.curve().clone(), surface)
|
||||
.sweep_with_cache(path, cache, objects),
|
||||
);
|
||||
face.surface = surface.clone();
|
||||
face.exterior.write().surface = surface;
|
||||
}
|
||||
|
||||
// Now we're ready to create the edges.
|
||||
let mut edge_bottom = face.exterior.write().add_half_edge();
|
||||
@ -266,7 +270,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let mut cycle = PartialCycle {
|
||||
surface: Partial::from(surface),
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
cycle.half_edges.extend(
|
||||
@ -274,6 +278,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let face = PartialFace {
|
||||
surface: Partial::from(surface),
|
||||
exterior: Partial::from_partial(cycle),
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -53,12 +53,13 @@ impl Sweep for Handle<Face> {
|
||||
};
|
||||
faces.push(bottom_face.clone());
|
||||
|
||||
let top_surface =
|
||||
bottom_face.surface().clone().translate(path, objects);
|
||||
let mut top_face = PartialFace {
|
||||
surface: Partial::from(top_surface.clone()),
|
||||
color: Some(self.color()),
|
||||
..PartialFace::default()
|
||||
};
|
||||
let top_surface =
|
||||
bottom_face.surface().clone().translate(path, objects);
|
||||
|
||||
for (i, cycle) in bottom_face.all_cycles().cloned().enumerate() {
|
||||
let cycle = cycle.reverse(objects);
|
||||
@ -84,7 +85,9 @@ impl Sweep for Handle<Face> {
|
||||
|
||||
top_cycle.write().surface = Partial::from(top_surface.clone());
|
||||
|
||||
top_cycle.write().connect_to_closed_edges(top_edges);
|
||||
top_cycle
|
||||
.write()
|
||||
.connect_to_closed_edges(top_edges, &top_surface.geometry());
|
||||
|
||||
for half_edge in &mut top_cycle.write().half_edges {
|
||||
for (_, surface_vertex) in &mut half_edge.write().vertices {
|
||||
@ -161,6 +164,7 @@ mod tests {
|
||||
let mut sketch = PartialSketch::default();
|
||||
|
||||
let mut face = sketch.add_face();
|
||||
face.write().surface = Partial::from(surface.clone());
|
||||
face.write().exterior.write().surface =
|
||||
Partial::from(surface.clone());
|
||||
face.write()
|
||||
@ -175,23 +179,37 @@ mod tests {
|
||||
.insert(&mut services.objects)
|
||||
.sweep(UP, &mut services.objects);
|
||||
|
||||
let mut bottom = PartialFace::default();
|
||||
bottom.exterior.write().surface = Partial::from(surface.clone());
|
||||
bottom
|
||||
.exterior
|
||||
.write()
|
||||
.update_as_polygon_from_points(TRIANGLE);
|
||||
let bottom = bottom
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
.reverse(&mut services.objects);
|
||||
let mut top = PartialFace::default();
|
||||
top.exterior.write().surface =
|
||||
Partial::from(surface.clone().translate(UP, &mut services.objects));
|
||||
top.exterior.write().update_as_polygon_from_points(TRIANGLE);
|
||||
let top = top
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects);
|
||||
let bottom = {
|
||||
let mut bottom = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
bottom.exterior.write().surface = Partial::from(surface.clone());
|
||||
bottom
|
||||
.exterior
|
||||
.write()
|
||||
.update_as_polygon_from_points(TRIANGLE);
|
||||
|
||||
bottom
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
.reverse(&mut services.objects)
|
||||
};
|
||||
let top = {
|
||||
let surface = surface.clone().translate(UP, &mut services.objects);
|
||||
|
||||
let mut top = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
top.exterior.write().surface = Partial::from(surface);
|
||||
top.exterior.write().update_as_polygon_from_points(TRIANGLE);
|
||||
|
||||
top.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
};
|
||||
|
||||
assert!(solid.find_face(&bottom).is_some());
|
||||
assert!(solid.find_face(&top).is_some());
|
||||
@ -227,6 +245,7 @@ mod tests {
|
||||
let mut sketch = PartialSketch::default();
|
||||
|
||||
let mut face = sketch.add_face();
|
||||
face.write().surface = Partial::from(surface.clone());
|
||||
face.write().exterior.write().surface =
|
||||
Partial::from(surface.clone());
|
||||
face.write()
|
||||
@ -241,24 +260,38 @@ mod tests {
|
||||
.insert(&mut services.objects)
|
||||
.sweep(DOWN, &mut services.objects);
|
||||
|
||||
let mut bottom = PartialFace::default();
|
||||
bottom.exterior.write().surface = Partial::from(
|
||||
surface.clone().translate(DOWN, &mut services.objects),
|
||||
);
|
||||
bottom
|
||||
.exterior
|
||||
.write()
|
||||
.update_as_polygon_from_points(TRIANGLE);
|
||||
let bottom = bottom
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
.reverse(&mut services.objects);
|
||||
let mut top = PartialFace::default();
|
||||
top.exterior.write().surface = Partial::from(surface.clone());
|
||||
top.exterior.write().update_as_polygon_from_points(TRIANGLE);
|
||||
let top = top
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects);
|
||||
let bottom = {
|
||||
let surface =
|
||||
surface.clone().translate(DOWN, &mut services.objects);
|
||||
|
||||
let mut bottom = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
bottom.exterior.write().surface = Partial::from(surface);
|
||||
bottom
|
||||
.exterior
|
||||
.write()
|
||||
.update_as_polygon_from_points(TRIANGLE);
|
||||
|
||||
bottom
|
||||
.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
.reverse(&mut services.objects)
|
||||
};
|
||||
let top = {
|
||||
let mut top = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
top.exterior.write().surface = Partial::from(surface.clone());
|
||||
top.exterior.write().update_as_polygon_from_points(TRIANGLE);
|
||||
|
||||
top.build(&mut services.objects)
|
||||
.insert(&mut services.objects)
|
||||
};
|
||||
|
||||
assert!(solid.find_face(&bottom).is_some());
|
||||
assert!(solid.find_face(&top).is_some());
|
||||
|
@ -17,6 +17,10 @@ impl TransformObject for Face {
|
||||
// Color does not need to be transformed.
|
||||
let color = self.color();
|
||||
|
||||
let surface = self
|
||||
.surface()
|
||||
.clone()
|
||||
.transform_with_cache(transform, objects, cache);
|
||||
let exterior = self
|
||||
.exterior()
|
||||
.clone()
|
||||
@ -25,7 +29,7 @@ impl TransformObject for Face {
|
||||
interior.transform_with_cache(transform, objects, cache)
|
||||
});
|
||||
|
||||
Self::new(exterior, interiors, color)
|
||||
Self::new(surface, exterior, interiors, color)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,13 @@ mod tests {
|
||||
let c = [2., 2.];
|
||||
let d = [0., 1.];
|
||||
|
||||
let mut face = PartialFace::default();
|
||||
face.exterior.write().surface =
|
||||
Partial::from(services.objects.surfaces.xy_plane());
|
||||
let surface = Partial::from(services.objects.surfaces.xy_plane());
|
||||
|
||||
let mut face = PartialFace {
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = surface;
|
||||
face.exterior
|
||||
.write()
|
||||
.update_as_polygon_from_points([a, b, c, d]);
|
||||
@ -136,7 +140,10 @@ mod tests {
|
||||
let h = [3., 1.];
|
||||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface.clone());
|
||||
face.exterior
|
||||
.write()
|
||||
@ -200,7 +207,10 @@ mod tests {
|
||||
let e = [0.0, 1.0];
|
||||
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface.clone());
|
||||
face.exterior
|
||||
.write()
|
||||
|
@ -1,10 +1,7 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use fj_interop::ext::ArrayExt;
|
||||
use fj_math::Point;
|
||||
|
||||
use crate::{
|
||||
builder::SurfaceBuilder,
|
||||
geometry::surface::SurfaceGeometry,
|
||||
objects::HalfEdge,
|
||||
partial::{Partial, PartialCycle},
|
||||
};
|
||||
@ -64,35 +61,6 @@ pub trait CycleBuilder {
|
||||
/// Will update each half-edge in the cycle to be a line segment.
|
||||
fn update_as_polygon(&mut self);
|
||||
|
||||
/// Update cycle as a triangle, from global (3D) points
|
||||
///
|
||||
/// Uses the three points to infer a plane that is used as the surface.
|
||||
///
|
||||
/// # Implementation Note
|
||||
///
|
||||
/// This method is probably just temporary, and will be generalized into a
|
||||
/// "update as polygon from global points" method sooner or later. For now,
|
||||
/// I didn't want to deal with the question of how to infer the surface, and
|
||||
/// how to handle points that don't fit that surface.
|
||||
fn update_as_triangle_from_global_points(
|
||||
&mut self,
|
||||
points: [impl Into<Point<3>>; 3],
|
||||
) -> [Partial<HalfEdge>; 3];
|
||||
|
||||
/// Connect the cycle to the provided half-edges
|
||||
///
|
||||
/// Assumes that the provided half-edges, once translated into local
|
||||
/// equivalents of this cycle, will not form a cycle themselves.
|
||||
///
|
||||
/// Returns the local equivalents of the provided half-edges and, as the
|
||||
/// last entry, an additional half-edge that closes the cycle.
|
||||
fn connect_to_open_edges<O>(
|
||||
&mut self,
|
||||
edges: O,
|
||||
) -> O::SizePlusOne<Partial<HalfEdge>>
|
||||
where
|
||||
O: ObjectArgument<Partial<HalfEdge>>;
|
||||
|
||||
/// Connect the cycles to the provided half-edges
|
||||
///
|
||||
/// Assumes that the provided half-edges, once translated into local
|
||||
@ -102,6 +70,7 @@ pub trait CycleBuilder {
|
||||
fn connect_to_closed_edges<O>(
|
||||
&mut self,
|
||||
edges: O,
|
||||
surface: &SurfaceGeometry,
|
||||
) -> O::SameSize<Partial<HalfEdge>>
|
||||
where
|
||||
O: ObjectArgument<Partial<HalfEdge>>;
|
||||
@ -204,65 +173,17 @@ impl CycleBuilder for PartialCycle {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_as_triangle_from_global_points(
|
||||
&mut self,
|
||||
points_global: [impl Into<Point<3>>; 3],
|
||||
) -> [Partial<HalfEdge>; 3] {
|
||||
let points_global = points_global.map(Into::into);
|
||||
|
||||
let (points_surface, _) = self
|
||||
.surface
|
||||
.write()
|
||||
.update_as_plane_from_points(points_global);
|
||||
|
||||
let half_edges = self.update_as_polygon_from_points(points_surface);
|
||||
|
||||
for (mut half_edge, point) in half_edges.clone().zip_ext(points_global)
|
||||
{
|
||||
let [vertex, _] = &mut half_edge.write().vertices;
|
||||
vertex.1.write().global_form.write().position = Some(point);
|
||||
}
|
||||
|
||||
half_edges
|
||||
}
|
||||
|
||||
fn connect_to_open_edges<O>(
|
||||
&mut self,
|
||||
edges: O,
|
||||
) -> O::SizePlusOne<Partial<HalfEdge>>
|
||||
where
|
||||
O: ObjectArgument<Partial<HalfEdge>>,
|
||||
{
|
||||
// We need to create the additional half-edge last, but at the same time
|
||||
// need to provide it to the `map_plus_one` method first. Really no
|
||||
// choice but to create them all in one go, as we do here.
|
||||
let mut half_edges = VecDeque::new();
|
||||
for _ in 0..edges.num_objects() {
|
||||
half_edges.push_back(self.add_half_edge());
|
||||
}
|
||||
let additional_half_edge = self.add_half_edge();
|
||||
|
||||
edges.map_plus_one(additional_half_edge, |other| {
|
||||
let mut this = half_edges.pop_front().expect(
|
||||
"Pushed correct number of half-edges; should be able to pop",
|
||||
);
|
||||
this.write()
|
||||
.update_from_other_edge(&other, &self.surface.read().geometry);
|
||||
this
|
||||
})
|
||||
}
|
||||
|
||||
fn connect_to_closed_edges<O>(
|
||||
&mut self,
|
||||
edges: O,
|
||||
surface: &SurfaceGeometry,
|
||||
) -> O::SameSize<Partial<HalfEdge>>
|
||||
where
|
||||
O: ObjectArgument<Partial<HalfEdge>>,
|
||||
{
|
||||
edges.map(|other| {
|
||||
let mut this = self.add_half_edge();
|
||||
this.write()
|
||||
.update_from_other_edge(&other, &self.surface.read().geometry);
|
||||
this.write().update_from_other_edge(&other, surface);
|
||||
this
|
||||
})
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ pub trait HalfEdgeBuilder {
|
||||
fn update_from_other_edge(
|
||||
&mut self,
|
||||
other: &Partial<HalfEdge>,
|
||||
surface: &Option<SurfaceGeometry>,
|
||||
surface: &SurfaceGeometry,
|
||||
);
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ impl HalfEdgeBuilder for PartialHalfEdge {
|
||||
fn update_from_other_edge(
|
||||
&mut self,
|
||||
other: &Partial<HalfEdge>,
|
||||
surface: &Option<SurfaceGeometry>,
|
||||
surface: &SurfaceGeometry,
|
||||
) {
|
||||
let global_curve = other.read().curve.read().global_form.clone();
|
||||
self.curve.write().global_form = global_curve.clone();
|
||||
@ -230,103 +230,78 @@ impl HalfEdgeBuilder for PartialHalfEdge {
|
||||
|
||||
self.curve.write().path =
|
||||
other.read().curve.read().path.as_ref().and_then(|path| {
|
||||
match surface {
|
||||
Some(surface) => {
|
||||
// We have information about the other edge's surface
|
||||
// available. We need to use that to interpret what the
|
||||
// other edge's curve path means for our curve path.
|
||||
match surface.u {
|
||||
GlobalPath::Circle(circle) => {
|
||||
// The other surface is curved. We're entering
|
||||
// some dodgy territory here, as only some edge
|
||||
// cases can be represented using our current
|
||||
// curve/surface representation.
|
||||
match path {
|
||||
MaybeSurfacePath::Defined(
|
||||
SurfacePath::Line(_),
|
||||
)
|
||||
| MaybeSurfacePath::UndefinedLine => {
|
||||
// We're dealing with a line on a
|
||||
// rounded surface.
|
||||
//
|
||||
// Based on the current uses of this
|
||||
// method, we can make some assumptions:
|
||||
//
|
||||
// 1. The line is parallel to the u-axis
|
||||
// of the other surface.
|
||||
// 2. The surface that *our* edge is in
|
||||
// is a plane that is parallel to the
|
||||
// the plane of the circle that
|
||||
// defines the curvature of the other
|
||||
// surface.
|
||||
//
|
||||
// These assumptions are necessary
|
||||
// preconditions for the following code
|
||||
// to work. But unfortunately, I see no
|
||||
// way to check those preconditions
|
||||
// here, as neither the other line nor
|
||||
// our surface is necessarily defined
|
||||
// yet.
|
||||
//
|
||||
// Handling this case anyway feels like
|
||||
// a grave sin, but I don't know what
|
||||
// else to do. If you tracked some
|
||||
// extremely subtle and annoying bug
|
||||
// back to this code, I apologize.
|
||||
//
|
||||
// I hope that I'll come up with a
|
||||
// better curve/surface representation
|
||||
// before this becomes a problem.
|
||||
Some(
|
||||
MaybeSurfacePath::UndefinedCircle {
|
||||
radius: circle.radius(),
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// The other edge is a line segment in a
|
||||
// curved surface. No idea how to deal
|
||||
// with this.
|
||||
todo!(
|
||||
"Can't connect edge to circle on \
|
||||
curved surface"
|
||||
)
|
||||
}
|
||||
}
|
||||
// We have information about the other edge's surface available.
|
||||
// We need to use that to interpret what the other edge's curve
|
||||
// path means for our curve path.
|
||||
match surface.u {
|
||||
GlobalPath::Circle(circle) => {
|
||||
// The other surface is curved. We're entering some
|
||||
// dodgy territory here, as only some edge cases can be
|
||||
// represented using our current curve/surface
|
||||
// representation.
|
||||
match path {
|
||||
MaybeSurfacePath::Defined(SurfacePath::Line(_))
|
||||
| MaybeSurfacePath::UndefinedLine => {
|
||||
// We're dealing with a line on a rounded
|
||||
// surface.
|
||||
//
|
||||
// Based on the current uses of this method, we
|
||||
// can make some assumptions:
|
||||
//
|
||||
// 1. The line is parallel to the u-axis of the
|
||||
// other surface.
|
||||
// 2. The surface that *our* edge is in is a
|
||||
// plane that is parallel to the the plane of
|
||||
// the circle that defines the curvature of
|
||||
// the other surface.
|
||||
//
|
||||
// These assumptions are necessary preconditions
|
||||
// for the following code to work. But
|
||||
// unfortunately, I see no way to check those
|
||||
// preconditions here, as neither the other line
|
||||
// nor our surface is necessarily defined yet.
|
||||
//
|
||||
// Handling this case anyway feels like a grave
|
||||
// sin, but I don't know what else to do. If you
|
||||
// tracked some extremely subtle and annoying
|
||||
// bug back to this code, I apologize.
|
||||
//
|
||||
// I hope that I'll come up with a better curve/
|
||||
// surface representation before this becomes a
|
||||
// problem.
|
||||
Some(MaybeSurfacePath::UndefinedCircle {
|
||||
radius: circle.radius(),
|
||||
})
|
||||
}
|
||||
GlobalPath::Line(_) => {
|
||||
// The other edge is defined on a plane.
|
||||
match path {
|
||||
MaybeSurfacePath::Defined(
|
||||
SurfacePath::Line(_),
|
||||
)
|
||||
| MaybeSurfacePath::UndefinedLine => {
|
||||
// The other edge is a line segment on
|
||||
// a plane. That means our edge must be
|
||||
// a line segment too.
|
||||
Some(MaybeSurfacePath::UndefinedLine)
|
||||
}
|
||||
_ => {
|
||||
// The other edge is a circle or arc on
|
||||
// a plane. I'm actually not sure what
|
||||
// that means for our edge. We might be
|
||||
// able to represent it somehow, but
|
||||
// let's leave that as an exercise for
|
||||
// later.
|
||||
todo!(
|
||||
"Can't connect edge to circle on \
|
||||
plane"
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// The other edge is a line segment in a curved
|
||||
// surface. No idea how to deal with this.
|
||||
todo!(
|
||||
"Can't connect edge to circle on curved \
|
||||
surface"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// We know nothing about the surface the other edge is
|
||||
// on. This means we can't infer anything about our
|
||||
// curve from the other curve.
|
||||
None
|
||||
GlobalPath::Line(_) => {
|
||||
// The other edge is defined on a plane.
|
||||
match path {
|
||||
MaybeSurfacePath::Defined(SurfacePath::Line(_))
|
||||
| MaybeSurfacePath::UndefinedLine => {
|
||||
// The other edge is a line segment on a plane.
|
||||
// That means our edge must be a line segment
|
||||
// too.
|
||||
Some(MaybeSurfacePath::UndefinedLine)
|
||||
}
|
||||
_ => {
|
||||
// The other edge is a circle or arc on a plane.
|
||||
// I'm actually not sure what that means for our
|
||||
// edge. We might be able to represent it
|
||||
// somehow, but let's leave that as an exercise
|
||||
// for later.
|
||||
todo!("Can't connect edge to circle on plane")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -34,6 +34,7 @@ use crate::{
|
||||
/// [`Shell`]: crate::objects::Shell
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct Face {
|
||||
surface: Handle<Surface>,
|
||||
exterior: Handle<Cycle>,
|
||||
interiors: Vec<Handle<Cycle>>,
|
||||
color: Color,
|
||||
@ -42,6 +43,7 @@ pub struct Face {
|
||||
impl Face {
|
||||
/// Construct an instance of `Face`
|
||||
pub fn new(
|
||||
surface: Handle<Surface>,
|
||||
exterior: Handle<Cycle>,
|
||||
interiors: impl IntoIterator<Item = Handle<Cycle>>,
|
||||
color: Color,
|
||||
@ -49,6 +51,7 @@ impl Face {
|
||||
let interiors = interiors.into_iter().collect();
|
||||
|
||||
Self {
|
||||
surface,
|
||||
exterior,
|
||||
interiors,
|
||||
color,
|
||||
@ -57,7 +60,7 @@ impl Face {
|
||||
|
||||
/// Access the surface of the face
|
||||
pub fn surface(&self) -> &Handle<Surface> {
|
||||
self.exterior().surface()
|
||||
&self.surface
|
||||
}
|
||||
|
||||
/// Access the cycle that bounds the face on the outside
|
||||
|
@ -1,7 +1,7 @@
|
||||
use fj_interop::mesh::Color;
|
||||
|
||||
use crate::{
|
||||
objects::{Cycle, Face, Objects},
|
||||
objects::{Cycle, Face, Objects, Surface},
|
||||
partial::{FullToPartialCache, Partial, PartialObject},
|
||||
services::Service,
|
||||
};
|
||||
@ -9,6 +9,9 @@ use crate::{
|
||||
/// A partial [`Face`]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PartialFace {
|
||||
/// The surface that the face is defined in
|
||||
pub surface: Partial<Surface>,
|
||||
|
||||
/// The cycle that bounds the face on the outside
|
||||
pub exterior: Partial<Cycle>,
|
||||
|
||||
@ -26,6 +29,7 @@ impl PartialObject for PartialFace {
|
||||
|
||||
fn from_full(face: &Self::Full, cache: &mut FullToPartialCache) -> Self {
|
||||
Self {
|
||||
surface: Partial::from_full(face.surface().clone(), cache),
|
||||
exterior: Partial::from_full(face.exterior().clone(), cache),
|
||||
interiors: face
|
||||
.interiors()
|
||||
@ -36,11 +40,12 @@ impl PartialObject for PartialFace {
|
||||
}
|
||||
|
||||
fn build(self, objects: &mut Service<Objects>) -> Self::Full {
|
||||
let surface = self.surface.build(objects);
|
||||
let exterior = self.exterior.build(objects);
|
||||
let interiors =
|
||||
self.interiors.into_iter().map(|cycle| cycle.build(objects));
|
||||
let color = self.color.unwrap_or_default();
|
||||
|
||||
Face::new(exterior, interiors, color)
|
||||
Face::new(surface, exterior, interiors, color)
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,10 @@ mod tests {
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
|
||||
let valid = {
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface);
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
@ -141,7 +144,12 @@ mod tests {
|
||||
.insert(&mut services.objects);
|
||||
|
||||
let interiors = [cycle];
|
||||
Face::new(valid.exterior().clone(), interiors, valid.color())
|
||||
Face::new(
|
||||
valid.surface().clone(),
|
||||
valid.exterior().clone(),
|
||||
interiors,
|
||||
valid.color(),
|
||||
)
|
||||
};
|
||||
|
||||
valid.validate_and_return_first_error()?;
|
||||
@ -157,7 +165,10 @@ mod tests {
|
||||
let surface = services.objects.surfaces.xy_plane();
|
||||
|
||||
let valid = {
|
||||
let mut face = PartialFace::default();
|
||||
let mut face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
face.exterior.write().surface = Partial::from(surface);
|
||||
face.exterior.write().update_as_polygon_from_points([
|
||||
[0., 0.],
|
||||
@ -178,7 +189,12 @@ mod tests {
|
||||
.map(|cycle| cycle.reverse(&mut services.objects))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Face::new(valid.exterior().clone(), interiors, valid.color())
|
||||
Face::new(
|
||||
valid.surface().clone(),
|
||||
valid.exterior().clone(),
|
||||
interiors,
|
||||
valid.color(),
|
||||
)
|
||||
};
|
||||
|
||||
valid.validate_and_return_first_error()?;
|
||||
|
@ -82,6 +82,7 @@ impl Shape for fj::Difference2d {
|
||||
);
|
||||
|
||||
let face = PartialFace {
|
||||
surface: Partial::from(surface.clone()),
|
||||
exterior: Partial::from(exterior),
|
||||
interiors,
|
||||
color: Some(Color(self.color())),
|
||||
|
@ -37,7 +37,7 @@ impl Shape for fj::Sketch {
|
||||
};
|
||||
let exterior = {
|
||||
let mut cycle = PartialCycle {
|
||||
surface,
|
||||
surface: surface.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
cycle.half_edges.push(half_edge);
|
||||
@ -45,6 +45,7 @@ impl Shape for fj::Sketch {
|
||||
};
|
||||
|
||||
PartialFace {
|
||||
surface,
|
||||
exterior,
|
||||
color: Some(Color(self.color())),
|
||||
..Default::default()
|
||||
@ -59,7 +60,7 @@ impl Shape for fj::Sketch {
|
||||
|
||||
let exterior = {
|
||||
let mut cycle = PartialCycle {
|
||||
surface: Partial::from(surface),
|
||||
surface: Partial::from(surface.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
let mut line_segments = vec![];
|
||||
@ -98,6 +99,7 @@ impl Shape for fj::Sketch {
|
||||
};
|
||||
|
||||
PartialFace {
|
||||
surface: Partial::from(surface),
|
||||
exterior,
|
||||
color: Some(Color(self.color())),
|
||||
..Default::default()
|
||||
|
Loading…
Reference in New Issue
Block a user