Skip to main content

geop_ops_model/sketch/
fields.rs

1//! Building blocks of the forms of what is drawn in a sketch, here and in a
2//! 3-D sketch: a filled region, how a sketch's constraints stand.
3
4use geop_core_editor::editing::{Shape, Tone};
5use geop_core_math::{primitives::CoordinateSystem, scalars::Scalar, vector::Vector2};
6
7/// The area of `plane`'s `u`/`v` plane inside `outer` but outside `holes`,
8/// as triangles — to draw a region filled. No triangles for loops that do
9/// not triangulate.
10pub fn region(plane: &CoordinateSystem, outer: &[Vector2], holes: &[Vec<Vector2>]) -> Shape {
11    let plain = |loop_: &[Vector2]| -> Vec<[f64; 2]> {
12        loop_
13            .iter()
14            .map(|p| [p[0].to_f64(), p[1].to_f64()])
15            .collect()
16    };
17    let holes: Vec<Vec<[f64; 2]>> = holes.iter().map(|h| plain(h)).collect();
18    let at = |p: [f64; 2]| plane.uv_to_xyz(&Vector2::from_array(p.map(Scalar::from_f64)));
19    let triangles = geop_core_rasterize::triangulate_polygon(&plain(outer), &holes)
20        .into_iter()
21        .map(|t| t.map(at))
22        .collect();
23    Shape::Triangles { triangles }
24}
25
26/// How a sketch's constraints stand, followed by what it draws, `drawn`:
27/// how many conflict, unless all hold (`converged`), and then whether the
28/// sketch is fully constrained or how many degrees of freedom it has left.
29pub fn constraint_status(
30    converged: bool,
31    conflicts: usize,
32    dof: usize,
33    drawn: &str,
34) -> (String, Tone) {
35    let plural = |n: usize| if n == 1 { "" } else { "s" };
36    if !converged {
37        let text = format!(
38            "{conflicts} constraint{} conflict · {drawn}",
39            plural(conflicts)
40        );
41        (text, Tone::Error)
42    } else if dof == 0 {
43        (format!("Fully constrained · {drawn}"), Tone::Success)
44    } else {
45        (
46            format!("{dof} degree{} of freedom · {drawn}", plural(dof)),
47            Tone::Hint,
48        )
49    }
50}