7#include "TProjection.h"
20#include "Displacement.h"
22#include "IException.h"
25#include "NaifStatus.h"
28#include "PvlKeyword.h"
29#include "SpecialPixel.h"
31#include "WorldMapper.h"
106 QString msg =
"Projection failed. No target radii are available "
107 "through keywords [EquatorialRadius and PolarRadius] "
114 QString msg =
"Projection failed. Invalid value for keyword "
115 "[EquatorialRadius]. It must be greater than zero";
119 QString msg =
"Projection failed. Invalid value for keyword "
120 "[PolarRadius]. It must be greater than zero";
125 if ((QString)
m_mappingGrp[
"LatitudeType"] ==
"Planetographic") {
128 else if ((QString)
m_mappingGrp[
"LatitudeType"] ==
"Planetocentric") {
132 QString msg =
"Projection failed. Invalid value for keyword "
133 "[LatitudeType] must be "
134 "[Planetographic or Planetocentric]";
139 if ((QString)
m_mappingGrp[
"LongitudeDirection"] ==
"PositiveWest") {
142 else if ((QString)
m_mappingGrp[
"LongitudeDirection"] ==
"PositiveEast") {
146 QString msg =
"Projection failed. Invalid value for keyword "
147 "[LongitudeDirection] must be "
148 "[PositiveWest or PositiveEast]";
153 if ((QString)
m_mappingGrp[
"LongitudeDomain"] ==
"360") {
156 else if ((QString)
m_mappingGrp[
"LongitudeDomain"] ==
"180") {
160 QString msg =
"Projection failed. Invalid value for keyword "
161 "[LongitudeDomain] must be [180 or 360]";
177 QString msg =
"Projection failed. "
179 +
"] is outside the range of [-90:90]";
184 QString msg =
"Projection failed. "
186 +
"] is outside the range of [-90:90]";
191 QString msg =
"Projection failed. "
192 "[MinimumLatitude,MaximumLatitude] of ["
195 +
"properly ordered";
200 QString msg =
"Projection failed. "
201 "[MinimumLongitude,MaximumLongitude] of ["
204 +
"properly ordered";
220 QString msg =
"Projection failed. Invalid keyword value(s). "
222 +
" must be greater than or equal to [PolarRadius] = "
241 QString msg =
"Projection failed. Invalid label group [Mapping]";
261 if (!Projection::operator==(proj))
return false;
264 if (
PolarRadius() != tproj->PolarRadius())
return false;
327 if (latitude ==
Null) {
329 "Unable to calculate local radius. The given latitude value ["
330 +
toString(latitude) +
"] is invalid.",
336 if (a - c < DBL_EPSILON) {
340 double lat = latitude *
PI / 180.0;
341 return a * c / sqrt(pow(c * cos(lat), 2) + pow(a * sin(lat), 2));
435 double eRadius,
double pRadius) {
436 if (lat ==
Null || abs(lat) > 90.0) {
438 "Unable to convert to Planetocentric. The given latitude value ["
443 if (abs(mylat) < 90.0) {
445 mylat = atan(tan(mylat) * (pRadius / eRadius) *
446 (pRadius / eRadius));
481 double eRadius,
double pRadius) {
483 if (qFuzzyCompare(fabs(lat), 90.0)) {
486 if (lat ==
Null || fabs(lat) > 90.0) {
488 "Unable to convert to Planetographic. The given latitude value ["
493 if (fabs(mylat) < 90.0) {
495 mylat = atan(tan(mylat) * (eRadius / pRadius) *
496 (eRadius / pRadius));
510 return "Planetocentric";
551 "Unable to convert to PositiveEast. The given longitude value ["
562 else if (domain == 180) {
566 QString msg =
"Unable to convert longitude. Domain [" +
toString(domain)
567 +
"] is not 180 or 360.";
590 "Unable to convert to PositiveWest. The given longitude value ["
601 else if (domain == 180) {
605 QString msg =
"Unable to convert longitude. Domain [" +
toString(domain)
606 +
"] is not 180 or 360.";
622 return "PositiveWest";
660 "Unable to convert to 180 degree domain. The given longitude value ["
678 "Unable to convert to 360 degree domain. The given longitude value ["
684 if ( (lon < 0.0 || lon > 360.0) &&
685 !qFuzzyCompare(lon, 0.0) && !qFuzzyCompare(lon, 360.0)) {
994 double &minY,
double &maxY) {
1064 if (latitude ==
Null || longitude ==
Null) {
1105 if (adjustedMinLon > adjustedMaxLon) {
1106 if (adjustedLon > adjustedMinLon) {
1109 adjustedMinLon -= 360;
1113 if (qFuzzyCompare(maxLon - minLon, 360.0)) {
1116 else if (adjustedMinLon <= adjustedLon && adjustedLon <= adjustedMaxLon) {
1196 double &minY,
double &maxY) {
1208 double minFoundX1, minFoundX2;
1209 double minFoundY1, minFoundY2;
1225 double minFoundX3, minFoundX4;
1226 double minFoundY3, minFoundY4;
1242 double minFoundX5 = min(minFoundX1, minFoundX2);
1243 double minFoundX6 = min(minFoundX3, minFoundX4);
1246 double minFoundY5 = min(minFoundY1, minFoundY2);
1247 double minFoundY6 = min(minFoundY3, minFoundY4);
1251 double maxFoundX1, maxFoundX2;
1252 double maxFoundY1, maxFoundY2;
1268 double maxFoundX3, maxFoundX4;
1269 double maxFoundY3, maxFoundY4;
1285 double maxFoundX5 = max(maxFoundX1, maxFoundX2);
1286 double maxFoundX6 = max(maxFoundX3, maxFoundX4);
1289 double maxFoundY5 = max(maxFoundY1, maxFoundY2);
1290 double maxFoundY6 = max(maxFoundY3, maxFoundY4);
1295 for (
unsigned int specialLatCase = 0;
1296 specialLatCase < specialLatCases.size();
1297 specialLatCase ++) {
1298 double minX, maxX, minY, maxY;
1302 minX, specialLatCases[specialLatCase],
true,
false,
true);
1305 minY, specialLatCases[specialLatCase],
false,
false,
true);
1308 maxX, specialLatCases[specialLatCase],
true,
false,
false);
1311 maxY, specialLatCases[specialLatCase],
false,
false,
false);
1320 for (
unsigned int specialLonCase = 0;
1321 specialLonCase < specialLonCases.size();
1322 specialLonCase ++) {
1323 double minX, maxX, minY, maxY;
1327 minX, specialLonCases[specialLonCase],
true,
true,
true);
1330 minY, specialLonCases[specialLonCase],
false,
true,
true);
1333 maxX, specialLonCases[specialLonCase],
true,
true,
false);
1336 maxY, specialLonCases[specialLonCase],
false,
true,
false);
1398 double &extremeVal,
const double constBorder,
1399 bool searchX,
bool searchLongitude,
bool findMin) {
1400 if (minBorder ==
Null || maxBorder ==
Null || constBorder ==
Null) {
1404 const int NUM_ATTEMPTS = (
unsigned int)DBL_DIG;
1407 double minBorderX, minBorderY, maxBorderX, maxBorderY;
1411 findExtreme(minBorder, maxBorder, minBorderX, minBorderY, maxBorderX,
1412 maxBorderY, constBorder, searchX, searchLongitude, findMin);
1413 if (minBorderX ==
Null && maxBorderX ==
Null
1414 && minBorderY ==
Null && maxBorderY ==
Null ) {
1415 attempts = NUM_ATTEMPTS;
1420 while ((fabs(minBorderX - maxBorderX) > TOLERANCE
1421 || fabs(minBorderY - maxBorderY) > TOLERANCE)
1422 && (attempts < NUM_ATTEMPTS));
1427 if (attempts >= NUM_ATTEMPTS) {
1432 if (searchLongitude) {
1442 if (searchX) extremeVal = min(minBorderX, maxBorderX);
1443 else extremeVal = min(minBorderY, maxBorderY);
1446 if (searchX) extremeVal = max(minBorderX, maxBorderX);
1447 else extremeVal = max(minBorderY, maxBorderY);
1512 double &minBorderX,
double &minBorderY,
1513 double &maxBorderX,
double &maxBorderY,
1514 const double constBorder,
bool searchX,
1515 bool searchLongitude,
bool findMin) {
1516 if (minBorder ==
Null || maxBorder ==
Null || constBorder ==
Null) {
1518 minBorderY = minBorderX;
1519 minBorderY = minBorderX;
1522 if (!searchLongitude && (fabs(fabs(constBorder) - 90.0) < DBL_EPSILON)) {
1527 maxBorderY = minBorderY;
1531 const double STEP_SIZE = (maxBorder - minBorder) / 10.0;
1532 const double LOOP_END = maxBorder + (STEP_SIZE / 2.0);
1535 double currBorderVal = minBorder;
1543 while (!
m_good && currBorderVal <= LOOP_END) {
1544 currBorderVal+=STEP_SIZE;
1545 if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1546 currBorderVal = 90.0;
1560 double border1 = currBorderVal;
1561 double border2 = currBorderVal;
1562 double border3 = currBorderVal;
1568 double value2 = value1;
1572 double extremeVal2 = value2;
1576 double extremeBorder1 = minBorder;
1577 double extremeBorder3 = minBorder;
1579 while (currBorderVal <= LOOP_END) {
1586 if (searchLongitude && (currBorderVal - 90.0 > DBL_EPSILON)) {
1587 currBorderVal = 90.0;
1591 currBorderVal += STEP_SIZE;
1600 border1 = currBorderVal;
1604 if ((findMin && value2 < extremeVal2)
1605 || (!findMin && value2 > extremeVal2)) {
1610 extremeVal2 = value2;
1612 extremeBorder3 = border3;
1613 extremeBorder1 = border1;
1620 minBorder = extremeBorder3;
1625 if (extremeBorder1 <= maxBorder ) {
1626 maxBorder = extremeBorder1;
1674 const double constBorder,
1675 bool variableIsLat) {
1676 if (variableBorder ==
Null || constBorder ==
Null) {
1680 if (variableIsLat) {
1681 lat = variableBorder;
1686 lon = variableBorder;
1702 keyNames <<
"TargetName" <<
"ProjectionName" <<
"EquatorialRadius" <<
"PolarRadius"
1703 <<
"LatitudeType" <<
"LongitudeDirection" <<
"LongitudeDomain"
1704 <<
"PixelResolution" <<
"Scale" <<
"UpperLeftCornerX" <<
"UpperLeftCornerY"
1705 <<
"MinimumLatitude" <<
"MaximumLatitude" <<
"MinimumLongitude" <<
"MaximumLongitude"
1708 foreach (QString keyName, keyNames) {
1772 QString msg =
"Snyder's q variable should only be computed for "
1773 "ellipsoidal projections.";
1778 * (sinPhi / (1 - eSinPhi * eSinPhi)
1779 - 1 / (2 *
m_eccentricity) * log( (1 - eSinPhi) / (1 + eSinPhi) ));
1804 double localPhi =
HALFPI - 2.0 * atan(t);
1806 double difference = DBL_MAX;
1813 const int MAX_ITERATIONS = 45;
1815 while ((iteration < MAX_ITERATIONS) && (difference > 0.0000000001)) {
1816 double eccTimesSinphi =
Eccentricity() * sin(localPhi);
1818 2.0 * atan(t * pow((1.0 - eccTimesSinphi) /
1819 (1.0 + eccTimesSinphi), halfEcc));
1820 difference = fabs(newPhi - localPhi);
1825 if (iteration >= MAX_ITERATIONS) {
1826 QString msg =
"Failed to converge in TProjection::phi2Compute()";
1849 double denominator = sqrt(1.0 - eccTimesSinphi * eccTimesSinphi);
1850 return cosphi / denominator;
1871 if ((
HALFPI) - fabs(phi) < DBL_EPSILON)
return 0.0;
1874 double denominator = pow((1.0 - eccTimesSinphi) /
1875 (1.0 + eccTimesSinphi),
1877 return tan(0.5 * (
HALFPI - phi)) / denominator;
1895 return sqrt(pow(onePlusEcc, onePlusEcc) *
1896 pow(oneMinusEcc, oneMinusEcc));
double degrees() const
Get the angle in units of Degrees.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
@ Unknown
A type of error that cannot be classified as any of the other error types.
This class is designed to encapsulate the concept of a Longitude.
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.
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
WorldMapper * m_mapper
This points to a mapper passed into the SetWorldMapper method.
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround,...
double m_maximumX
See minimumX description.
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.
double PixelResolution() const
Returns the pixel resolution value from the PVL mapping group in meters/pixel.
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.
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
PvlGroup m_mappingGrp
Mapping group that created this projection.
double m_minimumY
See minimumX description.
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.
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.
Container for cube-like labels.
Base class for Map TProjections.
double m_longitude
This contains the currently set longitude value.
virtual bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType,...
bool xyRangeOblique(double &minX, double &maxX, double &minY, double &maxY)
This method is used to find the XY range for oblique aspect projections (non-polar projections) by "w...
bool SetUnboundUniversalGround(const double coord1, const double coord2)
This method is used to set the latitude/longitude.
bool IsPlanetocentric() const
This indicates if the latitude type is planetocentric (as opposed to planetographic).
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
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_polarRadius
Polar radius of the target.
std::vector< double > m_specialLatCases
Constant Latitudes that intersect a discontinuity.
double m_maximumLongitude
Contains the maximum longitude for the entire ground range.
static double To180Domain(const double lon)
This method converts a longitude into the -180 to 180 domain.
double m_equatorialRadius
Polar radius of the target.
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
virtual double MaximumLatitude() const
This returns the maximum latitude of the area of interest.
virtual ~TProjection()
Destroys the TProjection object.
void findExtreme(double &minBorder, double &maxBorder, double &minBorderX, double &minBorderY, double &maxBorderX, double &maxBorderY, const double constBorder, bool searchX, bool searchLongitude, bool findMin)
Searches for extreme (min/max/discontinuity) coordinate values across latitudes/longitudes.
double LocalRadius() const
This method returns the local radius in meters at the current latitude position.
virtual bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
int m_longitudeDomain
This integer is either 180 or 360 and is read from the labels.
double mCompute(const double sinphi, const double cosphi) const
A convience method to compute Snyder's m equation (14-15) for a given latitude, .
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
bool Has180Domain() const
This indicates if the longitude domain is -180 to 180 (as opposed to 0 to 360).
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...
std::vector< double > m_specialLonCases
Constant Longitudes that intersect a discontinuity.
void setSearchGround(const double variableBorder, const double constBorder, bool variableIsLat)
This function sets the ground for the given border values.
virtual double MinimumLongitude() const
This returns the minimum longitude of the area of interest.
virtual double UniversalLongitude()
This returns a universal longitude (positive east in 0 to 360 domain).
double PolarRadius() const
This returns the polar radius of the target.
bool inLongitudeRange(double longitude)
Determine whether the given longitude is within the range of the MinimumLongitude and MaximumLongitud...
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method.
double Eccentricity() const
This returns the eccentricity of the target,.
bool IsPositiveWest() const
This indicates if the longitude direction type is positive east (as opposed to postive west).
QString LongitudeDirectionString() const
This method returns the longitude direction as a string.
bool inLatitudeRange(double latitude)
Determine whether the given latitude is within the range of the MinimumLatitude and MaximumLatitude r...
virtual PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
double m_eccentricity
The eccentricity of the target body.
double qCompute(const double sinPhi) const
A convience method to compute Snyder's q equation (3-12) for a given latitude, .
virtual bool operator==(const Projection &proj)
This method determines whether two map projection objects are equal by comparing the equatorial radiu...
double phi2Compute(const double t) const
A convience method to compute latitude angle phi2 given small t, from Syder's recursive equation (7-9...
double m_minimumLongitude
Contains the minimum longitude for the entire ground range.
void doSearch(double minBorder, double maxBorder, double &extremeVal, const double constBorder, bool searchX, bool searchLongitude, bool findMin)
This method searches for extreme (min/max/discontinuity) coordinate values along the constBorder line...
double e4Compute() const
A convience method to compute.
double tCompute(const double phi, const double sinphi) const
A convience method to compute Snyder's t equation (15-9) for a given latitude, .
@ PositiveWest
Longitude values increase in the westerly direction.
@ PositiveEast
Longitude values increase in the easterly direction.
double m_maximumLatitude
Contains the maximum latitude for the entire ground range.
virtual double Latitude() const
This returns a latitude with correct latitude type as specified in the label object.
static double ToPositiveWest(const double lon, const int domain)
This method converts a longitude into the positive west direction.
static double To360Domain(const double lon)
This method converts a longitude into the 0 to 360 domain.
TProjection(Pvl &label)
Constructs an empty TProjection object.
QString LongitudeDomainString() const
This method returns the longitude domain as a string.
bool IsPlanetographic() const
This indicates if the latitude type is planetographic (as opposed to planetocentric).
virtual bool IsEquatorialCylindrical()
This method returns true if the projection is equatorial cylindrical.
QString LatitudeTypeString() const
This method returns the latitude type as a string.
bool Has360Domain() const
This indicates if the longitude domain is 0 to 360 (as opposed to -180 to 180).
@ Planetocentric
Latitudes are measured as the angle from the equatorial plane to the plane through the center of the ...
@ Planetographic
Latitudes are measured as the angle from the equatorial plane to the normal to the surface of the pla...
virtual double MinimumLatitude() const
This returns the minimum latitude of the area of interest.
LatitudeType m_latitudeType
An enumerated type indicating the LatitudeType read from the labels.
virtual double MaximumLongitude() const
This returns the maximum longitude of the area of interest.
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
static double ToPositiveEast(const double lon, const int domain)
This method converts a longitude into the positive east direction.
virtual double UniversalLatitude()
This returns a universal latitude (planetocentric).
double EquatorialRadius() const
This returns the equatorial radius of the target.
bool IsPositiveEast() const
This indicates if the longitude direction type is positive west (as opposed to postive east).
double Scale() const
This method returns the scale for mapping world coordinates into projection coordinates.
virtual double Longitude() const
This returns a longitude with correct longitude direction and domain as specified in the label object...
double ToPlanetographic(const double lat) const
This method converts a planetocentric latitude to a planetographic latitude.
double m_latitude
This contains the currently set latitude value.
virtual double TrueScaleLatitude() const
This method returns the latitude of true scale.
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
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.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
const double Null
Value for an Isis Null pixel.
const double HALFPI
The mathematical constant PI/2.
const double PI
The mathematical constant PI.
Namespace for the standard library.