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
34using namespace std;
35namespace 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 {
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 {
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
Displacement is a signed length, usually in meters.
double meters() const
Get the displacement in meters.
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
Base class for Map Projections.
Definition Projection.h:155
double m_y
This contains the rotated Y coordinate for a specific projection at the position indicated by m_latit...
Definition Projection.h:339
static double ToHours(double angle)
Converts the given angle (in degrees) to hours by using the ratio 15 degrees per hour.
double ToWorldY(const double projectionY) const
This method converts a projection y value to a world y value.
virtual bool SetUniversalGround(const double coord1, const double coord2)
This method is used to set the lat/lon or radius/azimuth (i.e.
void SetWorldMapper(WorldMapper *mapper)
If desired the programmer can use this method to set a world mapper to be used in the SetWorld,...
double m_rotation
Rotation of map (usually zero)
Definition Projection.h:333
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition Projection.h:166
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
Definition Projection.h:166
WorldMapper * m_mapper
This points to a mapper passed into the SetWorldMapper method.
Definition Projection.h:292
double Resolution() const
This method returns the resolution for mapping world coordinates into projection coordinates.
virtual bool operator==(const Projection &proj)
This method determines whether two map projection objects are equal by comparing the resolution,...
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround,...
double m_maximumX
See minimumX description.
Definition Projection.h:326
virtual bool SetWorld(const double x, const double y)
This method is used to set a world coordinate.
virtual ~Projection()
Destroys the Projection object.
bool IsSky() const
Returns true if projection is sky and false if it is land.
virtual bool HasGroundRange() const
This indicates if the longitude direction type is positive west (as opposed to postive east).
double ToWorldX(const double projectionX) const
This method converts a projection x value to a world x value.
double m_pixelResolution
Pixel resolution value from the PVL mapping group, in meters/pixel.
Definition Projection.h:344
void SetUpperLeftCorner(const Displacement &x, const Displacement &y)
This method searches for extreme (min/max/discontinuity) coordinate values along the constBorder line...
bool m_groundRangeGood
Indicates if the ground range (min/max lat/lons) were read from the labels.
Definition Projection.h:313
double PixelResolution() const
Returns the pixel resolution value from the PVL mapping group in meters/pixel.
virtual bool SetUnboundUniversalGround(const double coord1, const double coord2)
This method is used to set the lat/lon or radius/azimuth (i.e.
virtual double WorldY() const
This returns the world Y coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround,...
virtual double WorldX() const
This returns the world X coordinate provided SetGround, SetCoordinate, SetUniversalGround,...
double ToProjectionY(const double worldY) const
This method converts a world y value to a projection y value.
virtual QString Name() const =0
This method returns the name of the map projection.
double GetX() const
Calculates the unrotated form of current x value.
bool operator!=(const Projection &proj)
This method determines whether two map projection objects are not equal.
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
Projection(Pvl &label)
Constructs an empty Projection object.
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition Projection.h:329
static QString ToHMS(double angle)
Converts the given angle (in degrees) to hours, minutes, seconds.
double m_minimumY
See minimumX description.
Definition Projection.h:327
bool m_sky
Indicates whether projection is sky or land.
Definition Projection.h:310
double Rotation() const
Returns the value of the Rotation keyword from the mapping group.
double ToProjectionX(const double worldX) const
This method converts a world x value to a projection x value.
double GetY() const
Calculates the unrotated form of the current y value.
virtual bool IsEquatorialCylindrical()
This method returns true if the projection is equatorial cylindrical.
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,...
double m_x
This contains the rotated X coordinate for a specific projection at theposition indicated by m_latitu...
Definition Projection.h:335
ProjectionType projectionType() const
Returns an enum value for the projection type.
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.
static QString ToDMS(double angle)
Converts the given angle (in degrees) to degrees, minutes, seconds.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
@ Traverse
Search child objects.
Definition PvlObject.h:158
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition PvlObject.h:129
Base class for Map Projections of plane shapes.
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...
Base class for Map TProjections.
bool SetUnboundUniversalGround(const double coord1, const double coord2)
This method is used to set the latitude/longitude.
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...
Create a mapping between a projection and other coordinate system.
Definition WorldMapper.h:38
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.
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.
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.
virtual double Resolution() const
This virtual method will the resolution of the world system relative to one unit in the projection sy...
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.
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 Null
Value for an Isis Null pixel.
const double PI
The mathematical constant PI.
Definition Constants.h:40
Namespace for the standard library.