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
use fj_interop::mesh::Color;
use fj_math::{Line, Point, Scalar};
use crate::{
algorithms::approx::Tolerance,
objects::{
Curve, CurveKind, Edge, GlobalCurve, GlobalEdge, GlobalVertex, Surface,
SweptCurve, Vertex, VerticesOfEdge,
},
};
use super::{Path, Sweep};
impl Sweep for (Vertex, Surface) {
type Swept = Edge;
fn sweep(
self,
path: impl Into<Path>,
tolerance: impl Into<Tolerance>,
color: Color,
) -> Self::Swept {
let (vertex, surface) = self;
let path = path.into();
// The result of sweeping a `Vertex` is an `Edge`. Seems
// straight-forward at first, but there are some subtleties we need to
// understand:
//
// 1. To create an `Edge`, we need the `Curve` that defines it. A
// `Curve` is defined in a `Surface`, and we're going to need that to
// create the `Curve`. Which is why this `Sweep` implementation is
// for `(Vertex, Surface)`, and not just for `Vertex`.
// 2. Please note that, while the result `Edge` has two vertices, our
// input `Vertex` is not one of them! It can't be, unless the `Curve`
// of the resulting `Edge` happens to be the same `Curve` that the
// input `Vertex` is defined on. That would be an edge case that
// probably can't result in anything valid, and we're going to ignore
// it for now.
// 3. This means, we have to compute everything that defines the
// resulting `Edge`: The `Curve`, the vertices, and the
// `GlobalCurve`.
//
// Before we get to that though, let's make sure that whoever called
// this didn't give us bad input.
// So, we're supposed to create the `Edge` by sweeping a `Vertex` using
// `path`. Unless `path` is identical to the path that created the
// `Surface`, this doesn't make any sense.
//
// Further, the `Curve` that was swept to create the `Surface` needs to
// be the same `Curve` that the input `Vertex` is defined on. If it's
// not, we have no way of knowing the surface coordinates of the input
// `Vertex` on the `Surface`, and we're going to need to do that further
// down.
//
// Let's make sure that these requirements are met.
{
let Surface::SweptCurve(SweptCurve {
curve: surface_curve,
path: surface_path,
}) = surface;
assert_eq!(vertex.curve().global().kind(), &surface_curve);
assert_eq!(path.inner(), surface_path);
}
// With that out of the way, let's start by creating the `GlobalEdge`,
// as that is the most straight-forward part of this operations, and
// we're going to need it soon anyway.
let edge_global = vertex.global().sweep(path, tolerance, color);
// Next, let's compute the surface coordinates of the two vertices of
// the output `Edge`, as we're going to need these for the rest of this
// operation.
//
// They both share a u-coordinate, which is the t-coordinate of our
// input `Vertex`. Remember, we validated above, that the `Curve` of the
// `Surface` and the curve of the input `Vertex` are the same, so we can
// do that.
//
// Now remember what we also validated above: That `path`, which we're
// using to create the output `Edge`, also created the `Surface`, and
// thereby defined its coordinate system. That makes the v-coordinates
// straight-forward: The start of the edge is at zero, the end is at
// one.
let u = vertex.position().t;
let v_a = Scalar::ZERO;
let v_b = Scalar::ONE;
// Armed with those coordinates, creating the `Curve` of the output
// `Edge` becomes straight-forward.
let curve = {
let a = Point::from([u, v_a]);
let b = Point::from([u, v_b]);
let line = Line::from_points([a, b]);
Curve::new(surface, CurveKind::Line(line), *edge_global.curve())
};
// And now the vertices. Again, nothing wild here.
let vertices = {
let [&a, &b] = edge_global.vertices().get_or_panic();
let a = Vertex::new([v_a], curve, a);
let b = Vertex::new([v_b], curve, b);
VerticesOfEdge::from_vertices([a, b])
};
// And finally, creating the output `Edge` is just a matter of
// assembling the pieces we've already created.
Edge::new(curve, vertices, edge_global)
}
}
impl Sweep for GlobalVertex {
type Swept = GlobalEdge;
fn sweep(
self,
path: impl Into<Path>,
_: impl Into<Tolerance>,
_: Color,
) -> Self::Swept {
let a = self;
let b =
GlobalVertex::from_position(self.position() + path.into().inner());
let curve =
GlobalCurve::build().line_from_points([a.position(), b.position()]);
GlobalEdge::new(curve, VerticesOfEdge::from_vertices([a, b]))
}
}