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;
1028 std::unique_ptr< geos::geom::Geometry > resultAuto(
1029 BinaryOp(geomFirst, geomSecond, geos::operation::overlay::overlayOp(code)).release());
1031 result = resultAuto->clone();
1033 catch(geos::util::GEOSException *exc) {
1035 if(!failed || precision == minPrecision)
throw;
1040 if(precision == minPrecision) {
1041 IString msg =
"An unknown geos error occurred";
1042 throw IException(IException::Programmer, msg,
_FILEINFO_);
1046 IString msg =
"An unknown geos error occurred when attempting to clone a geometry";
1047 throw IException(IException::Programmer, msg,
_FILEINFO_);
1054 geos::geom::Geometry *tmp = ReducePrecision(geomFirst, precision);
1058 tmp = ReducePrecision(geomSecond, precision);
1070 if(result && !result->isValid()) {
1072 geos::geom::Geometry *newResult = FixGeometry(result);
1074 if(fabs(newResult->getArea() / result->getArea() - 1.0) > 0.50) {
1078 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1079 throw IException(IException::Programmer, msg,
_FILEINFO_);
1085 catch(IException &e) {
1086 IString msg =
"Operation [" + IString((
int)opcode) +
"] failed";
1087 throw IException(IException::Programmer, msg,
_FILEINFO_);
1091 if(result == NULL) {
1092 IString msg =
"Operation [" + IString((
int)opcode) +
" failed";
1093 throw IException(IException::Programmer, msg,
_FILEINFO_);
1109 geos::geom::Geometry *PolygonTools::FixGeometry(
const geos::geom::Geometry *geom) {
1110 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1111 return FixGeometry(dynamic_cast<const geos::geom::MultiPolygon *>(geom));
1113 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1114 return FixGeometry(dynamic_cast<const geos::geom::LinearRing *>(geom));
1116 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1117 return FixGeometry(dynamic_cast<const geos::geom::Polygon *>(geom));
1119 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1120 return FixGeometry(MakeMultiPolygon(geom));
1123 IString msg =
"PolygonTools::FixGeometry does not support [" + GetGeometryName(geom) +
"]";
1137 geos::geom::MultiPolygon *PolygonTools::FixGeometry(
const geos::geom::MultiPolygon *poly) {
1139 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1142 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1143 geos::geom::Polygon *fixedpoly = FixGeometry(
1144 dynamic_cast<const geos::geom::Polygon *>(
1145 poly->getGeometryN(geomIndex)));
1146 if(fixedpoly->isValid()) {
1147 newPolys->push_back(fixedpoly);
1155 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys);
1160 geos::geom::Polygon *PolygonTools::FixGeometry(
const geos::geom::Polygon *poly) {
1163 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1164 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1165 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1168 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1169 holes->push_back(thisHole->clone());
1174 geos::geom::LinearRing *newHole = FixGeometry((geos::geom::LinearRing *)thisHole);
1175 holes->push_back(newHole);
1177 catch (IException &e) {
1178 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1179 throw IException(IException::Programmer, msg,
_FILEINFO_);
1184 const geos::geom::LineString *exterior = poly->getExteriorRing();
1187 geos::geom::LinearRing *newExterior = NULL;
1189 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1190 newExterior = FixGeometry((geos::geom::LinearRing *)exterior);
1193 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior " 1194 "ring is not simple and closed";
1195 throw IException(IException::Programmer, msg,
_FILEINFO_);
1198 return globalFactory.createPolygon(newExterior, holes);
1200 catch (IException &e) {
1201 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1202 throw IException(e, IException::Programmer, msg,
_FILEINFO_);
1222 geos::geom::LinearRing *PolygonTools::FixGeometry(
const geos::geom::LinearRing *ring) {
1224 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1227 if(coords->getSize() < 4) {
1228 return globalFactory.createLinearRing(
new geos::geom::DefaultCoordinateSequence());
1231 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1232 const geos::geom::Coordinate *lastCoordinate = &coords->getAt(0);
1233 newCoords->add(*lastCoordinate);
1236 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1237 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1242 double difference[2] = {
1243 lastCoordinate->x - thisCoordinate->x,
1244 lastCoordinate->y - thisCoordinate->y,
1248 double minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1250 minDiff = min(minDiff, fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1])));
1254 if(difference[0] == 0.0 && difference[1] != 0.0) {
1256 minDiff = fabs(DecimalPlace(thisCoordinate->y) - DecimalPlace(difference[1]));
1258 else if(difference[1] == 0.0 && difference[0] != 0.0) {
1260 minDiff = fabs(DecimalPlace(thisCoordinate->x) - DecimalPlace(difference[0]));
1262 else if(difference[0] == 0.0 && difference[1] == 0.0) {
1269 newCoords->add(*thisCoordinate);
1270 lastCoordinate = thisCoordinate;
1274 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1275 geos::geom::LinearRing *newRing = NULL;
1279 if(newCoords->getSize() > 3) {
1280 newRing = globalFactory.createLinearRing(newCoords);
1287 catch(geos::util::GEOSException *exc) {
1291 IString msg =
"Error when attempting to fix linear ring";
1295 if(newRing && !newRing->isValid() && ring->isValid()) {
1296 IString msg =
"Failed when attempting to fix linear ring";
1299 else if(!newRing || !newRing->isValid()) {
1304 newRing =
dynamic_cast<geos::geom::LinearRing *
>(ring->clone());
1322 int PolygonTools::DecimalPlace(
double num) {
1324 if(num == 0.0)
return 0;
1328 int decimalPlace = 1;
1339 return decimalPlace;
1350 geos::geom::Geometry *PolygonTools::Difference(
const geos::geom::Geometry *geom1,
1351 const geos::geom::Geometry *geom2) {
1353 return Operate(geom1, geom2, (
unsigned int)geos::operation::overlay::OverlayOp::opDIFFERENCE);
1355 catch(geos::util::GEOSException *exc) {
1356 IString msg =
"Difference operation failed. The reason given was [" +
1362 IString msg =
"Difference operation failed";
1366 IString msg =
"Difference operation failed for an unknown reason";
1385 geos::geom::MultiPolygon *PolygonTools::MakeMultiPolygon(
const geos::geom::Geometry *geom) {
1387 if(geom->isEmpty()) {
1388 return Isis::globalFactory.createMultiPolygon();
1391 else if(geom->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1392 return Isis::globalFactory.createMultiPolygon();
1395 else if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1396 return dynamic_cast<geos::geom::MultiPolygon *
>(geom->clone());
1399 else if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1400 vector<geos::geom::Geometry *> *polys =
new vector<geos::geom::Geometry *>;
1401 polys->push_back(geom->clone());
1402 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(polys);
1406 else if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1407 vector<geos::geom::Geometry *> * polys =
1408 new vector<geos::geom::Geometry *>;
1409 const geos::geom::GeometryCollection *gc =
1410 dynamic_cast<const geos::geom::GeometryCollection *
>(geom);
1411 for(
unsigned int i = 0; i < gc->getNumGeometries(); ++i) {
1412 geos::geom::MultiPolygon *subMultiPoly =
1413 MakeMultiPolygon(gc->getGeometryN(i));
1415 for(
unsigned int subPoly = 0;
1416 subPoly < subMultiPoly->getNumGeometries();
1418 const geos::geom::Polygon *poly =
1419 dynamic_cast<const geos::geom::Polygon *
>(
1420 subMultiPoly->getGeometryN(subPoly));
1421 polys->push_back(dynamic_cast<geos::geom::Polygon *>(poly->clone()));
1425 geos::geom::MultiPolygon *mp =
1426 Isis::globalFactory.createMultiPolygon(polys);
1427 if(mp->getArea() - DBL_EPSILON <= DBL_EPSILON) {
1429 mp = Isis::globalFactory.createMultiPolygon();
1437 return Isis::globalFactory.createMultiPolygon();
1442 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1443 const geos::geom::Polygon *polyA,
const geos::geom::Polygon *polyB) {
1444 geos::geom::CoordinateSequence *polyAPoints = polyA->getCoordinates();
1445 geos::geom::CoordinateSequence *polyBPoints = polyB->getCoordinates();
1447 unsigned int aIntersectionBegin = 0;
1448 unsigned int aIntersectionEnd = 0;
1449 unsigned int bIntersectionBegin = 0;
1450 unsigned int bIntersectionEnd = 0;
1452 bool intersectionStarted =
false;
1453 bool intersectionEnded =
false;
1455 unsigned int lastBMatch = 0;
1456 for (
unsigned int i = 0;
1457 !intersectionEnded && i < polyAPoints->getSize();
1460 bool foundEquivalent =
false;
1462 geos::geom::Coordinate coordA = polyAPoints->getAt(i);
1463 coordA = *ReducePrecision(&coordA, 13);
1465 for (
unsigned int j = 0;
1466 !foundEquivalent && j < polyBPoints->getSize();
1468 geos::geom::Coordinate coordB = polyBPoints->getAt(j);
1469 coordB = *ReducePrecision(&coordB, 13);
1471 foundEquivalent = coordA.equals(coordB);
1473 if (foundEquivalent) lastBMatch = j;
1475 if (foundEquivalent && !intersectionStarted) {
1476 intersectionStarted =
true;
1477 aIntersectionBegin = i;
1478 bIntersectionBegin = j;
1482 if (!foundEquivalent && intersectionStarted && !intersectionEnded) {
1483 intersectionEnded =
true;
1484 aIntersectionEnd = i;
1485 bIntersectionEnd = lastBMatch;
1489 geos::geom::MultiPolygon * result = NULL;
1490 if (intersectionStarted && intersectionEnded) {
1491 geos::geom::CoordinateSequence *merged =
1492 new geos::geom::CoordinateArraySequence;
1495 for (i = 0; i < aIntersectionBegin; i ++) {
1496 merged->add(polyAPoints->getAt(i));
1499 i = bIntersectionBegin;
1500 while (i != bIntersectionEnd) {
1501 merged->add(polyBPoints->getAt(i));
1503 if (i >= polyBPoints->getSize()) i = 0;
1506 for (i = aIntersectionEnd; i < polyAPoints->getSize() - 1; i++) {
1507 merged->add(polyAPoints->getAt(i));
1510 merged->add(merged->getAt(0));
1511 result = MakeMultiPolygon(globalFactory.createPolygon(
1512 globalFactory.createLinearRing(merged), NULL));
1519 geos::geom::MultiPolygon *PolygonTools::FixSeam(
1520 const geos::geom::MultiPolygon *poly) {
1522 std::vector<geos::geom::Geometry *> *polys =
1523 new std::vector<geos::geom::Geometry *>;
1526 for(
unsigned int copyIndex = 0;
1527 copyIndex < poly->getNumGeometries();
1529 polys->push_back(poly->getGeometryN(copyIndex)->clone());
1532 unsigned int outerPolyIndex = 0;
1534 while(outerPolyIndex + 1 < polys->size()) {
1535 unsigned int innerPolyIndex = outerPolyIndex + 1;
1537 while(innerPolyIndex < polys->size()) {
1538 geos::geom::MultiPolygon *fixedPair = FixSeam(
1539 dynamic_cast<geos::geom::Polygon *>(polys->at(outerPolyIndex)),
1540 dynamic_cast<geos::geom::Polygon *>(polys->at(innerPolyIndex)));
1542 if(fixedPair != NULL) {
1543 geos::geom::Geometry *oldInnerPoly = polys->at(innerPolyIndex);
1544 geos::geom::Geometry *oldOuterPoly = polys->at(outerPolyIndex);
1546 polys->erase(polys->begin() + innerPolyIndex);
1547 (*polys)[outerPolyIndex] = fixedPair->getGeometryN(0)->clone();
1548 innerPolyIndex = outerPolyIndex + 1;
1553 delete oldInnerPoly;
1554 oldInnerPoly = NULL;
1556 delete oldOuterPoly;
1557 oldOuterPoly = NULL;
1567 return globalFactory.createMultiPolygon(polys);
1580 geos::geom::Geometry *PolygonTools::ReducePrecision(
const geos::geom::Geometry *geom,
1581 unsigned int precision) {
1582 if(geom->getGeometryTypeId() == geos::geom::GEOS_MULTIPOLYGON) {
1583 return ReducePrecision(
1584 dynamic_cast<const geos::geom::MultiPolygon *>(geom), precision);
1586 if(geom->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1587 return ReducePrecision(
1588 dynamic_cast<const geos::geom::LinearRing *>(geom), precision);
1590 if(geom->getGeometryTypeId() == geos::geom::GEOS_POLYGON) {
1591 return ReducePrecision(
1592 dynamic_cast<const geos::geom::Polygon *>(geom), precision);
1594 if(geom->getGeometryTypeId() == geos::geom::GEOS_GEOMETRYCOLLECTION) {
1595 return ReducePrecision(MakeMultiPolygon(geom), precision);
1598 IString msg =
"PolygonTools::ReducePrecision does not support [" +
1599 GetGeometryName(geom) +
"]";
1614 geos::geom::MultiPolygon *PolygonTools::ReducePrecision(
const geos::geom::MultiPolygon *poly,
1615 unsigned int precision) {
1617 vector<geos::geom::Geometry *> *newPolys =
new vector<geos::geom::Geometry *>;
1620 for(
unsigned int geomIndex = 0; geomIndex < poly->getNumGeometries(); geomIndex ++) {
1621 geos::geom::Geometry *lowerPrecision = ReducePrecision(
1622 dynamic_cast<const geos::geom::Polygon *>(
1623 poly->getGeometryN(geomIndex)),
1626 if(!lowerPrecision->isEmpty()) {
1627 newPolys->push_back(lowerPrecision);
1630 delete lowerPrecision;
1634 geos::geom::MultiPolygon *mp = Isis::globalFactory.createMultiPolygon(newPolys);
1648 geos::geom::Polygon *PolygonTools::ReducePrecision(
const geos::geom::Polygon *poly,
1649 unsigned int precision) {
1651 vector<geos::geom::Geometry *> *holes =
new vector<geos::geom::Geometry *>;
1652 for(
unsigned int holeIndex = 0; holeIndex < poly->getNumInteriorRing(); holeIndex ++) {
1653 const geos::geom::LineString *thisHole = poly->getInteriorRingN(holeIndex);
1656 if(thisHole->getGeometryTypeId() != geos::geom::GEOS_LINEARRING) {
1657 holes->push_back(thisHole->clone());
1662 geos::geom::LinearRing *newHole = ReducePrecision((geos::geom::LinearRing *)thisHole,
1665 if(!newHole->isEmpty()) {
1666 holes->push_back(newHole);
1674 IString msg =
"Failed when attempting to fix interior ring of multipolygon";
1680 const geos::geom::LineString *exterior = poly->getExteriorRing();
1683 geos::geom::LinearRing *newExterior = NULL;
1685 if(exterior->getGeometryTypeId() == geos::geom::GEOS_LINEARRING) {
1686 newExterior = ReducePrecision((geos::geom::LinearRing *)exterior, precision);
1689 IString msg =
"Failed when attempting to fix exterior ring of polygon. The exterior " 1690 "ring is not simple and closed";
1694 return globalFactory.createPolygon(newExterior, holes);
1697 IString msg =
"Failed when attempting to fix exterior ring of polygon";
1712 geos::geom::LinearRing *PolygonTools::ReducePrecision(
const geos::geom::LinearRing *ring,
1713 unsigned int precision) {
1714 geos::geom::CoordinateSequence *coords = ring->getCoordinates();
1717 if(coords->getSize() <= 0)
return dynamic_cast<geos::geom::LinearRing *>(
1720 geos::geom::CoordinateSequence *newCoords =
new geos::geom::DefaultCoordinateSequence();
1721 geos::geom::Coordinate *coord = ReducePrecision(&coords->getAt(0), precision);
1722 newCoords->add(*coord);
1727 for(
unsigned int coordIndex = 1; coordIndex < coords->getSize() - 1; coordIndex ++) {
1728 const geos::geom::Coordinate *thisCoordinate = &coords->getAt(coordIndex);
1729 coord = ReducePrecision(thisCoordinate, precision);
1730 newCoords->add(*coord);
1735 newCoords->add(geos::geom::Coordinate(newCoords->getAt(0).x, newCoords->getAt(0).y));
1736 geos::geom::LinearRing *newRing = NULL;
1740 newRing = globalFactory.createLinearRing(newCoords);
1742 catch(geos::util::GEOSException *exc) {
1746 IString msg =
"Error when attempting to reduce precision of linear ring";
1752 geos::geom::LinearRing *tmp = Despike(newRing);
1759 if(!newRing->isValid()) {
1760 IString msg =
"Failed when attempting to reduce precision of linear ring";
1777 geos::geom::Coordinate *PolygonTools::ReducePrecision(
const geos::geom::Coordinate *coord,
1778 unsigned int precision) {
1779 return new geos::geom::Coordinate(
1780 ReducePrecision(coord->x, precision),
1781 ReducePrecision(coord->y, precision),
1782 ReducePrecision(coord->z, precision)
1796 double PolygonTools::ReducePrecision(
double num,
unsigned int precision) {
1797 double result = num;
1801 int decimalPlace = DecimalPlace(num);
1802 double factor = pow(10.0, (
int)decimalPlace);
1805 double reducedNum = num / factor;
1807 double cutoff = pow(10.0, (
int)precision);
1808 double round_offset = (num < 0) ? -0.5 : 0.5;
1811 reducedNum = ((
long long)(reducedNum * cutoff + round_offset)) / cutoff;
1812 result = reducedNum * factor;
1827 QString PolygonTools::GetGeometryName(
const geos::geom::Geometry *geom) {
1828 switch(geom->getGeometryTypeId()) {
1829 case geos::geom::GEOS_POINT:
1831 case geos::geom::GEOS_LINESTRING:
1832 return "Line String";
1833 case geos::geom::GEOS_LINEARRING:
1834 return "Linear Ring";
1835 case geos::geom::GEOS_POLYGON:
1837 case geos::geom::GEOS_MULTIPOINT:
1838 return "Multi Point";
1839 case geos::geom::GEOS_MULTILINESTRING:
1840 return "Multi Line String";
1841 case geos::geom::GEOS_MULTIPOLYGON:
1842 return "Multi Polygon";
1843 case geos::geom::GEOS_GEOMETRYCOLLECTION:
1844 return "Geometry Collection";
1851 bool PolygonTools::Equal(
const geos::geom::MultiPolygon *poly1,
1852 const geos::geom::MultiPolygon *poly2) {
1854 vector<const geos::geom::Polygon *> polys1;
1855 vector<const geos::geom::Polygon *> polys2;
1857 if(poly1->getNumGeometries() != poly2->getNumGeometries())
return false;
1860 for(
unsigned int geomIndex = 0; geomIndex < poly1->getNumGeometries(); geomIndex ++) {
1861 polys1.push_back(dynamic_cast<const geos::geom::Polygon *>(
1862 poly1->getGeometryN(geomIndex)));
1863 polys2.push_back(dynamic_cast<const geos::geom::Polygon *>(
1864 poly2->getGeometryN(geomIndex)));
1867 for(
int p1 = polys1.size() - 1; (p1 >= 0) && polys1.size(); p1 --) {
1868 for(
int p2 = polys2.size() - 1; (p2 >= 0) && polys2.size(); p2 --) {
1869 if(Equal(polys1[p1], polys2[p2])) {
1871 polys1[p1] = polys1[polys1.size()-1];
1872 polys1.resize(polys1.size() - 1);
1874 polys2[p2] = polys2[polys2.size()-1];
1875 polys2.resize(polys2.size() - 1);
1880 return (polys1.size() == 0) && (polys2.size() == 0);
1884 bool PolygonTools::Equal(
const geos::geom::Polygon *poly1,
const geos::geom::Polygon *poly2) {
1885 vector<const geos::geom::LineString *> holes1;
1886 vector<const geos::geom::LineString *> holes2;
1888 if(poly1->getNumInteriorRing() != poly2->getNumInteriorRing())
return false;
1890 if(!Equal(poly1->getExteriorRing(), poly2->getExteriorRing()))
return false;
1893 for(
unsigned int holeIndex = 0; holeIndex < poly1->getNumInteriorRing(); holeIndex ++) {
1896 if(poly1->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1897 holes1.push_back(poly1->getInteriorRingN(holeIndex));
1900 if(poly2->getInteriorRingN(holeIndex)->getGeometryTypeId() == geos::geom::GEOS_LINESTRING) {
1901 holes2.push_back(poly2->getInteriorRingN(holeIndex));
1906 if(holes1.size() != holes2.size())
return false;
1908 for(
int h1 = holes1.size() - 1; (h1 >= 0) && holes1.size(); h1 --) {
1909 for(
int h2 = holes2.size() - 1; (h2 >= 0) && holes2.size(); h2 --) {
1910 if(Equal(holes1[h1], holes2[h2])) {
1912 holes1[h1] = holes1[holes1.size()-1];
1913 holes1.resize(holes1.size() - 1);
1915 holes2[h2] = holes2[holes2.size()-1];
1916 holes2.resize(holes2.size() - 1);
1921 return (holes1.size() == 0) && (holes2.size() == 0);
1925 bool PolygonTools::Equal(
const geos::geom::LineString *lineString1,
1926 const geos::geom::LineString *lineString2) {
1928 geos::geom::CoordinateSequence *coords1 = lineString1->getCoordinates();
1929 geos::geom::CoordinateSequence *coords2 = lineString2->getCoordinates();
1930 bool isEqual =
true;
1932 if(coords1->getSize() != coords2->getSize()) isEqual =
false;
1934 unsigned int index1 = 0;
1935 unsigned int index2 = 0;
1938 for(; index2 < coords2->getSize() - 1 && isEqual; index2 ++) {
1939 if(Equal(coords1->getAt(index1), coords2->getAt(index2)))
break;
1942 if(index2 == coords2->getSize() - 1) isEqual =
false;
1944 for(; index1 < coords1->getSize() - 1 && isEqual; index1 ++, index2 ++) {
1945 if(!Equal(coords1->getAt(index1), coords2->getAt(index2 % (coords2->getSize() - 1)))) {
1956 bool PolygonTools::Equal(
const geos::geom::Coordinate &coord1,
1957 const geos::geom::Coordinate &coord2) {
1959 if(!Equal(coord1.x, coord2.x))
return false;
1960 if(!Equal(coord1.y, coord2.y))
return false;
1961 if(!Equal(coord1.y, coord2.y))
return false;
1967 bool PolygonTools::Equal(
const double d1,
const double d2) {
1968 const double cutoff = 1e15;
1970 if(DecimalPlace(d1) != DecimalPlace(d2))
return false;
1972 int decimalPlace = DecimalPlace(d1);
1973 double factor = pow(10.0, (
int)decimalPlace);
1976 double reducedNum = d1 / factor;
1978 double round_offset = (d1 < 0) ? -0.5 : 0.5;
1981 long long num1 = ((
long long)(reducedNum * cutoff + round_offset));
1983 factor = pow(10.0, (
int)decimalPlace);
1986 reducedNum = d2 / factor;
1988 round_offset = (d2 < 0) ? -0.5 : 0.5;
1991 long long num2 = ((
long long)(reducedNum * cutoff + round_offset));
1994 return (num1 == num2);
2012 geos::geom::MultiPolygon *PolygonTools::SplitPolygonOn360(
const geos::geom::Polygon *inPoly) {
2013 bool convertLon =
false;
2014 bool negAdjust =
false;
2015 bool newCoords =
false;
2016 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2018 double lonOffset = 0;
2019 geos::geom::CoordinateSequence *inPolyCoords = inPoly->getCoordinates();
2020 double prevLon = inPolyCoords->getAt(0).x;
2021 double prevLat = inPolyCoords->getAt(0).y;
2023 newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat));
2025 for (
unsigned int i = 1; i < inPolyCoords->getSize(); i++) {
2026 lon = inPolyCoords->getAt(i).x;
2027 lat = inPolyCoords->getAt(i).y;
2029 if (abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) {
2037 if ((lon - prevLon) > 0) {
2041 else if ((lon - prevLon) < 0) {
2050 if (newCoords && dist == 0.0) {
2051 double longitude = (lon + lonOffset) - prevLon;
2052 double latitude = lat - prevLat;
2053 dist = std::sqrt((longitude * longitude) + (latitude * latitude));
2057 newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat));
2064 delete inPolyCoords;
2068 geos::geom::Polygon *newPoly = globalFactory.createPolygon
2069 (globalFactory.createLinearRing(newLonLatPts), NULL);
2070 geos::geom::MultiPolygon *multi_polygon = PolygonTools::MakeMultiPolygon(newPoly);
2071 delete newLonLatPts;
2072 return multi_polygon;
2077 geos::geom::Polygon *newPoly = globalFactory.createPolygon
2078 (globalFactory.createLinearRing(newLonLatPts), NULL);
2080 geos::geom::CoordinateSequence *pts =
new geos::geom::CoordinateArraySequence();
2081 geos::geom::CoordinateSequence *pts2 =
new geos::geom::CoordinateArraySequence();
2089 pts->add(geos::geom::Coordinate(0., 90.));
2090 pts->add(geos::geom::Coordinate(-360., 90.));
2091 pts->add(geos::geom::Coordinate(-360., -90.));
2092 pts->add(geos::geom::Coordinate(0., -90.));
2093 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2094 pts->add(geos::geom::Coordinate(0.0, lat));
2096 pts->add(geos::geom::Coordinate(0., 90.));
2097 pts2->add(geos::geom::Coordinate(0., 90.));
2098 pts2->add(geos::geom::Coordinate(360., 90.));
2099 pts2->add(geos::geom::Coordinate(360., -90.));
2100 pts2->add(geos::geom::Coordinate(0., -90.));
2101 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2102 pts2->add(geos::geom::Coordinate(0.0, lat));
2104 pts2->add(geos::geom::Coordinate(0., 90.));
2107 pts->add(geos::geom::Coordinate(360., 90.));
2108 pts->add(geos::geom::Coordinate(720., 90.));
2109 pts->add(geos::geom::Coordinate(720., -90.));
2110 pts->add(geos::geom::Coordinate(360., -90.));
2111 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2112 pts->add(geos::geom::Coordinate(360.0, lat));
2114 pts->add(geos::geom::Coordinate(360., 90.));
2115 pts2->add(geos::geom::Coordinate(360., 90.));
2116 pts2->add(geos::geom::Coordinate(0., 90.));
2117 pts2->add(geos::geom::Coordinate(0., -90.));
2118 pts2->add(geos::geom::Coordinate(360., -90.));
2119 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
2120 pts2->add(geos::geom::Coordinate(360.0, lat));
2122 pts2->add(geos::geom::Coordinate(360., 90.));
2125 geos::geom::Polygon *boundaryPoly = globalFactory.createPolygon
2126 (globalFactory.createLinearRing(pts), NULL);
2127 geos::geom::Polygon *boundaryPoly2 = globalFactory.createPolygon
2128 (globalFactory.createLinearRing(pts2), NULL);
2134 geos::geom::Geometry *intersection = PolygonTools::Intersect(newPoly, boundaryPoly);
2135 geos::geom::MultiPolygon *convertPoly = PolygonTools::MakeMultiPolygon(intersection);
2136 delete intersection;
2138 intersection = PolygonTools::Intersect(newPoly, boundaryPoly2);
2139 geos::geom::MultiPolygon *convertPoly2 = PolygonTools::MakeMultiPolygon(intersection);
2140 delete intersection;
2147 vector<geos::geom::Geometry *> *finalpolys =
new vector<geos::geom::Geometry *>;
2148 geos::geom::Geometry *newGeom = NULL;
2150 for (
unsigned int i = 0; i < convertPoly->getNumGeometries(); i++) {
2151 newGeom = (convertPoly->getGeometryN(i))->clone();
2152 pts = convertPoly->getGeometryN(i)->getCoordinates();
2153 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
2156 for (
unsigned int k = 0; k < pts->getSize() ; k++) {
2157 double lon = pts->getAt(k).x;
2158 double lat = pts->getAt(k).y;
2165 newLonLatPts->add(geos::geom::Coordinate(lon, lat), k);
2169 finalpolys->push_back(globalFactory.createPolygon
2170 (globalFactory.createLinearRing(newLonLatPts), NULL));
2174 for (
unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) {
2175 newGeom = (convertPoly2->getGeometryN(i))->clone();
2176 finalpolys->push_back(newGeom);
2179 geos::geom::MultiPolygon *multi_polygon = globalFactory.createMultiPolygon(*finalpolys);
2183 delete newLonLatPts;
2186 return multi_polygon;
2188 catch(geos::util::IllegalArgumentException *geosIll) {
2189 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2190 msg +=
"geos illegal argument [" +
IString(geosIll->what()) +
"]";
2194 catch(geos::util::GEOSException *geosExc) {
2195 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2196 msg +=
"geos exception [" +
IString(geosExc->what()) +
"]";
2201 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2202 msg +=
"isis operation exception [" +
IString(e.
what()) +
"]";
2206 std::string msg =
"Unable to split polygon on longitude boundry (SplitPolygonOn360) due to ";
2207 msg +=
"unknown exception";
const char * what() const
Returns a string representation of this exception in its current state.
double Line() const
Returns the current line value of the camera model or projection.
Base class for Map TProjections.
Namespace for the standard library.
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround, or SetWorld returned with success.
double Longitude() const
This returns a longitude with correct longitude direction and domain as specified in the label object...
#define _FILEINFO_
Macro for the filename and line number.
virtual bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType, LongitudeDirection, and LongitudeDomain.
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround, or SetWorld returned with success.
bool SetWorld(const double x, const double y)
This method is used to set a world coordinate.
double Latitude() const
This returns a latitude with correct latitude type as specified in the label object.
Adds specific functionality to C++ strings.
Namespace for ISIS/Bullet specific routines.
bool SetUniversalGround(double lat, double lon)
Returns whether the lat/lon position was set successfully in the camera model or projection.
double Sample() const
Returns the current line value of the camera model or projection.