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