1use crate::error::Result;
40use oxigdal_core::vector::{Coordinate, Point, Polygon};
41
42pub fn contains<T: ContainsPredicate>(a: &T, b: &T) -> Result<bool> {
61 a.contains(b)
62}
63
64pub fn within<T: ContainsPredicate>(a: &T, b: &T) -> Result<bool> {
79 b.contains(a)
80}
81
82pub fn intersects<T: IntersectsPredicate>(a: &T, b: &T) -> Result<bool> {
97 a.intersects(b)
98}
99
100pub fn disjoint<T: IntersectsPredicate>(a: &T, b: &T) -> Result<bool> {
115 Ok(!a.intersects(b)?)
116}
117
118pub fn touches<T: TouchesPredicate>(a: &T, b: &T) -> Result<bool> {
133 a.touches(b)
134}
135
136pub fn overlaps<T: OverlapsPredicate>(a: &T, b: &T) -> Result<bool> {
156 a.overlaps(b)
157}
158
159pub fn crosses<T: CrossesPredicate>(a: &T, b: &T) -> Result<bool> {
178 a.crosses(b)
179}
180
181pub trait ContainsPredicate {
183 fn contains(&self, other: &Self) -> Result<bool>;
185}
186
187pub trait IntersectsPredicate {
189 fn intersects(&self, other: &Self) -> Result<bool>;
191}
192
193pub trait TouchesPredicate {
195 fn touches(&self, other: &Self) -> Result<bool>;
197}
198
199pub trait OverlapsPredicate {
201 fn overlaps(&self, other: &Self) -> Result<bool>;
203}
204
205pub trait CrossesPredicate {
207 fn crosses(&self, other: &Self) -> Result<bool>;
209}
210
211impl ContainsPredicate for Point {
213 fn contains(&self, other: &Self) -> Result<bool> {
214 Ok((self.coord.x - other.coord.x).abs() < f64::EPSILON
216 && (self.coord.y - other.coord.y).abs() < f64::EPSILON)
217 }
218}
219
220impl ContainsPredicate for Polygon {
222 fn contains(&self, other: &Self) -> Result<bool> {
223 for coord in &other.exterior.coords {
225 if !point_in_polygon_or_boundary(coord, self) {
226 return Ok(false);
227 }
228 }
229
230 let mut has_interior_point = false;
232 for coord in &other.exterior.coords {
233 if point_strictly_inside_polygon(coord, self) {
234 has_interior_point = true;
235 break;
236 }
237 }
238
239 Ok(has_interior_point)
240 }
241}
242
243impl IntersectsPredicate for Point {
245 fn intersects(&self, other: &Self) -> Result<bool> {
246 self.contains(other)
247 }
248}
249
250impl IntersectsPredicate for Polygon {
252 fn intersects(&self, other: &Self) -> Result<bool> {
253 for coord in &other.exterior.coords {
255 if point_in_polygon_or_boundary(coord, self) {
256 return Ok(true);
257 }
258 }
259
260 for coord in &self.exterior.coords {
261 if point_in_polygon_or_boundary(coord, other) {
262 return Ok(true);
263 }
264 }
265
266 Ok(rings_intersect(
268 &self.exterior.coords,
269 &other.exterior.coords,
270 ))
271 }
272}
273
274impl TouchesPredicate for Polygon {
276 fn touches(&self, other: &Self) -> Result<bool> {
277 let mut has_boundary_contact = false;
278 let mut has_interior_contact = false;
279
280 for coord in &other.exterior.coords {
282 if point_on_polygon_boundary(coord, self) {
283 has_boundary_contact = true;
284 } else if point_strictly_inside_polygon(coord, self) {
285 has_interior_contact = true;
286 }
287 }
288
289 for coord in &self.exterior.coords {
291 if point_strictly_inside_polygon(coord, other) {
292 has_interior_contact = true;
293 }
294 }
295
296 Ok(has_boundary_contact && !has_interior_contact)
297 }
298}
299
300impl OverlapsPredicate for Point {
302 fn overlaps(&self, _other: &Self) -> Result<bool> {
303 Ok(false)
305 }
306}
307
308impl OverlapsPredicate for Polygon {
310 fn overlaps(&self, other: &Self) -> Result<bool> {
311 if !self.intersects(other)? {
318 return Ok(false);
319 }
320
321 if self.contains(other)? || other.contains(self)? {
323 return Ok(false);
324 }
325
326 Ok(true)
329 }
330}
331
332impl CrossesPredicate for Point {
334 fn crosses(&self, _other: &Self) -> Result<bool> {
335 Ok(false)
337 }
338}
339
340impl CrossesPredicate for Polygon {
342 fn crosses(&self, _other: &Self) -> Result<bool> {
343 Ok(false)
347 }
348}
349
350pub fn point_in_polygon_or_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
352 point_in_polygon_boundary(point, polygon) || point_on_polygon_boundary(point, polygon)
353}
354
355pub fn point_strictly_inside_polygon(point: &Coordinate, polygon: &Polygon) -> bool {
357 point_in_polygon_boundary(point, polygon) && !point_on_polygon_boundary(point, polygon)
358}
359
360pub fn point_on_polygon_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
362 point_on_ring(&polygon.exterior.coords, point)
363 || polygon
364 .interiors
365 .iter()
366 .any(|hole| point_on_ring(&hole.coords, point))
367}
368
369fn point_on_ring(ring: &[Coordinate], point: &Coordinate) -> bool {
371 for i in 0..ring.len().saturating_sub(1) {
372 if point_on_segment(point, &ring[i], &ring[i + 1]) {
373 return true;
374 }
375 }
376 false
377}
378
379fn point_on_segment(point: &Coordinate, seg_start: &Coordinate, seg_end: &Coordinate) -> bool {
381 let cross = (seg_end.y - seg_start.y) * (point.x - seg_start.x)
383 - (seg_end.x - seg_start.x) * (point.y - seg_start.y);
384
385 if cross.abs() > f64::EPSILON {
386 return false;
387 }
388
389 let dot = (point.x - seg_start.x) * (seg_end.x - seg_start.x)
391 + (point.y - seg_start.y) * (seg_end.y - seg_start.y);
392
393 let len_sq = (seg_end.x - seg_start.x).powi(2) + (seg_end.y - seg_start.y).powi(2);
394
395 if dot < -f64::EPSILON || dot > len_sq + f64::EPSILON {
396 return false;
397 }
398
399 true
400}
401
402fn point_in_polygon_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
404 let mut inside = ray_casting_test(point, &polygon.exterior.coords);
405
406 for hole in &polygon.interiors {
408 if ray_casting_test(point, &hole.coords) {
409 inside = !inside;
410 }
411 }
412
413 inside
414}
415
416fn ray_casting_test(point: &Coordinate, ring: &[Coordinate]) -> bool {
418 let mut inside = false;
419 let n = ring.len();
420
421 let mut j = n - 1;
422 for i in 0..n {
423 let xi = ring[i].x;
424 let yi = ring[i].y;
425 let xj = ring[j].x;
426 let yj = ring[j].y;
427
428 let intersect = ((yi > point.y) != (yj > point.y))
429 && (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
430
431 if intersect {
432 inside = !inside;
433 }
434
435 j = i;
436 }
437
438 inside
439}
440
441#[allow(dead_code)]
445fn winding_number_test(point: &Coordinate, ring: &[Coordinate]) -> bool {
446 let mut winding_number = 0;
447 let n = ring.len();
448
449 for i in 0..n - 1 {
450 let p1 = &ring[i];
451 let p2 = &ring[i + 1];
452
453 if p1.y <= point.y {
454 if p2.y > point.y {
455 if is_left(p1, p2, point) > 0.0 {
457 winding_number += 1;
458 }
459 }
460 } else if p2.y <= point.y {
461 if is_left(p1, p2, point) < 0.0 {
463 winding_number -= 1;
464 }
465 }
466 }
467
468 winding_number != 0
469}
470
471fn is_left(p1: &Coordinate, p2: &Coordinate, point: &Coordinate) -> f64 {
473 (p2.x - p1.x) * (point.y - p1.y) - (point.x - p1.x) * (p2.y - p1.y)
474}
475
476fn rings_intersect(ring1: &[Coordinate], ring2: &[Coordinate]) -> bool {
478 for i in 0..ring1.len().saturating_sub(1) {
479 for j in 0..ring2.len().saturating_sub(1) {
480 if segments_intersect(&ring1[i], &ring1[i + 1], &ring2[j], &ring2[j + 1]) {
481 return true;
482 }
483 }
484 }
485 false
486}
487
488fn segments_intersect(p1: &Coordinate, p2: &Coordinate, p3: &Coordinate, p4: &Coordinate) -> bool {
490 let d1 = direction(p3, p4, p1);
491 let d2 = direction(p3, p4, p2);
492 let d3 = direction(p1, p2, p3);
493 let d4 = direction(p1, p2, p4);
494
495 if ((d1 > 0.0 && d2 < 0.0) || (d1 < 0.0 && d2 > 0.0))
496 && ((d3 > 0.0 && d4 < 0.0) || (d3 < 0.0 && d4 > 0.0))
497 {
498 return true;
499 }
500
501 if d1.abs() < f64::EPSILON && on_segment(p3, p1, p4) {
503 return true;
504 }
505 if d2.abs() < f64::EPSILON && on_segment(p3, p2, p4) {
506 return true;
507 }
508 if d3.abs() < f64::EPSILON && on_segment(p1, p3, p2) {
509 return true;
510 }
511 if d4.abs() < f64::EPSILON && on_segment(p1, p4, p2) {
512 return true;
513 }
514
515 false
516}
517
518fn direction(a: &Coordinate, b: &Coordinate, p: &Coordinate) -> f64 {
520 (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y)
521}
522
523fn on_segment(p: &Coordinate, q: &Coordinate, r: &Coordinate) -> bool {
525 q.x <= p.x.max(r.x) && q.x >= p.x.min(r.x) && q.y <= p.y.max(r.y) && q.y >= p.y.min(r.y)
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531 use crate::error::AlgorithmError;
532 use oxigdal_core::vector::LineString;
533
534 fn create_square() -> Result<Polygon> {
535 let coords = vec![
536 Coordinate::new_2d(0.0, 0.0),
537 Coordinate::new_2d(4.0, 0.0),
538 Coordinate::new_2d(4.0, 4.0),
539 Coordinate::new_2d(0.0, 4.0),
540 Coordinate::new_2d(0.0, 0.0),
541 ];
542 let exterior = LineString::new(coords).map_err(|e| AlgorithmError::Core(e))?;
543 Polygon::new(exterior, vec![]).map_err(|e| AlgorithmError::Core(e))
544 }
545
546 #[test]
547 fn test_point_contains_point() {
548 let p1 = Point::new(1.0, 2.0);
549 let p2 = Point::new(1.0, 2.0);
550 let p3 = Point::new(3.0, 4.0);
551
552 let result1 = p1.contains(&p2);
553 assert!(result1.is_ok());
554 if let Ok(contains) = result1 {
555 assert!(contains);
556 }
557
558 let result2 = p1.contains(&p3);
559 assert!(result2.is_ok());
560 if let Ok(contains) = result2 {
561 assert!(!contains);
562 }
563 }
564
565 #[test]
566 fn test_polygon_contains_point() {
567 let poly = create_square();
568 assert!(poly.is_ok());
569
570 if let Ok(p) = poly {
571 let inside = Coordinate::new_2d(2.0, 2.0);
573 assert!(point_strictly_inside_polygon(&inside, &p));
574
575 let outside = Coordinate::new_2d(5.0, 5.0);
577 assert!(!point_in_polygon_or_boundary(&outside, &p));
578
579 let boundary = Coordinate::new_2d(0.0, 2.0);
581 assert!(point_on_polygon_boundary(&boundary, &p));
582 }
583 }
584
585 #[test]
586 fn test_point_in_polygon_boundary() {
587 let poly = create_square();
588 assert!(poly.is_ok());
589
590 if let Ok(p) = poly {
591 let inside = Coordinate::new_2d(2.0, 2.0);
592 assert!(point_in_polygon_boundary(&inside, &p));
593
594 let outside = Coordinate::new_2d(5.0, 5.0);
595 assert!(!point_in_polygon_boundary(&outside, &p));
596 }
597 }
598
599 #[test]
600 fn test_point_on_segment() {
601 let seg_start = Coordinate::new_2d(0.0, 0.0);
602 let seg_end = Coordinate::new_2d(4.0, 0.0);
603
604 let on = Coordinate::new_2d(2.0, 0.0);
606 assert!(point_on_segment(&on, &seg_start, &seg_end));
607
608 let off = Coordinate::new_2d(2.0, 1.0);
610 assert!(!point_on_segment(&off, &seg_start, &seg_end));
611 }
612
613 #[test]
614 fn test_polygon_intersects_polygon() {
615 let poly1 = create_square();
616 assert!(poly1.is_ok());
617
618 let coords2 = vec![
620 Coordinate::new_2d(2.0, 2.0),
621 Coordinate::new_2d(6.0, 2.0),
622 Coordinate::new_2d(6.0, 6.0),
623 Coordinate::new_2d(2.0, 6.0),
624 Coordinate::new_2d(2.0, 2.0),
625 ];
626 let exterior2 = LineString::new(coords2);
627 assert!(exterior2.is_ok());
628
629 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
630 let poly2 = Polygon::new(ext2, vec![]);
631 assert!(poly2.is_ok());
632
633 if let Ok(p2) = poly2 {
634 let result: crate::error::Result<bool> = intersects(&p1, &p2);
635 assert!(result.is_ok());
636
637 if let Ok(do_intersect) = result {
638 assert!(do_intersect);
639 }
640 }
641 }
642 }
643
644 #[test]
645 fn test_disjoint_polygons() {
646 let poly1 = create_square();
647
648 let coords2 = vec![
650 Coordinate::new_2d(10.0, 10.0),
651 Coordinate::new_2d(14.0, 10.0),
652 Coordinate::new_2d(14.0, 14.0),
653 Coordinate::new_2d(10.0, 14.0),
654 Coordinate::new_2d(10.0, 10.0),
655 ];
656 let exterior2 = LineString::new(coords2);
657
658 assert!(poly1.is_ok() && exterior2.is_ok());
659
660 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
661 let poly2 = Polygon::new(ext2, vec![]);
662 assert!(poly2.is_ok());
663
664 if let Ok(p2) = poly2 {
665 let result: crate::error::Result<bool> = intersects(&p1, &p2);
666 assert!(result.is_ok());
667
668 if let Ok(do_intersect) = result {
669 assert!(!do_intersect);
670 }
671 }
672 }
673 }
674
675 #[test]
676 fn test_segments_intersect() {
677 let p1 = Coordinate::new_2d(0.0, 0.0);
679 let p2 = Coordinate::new_2d(2.0, 2.0);
680 let p3 = Coordinate::new_2d(0.0, 2.0);
681 let p4 = Coordinate::new_2d(2.0, 0.0);
682
683 assert!(segments_intersect(&p1, &p2, &p3, &p4));
684 }
685
686 #[test]
687 fn test_segments_no_intersect() {
688 let p1 = Coordinate::new_2d(0.0, 0.0);
690 let p2 = Coordinate::new_2d(2.0, 0.0);
691 let p3 = Coordinate::new_2d(0.0, 1.0);
692 let p4 = Coordinate::new_2d(2.0, 1.0);
693
694 assert!(!segments_intersect(&p1, &p2, &p3, &p4));
695 }
696
697 #[test]
698 fn test_ray_casting() {
699 let ring = vec![
700 Coordinate::new_2d(0.0, 0.0),
701 Coordinate::new_2d(4.0, 0.0),
702 Coordinate::new_2d(4.0, 4.0),
703 Coordinate::new_2d(0.0, 4.0),
704 Coordinate::new_2d(0.0, 0.0),
705 ];
706
707 let inside = Coordinate::new_2d(2.0, 2.0);
708 assert!(ray_casting_test(&inside, &ring));
709
710 let outside = Coordinate::new_2d(5.0, 5.0);
711 assert!(!ray_casting_test(&outside, &ring));
712 }
713
714 #[test]
715 fn test_winding_number() {
716 let ring = vec![
717 Coordinate::new_2d(0.0, 0.0),
718 Coordinate::new_2d(4.0, 0.0),
719 Coordinate::new_2d(4.0, 4.0),
720 Coordinate::new_2d(0.0, 4.0),
721 Coordinate::new_2d(0.0, 0.0),
722 ];
723
724 let inside = Coordinate::new_2d(2.0, 2.0);
725 assert!(winding_number_test(&inside, &ring));
726
727 let outside = Coordinate::new_2d(5.0, 5.0);
728 assert!(!winding_number_test(&outside, &ring));
729 }
730
731 #[test]
732 fn test_overlaps_polygons_partial() {
733 let poly1 = create_square();
735 assert!(poly1.is_ok());
736
737 let coords2 = vec![
738 Coordinate::new_2d(2.0, 2.0),
739 Coordinate::new_2d(6.0, 2.0),
740 Coordinate::new_2d(6.0, 6.0),
741 Coordinate::new_2d(2.0, 6.0),
742 Coordinate::new_2d(2.0, 2.0),
743 ];
744 let exterior2 = LineString::new(coords2);
745 assert!(exterior2.is_ok());
746
747 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
748 let poly2 = Polygon::new(ext2, vec![]);
749 assert!(poly2.is_ok());
750
751 if let Ok(p2) = poly2 {
752 let result = overlaps(&p1, &p2);
753 assert!(result.is_ok());
754 if let Ok(do_overlap) = result {
755 assert!(do_overlap, "Partially overlapping polygons should overlap");
756 }
757 }
758 }
759 }
760
761 #[test]
762 fn test_overlaps_polygons_disjoint() {
763 let poly1 = create_square();
765 assert!(poly1.is_ok());
766
767 let coords2 = vec![
768 Coordinate::new_2d(10.0, 10.0),
769 Coordinate::new_2d(14.0, 10.0),
770 Coordinate::new_2d(14.0, 14.0),
771 Coordinate::new_2d(10.0, 14.0),
772 Coordinate::new_2d(10.0, 10.0),
773 ];
774 let exterior2 = LineString::new(coords2);
775 assert!(exterior2.is_ok());
776
777 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
778 let poly2 = Polygon::new(ext2, vec![]);
779 assert!(poly2.is_ok());
780
781 if let Ok(p2) = poly2 {
782 let result = overlaps(&p1, &p2);
783 assert!(result.is_ok());
784 if let Ok(do_overlap) = result {
785 assert!(!do_overlap, "Disjoint polygons should not overlap");
786 }
787 }
788 }
789 }
790
791 #[test]
792 fn test_overlaps_polygons_contained() {
793 let poly1 = create_square();
795 assert!(poly1.is_ok());
796
797 let coords2 = vec![
798 Coordinate::new_2d(1.0, 1.0),
799 Coordinate::new_2d(3.0, 1.0),
800 Coordinate::new_2d(3.0, 3.0),
801 Coordinate::new_2d(1.0, 3.0),
802 Coordinate::new_2d(1.0, 1.0),
803 ];
804 let exterior2 = LineString::new(coords2);
805 assert!(exterior2.is_ok());
806
807 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
808 let poly2 = Polygon::new(ext2, vec![]);
809 assert!(poly2.is_ok());
810
811 if let Ok(p2) = poly2 {
812 let result = overlaps(&p1, &p2);
813 assert!(result.is_ok());
814 if let Ok(do_overlap) = result {
815 assert!(!do_overlap, "Contained polygons should not overlap");
816 }
817 }
818 }
819 }
820
821 #[test]
822 fn test_overlaps_points() {
823 let p1 = Point::new(1.0, 2.0);
824 let p2 = Point::new(1.0, 2.0);
825
826 let result = overlaps(&p1, &p2);
827 assert!(result.is_ok());
828 if let Ok(do_overlap) = result {
829 assert!(!do_overlap, "Points should not overlap");
830 }
831 }
832
833 #[test]
834 fn test_crosses_polygons() {
835 let poly1 = create_square();
838 assert!(poly1.is_ok());
839
840 let coords2 = vec![
841 Coordinate::new_2d(-1.0, 2.0),
842 Coordinate::new_2d(5.0, 2.0),
843 Coordinate::new_2d(5.0, 3.0),
844 Coordinate::new_2d(-1.0, 3.0),
845 Coordinate::new_2d(-1.0, 2.0),
846 ];
847 let exterior2 = LineString::new(coords2);
848 assert!(exterior2.is_ok());
849
850 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
851 let poly2 = Polygon::new(ext2, vec![]);
852 assert!(poly2.is_ok());
853
854 if let Ok(p2) = poly2 {
855 let result = crosses(&p1, &p2);
856 assert!(result.is_ok());
857 if let Ok(do_cross) = result {
858 assert!(
859 !do_cross,
860 "Polygon/Polygon crosses is undefined per OGC, must return false"
861 );
862 }
863 }
864 }
865 }
866
867 #[test]
868 fn test_crosses_polygons_disjoint() {
869 let poly1 = create_square();
871 assert!(poly1.is_ok());
872
873 let coords2 = vec![
874 Coordinate::new_2d(10.0, 10.0),
875 Coordinate::new_2d(14.0, 10.0),
876 Coordinate::new_2d(14.0, 14.0),
877 Coordinate::new_2d(10.0, 14.0),
878 Coordinate::new_2d(10.0, 10.0),
879 ];
880 let exterior2 = LineString::new(coords2);
881 assert!(exterior2.is_ok());
882
883 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
884 let poly2 = Polygon::new(ext2, vec![]);
885 assert!(poly2.is_ok());
886
887 if let Ok(p2) = poly2 {
888 let result = crosses(&p1, &p2);
889 assert!(result.is_ok());
890 if let Ok(do_cross) = result {
891 assert!(!do_cross, "Disjoint polygons should not cross");
892 }
893 }
894 }
895 }
896
897 #[test]
898 fn test_crosses_points() {
899 let p1 = Point::new(1.0, 2.0);
900 let p2 = Point::new(3.0, 4.0);
901
902 let result = crosses(&p1, &p2);
903 assert!(result.is_ok());
904 if let Ok(do_cross) = result {
905 assert!(!do_cross, "Points should not cross");
906 }
907 }
908
909 #[test]
910 fn test_touches_adjacent_polygons() {
911 let poly1 = create_square();
913 assert!(poly1.is_ok());
914
915 let coords2 = vec![
916 Coordinate::new_2d(4.0, 0.0),
917 Coordinate::new_2d(8.0, 0.0),
918 Coordinate::new_2d(8.0, 4.0),
919 Coordinate::new_2d(4.0, 4.0),
920 Coordinate::new_2d(4.0, 0.0),
921 ];
922 let exterior2 = LineString::new(coords2);
923 assert!(exterior2.is_ok());
924
925 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
926 let poly2 = Polygon::new(ext2, vec![]);
927 assert!(poly2.is_ok());
928
929 if let Ok(p2) = poly2 {
930 let result = touches(&p1, &p2);
931 assert!(result.is_ok());
932 if let Ok(do_touch) = result {
933 assert!(do_touch, "Adjacent polygons should touch");
934 }
935 }
936 }
937 }
938
939 #[test]
940 fn test_within_polygon() {
941 let poly1 = create_square();
943 assert!(poly1.is_ok());
944
945 let coords2 = vec![
946 Coordinate::new_2d(1.0, 1.0),
947 Coordinate::new_2d(3.0, 1.0),
948 Coordinate::new_2d(3.0, 3.0),
949 Coordinate::new_2d(1.0, 3.0),
950 Coordinate::new_2d(1.0, 1.0),
951 ];
952 let exterior2 = LineString::new(coords2);
953 assert!(exterior2.is_ok());
954
955 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
956 let poly2 = Polygon::new(ext2, vec![]);
957 assert!(poly2.is_ok());
958
959 if let Ok(p2) = poly2 {
960 let result = within(&p2, &p1);
961 assert!(result.is_ok());
962 if let Ok(is_within) = result {
963 assert!(is_within, "Small polygon should be within larger polygon");
964 }
965 }
966 }
967 }
968
969 #[test]
970 fn test_contains_polygon() {
971 let poly1 = create_square();
973 assert!(poly1.is_ok());
974
975 let coords2 = vec![
976 Coordinate::new_2d(1.0, 1.0),
977 Coordinate::new_2d(3.0, 1.0),
978 Coordinate::new_2d(3.0, 3.0),
979 Coordinate::new_2d(1.0, 3.0),
980 Coordinate::new_2d(1.0, 1.0),
981 ];
982 let exterior2 = LineString::new(coords2);
983 assert!(exterior2.is_ok());
984
985 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
986 let poly2 = Polygon::new(ext2, vec![]);
987 assert!(poly2.is_ok());
988
989 if let Ok(p2) = poly2 {
990 let result = contains(&p1, &p2);
991 assert!(result.is_ok());
992 if let Ok(does_contain) = result {
993 assert!(does_contain, "Large polygon should contain smaller polygon");
994 }
995 }
996 }
997 }
998
999 #[test]
1000 fn test_disjoint_polygons_separated() {
1001 let poly1 = create_square();
1002 assert!(poly1.is_ok());
1003
1004 let coords2 = vec![
1005 Coordinate::new_2d(10.0, 10.0),
1006 Coordinate::new_2d(14.0, 10.0),
1007 Coordinate::new_2d(14.0, 14.0),
1008 Coordinate::new_2d(10.0, 14.0),
1009 Coordinate::new_2d(10.0, 10.0),
1010 ];
1011 let exterior2 = LineString::new(coords2);
1012 assert!(exterior2.is_ok());
1013
1014 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
1015 let poly2 = Polygon::new(ext2, vec![]);
1016 assert!(poly2.is_ok());
1017
1018 if let Ok(p2) = poly2 {
1019 let result = disjoint(&p1, &p2);
1020 assert!(result.is_ok());
1021 if let Ok(are_disjoint) = result {
1022 assert!(are_disjoint, "Separated polygons should be disjoint");
1023 }
1024 }
1025 }
1026 }
1027}