runmat_plot/plots/
reference_line.rs1use crate::core::{BoundingBox, RenderData};
4use crate::plots::line::{LinePlot, LineStyle};
5use glam::{Vec3, Vec4};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ReferenceLineOrientation {
9 Vertical,
10 Horizontal,
11}
12
13#[derive(Debug, Clone)]
14pub struct ReferenceLine {
15 pub orientation: ReferenceLineOrientation,
16 pub value: f64,
17 pub color: Vec4,
18 pub line_width: f32,
19 pub line_style: LineStyle,
20 pub label: Option<String>,
21 pub display_name: Option<String>,
22 pub label_orientation: String,
23 pub visible: bool,
24}
25
26impl ReferenceLine {
27 pub fn new(orientation: ReferenceLineOrientation, value: f64) -> Result<Self, String> {
28 if !value.is_finite() {
29 return Err("reference line coordinate must be finite".to_string());
30 }
31 Ok(Self {
32 orientation,
33 value,
34 color: Vec4::new(0.0, 0.0, 0.0, 1.0),
35 line_width: 1.0,
36 line_style: LineStyle::Solid,
37 label: None,
38 display_name: None,
39 label_orientation: "aligned".to_string(),
40 visible: true,
41 })
42 }
43
44 pub fn with_style(mut self, color: Vec4, line_width: f32, line_style: LineStyle) -> Self {
45 self.color = color;
46 self.line_width = line_width;
47 self.line_style = line_style;
48 self
49 }
50
51 pub fn label_for_legend(&self) -> Option<String> {
52 self.display_name.clone().or_else(|| self.label.clone())
53 }
54
55 pub fn coordinate_bounds(&self) -> BoundingBox {
56 match self.orientation {
57 ReferenceLineOrientation::Vertical => BoundingBox::new(
58 Vec3::new(self.value as f32, 0.0, 0.0),
59 Vec3::new(self.value as f32, 0.0, 0.0),
60 ),
61 ReferenceLineOrientation::Horizontal => BoundingBox::new(
62 Vec3::new(0.0, self.value as f32, 0.0),
63 Vec3::new(0.0, self.value as f32, 0.0),
64 ),
65 }
66 }
67
68 pub fn render_data_with_range(
69 &self,
70 x_range: (f64, f64),
71 y_range: (f64, f64),
72 viewport_px: Option<(u32, u32)>,
73 ) -> RenderData {
74 let (x, y) = match self.orientation {
75 ReferenceLineOrientation::Vertical => {
76 (vec![self.value, self.value], vec![y_range.0, y_range.1])
77 }
78 ReferenceLineOrientation::Horizontal => {
79 (vec![x_range.0, x_range.1], vec![self.value, self.value])
80 }
81 };
82 let mut line = LinePlot::new(x, y)
83 .expect("reference line builds finite two-point line")
84 .with_style(self.color, self.line_width, self.line_style);
85 if let Some(label) = self.label_for_legend() {
86 line = line.with_label(label);
87 }
88 line.render_data_with_viewport(viewport_px)
89 }
90
91 pub fn estimated_memory_usage(&self) -> usize {
92 std::mem::size_of::<Self>()
93 + self.label.as_ref().map_or(0, String::len)
94 + self.display_name.as_ref().map_or(0, String::len)
95 + self.label_orientation.len()
96 }
97}