@@ -474,24 +474,12 @@ double LinearRing<T>::distance(const LineString<U>& o) const {
474474
475475// -- buffer ------------------------------------------------------------------
476476
477+ // NOTE: same MultiPolygon→convex-hull fallback as LineString::buffer()
477478template <typename T>
478479Polygon<double > LinearRing<T>::buffer(double distance) const {
479480 if (!geos_ring_ || geos_ring_->isEmpty ()) return Polygon<double >();
480481 auto buf = geos_ring_->buffer (distance, 16 );
481- if (!buf || buf->isEmpty ()) return Polygon<double >();
482- const auto * poly = buf.get ();
483- if (poly->getGeometryTypeId () != geos::geom::GEOS_POLYGON) {
484- if (poly->getNumGeometries () > 0 ) poly = poly->getGeometryN (0 );
485- }
486- if (poly->getGeometryTypeId () != geos::geom::GEOS_POLYGON || poly->isEmpty ()) return Polygon<double >();
487- auto * gp = dynamic_cast <const geos::geom::Polygon*>(poly);
488- if (!gp) return Polygon<double >();
489- auto * cs = gp->getExteriorRing ()->getCoordinatesRO ();
490- if (!cs || cs->isEmpty ()) return Polygon<double >();
491- size_t n = cs->getSize ();
492- std::vector<double > c (n*2 );
493- for (size_t i = 0 ; i < n; ++i) { c[i*2 ]=cs->getAt (i).x ; c[i*2 +1 ]=cs->getAt (i).y ; }
494- return Polygon<double >(c.data (), n, 2 );
482+ return ::shapely::detail::extract_polygon_or_hull<T>(buf.get ());
495483}
496484
497485// -- boundary ----------------------------------------------------------------
@@ -840,21 +828,7 @@ Polygon<double> Polygon<T>::intersection(const Polygon<double>& other) const {
840828 if (geos_polygon_->isEmpty () || other.geos_polygon_ ->isEmpty ()) return Polygon<double >();
841829 if (!geos_polygon_->isValid () || !other.geos_polygon_ ->isValid ()) return Polygon<double >();
842830 auto inter = geos_polygon_->intersection (other.geos_polygon_ .get ());
843- if (!inter || inter->isEmpty ()) return Polygon<double >();
844- const auto * geom = inter.get ();
845- if (geom->getGeometryTypeId () == geos::geom::GEOS_POLYGON) {
846- auto * gp = dynamic_cast <const geos::geom::Polygon*>(geom);
847- if (gp) {
848- auto * cs = gp->getExteriorRing ()->getCoordinatesRO ();
849- if (cs && !cs->isEmpty ()) {
850- size_t n = cs->getSize ();
851- std::vector<double > c (n*2 );
852- for (size_t i = 0 ; i < n; ++i) { c[i*2 ]=cs->getAt (i).x ; c[i*2 +1 ]=cs->getAt (i).y ; }
853- return Polygon<double >(c.data (), n, 2 );
854- }
855- }
856- }
857- return Polygon<double >();
831+ return ::shapely::detail::extract_polygon_or_hull<T>(inter.get ());
858832}
859833
860834// Python: shapely/geometry/base.py::centroid:L478
@@ -871,43 +845,27 @@ Point<double> Polygon<T>::centroid() const {
871845// Python: shapely/geometry/base.py::buffer:L541
872846// -- buffer ------------------------------------------------------------------
873847
848+ // NOTE: same MultiPolygon→convex-hull fallback as LineString::buffer()
874849template <typename T>
875850Polygon<double > Polygon<T>::buffer(double distance) const {
876851 if (geos_polygon_->isEmpty ()) return Polygon<double >();
877852 if (!geos_polygon_->isValid () || !geos_polygon_->isSimple ()) return Polygon<double >();
878853 auto buf = geos_polygon_->buffer (distance, 16 );
879- if (!buf || buf->isEmpty ()) return Polygon<double >();
880- const auto * poly = buf.get ();
881- if (poly->getGeometryTypeId () != geos::geom::GEOS_POLYGON) {
882- if (poly->getNumGeometries () > 0 ) poly = poly->getGeometryN (0 );
883- }
884- if (poly->getGeometryTypeId () != geos::geom::GEOS_POLYGON || poly->isEmpty ()) return Polygon<double >();
885- auto * gp = dynamic_cast <const geos::geom::Polygon*>(poly);
886- if (!gp) return Polygon<double >();
887- auto * cs = gp->getExteriorRing ()->getCoordinatesRO ();
888- if (!cs || cs->isEmpty ()) return Polygon<double >();
889- size_t n = cs->getSize ();
890- std::vector<double > c (n*2 );
891- for (size_t i = 0 ; i < n; ++i) { c[i*2 ]=cs->getAt (i).x ; c[i*2 +1 ]=cs->getAt (i).y ; }
892- return Polygon<double >(c.data (), n, 2 );
854+ return ::shapely::detail::extract_polygon_or_hull<T>(buf.get ());
893855}
894856
895857// Python: shapely/geometry/base.py::difference:L553, sym_difference:L697
896858// -- difference / union / sym_difference -------------------------------------
859+ // NOTE: GEOS may return MultiPolygon for diff/union/symdiff (e.g. U-shaped
860+ // polygon cut through the middle). Use convex hull to collapse into a single
861+ // Polygon<T> so callers always get a valid result (Python shapely returns the
862+ // MultiPolygon as-is; we trade that for C++ type safety).
897863
898864#define POLY_CONSTRUCT (OP, GEOS_FN ) \
899865template <typename T> \
900866Polygon<double > Polygon<T>::OP(const Polygon<double >& o) const { \
901- auto res = detail::GEOS_FN (geos_polygon_.get (), o.geos_polygon_ .get ()); \
902- if (!res || res->isEmpty ()) return Polygon<double >(); \
903- auto * gp = dynamic_cast <geos::geom::Polygon*>(res.get ()); \
904- if (!gp) return Polygon<double >(); \
905- auto * cs = gp->getExteriorRing ()->getCoordinatesRO (); \
906- if (!cs || cs->isEmpty ()) return Polygon<double >(); \
907- size_t n = cs->getSize (); \
908- std::vector<double > c (n*2 ); \
909- for (size_t i = 0 ; i < n; ++i) { c[i*2 ]=cs->getAt (i).x ; c[i*2 +1 ]=cs->getAt (i).y ; } \
910- return Polygon<double >(c.data (), n, 2 ); \
867+ auto res = ::shapely::detail::GEOS_FN (geos_polygon_.get (), o.geos_polygon_ .get ()); \
868+ return ::shapely::detail::extract_polygon_or_hull<T>(res.get ()); \
911869}
912870POLY_CONSTRUCT (difference, geos_difference)
913871POLY_CONSTRUCT (union_op, geos_union)
@@ -918,15 +876,7 @@ POLY_CONSTRUCT(symmetric_difference, geos_sym_difference)
918876template <typename T>
919877Polygon<double > Polygon<T>::simplify(double tol) const {
920878 auto res = detail::geos_simplify (geos_polygon_.get (), tol);
921- if (!res || res->isEmpty ()) return Polygon<double >();
922- auto * gp = dynamic_cast <geos::geom::Polygon*>(res.get ());
923- if (!gp) return Polygon<double >();
924- auto * cs = gp->getExteriorRing ()->getCoordinatesRO ();
925- if (!cs || cs->isEmpty ()) return Polygon<double >();
926- size_t n = cs->getSize ();
927- std::vector<double > c (n*2 );
928- for (size_t i = 0 ; i < n; ++i) { c[i*2 ]=cs->getAt (i).x ; c[i*2 +1 ]=cs->getAt (i).y ; }
929- return Polygon<double >(c.data (), n, 2 );
879+ return ::shapely::detail::extract_polygon_or_hull<T>(res.get ());
930880}
931881
932882// Python: shapely/geometry/base.py::convex_hull:L567
0 commit comments