geop_core_topology/uv_loop.rs
1//! A face's loop in its surface's parameter plane: the signed area it
2//! encloses, integrated exactly from its pcurves ([`loop_signed_area`]),
3//! and a polygon sampled along them, for the rasterizer to triangulate
4//! ([`sample_loop_to_polygon`]).
5//!
6//! Ask the area which way a loop runs, never a sampled polygon: the gap
7//! between a polygon and the pcurves is part of no enclosure (see
8//! [`geop_core_geometry::nurb_curve::loop_signed_area`]).
9
10use geop_core_geometry::nurb_curve;
11use geop_core_math::{geop_error::GeopResult, scalars::Scalar, vector::Vector2};
12
13use crate::{CoedgeId, Curve2, Model};
14
15/// The signed area, in `(u, v)`, of the loop anchored at `first`: positive
16/// counter-clockwise, negative clockwise.
17pub fn loop_signed_area(model: &Model, first: CoedgeId) -> GeopResult<Scalar> {
18 let pcurves = model
19 .iterate_loop_coedges(first)
20 .map(|coedge| Ok(&model.get_coedge(coedge)?.pcurve))
21 .collect::<GeopResult<Vec<_>>>()?;
22 nurb_curve::loop_signed_area(pcurves)
23}
24
25/// Sample the pcurves of the loop anchored at `first` (in traversal order)
26/// into a closed `(u, v)` polygon, `n` samples per coedge (the last sample of
27/// each coedge is dropped, since it coincides with the next coedge's first
28/// sample).
29pub fn sample_loop_to_polygon(
30 model: &Model,
31 first: CoedgeId,
32 n: usize,
33) -> GeopResult<Vec<Vector2>> {
34 sample_pcurves_to_polygon(
35 model
36 .iterate_loop_coedges(first)
37 .map(|coedge| &model.coedges[&coedge].pcurve),
38 n - 1,
39 )
40}
41
42/// Sample `pcurves`, a loop's in order, into a closed `(u, v)` polygon: `n`
43/// points evenly along each one's domain, its end left out, as the next
44/// one starts there.
45pub fn sample_pcurves_to_polygon<'a>(
46 pcurves: impl IntoIterator<Item = &'a Curve2>,
47 n: usize,
48) -> GeopResult<Vec<Vector2>> {
49 let mut poly = Vec::new();
50 for pcurve in pcurves {
51 let (t0, t1) = pcurve.domain();
52 for i in 0..n {
53 let frac = Scalar::from_ratio(i as i64, n as i64)?;
54 let t = t0.add(t1.sub(t0).mul(frac));
55 poly.push(pcurve.evaluate(t)?);
56 }
57 }
58 Ok(poly)
59}