1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::xml;
use crate::Result;
use roxmltree::Node;

/// Optional minimum and maximum values for Cartesian X, Y and Z coordinates.
#[derive(Clone, Debug, Default)]
pub struct CartesianBounds {
    pub x_min: Option<f64>,
    pub x_max: Option<f64>,
    pub y_min: Option<f64>,
    pub y_max: Option<f64>,
    pub z_min: Option<f64>,
    pub z_max: Option<f64>,
}

impl CartesianBounds {
    pub(crate) fn from_node(node: &Node) -> Result<Self> {
        Ok(Self {
            x_min: xml::opt_f64(node, "xMinimum")?,
            x_max: xml::opt_f64(node, "xMaximum")?,
            y_min: xml::opt_f64(node, "yMinimum")?,
            y_max: xml::opt_f64(node, "yMaximum")?,
            z_min: xml::opt_f64(node, "zMinimum")?,
            z_max: xml::opt_f64(node, "zMaximum")?,
        })
    }

    pub(crate) fn xml_string(&self) -> String {
        let mut xml = String::from("<cartesianBounds type=\"Structure\">\n");
        if let Some(min) = self.x_min {
            xml += &xml::gen_float("xMinimum", min);
        }
        if let Some(max) = self.x_max {
            xml += &xml::gen_float("xMaximum", max);
        }
        if let Some(min) = self.y_min {
            xml += &xml::gen_float("yMinimum", min);
        }
        if let Some(max) = self.y_max {
            xml += &xml::gen_float("yMaximum", max);
        }
        if let Some(min) = self.z_min {
            xml += &xml::gen_float("zMinimum", min);
        }
        if let Some(max) = self.z_max {
            xml += &xml::gen_float("zMaximum", max);
        }
        xml += "</cartesianBounds>\n";
        xml
    }
}

/// Optional minimum and maximum values for spherical coordinates.
#[derive(Clone, Debug, Default)]
pub struct SphericalBounds {
    pub range_min: Option<f64>,
    pub range_max: Option<f64>,
    pub elevation_min: Option<f64>,
    pub elevation_max: Option<f64>,
    pub azimuth_start: Option<f64>,
    pub azimuth_end: Option<f64>,
}

impl SphericalBounds {
    pub(crate) fn from_node(node: &Node) -> Result<Self> {
        Ok(Self {
            range_min: xml::opt_f64(node, "rangeMinimum")?,
            range_max: xml::opt_f64(node, "rangeMaximum")?,
            elevation_min: xml::opt_f64(node, "elevationMinimum")?,
            elevation_max: xml::opt_f64(node, "elevationMaximum")?,
            azimuth_start: xml::opt_f64(node, "azimuthStart")?,
            azimuth_end: xml::opt_f64(node, "azimuthEnd")?,
        })
    }

    pub(crate) fn xml_string(&self) -> String {
        let mut xml = String::from("<sphericalBounds type=\"Structure\">\n");
        if let Some(min) = self.azimuth_start {
            xml += &xml::gen_float("azimuthStart", min);
        }
        if let Some(max) = self.azimuth_end {
            xml += &xml::gen_float("azimuthEnd", max);
        }
        if let Some(min) = self.elevation_min {
            xml += &xml::gen_float("elevationMinimum", min);
        }
        if let Some(max) = self.elevation_max {
            xml += &xml::gen_float("elevationMaximum", max);
        }
        if let Some(min) = self.range_min {
            xml += &xml::gen_float("rangeMinimum", min);
        }
        if let Some(max) = self.range_max {
            xml += &xml::gen_float("rangeMaximum", max);
        }
        xml += "</sphericalBounds>\n";
        xml
    }
}

/// Optional minimum and maximum values for the row, column and return indices.
#[derive(Clone, Debug, Default)]
pub struct IndexBounds {
    pub row_min: Option<i64>,
    pub row_max: Option<i64>,
    pub column_min: Option<i64>,
    pub column_max: Option<i64>,
    pub return_min: Option<i64>,
    pub return_max: Option<i64>,
}

impl IndexBounds {
    pub(crate) fn from_node(node: &Node) -> Result<Self> {
        Ok(Self {
            row_min: xml::opt_int(node, "rowMinimum")?,
            row_max: xml::opt_int(node, "rowMaximum")?,
            column_min: xml::opt_int(node, "columnMinimum")?,
            column_max: xml::opt_int(node, "columnMaximum")?,
            return_min: xml::opt_int(node, "returnMinimum")?,
            return_max: xml::opt_int(node, "returnMaximum")?,
        })
    }

    pub(crate) fn xml_string(&self) -> String {
        let mut xml = String::from("<indexBounds type=\"Structure\">\n");
        if let Some(min) = self.row_min {
            xml += &xml::gen_int("rowMinimum", min);
        }
        if let Some(max) = self.row_max {
            xml += &xml::gen_int("rowMaximum", max);
        }
        if let Some(min) = self.column_min {
            xml += &xml::gen_int("columnMinimum", min);
        }
        if let Some(max) = self.column_max {
            xml += &xml::gen_int("columnMaximum", max);
        }
        if let Some(min) = self.return_min {
            xml += &xml::gen_int("returnMinimum", min);
        }
        if let Some(max) = self.return_max {
            xml += &xml::gen_int("returnMaximum", max);
        }
        xml += "</indexBounds>\n";
        xml
    }
}