energyml_section/panels.rs
1//! The section fills, put back on the trace - the coloured panels of the 3D
2//! view (ADR-0015).
3//!
4//! The 3D surfaces are created from the 2D view being drawn. Their colouring
5//! is chosen by the user, for each surface line projected in the 2D section
6//! view, as to whether the colour propagates up to the line above, the line
7//! below, or both.
8//!
9//! The panels are the **polygons of the drawing** - the same rule
10//! (`crate::layout::fill::polygons`: a trace to its neighbour in each
11//! abscissa, nothing where there is none), the same choices (`View::fills`), the same hidden traces,
12//! the same colour - each vertex `(s, z)` put back at `point_at(trace, s)`, `z`
13//! unchanged. Nothing is recomputed from a surface: the 3D shows what the 2D
14//! drew.
15//!
16//! Every section of the catalogue gets its panels, whichever the view's target
17//! is: the view carries the choices, the 3D shows every section. A view's
18//! `portion` is a crop of one drawing and does not apply here.
19
20use energyml_geometry::fence::point_at;
21use serde::{Deserialize, Serialize};
22
23use crate::layout::fill::{self, Span};
24use crate::layout::trace_colour;
25use crate::model::{Catalogue, FillChoice, Item, Section, SectionKey, TraceItem, View};
26
27/// The filled polygons of one trace on one section, in the scene's `(x, y, z)`.
28#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct Panel {
31 /// The section the polygons stand on.
32 pub section: SectionKey,
33 /// The trace (surface) they fill from, by key - `FillChoice::key`.
34 pub key: String,
35 /// Their colour: the drawing's.
36 pub colour: String,
37 /// Each polygon's vertices, not closed.
38 pub polygons: Vec<Vec<[f64; 3]>>,
39 /// The same polygons in the section's own `(s, z)`, vertex for vertex -
40 /// where a polygon is flat, so where it is triangulated: unrolled from its
41 /// 3D vertices instead, a trace folding back on itself would fold it too.
42 pub sz: Vec<Vec<[f64; 2]>>,
43}
44
45/// The panels of every section of `catalogue` for the fills `view` chooses.
46pub fn panels(catalogue: &Catalogue, view: &View) -> Vec<Panel> {
47 let mut out = Vec::new();
48 if view.fills.is_empty() {
49 return out;
50 }
51 for section in std::iter::once(&catalogue.long).chain(catalogue.crosses.iter()) {
52 of_section(section, view, &mut out);
53 }
54 out
55}
56
57fn of_section(section: &Section, view: &View, out: &mut Vec<Panel>) {
58 // What the drawing keeps: a hidden trace is neither filled nor a neighbour.
59 let mut kept: Vec<(String, &TraceItem, String, Vec<Span>)> = Vec::new();
60 for item in §ion.items {
61 let Item::Trace(t) = item else { continue };
62 let key = t.object.key();
63 if view.hidden.contains(&key) {
64 continue;
65 }
66 let spans: Vec<Span> = t.spans.iter().filter(|s| s.len() >= 2).cloned().collect();
67 if spans.is_empty() {
68 continue;
69 }
70 // The drawing's cascade: the scene, the file, then the derived hue.
71 let colour = trace_colour(view, t);
72 kept.push((key, t, colour, spans));
73 }
74 let lines: Vec<fill::Line<'_>> = kept
75 .iter()
76 .map(|(k, item, _, s)| fill::Line {
77 key: k,
78 item,
79 spans: s,
80 })
81 .collect();
82 for ((key, _, colour, _), mine) in kept.iter().zip(&lines) {
83 let Some(FillChoice { up, down, .. }) = view.fills.iter().find(|f| f.key == *key) else {
84 continue;
85 };
86 let mut polygons = Vec::new();
87 let mut sz = Vec::new();
88 for (wanted, is_up) in [(*up, true), (*down, false)] {
89 if !wanted {
90 continue;
91 }
92 for poly in fill::polygons(mine, &lines, is_up) {
93 polygons.push(
94 poly.iter()
95 .map(|&[s, z]| {
96 let [x, y] = point_at(§ion.trace, s);
97 [x, y, z]
98 })
99 .collect(),
100 );
101 sz.push(poly);
102 }
103 }
104 if !polygons.is_empty() {
105 out.push(Panel {
106 section: section.key,
107 key: key.clone(),
108 colour: colour.clone(),
109 polygons,
110 sz,
111 });
112 }
113 }
114}