Skip to main content

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 &section.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(&section.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}