16 #include <geos/geom/Geometry.h>
17 #include <geos/geom/Polygon.h>
18 #include <geos/geom/CoordinateArraySequence.h>
19 #include <geos/algorithm/LineIntersector.h>
20 #include <geos/util/IllegalArgumentException.h>
21 #include <geos/util/TopologyException.h>
22 #include <geos/util/GEOSException.h>
23 #include <geos/io/WKTReader.h>
24 #include <geos/io/WKTWriter.h>
25 #include <geos/operation/distance/DistanceOp.h>
27 #include "ImagePolygon.h"
29 #include "SpecialPixel.h"
30 #include "PolygonTools.h"
40 ImagePolygon::ImagePolygon() {
56 p_subpixelAccuracy = 50;
69 geos::io::WKTReader *wkt =
new geos::io::WKTReader(&(*globalFactory));
72 p_pts =
new geos::geom::CoordinateArraySequence;
75 geos::geom::CoordinateArraySequence coordArray = geos::geom::CoordinateArraySequence(*(poly->getCoordinates()));
76 for (
size_t i = 0; i < coordArray.getSize(); i++) {
77 p_pts->add(geos::geom::Coordinate(coordArray.getAt(i)));
122 int ns,
int nl,
int band) {
140 QString msg =
"Can not create polygon, ";
142 msg +=
"] is not a camera or map projection";
146 polyError.
append(camError);
147 polyError.
append(projError);
179 std::string msg =
"Cannot use an ellipsoid shape model";
180 msg +=
" on a limb image without a camera.";
218 int ss,
int sl,
int ns,
int nl,
int band,
219 bool increasePrecision) {
223 if (sinc < 1 || linc < 1) {
224 std::string msg =
"Sample and line increments must be 1 or greater";
228 cam =
initCube(cube, ss, sl, ns, nl, band);
231 bool polygonGenerated =
false;
232 while (!polygonGenerated) {
238 p_pts =
new geos::geom::CoordinateArraySequence();
242 polygonGenerated =
true;
250 if (increasePrecision && (sinc > 1 || linc > 1)) {
254 QString msg =
"Cannot find polygon for image "
256 msg += increasePrecision ?
"Cannot increase precision any further" :
257 "The increment/step size might be too large";
283 p_pts =
new geos::geom::CoordinateArraySequence();
285 for (std::vector<double> coord : polyCoordinates) {
286 p_pts->add(geos::geom::Coordinate(coord[0], coord[1]));
289 std::vector<geos::geom::Geometry *> *polys =
new std::vector<geos::geom::Geometry *>;
290 geos::geom::Polygon *poly = globalFactory->createPolygon(globalFactory->createLinearRing(
p_pts),
nullptr);
291 polys->push_back(poly->clone());
292 p_polygons = globalFactory->createMultiPolygon(polys);
317 geos::geom::Coordinate lastPoint,
318 int recursionDepth) {
319 double x = lastPoint.x - currentPoint->x;
320 double y = lastPoint.y - currentPoint->y;
321 geos::geom::Coordinate result;
324 if (recursionDepth > 6) {
325 return *currentPoint;
329 if (x == 0.0 && y == 0.0) {
332 double s = currentPoint->x + samp;
333 double l = currentPoint->y + line;
337 geos::geom::Coordinate next(s, l);
343 std::string msg =
"Unable to create image footprint. Starting point is not on the edge of the image.";
346 else if (x < 0 && y < 0) {
347 geos::geom::Coordinate next(currentPoint->x, currentPoint->y - 1 *
p_lineinc);
350 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
356 else if (x == 0.0 && y < 0) {
357 geos::geom::Coordinate next(currentPoint->x + 1 *
p_sampinc, currentPoint->y - 1 *
p_lineinc);
360 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
366 else if (x > 0 && y < 0) {
367 geos::geom::Coordinate next(currentPoint->x + 1 *
p_sampinc, currentPoint->y);
370 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
376 else if (x > 0 && y == 0.0) {
377 geos::geom::Coordinate next(currentPoint->x + 1 *
p_sampinc, currentPoint->y + 1 *
p_lineinc);
380 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
386 else if (x > 0 && y > 0) {
387 geos::geom::Coordinate next(currentPoint->x, currentPoint->y + 1 *
p_lineinc);
390 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
396 else if (x == 0.0 && y > 0) {
397 geos::geom::Coordinate next(currentPoint->x - 1 *
p_sampinc, currentPoint->y + 1 *
p_lineinc);
400 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
406 else if (x < 0 && y > 0) {
407 geos::geom::Coordinate next(currentPoint->x - 1 *
p_sampinc, currentPoint->y);
410 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
416 else if (x < 0 && y == 0.0) {
417 geos::geom::Coordinate next(currentPoint->x - 1 *
p_sampinc, currentPoint->y - 1 *
p_lineinc);
420 result =
FindNextPoint(currentPoint, next, recursionDepth + 1);
427 std::string msg =
"Unable to create image footprint. Error walking image.";
458 const double origSample = sample - sinc;
460 const double origLine = line - linc;
463 if (sample < startSample && sinc < 0) {
465 if (origSample == startSample) {
469 sample = startSample;
473 if (sample > endSample && sinc > 0) {
475 if (origSample == endSample) {
483 if (line < startLine && linc < 0) {
485 if (origLine == startLine) {
493 if (line > endLine && linc > 0) {
495 if (fabs(origLine - endLine) < 0.5) {
536 geos::geom::Coordinate firstPoint(sample, line);
537 geos::geom::Coordinate lastPoint = firstPoint;
538 if (!firstPoint.equals(
FindNextPoint(&firstPoint, lastPoint))) {
546 std::string msg =
"No lat/lon data found for image";
595 m_leftCoord =
new geos::geom::Coordinate(sample, line);
604 m_rightCoord =
new geos::geom::Coordinate(sample, line);
614 m_topCoord =
new geos::geom::Coordinate(sample, line);
624 m_botCoord =
new geos::geom::Coordinate(sample, line);
639 vector<geos::geom::Coordinate> points;
640 double lat, lon, prevLat, prevLon;
644 points.push_back(firstPoint);
650 geos::geom::Coordinate currentPoint = firstPoint;
651 geos::geom::Coordinate lastPoint = firstPoint;
652 geos::geom::Coordinate tempPoint;
660 bool snapToFirstPoint =
true;
666 snapToFirstPoint &= (points.size() > 2);
673 snapToFirstPoint &= (
DistanceSquared(¤tPoint, &firstPoint) < (minStepSize * minStepSize));
676 if (snapToFirstPoint) {
677 tempPoint = firstPoint;
683 for (
int pt = 0; pt < (int)points.size(); pt ++) {
684 if (points[pt].equals(tempPoint)) {
685 tempPoint = firstPoint;
692 if (tempPoint.equals(currentPoint)) {
693 geos::geom::Coordinate oldDuplicatePoint = tempPoint;
696 tempPoint = lastPoint;
697 lastPoint = currentPoint;
698 currentPoint = tempPoint;
702 if (points.size() < 3) {
703 std::string msg =
"Failed to find next point in the image.";
712 if (tempPoint.equals(currentPoint) || tempPoint.equals(oldDuplicatePoint)) {
713 std::string msg =
"Failed to find next valid point in the image.";
721 if (points[points.size()-3].x == tempPoint.x &&
722 points[points.size()-3].y == tempPoint.y) {
728 currentPoint = points[points.size()-1];
740 if (points.size() > 250) {
744 for (
unsigned int pt = 1; pt < points.size() && cycleStart == 0; pt ++) {
745 for (
unsigned int check = pt + 1; check < points.size() && cycleStart == 0; check ++) {
746 if (points[pt] == points[check]) {
754 if (cycleStart != 0) {
755 vector<geos::geom::Coordinate> cyclePoints;
756 for (
int pt = cycleStart; pt <= cycleEnd; pt ++) {
757 cyclePoints.push_back(points[pt]);
760 points = cyclePoints;
767 lastPoint = currentPoint;
768 currentPoint = tempPoint;
769 points.push_back(currentPoint);
772 while (!currentPoint.equals(firstPoint));
774 if (points.size() <= 3) {
775 std::string msg =
"Failed to find enough points on the image.";
785 vector<geos::geom::Coordinate> *crossingPoints =
new vector<geos::geom::Coordinate>;
786 for (
unsigned int i = 0; i < points.size(); i++) {
787 geos::geom::Coordinate *temp = &(points.at(i));
791 if (abs(lon - prevLon) >= 180 && i != 0) {
792 crossingPoints->push_back(geos::geom::Coordinate(prevLon, prevLat));
794 p_pts->add(geos::geom::Coordinate(lon, lat));
801 geos::geom::CoordinateSequence *tempPts =
new geos::geom::CoordinateArraySequence();
804 tempPts->add(geos::geom::Coordinate((*
p_pts)[0].x, (*
p_pts)[0].y));
805 tempPts->add(geos::geom::Coordinate((*
p_pts)[1].x, (*
p_pts)[1].y));
808 tempPts->add(geos::geom::Coordinate((*
p_pts)[0].x, (*
p_pts)[0].y));
810 geos::geom::Polygon *tempPoly = globalFactory->createPolygon
811 (globalFactory->createLinearRing(tempPts), NULL);
814 if (!tempPoly->isValid()) {
823 delete crossingPoints;
824 crossingPoints = NULL;
837 bool hasNorthPole =
false;
838 bool hasSouthPole =
false;
841 double nPoleSample =
Null;
842 double nPoleLine =
Null;
853 if (nPoleSample >= 0.5 && nPoleLine >= 0.5 &&
854 nPoleSample <= p_cube->sampleCount() + 0.5 &&
855 nPoleLine <= p_cube->lineCount() + 0.5) {
861 double sPoleSample =
Null;
862 double sPoleLine =
Null;
873 if (sPoleSample >= 0.5 && sPoleLine >= 0.5 &&
874 sPoleSample <= p_cube->sampleCount() + 0.5 &&
875 sPoleLine <= p_cube->lineCount() + 0.5) {
880 if (hasNorthPole && hasSouthPole) {
881 std::string msg =
"Unable to create image footprint because image has both poles";
884 else if (crossingPoints->size() == 0) {
903 else if (hasSouthPole) {
918 geos::geom::Coordinate *closestPoint = &crossingPoints->at(0);
919 geos::geom::Coordinate *pole = NULL;
923 pole =
new geos::geom::Coordinate(0, 90);
925 else if (hasSouthPole) {
926 pole =
new geos::geom::Coordinate(0, -90);
928 else if (crossingPoints->size() % 2 == 1) {
929 geos::geom::Coordinate nPole(0, 90);
930 double nDist = DBL_MAX;
931 geos::geom::Coordinate sPole(0, -90);
932 double sDist = DBL_MAX;
934 for (
unsigned int index = 0; index <
p_pts->size(); index ++) {
946 pole =
new geos::geom::Coordinate(0, -90);
949 pole =
new geos::geom::Coordinate(0, 90);
959 double closestDistance = DBL_MAX;
960 for (
unsigned int i = 0; i < crossingPoints->size(); i++) {
961 geos::geom::Coordinate *temp = &crossingPoints->at(i);
966 while ((temp->x - mod) > 180) mod += 360.0;
969 geos::geom::Coordinate modPointMem = geos::geom::Coordinate(temp->x - mod, temp->y);
970 geos::geom::Coordinate *modPoint = &modPointMem;
976 if (tempDistance < closestDistance) {
977 closestDistance = tempDistance;
982 if (closestDistance == DBL_MAX) {
983 std::string msg =
"Image contains a pole but did not detect a meridian crossing!";
988 geos::geom::CoordinateSequence *new_points =
new geos::geom::CoordinateArraySequence();
989 for (
unsigned int i = 0; i <
p_pts->size(); i++) {
990 geos::geom::Coordinate temp =
p_pts->getAt(i);
991 new_points->add(temp);
992 if (temp.equals(*closestPoint)) {
994 if (i + 1 !=
p_pts->size()) {
995 double fromLon, toLon;
996 if ((
p_pts->getAt(i + 1).x - closestPoint->x) > 0) {
1005 geos::algorithm::LineIntersector lineIntersector;
1006 geos::geom::Coordinate crossingPoint;
1007 geos::geom::Coordinate nPole(0.0, 90.0);
1008 geos::geom::Coordinate sPole(0.0, -90.0);
1009 double dist = DBL_MAX;
1011 for (
int num = 0; num < 2 && dist > 180.0; num ++) {
1012 nPole = geos::geom::Coordinate(num * 360.0, 90.0);
1013 sPole = geos::geom::Coordinate(num * 360.0, -90.0);
1015 if (temp.x > 0.0 &&
p_pts->getAt(i + 1).x > 0.0) {
1016 crossingPoint = geos::geom::Coordinate(
p_pts->getAt(i + 1).x - 360.0 + (num * 720.0),
p_pts->getAt(i + 1).y);
1018 else if (temp.x < 0.0 &&
p_pts->getAt(i + 1).x < 0.0) {
1019 crossingPoint = geos::geom::Coordinate(
p_pts->getAt(i + 1).x + 360.0 - (num * 720.0),
p_pts->getAt(i + 1).y);
1025 lineIntersector.computeIntersection(nPole, sPole, temp, crossingPoint);
1027 if (lineIntersector.hasIntersection()) {
1028 const geos::geom::Coordinate &intersection = lineIntersector.getIntersection(0);
1031 if (pole->y < intersection.y) {
1034 vector<double> lats;
1035 double maxLat = std::max(intersection.y, pole->y);
1036 double minLat = std::min(intersection.y, pole->y);
1037 for (
double lat = intersection.y + dist; lat < maxLat && lat > minLat; lat += dist) {
1038 lats.push_back(lat);
1042 new_points->add(geos::geom::Coordinate(fromLon, intersection.y));
1043 for (
int lat = 0; lat < (int)lats.size(); lat ++) {
1044 new_points->add(geos::geom::Coordinate(fromLon, lats[lat]));
1046 new_points->add(geos::geom::Coordinate(fromLon, pole->y));
1047 new_points->add(geos::geom::Coordinate(toLon, pole->y));
1048 for (
int lat = lats.size() - 1; lat >= 0; lat --) {
1049 new_points->add(geos::geom::Coordinate(toLon, lats[lat]));
1051 new_points->add(geos::geom::Coordinate(toLon, intersection.y));
1054 std::string msg =
"Image contains a pole but could not determine a meridian crossing!";
1142 bool convertLon =
false;
1143 bool negAdjust =
false;
1144 bool newCoords =
false;
1145 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
1147 double lonOffset = 0;
1148 double prevLon =
p_pts->getAt(0).x;
1149 double prevLat =
p_pts->getAt(0).y;
1151 newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat));
1153 for (
unsigned int i = 1; i <
p_pts->getSize(); i++) {
1154 lon =
p_pts->getAt(i).x;
1155 lat =
p_pts->getAt(i).y;
1157 if (abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) {
1165 if ((lon - prevLon) > 0) {
1169 else if ((lon - prevLon) < 0) {
1180 if (newCoords && dist == 0.0) {
1181 double longitude = (lon + lonOffset) - prevLon;
1182 double latitude = lat - prevLat;
1183 dist = std::sqrt((longitude * longitude) + (latitude * latitude));
1187 newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat));
1196 geos::geom::Polygon *newPoly = globalFactory->createPolygon
1197 (globalFactory->createLinearRing(newLonLatPts), NULL);
1199 delete newLonLatPts;
1205 geos::geom::Polygon *newPoly = globalFactory->createPolygon
1206 (globalFactory->createLinearRing(newLonLatPts), NULL);
1208 geos::geom::CoordinateSequence *pts =
new geos::geom::CoordinateArraySequence();
1209 geos::geom::CoordinateSequence *pts2 =
new geos::geom::CoordinateArraySequence();
1217 pts->add(geos::geom::Coordinate(0., 90.));
1218 pts->add(geos::geom::Coordinate(-360., 90.));
1219 pts->add(geos::geom::Coordinate(-360., -90.));
1220 pts->add(geos::geom::Coordinate(0., -90.));
1221 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
1222 pts->add(geos::geom::Coordinate(0.0, lat));
1224 pts->add(geos::geom::Coordinate(0., 90.));
1225 pts2->add(geos::geom::Coordinate(0., 90.));
1226 pts2->add(geos::geom::Coordinate(360., 90.));
1227 pts2->add(geos::geom::Coordinate(360., -90.));
1228 pts2->add(geos::geom::Coordinate(0., -90.));
1229 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
1230 pts2->add(geos::geom::Coordinate(0.0, lat));
1232 pts2->add(geos::geom::Coordinate(0., 90.));
1235 pts->add(geos::geom::Coordinate(360., 90.));
1236 pts->add(geos::geom::Coordinate(720., 90.));
1237 pts->add(geos::geom::Coordinate(720., -90.));
1238 pts->add(geos::geom::Coordinate(360., -90.));
1239 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
1240 pts->add(geos::geom::Coordinate(360.0, lat));
1242 pts->add(geos::geom::Coordinate(360., 90.));
1243 pts2->add(geos::geom::Coordinate(360., 90.));
1244 pts2->add(geos::geom::Coordinate(0., 90.));
1245 pts2->add(geos::geom::Coordinate(0., -90.));
1246 pts2->add(geos::geom::Coordinate(360., -90.));
1247 for (
double lat = -90.0 + dist; lat < 90.0; lat += dist) {
1248 pts2->add(geos::geom::Coordinate(360.0, lat));
1250 pts2->add(geos::geom::Coordinate(360., 90.));
1253 geos::geom::Polygon *boundaryPoly = globalFactory->createPolygon
1254 (globalFactory->createLinearRing(pts), NULL);
1255 geos::geom::Polygon *boundaryPoly2 = globalFactory->createPolygon
1256 (globalFactory->createLinearRing(pts2), NULL);
1264 delete intersection;
1268 delete intersection;
1275 vector<geos::geom::Geometry *> *finalpolys =
new vector<geos::geom::Geometry *>;
1276 geos::geom::Geometry *newGeom = NULL;
1278 for (
unsigned int i = 0; i < convertPoly->getNumGeometries(); i++) {
1279 newGeom = (convertPoly->getGeometryN(i))->clone();
1280 pts = convertPoly->getGeometryN(i)->getCoordinates();
1281 geos::geom::CoordinateSequence *newLonLatPts =
new geos::geom::CoordinateArraySequence();
1284 for (
unsigned int k = 0; k < pts->getSize() ; k++) {
1285 double lon = pts->getAt(k).x;
1286 double lat = pts->getAt(k).y;
1293 newLonLatPts->add(geos::geom::Coordinate(lon, lat), k);
1297 finalpolys->push_back(globalFactory->createPolygon
1298 (globalFactory->createLinearRing(newLonLatPts), NULL));
1302 for (
unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) {
1303 newGeom = (convertPoly2->getGeometryN(i))->clone();
1304 finalpolys->push_back(newGeom);
1307 p_polygons = globalFactory->createMultiPolygon(*finalpolys);
1311 delete newLonLatPts;
1315 catch(geos::util::IllegalArgumentException *geosIll) {
1316 std::string msg =
"Unable to create image footprint (Fix360Poly) due to ";
1317 msg +=
"geos illegal argument [" +
IString(geosIll->what()) +
"]";
1321 catch(geos::util::GEOSException *geosExc) {
1322 std::string msg =
"Unable to create image footprint (Fix360Poly) due to ";
1323 msg +=
"geos exception [" +
IString(geosExc->what()) +
"]";
1328 std::string msg =
"Unable to create image footprint (Fix360Poly) due to ";
1329 msg +=
"isis operation exception [" +
IString(e.
what()) +
"]";
1333 std::string msg =
"Unable to create image footprint (Fix360Poly) due to ";
1334 msg +=
"unknown exception";
1348 geos::io::WKTWriter *wkt =
new geos::io::WKTWriter();
1352 string msg =
"Cannot write a NULL polygon!";
1359 Blob newBlob(
"Footprint",
"Polygon");
1374 return ((p2->x - p1->x) * (p2->x - p1->x)) + ((p2->y - p1->y) * (p2->y - p1->y));
1384 bool hasFourCorners =
true;
1389 return !hasFourCorners;
1408 geos::geom::Coordinate newPoint,
1409 geos::geom::Coordinate lastPoint) {
1410 geos::geom::Coordinate result = newPoint;
1415 double x = lastPoint.x;
1416 double y = lastPoint.y;
1429 geos::geom::Coordinate invalid(x, y);
1430 geos::geom::Coordinate valid(result.x, result.y);
1433 while (!
SetImage(invalid.x, invalid.y)) {
1435 if (invalid.x > valid.x) {
1436 x = (int)invalid.x - 1;
1438 else if (invalid.x < valid.x) {
1439 x = (int)invalid.x + 1;
1444 if (invalid.y > valid.y) {
1445 y = (int)invalid.y - 1;
1447 else if (invalid.y < valid.y) {
1448 y = (int)invalid.y + 1;
1453 invalid = geos::geom::Coordinate(x, y);
1473 geos::geom::Coordinate newPoint) {
1474 geos::geom::Coordinate originalPoint = newPoint;
1475 geos::geom::Coordinate modPoint = newPoint;
1483 else if (currentPoint->x < newPoint.x && currentPoint->y > newPoint.y) {
1484 while (newPoint.x >= currentPoint->x &&
SetImage(newPoint.x, newPoint.y)) {
1485 modPoint = newPoint;
1491 else if (currentPoint->y < newPoint.y && currentPoint->x < newPoint.x) {
1492 while (newPoint.y >= currentPoint->y &&
SetImage(newPoint.x, newPoint.y)) {
1493 modPoint = newPoint;
1499 else if (currentPoint->x > newPoint.x && currentPoint->y < newPoint.y) {
1500 while (newPoint.x <= currentPoint->x &&
SetImage(newPoint.x, newPoint.y)) {
1501 modPoint = newPoint;
1507 else if (currentPoint->y > newPoint.y && currentPoint->x > newPoint.x) {
1508 while (newPoint.y <= currentPoint->y &&
SetImage(newPoint.x, newPoint.y)) {
1509 modPoint = newPoint;
1514 if (currentPoint->x == modPoint.x && currentPoint->y == modPoint.y) {
1515 return originalPoint;
1532 geos::geom::Coordinate old = points.at(0);
1533 bool didStartingPoint =
false;
1534 for (
unsigned int pt = 1; !didStartingPoint; pt ++) {
1535 if (pt >= points.size() - 1) {
1537 didStartingPoint =
true;
1542 double stepY = (old.x - points.at(pt + 1).x) / maxStep;
1543 double stepX = (points.at(pt + 1).y - old.y) / maxStep;
1545 geos::geom::Coordinate valid = points.at(pt);
1546 geos::geom::Coordinate invalid(valid.x + stepX, valid.y + stepY);
1549 geos::geom::Coordinate half((valid.x + invalid.x) / 2.0, (valid.y + invalid.y) / 2.0);
1558 old = points.at(pt);
1566 points[points.size()-1] = geos::geom::Coordinate(points[0].x, points[0].y);