33 #include "geos/geom/BinaryOp.h"
34 #include "geos/geom/CoordinateArraySequence.h"
35 #include "geos/geom/CoordinateSequence.h"
36 #include "geos/geom/LinearRing.h"
37 #include "geos/geom/Point.h"
38 #include "geos/geom/Polygon.h"
39 #include "geos/operation/distance/DistanceOp.h"
40 #include "geos/opOverlay.h"
41 #include "geos/operation/overlay/snap/GeometrySnapper.h"
63 geos::geom::MultiPolygon *PolygonTools::LatLonToXY(
64 const geos::geom::MultiPolygon &lonLatPolygon,
TProjection *projection) {
65 if (projection == NULL) {
66 string msg =
"Unable to convert Lon/Lat polygon to X/Y. ";
67 msg +=
"No projection has was supplied";
72 if(lonLatPolygon.isEmpty()) {
73 return globalFactory.createMultiPolygon();
76 vector<geos::geom::Geometry *> *xyPolys =
new vector<geos::geom::Geometry *>;
78 for(
unsigned int g = 0; g < lonLatPolygon.getNumGeometries(); ++g) {
79 const geos::geom::Polygon *poly =
80 dynamic_cast<const geos::geom::Polygon *
>(
81 lonLatPolygon.getGeometryN(g));
84 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
85 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
86 geos::geom::CoordinateSequence *xycoords =
new geos::geom::CoordinateArraySequence();
87 geos::geom::CoordinateSequence *llcoords =
88 poly->getInteriorRingN(h)->getCoordinates();
91 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
92 projection->
SetGround(llcoords->getAt(cord).y,
93 llcoords->getAt(cord).x);
94 xycoords->add(geos::geom::Coordinate(projection->
XCoord(),
98 geos::geom::LinearRing *hole = globalFactory.createLinearRing(xycoords);
100 if(hole->isValid() && !hole->isEmpty()) {
101 holes->push_back(hole);
109 geos::geom::CoordinateSequence *xycoords =
new geos::geom::CoordinateArraySequence();
110 geos::geom::CoordinateSequence *llcoords =
111 poly->getExteriorRing()->getCoordinates();
114 for (
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
115 projection->
SetGround(llcoords->getAt(cord).y,
116 llcoords->getAt(cord).x);
117 xycoords->add(geos::geom::Coordinate(projection->
XCoord(),
121 geos::geom::Polygon *newPoly = globalFactory.createPolygon(
122 globalFactory.createLinearRing(xycoords), holes);
124 if(newPoly->isValid() && !newPoly->isEmpty() && newPoly->getArea() > 1.0e-14) {
125 xyPolys->push_back(newPoly);
133 geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(xyPolys);
135 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
140 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
148 IString msg =
"Unable to convert polygon from Lat/Lon to X/Y";
169 geos::geom::MultiPolygon *PolygonTools::XYToLatLon(
170 const geos::geom::MultiPolygon &xYPolygon,
TProjection *projection) {
172 if(projection == NULL) {
173 string msg =
"Unable to convert X/Y polygon to Lon/Lat. ";
174 msg +=
"No projection was supplied";
179 if(xYPolygon.isEmpty()) {
180 return globalFactory.createMultiPolygon();
183 vector<geos::geom::Geometry *> *llPolys =
new vector<geos::geom::Geometry *>;
185 for(
unsigned int g = 0; g < xYPolygon.getNumGeometries(); ++g) {
186 const geos::geom::Polygon *poly =
187 dynamic_cast<const geos::geom::Polygon *
>(
188 xYPolygon.getGeometryN(g));
191 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
192 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
193 geos::geom::CoordinateSequence *llcoords =
new geos::geom::CoordinateArraySequence();
194 geos::geom::CoordinateSequence *xycoords =
195 poly->getInteriorRingN(h)->getCoordinates();
198 for(
unsigned int cord = 0; cord < xycoords->getSize(); ++cord) {
199 projection->
SetWorld(xycoords->getAt(cord).x,
200 xycoords->getAt(cord).y);
201 llcoords->add(geos::geom::Coordinate(projection->
Longitude(),
204 holes->push_back(globalFactory.createLinearRing(llcoords));
208 geos::geom::CoordinateSequence *llcoords =
new geos::geom::DefaultCoordinateSequence();
209 geos::geom::CoordinateSequence *xycoords =
210 poly->getExteriorRing()->getCoordinates();
213 for(
unsigned int cord = 0; cord < xycoords->getSize(); ++cord) {
214 projection->
SetWorld(xycoords->getAt(cord).x,
215 xycoords->getAt(cord).y);
216 llcoords->add(geos::geom::Coordinate(projection->
Longitude(),
220 llPolys->push_back(globalFactory.createPolygon(
221 globalFactory.createLinearRing(llcoords), holes));
226 geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(llPolys);
228 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
233 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
241 IString msg =
"Unable to convert polygon from X/Y to Lat/Lon";
261 geos::geom::MultiPolygon *PolygonTools::LatLonToSampleLine(
265 string msg =
"Unable to convert Lon/Lat polygon to Sample/Line. ";
266 msg +=
"No UniversalGroundMap was supplied";
271 if(lonLatPolygon.isEmpty()) {
272 return globalFactory.createMultiPolygon();
275 vector<geos::geom::Geometry *> *slPolys =
new vector<geos::geom::Geometry *>;
277 for(
unsigned int g = 0; g < lonLatPolygon.getNumGeometries(); g++) {
278 const geos::geom::Polygon *poly =
279 dynamic_cast<const geos::geom::Polygon *
>(
280 lonLatPolygon.getGeometryN(g));
283 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
284 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
285 geos::geom::CoordinateSequence *slcoords =
new geos::geom::DefaultCoordinateSequence();
286 geos::geom::CoordinateSequence *llcoords =
287 poly->getInteriorRingN(h)->getCoordinates();
290 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
292 llcoords->getAt(cord).x);
293 slcoords->add(geos::geom::Coordinate(ugm->
Sample(),
296 holes->push_back(globalFactory.createLinearRing(slcoords));
302 geos::geom::CoordinateSequence *slcoords =
new geos::geom::CoordinateArraySequence();
303 geos::geom::CoordinateSequence *llcoords =
304 poly->getExteriorRing()->getCoordinates();
307 for(
unsigned int cord = 0; cord < llcoords->getSize(); ++cord) {
309 llcoords->getAt(cord).x)) {
310 slcoords->add(geos::geom::Coordinate(ugm->
Sample(),
316 if (slcoords->getSize() > 0 && !slcoords->front().equals(slcoords->back())) {
317 slcoords->add(slcoords->front());
321 slPolys->push_back(globalFactory.createPolygon(
322 globalFactory.createLinearRing(slcoords), holes));
324 catch (std::exception &e) {
326 QObject::tr(
"Unable to convert polygon from Lat/Lon to Sample/Line. The "
327 "error given was [%1].").arg(e.what()),
335 geos::geom::MultiPolygon *spikedPoly = globalFactory.createMultiPolygon(slPolys);
337 if(spikedPoly->isValid() && !spikedPoly->isEmpty()) {
342 geos::geom::MultiPolygon *despikedPoly = Despike(spikedPoly);
350 IString msg =
"Unable to convert polygon from Lat/Lon to Sample/Line";
370 geos::geom::MultiPolygon *PolygonTools::CopyMultiPolygon(
const geos::geom::MultiPolygon *mpolygon) {
372 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
373 for(
unsigned int i = 0; i < mpolygon->getNumGeometries(); ++i) {
374 polys->push_back((mpolygon->getGeometryN(i))->clone());
376 return globalFactory.createMultiPolygon(polys);
392 geos::geom::MultiPolygon *PolygonTools::CopyMultiPolygon(
const geos::geom::MultiPolygon &mpolygon) {
394 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
395 for(
unsigned int i = 0; i < mpolygon.getNumGeometries(); ++i) {
396 polys->push_back((mpolygon.getGeometryN(i))->clone());
398 return globalFactory.createMultiPolygon(polys);
410 QString PolygonTools::ToGML(
const geos::geom::MultiPolygon *mpolygon, QString idString,
416 os <<
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" << endl;
417 os <<
"<ogr:FeatureCollection" << endl;
418 os <<
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl;
419 os <<
" xsi:schemaLocation=\"http://ogr.maptools.org/ " << schema <<
"\"" << endl;
420 os <<
" xmlns:ogr=\"http://ogr.maptools.org/\"" << endl;
421 os <<
" xmlns:gml=\"http://www.opengis.net/gml\">" << endl;
422 os <<
" <gml:boundedBy>" << endl;
423 os <<
" <gml:Box>" << endl;
424 os <<
" <gml:coord>";
426 setprecision(15) << mpolygon->getEnvelopeInternal()->getMinX() <<
429 setprecision(15) << mpolygon->getEnvelopeInternal()->getMinY() <<
431 os <<
"</gml:coord>" << endl;
432 os <<
" <gml:coord>";
434 setprecision(15) << mpolygon->getEnvelopeInternal()->getMaxX() <<
437 setprecision(15) << mpolygon->getEnvelopeInternal()->getMaxY() <<
439 os <<
"</gml:coord>" << endl;
440 os <<
" </gml:Box>" << endl;
441 os <<
" </gml:boundedBy>" << endl << endl;
442 os <<
" <gml:featureMember>" << endl;
443 os <<
" <ogr:multi_polygon fid=\"0\">" << endl;
444 os <<
" <ogr:ID>" << idString <<
"</ogr:ID>" << endl;
445 os <<
" <ogr:geometryProperty><gml:MultiPolygon><gml:polygonMember>" <<
446 "<gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>";
449 for(
unsigned int polyN = 0; polyN < mpolygon->getNumGeometries(); polyN++) {
450 geos::geom::CoordinateSequence *pts = mpolygon->getGeometryN(polyN)->getCoordinates();
452 for(
unsigned int i = 0; i < pts->getSize(); i++) {
453 double lon = pts->getAt(i).x;
454 double lat = pts->getAt(i).y;
456 os << setprecision(15) << lon <<
"," << setprecision(15) << lat <<
" ";
460 os <<
"</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs>" <<
461 "</gml:Polygon></gml:polygonMember></gml:MultiPolygon>" <<
462 "</ogr:geometryProperty>" << endl;
463 os <<
" </ogr:multi_polygon>" << endl;
464 os <<
" </gml:featureMember>" << endl;
465 os <<
"</ogr:FeatureCollection>";
467 return os.str().c_str();
477 QString PolygonTools::GMLSchema() {
481 os <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
482 os <<
"<xs:schema targetNamespace=\"http://ogr.maptools.org/\" "
483 "xmlns:ogr=\"http://ogr.maptools.org/\" "
484 "xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "
485 "xmlns:gml=\"http://www.opengis.net/gml\" "
486 "elementFormDefault=\"qualified\" "
487 "version=\"1.0\">" << endl;
488 os <<
" <xs:import namespace=\"http://www.opengis.net/gml\" "
489 "schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/>" << endl;
490 os <<
" <xs:element name=\"FeatureCollection\" "
491 "type=\"ogr:FeatureCollectionType\" "
492 "substitutionGroup=\"gml:_FeatureCollection\"/>" << endl;
493 os <<
" <xs:complexType name=\"FeatureCollectionType\">" << endl;
494 os <<
" <xs:complexContent>" << endl;
495 os <<
" <xs:extension base=\"gml:AbstractFeatureCollectionType\">" << endl;
496 os <<
" <xs:attribute name=\"lockId\" type=\"xs:string\" use=\"optional\"/>" << endl;
497 os <<
" <xs:attribute name=\"scope\" type=\"xs:string\" use=\"optional\"/>" << endl;
498 os <<
" </xs:extension>" << endl;
499 os <<
" </xs:complexContent>" << endl;
500 os <<
" </xs:complexType>" << endl;
501 os <<
" <xs:element name=\"multi_polygon\" "
502 "type=\"ogr:multi_polygon_Type\" "
503 "substitutionGroup=\"gml:_Feature\"/>" << endl;
504 os <<
" <xs:complexType name=\"multi_polygon_Type\">" << endl;
505 os <<
" <xs:complexContent>" << endl;
506 os <<
" <xs:extension base=\"gml:AbstractFeatureType\">" << endl;
507 os <<
" <xs:sequence>" << endl;
508 os <<
" <xs:element name=\"geometryProperty\" "
509 "type=\"gml:MultiPolygonPropertyType\" "
510 "nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\"/>" << endl;
511 os <<
" <xs:element name=\"fid\" nillable=\"true\" minOccurs=\"0\" "
512 "maxOccurs=\"1\">" << endl;
513 os <<
" <xs:simpleType>" << endl;
514 os <<
" <xs:restriction base=\"xs:string\">" << endl;
515 os <<
" </xs:restriction>" << endl;
516 os <<
" </xs:simpleType>" << endl;
517 os <<
" </xs:element>" << endl;
518 os <<
" <xs:element name=\"ID\" nillable=\"true\" minOccurs=\"0\" "
519 "maxOccurs=\"1\">" << endl;
520 os <<
" <xs:simpleType>" << endl;
521 os <<
" <xs:restriction base=\"xs:integer\">" << endl;
522 os <<
" <xs:totalDigits value=\"16\"/>" << endl;
523 os <<
" </xs:restriction>" << endl;
524 os <<
" </xs:simpleType>" << endl;
525 os <<
" </xs:element>" << endl;
526 os <<
" </xs:sequence>" << endl;
527 os <<
" </xs:extension>" << endl;
528 os <<
" </xs:complexContent>" << endl;
529 os <<
" </xs:complexType>" << endl;
530 os <<
"</xs:schema>";
532 return os.str().c_str();
543 geos::geom::MultiPolygon *PolygonTools::To180(geos::geom::MultiPolygon *poly360) {
551 geos::geom::CoordinateArraySequence *leftOf180Pts =
552 new geos::geom::CoordinateArraySequence();
553 leftOf180Pts->add(geos::geom::Coordinate(0, -90));
554 leftOf180Pts->add(geos::geom::Coordinate(0, 90));
555 leftOf180Pts->add(geos::geom::Coordinate(180, 90));
556 leftOf180Pts->add(geos::geom::Coordinate(180, -90));
557 leftOf180Pts->add(geos::geom::Coordinate(0, -90));
559 geos::geom::LinearRing *leftOf180Geom =
560 globalFactory.createLinearRing(leftOf180Pts);
562 geos::geom::Polygon *leftOf180Poly =
563 globalFactory.createPolygon(leftOf180Geom, NULL);
565 geos::geom::CoordinateArraySequence *rightOf180Pts =
566 new geos::geom::CoordinateArraySequence();
567 rightOf180Pts->add(geos::geom::Coordinate(180, -90));
568 rightOf180Pts->add(geos::geom::Coordinate(180, 90));
569 rightOf180Pts->add(geos::geom::Coordinate(360, 90));
570 rightOf180Pts->add(geos::geom::Coordinate(360, -90));
571 rightOf180Pts->add(geos::geom::Coordinate(180, -90));
573 geos::geom::LinearRing *rightOf180Geom =
574 globalFactory.createLinearRing(rightOf180Pts);
576 geos::geom::Polygon *rightOf180Poly =
577 globalFactory.createPolygon(rightOf180Geom, NULL);
579 geos::geom::Geometry *preserved = Intersect(leftOf180Poly, poly360);
580 geos::geom::Geometry *moving = Intersect(rightOf180Poly, poly360);
582 geos::geom::CoordinateSequence *movingPts = moving->getCoordinates();
583 geos::geom::CoordinateSequence *movedPts =
584 new geos::geom::CoordinateArraySequence();
586 for(
unsigned int i = 0; i < movingPts->getSize(); i ++) {
587 movedPts->add(geos::geom::Coordinate(movingPts->getAt(i).x - 360.0,
588 movingPts->getAt(i).y));
591 if(movedPts->getSize()) {
592 movedPts->add(geos::geom::Coordinate(movedPts->getAt(0).x,
593 movedPts->getAt(0).y));
596 geos::geom::Geometry *moved = globalFactory.createPolygon(
597 globalFactory.createLinearRing(movedPts), NULL);
599 std::vector<geos::geom::Geometry *> *geomsForCollection =
new
600 std::vector<geos::geom::Geometry *>;
601 geomsForCollection->push_back(preserved);
602 geomsForCollection->push_back(moved);
604 geos::geom::GeometryCollection *the180Polys =
605 Isis::globalFactory.createGeometryCollection(geomsForCollection);
607 geos::geom::MultiPolygon *result = MakeMultiPolygon(the180Polys);
611 geos::geom::MultiPolygon *fixedResult = FixSeam(result);
617 catch(geos::util::GEOSException *exc) {
618 IString msg =
"Conversion to 180 failed. The reason given was [" +
624 IString msg =
"Conversion to 180 failed. Could not determine the reason";
640 double PolygonTools::Thickness(
const geos::geom::MultiPolygon *mpolygon) {
641 const geos::geom::Envelope *envelope = mpolygon->getEnvelopeInternal();
643 double x = fabs(envelope->getMaxX() - envelope->getMinX());
644 double y = fabs(envelope->getMaxY() - envelope->getMinY());
645 double extent = max(x, y);
647 return mpolygon->getArea() / (extent * extent);
662 geos::geom::MultiPolygon *PolygonTools::Despike(
const geos::geom::Geometry *geom) {
663 geos::geom::MultiPolygon *spiked = MakeMultiPolygon(geom);
664 geos::geom::MultiPolygon *despiked = Despike(spiked);
683 geos::geom::MultiPolygon *PolygonTools::Despike(
const geos::geom::MultiPolygon *multiPoly) {
685 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
686 for(
unsigned int g = 0; g < multiPoly->getNumGeometries(); ++g) {
687 const geos::geom::Polygon *poly =
688 dynamic_cast<const geos::geom::Polygon *
>(multiPoly->getGeometryN(g));
691 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
692 for(
unsigned int h = 0; h < poly->getNumInteriorRing(); ++h) {
693 const geos::geom::LineString *ls = poly->getInteriorRingN(h);
694 geos::geom::LinearRing *lr;
701 geos::geom::LinearRing *fixed = FixGeometry(lr);
708 holes->push_back(lr);
716 const geos::geom::LineString *ls = poly->getExteriorRing();
717 geos::geom::LinearRing *lr;
723 geos::geom::LinearRing *fixed = FixGeometry(lr);
731 if(ls->isValid() && ls->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
732 lr =
dynamic_cast<geos::geom::LinearRing *
>(ls->clone());
741 geos::geom::Polygon *tp = Isis::globalFactory.createPolygon(lr, holes);
743 if(tp->isEmpty() || !tp->isValid()) {
745 newPolys->push_back(poly->clone());
748 newPolys->push_back(tp);
754 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys);
756 if(!mp->isValid() || mp->isEmpty()) {
759 IString msg =
"Despike failed to correct the polygon";
764 if(fabs((mp->getArea() / multiPoly->getArea()) - 1.0) > 0.50) {
765 IString msg =
"Despike failed to correct the polygon " + mp->toString();
788 geos::geom::LinearRing *PolygonTools::Despike(
const geos::geom::LineString *lineString) {
789 geos::geom::CoordinateSequence *vertices = lineString->getCoordinates();
792 if(vertices->getSize() < 4) {
794 return Isis::globalFactory.createLinearRing(geos::geom::CoordinateArraySequence());
799 vertices->deleteAt(vertices->getSize() - 1);
804 for(
long index = 0; index < (long)vertices->getSize(); index++) {
806 if(vertices->getSize() < 3) {
812 long testCoords[3] = {
820 for(
int j = 0; j < 3; j++) {
821 while(testCoords[j] < 0) {
822 testCoords[j] += vertices->getSize();
825 while(testCoords[j] >= (
long)vertices->getSize()) {
826 testCoords[j] -= vertices->getSize();
831 if(IsSpiked(vertices->getAt(testCoords[0]),
832 vertices->getAt(testCoords[1]),
833 vertices->getAt(testCoords[2]))) {
835 vertices->deleteAt(testCoords[1]);
842 if(vertices->getSize() < 3) {
846 return Isis::globalFactory.createLinearRing(geos::geom::CoordinateArraySequence());
850 vertices->add(vertices->getAt(0));
851 return Isis::globalFactory.createLinearRing(vertices);
864 bool PolygonTools::IsSpiked(geos::geom::Coordinate first,
865 geos::geom::Coordinate middle,
866 geos::geom::Coordinate last) {
867 return TestSpiked(first, middle, last) || TestSpiked(last, middle, first);
898 bool PolygonTools::TestSpiked(geos::geom::Coordinate first, geos::geom::Coordinate middle,
899 geos::geom::Coordinate last) {
900 geos::geom::Point *firstPt = Isis::globalFactory.createPoint(first);
901 geos::geom::Point *middlePt = Isis::globalFactory.createPoint(middle);
902 geos::geom::Point *lastPt = Isis::globalFactory.createPoint(last);
904 geos::geom::CoordinateSequence *coords =
new geos::geom::CoordinateArraySequence();
907 geos::geom::LineString *line = Isis::globalFactory.createLineString(coords);
913 double tolerance = line->getLength() / 100.0;
917 double distanceLastMiddle = geos::operation::distance::DistanceOp::distance(lastPt, middlePt);
918 double distanceLastLine = geos::operation::distance::DistanceOp::distance(lastPt, line);
920 if(distanceLastMiddle == 0.0)
return true;
924 if(distanceLastLine / distanceLastMiddle >= .05) {
929 if(spiked && distanceLastLine > tolerance) {
934 geos::geom::CoordinateSequence *coords =
new geos::geom::CoordinateArraySequence();
941 geos::geom::LinearRing *shell = Isis::globalFactory.createLinearRing(coords);
942 std::vector<geos::geom::Geometry *> *empty =
new std::vector<geos::geom::Geometry *>;
945 geos::geom::Polygon *poly = Isis::globalFactory.createPolygon(shell, empty);
950 if(poly->getArea() < 1.0e-10) {
980 geos::geom::Geometry *PolygonTools::Intersect(
const geos::geom::Geometry *geom1,
981 const geos::geom::Geometry *geom2) {
983 return Operate(geom1, geom2, (
unsigned int)geos::operation::overlay::OverlayOp::opINTERSECTION);
985 catch(geos::util::GEOSException *exc) {
986 IString msg =
"Intersect operation failed. The reason given was [" +
IString(exc->what()) +
"]";
991 IString msg =
"Intersect operation failed";
995 IString msg =
"Intersect operation failed for an unknown reason";
1001 geos::geom::Geometry *PolygonTools::Operate(
const geos::geom::Geometry *geom1,
1002 const geos::geom::Geometry *geom2,
1003 unsigned int opcode) {
1005 geos::operation::overlay::OverlayOp::OpCode code =
1006 (geos::operation::overlay::OverlayOp::OpCode)opcode;
1008 geos::geom::Geometry *result = NULL;
1010 geos::geom::Geometry *geomFirst = MakeMultiPolygon(geom1);
1011 geos::geom::Geometry *geomSecond = MakeMultiPolygon(geom2);
1013 geos::operation::overlay::snap::GeometrySnapper snap(*geomFirst);
1014 geos::geom::Geometry *geomSnapped = snap.snapTo(*geomSecond, 1.0e-10)->clone();
1015 if(!geomSnapped->isValid()) {
1020 geomFirst = geomSnapped;
1023 unsigned int precision = 15;
1024 unsigned int minPrecision = 13;
1027 std::auto_ptr< geos::geom::Geometry > resultAuto =
1028 BinaryOp(geomFirst, geomSecond, geos::operation::overlay::overlayOp(code));
1030 result = resultAuto->clone();
1032 catch(geos::util::GEOSException *exc) {
1034 if(!failed || precision == minPrecision)
throw;
1039 if(precision == minPrecision) {
1040 IString msg =
"An unknown geos error occurred";
1041 throw IException(IException::Programmer, msg,
_FILEINFO_);
1045 IString msg =
"An unknown geos error occurred when attempting to clone a geometry";
1046 throw IException(IException::Programmer, msg,
_FILEINFO_);
1053 geos::geom::Geometry *tmp = ReducePrecision(geomFirst, precision);
1057 tmp = ReducePrecision(geomSecond, precision);
1069 if(result && !result->isValid()) {
1071 geos::geom::Geometry *newResult = FixGeometry(result);
1073 if(fabs(newResult->getArea() / result->getArea() - 1.0) > 0.50) {
1077 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1078 throw IException(IException::Programmer, msg,
_FILEINFO_);
1084 catch(IException &e) {
1085 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1086 throw IException(IException::Programmer, msg,
_FILEINFO_);
1090 if(result == NULL) {
1091 IString msg =
"Operation [" + IString((
int)opcode) +
" failed";
1092 throw IException(IException::Programmer, msg,
_FILEINFO_);
1108 geos::geom::Geometry *PolygonTools::FixGeometry(
const geos::geom::Geometry *geom) {
1109 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1110 return FixGeometry(dynamic_cast<const geos::geom::MultiPolygon *>(geom));
1112 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1113 return FixGeometry(dynamic_cast<const geos::geom::LinearRing *>(geom));
1115 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1116 return FixGeometry(dynamic_cast<const geos::geom::Polygon *>(geom));
1118 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1119 return FixGeometry(MakeMultiPolygon(geom));
1122 IString msg =
"PolygonTools::FixGeometry does not support [" + GetGeometryName(geom) +
"]";
1136 geos::geom::MultiPolygon *PolygonTools::FixGeometry(
const geos::geom::MultiPolygon *poly) {
1138 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1141 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1142 geos::geom::Polygon *fixedpoly = FixGeometry(
1143 dynamic_cast<const geos::geom::Polygon *>(
1144 poly->getGeometryN(geomIndex)));
1145 if(fixedpoly->isValid()) {
1146 newPolys->push_back(fixedpoly);
1154 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys);
1159 geos::geom::Polygon *PolygonTools::FixGeometry(
const geos::geom::Polygon *poly) {
1162 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1163 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1164 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1167 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1168 holes->push_back(thisHole->clone());
1173 geos::geom::LinearRing *newHole = FixGeometry((geos::geom::LinearRing *)thisHole);
1174 holes->push_back(newHole);
1176 catch (IException &e) {
1177 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1178 throw IException(IException::Programmer, msg,
_FILEINFO_);
1183 const geos::geom::LineString *exterior = poly->getExteriorRing();
1186 geos::geom::LinearRing *newExterior = NULL;
1188 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1189 newExterior = FixGeometry((geos::geom::LinearRing *)exterior);
1192 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior "
1193 "ring is not simple and closed";
1194 throw IException(IException::Programmer, msg,
_FILEINFO_);
1197 return globalFactory.createPolygon(newExterior, holes);
1199 catch (IException &e) {
1200 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1201 throw IException(e, IException::Programmer, msg,
_FILEINFO_);
1221 geos::geom::LinearRing *PolygonTools::FixGeometry(
const geos::geom::LinearRing *ring) {
1223 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1226 if(coords->getSize() < 4) {
1227 return globalFactory.createLinearRing(
new geos::geom::DefaultCoordinateSequence());
1230 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1231 const geos::geom::Coordinate *lastCoordinate = &coords->getAt(0);
1232 newCoords->add(*lastCoordinate);
1235 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1236 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1241 double difference[2] = {
1242 lastCoordinate->x - thisCoordinate->x,
1243 lastCoordinate->y - thisCoordinate->y,
1247 double minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1249 minDiff = min(minDiff, fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1])));
1253 if(difference[0] == 0.0 && difference[1] != 0.0) {
1255 minDiff = fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1]));
1257 else if(difference[1] == 0.0 && difference[0] != 0.0) {
1259 minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1261 else if(difference[0] == 0.0 && difference[1] == 0.0) {
1268 newCoords->add(*thisCoordinate);
1269 lastCoordinate = thisCoordinate;
1273 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1274 geos::geom::LinearRing *newRing = NULL;
1278 if(newCoords->getSize() > 3) {
1279 newRing = globalFactory.createLinearRing(newCoords);
1286 catch(geos::util::GEOSException *exc) {
1290 IString msg =
"Error when attempting to fix linear ring";
1294 if(newRing && !newRing->isValid() && ring->isValid()) {
1295 IString msg =
"Failed when attempting to fix linear ring";
1298 else if(!newRing || !newRing->isValid()) {
1303 newRing =
dynamic_cast<geos::geom::LinearRing *
>(ring->clone());
1321 int PolygonTools::DecimalPlace(
double num) {
1323 if(num == 0.0)
return 0;
1327 int decimalPlace = 1;
1338 return decimalPlace;
1349 geos::geom::Geometry *PolygonTools::Difference(
const geos::geom::Geometry *geom1,
1350 const geos::geom::Geometry *geom2) {
1352 return Operate(geom1, geom2, (
unsigned int)geos::operation::overlay::OverlayOp::opDIFFERENCE);
1354 catch(geos::util::GEOSException *exc) {
1355 IString msg =
"Difference operation failed. The reason given was [" +
1361 IString msg =
"Difference operation failed";
1365 IString msg =
"Difference operation failed for an unknown reason";
1384 geos::geom::MultiPolygon *PolygonTools::MakeMultiPolygon(
const geos::geom::Geometry *geom) {
1386 if(geom->isEmpty()) {
1387 return Isis::globalFactory.createMultiPolygon();
1390 else if(geom->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1391 return Isis::globalFactory.createMultiPolygon();
1394 else if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1395 return dynamic_cast<geos::geom::MultiPolygon *
>(geom->clone());
1398 else if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1399 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
1400 polys->push_back(geom->clone());
1401 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(polys);
1405 else if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1406 vector<geos::geom::Geometry *> * polys =
1407 new vector<geos::geom::Geometry *>;
1408 const geos::geom::GeometryCollection *gc =
1409 dynamic_cast<const geos::geom::GeometryCollection *
>(geom);
1410 for(
unsigned int i = 0; i < gc->getNumGeometries(); ++i) {
1411 geos::geom::MultiPolygon *subMultiPoly =
1412 MakeMultiPolygon(gc->getGeometryN(i));
1414 for(
unsigned int subPoly = 0;
1415 subPoly < subMultiPoly->getNumGeometries();
1417 const geos::geom::Polygon *poly =
1418 dynamic_cast<const geos::geom::Polygon *
>(
1419 subMultiPoly->getGeometryN(subPoly));
1420 polys->push_back(dynamic_cast<geos::geom::Polygon *>(poly->clone()));
1424 geos::geom::MultiPolygon *mp =
1425 Isis::globalFactory.createMultiPolygon(polys);
1426 if(mp->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1428 mp = Isis::globalFactory.createMultiPolygon();
1436 return Isis::globalFactory.createMultiPolygon();
1441 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1442 const geos::geom::Polygon *polyA,
const geos::geom::Polygon *polyB) {
1443 geos::geom::CoordinateSequence *polyAPoints = polyA->getCoordinates();
1444 geos::geom::CoordinateSequence *polyBPoints = polyB->getCoordinates();
1446 unsigned int aIntersectionBegin = 0;
1447 unsigned int aIntersectionEnd = 0;
1448 unsigned int bIntersectionBegin = 0;
1449 unsigned int bIntersectionEnd = 0;
1451 bool intersectionStarted =
false;
1452 bool intersectionEnded =
false;
1454 unsigned int lastBMatch = 0;
1455 for (
unsigned int i = 0;
1456 !intersectionEnded && i < polyAPoints->getSize();
1459 bool foundEquivalent =
false;
1461 geos::geom::Coordinate coordA = polyAPoints->getAt(i);
1462 coordA = *ReducePrecision(&coordA, 13);
1464 for (
unsigned int j = 0;
1465 !foundEquivalent && j < polyBPoints->getSize();
1467 geos::geom::Coordinate coordB = polyBPoints->getAt(j);
1468 coordB = *ReducePrecision(&coordB, 13);
1470 foundEquivalent = coordA.equals(coordB);
1472 if (foundEquivalent) lastBMatch = j;
1474 if (foundEquivalent && !intersectionStarted) {
1475 intersectionStarted =
true;
1476 aIntersectionBegin = i;
1477 bIntersectionBegin = j;
1481 if (!foundEquivalent && intersectionStarted && !intersectionEnded) {
1482 intersectionEnded =
true;
1483 aIntersectionEnd = i;
1484 bIntersectionEnd = lastBMatch;
1488 geos::geom::MultiPolygon * result = NULL;
1489 if (intersectionStarted && intersectionEnded) {
1490 geos::geom::CoordinateSequence *merged =
1491 new geos::geom::CoordinateArraySequence;
1494 for (i = 0; i < aIntersectionBegin; i ++) {
1495 merged->add(polyAPoints->getAt(i));
1498 i = bIntersectionBegin;
1499 while (i != bIntersectionEnd) {
1500 merged->add(polyBPoints->getAt(i));
1502 if (i >= polyBPoints->getSize()) i = 0;
1505 for (i = aIntersectionEnd; i < polyAPoints->getSize() - 1; i++) {
1506 merged->add(polyAPoints->getAt(i));
1509 merged->add(merged->getAt(0));
1510 result = MakeMultiPolygon(globalFactory.createPolygon(
1511 globalFactory.createLinearRing(merged), NULL));
1518 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1519 const geos::geom::MultiPolygon *poly) {
1521 std::vector<geos::geom::Geometry *> *polys =
1522 new std::vector<geos::geom::Geometry *>;
1525 for(
unsigned int copyIndex = 0;
1526 copyIndex < poly->getNumGeometries();
1528 polys->push_back(poly->getGeometryN(copyIndex)->clone());
1531 unsigned int outerPolyIndex = 0;
1533 while(outerPolyIndex + 1 < polys->size()) {
1534 unsigned int innerPolyIndex = outerPolyIndex + 1;
1536 while(innerPolyIndex < polys->size()) {
1537 geos::geom::MultiPolygon *fixedPair = FixSeam(
1538 dynamic_cast<geos::geom::Polygon *>(polys->at(outerPolyIndex)),
1539 dynamic_cast<geos::geom::Polygon *>(polys->at(innerPolyIndex)));
1541 if(fixedPair != NULL) {
1542 geos::geom::Geometry *oldInnerPoly = polys->at(innerPolyIndex);
1543 geos::geom::Geometry *oldOuterPoly = polys->at(outerPolyIndex);
1545 polys->erase(polys->begin() + innerPolyIndex);
1546 (*polys)[outerPolyIndex] = fixedPair->getGeometryN(0)->clone();
1547 innerPolyIndex = outerPolyIndex + 1;
1552 delete oldInnerPoly;
1553 oldInnerPoly = NULL;
1555 delete oldOuterPoly;
1556 oldOuterPoly = NULL;
1566 return globalFactory.createMultiPolygon(polys);
1579 geos::geom::Geometry *PolygonTools::ReducePrecision(
const geos::geom::Geometry *geom,
1580 unsigned int precision) {
1581 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1582 return ReducePrecision(
1583 dynamic_cast<const geos::geom::MultiPolygon *>(geom), precision);
1585 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1586 return ReducePrecision(
1587 dynamic_cast<const geos::geom::LinearRing *>(geom), precision);
1589 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1590 return ReducePrecision(
1591 dynamic_cast<const geos::geom::Polygon *>(geom), precision);
1593 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1594 return ReducePrecision(MakeMultiPolygon(geom), precision);
1597 IString msg =
"PolygonTools::ReducePrecision does not support [" +
1598 GetGeometryName(geom) +
"]";
1613 geos::geom::MultiPolygon *PolygonTools::ReducePrecision(
const geos::geom::MultiPolygon *poly,
1614 unsigned int precision) {
1616 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1619 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1620 geos::geom::Geometry *lowerPrecision = ReducePrecision(
1621 dynamic_cast<const geos::geom::Polygon *>(
1622 poly->getGeometryN(geomIndex)),
1625 if(!lowerPrecision->isEmpty()) {
1626 newPolys->push_back(lowerPrecision);
1629 delete lowerPrecision;
1633 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys);
1647 geos::geom::Polygon *PolygonTools::ReducePrecision(
const geos::geom::Polygon *poly,
1648 unsigned int precision) {
1650 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1651 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1652 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1655 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1656 holes->push_back(thisHole->clone());
1661 geos::geom::LinearRing *newHole = ReducePrecision((geos::geom::LinearRing *)thisHole,
1664 if(!newHole->isEmpty()) {
1665 holes->push_back(newHole);
1673 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1679 const geos::geom::LineString *exterior = poly->getExteriorRing();
1682 geos::geom::LinearRing *newExterior = NULL;
1684 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1685 newExterior = ReducePrecision((geos::geom::LinearRing *)exterior, precision);
1688 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior "
1689 "ring is not simple and closed";
1693 return globalFactory.createPolygon(newExterior, holes);
1696 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1711 geos::geom::LinearRing *PolygonTools::ReducePrecision(
const geos::geom::LinearRing *ring,
1712 unsigned int precision) {
1713 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1716 if(coords->getSize() <= 0)
return dynamic_cast<geos::geom::LinearRing *>(
1719 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1720 geos::geom::Coordinate *coord = ReducePrecision(&coords->getAt(0), precision);
1721 newCoords->add(*coord);
1726 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1727 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1728 coord = ReducePrecision(thisCoordinate, precision);
1729 newCoords->add(*coord);
1734 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1735 geos::geom::LinearRing *newRing = NULL;
1739 newRing = globalFactory.createLinearRing(newCoords);
1741 catch(geos::util::GEOSException *exc) {
1745 IString msg =
"Error when attempting to reduce precision of linear ring";
1751 geos::geom::LinearRing *tmp = Despike(newRing);
1758 if(!newRing->isValid()) {
1759 IString msg =
"Failed when attempting to reduce precision of linear ring";
1776 geos::geom::Coordinate *PolygonTools::ReducePrecision(
const geos::geom::Coordinate *coord,
1777 unsigned int precision) {
1778 return new geos::geom::Coordinate(
1779 ReducePrecision(coord->x, precision),
1780 ReducePrecision(coord->y, precision),
1781 ReducePrecision(coord->z, precision)
1795 double PolygonTools::ReducePrecision(
double num,
unsigned int precision) {
1796 double result = num;
1800 int decimalPlace = DecimalPlace(num);
1801 double factor = pow(10.0, (
int)decimalPlace);
1804 double reducedNum = num / factor;
1806 double cutoff = pow(10.0, (
int)precision);
1807 double round_offset = (num < 0) ? -0.5 : 0.5;
1810 reducedNum = ((
long long)(reducedNum * cutoff + round_offset)) / cutoff;
1811 result = reducedNum * factor;
1826 QString PolygonTools::GetGeometryName(
const geos::geom::Geometry *geom) {
1827 switch(geom->getGeometryTypeId()) {
1828 case geos::geom::GEOS_POINT:
1830 case geos::geom::GEOS_LINESTRING:
1831 return "Line String";
1832 case geos::geom::GEOS_LINEARRING:
1833 return "Linear Ring";
1834 case geos::geom::GEOS_POLYGON:
1836 case geos::geom::GEOS_MULTIPOINT:
1837 return "Multi Point";
1838 case geos::geom::GEOS_MULTILINESTRING:
1839 return "Multi Line String";
1840 case geos::geom::GEOS_MULTIPOLYGON:
1841 return "Multi Polygon";
1842 case geos::geom::GEOS_GEOMETRYCOLLECTION:
1843 return "Geometry Collection";
1850 bool PolygonTools::Equal(
const geos::geom::MultiPolygon *poly1,
1851 const geos::geom::MultiPolygon *poly2) {
1853 vector<const geos::geom::Polygon *> polys1;
1854 vector<const geos::geom::Polygon *> polys2;
1856 if(poly1->getNumGeometries() != poly2->getNumGeometries())
return false;
1859 for(
unsigned int geomIndex = 0; geomIndex < poly1->getNumGeometries(); geomIndex ++) {
1860 polys1.push_back(dynamic_cast<const geos::geom::Polygon *>(
1861 poly1->getGeometryN(geomIndex)));
1862 polys2.push_back(dynamic_cast<const geos::geom::Polygon *>(
1863 poly2->getGeometryN(geomIndex)));
1866 for(
int p1 = polys1.size() - 1; (p1 >= 0) && polys1.size(); p1 --) {
1867 for(
int p2 = polys2.size() - 1; (p2 >= 0) && polys2.size(); p2 --) {
1868 if(Equal(polys1[p1], polys2[p2])) {
1870 polys1[p1] = polys1[polys1.size()-1];
1871 polys1.resize(polys1.size() - 1);
1873 polys2[p2] = polys2[polys2.size()-1];
1874 polys2.resize(polys2.size() - 1);
1879 return (polys1.size() == 0) && (polys2.size() == 0);
1883 bool PolygonTools::Equal(
const geos::geom::Polygon *poly1,
const geos::geom::Polygon *poly2) {
1884 vector<const geos::geom::LineString *> holes1;
1885 vector<const geos::geom::LineString *> holes2;
1887 if(poly1->getNumInteriorRing() != poly2->getNumInteriorRing())
return false;
1889 if(!Equal(poly1->getExteriorRing(), poly2->getExteriorRing()))
return false;
1892 for(
unsigned int holeIndex = 0; holeIndex < poly1->getNumInteriorRing(); holeIndex ++) {
1895 if(poly1->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1896 holes1.push_back(poly1->getInteriorRingN(holeIndex));
1899 if(poly2->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1900 holes2.push_back(poly2->getInteriorRingN(holeIndex));
1905 if(holes1.size() != holes2.size())
return false;
1907 for(
int h1 = holes1.size() - 1; (h1 >= 0) && holes1.size(); h1 --) {
1908 for(
int h2 = holes2.size() - 1; (h2 >= 0) && holes2.size(); h2 --) {
1909 if(Equal(holes1[h1], holes2[h2])) {
1911 holes1[h1] = holes1[holes1.size()-1];
1912 holes1.resize(holes1.size() - 1);
1914 holes2[h2] = holes2[holes2.size()-1];
1915 holes2.resize(holes2.size() - 1);
1920 return (holes1.size() == 0) && (holes2.size() == 0);
1924 bool PolygonTools::Equal(
const geos::geom::LineString *lineString1,
1925 const geos::geom::LineString *lineString2) {
1927 geos::geom::CoordinateSequence *coords1 = lineString1->getCoordinates();
1928 geos::geom::CoordinateSequence *coords2 = lineString2->getCoordinates();
1929 bool isEqual =
true;
1931 if(coords1->getSize() != coords2->getSize()) isEqual =
false;
1933 unsigned int index1 = 0;
1934 unsigned int index2 = 0;
1937 for(; index2 < coords2->getSize() - 1 && isEqual; index2 ++) {
1938 if(Equal(coords1->getAt(index1), coords2->getAt(index2)))
break;
1941 if(index2 == coords2->getSize() - 1) isEqual =
false;
1943 for(; index1 < coords1->getSize() - 1 && isEqual; index1 ++, index2 ++) {
1944 if(!Equal(coords1->getAt(index1), coords2->getAt(index2 % (coords2->getSize() - 1)))) {
1955 bool PolygonTools::Equal(
const geos::geom::Coordinate &coord1,
1956 const geos::geom::Coordinate &coord2) {
1958 if(!Equal(coord1.x, coord2.x))
return false;
1959 if(!Equal(coord1.y, coord2.y))
return false;
1960 if(!Equal(coord1.y, coord2.y))
return false;
1966 bool PolygonTools::Equal(
const double d1,
const double d2) {
1967 const double cutoff = 1e15;
1969 if(DecimalPlace(d1) != DecimalPlace(d2))
return false;
1971 int decimalPlace = DecimalPlace(d1);
1972 double factor = pow(10.0, (
int)decimalPlace);
1975 double reducedNum = d1 / factor;
1977 double round_offset = (d1 < 0) ? -0.5 : 0.5;
1980 long long num1 = ((
long long)(reducedNum * cutoff + round_offset));
1982 factor = pow(10.0, (
int)decimalPlace);
1985 reducedNum = d2 / factor;
1987 round_offset = (d2 < 0) ? -0.5 : 0.5;
1990 long long num2 = ((
long long)(reducedNum * cutoff + round_offset));
1993 return (num1 == num2);
2011 geos::geom::MultiPolygon *PolygonTools::SplitPolygonOn360(
const geos::geom::Polygon *inPoly) {
2012 bool convertLon =
false;
2013 bool negAdjust =
false;
2014 bool newCoords =
false;
2015 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2017 double lonOffset = 0;
2018 geos::geom::CoordinateSequence *inPolyCoords = inPoly->getCoordinates();
2019 double prevLon = inPolyCoords->getAt(0).x;
2020 double prevLat = inPolyCoords->getAt(0).y;
2022 newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat));
2024 for (
unsigned int i = 1; i < inPolyCoords->getSize(); i++) {
2025 lon = inPolyCoords->getAt(i).x;
2026 lat = inPolyCoords->getAt(i).y;
2028 if (abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) {
2036 if ((lon - prevLon) > 0) {
2040 else if ((lon - prevLon) < 0) {
2049 if (newCoords && dist == 0.0) {
2050 double longitude = (lon + lonOffset) - prevLon;
2051 double latitude = lat - prevLat;
2052 dist = std::sqrt((longitude * longitude) + (latitude * latitude));
2056 newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat));
2063 delete inPolyCoords;
2067 geos::geom::Polygon *newPoly = globalFactory.createPolygon
2068 (globalFactory.createLinearRing(newLonLatPts), NULL);
2069 geos::geom::MultiPolygon *multi_polygon = PolygonTools::MakeMultiPolygon(newPoly);
2070 delete newLonLatPts;
2071 return multi_polygon;
2076 geos::geom::Polygon *newPoly = globalFactory.createPolygon
2077 (globalFactory.createLinearRing(newLonLatPts), NULL);
2079 geos::geom::CoordinateSequence *pts =
new geos::geom::CoordinateArraySequence();
2080 geos::geom::CoordinateSequence *pts2 =
new geos::geom::CoordinateArraySequence();
2088 pts->add(geos::geom::Coordinate(0., 90.));
2089 pts->add(geos::geom::Coordinate(-360., 90.));
2090 pts->add(geos::geom::Coordinate(-360., -90.));
2091 pts->add(geos::geom::Coordinate(0., -90.));
2092 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2093 pts->add(geos::geom::Coordinate(0.0, lat));
2095 pts->add(geos::geom::Coordinate(0., 90.));
2096 pts2->add(geos::geom::Coordinate(0., 90.));
2097 pts2->add(geos::geom::Coordinate(360., 90.));
2098 pts2->add(geos::geom::Coordinate(360., -90.));
2099 pts2->add(geos::geom::Coordinate(0., -90.));
2100 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2101 pts2->add(geos::geom::Coordinate(0.0, lat));
2103 pts2->add(geos::geom::Coordinate(0., 90.));
2106 pts->add(geos::geom::Coordinate(360., 90.));
2107 pts->add(geos::geom::Coordinate(720., 90.));
2108 pts->add(geos::geom::Coordinate(720., -90.));
2109 pts->add(geos::geom::Coordinate(360., -90.));
2110 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2111 pts->add(geos::geom::Coordinate(360.0, lat));
2113 pts->add(geos::geom::Coordinate(360., 90.));
2114 pts2->add(geos::geom::Coordinate(360., 90.));
2115 pts2->add(geos::geom::Coordinate(0., 90.));
2116 pts2->add(geos::geom::Coordinate(0., -90.));
2117 pts2->add(geos::geom::Coordinate(360., -90.));
2118 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2119 pts2->add(geos::geom::Coordinate(360.0, lat));
2121 pts2->add(geos::geom::Coordinate(360., 90.));
2124 geos::geom::Polygon *boundaryPoly = globalFactory.createPolygon
2125 (globalFactory.createLinearRing(pts), NULL);
2126 geos::geom::Polygon *boundaryPoly2 = globalFactory.createPolygon
2127 (globalFactory.createLinearRing(pts2), NULL);
2133 geos::geom::Geometry *intersection = PolygonTools::Intersect(newPoly, boundaryPoly);
2134 geos::geom::MultiPolygon *convertPoly = PolygonTools::MakeMultiPolygon(intersection);
2135 delete intersection;
2137 intersection = PolygonTools::Intersect(newPoly, boundaryPoly2);
2138 geos::geom::MultiPolygon *convertPoly2 = PolygonTools::MakeMultiPolygon(intersection);
2139 delete intersection;
2146 vector<geos::geom::Geometry *> *finalpolys =
new vector<geos::geom::Geometry *>;
2147 geos::geom::Geometry *newGeom = NULL;
2149 for (
unsigned int i = 0; i < convertPoly->getNumGeometries(); i++) {
2150 newGeom = (convertPoly->getGeometryN(i))->clone();
2151 pts = convertPoly->getGeometryN(i)->getCoordinates();
2152 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2155 for (
unsigned int k = 0; k < pts->getSize() ; k++) {
2156 double lon = pts->getAt(k).x;
2157 double lat = pts->getAt(k).y;
2164 newLonLatPts->add(geos::geom::Coordinate(lon, lat), k);
2168 finalpolys->push_back(globalFactory.createPolygon
2169 (globalFactory.createLinearRing(newLonLatPts), NULL));
2173 for (
unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) {
2174 newGeom = (convertPoly2->getGeometryN(i))->clone();
2175 finalpolys->push_back(newGeom);
2178 geos::geom::MultiPolygon *multi_polygon = globalFactory.createMultiPolygon(*finalpolys);
2182 delete newLonLatPts;
2185 return multi_polygon;
2187 catch(geos::util::IllegalArgumentException *geosIll) {
2188 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2189 msg +=
"geos illegal argument [" +
IString(geosIll->what()) +
"]";
2193 catch(geos::util::GEOSException *geosExc) {
2194 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2195 msg +=
"geos exception [" +
IString(geosExc->what()) +
"]";
2200 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2201 msg +=
"isis operation exception [" +
IString(e.
what()) +
"]";
2205 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2206 msg +=
"unknown exception";