16 #include "geos/geom/BinaryOp.h"
17 #include "geos/geom/CoordinateArraySequence.h"
18 #include "geos/geom/CoordinateSequence.h"
19 #include "geos/geom/LinearRing.h"
20 #include "geos/geom/Point.h"
21 #include "geos/geom/Polygon.h"
22 #include "geos/operation/distance/DistanceOp.h"
23 #include "geos/opOverlay.h"
24 #include "geos/operation/overlay/snap/GeometrySnapper.h"
26 #include "SpecialPixel.h"
27 #include "PolygonTools.h"
28 #include "TProjection.h"
29 #include "ProjectionFactory.h"
30 #include "UniversalGroundMap.h"
47 geos::geom::MultiPolygon *PolygonTools::LatLonToXY(
48 const geos::geom::MultiPolygon &lonLatPolygon,
TProjection *projection) {
49 if (projection == NULL) {
50 string msg =
"Unable to convert Lon/Lat polygon to X/Y. ";
51 msg +=
"No projection has was supplied";
52 throw IException(IException::Programmer, msg, _FILEINFO_);
56 if(lonLatPolygon.isEmpty()) {
57 return globalFactory->createMultiPolygon();
60 vector<geos::geom::Geometry *> *xyPolys =
new vector<geos::geom::Geometry *>;
62 for(
unsigned int g = 0; g < lonLatPolygon.getNumGeometries(); ++g) {
63 const geos::geom::Polygon *poly =
64 dynamic_cast<const geos::geom::Polygon *
>(
65 lonLatPolygon.getGeometryN(g));
68 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
69 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
70 geos::geom::CoordinateSequence *xycoords =
new geos::geom::CoordinateArraySequence();
71 geos::geom::CoordinateSequence *llcoords =
72 poly->getInteriorRingN(h)->getCoordinates();
75 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
76 projection->
SetGround(llcoords->getAt(cord).y,
77 llcoords->getAt(cord).x);
78 xycoords->add(geos::geom::Coordinate(projection->
XCoord(),
82 geos::geom::LinearRing *hole = globalFactory->createLinearRing(xycoords);
84 if(hole->isValid() && !hole->isEmpty()) {
85 holes->push_back(hole);
93 geos::geom::CoordinateSequence *xycoords =
new geos::geom::CoordinateArraySequence();
94 geos::geom::CoordinateSequence *llcoords =
95 poly->getExteriorRing()->getCoordinates();
98 for (
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
99 projection->
SetGround(llcoords->getAt(cord).y,
100 llcoords->getAt(cord).x);
101 xycoords->add(geos::geom::Coordinate(projection->
XCoord(),
105 geos::geom::Polygon *newPoly = globalFactory->createPolygon(
106 globalFactory->createLinearRing(xycoords), holes);
108 if(newPoly->isValid() && !newPoly->isEmpty() && newPoly->getArea() > 1.0e-14) {
109 xyPolys->push_back(newPoly);
117 geos::geom::MultiPolygon *spikedPoly = globalFactory->createMultiPolygon(xyPolys);
119 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
124 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
132 IString msg =
"Unable to convert polygon from Lat/Lon to X/Y";
133 throw IException(IException::Programmer, msg, _FILEINFO_);
153 geos::geom::MultiPolygon *PolygonTools::XYToLatLon(
154 const geos::geom::MultiPolygon &xYPolygon,
TProjection *projection) {
156 if(projection == NULL) {
157 string msg =
"Unable to convert X/Y polygon to Lon/Lat. ";
158 msg +=
"No projection was supplied";
159 throw IException(IException::Programmer, msg, _FILEINFO_);
163 if(xYPolygon.isEmpty()) {
164 return globalFactory->createMultiPolygon();
167 vector<geos::geom::Geometry *> *llPolys =
new vector<geos::geom::Geometry *>;
169 for(
unsigned int g = 0; g < xYPolygon.getNumGeometries(); ++g) {
170 const geos::geom::Polygon *poly =
171 dynamic_cast<const geos::geom::Polygon *
>(
172 xYPolygon.getGeometryN(g));
175 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
176 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
177 geos::geom::CoordinateSequence *llcoords =
new geos::geom::CoordinateArraySequence();
178 geos::geom::CoordinateSequence *xycoords =
179 poly->getInteriorRingN(h)->getCoordinates();
182 for(
unsigned int cord = 0; cord < xycoords->getSize(); ++cord) {
183 projection->
SetWorld(xycoords->getAt(cord).x,
184 xycoords->getAt(cord).y);
185 llcoords->add(geos::geom::Coordinate(projection->
Longitude(),
188 holes->push_back(globalFactory->createLinearRing(llcoords));
192 geos::geom::CoordinateSequence *llcoords =
new geos::geom::DefaultCoordinateSequence();
193 geos::geom::CoordinateSequence *xycoords =
194 poly->getExteriorRing()->getCoordinates();
197 for(
unsigned int cord = 0; cord < xycoords->getSize(); ++cord) {
198 projection->
SetWorld(xycoords->getAt(cord).x,
199 xycoords->getAt(cord).y);
200 llcoords->add(geos::geom::Coordinate(projection->
Longitude(),
204 llPolys->push_back(globalFactory->createPolygon(
205 globalFactory->createLinearRing(llcoords), holes));
210 geos::geom::MultiPolygon *spikedPoly = globalFactory->createMultiPolygon(llPolys);
212 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
217 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
225 IString msg =
"Unable to convert polygon from X/Y to Lat/Lon";
226 throw IException(IException::Programmer, msg, _FILEINFO_);
245 geos::geom::MultiPolygon *PolygonTools::LatLonToSampleLine(
249 string msg =
"Unable to convert Lon/Lat polygon to Sample/Line. ";
250 msg +=
"No UniversalGroundMap was supplied";
251 throw IException(IException::Programmer, msg, _FILEINFO_);
255 if(lonLatPolygon.isEmpty()) {
256 return globalFactory->createMultiPolygon();
259 vector<geos::geom::Geometry *> *slPolys =
new vector<geos::geom::Geometry *>;
261 for(
unsigned int g = 0; g < lonLatPolygon.getNumGeometries(); g++) {
262 const geos::geom::Polygon *poly =
263 dynamic_cast<const geos::geom::Polygon *
>(
264 lonLatPolygon.getGeometryN(g));
267 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
268 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
269 geos::geom::CoordinateSequence *slcoords =
new geos::geom::DefaultCoordinateSequence();
270 geos::geom::CoordinateSequence *llcoords =
271 poly->getInteriorRingN(h)->getCoordinates();
274 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
276 llcoords->getAt(cord).x);
277 slcoords->add(geos::geom::Coordinate(ugm->
Sample(),
280 holes->push_back(globalFactory->createLinearRing(slcoords));
286 geos::geom::CoordinateSequence *slcoords =
new geos::geom::CoordinateArraySequence();
287 geos::geom::CoordinateSequence *llcoords =
288 poly->getExteriorRing()->getCoordinates();
291 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
293 llcoords->getAt(cord).x)) {
294 slcoords->add(geos::geom::Coordinate(ugm->
Sample(),
300 if (slcoords->getSize() > 0 && !slcoords->front().equals(slcoords->back())) {
301 slcoords->add(slcoords->front());
305 slPolys->push_back(globalFactory->createPolygon(
306 globalFactory->createLinearRing(slcoords), holes));
308 catch (std::exception &e) {
310 QObject::tr(
"Unable to convert polygon from Lat/Lon to Sample/Line. The "
311 "error given was [%1].").arg(e.what()),
319 geos::geom::MultiPolygon *spikedPoly = globalFactory->createMultiPolygon(slPolys);
321 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
326 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
334 IString msg =
"Unable to convert polygon from Lat/Lon to Sample/Line";
335 throw IException(IException::Programmer, msg, _FILEINFO_);
354 geos::geom::MultiPolygon *PolygonTools::CopyMultiPolygon(
const geos::geom::MultiPolygon *mpolygon) {
356 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
357 for(
unsigned int i = 0; i < mpolygon->getNumGeometries(); ++i) {
358 polys->push_back((mpolygon->getGeometryN(i))->clone());
360 return globalFactory->createMultiPolygon(polys);
376 geos::geom::MultiPolygon *PolygonTools::CopyMultiPolygon(
const geos::geom::MultiPolygon &mpolygon) {
378 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
379 for(
unsigned int i = 0; i < mpolygon.getNumGeometries(); ++i) {
380 polys->push_back((mpolygon.getGeometryN(i))->clone());
382 return globalFactory->createMultiPolygon(polys);
394 QString PolygonTools::ToGML(
const geos::geom::MultiPolygon *mpolygon, QString idString,
400 os <<
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" << endl;
401 os <<
"<ogr:FeatureCollection" << endl;
402 os <<
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl;
403 os <<
" xsi:schemaLocation=\"http://ogr.maptools.org/ " << schema <<
"\"" << endl;
404 os <<
" xmlns:ogr=\"http://ogr.maptools.org/\"" << endl;
405 os <<
" xmlns:gml=\"http://www.opengis.net/gml\">" << endl;
406 os <<
" <gml:boundedBy>" << endl;
407 os <<
" <gml:Box>" << endl;
408 os <<
" <gml:coord>";
410 setprecision(15) << mpolygon->getEnvelopeInternal()->getMinX() <<
413 setprecision(15) << mpolygon->getEnvelopeInternal()->getMinY() <<
415 os <<
"</gml:coord>" << endl;
416 os <<
" <gml:coord>";
418 setprecision(15) << mpolygon->getEnvelopeInternal()->getMaxX() <<
421 setprecision(15) << mpolygon->getEnvelopeInternal()->getMaxY() <<
423 os <<
"</gml:coord>" << endl;
424 os <<
" </gml:Box>" << endl;
425 os <<
" </gml:boundedBy>" << endl << endl;
426 os <<
" <gml:featureMember>" << endl;
427 os <<
" <ogr:multi_polygon fid=\"0\">" << endl;
428 os <<
" <ogr:ID>" << idString <<
"</ogr:ID>" << endl;
429 os <<
" <ogr:geometryProperty><gml:MultiPolygon><gml:polygonMember>" <<
430 "<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>";
433 for(
unsigned int polyN = 0; polyN < mpolygon->getNumGeometries(); polyN++) {
434 geos::geom::CoordinateSequence *pts = mpolygon->getGeometryN(polyN)->getCoordinates();
436 for(
unsigned int i = 0; i < pts->getSize(); i++) {
437 double lon = pts->getAt(i).x;
438 double lat = pts->getAt(i).y;
440 os << setprecision(15) << lon <<
"," << setprecision(15) << lat <<
" ";
444 os <<
"</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs>" <<
445 "</gml:Polygon></gml:polygonMember></gml:MultiPolygon>" <<
446 "</ogr:geometryProperty>" << endl;
447 os <<
" </ogr:multi_polygon>" << endl;
448 os <<
" </gml:featureMember>" << endl;
449 os <<
"</ogr:FeatureCollection>";
451 return os.str().c_str();
461 QString PolygonTools::GMLSchema() {
465 os <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
466 os <<
"<xs:schema targetNamespace=\"http://ogr.maptools.org/\" "
467 "xmlns:ogr=\"http://ogr.maptools.org/\" "
468 "xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "
469 "xmlns:gml=\"http://www.opengis.net/gml\" "
470 "elementFormDefault=\"qualified\" "
471 "version=\"1.0\">" << endl;
472 os <<
" <xs:import namespace=\"http://www.opengis.net/gml\" "
473 "schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/>" << endl;
474 os <<
" <xs:element name=\"FeatureCollection\" "
475 "type=\"ogr:FeatureCollectionType\" "
476 "substitutionGroup=\"gml:_FeatureCollection\"/>" << endl;
477 os <<
" <xs:complexType name=\"FeatureCollectionType\">" << endl;
478 os <<
" <xs:complexContent>" << endl;
479 os <<
" <xs:extension base=\"gml:AbstractFeatureCollectionType\">" << endl;
480 os <<
" <xs:attribute name=\"lockId\" type=\"xs:string\" use=\"optional\"/>" << endl;
481 os <<
" <xs:attribute name=\"scope\" type=\"xs:string\" use=\"optional\"/>" << endl;
482 os <<
" </xs:extension>" << endl;
483 os <<
" </xs:complexContent>" << endl;
484 os <<
" </xs:complexType>" << endl;
485 os <<
" <xs:element name=\"multi_polygon\" "
486 "type=\"ogr:multi_polygon_Type\" "
487 "substitutionGroup=\"gml:_Feature\"/>" << endl;
488 os <<
" <xs:complexType name=\"multi_polygon_Type\">" << endl;
489 os <<
" <xs:complexContent>" << endl;
490 os <<
" <xs:extension base=\"gml:AbstractFeatureType\">" << endl;
491 os <<
" <xs:sequence>" << endl;
492 os <<
" <xs:element name=\"geometryProperty\" "
493 "type=\"gml:MultiPolygonPropertyType\" "
494 "nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\"/>" << endl;
495 os <<
" <xs:element name=\"fid\" nillable=\"true\" minOccurs=\"0\" "
496 "maxOccurs=\"1\">" << endl;
497 os <<
" <xs:simpleType>" << endl;
498 os <<
" <xs:restriction base=\"xs:string\">" << endl;
499 os <<
" </xs:restriction>" << endl;
500 os <<
" </xs:simpleType>" << endl;
501 os <<
" </xs:element>" << endl;
502 os <<
" <xs:element name=\"ID\" nillable=\"true\" minOccurs=\"0\" "
503 "maxOccurs=\"1\">" << endl;
504 os <<
" <xs:simpleType>" << endl;
505 os <<
" <xs:restriction base=\"xs:integer\">" << endl;
506 os <<
" <xs:totalDigits value=\"16\"/>" << endl;
507 os <<
" </xs:restriction>" << endl;
508 os <<
" </xs:simpleType>" << endl;
509 os <<
" </xs:element>" << endl;
510 os <<
" </xs:sequence>" << endl;
511 os <<
" </xs:extension>" << endl;
512 os <<
" </xs:complexContent>" << endl;
513 os <<
" </xs:complexType>" << endl;
514 os <<
"</xs:schema>";
516 return os.str().c_str();
527 geos::geom::MultiPolygon *PolygonTools::To180(geos::geom::MultiPolygon *poly360) {
535 geos::geom::CoordinateArraySequence *leftOf180Pts =
536 new geos::geom::CoordinateArraySequence();
537 leftOf180Pts->add(geos::geom::Coordinate(0, -90));
538 leftOf180Pts->add(geos::geom::Coordinate(0, 90));
539 leftOf180Pts->add(geos::geom::Coordinate(180, 90));
540 leftOf180Pts->add(geos::geom::Coordinate(180, -90));
541 leftOf180Pts->add(geos::geom::Coordinate(0, -90));
543 geos::geom::LinearRing *leftOf180Geom =
544 globalFactory->createLinearRing(leftOf180Pts);
546 geos::geom::Polygon *leftOf180Poly =
547 globalFactory->createPolygon(leftOf180Geom, NULL);
549 geos::geom::CoordinateArraySequence *rightOf180Pts =
550 new geos::geom::CoordinateArraySequence();
551 rightOf180Pts->add(geos::geom::Coordinate(180, -90));
552 rightOf180Pts->add(geos::geom::Coordinate(180, 90));
553 rightOf180Pts->add(geos::geom::Coordinate(360, 90));
554 rightOf180Pts->add(geos::geom::Coordinate(360, -90));
555 rightOf180Pts->add(geos::geom::Coordinate(180, -90));
557 geos::geom::LinearRing *rightOf180Geom =
558 globalFactory->createLinearRing(rightOf180Pts);
560 geos::geom::Polygon *rightOf180Poly =
561 globalFactory->createPolygon(rightOf180Geom, NULL);
563 geos::geom::Geometry *preserved = Intersect(leftOf180Poly, poly360);
564 geos::geom::Geometry *moving = Intersect(rightOf180Poly, poly360);
566 geos::geom::CoordinateSequence *movingPts = moving->getCoordinates();
567 geos::geom::CoordinateSequence *movedPts =
568 new geos::geom::CoordinateArraySequence();
570 for(
unsigned int i = 0; i < movingPts->getSize(); i ++) {
571 movedPts->add(geos::geom::Coordinate(movingPts->getAt(i).x - 360.0,
572 movingPts->getAt(i).y));
575 if(movedPts->getSize()) {
576 movedPts->add(geos::geom::Coordinate(movedPts->getAt(0).x,
577 movedPts->getAt(0).y));
580 geos::geom::Geometry *moved = globalFactory->createPolygon(
581 globalFactory->createLinearRing(movedPts), NULL);
583 std::vector<geos::geom::Geometry *> *geomsForCollection =
new
584 std::vector<geos::geom::Geometry *>;
585 geomsForCollection->push_back(preserved);
586 geomsForCollection->push_back(moved);
588 geos::geom::GeometryCollection *the180Polys =
589 Isis::globalFactory->createGeometryCollection(geomsForCollection);
591 geos::geom::MultiPolygon *result = MakeMultiPolygon(the180Polys);
595 geos::geom::MultiPolygon *fixedResult = FixSeam(result);
601 catch(geos::util::GEOSException *exc) {
602 IString msg =
"Conversion to 180 failed. The reason given was [" +
605 throw IException(IException::Programmer, msg, _FILEINFO_);
608 IString msg =
"Conversion to 180 failed. Could not determine the reason";
609 throw IException(IException::Programmer, msg, _FILEINFO_);
624 double PolygonTools::Thickness(
const geos::geom::MultiPolygon *mpolygon) {
625 const geos::geom::Envelope *envelope = mpolygon->getEnvelopeInternal();
627 double x = fabs(envelope->getMaxX() - envelope->getMinX());
628 double y = fabs(envelope->getMaxY() - envelope->getMinY());
629 double extent = max(x, y);
631 return mpolygon->getArea() / (extent * extent);
646 geos::geom::MultiPolygon *PolygonTools::Despike(
const geos::geom::Geometry *geom) {
647 geos::geom::MultiPolygon *spiked = MakeMultiPolygon(geom);
648 geos::geom::MultiPolygon *despiked = Despike(spiked);
667 geos::geom::MultiPolygon *PolygonTools::Despike(
const geos::geom::MultiPolygon *multiPoly) {
669 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
670 for(
unsigned int g = 0; g < multiPoly->getNumGeometries(); ++g) {
671 const geos::geom::Polygon *poly =
672 dynamic_cast<const geos::geom::Polygon *
>(multiPoly->getGeometryN(g));
675 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
676 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
677 const geos::geom::LineString *ls = poly->getInteriorRingN(h);
678 geos::geom::LinearRing *lr;
685 geos::geom::LinearRing *fixed = FixGeometry(lr);
692 holes->push_back(lr);
700 const geos::geom::LineString *ls = poly->getExteriorRing();
701 geos::geom::LinearRing *lr;
707 geos::geom::LinearRing *fixed = FixGeometry(lr);
715 if(ls->isValid() && ls->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
716 lr =
dynamic_cast<geos::geom::LinearRing *
>(ls->clone());
725 geos::geom::Polygon *tp = Isis::globalFactory->createPolygon(lr, holes);
727 if(tp->isEmpty() || !tp->isValid()) {
729 newPolys->push_back(poly->clone());
732 newPolys->push_back(tp);
738 geos::geom::MultiPolygon *mp = Isis::globalFactory->createMultiPolygon(newPolys);
740 if(!mp->isValid() || mp->isEmpty()) {
743 IString msg =
"Despike failed to correct the polygon";
744 throw IException(IException::Programmer, msg, _FILEINFO_);
748 if(fabs((mp->getArea() / multiPoly->getArea()) - 1.0) > 0.50) {
749 IString msg =
"Despike failed to correct the polygon " + mp->toString();
752 throw IException(IException::Programmer, msg, _FILEINFO_);
772 geos::geom::LinearRing *PolygonTools::Despike(
const geos::geom::LineString *lineString) {
773 geos::geom::CoordinateSequence *vertices = lineString->getCoordinates();
776 if(vertices->getSize() < 4) {
778 return Isis::globalFactory->createLinearRing(geos::geom::CoordinateArraySequence());
783 vertices->deleteAt(vertices->getSize() - 1);
788 for(
long index = 0; index < (long)vertices->getSize(); index++) {
790 if(vertices->getSize() < 3) {
796 long testCoords[3] = {
804 for(
int j = 0; j < 3; j++) {
805 while(testCoords[j] < 0) {
806 testCoords[j] += vertices->getSize();
809 while(testCoords[j] >= (
long)vertices->getSize()) {
810 testCoords[j] -= vertices->getSize();
815 if(IsSpiked(vertices->getAt(testCoords[0]),
816 vertices->getAt(testCoords[1]),
817 vertices->getAt(testCoords[2]))) {
819 vertices->deleteAt(testCoords[1]);
826 if(vertices->getSize() < 3) {
830 return Isis::globalFactory->createLinearRing(geos::geom::CoordinateArraySequence());
834 vertices->add(vertices->getAt(0));
835 return Isis::globalFactory->createLinearRing(vertices);
848 bool PolygonTools::IsSpiked(geos::geom::Coordinate first,
849 geos::geom::Coordinate middle,
850 geos::geom::Coordinate last) {
851 return TestSpiked(first, middle, last) || TestSpiked(last, middle, first);
882 bool PolygonTools::TestSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle,
883 geos::geom::Coordinate last) {
884 geos::geom::Point *firstPt = Isis::globalFactory->createPoint(first);
885 geos::geom::Point *middlePt = Isis::globalFactory->createPoint(middle);
886 geos::geom::Point *lastPt = Isis::globalFactory->createPoint(last);
888 geos::geom::CoordinateSequence *coords =
new geos::geom::CoordinateArraySequence();
891 geos::geom::LineString *line = Isis::globalFactory->createLineString(coords);
897 double tolerance = line->getLength() / 100.0;
901 double distanceLastMiddle = geos::operation::distance::DistanceOp::distance(lastPt, middlePt);
902 double distanceLastLine = geos::operation::distance::DistanceOp::distance(lastPt, line);
904 if(distanceLastMiddle == 0.0)
return true;
908 if(distanceLastLine / distanceLastMiddle >= .05) {
913 if(spiked && distanceLastLine > tolerance) {
918 geos::geom::CoordinateSequence *coords =
new geos::geom::CoordinateArraySequence();
925 geos::geom::LinearRing *shell = Isis::globalFactory->createLinearRing(coords);
926 std::vector<geos::geom::Geometry *> *empty =
new std::vector<geos::geom::Geometry *>;
929 geos::geom::Polygon *poly = Isis::globalFactory->createPolygon(shell, empty);
934 if(poly->getArea() < 1.0e-10) {
964 geos::geom::Geometry *PolygonTools::Intersect(
const geos::geom::Geometry *geom1,
965 const geos::geom::Geometry *geom2) {
967 return Operate(geom1, geom2, (
unsigned int)geos::operation::overlay::OverlayOp::opINTERSECTION);
969 catch(geos::util::GEOSException *exc) {
970 IString msg =
"Intersect operation failed. The reason given was [" +
IString(exc->what()) +
"]";
972 throw IException(IException::Programmer, msg, _FILEINFO_);
975 IString msg =
"Intersect operation failed";
976 throw IException(e, IException::Programmer, msg, _FILEINFO_);
979 IString msg =
"Intersect operation failed for an unknown reason";
980 throw IException(IException::Programmer, msg, _FILEINFO_);
985 geos::geom::Geometry *PolygonTools::Operate(
const geos::geom::Geometry *geom1,
986 const geos::geom::Geometry *geom2,
987 unsigned int opcode) {
989 geos::operation::overlay::OverlayOp::OpCode code =
990 (geos::operation::overlay::OverlayOp::OpCode)opcode;
992 geos::geom::Geometry *result = NULL;
994 geos::geom::Geometry *geomFirst = MakeMultiPolygon(geom1);
995 geos::geom::Geometry *geomSecond = MakeMultiPolygon(geom2);
997 geos::operation::overlay::snap::GeometrySnapper snap(*geomFirst);
998 geos::geom::Geometry *geomSnapped = snap.snapTo(*geomSecond, 1.0e-10)->clone();
999 if(!geomSnapped->isValid()) {
1004 geomFirst = geomSnapped;
1007 unsigned int precision = 15;
1008 unsigned int minPrecision = 13;
1012 std::unique_ptr< geos::geom::Geometry > resultAuto(
1013 BinaryOp(geomFirst, geomSecond, geos::operation::overlay::overlayOp(code)).release());
1015 result = resultAuto->clone();
1017 catch(geos::util::GEOSException *exc) {
1019 if(!failed || precision == minPrecision)
throw;
1024 if(precision == minPrecision) {
1025 IString msg =
"An unknown geos error occurred";
1026 throw IException(IException::Programmer, msg, _FILEINFO_);
1030 IString msg =
"An unknown geos error occurred when attempting to clone a geometry";
1031 throw IException(IException::Programmer, msg, _FILEINFO_);
1038 geos::geom::Geometry *tmp = ReducePrecision(geomFirst, precision);
1042 tmp = ReducePrecision(geomSecond, precision);
1054 if(result && !result->isValid()) {
1056 geos::geom::Geometry *newResult = FixGeometry(result);
1058 if(fabs(newResult->getArea() / result->getArea() - 1.0) > 0.50) {
1062 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1063 throw IException(IException::Programmer, msg, _FILEINFO_);
1069 catch(IException &e) {
1070 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1071 throw IException(IException::Programmer, msg, _FILEINFO_);
1075 if(result == NULL) {
1076 IString msg =
"Operation [" + IString((
int)opcode) +
" failed";
1077 throw IException(IException::Programmer, msg, _FILEINFO_);
1093 geos::geom::Geometry *PolygonTools::FixGeometry(
const geos::geom::Geometry *geom) {
1094 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1095 return FixGeometry(
dynamic_cast<const geos::geom::MultiPolygon *
>(geom));
1097 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1098 return FixGeometry(
dynamic_cast<const geos::geom::LinearRing *
>(geom));
1100 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1101 return FixGeometry(
dynamic_cast<const geos::geom::Polygon *
>(geom));
1103 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1104 return FixGeometry(MakeMultiPolygon(geom));
1107 IString msg =
"PolygonTools::FixGeometry does not support [" + GetGeometryName(geom) +
"]";
1108 throw IException(IException::Programmer, msg, _FILEINFO_);
1121 geos::geom::MultiPolygon *PolygonTools::FixGeometry(
const geos::geom::MultiPolygon *poly) {
1123 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1126 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1127 geos::geom::Polygon *fixedpoly = FixGeometry(
1128 dynamic_cast<const geos::geom::Polygon *
>(
1129 poly->getGeometryN(geomIndex)));
1130 if(fixedpoly->isValid()) {
1131 newPolys->push_back(fixedpoly);
1139 geos::geom::MultiPolygon *mp = Isis::globalFactory->createMultiPolygon(newPolys);
1144 geos::geom::Polygon *PolygonTools::FixGeometry(
const geos::geom::Polygon *poly) {
1147 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1148 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1149 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1152 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1153 holes->push_back(thisHole->clone());
1158 geos::geom::LinearRing *newHole = FixGeometry((geos::geom::LinearRing *)thisHole);
1159 holes->push_back(newHole);
1161 catch (IException &e) {
1162 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1163 throw IException(IException::Programmer, msg, _FILEINFO_);
1168 const geos::geom::LineString *exterior = poly->getExteriorRing();
1171 geos::geom::LinearRing *newExterior = NULL;
1173 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1174 newExterior = FixGeometry((geos::geom::LinearRing *)exterior);
1177 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior "
1178 "ring is not simple and closed";
1179 throw IException(IException::Programmer, msg, _FILEINFO_);
1182 return globalFactory->createPolygon(newExterior, holes);
1184 catch (IException &e) {
1185 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1186 throw IException(e, IException::Programmer, msg, _FILEINFO_);
1206 geos::geom::LinearRing *PolygonTools::FixGeometry(
const geos::geom::LinearRing *ring) {
1208 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1211 if(coords->getSize() < 4) {
1212 return globalFactory->createLinearRing(
new geos::geom::DefaultCoordinateSequence());
1215 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1216 const geos::geom::Coordinate *lastCoordinate = &coords->getAt(0);
1217 newCoords->add(*lastCoordinate);
1220 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1221 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1226 double difference[2] = {
1227 lastCoordinate->x - thisCoordinate->x,
1228 lastCoordinate->y - thisCoordinate->y,
1232 double minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1234 minDiff = min(minDiff, fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1])));
1238 if(difference[0] == 0.0 && difference[1] != 0.0) {
1240 minDiff = fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1]));
1242 else if(difference[1] == 0.0 && difference[0] != 0.0) {
1244 minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1246 else if(difference[0] == 0.0 && difference[1] == 0.0) {
1253 newCoords->add(*thisCoordinate);
1254 lastCoordinate = thisCoordinate;
1258 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1259 geos::geom::LinearRing *newRing = NULL;
1263 if(newCoords->getSize() > 3) {
1264 newRing = globalFactory->createLinearRing(newCoords);
1271 catch(geos::util::GEOSException *exc) {
1275 IString msg =
"Error when attempting to fix linear ring";
1276 throw IException(IException::Programmer, msg, _FILEINFO_);
1279 if(newRing && !newRing->isValid() && ring->isValid()) {
1280 IString msg =
"Failed when attempting to fix linear ring";
1281 throw IException(IException::Programmer, msg, _FILEINFO_);
1283 else if(!newRing || !newRing->isValid()) {
1288 newRing =
dynamic_cast<geos::geom::LinearRing *
>(ring->clone());
1306 int PolygonTools::DecimalPlace(
double num) {
1308 if(num == 0.0)
return 0;
1312 int decimalPlace = 1;
1323 return decimalPlace;
1334 geos::geom::Geometry *PolygonTools::Difference(
const geos::geom::Geometry *geom1,
1335 const geos::geom::Geometry *geom2) {
1337 return Operate(geom1, geom2, (
unsigned int)geos::operation::overlay::OverlayOp::opDIFFERENCE);
1339 catch(geos::util::GEOSException *exc) {
1340 IString msg =
"Difference operation failed. The reason given was [" +
1343 throw IException(IException::Programmer, msg, _FILEINFO_);
1346 IString msg =
"Difference operation failed";
1347 throw IException(e, IException::Programmer, msg, _FILEINFO_);
1350 IString msg =
"Difference operation failed for an unknown reason";
1351 throw IException(IException::Programmer, msg, _FILEINFO_);
1369 geos::geom::MultiPolygon *PolygonTools::MakeMultiPolygon(
const geos::geom::Geometry *geom) {
1371 if(geom->isEmpty()) {
1372 return Isis::globalFactory->createMultiPolygon();
1375 else if(geom->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1376 return Isis::globalFactory->createMultiPolygon();
1379 else if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1380 return dynamic_cast<geos::geom::MultiPolygon *
>(geom->clone());
1383 else if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1384 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
1385 polys->push_back(geom->clone());
1386 geos::geom::MultiPolygon *mp = Isis::globalFactory->createMultiPolygon(polys);
1390 else if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1391 vector<geos::geom::Geometry *> * polys =
1392 new vector<geos::geom::Geometry *>;
1393 const geos::geom::GeometryCollection *gc =
1394 dynamic_cast<const geos::geom::GeometryCollection *
>(geom);
1395 for(
unsigned int i = 0; i < gc->getNumGeometries(); ++i) {
1396 geos::geom::MultiPolygon *subMultiPoly =
1397 MakeMultiPolygon(gc->getGeometryN(i));
1399 for(
unsigned int subPoly = 0;
1400 subPoly < subMultiPoly->getNumGeometries();
1402 const geos::geom::Polygon *poly =
1403 dynamic_cast<const geos::geom::Polygon *
>(
1404 subMultiPoly->getGeometryN(subPoly));
1405 polys->push_back(
dynamic_cast<geos::geom::Polygon *
>(poly->clone()));
1409 geos::geom::MultiPolygon *mp =
1410 Isis::globalFactory->createMultiPolygon(polys);
1411 if(mp->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1413 mp = Isis::globalFactory->createMultiPolygon();
1421 return Isis::globalFactory->createMultiPolygon();
1426 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1427 const geos::geom::Polygon *polyA,
const geos::geom::Polygon *polyB) {
1428 geos::geom::CoordinateSequence *polyAPoints = polyA->getCoordinates();
1429 geos::geom::CoordinateSequence *polyBPoints = polyB->getCoordinates();
1431 unsigned int aIntersectionBegin = 0;
1432 unsigned int aIntersectionEnd = 0;
1433 unsigned int bIntersectionBegin = 0;
1434 unsigned int bIntersectionEnd = 0;
1436 bool intersectionStarted =
false;
1437 bool intersectionEnded =
false;
1439 unsigned int lastBMatch = 0;
1440 for (
unsigned int i = 0;
1441 !intersectionEnded && i < polyAPoints->getSize();
1444 bool foundEquivalent =
false;
1446 geos::geom::Coordinate coordA = polyAPoints->getAt(i);
1447 coordA = *ReducePrecision(&coordA, 13);
1449 for (
unsigned int j = 0;
1450 !foundEquivalent && j < polyBPoints->getSize();
1452 geos::geom::Coordinate coordB = polyBPoints->getAt(j);
1453 coordB = *ReducePrecision(&coordB, 13);
1455 foundEquivalent = coordA.equals(coordB);
1457 if (foundEquivalent) lastBMatch = j;
1459 if (foundEquivalent && !intersectionStarted) {
1460 intersectionStarted =
true;
1461 aIntersectionBegin = i;
1462 bIntersectionBegin = j;
1466 if (!foundEquivalent && intersectionStarted && !intersectionEnded) {
1467 intersectionEnded =
true;
1468 aIntersectionEnd = i;
1469 bIntersectionEnd = lastBMatch;
1473 geos::geom::MultiPolygon * result = NULL;
1474 if (intersectionStarted && intersectionEnded) {
1475 geos::geom::CoordinateSequence *merged =
1476 new geos::geom::CoordinateArraySequence;
1479 for (i = 0; i < aIntersectionBegin; i ++) {
1480 merged->add(polyAPoints->getAt(i));
1483 i = bIntersectionBegin;
1484 while (i != bIntersectionEnd) {
1485 merged->add(polyBPoints->getAt(i));
1487 if (i >= polyBPoints->getSize()) i = 0;
1490 for (i = aIntersectionEnd; i < polyAPoints->getSize() - 1; i++) {
1491 merged->add(polyAPoints->getAt(i));
1494 merged->add(merged->getAt(0));
1495 result = MakeMultiPolygon(globalFactory->createPolygon(
1496 globalFactory->createLinearRing(merged), NULL));
1503 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1504 const geos::geom::MultiPolygon *poly) {
1506 std::vector<geos::geom::Geometry *> *polys =
1507 new std::vector<geos::geom::Geometry *>;
1510 for(
unsigned int copyIndex = 0;
1511 copyIndex < poly->getNumGeometries();
1513 polys->push_back(poly->getGeometryN(copyIndex)->clone());
1516 unsigned int outerPolyIndex = 0;
1518 while(outerPolyIndex + 1 < polys->size()) {
1519 unsigned int innerPolyIndex = outerPolyIndex + 1;
1521 while(innerPolyIndex < polys->size()) {
1522 geos::geom::MultiPolygon *fixedPair = FixSeam(
1523 dynamic_cast<geos::geom::Polygon *
>(polys->at(outerPolyIndex)),
1524 dynamic_cast<geos::geom::Polygon *
>(polys->at(innerPolyIndex)));
1526 if(fixedPair != NULL) {
1527 geos::geom::Geometry *oldInnerPoly = polys->at(innerPolyIndex);
1528 geos::geom::Geometry *oldOuterPoly = polys->at(outerPolyIndex);
1530 polys->erase(polys->begin() + innerPolyIndex);
1531 (*polys)[outerPolyIndex] = fixedPair->getGeometryN(0)->clone();
1532 innerPolyIndex = outerPolyIndex + 1;
1537 delete oldInnerPoly;
1538 oldInnerPoly = NULL;
1540 delete oldOuterPoly;
1541 oldOuterPoly = NULL;
1551 return globalFactory->createMultiPolygon(polys);
1564 geos::geom::Geometry *PolygonTools::ReducePrecision(
const geos::geom::Geometry *geom,
1565 unsigned int precision) {
1566 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1567 return ReducePrecision(
1568 dynamic_cast<const geos::geom::MultiPolygon *
>(geom), precision);
1570 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1571 return ReducePrecision(
1572 dynamic_cast<const geos::geom::LinearRing *
>(geom), precision);
1574 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1575 return ReducePrecision(
1576 dynamic_cast<const geos::geom::Polygon *
>(geom), precision);
1578 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1579 return ReducePrecision(MakeMultiPolygon(geom), precision);
1582 IString msg =
"PolygonTools::ReducePrecision does not support [" +
1583 GetGeometryName(geom) +
"]";
1584 throw IException(IException::Programmer, msg, _FILEINFO_);
1598 geos::geom::MultiPolygon *PolygonTools::ReducePrecision(
const geos::geom::MultiPolygon *poly,
1599 unsigned int precision) {
1601 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1604 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1605 geos::geom::Geometry *lowerPrecision = ReducePrecision(
1606 dynamic_cast<const geos::geom::Polygon *
>(
1607 poly->getGeometryN(geomIndex)),
1610 if(!lowerPrecision->isEmpty()) {
1611 newPolys->push_back(lowerPrecision);
1614 delete lowerPrecision;
1618 geos::geom::MultiPolygon *mp = Isis::globalFactory->createMultiPolygon(newPolys);
1632 geos::geom::Polygon *PolygonTools::ReducePrecision(
const geos::geom::Polygon *poly,
1633 unsigned int precision) {
1635 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1636 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1637 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1640 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1641 holes->push_back(thisHole->clone());
1646 geos::geom::LinearRing *newHole = ReducePrecision((geos::geom::LinearRing *)thisHole,
1649 if(!newHole->isEmpty()) {
1650 holes->push_back(newHole);
1658 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1659 throw IException(e, IException::Programmer, msg, _FILEINFO_);
1664 const geos::geom::LineString *exterior = poly->getExteriorRing();
1667 geos::geom::LinearRing *newExterior = NULL;
1669 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1670 newExterior = ReducePrecision((geos::geom::LinearRing *)exterior, precision);
1673 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior "
1674 "ring is not simple and closed";
1675 throw IException(IException::Programmer, msg, _FILEINFO_);
1678 return globalFactory->createPolygon(newExterior, holes);
1681 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1682 throw IException(e, IException::Programmer, msg, _FILEINFO_);
1696 geos::geom::LinearRing *PolygonTools::ReducePrecision(
const geos::geom::LinearRing *ring,
1697 unsigned int precision) {
1698 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1701 if(coords->getSize() <= 0)
return dynamic_cast<geos::geom::LinearRing *
>(
1704 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1705 geos::geom::Coordinate *coord = ReducePrecision(&coords->getAt(0), precision);
1706 newCoords->add(*coord);
1711 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1712 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1713 coord = ReducePrecision(thisCoordinate, precision);
1714 newCoords->add(*coord);
1719 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1720 geos::geom::LinearRing *newRing = NULL;
1724 newRing = globalFactory->createLinearRing(newCoords);
1726 catch(geos::util::GEOSException *exc) {
1730 IString msg =
"Error when attempting to reduce precision of linear ring";
1731 throw IException(IException::Programmer, msg, _FILEINFO_);
1736 geos::geom::LinearRing *tmp = Despike(newRing);
1743 if(!newRing->isValid()) {
1744 IString msg =
"Failed when attempting to reduce precision of linear ring";
1745 throw IException(IException::Programmer, msg, _FILEINFO_);
1761 geos::geom::Coordinate *PolygonTools::ReducePrecision(
const geos::geom::Coordinate *coord,
1762 unsigned int precision) {
1763 return new geos::geom::Coordinate(
1764 ReducePrecision(coord->x, precision),
1765 ReducePrecision(coord->y, precision),
1766 ReducePrecision(coord->z, precision)
1780 double PolygonTools::ReducePrecision(
double num,
unsigned int precision) {
1781 double result = num;
1785 int decimalPlace = DecimalPlace(num);
1786 double factor = pow(10.0, (
int)decimalPlace);
1789 double reducedNum = num / factor;
1791 double cutoff = pow(10.0, (
int)precision);
1792 double round_offset = (num < 0) ? -0.5 : 0.5;
1795 reducedNum = ((
long long)(reducedNum * cutoff + round_offset)) / cutoff;
1796 result = reducedNum * factor;
1811 QString PolygonTools::GetGeometryName(
const geos::geom::Geometry *geom) {
1812 switch(geom->getGeometryTypeId()) {
1813 case geos::geom::GEOS_POINT:
1815 case geos::geom::GEOS_LINESTRING:
1816 return "Line String";
1817 case geos::geom::GEOS_LINEARRING:
1818 return "Linear Ring";
1819 case geos::geom::GEOS_POLYGON:
1821 case geos::geom::GEOS_MULTIPOINT:
1822 return "Multi Point";
1823 case geos::geom::GEOS_MULTILINESTRING:
1824 return "Multi Line String";
1825 case geos::geom::GEOS_MULTIPOLYGON:
1826 return "Multi Polygon";
1827 case geos::geom::GEOS_GEOMETRYCOLLECTION:
1828 return "Geometry Collection";
1835 bool PolygonTools::Equal(
const geos::geom::MultiPolygon *poly1,
1836 const geos::geom::MultiPolygon *poly2) {
1838 vector<const geos::geom::Polygon *> polys1;
1839 vector<const geos::geom::Polygon *> polys2;
1841 if(poly1->getNumGeometries() != poly2->getNumGeometries())
return false;
1844 for(
unsigned int geomIndex = 0; geomIndex < poly1->getNumGeometries(); geomIndex ++) {
1845 polys1.push_back(
dynamic_cast<const geos::geom::Polygon *
>(
1846 poly1->getGeometryN(geomIndex)));
1847 polys2.push_back(
dynamic_cast<const geos::geom::Polygon *
>(
1848 poly2->getGeometryN(geomIndex)));
1851 for(
int p1 = polys1.size() - 1; (p1 >= 0) && polys1.size(); p1 --) {
1852 for(
int p2 = polys2.size() - 1; (p2 >= 0) && polys2.size(); p2 --) {
1853 if(Equal(polys1[p1], polys2[p2])) {
1855 polys1[p1] = polys1[polys1.size()-1];
1856 polys1.resize(polys1.size() - 1);
1858 polys2[p2] = polys2[polys2.size()-1];
1859 polys2.resize(polys2.size() - 1);
1864 return (polys1.size() == 0) && (polys2.size() == 0);
1868 bool PolygonTools::Equal(
const geos::geom::Polygon *poly1,
const geos::geom::Polygon *poly2) {
1869 vector<const geos::geom::LineString *> holes1;
1870 vector<const geos::geom::LineString *> holes2;
1872 if(poly1->getNumInteriorRing() != poly2->getNumInteriorRing())
return false;
1874 if(!Equal(poly1->getExteriorRing(), poly2->getExteriorRing()))
return false;
1877 for(
unsigned int holeIndex = 0; holeIndex < poly1->getNumInteriorRing(); holeIndex ++) {
1880 if(poly1->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1881 holes1.push_back(poly1->getInteriorRingN(holeIndex));
1884 if(poly2->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1885 holes2.push_back(poly2->getInteriorRingN(holeIndex));
1890 if(holes1.size() != holes2.size())
return false;
1892 for(
int h1 = holes1.size() - 1; (h1 >= 0) && holes1.size(); h1 --) {
1893 for(
int h2 = holes2.size() - 1; (h2 >= 0) && holes2.size(); h2 --) {
1894 if(Equal(holes1[h1], holes2[h2])) {
1896 holes1[h1] = holes1[holes1.size()-1];
1897 holes1.resize(holes1.size() - 1);
1899 holes2[h2] = holes2[holes2.size()-1];
1900 holes2.resize(holes2.size() - 1);
1905 return (holes1.size() == 0) && (holes2.size() == 0);
1909 bool PolygonTools::Equal(
const geos::geom::LineString *lineString1,
1910 const geos::geom::LineString *lineString2) {
1912 geos::geom::CoordinateSequence *coords1 = lineString1->getCoordinates();
1913 geos::geom::CoordinateSequence *coords2 = lineString2->getCoordinates();
1914 bool isEqual =
true;
1916 if(coords1->getSize() != coords2->getSize()) isEqual =
false;
1918 unsigned int index1 = 0;
1919 unsigned int index2 = 0;
1922 for(; index2 < coords2->getSize() - 1 && isEqual; index2 ++) {
1923 if(Equal(coords1->getAt(index1), coords2->getAt(index2)))
break;
1926 if(index2 == coords2->getSize() - 1) isEqual =
false;
1928 for(; index1 < coords1->getSize() - 1 && isEqual; index1 ++, index2 ++) {
1929 if(!Equal(coords1->getAt(index1), coords2->getAt(index2 % (coords2->getSize() - 1)))) {
1940 bool PolygonTools::Equal(
const geos::geom::Coordinate &coord1,
1941 const geos::geom::Coordinate &coord2) {
1943 if(!Equal(coord1.x, coord2.x))
return false;
1944 if(!Equal(coord1.y, coord2.y))
return false;
1945 if(!Equal(coord1.y, coord2.y))
return false;
1951 bool PolygonTools::Equal(
const double d1,
const double d2) {
1952 const double cutoff = 1e15;
1954 if(DecimalPlace(d1) != DecimalPlace(d2))
return false;
1956 int decimalPlace = DecimalPlace(d1);
1957 double factor = pow(10.0, (
int)decimalPlace);
1960 double reducedNum = d1 / factor;
1962 double round_offset = (d1 < 0) ? -0.5 : 0.5;
1965 long long num1 = ((
long long)(reducedNum * cutoff + round_offset));
1967 factor = pow(10.0, (
int)decimalPlace);
1970 reducedNum = d2 / factor;
1972 round_offset = (d2 < 0) ? -0.5 : 0.5;
1975 long long num2 = ((
long long)(reducedNum * cutoff + round_offset));
1978 return (num1 == num2);
1996 geos::geom::MultiPolygon *PolygonTools::SplitPolygonOn360(
const geos::geom::Polygon *inPoly) {
1997 bool convertLon =
false;
1998 bool negAdjust =
false;
1999 bool newCoords =
false;
2000 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2002 double lonOffset = 0;
2003 geos::geom::CoordinateSequence *inPolyCoords = inPoly->getCoordinates();
2004 double prevLon = inPolyCoords->getAt(0).x;
2005 double prevLat = inPolyCoords->getAt(0).y;
2007 newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat));
2009 for (
unsigned int i = 1; i < inPolyCoords->getSize(); i++) {
2010 lon = inPolyCoords->getAt(i).x;
2011 lat = inPolyCoords->getAt(i).y;
2013 if (abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) {
2021 if ((lon - prevLon) > 0) {
2025 else if ((lon - prevLon) < 0) {
2034 if (newCoords && dist == 0.0) {
2035 double longitude = (lon + lonOffset) - prevLon;
2036 double latitude = lat - prevLat;
2037 dist = std::sqrt((longitude * longitude) + (latitude * latitude));
2041 newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat));
2048 delete inPolyCoords;
2052 geos::geom::Polygon *newPoly = globalFactory->createPolygon
2053 (globalFactory->createLinearRing(newLonLatPts), NULL);
2054 geos::geom::MultiPolygon *multi_polygon = PolygonTools::MakeMultiPolygon(newPoly);
2055 delete newLonLatPts;
2056 return multi_polygon;
2061 geos::geom::Polygon *newPoly = globalFactory->createPolygon
2062 (globalFactory->createLinearRing(newLonLatPts), NULL);
2064 geos::geom::CoordinateSequence *pts =
new geos::geom::CoordinateArraySequence();
2065 geos::geom::CoordinateSequence *pts2 =
new geos::geom::CoordinateArraySequence();
2073 pts->add(geos::geom::Coordinate(0., 90.));
2074 pts->add(geos::geom::Coordinate(-360., 90.));
2075 pts->add(geos::geom::Coordinate(-360., -90.));
2076 pts->add(geos::geom::Coordinate(0., -90.));
2077 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2078 pts->add(geos::geom::Coordinate(0.0, lat));
2080 pts->add(geos::geom::Coordinate(0., 90.));
2081 pts2->add(geos::geom::Coordinate(0., 90.));
2082 pts2->add(geos::geom::Coordinate(360., 90.));
2083 pts2->add(geos::geom::Coordinate(360., -90.));
2084 pts2->add(geos::geom::Coordinate(0., -90.));
2085 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2086 pts2->add(geos::geom::Coordinate(0.0, lat));
2088 pts2->add(geos::geom::Coordinate(0., 90.));
2091 pts->add(geos::geom::Coordinate(360., 90.));
2092 pts->add(geos::geom::Coordinate(720., 90.));
2093 pts->add(geos::geom::Coordinate(720., -90.));
2094 pts->add(geos::geom::Coordinate(360., -90.));
2095 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2096 pts->add(geos::geom::Coordinate(360.0, lat));
2098 pts->add(geos::geom::Coordinate(360., 90.));
2099 pts2->add(geos::geom::Coordinate(360., 90.));
2100 pts2->add(geos::geom::Coordinate(0., 90.));
2101 pts2->add(geos::geom::Coordinate(0., -90.));
2102 pts2->add(geos::geom::Coordinate(360., -90.));
2103 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2104 pts2->add(geos::geom::Coordinate(360.0, lat));
2106 pts2->add(geos::geom::Coordinate(360., 90.));
2109 geos::geom::Polygon *boundaryPoly = globalFactory->createPolygon
2110 (globalFactory->createLinearRing(pts), NULL);
2111 geos::geom::Polygon *boundaryPoly2 = globalFactory->createPolygon
2112 (globalFactory->createLinearRing(pts2), NULL);
2118 geos::geom::Geometry *intersection = PolygonTools::Intersect(newPoly, boundaryPoly);
2119 geos::geom::MultiPolygon *convertPoly = PolygonTools::MakeMultiPolygon(intersection);
2120 delete intersection;
2122 intersection = PolygonTools::Intersect(newPoly, boundaryPoly2);
2123 geos::geom::MultiPolygon *convertPoly2 = PolygonTools::MakeMultiPolygon(intersection);
2124 delete intersection;
2131 vector<geos::geom::Geometry *> *finalpolys =
new vector<geos::geom::Geometry *>;
2132 geos::geom::Geometry *newGeom = NULL;
2134 for (
unsigned int i = 0; i < convertPoly->getNumGeometries(); i++) {
2135 newGeom = (convertPoly->getGeometryN(i))->clone();
2136 pts = convertPoly->getGeometryN(i)->getCoordinates();
2137 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2140 for (
unsigned int k = 0; k < pts->getSize() ; k++) {
2141 double lon = pts->getAt(k).x;
2142 double lat = pts->getAt(k).y;
2149 newLonLatPts->add(geos::geom::Coordinate(lon, lat), k);
2153 finalpolys->push_back(globalFactory->createPolygon
2154 (globalFactory->createLinearRing(newLonLatPts), NULL));
2158 for (
unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) {
2159 newGeom = (convertPoly2->getGeometryN(i))->clone();
2160 finalpolys->push_back(newGeom);
2163 geos::geom::MultiPolygon *multi_polygon = globalFactory->createMultiPolygon(*finalpolys);
2167 delete newLonLatPts;
2170 return multi_polygon;
2172 catch(geos::util::IllegalArgumentException *geosIll) {
2173 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2174 msg +=
"geos illegal argument [" +
IString(geosIll->what()) +
"]";
2176 throw IException(IException::Unknown, msg, _FILEINFO_);
2178 catch(geos::util::GEOSException *geosExc) {
2179 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2180 msg +=
"geos exception [" +
IString(geosExc->what()) +
"]";
2182 throw IException(IException::Unknown, msg, _FILEINFO_);
2185 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2186 msg +=
"isis operation exception [" +
IString(e.
what()) +
"]";
2187 throw IException(e, IException::Unknown, msg, _FILEINFO_);
2190 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2191 msg +=
"unknown exception";
2192 throw IException(IException::Unknown, msg, _FILEINFO_);