1use crate::cityjson::core::boundary::Boundary;
18use crate::cityjson::core::vertex::VertexRef;
19use crate::error::Error;
20use crate::resources::id::ResourceId;
21use crate::resources::mapping::SemanticOrMaterialMap;
22use crate::resources::mapping::textures::TextureMapCore;
23use crate::resources::storage::StringStorage;
24use crate::v2_0::vertex::VertexIndex;
25use std::str::FromStr;
26
27pub(crate) type ThemedMaterials<VR, RR, SS> = Vec<(
28 crate::cityjson::core::appearance::ThemeName<SS>,
29 SemanticOrMaterialMap<VR, RR>,
30)>;
31pub(crate) type ThemedTextures<VR, RR, SS> = Vec<(
32 crate::cityjson::core::appearance::ThemeName<SS>,
33 TextureMapCore<VR, RR>,
34)>;
35
36#[derive(Clone, Copy, Debug, PartialEq)]
37pub struct AffineTransform3D([f64; 16]);
38
39impl AffineTransform3D {
40 #[must_use]
41 pub fn new(matrix: [f64; 16]) -> Self {
42 Self(matrix)
43 }
44
45 #[must_use]
46 pub fn identity() -> Self {
47 Self([
48 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
49 ])
50 }
51
52 #[must_use]
53 pub fn as_array(&self) -> &[f64; 16] {
54 &self.0
55 }
56
57 #[must_use]
58 pub fn into_array(self) -> [f64; 16] {
59 self.0
60 }
61}
62
63impl Default for AffineTransform3D {
64 fn default() -> Self {
65 Self::identity()
66 }
67}
68
69impl From<[f64; 16]> for AffineTransform3D {
70 fn from(value: [f64; 16]) -> Self {
71 Self::new(value)
72 }
73}
74
75impl From<AffineTransform3D> for [f64; 16] {
76 fn from(value: AffineTransform3D) -> Self {
77 value.into_array()
78 }
79}
80
81impl AsRef<[f64; 16]> for AffineTransform3D {
82 fn as_ref(&self) -> &[f64; 16] {
83 self.as_array()
84 }
85}
86
87#[derive(Clone, Copy, Debug)]
88pub(crate) struct GeometryInstanceData<VR: VertexRef, RR: ResourceId> {
89 template: RR,
90 reference_point: VertexIndex<VR>,
91 transformation: AffineTransform3D,
92}
93
94impl<VR: VertexRef, RR: ResourceId> GeometryInstanceData<VR, RR> {
95 #[must_use]
96 pub(crate) fn new(
97 template: RR,
98 reference_point: VertexIndex<VR>,
99 transformation: AffineTransform3D,
100 ) -> Self {
101 Self {
102 template,
103 reference_point,
104 transformation,
105 }
106 }
107
108 pub(crate) fn template(&self) -> &RR {
109 &self.template
110 }
111
112 pub(crate) fn reference_point(&self) -> &VertexIndex<VR> {
113 &self.reference_point
114 }
115
116 pub(crate) fn transformation(&self) -> &AffineTransform3D {
117 &self.transformation
118 }
119}
120
121#[derive(Clone, Debug)]
124pub(crate) struct GeometryCore<VR: VertexRef, RR: ResourceId, SS: StringStorage> {
125 type_geometry: GeometryType,
126 lod: Option<LoD>,
127 boundaries: Option<Boundary<VR>>,
128 semantics: Option<SemanticOrMaterialMap<VR, RR>>,
129 materials: Option<ThemedMaterials<VR, RR, SS>>,
130 textures: Option<ThemedTextures<VR, RR, SS>>,
131 instance: Option<GeometryInstanceData<VR, RR>>,
132}
133
134impl<VR: VertexRef, RR: ResourceId, SS: StringStorage> GeometryCore<VR, RR, SS> {
135 #[allow(clippy::too_many_arguments)]
136 pub(crate) fn new(
137 type_geometry: GeometryType,
138 lod: Option<LoD>,
139 boundaries: Option<Boundary<VR>>,
140 semantics: Option<SemanticOrMaterialMap<VR, RR>>,
141 materials: Option<ThemedMaterials<VR, RR, SS>>,
142 textures: Option<ThemedTextures<VR, RR, SS>>,
143 instance: Option<GeometryInstanceData<VR, RR>>,
144 ) -> Self {
145 Self {
146 type_geometry,
147 lod,
148 boundaries,
149 semantics,
150 materials,
151 textures,
152 instance,
153 }
154 }
155
156 pub fn type_geometry(&self) -> &GeometryType {
157 &self.type_geometry
158 }
159
160 pub fn lod(&self) -> Option<&LoD> {
161 self.lod.as_ref()
162 }
163
164 pub fn boundaries(&self) -> Option<&Boundary<VR>> {
165 self.boundaries.as_ref()
166 }
167
168 pub(crate) fn semantics(&self) -> Option<&SemanticOrMaterialMap<VR, RR>> {
169 self.semantics.as_ref()
170 }
171
172 pub(crate) fn materials(&self) -> Option<&ThemedMaterials<VR, RR, SS>> {
173 self.materials.as_ref()
174 }
175
176 pub(crate) fn textures(&self) -> Option<&ThemedTextures<VR, RR, SS>> {
177 self.textures.as_ref()
178 }
179
180 pub(crate) fn instance(&self) -> Option<&GeometryInstanceData<VR, RR>> {
181 self.instance.as_ref()
182 }
183}
184
185#[repr(C)]
186#[derive(Debug, Clone, Copy, Hash, Ord, PartialOrd, Eq, PartialEq)]
187#[non_exhaustive]
188pub enum GeometryType {
189 MultiPoint,
190 MultiLineString,
191 MultiSurface,
192 CompositeSurface,
193 Solid,
194 MultiSolid,
195 CompositeSolid,
196 GeometryInstance,
197}
198
199impl std::fmt::Display for GeometryType {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 write!(f, "{self:?}")
202 }
203}
204
205impl FromStr for GeometryType {
206 type Err = Error;
207
208 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
209 match s {
210 "MultiPoint" => Ok(GeometryType::MultiPoint),
211 "MultiLineString" => Ok(GeometryType::MultiLineString),
212 "MultiSurface" => Ok(GeometryType::MultiSurface),
213 "CompositeSurface" => Ok(GeometryType::CompositeSurface),
214 "Solid" => Ok(GeometryType::Solid),
215 "MultiSolid" => Ok(GeometryType::MultiSolid),
216 "CompositeSolid" => Ok(GeometryType::CompositeSolid),
217 "GeometryInstance" => Ok(GeometryType::GeometryInstance),
218 &_ => Err(Error::InvalidGeometryType {
219 expected: "one of MultiPoint, MultiLineString, MultiSurface, CompositeSurface, Solid, MultiSolid, CompositeSolid, GeometryInstance"
220 .to_string(),
221 found: s.to_string(),
222 }),
223 }
224 }
225}
226
227#[repr(C)]
229#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
230#[non_exhaustive]
231pub enum LoD {
232 LoD0,
233 LoD0_0,
234 LoD0_1,
235 LoD0_2,
236 LoD0_3,
237 LoD1,
238 LoD1_0,
239 LoD1_1,
240 LoD1_2,
241 LoD1_3,
242 LoD2,
243 LoD2_0,
244 LoD2_1,
245 LoD2_2,
246 LoD2_3,
247 LoD3,
248 LoD3_0,
249 LoD3_1,
250 LoD3_2,
251 LoD3_3,
252}
253
254impl std::fmt::Display for LoD {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 match *self {
257 LoD::LoD0 => write!(f, "0"),
258 LoD::LoD0_0 => write!(f, "0.0"),
259 LoD::LoD0_1 => write!(f, "0.1"),
260 LoD::LoD0_2 => write!(f, "0.2"),
261 LoD::LoD0_3 => write!(f, "0.3"),
262 LoD::LoD1 => write!(f, "1"),
263 LoD::LoD1_0 => write!(f, "1.0"),
264 LoD::LoD1_1 => write!(f, "1.1"),
265 LoD::LoD1_2 => write!(f, "1.2"),
266 LoD::LoD1_3 => write!(f, "1.3"),
267 LoD::LoD2 => write!(f, "2"),
268 LoD::LoD2_0 => write!(f, "2.0"),
269 LoD::LoD2_1 => write!(f, "2.1"),
270 LoD::LoD2_2 => write!(f, "2.2"),
271 LoD::LoD2_3 => write!(f, "2.3"),
272 LoD::LoD3 => write!(f, "3"),
273 LoD::LoD3_0 => write!(f, "3.0"),
274 LoD::LoD3_1 => write!(f, "3.1"),
275 LoD::LoD3_2 => write!(f, "3.2"),
276 LoD::LoD3_3 => write!(f, "3.3"),
277 }
278 }
279}