1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
use fj_interop::{ext::ArrayExt, mesh::Color};
use fj_math::{Point, Scalar, Vector};
use crate::{
objects::{Cycle, Face, HalfEdge, Region, Surface, Vertex},
operations::{
build::{BuildCycle, BuildHalfEdge},
insert::Insert,
update::{UpdateCycle, UpdateHalfEdge},
},
services::Services,
storage::Handle,
};
use super::{vertex::SweepVertex, SweepCache, SweepSurfacePath};
/// # Sweep a [`HalfEdge`]
///
/// See [module documentation] for more information.
///
/// [module documentation]: super
pub trait SweepHalfEdge {
/// # Sweep the [`HalfEdge`]
///
/// Returns a face, the result of sweeping the edge, as well as the top edge
/// of that face, i.e. the edge that is the version of the original edge
/// that was translated along the sweep path.
///
/// In addition to the usual arguments that many sweep operations require,
/// some other ones are needed:
///
/// - `end_vertex`, the vertex where the half-edge ends. This is the start
/// vertex of the next half-edge in the cycle.
/// - The `surface` that the half-edge is defined on.
/// - The `color` of the resulting face, if applicable
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> (Face, Handle<HalfEdge>);
}
impl SweepHalfEdge for HalfEdge {
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
surface: &Surface,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
services: &mut Services,
) -> (Face, Handle<HalfEdge>) {
let path = path.into();
let surface = self
.path()
.sweep_surface_path(surface, path)
.insert(services);
// Next, we need to define the boundaries of the face. Let's start with
// the global vertices and edges.
let (vertices, curves) = {
let [a, b] = [self.start_vertex().clone(), end_vertex];
let (curve_up, c) = b.clone().sweep_vertex(cache, services);
let (curve_down, d) = a.clone().sweep_vertex(cache, services);
(
[a, b, c, d],
[
Some(self.curve().clone()),
Some(curve_up),
None,
Some(curve_down),
],
)
};
// Let's figure out the surface coordinates of the edge vertices.
let surface_points = {
let [a, b] = self.boundary().inner;
[
[a.t, Scalar::ZERO],
[b.t, Scalar::ZERO],
[b.t, Scalar::ONE],
[a.t, Scalar::ONE],
]
.map(Point::from)
};
let surface_points_next = {
let mut points = surface_points;
points.rotate_left(1);
points
};
// Now, the boundaries of each edge.
let boundaries = {
let [a, b] = self.boundary().inner;
let [c, d] = [0., 1.].map(|coord| Point::from([coord]));
[[a, b], [c, d], [b, a], [d, c]]
};
let mut exterior = Cycle::empty();
// Armed with all of that, we're ready to create the edges.
let [_edge_bottom, _edge_up, edge_top, _edge_down] = boundaries
.zip_ext(surface_points)
.zip_ext(surface_points_next)
.zip_ext(vertices)
.zip_ext(curves)
.map(|((((boundary, start), end), start_vertex), curve)| {
let edge = {
let edge = HalfEdge::line_segment(
[start, end],
Some(boundary),
services,
)
.update_start_vertex(|_| start_vertex);
let edge = if let Some(curve) = curve {
edge.update_curve(|_| curve)
} else {
edge
};
edge.insert(services)
};
exterior = exterior.add_half_edges([edge.clone()]);
edge
});
let exterior = exterior.insert(services);
let region = Region::new(exterior, [], color).insert(services);
let face = Face::new(surface, region);
(face, edge_top)
}
}