Isis 3 Programmer Reference
PolarStereographic.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "PolarStereographic.h"
8
9#include <cmath>
10#include <cfloat>
11#include <iostream>
12
13#include "Constants.h"
14#include "IException.h"
15#include "TProjection.h"
16#include "Pvl.h"
17#include "PvlGroup.h"
18#include "PvlKeyword.h"
19
20using namespace std;
21namespace Isis {
42 PolarStereographic::PolarStereographic(Pvl &label, bool allowDefaults) :
43 TProjection::TProjection(label) {
44 try {
45 // Try to read the mapping group
46 PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
47
48 // Compute and write the default center longitude if allowed and
49 // necessary
50 if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
51 double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
52 mapGroup += PvlKeyword("CenterLongitude", toString(lon));
53 }
54
55 // Compute and write the default center latitude if allowed and
56 // necessary
57 if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
58 double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
59 if (lat > 0.0) {
60 mapGroup += PvlKeyword("CenterLatitude", toString(90.0));
61 }
62 else {
63 mapGroup += PvlKeyword("CenterLatitude", toString(-90.0));
64 }
65 }
66
67 // Get the center longitude, convert to radians and adjust for longitude
68 // direction
69 m_centerLongitude = mapGroup["CenterLongitude"];
70 m_centerLongitude *= PI / 180.0;
72
73 // Get the center latitude, make sure it is ographic, and convert to
74 // radians.
75 m_centerLatitude = mapGroup["CenterLatitude"];
76 if (m_centerLatitude == 0) {
77 QString msg = "Invalid value for keyword [CenterLatitude] in map file.";
78 msg += " CenterLatitude cannot equal 0.0";
79 throw IException(IException::User, msg, _FILEINFO_);
80 }
81 if (IsPlanetocentric()) {
83 }
84 m_centerLatitude *= PI / 180.0;
85
86 // Compute some constants
87 m_e4 = e4Compute();
88 m_signFactor = 1.0;
89 if (m_centerLatitude < 0.0) m_signFactor = -1.0;
90
91 if ((HALFPI - fabs(m_centerLatitude)) > DBL_EPSILON) {
92 m_poleFlag = true; // We are not at a pole
93 double phi = m_signFactor * m_centerLatitude;
94 double sinphi = sin(phi);
95 double cosphi = cos(phi);
96 m_m = mCompute(sinphi, cosphi);
97 m_t = tCompute(phi, sinphi);
98 if (fabs(m_t) < DBL_EPSILON) m_poleFlag = false;
99 }
100 else {
101 m_poleFlag = false; // Implies we are at a pole
102 m_m = 0;
103 m_t = 0;
104 }
105 }
106 catch(IException &e) {
107 QString message = "Invalid label group [Mapping]";
108 throw IException(e, IException::Unknown, message, _FILEINFO_);
109 }
110 }
111
112
116
117
127 if (!Projection::operator==(proj)) return false;
128 // dont do the below it is a recusive plunge
129 // if (Projection::operator!=(proj)) return false;
130 PolarStereographic *pola = (PolarStereographic *) &proj;
131 if (pola->m_centerLongitude != m_centerLongitude) return false;
132 if (pola->m_centerLatitude != m_centerLatitude) return false;
133 return true;
134 }
135
136
142 QString PolarStereographic::Name() const {
143 return "PolarStereographic";
144 }
145
146
154 return "1.0";
155 }
156
157
167 return m_centerLatitude * 180.0 / PI;
168 }
169
170
183 bool PolarStereographic::SetGround(const double lat, const double lon) {
184 // Fix up longitude
185 m_longitude = lon;
186 double lonRadians = lon * PI / 180.0;
187 if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0;
188
189 // Now do latitude ... it must be planetographic
190 m_latitude = lat;
191 double latRadians = lat;
192 if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians);
193 latRadians = latRadians * PI / 180.0;
194
195 // Compute easting and northing
196 double lamda = m_signFactor * (lonRadians - m_centerLongitude);
197 double phi = m_signFactor * latRadians;
198 double sinphi = sin(phi);
199 double t = tCompute(phi, sinphi);
200
201 double dist;
202 if (m_poleFlag) {
203 dist = m_equatorialRadius * m_m * t / m_t;
204 }
205 else {
206 dist = m_equatorialRadius * 2.0 * t / m_e4;
207 }
208
209 double x = m_signFactor * dist * sin(lamda);
210 double y = -(m_signFactor * dist * cos(lamda));
211 SetComputedXY(x, y);
212
213 m_good = true;
214
215 //So we don't project the wrong pole.
216 if (qFuzzyCompare(lat * m_signFactor, -90.0))
217 m_good = false;
218
219 return m_good;
220 }
221
222
236 bool PolarStereographic::SetCoordinate(const double x, const double y) {
237 // Save the coordinate
238 SetXY(x, y);
239
240 double east = m_signFactor * GetX();
241 double north = m_signFactor * GetY();
242 double dist = sqrt(east * east + north * north);
243
244 double t;
245 if (m_poleFlag) {
246 t = dist * m_t / (m_m * m_equatorialRadius); // Snyder eqn (21-40)
247 }
248 else {
249 t = dist * m_e4 / (2.0 * m_equatorialRadius); //Snyder eqn (24-39)
250 //when latitude of true scale is North Polar
251 }
252
253 // Compute the latitude
254 double phi = phi2Compute(t);
255 m_latitude = m_signFactor * phi;
256
257 if (fabs(m_latitude) > HALFPI) {
258 QString msg = "X,Y causes latitude to be outside [-90,90] "
259 "in PolarStereographic Class";
260 throw IException(IException::Programmer, msg, _FILEINFO_);
261 }
262
263 // Compute the longitude
264 if (dist == 0.0) {
266 }
267 else {
268 m_longitude = m_signFactor * atan2(east, -north) + m_centerLongitude;
269 }
270
271 // Cleanup the longitude
272 m_longitude *= 180.0 / PI;
276
277 // Cleanup the latitude
278 m_latitude *= 180.0 / PI;
280
281 m_good = true;
282 return m_good;
283 }
284
285
309 bool PolarStereographic::XYRange(double &minX, double &maxX,
310 double &minY, double &maxY) {
311 // Check the corners of the lat/lon range
316
317 // Find the closest longitude >= to the minimum longitude that is offset
318 // from the center longitude by a multiple of 90.
319 double lon1 = m_centerLongitude * 180.0 / PI;
320 if (m_longitudeDirection == PositiveWest) lon1 *= -1.0;
321 while(lon1 > m_minimumLongitude) lon1 -= 90.0;
322 while(lon1 < m_minimumLongitude) lon1 += 90.0;
323
324 while(lon1 <= m_maximumLongitude) {
327 lon1 += 90.0;
328 }
329
330 // Make sure everything is ordered
331 if (m_minimumX >= m_maximumX) return false;
332 if (m_minimumY >= m_maximumY) return false;
333
334 // Return X/Y min/maxs
335 minX = m_minimumX;
336 maxX = m_maximumX;
337 minY = m_minimumY;
338 maxY = m_maximumY;
339 return true;
340 }
341
342
349 PvlGroup mapping = TProjection::Mapping();
350
351 mapping += m_mappingGrp["CenterLatitude"];
352 mapping += m_mappingGrp["CenterLongitude"];
353
354 return mapping;
355 }
356
357
365
366 mapping += m_mappingGrp["CenterLatitude"];
367
368 return mapping;
369 }
370
371
379
380 mapping += m_mappingGrp["CenterLongitude"];
381
382 return mapping;
383 }
384}
385
386
401extern "C" Isis::Projection *PolarStereographicPlugin(Isis::Pvl &lab,
402 bool allowDefaults) {
403 return new Isis::PolarStereographic(lab, allowDefaults);
404}
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
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Stereographic Map Projection for Polar Aspect.
PvlGroup Mapping()
This function returns the keywords that this projection uses.
QString Name() const
Returns the name of the map projection, "PolarStereographic".
~PolarStereographic()
Destroys the PolarStereographic object.
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.
double TrueScaleLatitude() const
Returns the latitude of true scale.
double m_t
Snyder's t-value from equation (15-19).
double m_signFactor
If the center latitude is positive, the sign factor is 1.
double m_centerLatitude
The center latitude for the map projection.
double m_m
Snyder's m-value from equation (14-15).
double m_poleFlag
Indicates whether the center latitude is at a pole.
bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType,...
double m_e4
Convenience variable for calculations.
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...
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
QString Version() const
Returns the version of the map projection.
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
PolarStereographic(Pvl &label, bool allowDefaults=false)
Constructs a PolarStereographic object.
double m_centerLongitude
The center longitude for the map projection.
Base class for Map Projections.
Definition Projection.h:155
double m_maximumX
See minimumX description.
Definition Projection.h:326
double GetX() const
Calculates the unrotated form of current x value.
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
double GetY() const
Calculates the unrotated form of the current y value.
void SetXY(double x, double y)
This protected method is a helper for derived classes.
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.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
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 TProjections.
double m_longitude
This contains the currently set longitude value.
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.
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.
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.
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method.
virtual PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
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.
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.
double m_maximumLatitude
Contains the maximum latitude for the entire ground range.
static double To360Domain(const double lon)
This method converts a longitude into the 0 to 360 domain.
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
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.
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 HALFPI
The mathematical constant PI/2.
Definition Constants.h:41
const double PI
The mathematical constant PI.
Definition Constants.h:40
Namespace for the standard library.