Isis 3 Programmer Reference
Projection.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Projection.h"
8 
9 #include <QObject>
10 
11 #include <cfloat>
12 #include <cmath>
13 #include <iomanip>
14 #include <sstream>
15 #include <vector>
16 
17 #include <SpiceUsr.h>
18 
19 #include "Constants.h"
20 #include "Displacement.h"
21 #include "FileName.h"
22 #include "IException.h"
23 #include "IString.h"
24 #include "Longitude.h"
25 #include "NaifStatus.h"
26 #include "Pvl.h"
27 #include "PvlGroup.h"
28 #include "PvlKeyword.h"
29 #include "RingPlaneProjection.h"
30 #include "SpecialPixel.h"
31 #include "TProjection.h"
32 #include "WorldMapper.h"
33 
34 using namespace std;
35 namespace Isis {
91  Projection::Projection(Pvl &label) : m_mappingGrp("Mapping") {
92  try {
93  // Try to read the mapping group
94  m_mappingGrp = label.findGroup("Mapping", Pvl::Traverse);
95 
96  // TODO** Try to generalize these to keep in parent Projection class and use for both azimuth and longitude
97  // Get the RingLongitudeDomain or LongitudeDomain
98  // if ((string) m_mappingGrp["LongitudeDomain"] == "360") {
99  // m_longitudeDomain = 360;
100  // }
101  // else if ((string) m_mappingGrp["LongitudeDomain"] == "180") {
102  // m_longitudeDomain = 180;
103  // }
104  // else {
105  // IString msg = "Projection failed. Invalid value for keyword "
106  // "[LongitudeDomain] must be [180 or 360]";
107  // throw IException(IException::Unknown, msg, _FILEINFO_);
108  // }
109 
110  // Get the map rotation
111  m_rotation = 0.0;
112  if (m_mappingGrp.hasKeyword("Rotation")) {
113  m_rotation = m_mappingGrp["Rotation"];
114  }
115 
116  // Initialize miscellaneous protected data elements
117  m_good = false;
118 
119  m_pixelResolution = 1.0;
120  if (m_mappingGrp.hasKeyword("PixelResolution")) {
121  m_pixelResolution = m_mappingGrp["PixelResolution"];
122  }
123 
124  m_minimumX = DBL_MAX;
125  m_maximumX = -DBL_MAX;
126  m_minimumY = DBL_MAX;
127  m_maximumY = -DBL_MAX;
128 
129  m_mapper = NULL;
130 
131  m_sky = false;
132  if (m_mappingGrp.hasKeyword("TargetName")) {
133  QString str = m_mappingGrp["TargetName"];
134  if (str.toUpper() == "SKY") m_sky = true;
135  }
136 
137  // initialize the rest of the x,y,lat,lon member variables
138  m_x = Null;
139  m_y = Null;
140  }
141  catch(IException &e) {
142  QString msg = "Projection failed. Invalid label group [Mapping]";
143  throw IException(e, IException::Unknown, msg, _FILEINFO_);
144  }
145  }
146 
149  delete m_mapper;
150  m_mapper = NULL;
151  }
152 
163  if (Resolution() != proj.Resolution()) return false;
164  if (Name() != proj.Name()) return false;
165  return true;
166  }
167 
168 
179  return !(*this == proj);
180  }
181 
182 
189  m_projectionType = ptype;
190  }
191 
192 
199  return m_projectionType;
200  }
201 
202 
208  bool Projection::IsSky() const {
209  return m_sky;
210  }
211 
212 
223  return false;
224  }
225 
233  // bool Projection::IsPositiveEast() const {
234  // return m_longitudeDirection == PositiveEast;
235  // }
236 
244  // bool Projection::IsPositiveWest() const {
245  // return m_longitudeDirection == PositiveWest;
246  // }
247 
248 
256  // string Projection::LongitudeDirectionString() const {
257  // if (m_longitudeDirection == PositiveEast) return "PositiveEast";
258  // return "PositiveWest";
259  // }
260 
268  // bool Projection::Has180Domain() const {
269  // return m_longitudeDomain == 180;
270 // }
271 
279  // bool Projection::Has360Domain() const {
280  // return m_longitudeDomain == 360;
281  // }
282 
293  // double Projection::To180Domain(const double lon) {
294  // if (lon == Null) {
295  // throw IException(IException::Unknown,
296  // "Unable to convert to 180 degree domain. The given longitude value ["
297  // + IString(lon) + "] is invalid.",
298  // _FILEINFO_);
299  // }
300  // return Isis::Longitude(lon, Angle::Degrees).force180Domain().degrees();
301  // }
302 
311  // double Projection::To360Domain(const double lon) {
312  // if (lon == Null) {
313  // throw IException(IException::Unknown,
314  // "Unable to convert to 360 degree domain. The given longitude value ["
315  // + IString(lon) + "] is invalid.",
316  // _FILEINFO_);
317  // }
318  // double result = lon;
319 
320  // if ( (lon < 0.0 || lon > 360.0) &&
321  // !qFuzzyCompare(lon, 0.0) && !qFuzzyCompare(lon, 360.0)) {
322  // result = Isis::Longitude(lon, Angle::Degrees).force360Domain().degrees();
323  // }
324 
325  // return result;
326  // }
327 
334  // string Projection::LongitudeDomainString() const {
335  // if (m_longitudeDomain == 360) return "360";
336  // return "180";
337  // }
338 
350  return m_groundRangeGood;
351  }
352 
353 
359  double Projection::Rotation() const {
360  return m_rotation;
361  }
362 
363 
374  bool Projection::IsGood() const {
375  return m_good;
376  }
377 
378 
387  double Projection::XCoord() const {
388  return m_x;
389  }
390 
391 
400  double Projection::YCoord() const {
401  return m_y;
402  }
403 
404 
417  bool Projection::SetUniversalGround(const double coord1, const double coord2) {
418  if (coord1 == Null || coord2 == Null) {
419  m_good = false;
420  return m_good;
421  }
422  if (projectionType() == Triaxial) {
423  TProjection *tproj = (TProjection *) this;
424  return tproj->SetUniversalGround(coord1, coord2);
425  }
426  else {
427  RingPlaneProjection *rproj = (RingPlaneProjection *) this;
428  return rproj->SetUniversalGround(coord1, coord2);
429  }
430  }
431 
432 
446  bool Projection::SetUnboundUniversalGround(const double coord1, const double coord2) {
447  if (coord1 == Null || coord2 == Null) {
448  m_good = false;
449  return m_good;
450  }
451  if (projectionType() == Triaxial) {
452  TProjection *tproj = (TProjection *) this;
453  return tproj->SetUnboundUniversalGround(coord1, coord2);
454  }
455  else {
456  RingPlaneProjection *rproj = (RingPlaneProjection *) this;
457  return rproj->SetUniversalGround(coord1, coord2);
458  }
459  }
460 
461 
475  m_mapper = mapper;
476  }
477 
497  bool Projection::SetWorld(const double worldX, const double worldY) {
498  double projectionX;
499  double projectionY;
500 
501  if (m_mapper != NULL) {
502  projectionX = m_mapper->ProjectionX(worldX);
503  projectionY = m_mapper->ProjectionY(worldY);
504  }
505  else {
506  projectionX = worldX;
507  projectionY = worldY;
508  }
509 
510  return SetCoordinate(projectionX, projectionY);
511  }
512 
524  double Projection::WorldX() const {
525  if (m_mapper != NULL) {
526  return m_mapper->WorldX(m_x);
527  }
528  else {
529  return m_x;
530  }
531  }
532 
544  double Projection::WorldY() const {
545  if (m_mapper != NULL) {
546  return m_mapper->WorldY(m_y);
547  }
548  else {
549  return m_y;
550  }
551  }
552 
566  double Projection::ToWorldX(const double projectionX) const {
567  if (projectionX == Null) {
569  "Unable to convert to world x. The given x-value ["
570  + IString(projectionX) + "] is invalid.",
571  _FILEINFO_);
572  }
573  if (m_mapper != NULL) {
574  return m_mapper->WorldX(projectionX);
575  }
576  else {
577  return projectionX;
578  }
579  }
580 
594  double Projection::ToWorldY(const double projectionY) const {
595  if (projectionY == Null) {
597  "Unable to convert to world y. The given y-value ["
598  + IString(projectionY) + "] is invalid.",
599  _FILEINFO_);
600  }
601  if (m_mapper != NULL) {
602  return m_mapper->WorldY(projectionY);
603  }
604  else {
605  return projectionY;
606  }
607  }
608 
622  double Projection::ToProjectionX(const double worldX) const {
623  if (worldX == Null) {
625  "Unable to convert to projection x. The given x-value ["
626  + IString(worldX) + "] is invalid.",
627  _FILEINFO_);
628  }
629  if (m_mapper != NULL) {
630  return m_mapper->ProjectionX(worldX);
631  }
632  else {
633  return worldX;
634  }
635  }
636 
650  double Projection::ToProjectionY(const double worldY) const {
651  if (worldY == Null) {
653  "Unable to convert to projection y. The given y-value ["
654  + IString(worldY) + "] is invalid.",
655  _FILEINFO_);
656  }
657  if (m_mapper != NULL) {
658  return m_mapper->ProjectionY(worldY);
659  }
660  else {
661  return worldY;
662  }
663  }
664 
675  double Projection::Resolution() const {
676  if (m_mapper != NULL) {
677  return m_mapper->Resolution();
678  }
679  else {
680  return 1.0;
681  }
682  }
683 
684 
693  double Projection::ToHours(double angle) {
694  return angle / 15.0;
695  }
696 
706  QString Projection::ToDMS(double angle) {
707  int iangle = (int)angle;
708  double mins = abs(angle - iangle) * 60.0;
709  int imins = (int)mins;
710  double secs = (mins - imins) * 60.0;
711  int isecs = (int)secs;
712  double frac = (secs - isecs) * 1000.0;
713  if (frac >= 1000.0) {
714  frac -= 1000.0;
715  isecs++;
716  }
717  if (isecs >= 60) {
718  isecs -= 60;
719  imins++;
720  }
721  if (imins >= 60) {
722  imins -= 60;
723  iangle++;
724  }
725  stringstream s;
726  s << iangle << " " << setw(2) << setfill('0')
727  << imins << "m " << setw(2) << setfill('0') << isecs << "." <<
728  setprecision(3) << frac << "s";
729  return s.str().c_str();
730  }
731 
741  QString Projection::ToHMS(double angle) {
742  double tangle = angle;
743  while (tangle < 0.0) tangle += 360.0;
744  while (tangle > 360.0) tangle -= 360.0;
745  double hrs = ToHours(tangle);
746  int ihrs = (int)(hrs);
747  double mins = (hrs - ihrs) * 60.0;
748  int imins = (int)(mins);
749  double secs = (mins - imins) * 60.0;
750  int isecs = (int)(secs);
751  double msecs = (secs - isecs) * 1000.0;
752  int imsecs = (int)(msecs + 0.5);
753  if (imsecs >= 1000) {
754  imsecs -= 1000;
755  isecs++;
756  }
757  if (isecs >= 60) {
758  isecs -= 60;
759  imins++;
760  }
761  if (imins >= 60) {
762  imins -= 60;
763  ihrs++;
764  }
765  stringstream s;
766  s << setw(2) << setfill('0') << ihrs << "h " << setw(2) << setfill('0') <<
767  imins << "m " << setw(2) << setfill('0') << isecs << "." << imsecs << "s";
768  return s.str().c_str();
769  }
770 
780  void Projection::SetComputedXY(double x, double y) {
781  if (x == Null || y == Null) {
782  m_good = false;
783  return;
784  }
785  if (m_rotation == 0.0) {
786  m_x = x;
787  m_y = y;
788  }
789  else {
790  double rot = m_rotation * PI / 180.0;
791  m_x = x * cos(rot) + y * sin(rot);
792  m_y = y * cos(rot) - x * sin(rot);
793  }
794  }
795 
804  void Projection::SetXY(double x, double y) {
805  if (x == Null || y == Null) {
806  m_good = false;
807  }
808  m_x = x;
809  m_y = y;
810  return;
811  }
812 
818  double Projection::GetX() const {
819  if (m_rotation == 0.0) return m_x;
820  double rot = m_rotation * PI / 180.0;
821  return m_x * cos(rot) - m_y * sin(rot);
822  }
823 
829  double Projection::GetY() const {
830  if (m_rotation == 0.0) return m_y;
831  double rot = m_rotation * PI / 180.0;
832  return m_y * cos(rot) + m_x * sin(rot);
833  }
834 
841  return m_pixelResolution;
842  }
843 
844 
845  // /**
846  // * This method is used to find the XY range for oblique aspect projections
847  // * (non-polar projections) by "walking" around each of the min/max lat/lon.
848  // *
849  // * @param minX Minimum x projection coordinate which covers the latitude
850  // * longitude range specified in the labels.
851  // * @param maxX Maximum x projection coordinate which covers the latitude
852  // * longitude range specified in the labels.
853  // * @param minY Minimum y projection coordinate which covers the latitude
854  // * longitude range specified in the labels.
855  // * @param maxY Maximum y projection coordinate which covers the latitude
856  // * longitude range specified in the labels.
857  // *
858  // * @return @b bool Indicates whether the method was successful.
859  // * @see XYRange()
860  // * @author Stephen Lambright
861  // * @internal
862  // * @history 2011-07-02 Jeannie Backer - Moved this code from
863  // * ObliqueCylindrical class to its own method here.
864  // */
865  // bool Projection::xyRangeOblique(double &minX, double &maxX,
866  // double &minY, double &maxY) {
867  // if (minX == Null || maxX == Null || minY == Null || maxY == Null) {
868  // return false;
869  // }
870  // //For oblique, we'll have to walk all 4 sides to find out min/max x/y values
871  // if (!HasGroundRange()) return false; // Don't have min/max lat/lon,
872  // //can't continue
873 
874  // m_specialLatCases.clear();
875  // m_specialLonCases.clear();
876 
877  // // First, search longitude for min X/Y
878  // double minFoundX1, minFoundX2;
879  // double minFoundY1, minFoundY2;
880 
881  // // Search for minX between minlat and maxlat along minlon
882  // doSearch(MinimumLatitude(), MaximumLatitude(),
883  // minFoundX1, MinimumLongitude(), true, true, true);
884  // // Search for minX between minlat and maxlat along maxlon
885  // doSearch(MinimumLatitude(), MaximumLatitude(),
886  // minFoundX2, MaximumLongitude(), true, true, true);
887  // // Search for minY between minlat and maxlat along minlon
888  // doSearch(MinimumLatitude(), MaximumLatitude(),
889  // minFoundY1, MinimumLongitude(), false, true, true);
890  // // Search for minY between minlat and maxlat along maxlon
891  // doSearch(MinimumLatitude(), MaximumLatitude(),
892  // minFoundY2, MaximumLongitude(), false, true, true);
893 
894  // // Second, search latitude for min X/Y
895  // double minFoundX3, minFoundX4;
896  // double minFoundY3, minFoundY4;
897 
898  // // Search for minX between minlon and maxlon along minlat
899  // doSearch(MinimumLongitude(), MaximumLongitude(),
900  // minFoundX3, MinimumLatitude(), true, false, true);
901  // // Search for minX between minlon and maxlon along maxlat
902  // doSearch(MinimumLongitude(), MaximumLongitude(),
903  // minFoundX4, MaximumLatitude(), true, false, true);
904  // // Search for minY between minlon and maxlon along minlat
905  // doSearch(MinimumLongitude(), MaximumLongitude(),
906  // minFoundY3, MinimumLatitude(), false, false, true);
907  // // Search for minY between minlon and maxlon along maxlat
908  // doSearch(MinimumLongitude(), MaximumLongitude(),
909  // minFoundY4, MaximumLatitude(), false, false, true);
910 
911  // // We've searched all possible minimums, go ahead and store the lowest
912  // double minFoundX5 = min(minFoundX1, minFoundX2);
913  // double minFoundX6 = min(minFoundX3, minFoundX4);
914  // m_minimumX = min(minFoundX5, minFoundX6);
915 
916  // double minFoundY5 = min(minFoundY1, minFoundY2);
917  // double minFoundY6 = min(minFoundY3, minFoundY4);
918  // m_minimumY = min(minFoundY5, minFoundY6);
919 
920  // // Search longitude for max X/Y
921  // double maxFoundX1, maxFoundX2;
922  // double maxFoundY1, maxFoundY2;
923 
924  // // Search for maxX between minlat and maxlat along minlon
925  // doSearch(MinimumLatitude(), MaximumLatitude(),
926  // maxFoundX1, MinimumLongitude(), true, true, false);
927  // // Search for maxX between minlat and maxlat along maxlon
928  // doSearch(MinimumLatitude(), MaximumLatitude(),
929  // maxFoundX2, MaximumLongitude(), true, true, false);
930  // // Search for maxY between minlat and maxlat along minlon
931  // doSearch(MinimumLatitude(), MaximumLatitude(),
932  // maxFoundY1, MinimumLongitude(), false, true, false);
933  // // Search for maxY between minlat and maxlat along maxlon
934  // doSearch(MinimumLatitude(), MaximumLatitude(),
935  // maxFoundY2, MaximumLongitude(), false, true, false);
936 
937  // // Search latitude for max X/Y
938  // double maxFoundX3, maxFoundX4;
939  // double maxFoundY3, maxFoundY4;
940 
941  // // Search for maxX between minlon and maxlon along minlat
942  // doSearch(MinimumLongitude(), MaximumLongitude(),
943  // maxFoundX3, MinimumLatitude(), true, false, false);
944  // // Search for maxX between minlon and maxlon along maxlat
945  // doSearch(MinimumLongitude(), MaximumLongitude(),
946  // maxFoundX4, MaximumLatitude(), true, false, false);
947  // // Search for maxY between minlon and maxlon along minlat
948  // doSearch(MinimumLongitude(), MaximumLongitude(),
949  // maxFoundY3, MinimumLatitude(), false, false, false);
950  // // Search for maxY between minlon and maxlon along maxlat
951  // doSearch(MinimumLongitude(), MaximumLongitude(),
952  // maxFoundY4, MaximumLatitude(), false, false, false);
953 
954  // // We've searched all possible maximums, go ahead and store the highest
955  // double maxFoundX5 = max(maxFoundX1, maxFoundX2);
956  // double maxFoundX6 = max(maxFoundX3, maxFoundX4);
957  // m_maximumX = max(maxFoundX5, maxFoundX6);
958 
959  // double maxFoundY5 = max(maxFoundY1, maxFoundY2);
960  // double maxFoundY6 = max(maxFoundY3, maxFoundY4);
961  // m_maximumY = max(maxFoundY5, maxFoundY6);
962 
963  // // Look along discontinuities for more extremes
964  // vector<double> specialLatCases = m_specialLatCases;
965  // for (unsigned int specialLatCase = 0;
966  // specialLatCase < specialLatCases.size();
967  // specialLatCase ++) {
968  // double minX, maxX, minY, maxY;
969 
970  // // Search for minX between minlon and maxlon along latitude discontinuities
971  // doSearch(MinimumLongitude(), MaximumLongitude(),
972  // minX, specialLatCases[specialLatCase], true, false, true);
973  // // Search for minY between minlon and maxlon along latitude discontinuities
974  // doSearch(MinimumLongitude(), MaximumLongitude(),
975  // minY, specialLatCases[specialLatCase], false, false, true);
976  // // Search for maxX between minlon and maxlon along latitude discontinuities
977  // doSearch(MinimumLongitude(), MaximumLongitude(),
978  // maxX, specialLatCases[specialLatCase], true, false, false);
979  // // Search for maxX between minlon and maxlon along latitude discontinuities
980  // doSearch(MinimumLongitude(), MaximumLongitude(),
981  // maxY, specialLatCases[specialLatCase], false, false, false);
982 
983  // m_minimumX = min(minX, m_minimumX);
984  // m_maximumX = max(maxX, m_maximumX);
985  // m_minimumY = min(minY, m_minimumY);
986  // m_maximumY = max(maxY, m_maximumY);
987  // }
988 
989  // vector<double> specialLonCases = m_specialLonCases;
990  // for (unsigned int specialLonCase = 0;
991  // specialLonCase < specialLonCases.size();
992  // specialLonCase ++) {
993  // double minX, maxX, minY, maxY;
994 
995  // // Search for minX between minlat and maxlat along longitude discontinuities
996  // doSearch(MinimumLatitude(), MaximumLatitude(),
997  // minX, specialLonCases[specialLonCase], true, true, true);
998  // // Search for minY between minlat and maxlat along longitude discontinuities
999  // doSearch(MinimumLatitude(), MaximumLatitude(),
1000  // minY, specialLonCases[specialLonCase], false, true, true);
1001  // // Search for maxX between minlat and maxlat along longitude discontinuities
1002  // doSearch(MinimumLatitude(), MaximumLatitude(),
1003  // maxX, specialLonCases[specialLonCase], true, true, false);
1004  // // Search for maxY between minlat and maxlat along longitude discontinuities
1005  // doSearch(MinimumLatitude(), MaximumLatitude(),
1006  // maxY, specialLonCases[specialLonCase], false, true, false);
1007 
1008  // m_minimumX = min(minX, m_minimumX);
1009  // m_maximumX = max(maxX, m_maximumX);
1010  // m_minimumY = min(minY, m_minimumY);
1011  // m_maximumY = max(maxY, m_maximumY);
1012  // }
1013 
1014  // m_specialLatCases.clear();
1015  // m_specialLonCases.clear();
1016 
1017  // // Make sure everything is ordered
1018  // if (m_minimumX >= m_maximumX) return false;
1019  // if (m_minimumY >= m_maximumY) return false;
1020 
1021  // // Return X/Y min/maxs
1022  // minX = m_minimumX;
1023  // maxX = m_maximumX;
1024  // minY = m_minimumY;
1025  // maxY = m_maximumY;
1026 
1027  // return true;
1028  // }
1029 
1067  // void Projection::doSearch(double minBorder, double maxBorder,
1068  // double &extremeVal, const double constBorder,
1069  // bool searchX, bool searchLongitude, bool findMin) {
1070  // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
1071  // return;
1072  // }
1073  // const double TOLERANCE = m_pixelResolution/2;
1074  // const int NUM_ATTEMPTS = (unsigned int)DBL_DIG; // It's unsafe to go past
1075  // // this precision
1076 
1077  // double minBorderX, minBorderY, maxBorderX, maxBorderY;
1078  // int attempts = 0;
1079 
1080  // do {
1081  // findExtreme(minBorder, maxBorder, minBorderX, minBorderY, maxBorderX,
1082  // maxBorderY, constBorder, searchX, searchLongitude, findMin);
1083  // if (minBorderX == Null && maxBorderX == Null
1084  // && minBorderY == Null && maxBorderY == Null ) {
1085  // attempts = NUM_ATTEMPTS;
1086  // continue;
1087  // }
1088  // attempts ++;
1089  // }
1090  // while ((fabs(minBorderX - maxBorderX) > TOLERANCE
1091  // || fabs(minBorderY - maxBorderY) > TOLERANCE)
1092  // && (attempts < NUM_ATTEMPTS));
1093  // // check both x and y distance in case symmetry of map
1094  // // For example, if minBorderX = maxBorderX but minBorderY = -maxBorderY,
1095  // // these points may not be close enough.
1096 
1097  // if (attempts >= NUM_ATTEMPTS) {
1098  // // We zoomed in on a discontinuity because our range never shrank, this
1099  // // will need to be rechecked later.
1100  // // *min and max border should be nearly identical, so it doesn't matter
1101  // // which is used here
1102  // if (searchLongitude) {
1103  // m_specialLatCases.push_back(minBorder);
1104  // }
1105  // else {
1106  // m_specialLonCases.push_back(minBorder);
1107  // }
1108  // }
1109 
1110  // // These values will always be accurate, even over a discontinuity
1111  // if (findMin) {
1112  // if (searchX) extremeVal = min(minBorderX, maxBorderX);
1113  // else extremeVal = min(minBorderY, maxBorderY);
1114  // }
1115  // else {
1116  // if (searchX) extremeVal = max(minBorderX, maxBorderX);
1117  // else extremeVal = max(minBorderY, maxBorderY);
1118  // }
1119  // return;
1120  // }
1121 
1181  // void Projection::findExtreme(double &minBorder, double &maxBorder,
1182  // double &minBorderX, double &minBorderY,
1183  // double &maxBorderX, double &maxBorderY,
1184  // const double constBorder, bool searchX,
1185  // bool searchLongitude, bool findMin) {
1186  // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
1187  // minBorderX = Null;
1188  // minBorderY = minBorderX;
1189  // minBorderX = minBorderX;
1190  // minBorderY = minBorderX;
1191  // return;
1192  // }
1193  // if (!searchLongitude && (fabs(fabs(constBorder) - 90.0) < DBL_EPSILON)) {
1194  // // it is impossible to search "along" a pole
1195  // setSearchGround(minBorder, constBorder, searchLongitude);
1196  // minBorderX = XCoord();
1197  // minBorderY = YCoord();
1198  // maxBorderX = minBorderX;
1199  // maxBorderY = minBorderY;
1200  // return;
1201  // }
1202  // // Always do 10 steps
1203  // const double STEP_SIZE = (maxBorder - minBorder) / 10.0;
1204  // const double LOOP_END = maxBorder + (STEP_SIZE / 2.0); // This ensures we do
1205  // // all of the steps
1206  // // properly
1207  // double currBorderVal = minBorder;
1208  // setSearchGround(minBorder, constBorder, searchLongitude);
1209 
1210  // // this makes sure that the initial currBorderVal is valid before entering
1211  // // the loop below
1212  // if (!m_good){
1213  // // minBorder = currBorderVal+STEP_SIZE < LOOP_END until setGround is good?
1214  // // then, if still not good return?
1215  // while (!m_good && currBorderVal <= LOOP_END) {
1216  // currBorderVal+=STEP_SIZE;
1217  // if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1218  // currBorderVal = 90.0;
1219  // }
1220  // setSearchGround(currBorderVal, constBorder, searchLongitude);
1221  // }
1222  // if (!m_good) {
1223  // minBorderX = Null;
1224  // minBorderY = minBorderX;
1225  // minBorderX = minBorderX;
1226  // minBorderY = minBorderX;
1227  // return;
1228  // }
1229  // }
1230 
1231  // // save the values of three consecutive steps from the minBorder towards
1232  // // the maxBorder along the constBorder. initialize these three border
1233  // // values (the non-constant lat or lon)
1234  // double border1 = currBorderVal;
1235  // double border2 = currBorderVal;
1236  // double border3 = currBorderVal;
1237 
1238  // // save the coordinate (x or y) values that correspond to the first
1239  // // two borders that are being saved.
1240  // // initialize these two coordinate values (x or y)
1241  // double value1 = (searchX) ? XCoord() : YCoord();
1242  // double value2 = value1;
1243 
1244  // // initialize the extreme coordinate value
1245  // // -- this is the largest coordinate value found so far
1246  // double extremeVal2 = value2;
1247 
1248  // // initialize the extreme border values
1249  // // -- these are the borders on either side of the extreme coordinate value
1250  // double extremeBorder1 = minBorder;
1251  // double extremeBorder3 = minBorder;
1252 
1253  // while (currBorderVal <= LOOP_END) {
1254 
1255  // // this conditional was added to prevent trying to SetGround with an
1256  // // invalid latitude greater than 90 degrees. There is no need check for
1257  // // latitude less than -90 since we start at the minBorder (already
1258  // // assumed to be valid) and step forward toward (and possibly past)
1259  // // maxBorder
1260  // if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1261  // currBorderVal = 90.0;
1262  // }
1263 
1264  // // update the current border value along constBorder
1265  // currBorderVal += STEP_SIZE;
1266  // setSearchGround(currBorderVal, constBorder, searchLongitude);
1267  // if (!m_good){
1268  // continue;
1269  // }
1270 
1271  // // update the border and coordinate values
1272  // border3 = border2;
1273  // border2 = border1;
1274  // border1 = currBorderVal;
1275  // value2 = value1;
1276  // value1 = (searchX) ? XCoord() : YCoord();
1277 
1278  // if ((findMin && value2 < extremeVal2)
1279  // || (!findMin && value2 > extremeVal2)) {
1280  // // Compare the coordinate value associated with the center border with
1281  // // the current extreme. If the updated coordinate value is more extreme
1282  // // (smaller or larger, depending on findMin), then we update the
1283  // // extremeVal and it's borders.
1284  // extremeVal2 = value2;
1285 
1286  // extremeBorder3 = border3;
1287  // extremeBorder1 = border1;
1288  // }
1289  // }
1290 
1291  // // update min/max border values to the values on either side of the most
1292  // // extreme coordinate found in this call to this method
1293 
1294  // minBorder = extremeBorder3; // Border 3 is lagging and thus smaller
1295 
1296  // // since the loop steps past the original maxBorder, we want to retain
1297  // // the original maxBorder value so we don't go outside of the original
1298  // // min/max range given
1299  // if (extremeBorder1 <= maxBorder ) {
1300  // maxBorder = extremeBorder1; // Border 1 is leading and thus larger
1301  // }
1302 
1303  // // update minBorder coordinate values
1304  // setSearchGround(minBorder, constBorder, searchLongitude);
1305  // // if (!m_good){
1306  // // this should not happen since minBorder has already been verified in
1307  // // the while loop above
1308  // // }
1309 
1310  // minBorderX = XCoord();
1311  // minBorderY = YCoord();
1312 
1313  // // update maxBorder coordinate values
1314  // setSearchGround(maxBorder, constBorder, searchLongitude);
1315  // // if (!m_good){
1316  // // this should not happen since maxBorder has already been verified in
1317  // // the while loop above
1318  // // }
1319 
1320  // maxBorderX = XCoord();
1321  // maxBorderY = YCoord();
1322  // return;
1323  // }
1324 
1347  // void Projection::setSearchGround(const double variableBorder,
1348  // const double constBorder,
1349  // bool variableIsLat) {
1350  // if (variableBorder == Null || constBorder == Null) {
1351  // return;
1352  // }
1353  // double lat, lon;
1354  // if (variableIsLat) {
1355  // lat = variableBorder;
1356  // lon = constBorder;
1357  // }
1358  // else {
1359  // lat = constBorder;
1360  // lon = variableBorder;
1361  // }
1362  // SetGround(lat, lon);
1363  // return;
1364  // }
1365 
1374  const Displacement &y) {
1375  PvlKeyword xKeyword("UpperLeftCornerX", toString(x.meters()), "meters");
1376  PvlKeyword yKeyword("UpperLeftCornerY", toString(y.meters()), "meters");
1377  m_mappingGrp.addKeyword(xKeyword,Pvl::Replace);
1378  m_mappingGrp.addKeyword(yKeyword,Pvl::Replace);
1379  }
1380 } //end namespace isis
Isis::WorldMapper::WorldX
virtual double WorldX(const double projectionX) const =0
This pure virtual method will return a world X coordinate given a projection Y coordinate in meters.
Isis::Projection::m_sky
bool m_sky
Indicates whether projection is sky or land.
Definition: Projection.h:310
Isis::PvlObject::findGroup
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:129
Isis::Projection::m_mapper
WorldMapper * m_mapper
This points to a mapper passed into the SetWorldMapper method.
Definition: Projection.h:292
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::Projection::Resolution
double Resolution() const
This method returns the resolution for mapping world coordinates into projection coordinates.
Definition: Projection.cpp:675
Isis::Projection::SetUpperLeftCorner
void SetUpperLeftCorner(const Displacement &x, const Displacement &y)
This method searches for extreme (min/max/discontinuity) coordinate values along the constBorder line...
Definition: Projection.cpp:1373
Isis::Projection::m_pixelResolution
double m_pixelResolution
Pixel resolution value from the PVL mapping group, in meters/pixel.
Definition: Projection.h:344
Isis::WorldMapper::ProjectionX
virtual double ProjectionX(const double worldX) const =0
This pure virtual method will return a projection X coordinate in meters given a world X coordinate.
Isis::Projection::Rotation
double Rotation() const
Returns the value of the Rotation keyword from the mapping group.
Definition: Projection.cpp:359
Isis::PvlContainer::addKeyword
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
Definition: PvlContainer.cpp:202
Isis::Projection::PixelResolution
double PixelResolution() const
Returns the pixel resolution value from the PVL mapping group in meters/pixel.
Definition: Projection.cpp:840
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
Isis::Projection::m_minimumY
double m_minimumY
See minimumX description.
Definition: Projection.h:327
Isis::Projection::GetX
double GetX() const
Calculates the unrotated form of current x value.
Definition: Projection.cpp:818
Isis::Projection::ToProjectionY
double ToProjectionY(const double worldY) const
This method converts a world y value to a projection y value.
Definition: Projection.cpp:650
Isis::Projection::Name
virtual QString Name() const =0
This method returns the name of the map projection.
Isis::Projection::projectionType
ProjectionType projectionType() const
Returns an enum value for the projection type.
Definition: Projection.cpp:198
Isis::PvlContainer::hasKeyword
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Definition: PvlContainer.cpp:159
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::Projection::SetXY
void SetXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:804
Isis::Projection::m_y
double m_y
This contains the rotated Y coordinate for a specific projection at the position indicated by m_latit...
Definition: Projection.h:339
Isis::Projection::SetWorldMapper
void SetWorldMapper(WorldMapper *mapper)
If desired the programmer can use this method to set a world mapper to be used in the SetWorld,...
Definition: Projection.cpp:474
Isis::WorldMapper::Resolution
virtual double Resolution() const
This virtual method will the resolution of the world system relative to one unit in the projection sy...
Definition: WorldMapper.h:100
Isis::Projection::SetUniversalGround
virtual bool SetUniversalGround(const double coord1, const double coord2)
This method is used to set the lat/lon or radius/azimuth (i.e.
Definition: Projection.cpp:417
Isis::WorldMapper::WorldY
virtual double WorldY(const double projectionY) const =0
This pure virtual method will return a world Y coordinate given a projection Y coordinate in meters.
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::Projection::m_mappingGrp
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:329
Isis::Projection::operator!=
bool operator!=(const Projection &proj)
This method determines whether two map projection objects are not equal.
Definition: Projection.cpp:178
Isis::Projection::GetY
double GetY() const
Calculates the unrotated form of the current y value.
Definition: Projection.cpp:829
Isis::Projection::setProjectionType
void setProjectionType(const ProjectionType ptype)
Sets the projection subclass type.
Definition: Projection.cpp:188
Isis::WorldMapper::ProjectionY
virtual double ProjectionY(const double worldY) const =0
This pure virtual method will return a projection Y coordinate in meters given a world Y coordinate.
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::Displacement
Displacement is a signed length, usually in meters.
Definition: Displacement.h:31
Isis::TProjection::SetUniversalGround
virtual bool SetUniversalGround(const double lat, const double lon)
This method is used to set the latitude/longitude which must be Planetocentric (latitude) and Positiv...
Definition: TProjection.cpp:839
Isis::Projection::WorldY
virtual double WorldY() const
This returns the world Y coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:544
Isis::Projection::IsGood
bool IsGood() const
This indicates if the last invocation of SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:374
Isis::RingPlaneProjection
Base class for Map Projections of plane shapes.
Definition: RingPlaneProjection.h:147
Isis::Displacement::meters
double meters() const
Get the displacement in meters.
Definition: Displacement.cpp:73
Isis::Projection::m_minimumX
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition: Projection.h:317
Isis::Projection::IsEquatorialCylindrical
virtual bool IsEquatorialCylindrical()
This method returns true if the projection is equatorial cylindrical.
Definition: Projection.cpp:222
Isis::Projection::m_good
bool m_good
Indicates if the contents of m_x, m_y, m_latitude, and m_longitude are valid.
Definition: Projection.h:300
Isis::TProjection
Base class for Map TProjections.
Definition: TProjection.h:166
Isis::TProjection::SetUnboundUniversalGround
bool SetUnboundUniversalGround(const double coord1, const double coord2)
This method is used to set the latitude/longitude.
Definition: TProjection.cpp:879
Isis::WorldMapper
Create a mapping between a projection and other coordinate system.
Definition: WorldMapper.h:38
Isis::Projection::ToWorldY
double ToWorldY(const double projectionY) const
This method converts a projection y value to a world y value.
Definition: Projection.cpp:594
Isis::RingPlaneProjection::SetUniversalGround
bool SetUniversalGround(const double ringRadius, const double ringLongitude)
This method is used to set the ring radius/longitude which must be PositiveEast/Domain360 (ring longi...
Definition: RingPlaneProjection.cpp:546
Isis::Projection::WorldX
virtual double WorldX() const
This returns the world X coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:524
Isis::Projection::m_rotation
double m_rotation
Rotation of map (usually zero)
Definition: Projection.h:333
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Projection::SetWorld
virtual bool SetWorld(const double x, const double y)
This method is used to set a world coordinate.
Definition: Projection.cpp:497
Isis::Projection::m_groundRangeGood
bool m_groundRangeGood
Indicates if the ground range (min/max lat/lons) were read from the labels.
Definition: Projection.h:313
Isis::Null
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:95
Isis::Projection::operator==
virtual bool operator==(const Projection &proj)
This method determines whether two map projection objects are equal by comparing the resolution,...
Definition: Projection.cpp:162
Isis::Projection::SetComputedXY
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:780
std
Namespace for the standard library.
Isis::Projection::ToWorldX
double ToWorldX(const double projectionX) const
This method converts a projection x value to a world x value.
Definition: Projection.cpp:566
Isis::Projection::ToProjectionX
double ToProjectionX(const double worldX) const
This method converts a world x value to a projection x value.
Definition: Projection.cpp:622
Isis::Projection::~Projection
virtual ~Projection()
Destroys the Projection object.
Definition: Projection.cpp:148
Isis::Projection::m_x
double m_x
This contains the rotated X coordinate for a specific projection at theposition indicated by m_latitu...
Definition: Projection.h:335
Isis::Projection::ToDMS
static QString ToDMS(double angle)
Converts the given angle (in degrees) to degrees, minutes, seconds.
Definition: Projection.cpp:706
Isis::Projection::Triaxial
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
Definition: Projection.h:166
Isis::Projection::IsSky
bool IsSky() const
Returns true if projection is sky and false if it is land.
Definition: Projection.cpp:208
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::Projection::ToHours
static double ToHours(double angle)
Converts the given angle (in degrees) to hours by using the ratio 15 degrees per hour.
Definition: Projection.cpp:693
Isis::Projection::YCoord
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:400
Isis::Projection::m_maximumY
double m_maximumY
See minimumX description.
Definition: Projection.h:328
Isis::Projection
Base class for Map Projections.
Definition: Projection.h:155
Isis::Projection::m_maximumX
double m_maximumX
See minimumX description.
Definition: Projection.h:326
Isis::Projection::ToHMS
static QString ToHMS(double angle)
Converts the given angle (in degrees) to hours, minutes, seconds.
Definition: Projection.cpp:741
Isis::Projection::ProjectionType
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition: Projection.h:166
Isis::Projection::XCoord
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:387
Isis::Projection::HasGroundRange
virtual bool HasGroundRange() const
This indicates if the longitude direction type is positive west (as opposed to postive east).
Definition: Projection.cpp:349
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::Projection::SetUnboundUniversalGround
virtual bool SetUnboundUniversalGround(const double coord1, const double coord2)
This method is used to set the lat/lon or radius/azimuth (i.e.
Definition: Projection.cpp:446