1use std::cmp::{Ordering, Reverse};
2
3use crate::algorithm::{
4 bounding_rect::BoundingRect, centroid::Centroid, coords_iter::CoordsIter,
5 dimensions::HasDimensions, euclidean_distance::EuclideanDistance,
6 line_intersection::LineIntersection, lines_iter::LinesIter, relate::Relate,
7};
8use crate::geometry::*;
9use crate::sweep::{Intersections, SweepPoint};
10use crate::GeoFloat;
11
12pub trait InteriorPoint {
51 type Output;
52
53 fn interior_point(&self) -> Self::Output;
73}
74
75impl<T> InteriorPoint for Line<T>
76where
77 T: GeoFloat,
78{
79 type Output = Point<T>;
80
81 fn interior_point(&self) -> Self::Output {
82 self.start_point()
85 }
86}
87
88impl<T> InteriorPoint for LineString<T>
89where
90 T: GeoFloat,
91{
92 type Output = Option<Point<T>>;
93
94 fn interior_point(&self) -> Self::Output {
97 match self.0.len() {
98 0 => None,
99 1 | 2 => Some(self.0[0].into()),
102 _ => {
103 let centroid = self
104 .centroid()
105 .expect("expected centroid for non-empty linestring");
106 self.0[1..(self.0.len() - 1)]
107 .iter()
108 .map(|coord| {
109 let pt = Point::from(*coord);
110 (pt, pt.euclidean_distance(¢roid))
111 })
112 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Less))
113 .map(|(pt, _distance)| pt)
114 }
115 }
116 }
117}
118
119impl<T> InteriorPoint for MultiLineString<T>
120where
121 T: GeoFloat,
122{
123 type Output = Option<Point<T>>;
124
125 fn interior_point(&self) -> Self::Output {
128 if let Some(centroid) = self.centroid() {
129 self.iter()
130 .filter_map(|linestring| {
131 linestring
132 .interior_point()
133 .map(|pt| (pt, pt.euclidean_distance(¢roid)))
134 })
135 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Less))
136 .map(|(pt, _distance)| pt)
137 } else {
138 None
139 }
140 }
141}
142
143fn polygon_interior_point_with_segment_length<T: GeoFloat>(
144 polygon: &Polygon<T>,
145) -> Option<(Point<T>, T)> {
146 if polygon.exterior().0.len() == 1 {
148 return Some((polygon.exterior().0[0].into(), T::zero()));
149 }
150
151 let two = T::one() + T::one();
152
153 let bounds = polygon.bounding_rect()?;
154
155 let mut y_mid = (bounds.min().y + bounds.max().y) / two;
160 if polygon.coords_iter().any(|coord| coord.y == y_mid) {
161 let next_closest = polygon
162 .coords_iter()
163 .filter_map(|coord| {
164 if coord.y == y_mid {
165 None
166 } else {
167 Some((coord.y, (coord.y - y_mid).abs()))
168 }
169 })
170 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Less));
171 if let Some((closest, _)) = next_closest {
172 y_mid = (y_mid + closest) / two
173 }
174 };
175
176 let scan_line = Line::new(
177 Coord {
178 x: bounds.min().x,
179 y: y_mid,
180 },
181 Coord {
182 x: bounds.max().x,
183 y: y_mid,
184 },
185 );
186
187 let lines = polygon.lines_iter().chain(std::iter::once(scan_line));
188
189 let mut intersections: Vec<SweepPoint<T>> = Vec::new();
190 for (l1, l2, inter) in Intersections::from_iter(lines) {
191 if !(l1 == scan_line || l2 == scan_line) {
192 continue;
193 }
194 match inter {
195 LineIntersection::Collinear { intersection } => {
196 intersections.push(SweepPoint::from(intersection.start));
197 intersections.push(SweepPoint::from(intersection.end));
198 }
199 LineIntersection::SinglePoint { intersection, .. } => {
200 intersections.push(SweepPoint::from(intersection));
201 }
202 }
203 }
204 intersections.sort();
205
206 let mut segments = Vec::new();
207 let mut intersections_iter = intersections.iter().peekable();
208 while let (Some(start), Some(end)) = (intersections_iter.next(), intersections_iter.peek()) {
209 let length = end.x - start.x;
210 let midpoint = Point::new((start.x + end.x) / two, y_mid);
211 segments.push((midpoint, length));
212 }
213 segments.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Less));
214
215 for (midpoint, segment_length) in segments {
216 let relation = polygon.relate(&midpoint);
219 if relation.is_intersects() {
220 return Some((
221 midpoint,
222 if relation.is_contains() {
223 segment_length
224 } else {
225 T::zero()
230 },
231 ));
232 }
233 }
234 polygon
236 .coords_iter()
237 .next()
238 .map(|coord| (coord.into(), T::zero()))
239}
240
241impl<T> InteriorPoint for Polygon<T>
242where
243 T: GeoFloat,
244{
245 type Output = Option<Point<T>>;
246
247 fn interior_point(&self) -> Self::Output {
248 polygon_interior_point_with_segment_length(self).map(|(point, _length)| point)
249 }
250}
251
252impl<T> InteriorPoint for MultiPolygon<T>
253where
254 T: GeoFloat,
255{
256 type Output = Option<Point<T>>;
257
258 fn interior_point(&self) -> Self::Output {
259 let segments = self
260 .iter()
261 .filter_map(polygon_interior_point_with_segment_length);
262 segments
263 .min_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Less))
264 .map(|(point, _length)| point)
265 }
266}
267
268impl<T> InteriorPoint for Rect<T>
269where
270 T: GeoFloat,
271{
272 type Output = Point<T>;
273
274 fn interior_point(&self) -> Self::Output {
275 self.center().into()
276 }
277}
278
279impl<T> InteriorPoint for Point<T>
280where
281 T: GeoFloat,
282{
283 type Output = Point<T>;
284
285 fn interior_point(&self) -> Self::Output {
286 *self
287 }
288}
289
290impl<T> InteriorPoint for MultiPoint<T>
303where
304 T: GeoFloat,
305{
306 type Output = Option<Point<T>>;
307
308 fn interior_point(&self) -> Self::Output {
309 if let Some(centroid) = self.centroid() {
310 self.iter()
311 .map(|pt| (pt, pt.euclidean_distance(¢roid)))
312 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Less))
313 .map(|(pt, _distance)| *pt)
314 } else {
315 None
316 }
317 }
318}
319
320impl<T> InteriorPoint for Geometry<T>
321where
322 T: GeoFloat,
323{
324 type Output = Option<Point<T>>;
325
326 crate::geometry_delegate_impl! {
327 fn interior_point(&self) -> Self::Output;
328 }
329}
330
331impl<T> InteriorPoint for GeometryCollection<T>
332where
333 T: GeoFloat,
334{
335 type Output = Option<Point<T>>;
336
337 fn interior_point(&self) -> Self::Output {
338 if let Some(centroid) = self.centroid() {
339 self.iter()
340 .filter_map(|geom| {
341 geom.interior_point().map(|pt| {
342 (
343 pt,
344 (Reverse(geom.dimensions()), pt.euclidean_distance(¢roid)),
346 )
347 })
348 })
349 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Less))
350 .map(|(pt, _distance)| pt)
351 } else {
352 None
353 }
354 }
355}
356
357impl<T> InteriorPoint for Triangle<T>
358where
359 T: GeoFloat,
360{
361 type Output = Point<T>;
362
363 fn interior_point(&self) -> Self::Output {
364 self.centroid()
365 }
366}
367
368#[cfg(test)]
369mod test {
370 use super::*;
371 use crate::{
372 algorithm::{contains::Contains, intersects::Intersects},
373 coord, line_string, point, polygon,
374 };
375
376 fn c<T: GeoFloat>(x: T, y: T) -> Coord<T> {
378 coord! { x: x, y: y }
379 }
380
381 fn p<T: GeoFloat>(x: T, y: T) -> Point<T> {
383 point! { x: x, y: y }
384 }
385
386 #[test]
388 fn empty_linestring_test() {
389 let linestring: LineString<f32> = line_string![];
390 let interior_point = linestring.interior_point();
391 assert!(interior_point.is_none());
392 }
393 #[test]
394 fn linestring_one_point_test() {
395 let coord = coord! {
396 x: 40.02f64,
397 y: 116.34,
398 };
399 let linestring = line_string![coord];
400 let interior_point = linestring.interior_point();
401 assert_eq!(interior_point, Some(Point::from(coord)));
402 }
403 #[test]
404 fn linestring_test() {
405 let linestring = line_string![
406 (x: 1., y: 1.),
407 (x: 7., y: 1.),
408 (x: 8., y: 1.),
409 (x: 9., y: 1.),
410 (x: 10., y: 1.),
411 (x: 11., y: 1.)
412 ];
413 assert_eq!(linestring.interior_point(), Some(point!(x: 7., y: 1. )));
414 }
415 #[test]
416 fn linestring_with_repeated_point_test() {
417 let l1 = LineString::from(vec![p(1., 1.), p(1., 1.), p(1., 1.)]);
418 assert_eq!(l1.interior_point(), Some(p(1., 1.)));
419
420 let l2 = LineString::from(vec![p(2., 2.), p(2., 2.), p(2., 2.)]);
421 let mls = MultiLineString::new(vec![l1, l2]);
422 assert_eq!(mls.interior_point(), Some(p(1., 1.)));
423 }
424 #[test]
426 fn empty_multilinestring_test() {
427 let mls: MultiLineString = MultiLineString::new(vec![]);
428 let interior_point = mls.interior_point();
429 assert!(interior_point.is_none());
430 }
431 #[test]
432 fn multilinestring_with_empty_line_test() {
433 let mls: MultiLineString = MultiLineString::new(vec![line_string![]]);
434 let interior_point = mls.interior_point();
435 assert!(interior_point.is_none());
436 }
437 #[test]
438 fn multilinestring_length_0_test() {
439 let coord = coord! {
440 x: 40.02f64,
441 y: 116.34,
442 };
443 let mls: MultiLineString = MultiLineString::new(vec![
444 line_string![coord],
445 line_string![coord],
446 line_string![coord],
447 ]);
448 assert_relative_eq!(mls.interior_point().unwrap(), Point::from(coord));
449 }
450 #[test]
451 fn multilinestring_one_line_test() {
452 let linestring = line_string![
453 (x: 1., y: 1.),
454 (x: 7., y: 1.),
455 (x: 8., y: 1.),
456 (x: 9., y: 1.),
457 (x: 10., y: 1.),
458 (x: 11., y: 1.)
459 ];
460 let mls: MultiLineString = MultiLineString::new(vec![linestring]);
461 assert_relative_eq!(mls.interior_point().unwrap(), point! { x: 7., y: 1. });
462 }
463 #[test]
464 fn multilinestring_test() {
465 let v1 = line_string![(x: 0.0, y: 0.0), (x: 1.0, y: 10.0)];
466 let v2 = line_string![(x: 1.0, y: 10.0), (x: 2.0, y: 0.0), (x: 3.0, y: 1.0)];
467 let v3 = line_string![(x: -12.0, y: -100.0), (x: 7.0, y: 8.0)];
468 let mls = MultiLineString::new(vec![v1, v2, v3]);
469 assert_eq!(mls.interior_point().unwrap(), point![x: 0., y: 0.]);
470 }
471 #[test]
473 fn empty_polygon_test() {
474 let poly: Polygon<f32> = polygon![];
475 assert!(poly.interior_point().is_none());
476 }
477 #[test]
478 fn polygon_one_point_test() {
479 let p = point![ x: 2., y: 1. ];
480 let v = Vec::new();
481 let linestring = line_string![p.0];
482 let poly = Polygon::new(linestring, v);
483 assert_relative_eq!(poly.interior_point().unwrap(), p);
484 }
485
486 #[test]
487 fn polygon_test() {
488 let poly = polygon![
489 (x: 0., y: 0.),
490 (x: 2., y: 0.),
491 (x: 2., y: 2.),
492 (x: 0., y: 2.),
493 (x: 0., y: 0.)
494 ];
495 assert_relative_eq!(poly.interior_point().unwrap(), point![x:1., y:1.]);
496 }
497 #[test]
498 fn polygon_hole_test() {
499 let ls1 = LineString::from(vec![
501 (5.0, 1.0),
502 (4.0, 2.0),
503 (4.0, 3.0),
504 (5.0, 4.0),
505 (6.0, 4.0),
506 (7.0, 3.0),
507 (7.0, 2.0),
508 (6.0, 1.0),
509 (5.0, 1.0),
510 ]);
511
512 let ls2 = LineString::from(vec![(5.0, 1.3), (5.5, 2.0), (6.0, 1.3), (5.0, 1.3)]);
513
514 let ls3 = LineString::from(vec![(5., 2.3), (5.5, 3.0), (6., 2.3), (5., 2.3)]);
515
516 let p1 = Polygon::new(ls1, vec![ls2, ls3]);
517 let interior_point = p1.interior_point().unwrap();
518 assert!(p1.contains(&interior_point));
519 assert_relative_eq!(interior_point, point!(x: 4.571428571428571, y: 2.5));
520 }
521 #[test]
522 fn flat_polygon_test() {
523 let poly = Polygon::new(
524 LineString::from(vec![p(0., 1.), p(1., 1.), p(0., 1.)]),
525 vec![],
526 );
527 assert_eq!(poly.interior_point(), Some(p(0.5, 1.)));
528 }
529 #[test]
530 fn diagonal_flat_polygon_test() {
531 let start: Coord<f64> = Coord {
534 x: 0.632690318327692,
535 y: 0.08104532928154995,
536 };
537 let end: Coord<f64> = Coord {
538 x: 0.4685039949468325,
539 y: 0.31750332644855794,
540 };
541 let poly = Polygon::new(LineString::new(vec![start, end, start]), vec![]);
542
543 assert_eq!(poly.interior_point(), Some(start.into()));
544 }
545 #[test]
546 fn polygon_vertex_on_median() {
547 let poly = Polygon::new(
548 LineString::from(vec![
549 (0.5, 1.0),
550 (0.5, 0.5),
551 (0.0, 0.5),
552 (0.0, 0.0),
553 (1.0, 0.0),
554 (1.0, 1.0),
555 (0.5, 1.0),
556 ]),
557 vec![],
558 );
559 let interior_point = poly.interior_point().unwrap();
560 assert_eq!(&interior_point, &p(0.75, 0.75));
561 }
562 #[test]
563 fn multi_poly_with_flat_polygon_test() {
564 let poly = Polygon::new(
565 LineString::from(vec![p(0., 0.), p(1., 0.), p(0., 0.)]),
566 vec![],
567 );
568 let multipoly = MultiPolygon::new(vec![poly]);
569 assert_eq!(multipoly.interior_point(), Some(p(0.5, 0.)));
570 }
571 #[test]
572 fn multi_poly_with_multiple_flat_polygon_test() {
573 let p1 = Polygon::new(
574 LineString::from(vec![p(1., 1.), p(1., 3.), p(1., 1.)]),
575 vec![],
576 );
577 let p2 = Polygon::new(
578 LineString::from(vec![p(2., 2.), p(6., 2.), p(2., 2.)]),
579 vec![],
580 );
581 let multipoly = MultiPolygon::new(vec![p1, p2]);
582 let interior = multipoly.interior_point().unwrap();
583 assert_eq!(&interior, &p(1., 2.));
584 assert!(multipoly.intersects(&interior));
585 }
586 #[test]
587 fn multi_poly_with_only_points_test() {
588 let p1 = Polygon::new(
589 LineString::from(vec![p(1., 1.), p(1., 1.), p(1., 1.)]),
590 vec![],
591 );
592 assert_eq!(p1.interior_point(), Some(p(1., 1.)));
593 let p2 = Polygon::new(
594 LineString::from(vec![p(2., 2.), p(2., 2.), p(2., 2.)]),
595 vec![],
596 );
597 let multipoly = MultiPolygon::new(vec![p1, p2]);
598 let interior_point = multipoly.interior_point().unwrap();
599 assert_eq!(multipoly.interior_point(), Some(p(1.0, 1.0)));
600 assert!(multipoly.intersects(&interior_point));
601 }
602 #[test]
603 fn multi_poly_with_one_ring_and_one_real_poly() {
604 let normal = Polygon::new(
608 LineString::from(vec![p(1., 1.), p(1., 3.), p(3., 1.), p(1., 1.)]),
609 vec![],
610 );
611 let flat = Polygon::new(
612 LineString::from(vec![p(2., 2.), p(6., 2.), p(2., 2.)]),
613 vec![],
614 );
615 let multipoly = MultiPolygon::new(vec![normal.clone(), flat]);
616 assert_eq!(multipoly.interior_point(), normal.interior_point());
617 }
618 #[test]
619 fn polygon_flat_interior_test() {
620 let poly = Polygon::new(
621 LineString::from(vec![p(0., 0.), p(0., 1.), p(1., 1.), p(1., 0.), p(0., 0.)]),
622 vec![LineString::from(vec![
623 p(0.1, 0.1),
624 p(0.1, 0.9),
625 p(0.1, 0.1),
626 ])],
627 );
628 assert_eq!(poly.interior_point(), Some(p(0.55, 0.5)));
629 }
630 #[test]
631 fn empty_interior_polygon_test() {
632 let poly = Polygon::new(
633 LineString::from(vec![p(0., 0.), p(0., 1.), p(1., 1.), p(1., 0.), p(0., 0.)]),
634 vec![LineString::new(vec![])],
635 );
636 assert_eq!(poly.interior_point(), Some(p(0.5, 0.5)));
637 }
638 #[test]
639 fn polygon_ring_test() {
640 let square = LineString::from(vec![p(0., 0.), p(0., 1.), p(1., 1.), p(1., 0.), p(0., 0.)]);
641 let poly = Polygon::new(square.clone(), vec![square]);
642 let interior_point = poly.interior_point().unwrap();
643 assert_eq!(&interior_point, &p(0.0, 0.5));
644 assert!(poly.intersects(&interior_point));
645 assert!(!poly.contains(&interior_point)); }
647 #[test]
648 fn polygon_cell_test() {
649 let square = LineString::from(vec![p(0., 0.), p(0., 2.), p(2., 2.), p(2., 0.), p(0., 0.)]);
652 let bottom = LineString::from(vec![p(0., 0.), p(2., 0.), p(2., 1.), p(0., 1.), p(0., 0.)]);
653 let top = LineString::from(vec![p(0., 1.), p(2., 1.), p(2., 2.), p(0., 2.), p(0., 1.)]);
654 let poly = Polygon::new(square, vec![top, bottom]);
655 let interior_point = poly.interior_point().unwrap();
656 assert!(poly.intersects(&interior_point));
657 assert!(!poly.contains(&interior_point));
658 }
659 #[test]
661 fn empty_multipolygon_polygon_test() {
662 assert!(MultiPolygon::<f64>::new(Vec::new())
663 .interior_point()
664 .is_none());
665 }
666
667 #[test]
668 fn multipolygon_one_polygon_test() {
669 let linestring =
670 LineString::from(vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]);
671 let poly = Polygon::new(linestring, Vec::new());
672 assert_eq!(
673 MultiPolygon::new(vec![poly]).interior_point(),
674 Some(p(1., 1.))
675 );
676 }
677 #[test]
678 fn multipolygon_two_polygons_test() {
679 let linestring =
680 LineString::from(vec![p(2., 1.), p(5., 1.), p(5., 3.), p(2., 3.), p(2., 1.)]);
681 let poly1 = Polygon::new(linestring, Vec::new());
682 let linestring =
683 LineString::from(vec![p(7., 1.), p(8., 1.), p(8., 2.), p(7., 2.), p(7., 1.)]);
684 let poly2 = Polygon::new(linestring, Vec::new());
685 let multipoly = MultiPolygon::new(vec![poly1, poly2]);
686 let interior_point = multipoly.interior_point().unwrap();
687 assert_relative_eq!(interior_point, point![x: 3.5, y: 2.]);
688 assert!(multipoly.contains(&interior_point));
689 }
690 #[test]
691 fn multipolygon_two_polygons_of_opposite_clockwise_test() {
692 let linestring = LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.), (0., 0.)]);
693 let poly1 = Polygon::new(linestring, Vec::new());
694 let linestring = LineString::from(vec![(0., 0.), (-2., 0.), (-2., 2.), (0., 2.), (0., 0.)]);
695 let poly2 = Polygon::new(linestring, Vec::new());
696 let multipoly = MultiPolygon::new(vec![poly1, poly2]);
697 let interior_point = multipoly.interior_point().unwrap();
698 assert_relative_eq!(interior_point, point![x: 1.0, y: 1.0]);
699 assert!(multipoly.contains(&interior_point));
700 }
701 #[test]
702 fn bounding_rect_test() {
703 let bounding_rect = Rect::new(coord! { x: 0., y: 50. }, coord! { x: 4., y: 100. });
704 let point = point![x: 2., y: 75.];
705 assert_eq!(point, bounding_rect.interior_point());
706 }
707 #[test]
708 fn line_test() {
709 let line1 = Line::new(c(0., 1.), c(1., 3.));
710 assert_eq!(line1.interior_point(), point![x: 0., y: 1.]);
711 }
712 #[test]
713 fn collection_test() {
714 let p0 = point!(x: 0.0, y: 0.0);
715 let p1 = point!(x: 2.0, y: 0.0);
716 let p2 = point!(x: 2.0, y: 2.0);
717 let p3 = point!(x: 0.0, y: 2.0);
718
719 let multi_point = MultiPoint::new(vec![p0, p1, p2, p3]);
720 assert_eq!(
721 multi_point.interior_point().unwrap(),
722 point!(x: 0.0, y: 0.0)
723 );
724 }
725 #[test]
726 fn mixed_collection_test() {
727 let linestring =
728 LineString::from(vec![p(0., 1.), p(0., 0.), p(1., 0.), p(1., 1.), p(0., 1.)]);
729 let poly1 = Polygon::new(linestring, Vec::new());
730 let linestring = LineString::from(vec![
731 p(10., 1.),
732 p(10., 0.),
733 p(11., 0.),
734 p(11., 1.),
735 p(10., 1.),
736 ]);
737 let poly2 = Polygon::new(linestring, Vec::new());
738
739 let high_dimension_shapes = GeometryCollection::new_from(vec![poly1.into(), poly2.into()]);
740
741 let mut mixed_shapes = high_dimension_shapes.clone();
742 mixed_shapes.0.push(Point::new(5_f64, 0_f64).into());
743 mixed_shapes.0.push(Point::new(5_f64, 1_f64).into());
744
745 assert_eq!(
748 high_dimension_shapes.interior_point().unwrap(),
749 mixed_shapes.interior_point().unwrap()
750 )
751 }
752 #[test]
753 fn triangles() {
754 assert_eq!(
756 Triangle::new(c(0., 0.), c(3., 0.), c(1.5, 3.)).interior_point(),
757 point!(x: 1.5, y: 1.0)
758 );
759
760 assert_eq!(
762 Triangle::new(c(0., 0.), c(3., 0.), c(1., 0.)).interior_point(),
763 point!(x: 1.5, y: 0.0)
764 );
765
766 assert_eq!(
768 Triangle::new(c(0., 0.), c(3., 3.), c(1., 1.)).interior_point(),
769 point!(x: 1.5, y: 1.5)
770 );
771
772 assert_eq!(
774 Triangle::new(c(0., 0.), c(0., 0.), c(1., 0.)).interior_point(),
775 point!(x: 0.5, y: 0.0)
776 );
777
778 assert_eq!(
780 Triangle::new(c(0., 0.5), c(0., 0.5), c(0., 0.5)).interior_point(),
781 point!(x: 0., y: 0.5)
782 )
783 }
784
785 #[test]
786 fn degenerate_triangle_like_ring() {
787 let triangle = Triangle::new(c(0., 0.), c(1., 1.), c(2., 2.));
788 let poly: Polygon<_> = triangle.into();
789
790 let line = Line::new(c(0., 1.), c(1., 3.));
791
792 let g1 = GeometryCollection::new_from(vec![triangle.into(), line.into()]);
793 let g2 = GeometryCollection::new_from(vec![poly.into(), line.into()]);
794
795 let pt1 = g1.interior_point().unwrap();
796 let pt2 = g2.interior_point().unwrap();
797 assert!(g1.intersects(&pt1));
801 assert!(g1.intersects(&pt2));
802 assert!(g2.intersects(&pt1));
803 assert!(g2.intersects(&pt2));
804 }
805
806 #[test]
807 fn degenerate_rect_like_ring() {
808 let rect = Rect::new(c(0., 0.), c(0., 4.));
809 let poly: Polygon<_> = rect.into();
810
811 let line = Line::new(c(0., 1.), c(1., 3.));
812
813 let g1 = GeometryCollection::new_from(vec![rect.into(), line.into()]);
814 let g2 = GeometryCollection::new_from(vec![poly.into(), line.into()]);
815 assert_eq!(g1.interior_point(), g2.interior_point());
816 }
817
818 #[test]
819 fn rectangles() {
820 assert_eq!(
822 Rect::new(c(0., 0.), c(4., 4.)).interior_point(),
823 point!(x: 2.0, y: 2.0)
824 );
825
826 assert_eq!(
828 Rect::new(c(0., 0.), c(4., 0.)).interior_point(),
829 point!(x: 2.0, y: 0.0)
830 );
831
832 assert_eq!(
834 Rect::new(c(4., 4.), c(4., 4.)).interior_point(),
835 point!(x: 4., y: 4.)
836 );
837
838 let collection = GeometryCollection::new_from(vec![
840 p(0., 0.).into(),
841 p(6., 0.).into(),
842 p(6., 6.).into(),
843 ]);
844 assert_eq!(collection.interior_point().unwrap(), point!(x: 6., y: 0.));
846 }
847}