Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
Projection.cpp
1
5
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 "Displacement.h"
18#include "FileName.h"
19#include "IException.h"
20#include "IString.h"
21#include "Pvl.h"
22#include "PvlKeyword.h"
23#include "RingPlaneProjection.h"
24#include "SpecialPixel.h"
25#include "TProjection.h"
26#include "WorldMapper.h"
27
28using namespace std;
29namespace Isis {
85 Projection::Projection(Pvl &label) : m_mappingGrp("Mapping") {
86 try {
87 // Try to read the mapping group
88 m_mappingGrp = label.findGroup("Mapping", Pvl::Traverse);
89
90 // TODO** Try to generalize these to keep in parent Projection class and use for both azimuth and longitude
91 // Get the RingLongitudeDomain or LongitudeDomain
92 // if ((string) m_mappingGrp["LongitudeDomain"] == "360") {
93 // m_longitudeDomain = 360;
94 // }
95 // else if ((string) m_mappingGrp["LongitudeDomain"] == "180") {
96 // m_longitudeDomain = 180;
97 // }
98 // else {
99 // IString msg = "Projection failed. Invalid value for keyword "
100 // "[LongitudeDomain] must be [180 or 360]";
101 // throw IException(IException::Unknown, msg, _FILEINFO_);
102 // }
103
104 // Get the map rotation
105 m_rotation = 0.0;
106 if (m_mappingGrp.hasKeyword("Rotation")) {
107 m_rotation = m_mappingGrp["Rotation"];
108 }
109
110 // Initialize miscellaneous protected data elements
111 m_good = false;
112
113 m_pixelResolution = 1.0;
114 if (m_mappingGrp.hasKeyword("PixelResolution")) {
115 m_pixelResolution = m_mappingGrp["PixelResolution"];
116 }
117
118 m_minimumX = DBL_MAX;
119 m_maximumX = -DBL_MAX;
120 m_minimumY = DBL_MAX;
121 m_maximumY = -DBL_MAX;
122
123 m_mapper = NULL;
124
125 m_sky = false;
126 if (m_mappingGrp.hasKeyword("TargetName")) {
127 QString str = m_mappingGrp["TargetName"];
128 if (str.toUpper() == "SKY") m_sky = true;
129 }
130
131 // initialize the rest of the x,y,lat,lon member variables
132 m_x = Null;
133 m_y = Null;
134 }
135 catch(IException &e) {
136 QString msg = "Projection failed. Invalid label group [Mapping]";
137 throw IException(e, IException::Unknown, msg, _FILEINFO_);
138 }
139 }
140
143 delete m_mapper;
144 m_mapper = NULL;
145 }
146
157 if (Resolution() != proj.Resolution()) return false;
158 if (Name() != proj.Name()) return false;
159 return true;
160 }
161
162
173 return !(*this == proj);
174 }
175
176
183 m_projectionType = ptype;
184 }
185
186
193 return m_projectionType;
194 }
195
196
202 bool Projection::IsSky() const {
203 return m_sky;
204 }
205
206
217 return false;
218 }
219
227 // bool Projection::IsPositiveEast() const {
228 // return m_longitudeDirection == PositiveEast;
229 // }
230
238 // bool Projection::IsPositiveWest() const {
239 // return m_longitudeDirection == PositiveWest;
240 // }
241
242
250 // string Projection::LongitudeDirectionString() const {
251 // if (m_longitudeDirection == PositiveEast) return "PositiveEast";
252 // return "PositiveWest";
253 // }
254
262 // bool Projection::Has180Domain() const {
263 // return m_longitudeDomain == 180;
264// }
265
273 // bool Projection::Has360Domain() const {
274 // return m_longitudeDomain == 360;
275 // }
276
287 // double Projection::To180Domain(const double lon) {
288 // if (lon == Null) {
289 // throw IException(IException::Unknown,
290 // "Unable to convert to 180 degree domain. The given longitude value ["
291 // + IString(lon) + "] is invalid.",
292 // _FILEINFO_);
293 // }
294 // return Isis::Longitude(lon, Angle::Degrees).force180Domain().degrees();
295 // }
296
305 // double Projection::To360Domain(const double lon) {
306 // if (lon == Null) {
307 // throw IException(IException::Unknown,
308 // "Unable to convert to 360 degree domain. The given longitude value ["
309 // + IString(lon) + "] is invalid.",
310 // _FILEINFO_);
311 // }
312 // double result = lon;
313
314 // if ( (lon < 0.0 || lon > 360.0) &&
315 // !qFuzzyCompare(lon, 0.0) && !qFuzzyCompare(lon, 360.0)) {
316 // result = Isis::Longitude(lon, Angle::Degrees).force360Domain().degrees();
317 // }
318
319 // return result;
320 // }
321
328 // string Projection::LongitudeDomainString() const {
329 // if (m_longitudeDomain == 360) return "360";
330 // return "180";
331 // }
332
344 return m_groundRangeGood;
345 }
346
347
353 double Projection::Rotation() const {
354 return m_rotation;
355 }
356
357
368 bool Projection::IsGood() const {
369 return m_good;
370 }
371
372
381 double Projection::XCoord() const {
382 return m_x;
383 }
384
385
394 double Projection::YCoord() const {
395 return m_y;
396 }
397
398
411 bool Projection::SetUniversalGround(const double coord1, const double coord2) {
412 if (coord1 == Null || coord2 == Null) {
413 m_good = false;
414 return m_good;
415 }
416 if (projectionType() == Triaxial) {
417 TProjection *tproj = (TProjection *) this;
418 return tproj->SetUniversalGround(coord1, coord2);
419 }
420 else {
422 return rproj->SetUniversalGround(coord1, coord2);
423 }
424 }
425
426
440 bool Projection::SetUnboundUniversalGround(const double coord1, const double coord2) {
441 if (coord1 == Null || coord2 == Null) {
442 m_good = false;
443 return m_good;
444 }
445 if (projectionType() == Triaxial) {
446 TProjection *tproj = (TProjection *) this;
447 return tproj->SetUnboundUniversalGround(coord1, coord2);
448 }
449 else {
451 return rproj->SetUniversalGround(coord1, coord2);
452 }
453 }
454
455
469 m_mapper = mapper;
470 }
471
491 bool Projection::SetWorld(const double worldX, const double worldY) {
492 double projectionX;
493 double projectionY;
494
495 if (m_mapper != NULL) {
496 projectionX = m_mapper->ProjectionX(worldX);
497 projectionY = m_mapper->ProjectionY(worldY);
498 }
499 else {
500 projectionX = worldX;
501 projectionY = worldY;
502 }
503
504 return SetCoordinate(projectionX, projectionY);
505 }
506
518 double Projection::WorldX() const {
519 if (m_mapper != NULL) {
520 return m_mapper->WorldX(m_x);
521 }
522 else {
523 return m_x;
524 }
525 }
526
538 double Projection::WorldY() const {
539 if (m_mapper != NULL) {
540 return m_mapper->WorldY(m_y);
541 }
542 else {
543 return m_y;
544 }
545 }
546
560 double Projection::ToWorldX(const double projectionX) const {
561 if (projectionX == Null) {
562 throw IException(IException::Unknown,
563 "Unable to convert to world x. The given x-value ["
564 + IString(projectionX) + "] is invalid.",
565 _FILEINFO_);
566 }
567 if (m_mapper != NULL) {
568 return m_mapper->WorldX(projectionX);
569 }
570 else {
571 return projectionX;
572 }
573 }
574
588 double Projection::ToWorldY(const double projectionY) const {
589 if (projectionY == Null) {
590 throw IException(IException::Unknown,
591 "Unable to convert to world y. The given y-value ["
592 + IString(projectionY) + "] is invalid.",
593 _FILEINFO_);
594 }
595 if (m_mapper != NULL) {
596 return m_mapper->WorldY(projectionY);
597 }
598 else {
599 return projectionY;
600 }
601 }
602
616 double Projection::ToProjectionX(const double worldX) const {
617 if (worldX == Null) {
618 throw IException(IException::Unknown,
619 "Unable to convert to projection x. The given x-value ["
620 + IString(worldX) + "] is invalid.",
621 _FILEINFO_);
622 }
623 if (m_mapper != NULL) {
624 return m_mapper->ProjectionX(worldX);
625 }
626 else {
627 return worldX;
628 }
629 }
630
644 double Projection::ToProjectionY(const double worldY) const {
645 if (worldY == Null) {
646 throw IException(IException::Unknown,
647 "Unable to convert to projection y. The given y-value ["
648 + IString(worldY) + "] is invalid.",
649 _FILEINFO_);
650 }
651 if (m_mapper != NULL) {
652 return m_mapper->ProjectionY(worldY);
653 }
654 else {
655 return worldY;
656 }
657 }
658
669 double Projection::Resolution() const {
670 if (m_mapper != NULL) {
671 return m_mapper->Resolution();
672 }
673 else {
674 return 1.0;
675 }
676 }
677
678
687 double Projection::ToHours(double angle) {
688 return angle / 15.0;
689 }
690
700 QString Projection::ToDMS(double angle) {
701 int iangle = (int)angle;
702 double mins = abs(angle - iangle) * 60.0;
703 int imins = (int)mins;
704 double secs = (mins - imins) * 60.0;
705 int isecs = (int)secs;
706 double frac = (secs - isecs) * 1000.0;
707 if (frac >= 1000.0) {
708 frac -= 1000.0;
709 isecs++;
710 }
711 if (isecs >= 60) {
712 isecs -= 60;
713 imins++;
714 }
715 if (imins >= 60) {
716 imins -= 60;
717 iangle++;
718 }
719 stringstream s;
720 s << iangle << " " << setw(2) << setfill('0')
721 << imins << "m " << setw(2) << setfill('0') << isecs << "." <<
722 setprecision(3) << frac << "s";
723 return s.str().c_str();
724 }
725
735 QString Projection::ToHMS(double angle) {
736 double tangle = angle;
737 while (tangle < 0.0) tangle += 360.0;
738 while (tangle > 360.0) tangle -= 360.0;
739 double hrs = ToHours(tangle);
740 int ihrs = (int)(hrs);
741 double mins = (hrs - ihrs) * 60.0;
742 int imins = (int)(mins);
743 double secs = (mins - imins) * 60.0;
744 int isecs = (int)(secs);
745 double msecs = (secs - isecs) * 1000.0;
746 int imsecs = (int)(msecs + 0.5);
747 if (imsecs >= 1000) {
748 imsecs -= 1000;
749 isecs++;
750 }
751 if (isecs >= 60) {
752 isecs -= 60;
753 imins++;
754 }
755 if (imins >= 60) {
756 imins -= 60;
757 ihrs++;
758 }
759 stringstream s;
760 s << setw(2) << setfill('0') << ihrs << "h " << setw(2) << setfill('0') <<
761 imins << "m " << setw(2) << setfill('0') << isecs << "." << imsecs << "s";
762 return s.str().c_str();
763 }
764
774 void Projection::SetComputedXY(double x, double y) {
775 if (x == Null || y == Null) {
776 m_good = false;
777 return;
778 }
779 if (m_rotation == 0.0) {
780 m_x = x;
781 m_y = y;
782 }
783 else {
784 double rot = m_rotation * PI / 180.0;
785 m_x = x * cos(rot) + y * sin(rot);
786 m_y = y * cos(rot) - x * sin(rot);
787 }
788 }
789
798 void Projection::SetXY(double x, double y) {
799 if (x == Null || y == Null) {
800 m_good = false;
801 }
802 m_x = x;
803 m_y = y;
804 return;
805 }
806
812 double Projection::GetX() const {
813 if (m_rotation == 0.0) return m_x;
814 double rot = m_rotation * PI / 180.0;
815 return m_x * cos(rot) - m_y * sin(rot);
816 }
817
823 double Projection::GetY() const {
824 if (m_rotation == 0.0) return m_y;
825 double rot = m_rotation * PI / 180.0;
826 return m_y * cos(rot) + m_x * sin(rot);
827 }
828
835 return m_pixelResolution;
836 }
837
838
839 // /**
840 // * This method is used to find the XY range for oblique aspect projections
841 // * (non-polar projections) by "walking" around each of the min/max lat/lon.
842 // *
843 // * @param minX Minimum x projection coordinate which covers the latitude
844 // * longitude range specified in the labels.
845 // * @param maxX Maximum x projection coordinate which covers the latitude
846 // * longitude range specified in the labels.
847 // * @param minY Minimum y projection coordinate which covers the latitude
848 // * longitude range specified in the labels.
849 // * @param maxY Maximum y projection coordinate which covers the latitude
850 // * longitude range specified in the labels.
851 // *
852 // * @return @b bool Indicates whether the method was successful.
853 // * @see XYRange()
854 // * @author Stephen Lambright
855 // * @internal
856 // * @history 2011-07-02 Jeannie Backer - Moved this code from
857 // * ObliqueCylindrical class to its own method here.
858 // */
859 // bool Projection::xyRangeOblique(double &minX, double &maxX,
860 // double &minY, double &maxY) {
861 // if (minX == Null || maxX == Null || minY == Null || maxY == Null) {
862 // return false;
863 // }
864 // //For oblique, we'll have to walk all 4 sides to find out min/max x/y values
865 // if (!HasGroundRange()) return false; // Don't have min/max lat/lon,
866 // //can't continue
867
868 // m_specialLatCases.clear();
869 // m_specialLonCases.clear();
870
871 // // First, search longitude for min X/Y
872 // double minFoundX1, minFoundX2;
873 // double minFoundY1, minFoundY2;
874
875 // // Search for minX between minlat and maxlat along minlon
876 // doSearch(MinimumLatitude(), MaximumLatitude(),
877 // minFoundX1, MinimumLongitude(), true, true, true);
878 // // Search for minX between minlat and maxlat along maxlon
879 // doSearch(MinimumLatitude(), MaximumLatitude(),
880 // minFoundX2, MaximumLongitude(), true, true, true);
881 // // Search for minY between minlat and maxlat along minlon
882 // doSearch(MinimumLatitude(), MaximumLatitude(),
883 // minFoundY1, MinimumLongitude(), false, true, true);
884 // // Search for minY between minlat and maxlat along maxlon
885 // doSearch(MinimumLatitude(), MaximumLatitude(),
886 // minFoundY2, MaximumLongitude(), false, true, true);
887
888 // // Second, search latitude for min X/Y
889 // double minFoundX3, minFoundX4;
890 // double minFoundY3, minFoundY4;
891
892 // // Search for minX between minlon and maxlon along minlat
893 // doSearch(MinimumLongitude(), MaximumLongitude(),
894 // minFoundX3, MinimumLatitude(), true, false, true);
895 // // Search for minX between minlon and maxlon along maxlat
896 // doSearch(MinimumLongitude(), MaximumLongitude(),
897 // minFoundX4, MaximumLatitude(), true, false, true);
898 // // Search for minY between minlon and maxlon along minlat
899 // doSearch(MinimumLongitude(), MaximumLongitude(),
900 // minFoundY3, MinimumLatitude(), false, false, true);
901 // // Search for minY between minlon and maxlon along maxlat
902 // doSearch(MinimumLongitude(), MaximumLongitude(),
903 // minFoundY4, MaximumLatitude(), false, false, true);
904
905 // // We've searched all possible minimums, go ahead and store the lowest
906 // double minFoundX5 = min(minFoundX1, minFoundX2);
907 // double minFoundX6 = min(minFoundX3, minFoundX4);
908 // m_minimumX = min(minFoundX5, minFoundX6);
909
910 // double minFoundY5 = min(minFoundY1, minFoundY2);
911 // double minFoundY6 = min(minFoundY3, minFoundY4);
912 // m_minimumY = min(minFoundY5, minFoundY6);
913
914 // // Search longitude for max X/Y
915 // double maxFoundX1, maxFoundX2;
916 // double maxFoundY1, maxFoundY2;
917
918 // // Search for maxX between minlat and maxlat along minlon
919 // doSearch(MinimumLatitude(), MaximumLatitude(),
920 // maxFoundX1, MinimumLongitude(), true, true, false);
921 // // Search for maxX between minlat and maxlat along maxlon
922 // doSearch(MinimumLatitude(), MaximumLatitude(),
923 // maxFoundX2, MaximumLongitude(), true, true, false);
924 // // Search for maxY between minlat and maxlat along minlon
925 // doSearch(MinimumLatitude(), MaximumLatitude(),
926 // maxFoundY1, MinimumLongitude(), false, true, false);
927 // // Search for maxY between minlat and maxlat along maxlon
928 // doSearch(MinimumLatitude(), MaximumLatitude(),
929 // maxFoundY2, MaximumLongitude(), false, true, false);
930
931 // // Search latitude for max X/Y
932 // double maxFoundX3, maxFoundX4;
933 // double maxFoundY3, maxFoundY4;
934
935 // // Search for maxX between minlon and maxlon along minlat
936 // doSearch(MinimumLongitude(), MaximumLongitude(),
937 // maxFoundX3, MinimumLatitude(), true, false, false);
938 // // Search for maxX between minlon and maxlon along maxlat
939 // doSearch(MinimumLongitude(), MaximumLongitude(),
940 // maxFoundX4, MaximumLatitude(), true, false, false);
941 // // Search for maxY between minlon and maxlon along minlat
942 // doSearch(MinimumLongitude(), MaximumLongitude(),
943 // maxFoundY3, MinimumLatitude(), false, false, false);
944 // // Search for maxY between minlon and maxlon along maxlat
945 // doSearch(MinimumLongitude(), MaximumLongitude(),
946 // maxFoundY4, MaximumLatitude(), false, false, false);
947
948 // // We've searched all possible maximums, go ahead and store the highest
949 // double maxFoundX5 = max(maxFoundX1, maxFoundX2);
950 // double maxFoundX6 = max(maxFoundX3, maxFoundX4);
951 // m_maximumX = max(maxFoundX5, maxFoundX6);
952
953 // double maxFoundY5 = max(maxFoundY1, maxFoundY2);
954 // double maxFoundY6 = max(maxFoundY3, maxFoundY4);
955 // m_maximumY = max(maxFoundY5, maxFoundY6);
956
957 // // Look along discontinuities for more extremes
958 // vector<double> specialLatCases = m_specialLatCases;
959 // for (unsigned int specialLatCase = 0;
960 // specialLatCase < specialLatCases.size();
961 // specialLatCase ++) {
962 // double minX, maxX, minY, maxY;
963
964 // // Search for minX between minlon and maxlon along latitude discontinuities
965 // doSearch(MinimumLongitude(), MaximumLongitude(),
966 // minX, specialLatCases[specialLatCase], true, false, true);
967 // // Search for minY between minlon and maxlon along latitude discontinuities
968 // doSearch(MinimumLongitude(), MaximumLongitude(),
969 // minY, specialLatCases[specialLatCase], false, false, true);
970 // // Search for maxX between minlon and maxlon along latitude discontinuities
971 // doSearch(MinimumLongitude(), MaximumLongitude(),
972 // maxX, specialLatCases[specialLatCase], true, false, false);
973 // // Search for maxX between minlon and maxlon along latitude discontinuities
974 // doSearch(MinimumLongitude(), MaximumLongitude(),
975 // maxY, specialLatCases[specialLatCase], false, false, false);
976
977 // m_minimumX = min(minX, m_minimumX);
978 // m_maximumX = max(maxX, m_maximumX);
979 // m_minimumY = min(minY, m_minimumY);
980 // m_maximumY = max(maxY, m_maximumY);
981 // }
982
983 // vector<double> specialLonCases = m_specialLonCases;
984 // for (unsigned int specialLonCase = 0;
985 // specialLonCase < specialLonCases.size();
986 // specialLonCase ++) {
987 // double minX, maxX, minY, maxY;
988
989 // // Search for minX between minlat and maxlat along longitude discontinuities
990 // doSearch(MinimumLatitude(), MaximumLatitude(),
991 // minX, specialLonCases[specialLonCase], true, true, true);
992 // // Search for minY between minlat and maxlat along longitude discontinuities
993 // doSearch(MinimumLatitude(), MaximumLatitude(),
994 // minY, specialLonCases[specialLonCase], false, true, true);
995 // // Search for maxX between minlat and maxlat along longitude discontinuities
996 // doSearch(MinimumLatitude(), MaximumLatitude(),
997 // maxX, specialLonCases[specialLonCase], true, true, false);
998 // // Search for maxY between minlat and maxlat along longitude discontinuities
999 // doSearch(MinimumLatitude(), MaximumLatitude(),
1000 // maxY, specialLonCases[specialLonCase], false, true, false);
1001
1002 // m_minimumX = min(minX, m_minimumX);
1003 // m_maximumX = max(maxX, m_maximumX);
1004 // m_minimumY = min(minY, m_minimumY);
1005 // m_maximumY = max(maxY, m_maximumY);
1006 // }
1007
1008 // m_specialLatCases.clear();
1009 // m_specialLonCases.clear();
1010
1011 // // Make sure everything is ordered
1012 // if (m_minimumX >= m_maximumX) return false;
1013 // if (m_minimumY >= m_maximumY) return false;
1014
1015 // // Return X/Y min/maxs
1016 // minX = m_minimumX;
1017 // maxX = m_maximumX;
1018 // minY = m_minimumY;
1019 // maxY = m_maximumY;
1020
1021 // return true;
1022 // }
1023
1061 // void Projection::doSearch(double minBorder, double maxBorder,
1062 // double &extremeVal, const double constBorder,
1063 // bool searchX, bool searchLongitude, bool findMin) {
1064 // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
1065 // return;
1066 // }
1067 // const double TOLERANCE = m_pixelResolution/2;
1068 // const int NUM_ATTEMPTS = (unsigned int)DBL_DIG; // It's unsafe to go past
1069 // // this precision
1070
1071 // double minBorderX, minBorderY, maxBorderX, maxBorderY;
1072 // int attempts = 0;
1073
1074 // do {
1075 // findExtreme(minBorder, maxBorder, minBorderX, minBorderY, maxBorderX,
1076 // maxBorderY, constBorder, searchX, searchLongitude, findMin);
1077 // if (minBorderX == Null && maxBorderX == Null
1078 // && minBorderY == Null && maxBorderY == Null ) {
1079 // attempts = NUM_ATTEMPTS;
1080 // continue;
1081 // }
1082 // attempts ++;
1083 // }
1084 // while ((fabs(minBorderX - maxBorderX) > TOLERANCE
1085 // || fabs(minBorderY - maxBorderY) > TOLERANCE)
1086 // && (attempts < NUM_ATTEMPTS));
1087 // // check both x and y distance in case symmetry of map
1088 // // For example, if minBorderX = maxBorderX but minBorderY = -maxBorderY,
1089 // // these points may not be close enough.
1090
1091 // if (attempts >= NUM_ATTEMPTS) {
1092 // // We zoomed in on a discontinuity because our range never shrank, this
1093 // // will need to be rechecked later.
1094 // // *min and max border should be nearly identical, so it doesn't matter
1095 // // which is used here
1096 // if (searchLongitude) {
1097 // m_specialLatCases.push_back(minBorder);
1098 // }
1099 // else {
1100 // m_specialLonCases.push_back(minBorder);
1101 // }
1102 // }
1103
1104 // // These values will always be accurate, even over a discontinuity
1105 // if (findMin) {
1106 // if (searchX) extremeVal = min(minBorderX, maxBorderX);
1107 // else extremeVal = min(minBorderY, maxBorderY);
1108 // }
1109 // else {
1110 // if (searchX) extremeVal = max(minBorderX, maxBorderX);
1111 // else extremeVal = max(minBorderY, maxBorderY);
1112 // }
1113 // return;
1114 // }
1115
1175 // void Projection::findExtreme(double &minBorder, double &maxBorder,
1176 // double &minBorderX, double &minBorderY,
1177 // double &maxBorderX, double &maxBorderY,
1178 // const double constBorder, bool searchX,
1179 // bool searchLongitude, bool findMin) {
1180 // if (minBorder == Null || maxBorder == Null || constBorder == Null) {
1181 // minBorderX = Null;
1182 // minBorderY = minBorderX;
1183 // minBorderX = minBorderX;
1184 // minBorderY = minBorderX;
1185 // return;
1186 // }
1187 // if (!searchLongitude && (fabs(fabs(constBorder) - 90.0) < DBL_EPSILON)) {
1188 // // it is impossible to search "along" a pole
1189 // setSearchGround(minBorder, constBorder, searchLongitude);
1190 // minBorderX = XCoord();
1191 // minBorderY = YCoord();
1192 // maxBorderX = minBorderX;
1193 // maxBorderY = minBorderY;
1194 // return;
1195 // }
1196 // // Always do 10 steps
1197 // const double STEP_SIZE = (maxBorder - minBorder) / 10.0;
1198 // const double LOOP_END = maxBorder + (STEP_SIZE / 2.0); // This ensures we do
1199 // // all of the steps
1200 // // properly
1201 // double currBorderVal = minBorder;
1202 // setSearchGround(minBorder, constBorder, searchLongitude);
1203
1204 // // this makes sure that the initial currBorderVal is valid before entering
1205 // // the loop below
1206 // if (!m_good){
1207 // // minBorder = currBorderVal+STEP_SIZE < LOOP_END until setGround is good?
1208 // // then, if still not good return?
1209 // while (!m_good && currBorderVal <= LOOP_END) {
1210 // currBorderVal+=STEP_SIZE;
1211 // if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1212 // currBorderVal = 90.0;
1213 // }
1214 // setSearchGround(currBorderVal, constBorder, searchLongitude);
1215 // }
1216 // if (!m_good) {
1217 // minBorderX = Null;
1218 // minBorderY = minBorderX;
1219 // minBorderX = minBorderX;
1220 // minBorderY = minBorderX;
1221 // return;
1222 // }
1223 // }
1224
1225 // // save the values of three consecutive steps from the minBorder towards
1226 // // the maxBorder along the constBorder. initialize these three border
1227 // // values (the non-constant lat or lon)
1228 // double border1 = currBorderVal;
1229 // double border2 = currBorderVal;
1230 // double border3 = currBorderVal;
1231
1232 // // save the coordinate (x or y) values that correspond to the first
1233 // // two borders that are being saved.
1234 // // initialize these two coordinate values (x or y)
1235 // double value1 = (searchX) ? XCoord() : YCoord();
1236 // double value2 = value1;
1237
1238 // // initialize the extreme coordinate value
1239 // // -- this is the largest coordinate value found so far
1240 // double extremeVal2 = value2;
1241
1242 // // initialize the extreme border values
1243 // // -- these are the borders on either side of the extreme coordinate value
1244 // double extremeBorder1 = minBorder;
1245 // double extremeBorder3 = minBorder;
1246
1247 // while (currBorderVal <= LOOP_END) {
1248
1249 // // this conditional was added to prevent trying to SetGround with an
1250 // // invalid latitude greater than 90 degrees. There is no need check for
1251 // // latitude less than -90 since we start at the minBorder (already
1252 // // assumed to be valid) and step forward toward (and possibly past)
1253 // // maxBorder
1254 // if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1255 // currBorderVal = 90.0;
1256 // }
1257
1258 // // update the current border value along constBorder
1259 // currBorderVal += STEP_SIZE;
1260 // setSearchGround(currBorderVal, constBorder, searchLongitude);
1261 // if (!m_good){
1262 // continue;
1263 // }
1264
1265 // // update the border and coordinate values
1266 // border3 = border2;
1267 // border2 = border1;
1268 // border1 = currBorderVal;
1269 // value2 = value1;
1270 // value1 = (searchX) ? XCoord() : YCoord();
1271
1272 // if ((findMin && value2 < extremeVal2)
1273 // || (!findMin && value2 > extremeVal2)) {
1274 // // Compare the coordinate value associated with the center border with
1275 // // the current extreme. If the updated coordinate value is more extreme
1276 // // (smaller or larger, depending on findMin), then we update the
1277 // // extremeVal and it's borders.
1278 // extremeVal2 = value2;
1279
1280 // extremeBorder3 = border3;
1281 // extremeBorder1 = border1;
1282 // }
1283 // }
1284
1285 // // update min/max border values to the values on either side of the most
1286 // // extreme coordinate found in this call to this method
1287
1288 // minBorder = extremeBorder3; // Border 3 is lagging and thus smaller
1289
1290 // // since the loop steps past the original maxBorder, we want to retain
1291 // // the original maxBorder value so we don't go outside of the original
1292 // // min/max range given
1293 // if (extremeBorder1 <= maxBorder ) {
1294 // maxBorder = extremeBorder1; // Border 1 is leading and thus larger
1295 // }
1296
1297 // // update minBorder coordinate values
1298 // setSearchGround(minBorder, constBorder, searchLongitude);
1299 // // if (!m_good){
1300 // // this should not happen since minBorder has already been verified in
1301 // // the while loop above
1302 // // }
1303
1304 // minBorderX = XCoord();
1305 // minBorderY = YCoord();
1306
1307 // // update maxBorder coordinate values
1308 // setSearchGround(maxBorder, constBorder, searchLongitude);
1309 // // if (!m_good){
1310 // // this should not happen since maxBorder has already been verified in
1311 // // the while loop above
1312 // // }
1313
1314 // maxBorderX = XCoord();
1315 // maxBorderY = YCoord();
1316 // return;
1317 // }
1318
1341 // void Projection::setSearchGround(const double variableBorder,
1342 // const double constBorder,
1343 // bool variableIsLat) {
1344 // if (variableBorder == Null || constBorder == Null) {
1345 // return;
1346 // }
1347 // double lat, lon;
1348 // if (variableIsLat) {
1349 // lat = variableBorder;
1350 // lon = constBorder;
1351 // }
1352 // else {
1353 // lat = constBorder;
1354 // lon = variableBorder;
1355 // }
1356 // SetGround(lat, lon);
1357 // return;
1358 // }
1359
1368 const Displacement &y) {
1369 PvlKeyword xKeyword("UpperLeftCornerX", toString(x.meters()), "meters");
1370 PvlKeyword yKeyword("UpperLeftCornerY", toString(y.meters()), "meters");
1371 m_mappingGrp.addKeyword(xKeyword,Pvl::Replace);
1372 m_mappingGrp.addKeyword(yKeyword,Pvl::Replace);
1373 }
1374} //end namespace isis
Displacement is a signed length, usually in meters.
double meters() const
Get the displacement in meters.
double m_y
This contains the rotated Y coordinate for a specific projection at the position indicated by m_latit...
Definition Projection.h:338
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:332
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition Projection.h:165
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
Definition Projection.h:165
WorldMapper * m_mapper
This points to a mapper passed into the SetWorldMapper method.
Definition Projection.h:291
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:325
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:343
void SetUpperLeftCorner(const Displacement &x, const Displacement &y)
This method is used to find the XY range for oblique aspect projections (non-polar projections) by "w...
bool m_groundRangeGood
Indicates if the ground range (min/max lat/lons) were read from the labels.
Definition Projection.h:312
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:299
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition Projection.h:316
Projection(Pvl &label)
Constructs an empty Projection object.
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition Projection.h:328
static QString ToHMS(double angle)
Converts the given angle (in degrees) to hours, minutes, seconds.
double m_minimumY
See minimumX description.
Definition Projection.h:326
bool m_sky
Indicates whether projection is sky or land.
Definition Projection.h:309
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:334
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:327
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.
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
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.
Namespace for the standard library.