1use std::{fmt, io, mem};
2
3use bytemuck::cast_slice;
4use geo_types::{MultiLineString, Point};
5
6use crate::{
7 BoundingBox, InputRelation, OutputRelation, RelationBetweenShapes, Zerometry, Zoint,
8 Zollection, Zolygon, ZultiPoints, ZultiPolygons, bounding_box::BOUNDING_BOX_SIZE_IN_BYTES,
9 zine::Zine,
10};
11
12#[derive(Clone, Copy)]
13pub struct ZultiLines<'a> {
14 bounding_box: &'a BoundingBox,
15 offsets: &'a [u32],
19 bytes: &'a [u8],
20}
21
22impl<'a> ZultiLines<'a> {
23 pub fn new(bounding_box: &'a BoundingBox, offsets: &'a [u32], bytes: &'a [u8]) -> Self {
24 Self {
25 bounding_box,
26 offsets,
27 bytes,
28 }
29 }
30
31 pub fn from_bytes(data: &'a [u8]) -> Self {
32 let bounding_box = BoundingBox::from_bytes(&data[..BOUNDING_BOX_SIZE_IN_BYTES]);
34 let data = &data[BOUNDING_BOX_SIZE_IN_BYTES..];
35
36 let offsets_count = u32::from_ne_bytes(data[..mem::size_of::<u32>()].try_into().unwrap());
39 let data = &data[mem::size_of::<u32>()..];
40 let size_of_offsets = offsets_count as usize * mem::size_of::<u32>();
42 let offsets = &data[..size_of_offsets];
43 let offsets: &[u32] = cast_slice(offsets);
44 let data = &data[size_of_offsets..];
45 let data = if offsets_count % 2 == 0 {
47 debug_assert_eq!(data[0..mem::size_of::<u32>()], [0, 0, 0, 0]);
48 &data[mem::size_of::<u32>()..]
49 } else {
50 data
51 };
52 let bytes = data;
54
55 Self {
56 bounding_box,
57 offsets,
58 bytes,
59 }
60 }
61
62 pub fn write_from_geometry(
63 writer: &mut Vec<u8>,
64 geometry: &MultiLineString<f64>,
65 ) -> Result<(), io::Error> {
66 BoundingBox::write_from_geometry(
67 writer,
68 geometry
69 .0
70 .iter()
71 .flat_map(|line| line.0.iter())
72 .map(|coord| Point::from((coord.x, coord.y))),
73 )?;
74 writer.extend((geometry.0.len() as u32).to_ne_bytes());
76 let offsets_addr = writer.len();
77 writer.extend(std::iter::repeat_n(
79 0,
80 geometry.0.len() * mem::size_of::<u32>(),
81 ));
82 if geometry.0.len() % 2 == 0 {
83 writer.extend(0_u32.to_ne_bytes());
85 }
86 let start = writer.len();
87 let mut offsets = Vec::new();
88 for line in geometry.iter() {
89 offsets.push(writer.len() as u32 - start as u32);
90 Zine::write_from_geometry(writer, line)?;
91 }
92
93 for (i, offset) in offsets.iter().enumerate() {
94 let offset_addr = offsets_addr + i * mem::size_of::<u32>();
95 writer[offset_addr..offset_addr + mem::size_of::<u32>()]
96 .copy_from_slice(&offset.to_ne_bytes());
97 }
98 Ok(())
99 }
100
101 pub fn bounding_box(&self) -> &'a BoundingBox {
102 self.bounding_box
103 }
104
105 pub fn get(&self, index: usize) -> Option<Zine<'a>> {
106 let offset = *self.offsets.get(index)?;
107 let next_offset = *self
108 .offsets
109 .get(index + 1)
110 .unwrap_or(&(self.bytes.len() as u32));
111 let bytes = &self.bytes[offset as usize..next_offset as usize];
112 Some(Zine::from_bytes(bytes))
113 }
114
115 pub fn len(&self) -> usize {
116 self.offsets.len()
117 }
118
119 pub fn is_empty(&self) -> bool {
120 self.len() == 0
121 }
122
123 pub fn lines(&'a self) -> impl Iterator<Item = Zine<'a>> {
124 (0..self.len()).map(move |index| self.get(index).unwrap())
125 }
126
127 pub fn to_geo(&self) -> geo_types::MultiLineString<f64> {
128 geo_types::MultiLineString::new(self.lines().map(|zine| zine.to_geo()).collect())
129 }
130}
131
132impl<'a> fmt::Debug for ZultiLines<'a> {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 struct ZinesDebug<'b, 'a>(&'b ZultiLines<'a>);
135
136 impl<'b, 'a> fmt::Debug for ZinesDebug<'b, 'a> {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_list().entries(self.0.lines()).finish()
139 }
140 }
141
142 f.debug_struct("ZultiLines")
143 .field("bounding_box", &self.bounding_box())
144 .field("zines", &ZinesDebug(self))
145 .finish()
146 }
147}
148
149impl<'a> RelationBetweenShapes<Zoint<'a>> for ZultiLines<'a> {
151 fn relation(&self, _other: &Zoint, relation: InputRelation) -> OutputRelation {
152 relation.to_false().make_disjoint_if_set()
153 }
154}
155
156impl<'a> RelationBetweenShapes<ZultiPoints<'a>> for ZultiLines<'a> {
157 fn relation(&self, _other: &ZultiPoints, relation: InputRelation) -> OutputRelation {
158 relation.to_false().make_disjoint_if_set()
159 }
160}
161
162impl<'a> RelationBetweenShapes<Zine<'a>> for ZultiLines<'a> {
163 fn relation(&self, other: &Zine, relation: InputRelation) -> OutputRelation {
164 if self.is_empty() || other.is_empty() || self.bounding_box().disjoint(other.bounding_box())
165 {
166 return relation.to_false().make_disjoint_if_set();
167 }
168
169 for line in self.lines() {
170 if line.intersects(other) {
171 return relation.to_false().make_intersect_if_set();
172 }
173 }
174
175 relation.to_false().make_disjoint_if_set()
176 }
177}
178
179impl<'a> RelationBetweenShapes<ZultiLines<'a>> for ZultiLines<'a> {
180 fn relation(&self, other: &ZultiLines, relation: InputRelation) -> OutputRelation {
181 if self.is_empty() || other.is_empty() || self.bounding_box().disjoint(other.bounding_box())
182 {
183 return relation.to_false().make_disjoint_if_set();
184 }
185
186 for left in self.lines() {
187 for right in other.lines() {
188 if left.intersects(&right) {
189 return relation.to_false().make_intersect_if_set();
190 }
191 }
192 }
193
194 relation.to_false().make_disjoint_if_set()
195 }
196}
197
198impl<'a> RelationBetweenShapes<Zolygon<'a>> for ZultiLines<'a> {
199 fn relation(&self, other: &Zolygon, relation: InputRelation) -> OutputRelation {
200 let mut output = relation.to_false();
201
202 if self.is_empty() || other.is_empty() || self.bounding_box().disjoint(other.bounding_box())
203 {
204 return output.make_disjoint_if_set();
205 }
206
207 let mut contained = 0;
208 for line in self.lines() {
209 let r = line.relation(other, relation.strip_strict().strip_disjoint());
210 output |= r;
211 if r.contained.unwrap_or_default() {
212 contained += 1;
213 }
214
215 if output.any_relation() && relation.early_exit {
216 return output;
217 }
218 }
219
220 if contained == self.len() {
221 output = output.make_strict_contains_if_set();
222 }
223
224 if output.any_relation() {
225 output
226 } else {
227 output.make_disjoint_if_set()
228 }
229 }
230}
231
232impl<'a> RelationBetweenShapes<ZultiPolygons<'a>> for ZultiLines<'a> {
233 fn relation(&self, other: &ZultiPolygons, relation: InputRelation) -> OutputRelation {
234 let mut output = relation.to_false();
235
236 if self.is_empty() || other.is_empty() || self.bounding_box().disjoint(other.bounding_box())
237 {
238 return output.make_disjoint_if_set();
239 }
240 let mut contained = 0;
241 for line in self.lines() {
242 for polygon in other.polygons() {
243 let r = line.relation(&polygon, relation.strip_strict().strip_disjoint());
244 output |= r;
245 if r.contained.unwrap_or_default() {
246 contained += 1;
247 }
248
249 if output.any_relation() && relation.early_exit {
250 return output;
251 }
252 }
253 }
254
255 if contained == self.len() {
256 output = output.make_strict_contained_if_set();
257 }
258
259 if output.any_relation() {
260 output
261 } else {
262 output.make_disjoint_if_set()
263 }
264 }
265}
266
267impl<'a> RelationBetweenShapes<Zollection<'a>> for ZultiLines<'a> {
268 fn relation(&self, other: &Zollection<'a>, relation: InputRelation) -> OutputRelation {
269 other
270 .relation(self, relation.swap_contains_relation())
271 .swap_contains_relation()
272 }
273}
274
275impl<'a> RelationBetweenShapes<Zerometry<'a>> for ZultiLines<'a> {
276 fn relation(&self, other: &Zerometry<'a>, relation: InputRelation) -> OutputRelation {
277 other
278 .relation(self, relation.swap_contains_relation())
279 .swap_contains_relation()
280 }
281}
282
283impl PartialEq<MultiLineString> for ZultiLines<'_> {
284 fn eq(&self, other: &MultiLineString) -> bool {
285 self.lines()
286 .zip(other.0.iter())
287 .all(|(zine, line)| zine.eq(line))
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use geo::{LineString, MultiPolygon, coord, polygon};
294 use geo_types::MultiLineString;
295 use insta::{assert_compact_debug_snapshot, assert_debug_snapshot, assert_snapshot};
296
297 use super::*;
298
299 #[test]
300 fn test_write_from_geometry_with_even_number_of_elements() {
301 let first_line = LineString::from(vec![
302 Point::from((0.0, 0.0)),
303 Point::from((10.0, 0.0)),
304 Point::from((0.0, 10.0)),
305 ]);
306 let second_line = LineString::from(vec![
307 Point::from((10.0, 10.0)),
308 Point::from((20.0, 0.0)),
309 Point::from((20.0, 10.0)),
310 ]);
311 let geometry = MultiLineString::new(vec![first_line.clone(), second_line.clone()]);
312
313 let mut writer = Vec::new();
314
315 ZultiLines::write_from_geometry(&mut writer, &geometry).unwrap();
316 assert_debug_snapshot!(writer);
318 let mut current_offset = 0;
319 let expected_bounding_box: &[f64] =
320 cast_slice(&writer[current_offset..BOUNDING_BOX_SIZE_IN_BYTES]);
321 assert_compact_debug_snapshot!(expected_bounding_box, @"[0.0, 0.0, 20.0, 10.0]");
322 current_offset += BOUNDING_BOX_SIZE_IN_BYTES;
323 let expected_nb_offsets: u32 = u32::from_ne_bytes(
324 writer[current_offset..current_offset + mem::size_of::<u32>()]
325 .try_into()
326 .unwrap(),
327 );
328 assert_snapshot!(expected_nb_offsets, @"2");
329 current_offset += mem::size_of::<u32>();
330 let expected_offsets: &[u32] = cast_slice(
332 &writer[current_offset
333 ..current_offset + mem::size_of::<u32>() * expected_nb_offsets as usize],
334 );
335 assert_compact_debug_snapshot!(expected_offsets, @"[0, 80]");
336 current_offset += mem::size_of::<u32>() * expected_nb_offsets as usize;
337 let padding = &writer[current_offset..current_offset + mem::size_of::<u32>()];
339 assert_compact_debug_snapshot!(padding, @"[0, 0, 0, 0]");
340 current_offset += mem::size_of::<u32>();
341 let first_zine_bytes = &writer[current_offset + expected_offsets[0] as usize
343 ..current_offset + expected_offsets[1] as usize];
344 assert_compact_debug_snapshot!(first_zine_bytes, @"[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64]");
345 let first_zine = Zine::from_bytes(first_zine_bytes);
346 assert_compact_debug_snapshot!(first_zine, @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 10.0, y: 10.0 } }, points: [Zoint { lng: 0.0, lat: 0.0 }, Zoint { lng: 10.0, lat: 0.0 }, Zoint { lng: 0.0, lat: 10.0 }] }");
347 assert_eq!(first_zine, first_line);
348 let second_zine_bytes = &writer[current_offset + expected_offsets[1] as usize..];
349 assert_compact_debug_snapshot!(second_zine_bytes, @"[0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 64, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 64, 0, 0, 0, 0, 0, 0, 36, 64]");
350 let second_zine = Zine::from_bytes(second_zine_bytes);
351 assert_compact_debug_snapshot!(second_zine, @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 10.0, y: 0.0 }, top_right: Coord { x: 20.0, y: 10.0 } }, points: [Zoint { lng: 10.0, lat: 10.0 }, Zoint { lng: 20.0, lat: 0.0 }, Zoint { lng: 20.0, lat: 10.0 }] }");
352 assert_eq!(second_zine, second_line);
353
354 let zulti_lines = ZultiLines::from_bytes(&writer);
356 assert_snapshot!(zulti_lines.len(), @"2");
357 assert_compact_debug_snapshot!(zulti_lines.bounding_box(), @"BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 20.0, y: 10.0 } }");
358 assert_compact_debug_snapshot!(zulti_lines.offsets, @"[0, 80]");
359 assert_compact_debug_snapshot!(zulti_lines.get(0).unwrap(), @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 10.0, y: 10.0 } }, points: [Zoint { lng: 0.0, lat: 0.0 }, Zoint { lng: 10.0, lat: 0.0 }, Zoint { lng: 0.0, lat: 10.0 }] }");
360 assert_compact_debug_snapshot!(zulti_lines.get(1).unwrap(), @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 10.0, y: 0.0 }, top_right: Coord { x: 20.0, y: 10.0 } }, points: [Zoint { lng: 10.0, lat: 10.0 }, Zoint { lng: 20.0, lat: 0.0 }, Zoint { lng: 20.0, lat: 10.0 }] }");
361 assert_compact_debug_snapshot!(zulti_lines.get(2), @"None");
362 assert_debug_snapshot!(zulti_lines, @r"
363 ZultiLines {
364 bounding_box: BoundingBox {
365 bottom_left: Coord {
366 x: 0.0,
367 y: 0.0,
368 },
369 top_right: Coord {
370 x: 20.0,
371 y: 10.0,
372 },
373 },
374 zines: [
375 Zine {
376 bounding_box: BoundingBox {
377 bottom_left: Coord {
378 x: 0.0,
379 y: 0.0,
380 },
381 top_right: Coord {
382 x: 10.0,
383 y: 10.0,
384 },
385 },
386 points: [
387 Zoint {
388 lng: 0.0,
389 lat: 0.0,
390 },
391 Zoint {
392 lng: 10.0,
393 lat: 0.0,
394 },
395 Zoint {
396 lng: 0.0,
397 lat: 10.0,
398 },
399 ],
400 },
401 Zine {
402 bounding_box: BoundingBox {
403 bottom_left: Coord {
404 x: 10.0,
405 y: 0.0,
406 },
407 top_right: Coord {
408 x: 20.0,
409 y: 10.0,
410 },
411 },
412 points: [
413 Zoint {
414 lng: 10.0,
415 lat: 10.0,
416 },
417 Zoint {
418 lng: 20.0,
419 lat: 0.0,
420 },
421 Zoint {
422 lng: 20.0,
423 lat: 10.0,
424 },
425 ],
426 },
427 ],
428 }
429 ");
430 }
431
432 #[test]
433 fn test_write_from_geometry_with_odd_number_of_elements() {
434 let first_line = LineString::from(vec![
435 Point::from((0.0, 0.0)),
436 Point::from((10.0, 0.0)),
437 Point::from((0.0, 10.0)),
438 ]);
439 let geometry = MultiLineString::new(vec![first_line.clone()]);
440
441 let mut writer = Vec::new();
442
443 ZultiLines::write_from_geometry(&mut writer, &geometry).unwrap();
444 assert_debug_snapshot!(writer);
446 let mut current_offset = 0;
447 let expected_bounding_box: &[f64] =
448 cast_slice(&writer[current_offset..BOUNDING_BOX_SIZE_IN_BYTES]);
449 assert_compact_debug_snapshot!(expected_bounding_box, @"[0.0, 0.0, 10.0, 10.0]");
450 current_offset += BOUNDING_BOX_SIZE_IN_BYTES;
451 let expected_nb_offsets: u32 = u32::from_ne_bytes(
452 writer[current_offset..current_offset + mem::size_of::<u32>()]
453 .try_into()
454 .unwrap(),
455 );
456 assert_snapshot!(expected_nb_offsets, @"1");
457 current_offset += mem::size_of::<u32>();
458 let expected_offsets: &[u32] = cast_slice(
460 &writer[current_offset
461 ..current_offset + mem::size_of::<u32>() * expected_nb_offsets as usize],
462 );
463 assert_compact_debug_snapshot!(expected_offsets, @"[0]");
464 current_offset += mem::size_of::<u32>() * expected_nb_offsets as usize;
465 let first_zine_bytes = &writer[current_offset + expected_offsets[0] as usize..];
469 assert_compact_debug_snapshot!(first_zine_bytes, @"[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64]");
470 let first_zine = Zine::from_bytes(first_zine_bytes);
471 assert_compact_debug_snapshot!(first_zine, @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 10.0, y: 10.0 } }, points: [Zoint { lng: 0.0, lat: 0.0 }, Zoint { lng: 10.0, lat: 0.0 }, Zoint { lng: 0.0, lat: 10.0 }] }");
472 assert_eq!(first_zine, first_line);
473
474 let zulti_polygon = ZultiLines::from_bytes(&writer);
476 assert_snapshot!(zulti_polygon.len(), @"1");
477 assert_compact_debug_snapshot!(zulti_polygon.bounding_box(), @"BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 10.0, y: 10.0 } }");
478 assert_compact_debug_snapshot!(zulti_polygon.offsets, @"[0]");
479 assert_compact_debug_snapshot!(zulti_polygon.get(0).unwrap(), @"Zine { bounding_box: BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 10.0, y: 10.0 } }, points: [Zoint { lng: 0.0, lat: 0.0 }, Zoint { lng: 10.0, lat: 0.0 }, Zoint { lng: 0.0, lat: 10.0 }] }");
480 assert_compact_debug_snapshot!(zulti_polygon.get(1), @"None");
481 assert_debug_snapshot!(zulti_polygon, @r"
482 ZultiLines {
483 bounding_box: BoundingBox {
484 bottom_left: Coord {
485 x: 0.0,
486 y: 0.0,
487 },
488 top_right: Coord {
489 x: 10.0,
490 y: 10.0,
491 },
492 },
493 zines: [
494 Zine {
495 bounding_box: BoundingBox {
496 bottom_left: Coord {
497 x: 0.0,
498 y: 0.0,
499 },
500 top_right: Coord {
501 x: 10.0,
502 y: 10.0,
503 },
504 },
505 points: [
506 Zoint {
507 lng: 0.0,
508 lat: 0.0,
509 },
510 Zoint {
511 lng: 10.0,
512 lat: 0.0,
513 },
514 Zoint {
515 lng: 0.0,
516 lat: 10.0,
517 },
518 ],
519 },
520 ],
521 }
522 ");
523 }
524
525 #[test]
526 fn test_write_from_geometry_with_no_elements() {
527 let geometry = MultiLineString::new(vec![]);
528
529 let mut writer = Vec::new();
530
531 ZultiLines::write_from_geometry(&mut writer, &geometry).unwrap();
532 assert_debug_snapshot!(writer);
534 let mut current_offset = 0;
535 let expected_bounding_box: &[f64] =
536 cast_slice(&writer[current_offset..BOUNDING_BOX_SIZE_IN_BYTES]);
537 assert_compact_debug_snapshot!(expected_bounding_box, @"[0.0, 0.0, 0.0, 0.0]");
538 current_offset += BOUNDING_BOX_SIZE_IN_BYTES;
539 let expected_nb_offsets: u32 = u32::from_ne_bytes(
540 writer[current_offset..current_offset + mem::size_of::<u32>()]
541 .try_into()
542 .unwrap(),
543 );
544 assert_snapshot!(expected_nb_offsets, @"0");
545 current_offset += mem::size_of::<u32>();
546 let expected_offsets: &[u32] = cast_slice(
548 &writer[current_offset
549 ..current_offset + mem::size_of::<u32>() * expected_nb_offsets as usize],
550 );
551 assert_compact_debug_snapshot!(expected_offsets, @"[]");
552 current_offset += mem::size_of::<u32>() * expected_nb_offsets as usize;
553 let padding = &writer[current_offset..current_offset + mem::size_of::<u32>()];
555 assert_compact_debug_snapshot!(padding, @"[0, 0, 0, 0]");
556
557 let zulti_lines = ZultiLines::from_bytes(&writer);
559 assert_snapshot!(zulti_lines.len(), @"0");
560 assert_compact_debug_snapshot!(zulti_lines.bounding_box(), @"BoundingBox { bottom_left: Coord { x: 0.0, y: 0.0 }, top_right: Coord { x: 0.0, y: 0.0 } }");
561 assert_compact_debug_snapshot!(zulti_lines.offsets, @"[]");
562 assert_compact_debug_snapshot!(zulti_lines.get(0), @"None");
563 assert_debug_snapshot!(zulti_lines, @r"
564 ZultiLines {
565 bounding_box: BoundingBox {
566 bottom_left: Coord {
567 x: 0.0,
568 y: 0.0,
569 },
570 top_right: Coord {
571 x: 0.0,
572 y: 0.0,
573 },
574 },
575 zines: [],
576 }
577 ");
578 }
579
580 #[test]
581 fn test_multi_lines_and_multipolygon() {
582 let inside_line = LineString::new(vec![
583 coord! { x: 0.4, y: 0.4},
584 coord! { x: 0.6, y: 0.4},
585 coord! { x: 0.6, y: 0.6},
586 coord! { x: 0.4, y: 0.6},
587 ]);
588 let outside_line = LineString::new(vec![
589 coord! { x: -0.4, y: -0.4},
590 coord! { x: -0.6, y: -0.4},
591 coord! { x: -0.6, y: -0.6},
592 coord! { x: -0.4, y: -0.6},
593 ]);
594 let inside = polygon![
595 (x: 0., y: 0.),
596 (x: 1., y: 0.),
597 (x: 1., y: 1.),
598 (x: 0., y: 1.),
599 ];
600 let outside = polygon![
601 (x: 5., y: 5.),
602 (x: 6., y: 5.),
603 (x: 6., y: 6.),
604 (x: 5., y: 6.),
605 ];
606 let intersect = polygon![
607 (x: 0.5, y: 0.5),
608 (x: 0.6, y: 0.5),
609 (x: 0.6, y: 0.6),
610 (x: 0.5, y: 0.6),
611 ];
612 let multi_line_strict_inside =
613 MultiLineString::new(vec![inside_line.clone(), inside_line.clone()]);
614 let multi_line_outside =
615 MultiLineString::new(vec![outside_line.clone(), outside_line.clone()]);
616 let multi_line_inside = MultiLineString::new(vec![outside_line, inside_line]);
617
618 let multi_polygons_inside = MultiPolygon::new(vec![inside.clone()]);
619 let multi_polygons_outside = MultiPolygon::new(vec![outside.clone()]);
620 let multi_polygons_intersect = MultiPolygon::new(vec![intersect.clone()]);
621 let multi_polygons_in_and_out = MultiPolygon::new(vec![inside.clone(), outside.clone()]);
622 let multi_polygons_all =
623 MultiPolygon::new(vec![inside.clone(), outside.clone(), intersect.clone()]);
624
625 let mut buf = Vec::new();
626 ZultiLines::write_from_geometry(&mut buf, &multi_line_strict_inside).unwrap();
627 let multi_line_strict_inside = ZultiLines::from_bytes(&buf);
628
629 let mut buf = Vec::new();
630 ZultiLines::write_from_geometry(&mut buf, &multi_line_outside).unwrap();
631 let multi_line_outside = ZultiLines::from_bytes(&buf);
632
633 let mut buf = Vec::new();
634 ZultiLines::write_from_geometry(&mut buf, &multi_line_inside).unwrap();
635 let multi_line_inside = ZultiLines::from_bytes(&buf);
636
637 let mut buf = Vec::new();
638 ZultiPolygons::write_from_geometry(&mut buf, &multi_polygons_inside).unwrap();
639 let multi_polygons_inside = ZultiPolygons::from_bytes(&buf);
640 let mut buf = Vec::new();
641 ZultiPolygons::write_from_geometry(&mut buf, &multi_polygons_outside).unwrap();
642 let multi_polygons_outside = ZultiPolygons::from_bytes(&buf);
643 let mut buf = Vec::new();
644 ZultiPolygons::write_from_geometry(&mut buf, &multi_polygons_intersect).unwrap();
645 let multi_polygons_intersect = ZultiPolygons::from_bytes(&buf);
646 let mut buf = Vec::new();
647 ZultiPolygons::write_from_geometry(&mut buf, &multi_polygons_in_and_out).unwrap();
648 let multi_polygons_in_and_out = ZultiPolygons::from_bytes(&buf);
649 let mut buf = Vec::new();
650 ZultiPolygons::write_from_geometry(&mut buf, &multi_polygons_all).unwrap();
651 let multi_polygons_all = ZultiPolygons::from_bytes(&buf);
652
653 assert_compact_debug_snapshot!(multi_line_strict_inside.all_relation(&multi_polygons_inside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(false), disjoint: Some(false) }");
654 assert_compact_debug_snapshot!(multi_line_strict_inside.all_relation(&multi_polygons_outside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
655 assert_compact_debug_snapshot!(multi_line_strict_inside.all_relation(&multi_polygons_intersect), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }");
656 assert_compact_debug_snapshot!(multi_line_strict_inside.all_relation(&multi_polygons_in_and_out), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(false), disjoint: Some(false) }");
657 assert_compact_debug_snapshot!(multi_line_strict_inside.all_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(true), disjoint: Some(false) }");
658 assert_compact_debug_snapshot!(multi_line_strict_inside.any_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
659
660 assert_compact_debug_snapshot!(multi_line_outside.all_relation(&multi_polygons_inside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
661 assert_compact_debug_snapshot!(multi_line_outside.all_relation(&multi_polygons_outside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
662 assert_compact_debug_snapshot!(multi_line_outside.all_relation(&multi_polygons_intersect), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
663 assert_compact_debug_snapshot!(multi_line_outside.all_relation(&multi_polygons_in_and_out), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
664 assert_compact_debug_snapshot!(multi_line_outside.all_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
665 assert_compact_debug_snapshot!(multi_line_outside.any_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
666
667 assert_compact_debug_snapshot!(multi_line_inside.all_relation(&multi_polygons_inside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
668 assert_compact_debug_snapshot!(multi_line_inside.all_relation(&multi_polygons_outside), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
669 assert_compact_debug_snapshot!(multi_line_inside.all_relation(&multi_polygons_intersect), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }");
670 assert_compact_debug_snapshot!(multi_line_inside.all_relation(&multi_polygons_in_and_out), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
671 assert_compact_debug_snapshot!(multi_line_inside.all_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }");
672 assert_compact_debug_snapshot!(multi_line_inside.any_relation(&multi_polygons_all), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
673 }
674}