Isis 3 Programmer Reference
RingPlaneProjection.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "RingPlaneProjection.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 "SpecialPixel.h"
30#include "WorldMapper.h"
31
32using namespace std;
33namespace Isis {
70 try {
71 // Mapping group is read by the parent (Projection)
72 // Get the RingLongitude Direction
73 if ((QString) m_mappingGrp["RingLongitudeDirection"] == "Clockwise") {
75 }
76 else if ((QString) m_mappingGrp["RingLongitudeDirection"] == "CounterClockwise") {
78 }
79 else {
80 QString msg = "Projection failed. Invalid value for keyword "
81 "[RingLongitudeDirection] must be "
82 "[Clockwise or CounterClockwise]";
83 throw IException(IException::Unknown, msg, _FILEINFO_);
84 }
85
86 // Get the RingLongitudeDomain
87 if ((QString) m_mappingGrp["RingLongitudeDomain"] == "360") {
89 }
90 else if ((QString) m_mappingGrp["RingLongitudeDomain"] == "180") {
92 }
93 else {
94 QString msg = "Projection failed. Invalid value for keyword "
95 "[RingLongitudeDomain] must be [180 or 360]";
96 throw IException(IException::Unknown, msg, _FILEINFO_);
97 }
98
99 // Get the ground range if it exists
100 m_groundRangeGood = false;
101
102 if ((m_mappingGrp.hasKeyword("MinimumRingLongitude")) &&
103 (m_mappingGrp.hasKeyword("MaximumRingLongitude")) &&
104 (m_mappingGrp.hasKeyword("MaximumRingRadius")) &&
105 (m_mappingGrp.hasKeyword("MinimumRingRadius"))) {
106 m_minimumRingLongitude = m_mappingGrp["MinimumRingLongitude"];
107 m_maximumRingLongitude = m_mappingGrp["MaximumRingLongitude"];
108 m_minimumRingRadius = m_mappingGrp["MinimumRingRadius"];
109 m_maximumRingRadius = m_mappingGrp["MaximumRingRadius"];
110
111 if (m_minimumRingRadius < 0) {
112 IString msg = "Projection failed. "
113 "[MinimumRingRadius] of ["+ IString(m_minimumRingRadius) + "] is not "
114 + "valid";
115 throw IException(IException::Unknown, msg, _FILEINFO_);
116 }
117
118 if (m_maximumRingRadius < 0) {
119 IString msg = "Projection failed. "
120 "[MaximumRingRadius] of ["+ IString(m_maximumRingRadius) + "] is not "
121 + "valid";
122 throw IException(IException::Unknown, msg, _FILEINFO_);
123 }
124
126 IString msg = "Projection failed. "
127 "[MinimumRingRadius,MaximumRingRadius] of ["
129 + IString(m_maximumRingRadius) + "] are not "
130 + "properly ordered";
131 throw IException(IException::Unknown, msg, _FILEINFO_);
132 }
133
135 IString msg = "Projection failed. "
136 "[MinimumRingLongitude,MaximumRingLongitude] of ["
138 + IString(m_maximumRingLongitude) + "] are not "
139 + "properly ordered";
140 throw IException(IException::Unknown, msg, _FILEINFO_);
141 }
142
143 m_groundRangeGood = true;
144 }
145 else {
146 // if no ground range is given, initialize the min/max ring rad/lon to 0
151 }
152
153 // Initialize miscellaneous protected data elements
154 // initialize the rest of the x,y,ring rad,ring lon
155 // member variables
158
159 // If we made it to this point, we have what we need for a ring plane projection
161 }
162 catch(IException &e) {
163 IString msg = "Projection failed. Invalid label group [Mapping]";
164 throw IException(e, IException::Unknown, msg, _FILEINFO_);
165 }
166 }
167
171
182 if (!Projection::operator==(proj)) return false;
183 RingPlaneProjection *rproj = (RingPlaneProjection *) &proj;
184 if (IsClockwise() != rproj->IsClockwise()) return false;
185 if (Has180Domain() != rproj->Has180Domain()) return false;
186 return true;
187 }
188
189
200 return 0.0;
201 }
202
203
214
225
240 double RingPlaneProjection::ToClockwise(const double ringLongitude, const int domain) {
241 if (ringLongitude == Null) {
243 "Unable to convert to Clockwise. The given ring longitude value ["
244 + Isis::toString(ringLongitude) + "] is invalid.",
245 _FILEINFO_);
246 }
247 double myRingLongitude = ringLongitude;
248
249 myRingLongitude *= -1;
250
251 if (domain == 360) {
252 myRingLongitude = To360Domain(myRingLongitude);
253 }
254 else if (domain == 180) {
255 myRingLongitude = To180Domain(myRingLongitude);
256 }
257 else {
258 IString msg = "Unable to convert ring longitude. Domain [" + Isis::toString(domain)
259 + "] is not 180 or 360.";
260 throw IException(IException::Unknown, msg, _FILEINFO_);
261 }
262
263 return myRingLongitude;
264 }
265
280 double RingPlaneProjection::ToCounterClockwise(const double ringLongitude, const int domain) {
281 if (ringLongitude == Null) {
283 "Unable to convert to CounterClockwise. The given ring longitude value ["
284 + IString(ringLongitude) + "] is invalid.",
285 _FILEINFO_);
286 }
287 double myRingLongitude = ringLongitude;
288
289 myRingLongitude *= -1;
290
291 if (domain == 360) {
292 myRingLongitude = To360Domain(myRingLongitude);
293 }
294 else if (domain == 180) {
295 myRingLongitude = To180Domain(myRingLongitude);
296 }
297 else {
298 IString msg = "Unable to convert ring longitude. Domain [" + IString(domain)
299 + "] is not 180 or 360.";
300 throw IException(IException::Unknown, msg, _FILEINFO_);
301 }
302
303 return myRingLongitude;
304 }
305
306
315 if (m_ringLongitudeDirection == Clockwise) return "Clockwise";
316 return "CounterClockwise";
317 }
318
327 return m_ringLongitudeDomain == 180;
328 }
329
338 return m_ringLongitudeDomain == 360;
339 }
340
352 double RingPlaneProjection::To180Domain(const double ringLongitude) {
353 if (ringLongitude == Null) {
355 "Unable to convert to 180 degree domain. The given ring longitude value ["
356 + IString(ringLongitude) + "] is invalid.",
357 _FILEINFO_);
358 }
359 return Isis::Longitude(ringLongitude, Angle::Degrees).force180Domain().degrees();
360 }
361
370 double RingPlaneProjection::To360Domain(const double ringLongitude) {
371 if (ringLongitude == Null) {
373 "Unable to convert to 360 degree domain. The given ring longitude value ["
374 + IString(ringLongitude) + "] is invalid.",
375 _FILEINFO_);
376 }
377 double result = ringLongitude;
378
379 if ( (ringLongitude < 0.0 || ringLongitude > 360.0) &&
380 !qFuzzyCompare(ringLongitude, 0.0) && !qFuzzyCompare(ringLongitude, 360.0)) {
381 result = Isis::Longitude(ringLongitude, Angle::Degrees).force360Domain().degrees();
382 }
383
384 return result;
385 }
386
394 if (m_ringLongitudeDomain == 360) return "360";
395 return "180";
396 }
397
408
419
430
441
456 bool RingPlaneProjection::SetGround(const double ringRadius, const double ringLongitude) {
457 if (ringRadius == Null || ringLongitude == Null) {
458 m_good = false;
459 return m_good;
460 }
461 else {
462 m_ringRadius = ringRadius;
463 m_ringLongitude = ringLongitude;
464 m_good = true;
465 SetComputedXY(ringLongitude, ringRadius);
466 }
467 return m_good;
468 }
469
485 bool RingPlaneProjection::SetCoordinate(const double x, const double y) {
486 if (x == Null || y == Null) {
487 m_good = false;
488 }
489 else {
490 m_good = true;
491 SetXY(x, y);
494 }
495 return m_good;
496 }
497
498
507 return m_ringRadius;
508 }
509
510
519 return m_ringRadius;
520 }
521
531 return m_ringLongitude;
532 }
533
546 bool RingPlaneProjection::SetUniversalGround(const double ringRadius, const double ringLongitude) {
547 if (ringRadius == Null || ringLongitude == Null) {
548 m_good = false;
549 return m_good;
550 }
551 // Deal with the ring longitude first
552 m_ringLongitude = ringLongitude;
553 if (m_ringLongitudeDirection == Clockwise) m_ringLongitude = -ringLongitude;
554 if (m_ringLongitudeDomain == 180) {
556 }
557 else {
558 // Do this because RingLongitudeDirection could cause (-360,0)
560 }
561
562 // Nothing to do with radius
563
564 m_ringRadius = ringRadius;
565
566 // Now the rad/ring longitude are in user defined coordinates so set them
568 }
569
576 double ringRadius = m_ringRadius;
577 return ringRadius;
578 }
579
580
590 double ringLongitude = m_ringLongitude;
591 if (m_ringLongitudeDirection == Clockwise) ringLongitude = -ringLongitude;
592 ringLongitude = To360Domain(ringLongitude);
593 return ringLongitude;
594 }
595
596
608 if (m_mapper != NULL) {
609 double localRadius = TrueScaleRingRadius();
610 return localRadius / m_mapper->Resolution() * DEG2RAD;
611 // return localRadius / m_mapper->Resolution();
612 }
613 else {
614 return 1.0;
615 }
616 }
617
618
656 bool RingPlaneProjection::XYRange(double &minX, double &maxX,
657 double &minY, double &maxY) {
658 if (minX == Null || maxX == Null || minY == Null || maxY == Null) {
659 return false;
660 }
661 if (m_groundRangeGood) {
664 minY = m_minimumRingRadius;
665 maxY = m_maximumRingRadius;
666 return true;
667 }
668 return false;
669 }
670
709 void RingPlaneProjection::XYRangeCheck(const double ringRadius, const double ringLongitude) {
710 if (ringRadius == Null || ringLongitude == Null) {
711 m_good = false;
712 return;
713 }
714 SetGround(ringRadius, ringLongitude);
715 if (!IsGood()) return;
716
717 if (XCoord() < m_minimumX) m_minimumX = XCoord();
718 if (XCoord() > m_maximumX) m_maximumX = XCoord();
719 if (YCoord() < m_minimumY) m_minimumY = YCoord();
720 if (YCoord() > m_maximumY) m_maximumY = YCoord();
721 return;
722 }
723
745 // bool Projection::xyRangeOblique(double &minX, double &maxX,
746 // double &minY, double &maxY) {
747 // if (minX == Null || maxX == Null || minY == Null || maxY == Null) {
748 // return false;
749 // }
750 // //For oblique, we'll have to walk all 4 sides to find out min/max x/y values
751 // if (!HasGroundRange()) return false; // Don't have min/max ring rad/lon,
752 // //can't continue
753
754 // m_specialLatCases.clear();
755 // m_specialLonCases.clear();
756
757 // // First, search ring longitude for
758 // min X/Y double minFoundX1, minFoundX2;
759 // double minFoundY1, minFoundY2;
760
761 // // Search for minX between minlat and maxlat along minlon
762 // doSearch(MinimumLatitude(), MaximumLatitude(),
763 // minFoundX1, MinimumLongitude(), true, true, true);
764 // // Search for minX between minlat and maxlat along maxlon
765 // doSearch(MinimumLatitude(), MaximumLatitude(),
766 // minFoundX2, MaximumLongitude(), true, true, true);
767 // // Search for minY between minlat and maxlat along minlon
768 // doSearch(MinimumLatitude(), MaximumLatitude(),
769 // minFoundY1, MinimumLongitude(), false, true, true);
770 // // Search for minY between minlat and maxlat along maxlon
771 // doSearch(MinimumLatitude(), MaximumLatitude(),
772 // minFoundY2, MaximumLongitude(), false, true, true);
773
774 // // Second, search latitude for min X/Y
775 // double minFoundX3, minFoundX4;
776 // double minFoundY3, minFoundY4;
777
778 // // Search for minX between minlon and maxlon along minlat
779 // doSearch(MinimumLongitude(), MaximumLongitude(),
780 // minFoundX3, MinimumLatitude(), true, false, true);
781 // // Search for minX between minlon and maxlon along maxlat
782 // doSearch(MinimumLongitude(), MaximumLongitude(),
783 // minFoundX4, MaximumLatitude(), true, false, true);
784 // // Search for minY between minlon and maxlon along minlat
785 // doSearch(MinimumLongitude(), MaximumLongitude(),
786 // minFoundY3, MinimumLatitude(), false, false, true);
787 // // Search for minY between minlon and maxlon along maxlat
788 // doSearch(MinimumLongitude(), MaximumLongitude(),
789 // minFoundY4, MaximumLatitude(), false, false, true);
790
791 // // We've searched all possible minimums, go ahead and store the lowest
792 // double minFoundX5 = min(minFoundX1, minFoundX2);
793 // double minFoundX6 = min(minFoundX3, minFoundX4);
794 // m_minimumX = min(minFoundX5, minFoundX6);
795
796 // double minFoundY5 = min(minFoundY1, minFoundY2);
797 // double minFoundY6 = min(minFoundY3, minFoundY4);
798 // m_minimumY = min(minFoundY5, minFoundY6);
799
800 // // Search ring longitude for
801 // max X/Y double maxFoundX1,
802 // maxFoundX2; double maxFoundY1,
803 // maxFoundY2;
804
805 // // Search for maxX between minlat and maxlat along minlon
806 // doSearch(MinimumLatitude(), MaximumLatitude(),
807 // maxFoundX1, MinimumLongitude(), true, true, false);
808 // // Search for maxX between minlat and maxlat along maxlon
809 // doSearch(MinimumLatitude(), MaximumLatitude(),
810 // maxFoundX2, MaximumLongitude(), true, true, false);
811 // // Search for maxY between minlat and maxlat along minlon
812 // doSearch(MinimumLatitude(), MaximumLatitude(),
813 // maxFoundY1, MinimumLongitude(), false, true, false);
814 // // Search for maxY between minlat and maxlat along maxlon
815 // doSearch(MinimumLatitude(), MaximumLatitude(),
816 // maxFoundY2, MaximumLongitude(), false, true, false);
817
818 // // Search latitude for max X/Y
819 // double maxFoundX3, maxFoundX4;
820 // double maxFoundY3, maxFoundY4;
821
822 // // Search for maxX between minlon and maxlon along minlat
823 // doSearch(MinimumLongitude(), MaximumLongitude(),
824 // maxFoundX3, MinimumLatitude(), true, false, false);
825 // // Search for maxX between minlon and maxlon along maxlat
826 // doSearch(MinimumLongitude(), MaximumLongitude(),
827 // maxFoundX4, MaximumLatitude(), true, false, false);
828 // // Search for maxY between minlon and maxlon along minlat
829 // doSearch(MinimumLongitude(), MaximumLongitude(),
830 // maxFoundY3, MinimumLatitude(), false, false, false);
831 // // Search for maxY between minlon and maxlon along maxlat
832 // doSearch(MinimumLongitude(), MaximumLongitude(),
833 // maxFoundY4, MaximumLatitude(), false, false, false);
834
835 // // We've searched all possible maximums, go ahead and store the highest
836 // double maxFoundX5 = max(maxFoundX1, maxFoundX2);
837 // double maxFoundX6 = max(maxFoundX3, maxFoundX4);
838 // m_maximumX = max(maxFoundX5, maxFoundX6);
839
840 // double maxFoundY5 = max(maxFoundY1, maxFoundY2);
841 // double maxFoundY6 = max(maxFoundY3, maxFoundY4);
842 // m_maximumY = max(maxFoundY5, maxFoundY6);
843
844 // // Look along discontinuities for more extremes
845 // vector<double> specialLatCases = m_specialLatCases;
846 // for (unsigned int specialLatCase = 0;
847 // specialLatCase < specialLatCases.size();
848 // specialLatCase ++) {
849 // double minX, maxX, minY, maxY;
850
851 // // Search for minX between minlon and maxlon along latitude discontinuities
852 // doSearch(MinimumLongitude(), MaximumLongitude(),
853 // minX, specialLatCases[specialLatCase], true, false, true);
854 // // Search for minY between minlon and maxlon along latitude discontinuities
855 // doSearch(MinimumLongitude(), MaximumLongitude(),
856 // minY, specialLatCases[specialLatCase], false, false, true);
857 // // Search for maxX between minlon and maxlon along latitude discontinuities
858 // doSearch(MinimumLongitude(), MaximumLongitude(),
859 // maxX, specialLatCases[specialLatCase], true, false, false);
860 // // Search for maxX between minlon and maxlon along latitude discontinuities
861 // doSearch(MinimumLongitude(), MaximumLongitude(),
862 // maxY, specialLatCases[specialLatCase], false, false, false);
863
864 // m_minimumX = min(minX, m_minimumX);
865 // m_maximumX = max(maxX, m_maximumX);
866 // m_minimumY = min(minY, m_minimumY);
867 // m_maximumY = max(maxY, m_maximumY);
868 // }
869
870 // vector<double> specialLonCases = m_specialLonCases;
871 // for (unsigned int specialLonCase = 0;
872 // specialLonCase < specialLonCases.size();
873 // specialLonCase ++) {
874 // double minX, maxX, minY, maxY;
875
876 // // Search for minX between minlat and maxlat along longitude discontinuities
877 // doSearch(MinimumLatitude(), MaximumLatitude(),
878 // minX, specialLonCases[specialLonCase], true, true, true);
879 // // Search for minY between minlat and maxlat along longitude discontinuities
880 // doSearch(MinimumLatitude(), MaximumLatitude(),
881 // minY, specialLonCases[specialLonCase], false, true, true);
882 // // Search for maxX between minlat and maxlat along longitude discontinuities
883 // doSearch(MinimumLatitude(), MaximumLatitude(),
884 // maxX, specialLonCases[specialLonCase], true, true, false);
885 // // Search for maxY between minlat and maxlat along longitude discontinuities
886 // doSearch(MinimumLatitude(), MaximumLatitude(),
887 // maxY, specialLonCases[specialLonCase], false, true, false);
888
889 // m_minimumX = min(minX, m_minimumX);
890 // m_maximumX = max(maxX, m_maximumX);
891 // m_minimumY = min(minY, m_minimumY);
892 // m_maximumY = max(maxY, m_maximumY);
893 // }
894
895 // m_specialLatCases.clear();
896 // m_specialLonCases.clear();
897
898 // // Make sure everything is ordered
899 // if (m_minimumX >= m_maximumX) return false;
900 // if (m_minimumY >= m_maximumY) return false;
901
902 // // Return X/Y min/maxs
903 // minX = m_minimumX;
904 // maxX = m_maximumX;
905 // minY = m_minimumY;
906 // maxY = m_maximumY;
907
908 // return true;
909 // }
910
948 // void Projection::doSearch(double minBorder, double maxBorder,
949 // double &extremeVal, const double constBorder,
950 // bool searchX, bool searchRingLongitude, bool findMin) {
951 // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
952 // return;
953 // }
954 // const double TOLERANCE = m_pixelResolution/2;
955 // const int NUM_ATTEMPTS = (unsigned int)DBL_DIG; // It's unsafe to go past
956 // // this precision
957
958 // double minBorderX, minBorderY, maxBorderX, maxBorderY;
959 // int attempts = 0;
960
961 // do {
962 // findExtreme(minBorder, maxBorder, minBorderX, minBorderY, maxBorderX,
963 // maxBorderY, constBorder, searchX, searchLongitude, findMin);
964 // if (minBorderX == Null && maxBorderX == Null
965 // && minBorderY == Null && maxBorderY == Null ) {
966 // attempts = NUM_ATTEMPTS;
967 // continue;
968 // }
969 // attempts ++;
970 // }
971 // while ((fabs(minBorderX - maxBorderX) > TOLERANCE
972 // || fabs(minBorderY - maxBorderY) > TOLERANCE)
973 // && (attempts < NUM_ATTEMPTS));
974 // // check both x and y distance in case symmetry of map
975 // // For example, if minBorderX = maxBorderX but minBorderY = -maxBorderY,
976 // // these points may not be close enough.
977
978 // if (attempts >= NUM_ATTEMPTS) {
979 // // We zoomed in on a discontinuity because our range never shrank, this
980 // // will need to be rechecked later.
981 // // *min and max border should be nearly identical, so it doesn't matter
982 // // which is used here
983 // if (searchLongitude) {
984 // m_specialLatCases.push_back(minBorder);
985 // }
986 // else {
987 // m_specialLonCases.push_back(minBorder);
988 // }
989 // }
990
991 // // These values will always be accurate, even over a discontinuity
992 // if (findMin) {
993 // if (searchX) extremeVal = min(minBorderX, maxBorderX);
994 // else extremeVal = min(minBorderY, maxBorderY);
995 // }
996 // else {
997 // if (searchX) extremeVal = max(minBorderX, maxBorderX);
998 // else extremeVal = max(minBorderY, maxBorderY);
999 // }
1000 // return;
1001 // }
1002
1062 // void Projection::findExtreme(double &minBorder, double &maxBorder,
1063 // double &minBorderX, double &minBorderY,
1064 // double &maxBorderX, double &maxBorderY,
1065 // const double constBorder, bool searchX,
1066 // bool searchRingLongitude, bool findMin) {
1067 // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
1068 // minBorderX = Null;
1069 // minBorderY = minBorderX;
1070 // minBorderX = minBorderX;
1071 // minBorderY = minBorderX;
1072 // return;
1073 // }
1074 // if (!searchRingLongitude && (fabs(fabs(constBorder) - 90.0) < DBL_EPSILON)) {
1075 // // it is impossible to search "along" a pole
1076 // setSearchGround(minBorder, constBorder, searchRingLongitude);
1077 // minBorderX = XCoord();
1078 // minBorderY = YCoord();
1079 // maxBorderX = minBorderX;
1080 // maxBorderY = minBorderY;
1081 // return;
1082 // }
1083 // // Always do 10 steps
1084 // const double STEP_SIZE = (maxBorder - minBorder) / 10.0;
1085 // const double LOOP_END = maxBorder + (STEP_SIZE / 2.0); // This ensures we do
1086 // // all of the steps
1087 // // properly
1088 // double currBorderVal = minBorder;
1089 // setSearchGround(minBorder, constBorder, searchRingLongitude);
1090
1091 // // this makes sure that the initial currBorderVal is valid before entering
1092 // // the loop below
1093 // if (!m_good){
1094 // // minBorder = currBorderVal+STEP_SIZE < LOOP_END until setGround is good?
1095 // // then, if still not good return?
1096 // while (!m_good && currBorderVal <= LOOP_END) {
1097 // currBorderVal+=STEP_SIZE;
1098 // if (searchRingLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1099 // currBorderVal = 90.0;
1100 // }
1101 // setSearchGround(currBorderVal, constBorder, searchRingLongitude);
1102 // }
1103 // if (!m_good) {
1104 // minBorderX = Null;
1105 // minBorderY = minBorderX;
1106 // minBorderX = minBorderX;
1107 // minBorderY = minBorderX;
1108 // return;
1109 // }
1110 // }
1111
1112 // // save the values of three consecutive steps from the minBorder towards
1113 // // the maxBorder along the constBorder. initialize these three border
1114 // // values (the non-constant lat or lon)
1115 // double border1 = currBorderVal;
1116 // double border2 = currBorderVal;
1117 // double border3 = currBorderVal;
1118
1119 // // save the coordinate (x or y) values that correspond to the first
1120 // // two borders that are being saved.
1121 // // initialize these two coordinate values (x or y)
1122 // double value1 = (searchX) ? XCoord() : YCoord();
1123 // double value2 = value1;
1124
1125 // // initialize the extreme coordinate value
1126 // // -- this is the largest coordinate value found so far
1127 // double extremeVal2 = value2;
1128
1129 // // initialize the extreme border values
1130 // // -- these are the borders on either side of the extreme coordinate value
1131 // double extremeBorder1 = minBorder;
1132 // double extremeBorder3 = minBorder;
1133
1134 // while (currBorderVal <= LOOP_END) {
1135
1136 // // this conditional was added to prevent trying to SetGround with an
1137 // // invalid latitude greater than 90 degrees. There is no need check for
1138 // // latitude less than -90 since we start at the minBorder (already
1139 // // assumed to be valid) and step forward toward (and possibly past)
1140 // // maxBorder
1141 // if (searchRingLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1142 // currBorderVal = 90.0;
1143 // }
1144
1145 // // update the current border value along constBorder
1146 // currBorderVal += STEP_SIZE;
1147 // setSearchGround(currBorderVal, constBorder, searchRingLongitude);
1148 // if (!m_good){
1149 // continue;
1150 // }
1151
1152 // // update the border and coordinate values
1153 // border3 = border2;
1154 // border2 = border1;
1155 // border1 = currBorderVal;
1156 // value2 = value1;
1157 // value1 = (searchX) ? XCoord() : YCoord();
1158
1159 // if ((findMin && value2 < extremeVal2)
1160 // || (!findMin && value2 > extremeVal2)) {
1161 // // Compare the coordinate value associated with the center border with
1162 // // the current extreme. If the updated coordinate value is more extreme
1163 // // (smaller or larger, depending on findMin), then we update the
1164 // // extremeVal and it's borders.
1165 // extremeVal2 = value2;
1166
1167 // extremeBorder3 = border3;
1168 // extremeBorder1 = border1;
1169 // }
1170 // }
1171
1172 // // update min/max border values to the values on either side of the most
1173 // // extreme coordinate found in this call to this method
1174
1175 // minBorder = extremeBorder3; // Border 3 is lagging and thus smaller
1176
1177 // // since the loop steps past the original maxBorder, we want to retain
1178 // // the original maxBorder value so we don't go outside of the original
1179 // // min/max range given
1180 // if (extremeBorder1 <= maxBorder ) {
1181 // maxBorder = extremeBorder1; // Border 1 is leading and thus larger
1182 // }
1183
1184 // // update minBorder coordinate values
1185 // setSearchGround(minBorder, constBorder, searchRingLongitude);
1186 // // if (!m_good){
1187 // // this should not happen since minBorder has already been verified in
1188 // // the while loop above
1189 // // }
1190
1191 // minBorderX = XCoord();
1192 // minBorderY = YCoord();
1193
1194 // // update maxBorder coordinate values
1195 // setSearchGround(maxBorder, constBorder, searchRingLongitude);
1196 // // if (!m_good){
1197 // // this should not happen since maxBorder has already been verified in
1198 // // the while loop above
1199 // // }
1200
1201 // maxBorderX = XCoord();
1202 // maxBorderY = YCoord();
1203 // return;
1204 // }
1205
1228 // void Projection::setSearchGround(const double variableBorder,
1229 // const double constBorder,
1230 // bool variableIsLat) {
1231 // if (variableBorder == Null || constBorder == Null) {
1232 // return;
1233 // }
1234 // double lat, lon;
1235 // if (variableIsLat) {
1236 // lat = variableBorder;
1237 // lon = constBorder;
1238 // }
1239 // else {
1240 // lat = constBorder;
1241 // lon = variableBorder;
1242 // }
1243 // SetGround(lat, lon);
1244 // return;
1245 // }
1246
1247
1254 PvlGroup mapping("Mapping");
1255
1256 if (m_mappingGrp.hasKeyword("TargetName")) {
1257 mapping += m_mappingGrp["TargetName"];
1258 }
1259
1260 mapping += m_mappingGrp["ProjectionName"];
1261 mapping += m_mappingGrp["RingLongitudeDirection"];
1262 mapping += m_mappingGrp["RingLongitudeDomain"];
1263
1264 if (m_mappingGrp.hasKeyword("PixelResolution")) {
1265 mapping += m_mappingGrp["PixelResolution"];
1266 }
1267 if (m_mappingGrp.hasKeyword("Scale")) {
1268 mapping += m_mappingGrp["Scale"];
1269 }
1270 if (m_mappingGrp.hasKeyword("UpperLeftCornerX")) {
1271 mapping += m_mappingGrp["UpperLeftCornerX"];
1272 }
1273 if (m_mappingGrp.hasKeyword("UpperLeftCornerY")) {
1274 mapping += m_mappingGrp["UpperLeftCornerY"];
1275 }
1276
1277 if (HasGroundRange()) {
1278 mapping += m_mappingGrp["MinimumRingRadius"];
1279 mapping += m_mappingGrp["MaximumRingRadius"];
1280 mapping += m_mappingGrp["MinimumRingLongitude"];
1281 mapping += m_mappingGrp["MaximumRingLongitude"];
1282 }
1283
1284 if (m_mappingGrp.hasKeyword("Rotation")) {
1285 mapping += m_mappingGrp["Rotation"];
1286 }
1287
1288 return mapping;
1289 }
1290
1297 PvlGroup mapping("Mapping");
1298
1299 if (HasGroundRange()) {
1300 mapping += m_mappingGrp["MinimumRingRadius"];
1301 mapping += m_mappingGrp["MaximumRingRadius"];
1302 }
1303
1304 return mapping;
1305 }
1306
1307
1314 PvlGroup mapping("Mapping");
1315
1316 if (HasGroundRange()) {
1317 mapping += m_mappingGrp["MinimumRingLongitude"];
1318 mapping += m_mappingGrp["MaximumRingLongitude"];
1319 }
1320
1321 return mapping;
1322 }
1323
1324} //end namespace isis
double degrees() const
Get the angle in units of Degrees.
Definition Angle.h:232
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
Adds specific functionality to C++ strings.
Definition IString.h:165
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
Longitude force180Domain() const
This returns a longitude that is constricted to -180 to 180 degrees.
Longitude force360Domain() const
This returns a longitude that is constricted to 0-360 degrees.
Base class for Map Projections.
Definition Projection.h:155
@ RingPlane
These projections are used to map ring planes.
Definition Projection.h:168
WorldMapper * m_mapper
This points to a mapper passed into the SetWorldMapper method.
Definition Projection.h:292
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround,...
double m_maximumX
See minimumX description.
Definition Projection.h:326
virtual bool HasGroundRange() const
This indicates if the longitude direction type is positive west (as opposed to postive east).
bool m_groundRangeGood
Indicates if the ground range (min/max lat/lons) were read from the labels.
Definition Projection.h:313
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround,...
bool m_good
Indicates if the contents of m_x, m_y, m_latitude, and m_longitude are valid.
Definition Projection.h:300
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition Projection.h:317
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition Projection.h:329
double m_minimumY
See minimumX description.
Definition Projection.h:327
void SetXY(double x, double y)
This protected method is a helper for derived classes.
bool IsGood() const
This indicates if the last invocation of SetGround, SetCoordinate, SetUniversalGround,...
void setProjectionType(const ProjectionType ptype)
Sets the projection subclass type.
double m_maximumY
See minimumX description.
Definition Projection.h:328
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
Base class for Map Projections of plane shapes.
static double ToClockwise(const double ringLongitude, const int domain)
This method converts an ring longitude into the clockwise direction.
double m_minimumRingLongitude
Contains the minimum longitude for the entire ground range.
bool Has360Domain() const
This indicates if the ring longitude domain is 0 to 360 (as opposed to -180 to 180).
double UniversalRingLongitude()
This returns a universal ring longitude (clockwise in 0 to 360 domain).
static double To360Domain(const double lon)
This method converts an ring longitude into the 0 to 360 domain.
double MaximumRingLongitude() const
This returns the maximum ring longitude of the area of interest.
double RingRadius() const
This returns a radius.
virtual PvlGroup MappingRingLongitudes()
This function returns the ring longitude keywords that this projection uses.
double UniversalRingRadius()
This returns a universal radius, which is just the radius in meters.
RingPlaneProjection(Pvl &label)
Constructs an empty RingPlaneProjection object.
virtual double TrueScaleRingRadius() const
This method returns the radius of true scale.
virtual ~RingPlaneProjection()
Destroys the Projection object.
bool IsClockwise() const
This indicates if the longitude direction type is positive west (as opposed to postive east).
int m_ringLongitudeDomain
This integer is either 180 or 360 and is read from the labels.
virtual PvlGroup Mapping()
This method is used to find the XY range for oblique aspect projections (non-polar projections) by "w...
virtual bool operator==(const Projection &proj)
This method determines whether two map projection objects are equal by comparing the ring longitude d...
double m_maximumRingRadius
Contains the maximum ring radius for the entire ground range.
double LocalRadius() const
This returns a local radius.
static double To180Domain(const double lon)
This method converts a ring longitude into the -180 to 180 domain.
bool IsCounterClockwise() const
This indicates if the longitude direction type is positive east (as opposed to postive west).
double m_maximumRingLongitude
Contains the maximum longitude for the entire ground range.
std::string RingLongitudeDirectionString() const
This method returns the ring longitude direction as a string.
void XYRangeCheck(const double ringRadius, const double ringLongitude)
This convience function is established to assist in the development of the XYRange virtual method.
double m_ringRadius
This contain a ring radius value in m.
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...
virtual PvlGroup MappingRingRadii()
This function returns the ring radius keywords that this projection uses.
virtual bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
double m_ringLongitude
This contain a ring longitude value.
static double ToCounterClockwise(const double ringLongitude, const int domain)
This method converts an ring longitude into the counterclockwise direction.
double Scale() const
This method returns the scale for mapping world coordinates into projection coordinates.
double MaximumRingRadius() const
This returns the maximum radius of the area of interest.
std::string RingLongitudeDomainString() const
This method returns the ring longitude domain as a string.
@ Clockwise
Ring longitude values increase in the clockwise direction.
@ CounterClockwise
Ring longitude values increase in the counterclockwise direction.
RingLongitudeDirection m_ringLongitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
bool Has180Domain() const
This indicates if the longitude domain is -180 to 180 (as opposed to 0 to 360).
double MinimumRingLongitude() const
This returns the minimum ring longitude of the area of interest.
double MinimumRingRadius() const
This returns the minimum radius of the area of interest.
double RingLongitude() const
This returns a ring longitude with correct ring longitude direction and domain as specified in the la...
virtual bool XYRange(double &minX, double &maxX, double &minY, double &maxY)
This method is used to determine the x/y range which completely covers the area of interest specified...
double m_minimumRingRadius
Contains the minimum ring radius for the entire ground range.
virtual bool SetGround(const double ringRadius, const double ringLongitude)
This method is used to set the ring radius/longitude (assumed to be of the correct LatitudeType,...
virtual double Resolution() const
This virtual method will the resolution of the world system relative to one unit in the projection sy...
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
const double DEG2RAD
Multiplier for converting from degrees to radians.
Definition Constants.h:43
const double Null
Value for an Isis Null pixel.
Namespace for the standard library.