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 146 147 148 149 150 151 152 153 154 155 156 157 158 159
use fj_interop::{ext::ArrayExt, Color};
use fj_math::{Point, Scalar, Vector};
use crate::{
geometry::SurfaceGeometry,
objects::{Cycle, Face, HalfEdge, Region, Vertex},
operations::{
build::{BuildCycle, BuildHalfEdge},
geometry::UpdateHalfEdgeGeometry,
insert::Insert,
presentation::SetColor,
update::{UpdateCycle, UpdateHalfEdge},
},
storage::Handle,
Core,
};
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: &SurfaceGeometry,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
core: &mut Core,
) -> (Face, Handle<HalfEdge>);
}
impl SweepHalfEdge for Handle<HalfEdge> {
fn sweep_half_edge(
&self,
end_vertex: Handle<Vertex>,
surface: &SurfaceGeometry,
color: Option<Color>,
path: impl Into<Vector<3>>,
cache: &mut SweepCache,
core: &mut Core,
) -> (Face, Handle<HalfEdge>) {
let path = path.into();
let surface = core
.layers
.geometry
.of_half_edge(self)
.path
.sweep_surface_path(surface, path, core);
// 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, core);
let (curve_down, d) = a.clone().sweep_vertex(cache, core);
(
[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 half_edge = {
let line_segment = HalfEdge::line_segment(
[start, end],
Some(boundary),
core,
);
let half_edge = line_segment
.update_start_vertex(|_, _| start_vertex, core);
let half_edge = if let Some(curve) = curve {
half_edge.update_curve(|_, _| curve, core)
} else {
half_edge
};
half_edge.insert(core).set_path(
core.layers.geometry.of_half_edge(&line_segment).path,
&mut core.layers.geometry,
)
};
exterior = exterior.add_half_edges([half_edge.clone()], core);
half_edge
});
let exterior = exterior.insert(core);
let region = Region::new(exterior, []).insert(core);
if let Some(color) = color {
region.set_color(color, core);
}
let face = Face::new(surface, region);
(face, edge_top)
}
}