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 if !self.intersects(other)? {
353 return Ok(false);
354 }
355
356 if self.contains(other)? || other.contains(self)? {
358 return Ok(false);
359 }
360
361 let mut other_some_inside = false;
363 let mut other_some_outside = false;
364
365 for coord in &other.exterior.coords {
366 if point_in_polygon_or_boundary(coord, self) {
367 other_some_inside = true;
368 } else {
369 other_some_outside = true;
370 }
371 }
372
373 let mut self_some_inside = false;
375 let mut self_some_outside = false;
376
377 for coord in &self.exterior.coords {
378 if point_in_polygon_or_boundary(coord, other) {
379 self_some_inside = true;
380 } else {
381 self_some_outside = true;
382 }
383 }
384
385 if (other_some_inside && other_some_outside) || (self_some_inside && self_some_outside) {
389 Ok(true)
390 } else if !other_some_inside && !self_some_inside {
391 Ok(true)
394 } else {
395 Ok(false)
396 }
397 }
398}
399
400pub fn point_in_polygon_or_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
402 point_in_polygon_boundary(point, polygon) || point_on_polygon_boundary(point, polygon)
403}
404
405pub fn point_strictly_inside_polygon(point: &Coordinate, polygon: &Polygon) -> bool {
407 point_in_polygon_boundary(point, polygon) && !point_on_polygon_boundary(point, polygon)
408}
409
410pub fn point_on_polygon_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
412 point_on_ring(&polygon.exterior.coords, point)
413 || polygon
414 .interiors
415 .iter()
416 .any(|hole| point_on_ring(&hole.coords, point))
417}
418
419fn point_on_ring(ring: &[Coordinate], point: &Coordinate) -> bool {
421 for i in 0..ring.len().saturating_sub(1) {
422 if point_on_segment(point, &ring[i], &ring[i + 1]) {
423 return true;
424 }
425 }
426 false
427}
428
429fn point_on_segment(point: &Coordinate, seg_start: &Coordinate, seg_end: &Coordinate) -> bool {
431 let cross = (seg_end.y - seg_start.y) * (point.x - seg_start.x)
433 - (seg_end.x - seg_start.x) * (point.y - seg_start.y);
434
435 if cross.abs() > f64::EPSILON {
436 return false;
437 }
438
439 let dot = (point.x - seg_start.x) * (seg_end.x - seg_start.x)
441 + (point.y - seg_start.y) * (seg_end.y - seg_start.y);
442
443 let len_sq = (seg_end.x - seg_start.x).powi(2) + (seg_end.y - seg_start.y).powi(2);
444
445 if dot < -f64::EPSILON || dot > len_sq + f64::EPSILON {
446 return false;
447 }
448
449 true
450}
451
452fn point_in_polygon_boundary(point: &Coordinate, polygon: &Polygon) -> bool {
454 let mut inside = ray_casting_test(point, &polygon.exterior.coords);
455
456 for hole in &polygon.interiors {
458 if ray_casting_test(point, &hole.coords) {
459 inside = !inside;
460 }
461 }
462
463 inside
464}
465
466fn ray_casting_test(point: &Coordinate, ring: &[Coordinate]) -> bool {
468 let mut inside = false;
469 let n = ring.len();
470
471 let mut j = n - 1;
472 for i in 0..n {
473 let xi = ring[i].x;
474 let yi = ring[i].y;
475 let xj = ring[j].x;
476 let yj = ring[j].y;
477
478 let intersect = ((yi > point.y) != (yj > point.y))
479 && (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
480
481 if intersect {
482 inside = !inside;
483 }
484
485 j = i;
486 }
487
488 inside
489}
490
491#[allow(dead_code)]
495fn winding_number_test(point: &Coordinate, ring: &[Coordinate]) -> bool {
496 let mut winding_number = 0;
497 let n = ring.len();
498
499 for i in 0..n - 1 {
500 let p1 = &ring[i];
501 let p2 = &ring[i + 1];
502
503 if p1.y <= point.y {
504 if p2.y > point.y {
505 if is_left(p1, p2, point) > 0.0 {
507 winding_number += 1;
508 }
509 }
510 } else if p2.y <= point.y {
511 if is_left(p1, p2, point) < 0.0 {
513 winding_number -= 1;
514 }
515 }
516 }
517
518 winding_number != 0
519}
520
521fn is_left(p1: &Coordinate, p2: &Coordinate, point: &Coordinate) -> f64 {
523 (p2.x - p1.x) * (point.y - p1.y) - (point.x - p1.x) * (p2.y - p1.y)
524}
525
526fn rings_intersect(ring1: &[Coordinate], ring2: &[Coordinate]) -> bool {
528 for i in 0..ring1.len().saturating_sub(1) {
529 for j in 0..ring2.len().saturating_sub(1) {
530 if segments_intersect(&ring1[i], &ring1[i + 1], &ring2[j], &ring2[j + 1]) {
531 return true;
532 }
533 }
534 }
535 false
536}
537
538fn segments_intersect(p1: &Coordinate, p2: &Coordinate, p3: &Coordinate, p4: &Coordinate) -> bool {
540 let d1 = direction(p3, p4, p1);
541 let d2 = direction(p3, p4, p2);
542 let d3 = direction(p1, p2, p3);
543 let d4 = direction(p1, p2, p4);
544
545 if ((d1 > 0.0 && d2 < 0.0) || (d1 < 0.0 && d2 > 0.0))
546 && ((d3 > 0.0 && d4 < 0.0) || (d3 < 0.0 && d4 > 0.0))
547 {
548 return true;
549 }
550
551 if d1.abs() < f64::EPSILON && on_segment(p3, p1, p4) {
553 return true;
554 }
555 if d2.abs() < f64::EPSILON && on_segment(p3, p2, p4) {
556 return true;
557 }
558 if d3.abs() < f64::EPSILON && on_segment(p1, p3, p2) {
559 return true;
560 }
561 if d4.abs() < f64::EPSILON && on_segment(p1, p4, p2) {
562 return true;
563 }
564
565 false
566}
567
568fn direction(a: &Coordinate, b: &Coordinate, p: &Coordinate) -> f64 {
570 (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y)
571}
572
573fn on_segment(p: &Coordinate, q: &Coordinate, r: &Coordinate) -> bool {
575 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)
576}
577
578#[cfg(test)]
579mod tests {
580 use super::*;
581 use crate::error::AlgorithmError;
582 use oxigdal_core::vector::LineString;
583
584 fn create_square() -> Result<Polygon> {
585 let coords = vec![
586 Coordinate::new_2d(0.0, 0.0),
587 Coordinate::new_2d(4.0, 0.0),
588 Coordinate::new_2d(4.0, 4.0),
589 Coordinate::new_2d(0.0, 4.0),
590 Coordinate::new_2d(0.0, 0.0),
591 ];
592 let exterior = LineString::new(coords).map_err(|e| AlgorithmError::Core(e))?;
593 Polygon::new(exterior, vec![]).map_err(|e| AlgorithmError::Core(e))
594 }
595
596 #[test]
597 fn test_point_contains_point() {
598 let p1 = Point::new(1.0, 2.0);
599 let p2 = Point::new(1.0, 2.0);
600 let p3 = Point::new(3.0, 4.0);
601
602 let result1 = p1.contains(&p2);
603 assert!(result1.is_ok());
604 if let Ok(contains) = result1 {
605 assert!(contains);
606 }
607
608 let result2 = p1.contains(&p3);
609 assert!(result2.is_ok());
610 if let Ok(contains) = result2 {
611 assert!(!contains);
612 }
613 }
614
615 #[test]
616 fn test_polygon_contains_point() {
617 let poly = create_square();
618 assert!(poly.is_ok());
619
620 if let Ok(p) = poly {
621 let inside = Coordinate::new_2d(2.0, 2.0);
623 assert!(point_strictly_inside_polygon(&inside, &p));
624
625 let outside = Coordinate::new_2d(5.0, 5.0);
627 assert!(!point_in_polygon_or_boundary(&outside, &p));
628
629 let boundary = Coordinate::new_2d(0.0, 2.0);
631 assert!(point_on_polygon_boundary(&boundary, &p));
632 }
633 }
634
635 #[test]
636 fn test_point_in_polygon_boundary() {
637 let poly = create_square();
638 assert!(poly.is_ok());
639
640 if let Ok(p) = poly {
641 let inside = Coordinate::new_2d(2.0, 2.0);
642 assert!(point_in_polygon_boundary(&inside, &p));
643
644 let outside = Coordinate::new_2d(5.0, 5.0);
645 assert!(!point_in_polygon_boundary(&outside, &p));
646 }
647 }
648
649 #[test]
650 fn test_point_on_segment() {
651 let seg_start = Coordinate::new_2d(0.0, 0.0);
652 let seg_end = Coordinate::new_2d(4.0, 0.0);
653
654 let on = Coordinate::new_2d(2.0, 0.0);
656 assert!(point_on_segment(&on, &seg_start, &seg_end));
657
658 let off = Coordinate::new_2d(2.0, 1.0);
660 assert!(!point_on_segment(&off, &seg_start, &seg_end));
661 }
662
663 #[test]
664 fn test_polygon_intersects_polygon() {
665 let poly1 = create_square();
666 assert!(poly1.is_ok());
667
668 let coords2 = vec![
670 Coordinate::new_2d(2.0, 2.0),
671 Coordinate::new_2d(6.0, 2.0),
672 Coordinate::new_2d(6.0, 6.0),
673 Coordinate::new_2d(2.0, 6.0),
674 Coordinate::new_2d(2.0, 2.0),
675 ];
676 let exterior2 = LineString::new(coords2);
677 assert!(exterior2.is_ok());
678
679 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
680 let poly2 = Polygon::new(ext2, vec![]);
681 assert!(poly2.is_ok());
682
683 if let Ok(p2) = poly2 {
684 let result: crate::error::Result<bool> = intersects(&p1, &p2);
685 assert!(result.is_ok());
686
687 if let Ok(do_intersect) = result {
688 assert!(do_intersect);
689 }
690 }
691 }
692 }
693
694 #[test]
695 fn test_disjoint_polygons() {
696 let poly1 = create_square();
697
698 let coords2 = vec![
700 Coordinate::new_2d(10.0, 10.0),
701 Coordinate::new_2d(14.0, 10.0),
702 Coordinate::new_2d(14.0, 14.0),
703 Coordinate::new_2d(10.0, 14.0),
704 Coordinate::new_2d(10.0, 10.0),
705 ];
706 let exterior2 = LineString::new(coords2);
707
708 assert!(poly1.is_ok() && exterior2.is_ok());
709
710 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
711 let poly2 = Polygon::new(ext2, vec![]);
712 assert!(poly2.is_ok());
713
714 if let Ok(p2) = poly2 {
715 let result: crate::error::Result<bool> = intersects(&p1, &p2);
716 assert!(result.is_ok());
717
718 if let Ok(do_intersect) = result {
719 assert!(!do_intersect);
720 }
721 }
722 }
723 }
724
725 #[test]
726 fn test_segments_intersect() {
727 let p1 = Coordinate::new_2d(0.0, 0.0);
729 let p2 = Coordinate::new_2d(2.0, 2.0);
730 let p3 = Coordinate::new_2d(0.0, 2.0);
731 let p4 = Coordinate::new_2d(2.0, 0.0);
732
733 assert!(segments_intersect(&p1, &p2, &p3, &p4));
734 }
735
736 #[test]
737 fn test_segments_no_intersect() {
738 let p1 = Coordinate::new_2d(0.0, 0.0);
740 let p2 = Coordinate::new_2d(2.0, 0.0);
741 let p3 = Coordinate::new_2d(0.0, 1.0);
742 let p4 = Coordinate::new_2d(2.0, 1.0);
743
744 assert!(!segments_intersect(&p1, &p2, &p3, &p4));
745 }
746
747 #[test]
748 fn test_ray_casting() {
749 let ring = vec![
750 Coordinate::new_2d(0.0, 0.0),
751 Coordinate::new_2d(4.0, 0.0),
752 Coordinate::new_2d(4.0, 4.0),
753 Coordinate::new_2d(0.0, 4.0),
754 Coordinate::new_2d(0.0, 0.0),
755 ];
756
757 let inside = Coordinate::new_2d(2.0, 2.0);
758 assert!(ray_casting_test(&inside, &ring));
759
760 let outside = Coordinate::new_2d(5.0, 5.0);
761 assert!(!ray_casting_test(&outside, &ring));
762 }
763
764 #[test]
765 fn test_winding_number() {
766 let ring = vec![
767 Coordinate::new_2d(0.0, 0.0),
768 Coordinate::new_2d(4.0, 0.0),
769 Coordinate::new_2d(4.0, 4.0),
770 Coordinate::new_2d(0.0, 4.0),
771 Coordinate::new_2d(0.0, 0.0),
772 ];
773
774 let inside = Coordinate::new_2d(2.0, 2.0);
775 assert!(winding_number_test(&inside, &ring));
776
777 let outside = Coordinate::new_2d(5.0, 5.0);
778 assert!(!winding_number_test(&outside, &ring));
779 }
780
781 #[test]
782 fn test_overlaps_polygons_partial() {
783 let poly1 = create_square();
785 assert!(poly1.is_ok());
786
787 let coords2 = vec![
788 Coordinate::new_2d(2.0, 2.0),
789 Coordinate::new_2d(6.0, 2.0),
790 Coordinate::new_2d(6.0, 6.0),
791 Coordinate::new_2d(2.0, 6.0),
792 Coordinate::new_2d(2.0, 2.0),
793 ];
794 let exterior2 = LineString::new(coords2);
795 assert!(exterior2.is_ok());
796
797 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
798 let poly2 = Polygon::new(ext2, vec![]);
799 assert!(poly2.is_ok());
800
801 if let Ok(p2) = poly2 {
802 let result = overlaps(&p1, &p2);
803 assert!(result.is_ok());
804 if let Ok(do_overlap) = result {
805 assert!(do_overlap, "Partially overlapping polygons should overlap");
806 }
807 }
808 }
809 }
810
811 #[test]
812 fn test_overlaps_polygons_disjoint() {
813 let poly1 = create_square();
815 assert!(poly1.is_ok());
816
817 let coords2 = vec![
818 Coordinate::new_2d(10.0, 10.0),
819 Coordinate::new_2d(14.0, 10.0),
820 Coordinate::new_2d(14.0, 14.0),
821 Coordinate::new_2d(10.0, 14.0),
822 Coordinate::new_2d(10.0, 10.0),
823 ];
824 let exterior2 = LineString::new(coords2);
825 assert!(exterior2.is_ok());
826
827 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
828 let poly2 = Polygon::new(ext2, vec![]);
829 assert!(poly2.is_ok());
830
831 if let Ok(p2) = poly2 {
832 let result = overlaps(&p1, &p2);
833 assert!(result.is_ok());
834 if let Ok(do_overlap) = result {
835 assert!(!do_overlap, "Disjoint polygons should not overlap");
836 }
837 }
838 }
839 }
840
841 #[test]
842 fn test_overlaps_polygons_contained() {
843 let poly1 = create_square();
845 assert!(poly1.is_ok());
846
847 let coords2 = vec![
848 Coordinate::new_2d(1.0, 1.0),
849 Coordinate::new_2d(3.0, 1.0),
850 Coordinate::new_2d(3.0, 3.0),
851 Coordinate::new_2d(1.0, 3.0),
852 Coordinate::new_2d(1.0, 1.0),
853 ];
854 let exterior2 = LineString::new(coords2);
855 assert!(exterior2.is_ok());
856
857 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
858 let poly2 = Polygon::new(ext2, vec![]);
859 assert!(poly2.is_ok());
860
861 if let Ok(p2) = poly2 {
862 let result = overlaps(&p1, &p2);
863 assert!(result.is_ok());
864 if let Ok(do_overlap) = result {
865 assert!(!do_overlap, "Contained polygons should not overlap");
866 }
867 }
868 }
869 }
870
871 #[test]
872 fn test_overlaps_points() {
873 let p1 = Point::new(1.0, 2.0);
874 let p2 = Point::new(1.0, 2.0);
875
876 let result = overlaps(&p1, &p2);
877 assert!(result.is_ok());
878 if let Ok(do_overlap) = result {
879 assert!(!do_overlap, "Points should not overlap");
880 }
881 }
882
883 #[test]
884 fn test_crosses_polygons() {
885 let poly1 = create_square();
887 assert!(poly1.is_ok());
888
889 let coords2 = vec![
890 Coordinate::new_2d(-1.0, 2.0),
891 Coordinate::new_2d(5.0, 2.0),
892 Coordinate::new_2d(5.0, 3.0),
893 Coordinate::new_2d(-1.0, 3.0),
894 Coordinate::new_2d(-1.0, 2.0),
895 ];
896 let exterior2 = LineString::new(coords2);
897 assert!(exterior2.is_ok());
898
899 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
900 let poly2 = Polygon::new(ext2, vec![]);
901 assert!(poly2.is_ok());
902
903 if let Ok(p2) = poly2 {
904 let result = crosses(&p1, &p2);
905 assert!(result.is_ok());
906 if let Ok(do_cross) = result {
907 assert!(do_cross, "Polygon crossing through another should cross");
908 }
909 }
910 }
911 }
912
913 #[test]
914 fn test_crosses_polygons_disjoint() {
915 let poly1 = create_square();
917 assert!(poly1.is_ok());
918
919 let coords2 = vec![
920 Coordinate::new_2d(10.0, 10.0),
921 Coordinate::new_2d(14.0, 10.0),
922 Coordinate::new_2d(14.0, 14.0),
923 Coordinate::new_2d(10.0, 14.0),
924 Coordinate::new_2d(10.0, 10.0),
925 ];
926 let exterior2 = LineString::new(coords2);
927 assert!(exterior2.is_ok());
928
929 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
930 let poly2 = Polygon::new(ext2, vec![]);
931 assert!(poly2.is_ok());
932
933 if let Ok(p2) = poly2 {
934 let result = crosses(&p1, &p2);
935 assert!(result.is_ok());
936 if let Ok(do_cross) = result {
937 assert!(!do_cross, "Disjoint polygons should not cross");
938 }
939 }
940 }
941 }
942
943 #[test]
944 fn test_crosses_points() {
945 let p1 = Point::new(1.0, 2.0);
946 let p2 = Point::new(3.0, 4.0);
947
948 let result = crosses(&p1, &p2);
949 assert!(result.is_ok());
950 if let Ok(do_cross) = result {
951 assert!(!do_cross, "Points should not cross");
952 }
953 }
954
955 #[test]
956 fn test_touches_adjacent_polygons() {
957 let poly1 = create_square();
959 assert!(poly1.is_ok());
960
961 let coords2 = vec![
962 Coordinate::new_2d(4.0, 0.0),
963 Coordinate::new_2d(8.0, 0.0),
964 Coordinate::new_2d(8.0, 4.0),
965 Coordinate::new_2d(4.0, 4.0),
966 Coordinate::new_2d(4.0, 0.0),
967 ];
968 let exterior2 = LineString::new(coords2);
969 assert!(exterior2.is_ok());
970
971 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
972 let poly2 = Polygon::new(ext2, vec![]);
973 assert!(poly2.is_ok());
974
975 if let Ok(p2) = poly2 {
976 let result = touches(&p1, &p2);
977 assert!(result.is_ok());
978 if let Ok(do_touch) = result {
979 assert!(do_touch, "Adjacent polygons should touch");
980 }
981 }
982 }
983 }
984
985 #[test]
986 fn test_within_polygon() {
987 let poly1 = create_square();
989 assert!(poly1.is_ok());
990
991 let coords2 = vec![
992 Coordinate::new_2d(1.0, 1.0),
993 Coordinate::new_2d(3.0, 1.0),
994 Coordinate::new_2d(3.0, 3.0),
995 Coordinate::new_2d(1.0, 3.0),
996 Coordinate::new_2d(1.0, 1.0),
997 ];
998 let exterior2 = LineString::new(coords2);
999 assert!(exterior2.is_ok());
1000
1001 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
1002 let poly2 = Polygon::new(ext2, vec![]);
1003 assert!(poly2.is_ok());
1004
1005 if let Ok(p2) = poly2 {
1006 let result = within(&p2, &p1);
1007 assert!(result.is_ok());
1008 if let Ok(is_within) = result {
1009 assert!(is_within, "Small polygon should be within larger polygon");
1010 }
1011 }
1012 }
1013 }
1014
1015 #[test]
1016 fn test_contains_polygon() {
1017 let poly1 = create_square();
1019 assert!(poly1.is_ok());
1020
1021 let coords2 = vec![
1022 Coordinate::new_2d(1.0, 1.0),
1023 Coordinate::new_2d(3.0, 1.0),
1024 Coordinate::new_2d(3.0, 3.0),
1025 Coordinate::new_2d(1.0, 3.0),
1026 Coordinate::new_2d(1.0, 1.0),
1027 ];
1028 let exterior2 = LineString::new(coords2);
1029 assert!(exterior2.is_ok());
1030
1031 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
1032 let poly2 = Polygon::new(ext2, vec![]);
1033 assert!(poly2.is_ok());
1034
1035 if let Ok(p2) = poly2 {
1036 let result = contains(&p1, &p2);
1037 assert!(result.is_ok());
1038 if let Ok(does_contain) = result {
1039 assert!(does_contain, "Large polygon should contain smaller polygon");
1040 }
1041 }
1042 }
1043 }
1044
1045 #[test]
1046 fn test_disjoint_polygons_separated() {
1047 let poly1 = create_square();
1048 assert!(poly1.is_ok());
1049
1050 let coords2 = vec![
1051 Coordinate::new_2d(10.0, 10.0),
1052 Coordinate::new_2d(14.0, 10.0),
1053 Coordinate::new_2d(14.0, 14.0),
1054 Coordinate::new_2d(10.0, 14.0),
1055 Coordinate::new_2d(10.0, 10.0),
1056 ];
1057 let exterior2 = LineString::new(coords2);
1058 assert!(exterior2.is_ok());
1059
1060 if let (Ok(p1), Ok(ext2)) = (poly1, exterior2) {
1061 let poly2 = Polygon::new(ext2, vec![]);
1062 assert!(poly2.is_ok());
1063
1064 if let Ok(p2) = poly2 {
1065 let result = disjoint(&p1, &p2);
1066 assert!(result.is_ok());
1067 if let Ok(are_disjoint) = result {
1068 assert!(are_disjoint, "Separated polygons should be disjoint");
1069 }
1070 }
1071 }
1072 }
1073}