1#[derive(Debug, Clone, Copy)]
5pub struct RawSliceView<'a, T> {
6 data: &'a [T],
7}
8
9impl<'a, T> RawSliceView<'a, T> {
10 #[inline]
11 pub fn new(data: &'a [T]) -> Self {
12 Self { data }
13 }
14
15 #[inline]
16 #[must_use]
17 pub fn as_slice(&self) -> &'a [T] {
18 self.data
19 }
20
21 #[inline]
22 #[must_use]
23 pub fn len(&self) -> usize {
24 self.data.len()
25 }
26
27 #[inline]
28 #[must_use]
29 pub fn is_empty(&self) -> bool {
30 self.data.is_empty()
31 }
32
33 #[inline]
34 #[must_use]
35 pub fn get(&self, index: usize) -> Option<&'a T> {
36 self.data.get(index)
37 }
38
39 #[inline]
40 pub fn iter(&self) -> std::slice::Iter<'a, T> {
41 self.into_iter()
42 }
43}
44
45impl<'a, T> IntoIterator for RawSliceView<'a, T> {
46 type Item = &'a T;
47 type IntoIter = std::slice::Iter<'a, T>;
48
49 fn into_iter(self) -> Self::IntoIter {
50 self.data.iter()
51 }
52}
53
54impl<'a, T> IntoIterator for &'_ RawSliceView<'a, T> {
55 type Item = &'a T;
56 type IntoIter = std::slice::Iter<'a, T>;
57
58 fn into_iter(self) -> Self::IntoIter {
59 self.data.iter()
60 }
61}
62
63#[derive(Debug, Clone, Copy)]
67pub struct RawPoolView<'a, T> {
68 resources: &'a [Option<T>],
69 generations: &'a [u16],
70}
71
72impl<'a, T> RawPoolView<'a, T> {
73 #[inline]
74 pub fn new(resources: &'a [Option<T>], generations: &'a [u16]) -> Self {
75 Self {
76 resources,
77 generations,
78 }
79 }
80
81 #[inline]
82 #[must_use]
83 pub fn resources(&self) -> &'a [Option<T>] {
84 self.resources
85 }
86
87 #[inline]
88 #[must_use]
89 pub fn generations(&self) -> &'a [u16] {
93 self.generations
94 }
95
96 #[inline]
97 #[must_use]
98 pub fn capacity(&self) -> usize {
99 self.resources.len()
100 }
101
102 #[must_use]
103 pub fn len(&self) -> usize {
104 self.resources.iter().filter(|r| r.is_some()).count()
105 }
106
107 #[inline]
108 #[must_use]
109 pub fn is_empty(&self) -> bool {
110 self.len() == 0
111 }
112
113 pub fn iter_occupied(&self) -> impl Iterator<Item = (usize, &'a T)> {
114 self.resources
115 .iter()
116 .enumerate()
117 .filter_map(|(i, opt)| opt.as_ref().map(|value| (i, value)))
118 }
119
120 #[must_use]
121 pub fn dense_index_remap(&self) -> DenseIndexRemap {
122 DenseIndexRemap::from_occupied_indices(
123 self.capacity(),
124 self.iter_occupied().map(|(i, _)| i),
125 )
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
131pub struct DenseIndexRemap {
132 dense_by_stored_index: Vec<Option<usize>>,
133 dense_len: usize,
134}
135
136impl DenseIndexRemap {
137 #[must_use]
138 pub fn identity(len: usize) -> Self {
139 Self {
140 dense_by_stored_index: (0..len).map(Some).collect(),
141 dense_len: len,
142 }
143 }
144
145 #[must_use]
146 pub fn from_occupied_indices(
147 capacity: usize,
148 occupied_indices: impl IntoIterator<Item = usize>,
149 ) -> Self {
150 let mut dense_by_stored_index = vec![None; capacity];
151 let mut dense_len = 0;
152
153 for stored_index in occupied_indices {
154 if let Some(slot) = dense_by_stored_index.get_mut(stored_index) {
155 *slot = Some(dense_len);
156 dense_len += 1;
157 }
158 }
159
160 Self {
161 dense_by_stored_index,
162 dense_len,
163 }
164 }
165
166 #[must_use]
167 pub fn get(&self, stored_index: usize) -> Option<usize> {
168 self.dense_by_stored_index
169 .get(stored_index)
170 .copied()
171 .flatten()
172 }
173
174 #[must_use]
175 pub fn len(&self) -> usize {
176 self.dense_len
177 }
178
179 #[must_use]
180 pub fn is_empty(&self) -> bool {
181 self.dense_len == 0
182 }
183
184 #[must_use]
185 pub fn as_slice(&self) -> &[Option<usize>] {
186 &self.dense_by_stored_index
187 }
188}
189
190#[derive(Debug, Clone, Copy)]
192pub struct ColumnarCoordinates<'a> {
193 pub x: &'a [i64],
194 pub y: &'a [i64],
195 pub z: &'a [i64],
196}
197
198#[derive(Debug, Clone, Copy)]
200pub struct ColumnarRealCoordinates<'a> {
201 pub x: &'a [f64],
202 pub y: &'a [f64],
203 pub z: &'a [f64],
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use crate::CityModelType;
210 use crate::v2_0::appearance::ImageType;
211 use crate::v2_0::geometry::semantic::SemanticType;
212 use crate::v2_0::{
213 GeometryDraft, Material, OwnedCityModel, RingDraft, Semantic, SurfaceDraft, Texture,
214 };
215
216 #[test]
217 fn dense_index_remap_compacts_sparse_slots() {
218 let remap = DenseIndexRemap::from_occupied_indices(5, [1, 3, 4]);
219 assert_eq!(remap.as_slice(), &[None, Some(0), None, Some(1), Some(2)]);
220 assert_eq!(remap.len(), 3);
221 }
222
223 #[test]
224 fn raw_export_remapping_is_stable_for_geometry_resources_and_uvs() {
225 let mut model = OwnedCityModel::new(CityModelType::CityJSON);
226 let stale_semantic = model
227 .add_semantic(Semantic::new(SemanticType::RoofSurface))
228 .unwrap();
229 let stale_material = model
230 .add_material(Material::new("stale".to_string()))
231 .unwrap();
232 let stale_texture = model
233 .add_texture(Texture::new("stale.png".to_string(), ImageType::Png))
234 .unwrap();
235
236 let live_semantic = model
237 .add_semantic(Semantic::new(SemanticType::WallSurface))
238 .unwrap();
239 let live_material = model
240 .add_material(Material::new("live".to_string()))
241 .unwrap();
242 let live_texture = model
243 .add_texture(Texture::new("live.png".to_string(), ImageType::Png))
244 .unwrap();
245
246 let geometry_handle = GeometryDraft::multi_surface(
247 None,
248 [SurfaceDraft::new(
249 RingDraft::new([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]).with_texture(
250 "theme".to_string(),
251 live_texture,
252 [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]],
253 ),
254 [],
255 )
256 .with_semantic(live_semantic)
257 .with_material("theme".to_string(), live_material)],
258 )
259 .insert_into(&mut model)
260 .unwrap();
261 assert!(model.remove_semantic(stale_semantic).is_some());
262 assert!(model.remove_material(stale_material).is_some());
263 assert!(model.remove_texture(stale_texture).is_some());
264
265 let raw = model.raw();
266 let semantic_remap = raw.semantics().dense_index_remap();
267 let material_remap = raw.materials().dense_index_remap();
268 let texture_remap = raw.textures().dense_index_remap();
269 let uv_remap = DenseIndexRemap::identity(raw.uv_coordinates().len());
270
271 assert_eq!(
272 semantic_remap.as_slice(),
273 raw.semantics().dense_index_remap().as_slice()
274 );
275 assert_eq!(
276 material_remap.as_slice(),
277 raw.materials().dense_index_remap().as_slice()
278 );
279 assert_eq!(
280 texture_remap.as_slice(),
281 raw.textures().dense_index_remap().as_slice()
282 );
283 assert_eq!(
284 uv_remap.as_slice(),
285 DenseIndexRemap::identity(raw.uv_coordinates().len()).as_slice()
286 );
287
288 let geometry = model.get_geometry(geometry_handle).unwrap();
289 let semantic_handle = geometry.semantics().unwrap().surfaces()[0].unwrap();
290 let (_material_theme, material_map) = geometry.materials().unwrap().first().unwrap();
291 let (_texture_theme, texture_map) = geometry.textures().unwrap().first().unwrap();
292
293 assert_eq!(
294 semantic_remap.get(semantic_handle.index() as usize),
295 Some(0)
296 );
297 assert_eq!(
298 material_remap.get(material_map.surfaces()[0].unwrap().index() as usize),
299 Some(0)
300 );
301 assert_eq!(
302 texture_remap.get(texture_map.ring_textures()[0].unwrap().index() as usize),
303 Some(0)
304 );
305
306 let remapped_uvs: Vec<_> = texture_map
307 .vertices()
308 .iter()
309 .map(|uv_ref| uv_remap.get(uv_ref.unwrap().to_usize()).unwrap())
310 .collect();
311 assert_eq!(remapped_uvs, vec![0, 1, 2]);
312 }
313}