File failed to load: https://isis.astrogeology.usgs.gov/6.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
Orthographic.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Orthographic.h"
8 
9 #include <cfloat>
10 #include <cmath>
11 #include <iomanip>
12 
13 #include <QDebug>
14 #include "Constants.h"
15 #include "IException.h"
16 #include "TProjection.h"
17 #include "Pvl.h"
18 #include "PvlGroup.h"
19 #include "PvlKeyword.h"
20 
21 using namespace std;
22 namespace Isis {
39  Orthographic::Orthographic(Pvl &label, bool allowDefaults) :
40  TProjection::TProjection(label) {
41  try {
42  // Try to read the mapping group
43  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
44 
45  /*
46  * Compute and write the default center longitude if allowed and
47  * necessary.
48  */
49  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
50  double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
51  mapGroup += PvlKeyword("CenterLongitude", toString(lon));
52  }
53 
54  /*
55  * Compute and write the default center latitude if allowed and
56  * necessary
57  */
58  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
59  double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
60  mapGroup += PvlKeyword("CenterLatitude", toString(lat));
61  }
62 
63  // Get the center longitude & latitude
64  m_centerLongitude = mapGroup["CenterLongitude"];
65  m_centerLatitude = mapGroup["CenterLatitude"];
66  if (IsPlanetocentric()) {
68  }
69 
70  //Restrict center longitude to avoid converting between domains.
71  if ((m_centerLongitude < -360.0) || (m_centerLongitude > 360.0)) {
72  QString msg = "The center longitude cannot exceed [-360, 360]. "
73  "[" + toString(m_centerLongitude) + "] is not valid";
74  throw IException(IException::User, msg, _FILEINFO_);
75  }
76 
77  // convert to radians, adjust for longitude direction
78  m_centerLongitude *= PI / 180.0;
79  m_centerLatitude *= PI / 180.0;
81 
82  // Calculate sine & cosine of center latitude
85 
86  /*
87  * This projection has a limited lat/lon range (can't do the world)
88  * So let's make sure that our lat/lon range is properly restricted!
89  * The equation: m_sinph0 * sinphi + m_cosph0 * cosphi * coslon tells us
90  * if we are inside of the projection.
91  *
92  * m_sinph0 = sin(center lat)
93  * sinphi = sin(lat)
94  * m_cosph0 = cos(center lat)
95  * cosphi = cos(lat)
96  * coslon = cos(lon - centerLon)
97  *
98  * Let's apply this equation at the extremes to minimize our lat/lon range
99  */
100  double sinphi, cosphi, coslon;
101 
102  /* Can we project at the minlat, center lon? If not, then we should move
103  * up the min lat to be inside the image.
104  */
105  sinphi = sin(m_minimumLatitude * PI / 180.0);
106  cosphi = cos(m_minimumLatitude * PI / 180.0);
107  coslon = 1.0; // at lon=centerLon: cos(lon-centerLon) = cos(0) = 1
108  if (m_sinph0 * sinphi + m_cosph0 * cosphi * coslon < 1E-10) {
109  /*solve for x: a * sin(x) + b * cos(x) * 1 = 0
110  * a * sin(x) + b * cos(x) = 0
111  * a * sin(x) = - b * cos(x)
112  * -(a * sin(x)) / b = cos(x)
113  * -(a / b) = cos(x) / sin(x)
114  * -(b / a) = sin(x) / cos(x)
115  * -(b / a) = tan(x)
116  * arctan(-(b / a)) = x
117  * arctan(-(m_cosph0 / m_sinph0)) = x
118  */
119  double newMin = atan2(- m_cosph0, m_sinph0) * 180.0 / PI;
120  if (newMin > m_minimumLatitude) {
121  m_minimumLatitude = newMin;
122  } // else something else is off (i.e. longitude range)
123  }
124 
125  //Restrict the longitude range to 360 degrees to simplify comparisons.
126  if ((m_maximumLongitude - m_minimumLongitude) > 360.0) {
127  QString msg = "The longitude range cannot exceed 360 degrees.";
128  throw IException(IException::User, msg, _FILEINFO_);
129  }
130 
131  sinphi = sin(m_minimumLatitude * PI / 180.0);
132  cosphi = cos(m_minimumLatitude * PI / 180.0);
133 
134  /* Can we project at the maxlat, center lon? If not, then we should move
135  * down the max lat to be inside the image.
136  */
137  sinphi = sin(m_maximumLatitude * PI / 180.0);
138  cosphi = cos(m_maximumLatitude * PI / 180.0);
139  coslon = 1.0; // at lon=centerLon: cos(lon-centerLon) = cos(0) = 1
140  if (m_sinph0 * sinphi + m_cosph0 * cosphi * coslon < 1E-10) {
141  // see above equations for latitude
142  double newMax = atan2(- m_cosph0, m_sinph0) * 180.8 / PI;
143  if (newMax < m_maximumLatitude && newMax > m_minimumLatitude) {
144  m_maximumLatitude = newMax;
145  } // else something else is off (i.e. longitude range)
146  }
147  }
148  catch(IException &e) {
149  QString message = "Invalid label group [Mapping]";
150  throw IException(e, IException::Io, message, _FILEINFO_);
151  }
152  }
153 
156  }
157 
167  if (!Projection::operator==(proj)) return false;
168  // dont do the below it is a recusive plunge
169  Orthographic *ortho = (Orthographic *) &proj;
170  if ((ortho->m_centerLongitude != m_centerLongitude) ||
171  (ortho->m_centerLatitude != m_centerLatitude)) return false;
172  return true;
173  }
174 
180  QString Orthographic::Name() const {
181  return "Orthographic";
182  }
183 
190  QString Orthographic::Version() const {
191  return "1.0";
192  }
193 
204  //Snyder pg. 45
205  // no distortion at center of projection (centerLatitude, centerLongitude)
206  return m_centerLatitude * 180.0 / PI;// Change to true scale
207  }
208 
221  bool Orthographic::SetGround(const double lat, const double lon) {
222  // Convert longitude to radians & clean up
223  m_longitude = lon;
224  double lonRadians = lon * PI / 180.0;
225  if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0;
226 
227  // Now convert latitude to radians & clean up ... it must be planetographic
228  m_latitude = lat;
229  double latRadians = lat;
230  if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians);
231  latRadians *= PI / 180.0;
232 
233  // Compute helper variables
234  double deltaLon = (lonRadians - m_centerLongitude);
235  double sinphi = sin(latRadians);
236  double cosphi = cos(latRadians);
237  double coslon = cos(deltaLon);
238 
239  // Lat/Lon cannot be projected
240  double g = m_sinph0 * sinphi + m_cosph0 * cosphi * coslon;
241  if ((g <= 0.0) && (fabs(g) > 1.0e-10)) {
242  m_good = false;
243  return m_good;
244  }
245 
246  // Compute the coordinates
247  double x = m_equatorialRadius * cosphi * sin(deltaLon);
248  double y = m_equatorialRadius * (m_cosph0 * sinphi - m_sinph0 * cosphi * coslon);
249 
250  SetComputedXY(x, y);
251  m_good = true;
252  return m_good;
253  }
254 
268  bool Orthographic::SetCoordinate(const double x, const double y) {
269  // Save the coordinate
270  SetXY(x, y);
271 
272  // Declare instance variables and calculate rho
273  double rho, con, z, sinz, cosz;
274  const double epsilon = 1.0e-10;
275  rho = sqrt(GetX() * GetX() + GetY() * GetY());
276 
277  /* Error calculating rho - should be less than equatorial radius.
278  *
279  * This if statement included "fabs(rho - m_equatorialRadius) < 1E-10 ||"
280  * to make the method more stable for limbs but this caused a false failure
281  * for some images when rho == m_equatorialRadius.
282  */
283  if (rho > m_equatorialRadius) {
284  m_good = false;
285  return m_good;
286  }
287 
288  // Calculate the latitude and longitude
290  if (fabs(rho) <= epsilon) {
292  }
293  else {
294  con = rho / m_equatorialRadius;
295  if (con > 1.0) con = 1.0;
296  if (con < -1.0) con = -1.0;
297  z = asin(con);
298  sinz = sin(z);
299  cosz = cos(z);
300  con = cosz * m_sinph0 + GetY() * sinz * m_cosph0 / rho;
301  if (con > 1.0) con = 1.0;
302  if (con < -1.0) con = -1.0;
303  m_latitude = asin(con);
304  con = fabs(m_centerLatitude) - HALFPI;
305  if (fabs(con) <= epsilon) {
306  if (m_centerLatitude >= 0.0) {
307  m_longitude += atan2(GetX(), -GetY());
308  }
309  else {
310  m_longitude += atan2(GetX(), GetY());
311  }
312  }
313  else {
314  con = cosz - m_sinph0 * sin(m_latitude);
315  if ((fabs(con) >= epsilon) || (fabs(GetX()) >= epsilon)) {
316  m_longitude += atan2(GetX() * sinz * m_cosph0, con * rho);
317  }
318  }
319  }
320 
321  // Convert to degrees
322  m_latitude *= 180.0 / PI;
323  m_longitude *= 180.0 / PI;
324 
325  // Cleanup the longitude
327 
328  /*
329  * When the longitude range is 0 to 360 and the seam is within the 180 displayable degrees,
330  * the longitude needs to be converted to its 360 lon domain counterpart. However, if the
331  * range is shifted out of the 0 to 360 range, the conversion is not necessary. For example,
332  * if the specified range is -180 to 180 and the clon is 0, the lon -90 is valid but will
333  * be converted to 270, which does not work with the comparison. The same idea applies if
334  * the range is 200 - 500 and the clon is 360. We want to display 270 to 450 (270 - 360 and
335  * 0 - 90). However, if 450 is converted to the 360 domain it becomes 90 which is no longer
336  * within the original 200 to 500 range.
337  */
338  // These need to be done for circular type projections
341 
342  // Cleanup the latitude
343  if (IsPlanetocentric())
345 
346  m_good = true;
347  return m_good;
348  }
349 
373  bool Orthographic::XYRange(double &minX, double &maxX,
374  double &minY, double &maxY) {
375  double lat, lon;
376 
377  //Restrict lon range to be between -360 and 360
378  double adjustedLon;
379  double adjustedMinLon = To360Domain(MinimumLongitude());
380  double adjustedMaxLon = To360Domain(MaximumLongitude());
381  bool correctedMinLon = false;
382 
383  if (adjustedMinLon >= adjustedMaxLon) {
384  adjustedMinLon -= 360;
385  correctedMinLon = true;
386  }
387 
388  // Check the corners of the lat/lon range
393 
394  // Walk top and bottom edges
395  for (lat = m_minimumLatitude; lat <= m_maximumLatitude; lat += 0.01) {
396  lon = m_minimumLongitude;
397  XYRangeCheck(lat, lon);
398 
399  lon = m_maximumLongitude;
400  XYRangeCheck(lat, lon);
401  }
402 
403  // Walk left and right edges
404  for (lon = m_minimumLongitude; lon <= m_maximumLongitude; lon += 0.01) {
405  lat = m_minimumLatitude;
406  XYRangeCheck(lat, lon);
407 
408  lat = m_maximumLatitude;
409  XYRangeCheck(lat, lon);
410  }
411 
412  /*
413  * Walk the limb.
414  * When the pair is valid and within the correct range, reassign min/max x/y.
415  *
416  * , - ~ ~ ~ - ,
417  * , ' ' ,
418  * , _______ ,
419  * , | | , <----- Walking the limb would not affect an
420  * , | | , image that does not extend to the
421  * , |_______| , limits of the projection.
422  * , ________________________,_
423  * , | , |
424  * ,| , |
425  * |,___________________,_'___| <-- This corner would wrap around.
426  * ' - , _ _ _ , ' The image would rotate because the
427  * center lat was closer to the pole.
428  * This would allow for a more completely
429  * longitude range.
430  * _o__o__
431  * o| |o <------------This is the rotated view. If the image
432  * o |_______| o limits extend over the pole (due to the
433  * o * o offset of the center lat) it is possible
434  * o o to have a lon range that is larger than
435  * o o 180 degrees.
436  *
437  */
438 
439  for (double angle = 0.0; angle <= 360.0; angle += 0.01) {
440  double x = m_equatorialRadius * cos(angle * PI / 180.0);
441  double y = m_equatorialRadius * sin(angle * PI / 180.0);
442 
443  if (SetCoordinate(x, y)){
444 
445  adjustedLon = To360Domain(m_longitude);
446  if (adjustedLon > To360Domain(MinimumLongitude()) && correctedMinLon) {
447  adjustedLon -= 360;
448  }
449  if (m_latitude <= m_maximumLatitude &&
450  adjustedLon <= adjustedMaxLon &&
452  adjustedLon >= adjustedMinLon) {
453  m_minimumX = qMin(x, m_minimumX);
454  m_maximumX = qMax(x, m_maximumX);
455  m_minimumY = qMin(y, m_minimumY);
456  m_maximumY = qMax(y, m_maximumY);
457  XYRangeCheck(m_latitude, adjustedLon);
458  }
459  }
460  }
461  // Make sure everything is ordered
462  if (m_minimumX >= m_maximumX ||
464  return false;
465 
466  // Return X/Y min/maxs
467  minX = m_minimumX;
468  maxX = m_maximumX;
469  minY = m_minimumY;
470  maxY = m_maximumY;
471 
472  return true;
473  }
474 
475 
482  PvlGroup mapping = TProjection::Mapping();
483 
484  mapping += m_mappingGrp["CenterLatitude"];
485  mapping += m_mappingGrp["CenterLongitude"];
486 
487  return mapping;
488  }
489 
497  mapping += m_mappingGrp["CenterLatitude"];
498 
499  return mapping;
500  }
501 
509 
510  mapping += m_mappingGrp["CenterLongitude"];
511 
512  return mapping;
513  }
514 } // end namespace isis
515 
529 extern "C" Isis::Projection *OrthographicPlugin(Isis::Pvl &lab,
530  bool allowDefaults) {
531  return new Isis::Orthographic(lab, allowDefaults);
532 }
Isis::TProjection::m_maximumLatitude
double m_maximumLatitude
Contains the maximum latitude for the entire ground range.
Definition: TProjection.h:356
Isis::Orthographic::XYRange
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...
Definition: Orthographic.cpp:373
Isis::HALFPI
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:41
Isis::TProjection::m_longitude
double m_longitude
This contains the currently set longitude value.
Definition: TProjection.h:318
Isis::TProjection::m_longitudeDomain
int m_longitudeDomain
This integer is either 180 or 360 and is read from the labels.
Definition: TProjection.h:331
Isis::Orthographic::Version
QString Version() const
Returns the version of the map projection.
Definition: Orthographic.cpp:190
Isis::PvlObject::findGroup
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:129
Isis::IException::Io
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:155
Isis::TProjection::m_minimumLongitude
double m_minimumLongitude
Contains the minimum longitude for the entire ground range.
Definition: TProjection.h:358
Isis::TProjection::m_latitude
double m_latitude
This contains the currently set latitude value.
Definition: TProjection.h:316
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::Orthographic::Mapping
PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: Orthographic.cpp:481
Isis::TProjection::m_longitudeDirection
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
Definition: TProjection.h:324
Isis::TProjection::m_minimumLatitude
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
Definition: TProjection.h:354
Isis::TProjection::PositiveWest
@ PositiveWest
Longitude values increase in the westerly direction.
Definition: TProjection.h:225
Isis::TProjection::MinimumLongitude
virtual double MinimumLongitude() const
This returns the minimum longitude of the area of interest.
Definition: TProjection.cpp:732
Isis::Projection::m_minimumY
double m_minimumY
See minimumX description.
Definition: Projection.h:327
Isis::Projection::GetX
double GetX() const
Calculates the unrotated form of current x value.
Definition: Projection.cpp:818
Isis::Orthographic::Name
QString Name() const
Returns the name of the map projection, "Orthographic".
Definition: Orthographic.cpp:180
Isis::Orthographic
Orthographic Map Projection.
Definition: Orthographic.h:75
Isis::PvlContainer::hasKeyword
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Definition: PvlContainer.cpp:159
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::Projection::SetXY
void SetXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:804
Isis::TProjection::ToPlanetocentric
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
Definition: TProjection.cpp:418
Isis::TProjection::XYRangeCheck
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method.
Definition: TProjection.cpp:1062
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::Projection::m_mappingGrp
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:329
Isis::Projection::GetY
double GetY() const
Calculates the unrotated form of the current y value.
Definition: Projection.cpp:829
Isis::Orthographic::SetCoordinate
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
Definition: Orthographic.cpp:268
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::Orthographic::SetGround
bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType,...
Definition: Orthographic.cpp:221
Isis::Projection::m_minimumX
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition: Projection.h:317
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::Projection::m_good
bool m_good
Indicates if the contents of m_x, m_y, m_latitude, and m_longitude are valid.
Definition: Projection.h:300
Isis::TProjection
Base class for Map TProjections.
Definition: TProjection.h:166
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::TProjection::To180Domain
static double To180Domain(const double lon)
This method converts a longitude into the -180 to 180 domain.
Definition: TProjection.cpp:657
Isis::Orthographic::~Orthographic
~Orthographic()
Destroys the Orthographic object.
Definition: Orthographic.cpp:155
Isis::TProjection::MaximumLongitude
virtual double MaximumLongitude() const
This returns the maximum longitude of the area of interest.
Definition: TProjection.cpp:743
Isis::Orthographic::MappingLongitudes
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: Orthographic.cpp:507
Isis::TProjection::MappingLongitudes
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: TProjection.cpp:1739
Isis::Orthographic::m_sinph0
double m_sinph0
Sine of the center latitude.
Definition: Orthographic.h:96
Isis::Projection::SetComputedXY
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:780
Isis::Orthographic::operator==
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.
Definition: Orthographic.cpp:166
std
Namespace for the standard library.
Isis::TProjection::m_maximumLongitude
double m_maximumLongitude
Contains the maximum longitude for the entire ground range.
Definition: TProjection.h:360
Isis::TProjection::MappingLatitudes
virtual PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
Definition: TProjection.cpp:1723
Isis::TProjection::ToPlanetographic
double ToPlanetographic(const double lat) const
This method converts a planetocentric latitude to a planetographic latitude.
Definition: TProjection.cpp:463
Isis::E
const double E
Sets some basic constants for use in ISIS programming.
Definition: Constants.h:39
Isis::Orthographic::MappingLatitudes
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
Definition: Orthographic.cpp:495
Isis::TProjection::Mapping
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: TProjection.cpp:1698
Isis::TProjection::m_equatorialRadius
double m_equatorialRadius
Polar radius of the target.
Definition: TProjection.h:335
Isis::TProjection::To360Domain
static double To360Domain(const double lon)
This method converts a longitude into the 0 to 360 domain.
Definition: TProjection.cpp:675
Isis::TProjection::IsPlanetocentric
bool IsPlanetocentric() const
This indicates if the latitude type is planetocentric (as opposed to planetographic).
Definition: TProjection.cpp:392
Isis::Orthographic::m_cosph0
double m_cosph0
Cosine of the center latitude.
Definition: Orthographic.h:97
Isis::Projection::m_maximumY
double m_maximumY
See minimumX description.
Definition: Projection.h:328
Isis::Projection
Base class for Map Projections.
Definition: Projection.h:155
Isis::Projection::m_maximumX
double m_maximumX
See minimumX description.
Definition: Projection.h:326
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::Orthographic::TrueScaleLatitude
double TrueScaleLatitude() const
Returns the center latitude, in degrees.
Definition: Orthographic.cpp:203
Isis::Orthographic::m_centerLongitude
double m_centerLongitude
The center longitude for the map projection.
Definition: Orthographic.h:94
Isis::Orthographic::m_centerLatitude
double m_centerLatitude
The center latitude for the map projection.
Definition: Orthographic.h:95

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:16:58