File failed to load: https://isis.astrogeology.usgs.gov/6.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
ImagePolygon.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 
8 #include "IsisDebug.h"
9 
10 #include <string>
11 #include <iostream>
12 #include <vector>
13 
14 #include <QDebug>
15 
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>
26 
27 #include "ImagePolygon.h"
28 #include "IString.h"
29 #include "SpecialPixel.h"
30 #include "PolygonTools.h"
31 
32 using namespace std;
33 
34 namespace Isis {
35 
40  ImagePolygon::ImagePolygon() {
41  p_polygons = NULL;
42 
43  p_cube = NULL;
44 
45  m_leftCoord = NULL;
46  m_rightCoord = NULL;
47  m_topCoord = NULL;
48  m_botCoord = NULL;
49 
50  p_cubeStartSamp = 1;
51  p_cubeStartLine = 1;
52 
53  p_emission = 180.0;
54  p_incidence = 180.0;
55 
56  p_subpixelAccuracy = 50; //An accuracte and quick number
57 
58  p_ellipsoid = false;
59  }
60 
61 
66  ImagePolygon::ImagePolygon(Blob &blob) : ImagePolygon() {
67  p_polyStr = string(blob.getBuffer(), blob.Size());
68 
69  geos::io::WKTReader *wkt = new geos::io::WKTReader(&(*globalFactory));
71 
72  p_pts = new geos::geom::CoordinateArraySequence;
73 
74  for (auto poly : *p_polygons) {
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)));
78  }
79  }
80 
81  delete wkt;
82  }
83 
84 
87  delete p_polygons;
88  p_polygons = NULL;
89 
90  p_cube = NULL;
91 
92  delete m_leftCoord;
93  m_leftCoord = NULL;
94 
95  delete m_rightCoord;
96  m_rightCoord = NULL;
97 
98  delete m_topCoord;
99  m_topCoord = NULL;
100 
101  delete m_botCoord;
102  m_botCoord = NULL;
103  }
104 
105 
121  Camera * ImagePolygon::initCube(Cube &cube, int ss, int sl,
122  int ns, int nl, int band) {
123  p_gMap = new UniversalGroundMap(cube);
124  p_gMap->SetBand(band);
125 
126  p_cube = &cube;
127 
128  Camera *cam = NULL;
129  p_isProjected = false;
130 
131  try {
132  cam = cube.camera();
133  }
134  catch(IException &camError) {
135  try {
136  cube.projection();
137  p_isProjected = true;
138  }
139  catch(IException &projError) {
140  QString msg = "Can not create polygon, ";
141  msg += "cube [" + cube.fileName();
142  msg += "] is not a camera or map projection";
143 
144  IException polyError(IException::User, msg, _FILEINFO_);
145 
146  polyError.append(camError);
147  polyError.append(projError);
148 
149  throw polyError;
150  }
151  }
152  if (cam != NULL) p_isProjected = cam->HasProjection();
153 
154  // Create brick for use in SetImage
155  p_brick = new Brick(1, 1, 1, cube.pixelType());
156 
157  //------------------------------------------------------------------------
158  // Save cube number of samples and lines for later use.
159  //------------------------------------------------------------------------
160  p_cubeSamps = cube.sampleCount();
161  p_cubeLines = cube.lineCount();
162 
163  if (ns != 0) {
164  p_cubeSamps = std::min(p_cubeSamps, ss + ns);
165  }
166 
167  if (nl != 0) {
168  p_cubeLines = std::min(p_cubeLines, sl + nl);
169  }
170 
171  p_cubeStartSamp = ss;
172  p_cubeStartLine = sl;
173 
174  if (p_ellipsoid && IsLimb() && p_gMap->Camera()) {
175  try {
177  }
178  catch(IException &) {
179  std::string msg = "Cannot use an ellipsoid shape model";
180  msg += " on a limb image without a camera.";
181  throw IException(IException::User, msg, _FILEINFO_);
182  }
183  }
184 
185  return cam;
186  }
187 
188 
217  void ImagePolygon::Create(Cube &cube, int sinc, int linc,
218  int ss, int sl, int ns, int nl, int band,
219  bool increasePrecision) {
220 
221  Camera *cam = NULL;
222 
223  if (sinc < 1 || linc < 1) {
224  std::string msg = "Sample and line increments must be 1 or greater";
225  throw IException(IException::User, msg, _FILEINFO_);
226  }
227 
228  cam = initCube(cube, ss, sl, ns, nl, band);
229 
230  // Reduce the increment size to find a valid polygon
231  bool polygonGenerated = false;
232  while (!polygonGenerated) {
233  try {
234  p_sampinc = sinc;
235  p_lineinc = linc;
236 
237  p_pts = NULL;
238  p_pts = new geos::geom::CoordinateArraySequence();
239 
240  WalkPoly();
241 
242  polygonGenerated = true;
243  }
244  catch (IException &e) {
245  delete p_pts;
246 
247  sinc = sinc * 2 / 3;
248  linc = linc * 2 / 3;
249 
250  if (increasePrecision && (sinc > 1 || linc > 1)) {
251  }
252  else {
253  e.print(); // This should be a NAIF error
254  QString msg = "Cannot find polygon for image "
255  "[" + cube.fileName() + "]: ";
256  msg += increasePrecision ? "Cannot increase precision any further" :
257  "The increment/step size might be too large";
258  throw IException(IException::User, msg, _FILEINFO_);
259  }
260  }
261  }
262 
263  /*------------------------------------------------------------------------
264  / If image contains 0/360 boundary, the polygon needs to be split up
265  / into multi polygons.
266  /-----------------------------------------------------------------------*/
267  if (cam) {
268  Pvl defaultMap;
269  cam->BasicMapping(defaultMap);
270  }
271 
272  // Create the polygon, fixing if needed
273  Fix360Poly();
274 
275  if (p_brick != 0) delete p_brick;
276 
277  if (p_gMap->Camera())
279  }
280 
281 
282  void ImagePolygon::Create(std::vector<std::vector<double>> polyCoordinates) {
283  p_pts = new geos::geom::CoordinateArraySequence();
284 
285  for (std::vector<double> coord : polyCoordinates) {
286  p_pts->add(geos::geom::Coordinate(coord[0], coord[1]));
287  }
288 
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);
293 
294  delete polys;
295 
296  Fix360Poly();
297  }
298 
299 
316  geos::geom::Coordinate ImagePolygon::FindNextPoint(geos::geom::Coordinate *currentPoint,
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;
322 
323  // Check to see if depth is too deep (walked all the way around and found nothing)
324  if (recursionDepth > 6) {
325  return *currentPoint;
326  }
327 
328  // Check and walk in appropriate direction
329  if (x == 0.0 && y == 0.0) { // Find the starting point on an image
330  for (int line = -1 * p_lineinc; line <= 1 * p_lineinc; line += p_lineinc) {
331  for (int samp = -1 * p_sampinc; samp <= 1 * p_sampinc; samp += p_sampinc) {
332  double s = currentPoint->x + samp;
333  double l = currentPoint->y + line;
334  // Try the next left hand rule point if (s,l) does not produce a
335  // lat/long or it is not on the image.
336  if (!InsideImage(s, l) || !SetImage(s, l)) {
337  geos::geom::Coordinate next(s, l);
338  return FindNextPoint(currentPoint, next);
339  }
340  }
341  }
342 
343  std::string msg = "Unable to create image footprint. Starting point is not on the edge of the image.";
344  throw IException(IException::Programmer, msg, _FILEINFO_);
345  }
346  else if (x < 0 && y < 0) { // current is top left
347  geos::geom::Coordinate next(currentPoint->x, currentPoint->y - 1 * p_lineinc);
348  MoveBackInsideImage(next.x, next.y, 0, -p_lineinc);
349  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
350  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
351  }
352  else {
353  result = FindBestPoint(currentPoint, next, lastPoint);
354  }
355  }
356  else if (x == 0.0 && y < 0) { // current is top
357  geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y - 1 * p_lineinc);
358  MoveBackInsideImage(next.x, next.y, p_sampinc, -p_lineinc);
359  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
360  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
361  }
362  else {
363  result = FindBestPoint(currentPoint, next, lastPoint);
364  }
365  }
366  else if (x > 0 && y < 0) { // current is top right
367  geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y);
368  MoveBackInsideImage(next.x, next.y, p_sampinc, 0);
369  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
370  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
371  }
372  else {
373  result = FindBestPoint(currentPoint, next, lastPoint);
374  }
375  }
376  else if (x > 0 && y == 0.0) { // current is right
377  geos::geom::Coordinate next(currentPoint->x + 1 * p_sampinc, currentPoint->y + 1 * p_lineinc);
378  MoveBackInsideImage(next.x, next.y, p_sampinc, p_lineinc);
379  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
380  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
381  }
382  else {
383  result = FindBestPoint(currentPoint, next, lastPoint);
384  }
385  }
386  else if (x > 0 && y > 0) { // current is bottom right
387  geos::geom::Coordinate next(currentPoint->x, currentPoint->y + 1 * p_lineinc);
388  MoveBackInsideImage(next.x, next.y, 0, p_lineinc);
389  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
390  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
391  }
392  else {
393  result = FindBestPoint(currentPoint, next, lastPoint);
394  }
395  }
396  else if (x == 0.0 && y > 0) { // current is bottom
397  geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y + 1 * p_lineinc);
398  MoveBackInsideImage(next.x, next.y, -p_sampinc, p_lineinc);
399  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
400  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
401  }
402  else {
403  result = FindBestPoint(currentPoint, next, lastPoint);
404  }
405  }
406  else if (x < 0 && y > 0) { // current is bottom left
407  geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y);
408  MoveBackInsideImage(next.x, next.y, -p_sampinc, 0);
409  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
410  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
411  }
412  else {
413  result = FindBestPoint(currentPoint, next, lastPoint);
414  }
415  }
416  else if (x < 0 && y == 0.0) { // current is left
417  geos::geom::Coordinate next(currentPoint->x - 1 * p_sampinc, currentPoint->y - 1 * p_lineinc);
418  MoveBackInsideImage(next.x, next.y, -p_sampinc, -p_lineinc);
419  if (!recursionDepth || !InsideImage(next.x, next.y) || !SetImage(next.x , next.y)) {
420  result = FindNextPoint(currentPoint, next, recursionDepth + 1);
421  }
422  else {
423  result = FindBestPoint(currentPoint, next, lastPoint);
424  }
425  }
426  else {
427  std::string msg = "Unable to create image footprint. Error walking image.";
428  throw IException(IException::Unknown, msg, _FILEINFO_);
429  }
430 
431 
432  return result;
433  }
434 
435 
446  void ImagePolygon::MoveBackInsideImage(double &sample, double &line, double sinc, double linc) {
447  // snap to centers of pixels!
448 
449  // Starting sample to snap to
450  const double startSample = p_cubeStartSamp;
451  // Ending sample to snap to
452  const double endSample = p_cubeSamps;
453  // Starting line to snap to
454  const double startLine = p_cubeStartLine;
455  // Ending line to snap to
456  const double endLine = p_cubeLines;
457  // Original sample for this point (before sinc)
458  const double origSample = sample - sinc;
459  // Original line for this point (before linc)
460  const double origLine = line - linc;
461 
462  // We moved left off the image - snap to the edge
463  if (sample < startSample && sinc < 0) {
464  // don't snap if we started at the edge
465  if (origSample == startSample) {
466  return;
467  }
468 
469  sample = startSample;
470  }
471 
472  // We moved right off the image - snap to the edge
473  if (sample > endSample && sinc > 0) {
474  // don't snap if we started at the edge
475  if (origSample == endSample) {
476  return;
477  }
478 
479  sample = endSample;
480  }
481 
482  // We moved up off the image - snap to the edge
483  if (line < startLine && linc < 0) {
484  // don't snap if we started at the edge
485  if (origLine == startLine) {
486  return;
487  }
488 
489  line = startLine;
490  }
491 
492  // We moved down off the image - snap to the edge
493  if (line > endLine && linc > 0) {
494  // don't snap if we started at the edge
495  if (fabs(origLine - endLine) < 0.5) {
496  return;
497  }
498 
499  line = endLine;
500  }
501 
502  return;
503  }
504 
505 
514  bool ImagePolygon::InsideImage(double sample, double line) {
515  return (sample >= p_cubeStartSamp - 0.5 &&
516  line > p_cubeStartLine - 0.5 &&
517  sample <= p_cubeSamps + 0.5 &&
518  line <= p_cubeLines + 0.5);
519  }
520 
521 
528  geos::geom::Coordinate ImagePolygon::FindFirstPoint() {
529  // @todo: Brute force method, should be improved
530  for (int sample = p_cubeStartSamp; sample <= p_cubeSamps; sample++) {
531  for (int line = p_cubeStartLine; line <= p_cubeLines; line++) {
532  if (SetImage(sample, line)) {
533  // An outlier check. Make sure that the pixel we use to start
534  // constructing a polygon is not surrounded by a bunch of invalid
535  // positions.
536  geos::geom::Coordinate firstPoint(sample, line);
537  geos::geom::Coordinate lastPoint = firstPoint;
538  if (!firstPoint.equals(FindNextPoint(&firstPoint, lastPoint))) {
539  return firstPoint;
540  }
541  }
542  }
543  }
544 
545  // Check to make sure a point was found
546  std::string msg = "No lat/lon data found for image";
547  throw IException(IException::User, msg, _FILEINFO_);
548  }
549 
550 
556  double result = 0.0;
557 
559  if (m_rightCoord && m_leftCoord)
560  result = m_rightCoord->x - m_leftCoord->x + 1;
561 
562  return result;
563  }
564 
565 
571  double result = 0.0;
572 
574  if (m_topCoord && m_botCoord)
575  result = m_botCoord->y - m_topCoord->y + 1;
576 
577  return result;
578  }
579 
580 
590  ASSERT(p_cube);
591 
592  for (int line = p_cubeStartLine; !m_leftCoord && line <= p_cubeLines; line++) {
593  for (int sample = p_cubeStartSamp; !m_leftCoord && sample <= p_cubeSamps; sample++) {
594  if (SetImage(sample, line)) {
595  m_leftCoord = new geos::geom::Coordinate(sample, line);
596  }
597  }
598  }
599 
600  if (m_leftCoord) {
601  for (int line = p_cubeStartLine; !m_rightCoord && line <= p_cubeLines; line++) {
602  for (int sample = p_cubeSamps; !m_rightCoord && sample >= m_leftCoord->x; sample--) {
603  if (SetImage(sample, line)) {
604  m_rightCoord = new geos::geom::Coordinate(sample, line);
605  }
606  }
607  }
608  }
609 
610  if (m_leftCoord && m_rightCoord) {
611  for (int sample = (int)m_leftCoord->x; !m_topCoord && sample <= m_rightCoord->x; sample++) {
612  for (int line = 1; !m_topCoord && line <= p_cubeLines; line++) {
613  if (SetImage(sample, line)) {
614  m_topCoord = new geos::geom::Coordinate(sample, line);
615  }
616  }
617  }
618  }
619 
620  if (m_leftCoord && m_rightCoord && m_topCoord) {
621  for (int sample = (int)m_leftCoord->x; !m_botCoord && sample <= m_rightCoord->x; sample++) {
622  for (int line = p_cube->lineCount(); !m_botCoord && line >= m_topCoord->y; line--) {
623  if (SetImage(sample, line)) {
624  m_botCoord = new geos::geom::Coordinate(sample, line);
625  }
626  }
627  }
628  }
629  }
630 
631 
639  vector<geos::geom::Coordinate> points;
640  double lat, lon, prevLat, prevLon;
641 
642  // Find the edge of the polygon
643  geos::geom::Coordinate firstPoint = FindFirstPoint();
644  points.push_back(firstPoint);
645  //************************
646  // Start walking the edge
647  //************************
648 
649  // set up for intialization
650  geos::geom::Coordinate currentPoint = firstPoint;
651  geos::geom::Coordinate lastPoint = firstPoint;
652  geos::geom::Coordinate tempPoint;
653 
654  do {
655  tempPoint = FindNextPoint(&currentPoint, lastPoint);
656  //exit(1);
657 
658 
659  // First check if the distance is within range of skipping
660  bool snapToFirstPoint = true;
661 
662  // Never needs to find firstPoint on incements of 1
663  snapToFirstPoint &= (p_sampinc != 1 && p_lineinc != 1);
664 
665  // Prevents catching the first point as the last
666  snapToFirstPoint &= (points.size() > 2);
667 
668  // This method fails for steps larger than line/sample length
669  snapToFirstPoint &= (p_sampinc < p_cubeSamps && p_lineinc < p_cubeLines);
670 
671  // Checks for appropriate distance without sqrt() call
672  int minStepSize = std::min(p_sampinc, p_lineinc);
673  snapToFirstPoint &= (DistanceSquared(&currentPoint, &firstPoint) < (minStepSize * minStepSize));
674 
675  // Searches for skipped firstPoint due to a large pixinc, by using a pixinc of 1
676  if (snapToFirstPoint) {
677  tempPoint = firstPoint;
678  }
679  // If pixinc is greater than line or sample dimention, then we could
680  // skip firstPoint. This checks for that case.
681  else if (p_sampinc > p_cubeSamps || p_lineinc > p_cubeLines) {
682  // This is not expensive because incement must be large
683  for (int pt = 0; pt < (int)points.size(); pt ++) {
684  if (points[pt].equals(tempPoint)) {
685  tempPoint = firstPoint;
686  break;
687  }
688  }
689  }
690 
691  // Failed to find the next point
692  if (tempPoint.equals(currentPoint)) {
693  geos::geom::Coordinate oldDuplicatePoint = tempPoint;
694 
695  // Init vars for first run through the loop
696  tempPoint = lastPoint;
697  lastPoint = currentPoint;
698  currentPoint = tempPoint;
699 
700  // Must be 3 (not 2) to prevent the revisit of the starting point,
701  // resulting in an infinite loop
702  if (points.size() < 3) {
703  std::string msg = "Failed to find next point in the image.";
704  throw IException(IException::Programmer, msg, _FILEINFO_);
705  }
706 
707  // remove last point from the list
708  points.pop_back();
709 
710  tempPoint = FindNextPoint(&currentPoint, lastPoint, 1);
711 
712  if (tempPoint.equals(currentPoint) || tempPoint.equals(oldDuplicatePoint)) {
713  std::string msg = "Failed to find next valid point in the image.";
714  throw IException(IException::Programmer, msg, _FILEINFO_);
715  }
716  }
717 
718 
719  // Check for triangle cycles and try to fix
720  if ((p_sampinc > 1 || p_lineinc > 1) && points.size() >= 3) {
721  if (points[points.size()-3].x == tempPoint.x &&
722  points[points.size()-3].y == tempPoint.y) {
723  // Remove the triangle from the list
724  points.pop_back();
725  points.pop_back();
726  points.pop_back();
727  // Reset the current (to be last) point
728  currentPoint = points[points.size()-1];
729  // change increment to prevent randomly bad pixels in the image
730  if (p_sampinc > 1) p_sampinc --;
731  if (p_lineinc > 1) p_lineinc --;
732  }
733 
740  if (points.size() > 250) {
741  int cycleStart = 0;
742  int cycleEnd = 0;
743 
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]) {
747  cycleStart = pt;
748  cycleEnd = check;
749  }
750  }
751  }
752 
753  // If a cycle was found, make it the polygon
754  if (cycleStart != 0) {
755  vector<geos::geom::Coordinate> cyclePoints;
756  for (int pt = cycleStart; pt <= cycleEnd; pt ++) {
757  cyclePoints.push_back(points[pt]);
758  }
759 
760  points = cyclePoints;
761  break;
762  }
763  }
764 
765  }
766 
767  lastPoint = currentPoint;
768  currentPoint = tempPoint;
769  points.push_back(currentPoint);
770 
771  }
772  while (!currentPoint.equals(firstPoint));
773 
774  if (points.size() <= 3) {
775  std::string msg = "Failed to find enough points on the image.";
776  throw IException(IException::Programmer, msg, _FILEINFO_);
777  }
778 
779  FindSubpixel(points);
780 
781  prevLat = 0;
782  prevLon = 0;
783  // this vector stores crossing points, where the image crosses the
784  // meridian. It stores the first coordinate of the pair in its vector
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));
788  SetImage(temp->x, temp->y);
789  lon = p_gMap->UniversalLongitude();
790  lat = p_gMap->UniversalLatitude();
791  if (abs(lon - prevLon) >= 180 && i != 0) {
792  crossingPoints->push_back(geos::geom::Coordinate(prevLon, prevLat));
793  }
794  p_pts->add(geos::geom::Coordinate(lon, lat));
795  prevLon = lon;
796  prevLat = lat;
797  }
798 
799 
800  // Checks for self-intersection and attempts to correct
801  geos::geom::CoordinateSequence *tempPts = new geos::geom::CoordinateArraySequence();
802 
803  // Gets the starting, second, second to last, and last points to check for validity
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));
806  tempPts->add(geos::geom::Coordinate((*p_pts)[p_pts->size()-3].x, (*p_pts)[p_pts->size()-3].y));
807  tempPts->add(geos::geom::Coordinate((*p_pts)[p_pts->size()-2].x, (*p_pts)[p_pts->size()-2].y));
808  tempPts->add(geos::geom::Coordinate((*p_pts)[0].x, (*p_pts)[0].y));
809 
810  geos::geom::Polygon *tempPoly = globalFactory->createPolygon
811  (globalFactory->createLinearRing(tempPts), NULL);
812 
813  // Remove the last point of the sequence if it produces invalid polygons
814  if (!tempPoly->isValid()) {
815  p_pts->deleteAt(p_pts->size() - 2);
816  }
817 
818  delete tempPts;
819  tempPts = NULL;
820  // end self-intersection check
821 
822  FixPolePoly(crossingPoints);
823  delete crossingPoints;
824  crossingPoints = NULL;
825  }
826 
827 
835  void ImagePolygon::FixPolePoly(std::vector<geos::geom::Coordinate> *crossingPoints) {
836  // We currently do not support both poles in one image
837  bool hasNorthPole = false;
838  bool hasSouthPole = false;
839 
840  if (p_gMap->SetUniversalGround(90, 0)) {
841  double nPoleSample = Null;
842  double nPoleLine = Null;
843 
844  if (p_gMap->Projection()) {
845  nPoleSample = p_gMap->Projection()->WorldX();
846  nPoleLine = p_gMap->Projection()->WorldY();
847  }
848  else if (p_gMap->Camera()) {
849  nPoleSample = p_gMap->Camera()->Sample();
850  nPoleLine = p_gMap->Camera()->Line();
851  }
852 
853  if (nPoleSample >= 0.5 && nPoleLine >= 0.5 &&
854  nPoleSample <= p_cube->sampleCount() + 0.5 &&
855  nPoleLine <= p_cube->lineCount() + 0.5) {
856  hasNorthPole = true;
857  }
858  }
859 
860  if (p_gMap->SetUniversalGround(-90, 0)) {
861  double sPoleSample = Null;
862  double sPoleLine = Null;
863 
864  if (p_gMap->Projection()) {
865  sPoleSample = p_gMap->Projection()->WorldX();
866  sPoleLine = p_gMap->Projection()->WorldY();
867  }
868  else if (p_gMap->Camera()) {
869  sPoleSample = p_gMap->Camera()->Sample();
870  sPoleLine = p_gMap->Camera()->Line();
871  }
872 
873  if (sPoleSample >= 0.5 && sPoleLine >= 0.5 &&
874  sPoleSample <= p_cube->sampleCount() + 0.5 &&
875  sPoleLine <= p_cube->lineCount() + 0.5) {
876  hasSouthPole = true;
877  }
878  }
879 
880  if (hasNorthPole && hasSouthPole) {
881  std::string msg = "Unable to create image footprint because image has both poles";
882  throw IException(IException::Programmer, msg, _FILEINFO_);
883  }
884  else if (crossingPoints->size() == 0) {
885  // No crossing points
886  return;
887  }
888 
889  if (hasNorthPole) {
890  p_gMap->SetUniversalGround(90, 0);
891 
892  // If the (north) pole is settable but not within proper angles,
893  // then the polygon does not contain the (north) pole when the cube does
894  if (p_gMap->Camera() &&
896  return;
897  }
898  if (p_gMap->Camera() &&
900  return;
901  }
902  }
903  else if (hasSouthPole) {
904  p_gMap->SetUniversalGround(-90, 0);
905 
906  // If the (south) pole is settable but not within proper angles,
907  // then the polygon does not contain the (south) pole when the cube does
908  if (p_gMap->Camera() &&
910  return;
911  }
912  if (p_gMap->Camera() &&
914  return;
915  }
916  }
917 
918  geos::geom::Coordinate *closestPoint = &crossingPoints->at(0);
919  geos::geom::Coordinate *pole = NULL;
920 
921  // Setup the right pole
922  if (hasNorthPole) {
923  pole = new geos::geom::Coordinate(0, 90);
924  }
925  else if (hasSouthPole) {
926  pole = new geos::geom::Coordinate(0, -90);
927  }
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;
933 
934  for (unsigned int index = 0; index < p_pts->size(); index ++) {
935  double north = DistanceSquared(&nPole, &((*p_pts)[index]));
936  if (north < nDist) {
937  nDist = north;
938  }
939  double south = DistanceSquared(&sPole, &((*p_pts)[index]));
940  if (south < sDist) {
941  sDist = south;
942  }
943  }
944 
945  if (sDist < nDist) {
946  pole = new geos::geom::Coordinate(0, -90);
947  }
948  else {
949  pole = new geos::geom::Coordinate(0, 90);
950  }
951  }
952 
953  // Skip the fix if no pole was determined
954  if (pole == NULL) {
955  return;
956  }
957 
958  // Find where the pole needs to be split
959  double closestDistance = DBL_MAX;
960  for (unsigned int i = 0; i < crossingPoints->size(); i++) {
961  geos::geom::Coordinate *temp = &crossingPoints->at(i);
962  double tempDistance;
963  // Make sure the Lat is as close to 0 as possible for a correct distance
964  if (temp->x > 180) {
965  double mod = 0.0;
966  while ((temp->x - mod) > 180) mod += 360.0;
967 
968  // Create the modified Point, create a pointer to it, and find the distance
969  geos::geom::Coordinate modPointMem = geos::geom::Coordinate(temp->x - mod, temp->y);
970  geos::geom::Coordinate *modPoint = &modPointMem;
971  tempDistance = DistanceSquared(modPoint, pole);
972  }
973  else {
974  tempDistance = DistanceSquared(temp, pole);
975  }
976  if (tempDistance < closestDistance) {
977  closestDistance = tempDistance;
978  closestPoint = temp;
979  }
980  }
981 
982  if (closestDistance == DBL_MAX) {
983  std::string msg = "Image contains a pole but did not detect a meridian crossing!";
984  throw IException(IException::Programmer, msg, _FILEINFO_);
985  }
986 
987  // split image at the pole
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)) {
993  // Setup direction
994  if (i + 1 != p_pts->size()) { // Prevent overflow exception
995  double fromLon, toLon;
996  if ((p_pts->getAt(i + 1).x - closestPoint->x) > 0) {
997  fromLon = 0.0;
998  toLon = 360.0;
999  }
1000  else {
1001  fromLon = 360.0;
1002  toLon = 0.0;
1003  }
1004 
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;
1010 
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);
1014 
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);
1017  }
1018  else if (temp.x < 0.0 && p_pts->getAt(i + 1).x < 0.0) { // This should never happen
1019  crossingPoint = geos::geom::Coordinate(p_pts->getAt(i + 1).x + 360.0 - (num * 720.0), p_pts->getAt(i + 1).y);
1020  }
1021 
1022  dist = std::sqrt(DistanceSquared(&temp, &crossingPoint));
1023  }
1024 
1025  lineIntersector.computeIntersection(nPole, sPole, temp, crossingPoint);
1026 
1027  if (lineIntersector.hasIntersection()) {
1028  const geos::geom::Coordinate &intersection = lineIntersector.getIntersection(0);
1029 
1030  // Calculate the latituded of the points along the meridian
1031  if (pole->y < intersection.y) {
1032  dist = -dist;
1033  }
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);
1039  }
1040 
1041  // Add the new points
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]));
1045  }
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]));
1050  }
1051  new_points->add(geos::geom::Coordinate(toLon, intersection.y));
1052  }
1053  else {
1054  std::string msg = "Image contains a pole but could not determine a meridian crossing!";
1055  throw IException(IException::Programmer, msg, _FILEINFO_);
1056  }
1057 
1058  }
1059  }
1060  }
1061  delete p_pts;
1062  p_pts = new_points;
1063  delete pole;
1064  }
1065 
1066 
1079  bool ImagePolygon::SetImage(const double sample, const double line) {
1080  bool found = false;
1081  if (!p_isProjected) {
1082  found = p_gMap->SetImage(sample, line);
1083  if (!found) {
1084  return false;
1085  }
1086  else {
1087  // Check for valid emission and incidence
1088  try {
1089  if (p_gMap->Camera() &&
1091  return false;
1092  }
1093  if (p_gMap->Camera() &&
1095  return false;
1096  }
1097  }
1098  catch(IException &error) {
1099  }
1100 
1109  // Make sure we can go back to image coordinates
1110  // This is done because some camera models due to distortion, get
1111  // a lat/lon for samp/line=1:1, but entering that lat/lon does
1112  // not return samp/line =1:1. Ie. moc WA global images
1113  //double lat = p_gMap->UniversalLatitude();
1114  //double lon = p_gMap->UniversalLongitude();
1115  //return p_gMap->SetUniversalGround(lat,lon);
1116 
1117  return found;
1118  }
1119  }
1120  else {
1121  // If projected, make sure the pixel DN is valid before worrying about
1122  // geometry.
1123  p_brick->SetBasePosition((int)sample, (int)line, 1);
1124  p_cube->read(*p_brick);
1125  if (Isis::IsNullPixel((*p_brick)[0])) {
1126  return false;
1127  }
1128  else {
1129  return p_gMap->SetImage(sample, line);
1130  }
1131  }
1132  }
1133 
1134 
1142  bool convertLon = false;
1143  bool negAdjust = false;
1144  bool newCoords = false; // coordinates have been adjusted
1145  geos::geom::CoordinateSequence *newLonLatPts = new geos::geom::CoordinateArraySequence();
1146  double lon, lat;
1147  double lonOffset = 0;
1148  double prevLon = p_pts->getAt(0).x;
1149  double prevLat = p_pts->getAt(0).y;
1150 
1151  newLonLatPts->add(geos::geom::Coordinate(prevLon, prevLat));
1152  double dist = 0.0;
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;
1156  // check to see if you just crossed the Meridian
1157  if (abs(lon - prevLon) > 180 && (prevLat != 90 && prevLat != -90)) {
1158  newCoords = true;
1159  // if you were already converting then stop (crossed Meridian even number of times)
1160  if (convertLon) {
1161  convertLon = false;
1162  lonOffset = 0;
1163  }
1164  else { // Need to start converting again, deside how to adjust coordinates
1165  if ((lon - prevLon) > 0) {
1166  lonOffset = -360.;
1167  negAdjust = true;
1168  }
1169  else if ((lon - prevLon) < 0) {
1170  lonOffset = 360.;
1171  negAdjust = false;
1172  }
1173  convertLon = true;
1174  }
1175 
1176 
1177  }
1178 
1179  // Change to a minimum calculation
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));
1184  }
1185 
1186  // add coord
1187  newLonLatPts->add(geos::geom::Coordinate(lon + lonOffset, lat));
1188 
1189  // set current to old
1190  prevLon = lon;
1191  prevLat = lat;
1192  }
1193 
1194  // Nothing was done so return
1195  if (!newCoords) {
1196  geos::geom::Polygon *newPoly = globalFactory->createPolygon
1197  (globalFactory->createLinearRing(newLonLatPts), NULL);
1199  delete newLonLatPts;
1200  return;
1201  }
1202 
1203  // bisect into seperate polygons
1204  try {
1205  geos::geom::Polygon *newPoly = globalFactory->createPolygon
1206  (globalFactory->createLinearRing(newLonLatPts), NULL);
1207 
1208  geos::geom::CoordinateSequence *pts = new geos::geom::CoordinateArraySequence();
1209  geos::geom::CoordinateSequence *pts2 = new geos::geom::CoordinateArraySequence();
1210 
1211  // Depending on direction of compensation bound accordingly
1212  //***************************************************
1213 
1214  // please verify correct if you change these values
1215  //***************************************************
1216  if (negAdjust) {
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));
1223  }
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));
1231  }
1232  pts2->add(geos::geom::Coordinate(0., 90.));
1233  }
1234  else {
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));
1241  }
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));
1249  }
1250  pts2->add(geos::geom::Coordinate(360., 90.));
1251  }
1252 
1253  geos::geom::Polygon *boundaryPoly = globalFactory->createPolygon
1254  (globalFactory->createLinearRing(pts), NULL);
1255  geos::geom::Polygon *boundaryPoly2 = globalFactory->createPolygon
1256  (globalFactory->createLinearRing(pts2), NULL);
1257  /*------------------------------------------------------------------------
1258  / Intersecting the original polygon (converted coordinates) with the
1259  / boundary polygons will create the multi polygons with the converted coordinates.
1260  / These will need to be converted back to the original coordinates.
1261  /-----------------------------------------------------------------------*/
1262  geos::geom::Geometry *intersection = PolygonTools::Intersect(newPoly, boundaryPoly);
1263  geos::geom::MultiPolygon *convertPoly = PolygonTools::MakeMultiPolygon(intersection);
1264  delete intersection;
1265 
1266  intersection = PolygonTools::Intersect(newPoly, boundaryPoly2);
1267  geos::geom::MultiPolygon *convertPoly2 = PolygonTools::MakeMultiPolygon(intersection);
1268  delete intersection;
1269 
1270  /*------------------------------------------------------------------------
1271  / Adjust points created in the negative space or >360 space to be back in
1272  / the 0-360 world. This will always only need to be done on convertPoly.
1273  / Then add geometries to finalpolys.
1274  /-----------------------------------------------------------------------*/
1275  vector<geos::geom::Geometry *> *finalpolys = new vector<geos::geom::Geometry *>;
1276  geos::geom::Geometry *newGeom = NULL;
1277 
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();
1282  // fix the points
1283 
1284  for (unsigned int k = 0; k < pts->getSize() ; k++) {
1285  double lon = pts->getAt(k).x;
1286  double lat = pts->getAt(k).y;
1287  if (negAdjust) {
1288  lon = lon + 360;
1289  }
1290  else {
1291  lon = lon - 360;
1292  }
1293  newLonLatPts->add(geos::geom::Coordinate(lon, lat), k);
1294 
1295  }
1296  // Add the points to polys
1297  finalpolys->push_back(globalFactory->createPolygon
1298  (globalFactory->createLinearRing(newLonLatPts), NULL));
1299  }
1300 
1301  // This loop is over polygons that will always be in 0-360 space no need to convert
1302  for (unsigned int i = 0; i < convertPoly2->getNumGeometries(); i++) {
1303  newGeom = (convertPoly2->getGeometryN(i))->clone();
1304  finalpolys->push_back(newGeom);
1305  }
1306 
1307  p_polygons = globalFactory->createMultiPolygon(*finalpolys);
1308 
1309  delete finalpolys;
1310  delete newGeom;
1311  delete newLonLatPts;
1312  delete pts;
1313  delete pts2;
1314  }
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()) + "]";
1318  delete geosIll;
1319  throw IException(IException::Unknown, msg, _FILEINFO_);
1320  }
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()) + "]";
1324  delete geosExc;
1325  throw IException(IException::Unknown, msg, _FILEINFO_);
1326  }
1327  catch(IException &e) {
1328  std::string msg = "Unable to create image footprint (Fix360Poly) due to ";
1329  msg += "isis operation exception [" + IString(e.what()) + "]";
1330  throw IException(e, IException::Unknown, msg, _FILEINFO_);
1331  }
1332  catch(...) {
1333  std::string msg = "Unable to create image footprint (Fix360Poly) due to ";
1334  msg += "unknown exception";
1335  throw IException(IException::Unknown, msg, _FILEINFO_);
1336  }
1337  }
1338 
1339 
1348  geos::io::WKTWriter *wkt = new geos::io::WKTWriter();
1349 
1350  // Check to see p_polygons is valid data
1351  if (!p_polygons) {
1352  string msg = "Cannot write a NULL polygon!";
1353  throw IException(IException::Programmer, msg, _FILEINFO_);
1354  }
1355 
1356  string polyStr = wkt->write(p_polygons);
1357  delete wkt;
1358 
1359  Blob newBlob("Footprint", "Polygon");
1360  newBlob.setData(polyStr.c_str(), polyStr.size());
1361  return newBlob;
1362  }
1363 
1364 
1373  double ImagePolygon::DistanceSquared(const geos::geom::Coordinate *p1, const geos::geom::Coordinate *p2) {
1374  return ((p2->x - p1->x) * (p2->x - p1->x)) + ((p2->y - p1->y) * (p2->y - p1->y));
1375  }
1376 
1377 
1384  bool hasFourCorners = true;
1385  hasFourCorners &= SetImage(1, 1);
1386  hasFourCorners &= SetImage(p_cubeSamps, 1);
1387  hasFourCorners &= SetImage(p_cubeSamps, p_cubeLines);
1388  hasFourCorners &= SetImage(1, p_cubeLines);
1389  return !hasFourCorners;
1390  }
1391 
1392 
1393 
1407  geos::geom::Coordinate ImagePolygon::FindBestPoint(geos::geom::Coordinate *currentPoint,
1408  geos::geom::Coordinate newPoint,
1409  geos::geom::Coordinate lastPoint) {
1410  geos::geom::Coordinate result = newPoint;
1411  // Use a binary search to snap to the limb when needed
1412  if (p_sampinc > 1 || p_lineinc > 1) {
1413 
1414  // Pull the invalid point back inside the image
1415  double x = lastPoint.x;
1416  double y = lastPoint.y;
1417  if (x < p_cubeStartSamp) {
1418  x = p_cubeStartSamp;
1419  }
1420  else if (x > p_cubeSamps) {
1421  x = p_cubeSamps;
1422  }
1423  if (y < p_cubeStartLine) {
1424  y = p_cubeStartLine;
1425  }
1426  else if (y > p_cubeLines) {
1427  y = p_cubeLines;
1428  }
1429  geos::geom::Coordinate invalid(x, y);
1430  geos::geom::Coordinate valid(result.x, result.y);
1431 
1432  // Find the best valid Coordinate
1433  while (!SetImage(invalid.x, invalid.y)) {
1434  int x, y;
1435  if (invalid.x > valid.x) {
1436  x = (int)invalid.x - 1;
1437  }
1438  else if (invalid.x < valid.x) {
1439  x = (int)invalid.x + 1;
1440  }
1441  else {
1442  x = (int)invalid.x;
1443  }
1444  if (invalid.y > valid.y) {
1445  y = (int)invalid.y - 1;
1446  }
1447  else if (invalid.y < valid.y) {
1448  y = (int)invalid.y + 1;
1449  }
1450  else {
1451  y = (int)invalid.y;
1452  }
1453  invalid = geos::geom::Coordinate(x, y);
1454  }
1455 
1456  result = FixCornerSkip(currentPoint, invalid);
1457  }
1458 
1459  return result;
1460  }
1461 
1462 
1472  geos::geom::Coordinate ImagePolygon::FixCornerSkip(geos::geom::Coordinate *currentPoint,
1473  geos::geom::Coordinate newPoint) {
1474  geos::geom::Coordinate originalPoint = newPoint;
1475  geos::geom::Coordinate modPoint = newPoint;
1476 
1477  // Step Too big
1479  return newPoint;
1480  }
1481 
1482  // An upper left corner
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;
1486  newPoint.x -= 1;
1487  }
1488  }
1489 
1490  // An upper right corner
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;
1494  newPoint.y -= 1;
1495  }
1496  }
1497 
1498  // An lower right corner
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;
1502  newPoint.x += 1;
1503  }
1504  }
1505 
1506  // An lower left corner
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;
1510  newPoint.y += 1;
1511  }
1512  }
1513 
1514  if (currentPoint->x == modPoint.x && currentPoint->y == modPoint.y) {
1515  return originalPoint;
1516  }
1517  return modPoint;
1518  }
1519 
1520 
1528  void ImagePolygon::FindSubpixel(std::vector<geos::geom::Coordinate> & points) {
1529  if (p_subpixelAccuracy > 0) {
1530 
1531  // Fix the polygon with subpixel accuracy
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) {
1536  pt = 0;
1537  didStartingPoint = true;
1538  }
1539 
1540  // Binary Coordinate Search
1541  double maxStep = std::max(p_sampinc, p_lineinc);
1542  double stepY = (old.x - points.at(pt + 1).x) / maxStep;
1543  double stepX = (points.at(pt + 1).y - old.y) / maxStep;
1544 
1545  geos::geom::Coordinate valid = points.at(pt);
1546  geos::geom::Coordinate invalid(valid.x + stepX, valid.y + stepY);
1547 
1548  for (int itt = 0; itt < p_subpixelAccuracy; itt ++) {
1549  geos::geom::Coordinate half((valid.x + invalid.x) / 2.0, (valid.y + invalid.y) / 2.0);
1550  if (SetImage(half.x, half.y) && InsideImage(half.x, half.y)) {
1551  valid = half;
1552  }
1553  else {
1554  invalid = half;
1555  }
1556  }
1557 
1558  old = points.at(pt);
1559 
1560  // Set new coordinate
1561  points[pt] = valid;
1562 
1563  }
1564 
1565  // Fix starting point
1566  points[points.size()-1] = geos::geom::Coordinate(points[0].x, points[0].y);
1567 
1568  }
1569  }
1570 
1571 
1572 } // end namespace isis
Isis::Brick::SetBasePosition
void SetBasePosition(const int start_sample, const int start_line, const int start_band)
This method is used to set the base position of the shape buffer.
Definition: Brick.h:120
Isis::ImagePolygon::~ImagePolygon
~ImagePolygon()
Destroys the Polygon object.
Definition: ImagePolygon.cpp:86
Isis::ImagePolygon::FixCornerSkip
geos::geom::Coordinate FixCornerSkip(geos::geom::Coordinate *currentPoint, geos::geom::Coordinate newPoint)
Looks at the next possible point relative to the lasts and attempts to adjust the point outward to gr...
Definition: ImagePolygon.cpp:1472
Isis::ImagePolygon::m_topCoord
geos::geom::Coordinate * m_topCoord
The cube's top-most valid coord.
Definition: ImagePolygon.h:282
Isis::ImagePolygon::p_sampinc
int p_sampinc
The increment for walking along the polygon in the sample direction.
Definition: ImagePolygon.h:290
Isis::ImagePolygon::InsideImage
bool InsideImage(double sample, double line)
This returns true if sample/line are inside the cube.
Definition: ImagePolygon.cpp:514
Isis::ImagePolygon::p_subpixelAccuracy
int p_subpixelAccuracy
The subpixel accuracy to use.
Definition: ImagePolygon.h:297
Isis::Cube::fileName
virtual QString fileName() const
Returns the opened cube's filename.
Definition: Cube.cpp:1563
Isis::UniversalGroundMap
Universal Ground Map.
Definition: UniversalGroundMap.h:69
Isis::ImagePolygon::validSampleDim
double validSampleDim()
Retuns the maximum valid sample width of the cube set with either initCube() or Create()
Definition: ImagePolygon.cpp:555
Isis::IException::print
void print() const
Prints a string representation of this exception to stderr.
Definition: IException.cpp:445
Isis::UniversalGroundMap::UniversalLatitude
double UniversalLatitude() const
Returns the universal latitude of the camera model or projection.
Definition: UniversalGroundMap.cpp:247
Isis::ImagePolygon::FindFirstPoint
geos::geom::Coordinate FindFirstPoint()
Finds the first point that projects in an image.
Definition: ImagePolygon.cpp:528
Isis::ImagePolygon::p_cubeLines
int p_cubeLines
The number of lines in the cube.
Definition: ImagePolygon.h:288
Isis::ImagePolygon::validLineDim
double validLineDim()
Retuns the maximum valid line width of the cube set with either initCube() or Create()
Definition: ImagePolygon.cpp:570
Isis::ImagePolygon::m_rightCoord
geos::geom::Coordinate * m_rightCoord
The cube's right-most valid coord.
Definition: ImagePolygon.h:281
Isis::Blob::setData
void setData(const char *buffer, int nbytes)
Set the data stored in the BLOB.
Definition: Blob.cpp:382
Isis::Cube::read
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
Definition: Cube.cpp:807
Isis::ImagePolygon::p_ellipsoid
bool p_ellipsoid
Uses an ellipsoid if a limb is detected.
Definition: ImagePolygon.h:295
Isis::Camera::Sample
virtual double Sample() const
Returns the current sample number.
Definition: Camera.cpp:2690
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
Isis::ImagePolygon::toBlob
Blob toBlob() const
Serialize the ImagePolygon to a Blob.
Definition: ImagePolygon.cpp:1347
Isis::ImagePolygon::initCube
Camera * initCube(Cube &cube, int ss=1, int sl=1, int ns=0, int nl=0, int band=1)
Create a Polygon from given cube.
Definition: ImagePolygon.cpp:121
Isis::ImagePolygon::polyStr
std::string polyStr() const
Return a geos Multipolygon.
Definition: ImagePolygon.h:215
Isis::IsNullPixel
bool IsNullPixel(const double d)
Returns if the input pixel is null.
Definition: SpecialPixel.h:235
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::ImagePolygon::Create
void Create(Cube &cube, int sinc=1, int linc=1, int ss=1, int sl=1, int ns=0, int nl=0, int band=1, bool increasePrecision=false)
Create a Polygon from given cube.
Definition: ImagePolygon.cpp:217
Isis::ImagePolygon::p_cube
Cube * p_cube
The cube provided.
Definition: ImagePolygon.h:267
Isis::ImagePolygon
Create cube polygons, read/write polygons to blobs.
Definition: ImagePolygon.h:153
Isis::UniversalGroundMap::Camera
Isis::Camera * Camera() const
Return the camera associated with the ground map (NULL implies none)
Definition: UniversalGroundMap.h:136
Isis::Camera
Definition: Camera.h:236
Isis::ImagePolygon::p_isProjected
bool p_isProjected
True when the provided cube is projected.
Definition: ImagePolygon.h:268
Isis::Brick
Buffer for containing a three dimensional section of an image.
Definition: Brick.h:45
Isis::ImagePolygon::m_leftCoord
geos::geom::Coordinate * m_leftCoord
The cube's left-most valid coord.
Definition: ImagePolygon.h:280
Isis::PolygonTools::Intersect
static geos::geom::Geometry * Intersect(const geos::geom::Geometry *geom1, const geos::geom::Geometry *geom2)
This applies the geos Intersect operator.
Definition: PolygonTools.cpp:964
Isis::ImagePolygon::p_emission
double p_emission
The maximum emission angle to consider valid.
Definition: ImagePolygon.h:293
Isis::ImagePolygon::m_botCoord
geos::geom::Coordinate * m_botCoord
The cube's bot-most valid coord.
Definition: ImagePolygon.h:283
Isis::IException::what
const char * what() const
Returns a string representation of this exception in its current state.
Definition: IException.cpp:375
Isis::Sensor::IgnoreElevationModel
void IgnoreElevationModel(bool ignore)
This allows you to ignore the cube elevation model and use the ellipse.
Definition: Sensor.cpp:60
Isis::IException::append
void append(const IException &exceptionSource)
Appends the given exception (and its list of previous exceptions) to this exception's causational exc...
Definition: IException.cpp:409
Isis::ImagePolygon::WalkPoly
void WalkPoly()
Walks the image finding its lon lat polygon and stores it to p_pts.
Definition: ImagePolygon.cpp:638
Isis::ImagePolygon::p_polyStr
std::string p_polyStr
The string representation of the polygon.
Definition: ImagePolygon.h:276
Isis::ImagePolygon::p_gMap
UniversalGroundMap * p_gMap
The cube's ground map.
Definition: ImagePolygon.h:278
Isis::Projection::WorldY
virtual double WorldY() const
This returns the world Y coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:544
Isis::ImagePolygon::p_brick
Brick * p_brick
Used to check for valid DNs.
Definition: ImagePolygon.h:270
Isis::Cube::lineCount
int lineCount() const
Definition: Cube.cpp:1734
Isis::ImagePolygon::FindNextPoint
geos::geom::Coordinate FindNextPoint(geos::geom::Coordinate *currentPoint, geos::geom::Coordinate lastPoint, int recursionDepth=0)
Finds the next point on the image using a left hand rule walking algorithm.
Definition: ImagePolygon.cpp:316
Isis::ImagePolygon::DistanceSquared
double DistanceSquared(const geos::geom::Coordinate *p1, const geos::geom::Coordinate *p2)
Calculates the distance squared between two coordinates.
Definition: ImagePolygon.cpp:1373
Isis::ImagePolygon::p_lineinc
int p_lineinc
The increment for walking along the polygon in the line direcction.
Definition: ImagePolygon.h:291
Isis::Blob::getBuffer
char * getBuffer()
Get the internal data buff of the Blob.
Definition: Blob.cpp:546
Isis::ImagePolygon::p_cubeStartLine
int p_cubeStartLine
The the line of the first valid point in the cube.
Definition: ImagePolygon.h:286
Isis::ImagePolygon::p_polygons
geos::geom::MultiPolygon * p_polygons
The multipolygon of the image.
Definition: ImagePolygon.h:274
Isis::ImagePolygon::p_cubeStartSamp
int p_cubeStartSamp
The the sample of the first valid point in the cube.
Definition: ImagePolygon.h:285
Isis::ImagePolygon::SetImage
bool SetImage(const double sample, const double line)
Sets the sample/line values of the cube to get lat/lon values.
Definition: ImagePolygon.cpp:1079
Isis::Cube::sampleCount
int sampleCount() const
Definition: Cube.cpp:1807
Isis::Projection::WorldX
virtual double WorldX() const
This returns the world X coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:524
Isis::ImagePolygon::p_cubeSamps
int p_cubeSamps
The number of samples in the cube.
Definition: ImagePolygon.h:287
Isis::Cube
IO Handler for Isis Cubes.
Definition: Cube.h:167
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Sensor::IncidenceAngle
virtual double IncidenceAngle() const
Returns the incidence angle in degrees.
Definition: Sensor.cpp:335
Isis::ImagePolygon::p_incidence
double p_incidence
The maximum incidence angle to consider valid.
Definition: ImagePolygon.h:294
Isis::Null
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:95
Isis::Blob::Size
int Size() const
Accessor method that returns the number of bytes in the blob data.
Definition: Blob.cpp:142
Isis::ImagePolygon::FixPolePoly
void FixPolePoly(std::vector< geos::geom::Coordinate > *crossingPoints)
If the cube crosses the 0/360 boundary and contains a pole, Some points are added to allow the polygo...
Definition: ImagePolygon.cpp:835
Isis::Camera::BasicMapping
void BasicMapping(Pvl &map)
Writes the basic mapping group to the specified Pvl.
Definition: Camera.cpp:1356
Isis::UniversalGroundMap::Projection
Isis::Projection * Projection() const
Return the projection associated with the ground map (NULL implies none)
Definition: UniversalGroundMap.h:131
Isis::ImagePolygon::IsLimb
bool IsLimb()
Returns True when the input image is a limb image.
Definition: ImagePolygon.cpp:1383
Isis::Cube::camera
Camera * camera()
Return a camera associated with the cube.
Definition: Cube.cpp:1451
Isis::ImagePolygon::calcImageBorderCoordinates
void calcImageBorderCoordinates()
Calculates the four border points, particularly for validSampleDim() and validLineDim()
Definition: ImagePolygon.cpp:589
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::PolygonTools::MakeMultiPolygon
static geos::geom::MultiPolygon * MakeMultiPolygon(const geos::geom::Geometry *geom)
Make a geos::geom::MultiPolygon out of the components of the argument.
Definition: PolygonTools.cpp:1369
std
Namespace for the standard library.
Isis::Cube::pixelType
PixelType pixelType() const
Definition: Cube.cpp:1758
Isis::ImagePolygon::MoveBackInsideImage
void MoveBackInsideImage(double &sample, double &line, double sinc, double linc)
This method ensures sample/line after sinc/linc have been applied is inside the image.
Definition: ImagePolygon.cpp:446
Isis::ImagePolygon::FindSubpixel
void FindSubpixel(std::vector< geos::geom::Coordinate > &points)
Takes p_polygons in sample/line space and finds its subpixel accuracy.
Definition: ImagePolygon.cpp:1528
Isis::ImagePolygon::Fix360Poly
void Fix360Poly()
If the cube crosses the 0/360 boundary and does not include a pole, the polygon is separated into mul...
Definition: ImagePolygon.cpp:1141
Isis::UniversalGroundMap::SetUniversalGround
bool SetUniversalGround(double lat, double lon)
Returns whether the lat/lon position was set successfully in the camera model or projection.
Definition: UniversalGroundMap.cpp:102
Isis::UniversalGroundMap::SetImage
bool SetImage(double sample, double line)
Returns whether the sample/line postion was set successfully in the camera model or projection.
Definition: UniversalGroundMap.cpp:233
Isis::ImagePolygon::FindBestPoint
geos::geom::Coordinate FindBestPoint(geos::geom::Coordinate *currentPoint, geos::geom::Coordinate newPoint, geos::geom::Coordinate lastPoint)
While walking the image in sample/line space, this function finds the best valid point between the fi...
Definition: ImagePolygon.cpp:1407
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::Sensor::EmissionAngle
virtual double EmissionAngle() const
Returns the emission angle in degrees.
Definition: Sensor.cpp:324
Isis::Camera::Line
virtual double Line() const
Returns the current line number.
Definition: Camera.cpp:2710
Isis::ImagePolygon::p_pts
geos::geom::CoordinateSequence * p_pts
The sequence of coordinates that compose the boundry of the image.
Definition: ImagePolygon.h:272
Isis::Blob
Definition: Blob.h:51
Isis::Camera::HasProjection
bool HasProjection()
Checks to see if the camera object has a projection.
Definition: Camera.cpp:2638
Isis::Cube::projection
Projection * projection()
Definition: Cube.cpp:1794
Isis::UniversalGroundMap::UniversalLongitude
double UniversalLongitude() const
Returns the universal longitude of the camera model or projection.
Definition: UniversalGroundMap.cpp:270
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::UniversalGroundMap::SetBand
void SetBand(const int band)
Set the image band number.
Definition: UniversalGroundMap.cpp:72

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:16:39