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