Isis 3 Programmer Reference
SurfacePoint.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "SurfacePoint.h"
8 
9 #include <SpiceUsr.h>
10 
11 #include "IException.h"
12 #include "IString.h"
13 #include "Latitude.h"
14 #include "Longitude.h"
15 #include "SpecialPixel.h"
16 
17 using namespace boost::numeric::ublas;
18 using namespace std;
19 
20 namespace Isis {
21 
26  SurfacePoint::SurfacePoint() {
27  InitCovariance();
28  InitPoint();
29  }
30 
35  SurfacePoint::SurfacePoint(const SurfacePoint &other) {
36  p_localRadius = other.p_localRadius;
37 
38  if(other.p_x) {
39  p_x = new Displacement(*other.p_x);
40  }
41  else {
42  p_x = NULL;
43  }
44 
45  if(other.p_y) {
46  p_y = new Displacement(*other.p_y);
47  }
48  else {
49  p_y = NULL;
50  }
51 
52  if(other.p_z) {
53  p_z = new Displacement(*other.p_z);
54  }
55  else {
56  p_z = NULL;
57  }
58 
59  if(other.p_rectCovar) {
60  p_rectCovar = new symmetric_matrix<double, upper>(*other.p_rectCovar);
61  }
62  else {
63  p_rectCovar = NULL;
64  }
65 
66  if(other.p_sphereCovar) {
67  p_sphereCovar = new symmetric_matrix<double, upper>(*other.p_sphereCovar);
68  }
69  else {
70  p_sphereCovar = NULL;
71  }
72  }
73 
74 
82  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
83  const Distance &radius) {
84  InitCovariance();
85  InitPoint();
86  SetSphericalPoint(lat, lon, radius);
87  }
88 
89 
90 
105  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
106  const Distance &radius, const Angle &latSigma, const Angle &lonSigma,
107  const Distance &radiusSigma) {
108  InitCovariance();
109  InitPoint();
110  SetSpherical(lat, lon, radius, latSigma, lonSigma, radiusSigma);
111  }
112 
113 
119  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
120  const Distance &radius, const symmetric_matrix<double, upper> &covar) {
121  InitCovariance();
122  InitPoint();
123  SetSpherical(lat, lon, radius, covar);
124  }
125 
126 
134  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
135  const Displacement &z) {
136  InitCovariance();
137  InitPoint();
138  SetRectangular(x, y, z);
139  }
140 
141 
156  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
157  const Displacement &z, const Distance &xSigma, const Distance &ySigma,
158  const Distance &zSigma) {
159  InitCovariance();
160  InitPoint();
161  SetRectangular(x, y, z, xSigma, ySigma, zSigma);
162  }
163 
164 
174  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
175  const Displacement &z, const symmetric_matrix<double, upper> &covar) {
176  InitCovariance();
177  InitPoint();
178  SetRectangular(x, y, z, covar);
179  }
180 
181 
186  SurfacePoint::~SurfacePoint() {
187  FreeAllocatedMemory();
188  }
189 
190 
195  void SurfacePoint::InitCovariance() {
196  p_rectCovar = NULL;
197  p_sphereCovar = NULL;
198  }
199 
200 
205  void SurfacePoint::InitPoint() {
206  p_x = NULL;
207  p_y = NULL;
208  p_z = NULL;
209  p_localRadius = Distance();
210  }
211 
212 
225  void SurfacePoint::SetRectangularPoint(const Displacement &x,
226  const Displacement &y, const Displacement &z) {
227 
228  if (!x.isValid() || !y.isValid() || !z.isValid()) {
229  IString msg = "x, y, and z must be set to valid displacements. One or "
230  "more coordinates have been set to an invalid displacement.";
231  throw IException(IException::User, msg, _FILEINFO_);
232  }
233 
234  if(p_x) {
235  *p_x = x;
236  }
237  else {
238  p_x = new Displacement(x);
239  }
240 
241  if(p_y) {
242  *p_y = y;
243  }
244  else {
245  p_y = new Displacement(y);
246  }
247 
248  if(p_z) {
249  *p_z = z;
250  }
251  else {
252  p_z = new Displacement(z);
253  }
254 
255  // Added 07-30-2018 to avoid trying to set an invalid SurfacePoint. This breaks the ringspt and cnetnewradii tests. Also the pole...mean test.
256  // if (!(this->Valid())) {
257  // IString msg = "All coodinates of the point are zero. At least one coordinate"
258  // " must be nonzero to be a valid SurfacePoint.";
259  // throw IException(IException::User, msg, _FILEINFO_);
260  // }
261 
262  if (!p_localRadius.isValid()) {
263  ComputeLocalRadius();
264  p_localRadius = GetLocalRadius();
265  }
266  }
267 
268 
283  void SurfacePoint::SetRectangular(const Displacement &x,
284  const Displacement &y, const Displacement &z, const Distance &xSigma,
285  const Distance &ySigma, const Distance &zSigma) {
286 
287  // Wipe out current local radius to ensure it will be recalculated in SetRectangularPoint
288  p_localRadius = Distance();
289 
290  SetRectangularPoint(x, y, z);
291 
292  if (xSigma.isValid() && ySigma.isValid() && zSigma.isValid())
293  SetRectangularSigmas(xSigma, ySigma, zSigma);
294  }
295 
296 
308  void SurfacePoint::SetRectangular(Displacement x, Displacement y, Displacement z,
309  const symmetric_matrix<double,upper>& covar) {
310  // Wipe out current local radius to ensure it will be recalulated in SetRectangularPoint
311  p_localRadius = Distance();
312 
313  SetRectangularPoint(x, y, z);
314  SetRectangularMatrix(covar);
315  }
316 
317 
327  void SurfacePoint::SetRectangularCoordinates(const Displacement &x,
328  const Displacement &y,
329  const Displacement &z) {
330  // Wipe out current local radius to ensure it will be recalculated in SetRectangularPoint
331  p_localRadius = Distance();
332 
333  SetRectangularPoint(x, y, z);
334  }
335 
336 
350  void SurfacePoint::SetRectangularSigmas(const Distance &xSigma,
351  const Distance &ySigma,
352  const Distance &zSigma) {
353  if (!xSigma.isValid() || !ySigma.isValid() || !zSigma.isValid()) {
354  IString msg = "x sigma, y sigma , and z sigma must be set to valid "
355  "distances. One or more sigmas have been set to an invalid distance.";
356  throw IException(IException::User, msg, _FILEINFO_);
357  }
358 
359  symmetric_matrix<double,upper> covar(3);
360  covar.clear();
361  covar(0,0) = xSigma.meters() * xSigma.meters();
362  covar(1,1) = ySigma.meters() * ySigma.meters();
363  covar(2,2) = zSigma.meters() * zSigma.meters();
364  SetRectangularMatrix(covar, Meters);
365  }
366 
367 
376  void SurfacePoint::SetRectangularMatrix(const symmetric_matrix<double, upper> &covar,
377  SurfacePoint::CoordUnits units) {
378 
379  // Make sure the point is set first
380  if (!Valid()) {
381  IString msg = "A point must be set before a variance/covariance matrix "
382  "can be set.";
383  throw IException(IException::Programmer, msg, _FILEINFO_);
384  }
385 
386  // Make sure the units are valid
387  if (units != Kilometers && units != Meters) {
388  IString msg = "Units must be Kilometers or Meters";
389  throw IException(IException::Programmer, msg, _FILEINFO_);
390  }
391 
392  // covar units are km**2
393  if (p_rectCovar) {
394  *p_rectCovar = covar;
395  }
396  else {
397  p_rectCovar = new symmetric_matrix<double, upper>(covar);
398  }
399 
400  if (units == Meters) {
401  // Convert input matrix to km to hold in memory
402  (*p_rectCovar)(0,0) = covar(0,0)/1.0e6;
403  (*p_rectCovar)(0,1) = covar(0,1)/1.0e6;
404  (*p_rectCovar)(0,2) = covar(0,2)/1.0e6;
405  (*p_rectCovar)(1,1) = covar(1,1)/1.0e6;
406  (*p_rectCovar)(1,2) = covar(1,2)/1.0e6;
407  (*p_rectCovar)(2,2) = covar(2,2)/1.0e6;
408  }
409 
410  SpiceDouble rectMat[3][3];
411 
412  // Compute the local radius of the surface point in meters. We will convert to km before saving the matrix.
413  double x2 = p_x->meters() * p_x->meters();
414  double y2 = p_y->meters() * p_y->meters();
415  double z = p_z->meters();
416  double radius = sqrt(x2 + y2 + z*z);
417 
418  // *** TODO *** Replace this section with LinearAlgebra multiply calls and avoid having to create a Spice matrix
419  rectMat[0][0] = covar(0,0);
420  rectMat[0][1] = rectMat[1][0] = covar(0,1);
421  rectMat[0][2] = rectMat[2][0] = covar(0,2);
422  rectMat[1][1] = covar(1,1);
423  rectMat[1][2] = rectMat[2][1] = covar(1,2);
424  rectMat[2][2] = covar(2,2);
425 
426  // Compute the Jacobian in meters. Don't deal with unit mismatch yet to preserve precision.
427  SpiceDouble J[3][3];
428  double zOverR = p_z->meters() / radius;
429  double r2 = radius*radius;
430  double denom = r2*radius*sqrt(1.0 - (zOverR*zOverR));
431  J[0][0] = -p_x->meters() * p_z->meters() / denom;
432  J[0][1] = -p_y->meters() * p_z->meters() / denom;
433  J[0][2] = (r2 - p_z->meters() * p_z->meters()) / denom;
434  J[1][0] = -p_y->meters() / (x2 + y2);
435  J[1][1] = p_x->meters() / (x2 + y2);
436  J[1][2] = 0.0;
437  J[2][0] = p_x->meters() / radius; // This row is unitless
438  J[2][1] = p_y->meters() / radius;
439  J[2][2] = p_z->meters() / radius;
440 
441  if(!p_sphereCovar)
442  p_sphereCovar = new symmetric_matrix<double, upper>(3);
443 
444  SpiceDouble mat[3][3];
445  mxm_c (J, rectMat, mat);
446  mxmt_c (mat, J, mat);
447  if (units == Kilometers) {
448  // Now take care of unit mismatch between rect matrix in km and Jacobian in m
449  (*p_sphereCovar)(0,0) = mat[0][0] * 1.0e6;
450  (*p_sphereCovar)(0,1) = mat[0][1] * 1.0e6;
451  (*p_sphereCovar)(0,2) = mat[0][2] * 1000.0;
452  (*p_sphereCovar)(1,1) = mat[1][1] * 1.0e6;
453 
454  (*p_sphereCovar)(1,2) = mat[1][2] * 1000.0;
455  (*p_sphereCovar)(2,2) = mat[2][2];
456  }
457  else { // (units == Meters)
458  // Convert matrix lengths from m to km
459  (*p_sphereCovar)(0,0) = mat[0][0];
460  (*p_sphereCovar)(0,1) = mat[0][1];
461  (*p_sphereCovar)(0,2) = mat[0][2] / 1000.0;
462  (*p_sphereCovar)(1,1) = mat[1][1];
463  (*p_sphereCovar)(1,2) = mat[1][2] / 1000.0;
464  (*p_sphereCovar)(2,2) = mat[2][2] / 1.0e6;
465  }
466  }
467 
468 
480  void SurfacePoint::SetSphericalPoint(const Latitude &lat,
481  const Longitude &lon,
482  const Distance &radius) {
483 // Is error checking necessary or does Latitude, Longitude, and Distance handle it?????
484  if (!lat.isValid() || !lon.isValid() || !radius.isValid()) {
485  IString msg = "Latitude, longitude, or radius is an invalid value.";
486  throw IException(IException::User, msg, _FILEINFO_);
487  }
488 
489  SpiceDouble dlat = (double) lat.radians();
490  SpiceDouble dlon = (double) lon.radians();
491  SpiceDouble dradius = radius.kilometers();
492 
493  SpiceDouble rect[3];
494  latrec_c ( dradius, dlon, dlat, rect);
495 
496  // Set local radius now since we have it and avoid calculating it later
497  p_localRadius = radius;
498 
499  SetRectangularPoint(Displacement(rect[0], Displacement::Kilometers),
500  Displacement(rect[1], Displacement::Kilometers),
501  Displacement(rect[2], Displacement::Kilometers));
502  }
503 
504 
518  void SurfacePoint::SetSpherical(const Latitude &lat, const Longitude &lon,
519  const Distance &radius, const Angle &latSigma, const Angle &lonSigma,
520  const Distance &radiusSigma) {
521 
522  SetSphericalPoint(lat, lon, radius);
523 
524  if (latSigma.isValid() && lonSigma.isValid() && radiusSigma.isValid())
525  SetSphericalSigmas(latSigma, lonSigma, radiusSigma);
526  }
527 
528 
538  void SurfacePoint::SetSpherical(const Latitude &lat, const Longitude &lon,
539  const Distance &radius, const symmetric_matrix<double, upper> &covar) {
540  SetSphericalPoint(lat, lon, radius);
541  SetSphericalMatrix(covar);
542  }
543 
544 
553  void SurfacePoint::SetSphericalCoordinates(const Latitude &lat,
554  const Longitude &lon, const Distance &radius) {
555  SetSphericalPoint(lat, lon, radius);
556  }
557 
558 
573  void SurfacePoint::SetSphericalSigmas(const Angle &latSigma,
574  const Angle &lonSigma,
575  const Distance &radiusSigma) {
576  if (latSigma.isValid() && lonSigma.isValid() && radiusSigma.isValid()) {
577  symmetric_matrix<double,upper> covar(3);
578  covar.clear();
579 
580  double sphericalCoordinate;
581  sphericalCoordinate = (double) latSigma.radians();
582  covar(0,0) = sphericalCoordinate*sphericalCoordinate;
583  sphericalCoordinate = (double) lonSigma.radians();
584  covar(1,1) = sphericalCoordinate*sphericalCoordinate;
585  sphericalCoordinate = (double) radiusSigma.meters();
586  covar(2,2) = sphericalCoordinate*sphericalCoordinate;
587 
588  // Use default set units for radius of meters*meters
589  SetSphericalMatrix(covar);
590  }
591  else {
592  delete p_sphereCovar;
593  p_sphereCovar = NULL;
594 
595  delete p_rectCovar;
596  p_rectCovar = NULL;
597  }
598  }
599 
600 
617  void SurfacePoint::SetSphericalSigmasDistance(const Distance &latSigma,
618  const Distance &lonSigma, const Distance &radiusSigma) {
619 
620  if (!Valid()) {
621  IString msg = "Cannot set spherical sigmas on an invalid surface point";
622  throw IException(IException::Programmer, msg, _FILEINFO_);
623  }
624 
625  SetSphericalSigmas(Angle(MetersToLatitude(latSigma.meters()),Angle::Radians),
626  Angle(MetersToLongitude(lonSigma.meters()), Angle::Radians), radiusSigma);
627  }
628 
629 
637  void SurfacePoint::SetSphericalMatrix(
638  const symmetric_matrix<double, upper> & covar,
639  SurfacePoint::CoordUnits units) {
640 
641  // Make sure the point is set first
642  if (!Valid()) {
643  IString msg = "A point must be set before a variance/covariance matrix "
644  "can be set.";
645  throw IException(IException::Programmer, msg, _FILEINFO_);
646  }
647 
648  // Make sure the units are valid
649  if (units != Kilometers && units != Meters) {
650  IString msg = "Units must be Kilometers or Meters";
651  throw IException(IException::Programmer, msg, _FILEINFO_);
652  }
653 
654  // Get the radius of the point in the same units as the input matrix when saving the input matrix
655  double radius = (double) GetLocalRadius().kilometers();
656 
657  // Save the spherical matrix in km and km**2
658  if (p_sphereCovar) {
659  *p_sphereCovar = covar;
660  }
661  else {
662  p_sphereCovar = new symmetric_matrix<double, upper>(covar);
663  }
664 
665  if (units == Meters) {
666  // Convert input matrix to km to store
667  (*p_sphereCovar)(0,0) = covar(0,0);
668  (*p_sphereCovar)(0,1) = covar(0,1);
669  (*p_sphereCovar)(0,2) = covar(0,2) / 1000.;
670  (*p_sphereCovar)(1,1) = covar(1,1);
671  (*p_sphereCovar)(1,2) = covar(1,2) / 1000.;
672  (*p_sphereCovar)(2,2) = covar(2,2) / 1.0e6;
673  radius = (double) GetLocalRadius().meters();
674  }
675 
676  // ***TODO*** Consider using LinearAlgebra matrix multiply and avoid creating SpiceDouble matrix.
677  SpiceDouble sphereMat[3][3];
678 
679  sphereMat[0][0] = covar(0,0);
680  sphereMat[0][1] = sphereMat[1][0] = covar(0,1);
681  sphereMat[0][2] = sphereMat[2][0] = covar(0,2);
682  sphereMat[1][1] = covar(1,1);
683  sphereMat[1][2] = sphereMat[2][1] = covar(1,2);
684  sphereMat[2][2] = covar(2,2);
685 
686 // std::cout<<"Ocovar = "<<sphereMat[0][0]<<" "<<sphereMat[0][1]<<" "<<sphereMat[0][2]<<std::endl
687 // <<" "<<sphereMat[1][0]<<" "<<sphereMat[1][1]<<" "<<sphereMat[1][2]<<std::endl
688 // <<" "<<sphereMat[2][0]<<" "<<sphereMat[2][1]<<" "<<sphereMat[2][2]<<std::endl;
689 
690  // Get the lat/lon/radius of the point
691  double lat = (double) GetLatitude().radians();
692  double lon = (double) GetLongitude().radians();
693 
694  // Compute the Jacobian in same units as input matrix.
695  SpiceDouble J[3][3];
696  double cosPhi = cos(lat);
697  double sinPhi = sin(lat);
698  double cosLamda = cos(lon);
699  double sinLamda = sin(lon);
700  double rcosPhi = radius*cosPhi;
701  double rsinPhi = radius*sinPhi;
702  J[0][0] = -rsinPhi * cosLamda;
703  J[0][1] = -rcosPhi * sinLamda;
704  J[0][2] = cosPhi * cosLamda;
705  J[1][0] = -rsinPhi * sinLamda;
706  J[1][1] = rcosPhi * cosLamda;
707  J[1][2] = cosPhi * sinLamda;
708  J[2][0] = rcosPhi;
709  J[2][1] = 0.0;
710  J[2][2] = sinPhi;
711 
712  if(!p_rectCovar)
713  p_rectCovar = new symmetric_matrix<double, upper>(3);
714 
715  SpiceDouble mat[3][3];
716  mxm_c (J, sphereMat, mat);
717  mxmt_c (mat, J, mat);
718 
719  if (units == Kilometers) {
720  (*p_rectCovar)(0,0) = mat[0][0];
721  (*p_rectCovar)(0,1) = mat[0][1];
722  (*p_rectCovar)(0,2) = mat[0][2];
723  (*p_rectCovar)(1,1) = mat[1][1];
724  (*p_rectCovar)(1,2) = mat[1][2];
725  (*p_rectCovar)(2,2) = mat[2][2];
726  }
727  else { // (units == Meters)
728  // Convert to km
729  (*p_rectCovar)(0,0) = mat[0][0]/1.0e6;
730  (*p_rectCovar)(0,1) = mat[0][1]/1.0e6;
731  (*p_rectCovar)(0,2) = mat[0][2]/1.0e6;
732  (*p_rectCovar)(1,1) = mat[1][1]/1.0e6;
733  (*p_rectCovar)(1,2) = mat[1][2]/1.0e6;
734  (*p_rectCovar)(2,2) = mat[2][2]/1.0e6;
735  }
736 // std::cout<<"Rcovar = "<<p_rectCovar(0,0)<<" "<<p_rectCovar(0,1)<<" "<<p_rectCovar(0,2)<<std::endl
737 // <<" "<<p_rectCovar(1,0)<<" "<<p_rectCovar(1,1)<<" "<<p_rectCovar(1,2)<<std::endl
738 // <<" "<<p_rectCovar(2,0)<<" "<<p_rectCovar(2,1)<<" "<<p_rectCovar(2,2)<<std::endl;
739  }
740 
741 
749  void SurfacePoint::SetMatrix(CoordinateType type, const symmetric_matrix<double, upper>& covar) {
750 
751  switch (type) {
752  case Latitudinal:
753  SetSphericalMatrix(covar, SurfacePoint::Kilometers);
754  break;
755  case Rectangular:
756  SetRectangularMatrix(covar, SurfacePoint::Kilometers);
757  break;
758  default:
759  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
760  throw IException(IException::Programmer, msg, _FILEINFO_);
761  }
762  }
763 
764 
773  std::vector<double> SurfacePoint::Partial(CoordinateType type, CoordIndex index) {
774  std::vector<double> derivative(3);
775  switch (type) {
776  case Latitudinal:
777  derivative = LatitudinalDerivative(index);
778  break;
779  case Rectangular:
780  derivative = RectangularDerivative(index);
781  break;
782  default:
783  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
784  throw IException(IException::Programmer, msg, _FILEINFO_);
785  }
786  return derivative;
787  }
788 
789 
798  std::vector<double> SurfacePoint::LatitudinalDerivative(CoordIndex index) {
799  std::vector<double> derivative(3);
800  double rlat = GetLatitude().radians();
801  double rlon = GetLongitude().radians();
802  double sinLon = sin(rlon);
803  double cosLon = cos(rlon);
804  double sinLat = sin(rlat);
805  double cosLat = cos(rlat);
806  double radkm = GetLocalRadius().kilometers();
807 
808  switch (index) {
809  case One:
810  derivative[0] = -radkm * sinLat * cosLon;
811  derivative[1] = -radkm * sinLon * sinLat;
812  derivative[2] = radkm * cosLat;
813  break;
814  case Two:
815  derivative[0] = -radkm * cosLat * sinLon;
816  derivative[1] = radkm * cosLat * cosLon;
817  derivative[2] = 0.0;
818  break;
819  case Three:
820  derivative[0] = cosLon * cosLat;
821  derivative[1] = sinLon * cosLat;
822  derivative[2] = sinLat;
823  break;
824  default:
825  IString msg = "Invalid coordinate index (must be less than 3).";
826  throw IException(IException::Programmer, msg, _FILEINFO_);
827  }
828  return derivative;
829  }
830 
831 
840  std::vector<double> SurfacePoint::RectangularDerivative(CoordIndex index) {
841  std::vector<double> derivative(3,0.0);
842 
843  switch (index) {
844  case One:
845  derivative[0] = 1.;
846  break;
847  case Two:
848  derivative[1] = 1.;
849  break;
850  case Three:
851  derivative[2] = 1.;
852  break;
853  default:
854  IString msg = "Invalid coordinate index (must be less than 3).";
855  throw IException(IException::Programmer, msg, _FILEINFO_);
856  }
857  return derivative;
858  }
859 
860 
870  void SurfacePoint::ToNaifArray(double naifOutput[3]) const {
871  if(Valid()) {
872  naifOutput[0] = p_x->kilometers();
873  naifOutput[1] = p_y->kilometers();
874  naifOutput[2] = p_z->kilometers();
875  }
876  else {
877  IString msg = "Cannot convert an invalid surface point to a naif array";
878  throw IException(IException::Programmer, msg, _FILEINFO_);
879  }
880  }
881 
891  void SurfacePoint::FromNaifArray(const double naifValues[3]) {
892  if(p_x && p_y && p_z) {
893  p_x->setKilometers(naifValues[0]);
894  p_y->setKilometers(naifValues[1]);
895  p_z->setKilometers(naifValues[2]);
896  }
897  else {
898  p_x = new Displacement(naifValues[0], Displacement::Kilometers);
899  p_y = new Displacement(naifValues[1], Displacement::Kilometers);
900  p_z = new Displacement(naifValues[2], Displacement::Kilometers);
901  }
902 
903  ComputeLocalRadius();
904  p_localRadius = GetLocalRadius();
905  }
906 
907 
914  void SurfacePoint::ResetLocalRadius(const Distance &radius) {
915 
916  if (!radius.isValid()) {
917  IString msg = "Radius value must be a valid Distance.";
918  throw IException(IException::Programmer, msg, _FILEINFO_);
919  }
920 
921  if (!p_x || !p_y || !p_z || !p_x->isValid() || !p_y->isValid() ||
922  !p_z->isValid()) {
923  IString msg = "In order to reset the local radius, a Surface Point must "
924  "already be set.";
925  throw IException(IException::Programmer, msg, _FILEINFO_);
926  }
927 
928  // Set latitudinal coordinates
929  SpiceDouble lat = (double) GetLatitude().radians();
930  SpiceDouble lon = (double) GetLongitude().radians();
931 
932  p_localRadius = radius;
933 
934  // Set rectangular coordinates
935  SpiceDouble rect[3];
936  latrec_c ((SpiceDouble) radius.kilometers(), lon, lat, rect);
937  p_x->setKilometers(rect[0]);
938  p_y->setKilometers(rect[1]);
939  p_z->setKilometers(rect[2]);
940 
941  // TODO What should be done to the variance/covariance matrix when the
942  // radius is reset??? With Bundle updates will this functionality be
943  // obsolete??? Ask Ken
944  }
945 
946 
947  bool SurfacePoint::Valid() const {
948  static const Displacement zero(0, Displacement::Meters);
949  return p_x && p_y && p_z && p_x->isValid() && p_y->isValid() && p_z->isValid() &&
950  (*p_x != zero || *p_y != zero || *p_z != zero);
951  }
952 
953 
962  double SurfacePoint::GetCoord(CoordinateType type, CoordIndex index, CoordUnits units) {
963  // TODO *** Is there a better way to satisfy the compiler that a value will be initialized?
964  // Don't the enums take care of preventing any other possibilities? no
965  double value = 0.;
966 
967  switch (type) {
968 
969  case Latitudinal:
970 
971  switch (index) {
972 
973  case One: // Latitude
974  value = LatToDouble(GetLatitude(), units);
975  break;
976 
977  case Two: // Longitude
978  value = LonToDouble(GetLongitude(), units);
979  break;
980 
981  case Three: // LocalRadius
982  value = DistanceToDouble(GetLocalRadius(), units);
983  break;
984 
985  default:
986  IString msg = "Invalid coordinate index (must be less than 3).";
987  throw IException(IException::Programmer, msg, _FILEINFO_);
988  }
989  break;
990 
991  case Rectangular:
992 
993  switch (index) {
994 
995  case One: // X
996  value = DisplacementToDouble(GetX(), units);
997  break;
998 
999  case Two: // Y
1000  value = DisplacementToDouble(GetY(), units);
1001  break;
1002 
1003  case Three: // Z
1004  value = DisplacementToDouble(GetZ(), units);
1005  break;
1006 
1007  default:
1008  IString msg = "Invalid coordinate index enum (must be less than 3).";
1009  throw IException(IException::Programmer, msg, _FILEINFO_);
1010  }
1011  break;
1012 
1013  default:
1014  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
1015  throw IException(IException::Programmer, msg, _FILEINFO_);
1016  }
1017  return value;
1018  }
1019 
1020 
1029  double SurfacePoint::GetSigma(CoordinateType type, CoordIndex index, CoordUnits units) {
1030  double value = 0; // See first TODO in GetCoord
1031 
1032  switch (type) {
1033 
1034  case Latitudinal:
1035 
1036  switch (index) {
1037 
1038  case One:
1039  value = DistanceToDouble(GetLatSigmaDistance(), units);
1040  break;
1041 
1042  case Two:
1043  value = DistanceToDouble(GetLonSigmaDistance(), units);
1044  break;
1045 
1046  case Three:
1047  value = DistanceToDouble(GetLocalRadiusSigma(), units);
1048  break;
1049 
1050  default:
1051  IString msg = "Invalid coordinate index (must be less than 3).";
1052  throw IException(IException::Programmer, msg, _FILEINFO_);
1053  }
1054  break;
1055 
1056  case Rectangular:
1057 
1058  switch (index) {
1059 
1060  case One:
1061  value = DistanceToDouble(GetXSigma(), units);
1062  break;
1063 
1064  case Two:
1065  value = DistanceToDouble(GetYSigma(), units);
1066  break;
1067 
1068  case Three:
1069  value = DistanceToDouble(GetZSigma(), units);
1070  break;
1071 
1072  default:
1073  IString msg = "Invalid coordinate index (must be less than 3).";
1074  throw IException(IException::Programmer, msg, _FILEINFO_);
1075  }
1076  break;
1077 
1078  default:
1079  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
1080  throw IException(IException::Programmer, msg, _FILEINFO_);
1081  }
1082 
1083  return value;
1084  }
1085 
1086 
1094  Distance SurfacePoint::GetSigmaDistance(CoordinateType type,
1095  CoordIndex index) {
1096  Distance dist = Distance(); // See first TODO in GetCoord
1097 
1098  switch (type) {
1099 
1100  case Latitudinal:
1101 
1102  switch (index) {
1103 
1104  case One:
1105  dist = GetLatSigmaDistance();
1106  break;
1107 
1108  case Two:
1109  dist = GetLonSigmaDistance();
1110  break;
1111 
1112  case Three:
1113  dist = GetLocalRadiusSigma();
1114  break;
1115 
1116  default:
1117  IString msg = "Invalid coordinate index (must be less than 3).";
1118  throw IException(IException::Programmer, msg, _FILEINFO_);
1119  }
1120  break;
1121 
1122  case Rectangular:
1123 
1124  switch (index) {
1125 
1126  case One:
1127  dist = GetXSigma();
1128  break;
1129 
1130  case Two:
1131  dist = GetYSigma();
1132  break;
1133 
1134  case Three:
1135  dist = GetZSigma();
1136  break;
1137 
1138  default:
1139  IString msg = "Invalid coordinate index (must be less than 3).";
1140  throw IException(IException::Programmer, msg, _FILEINFO_);
1141  }
1142  break;
1143 
1144  default:
1145  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
1146  throw IException(IException::Programmer, msg, _FILEINFO_);
1147  }
1148 
1149  return dist;
1150  }
1151 
1152 
1160  double SurfacePoint::DisplacementToDouble(Displacement disp, CoordUnits units) {
1161  double value;
1162 
1163  switch (units) {
1164 
1165  case Meters:
1166  value = disp.meters();
1167  break;
1168 
1169  case Kilometers:
1170  value = disp.kilometers();
1171  break;
1172 
1173  default:
1174  IString msg = "Unrecognized unit for a Displacement (must be meters or kilometers).";
1175  throw IException(IException::Programmer, msg, _FILEINFO_);
1176  }
1177  return value;
1178  }
1179 
1180 
1188  double SurfacePoint::DistanceToDouble(Distance dist, CoordUnits units) {
1189  double value;
1190 
1191  switch (units) {
1192 
1193  case Meters:
1194  value = dist.meters();
1195  break;
1196 
1197  case Kilometers:
1198  value = dist.kilometers();
1199  break;
1200 
1201  default:
1202  IString msg = "Unrecognized unit for a Distance (not meters or kilometers).";
1203  throw IException(IException::Programmer, msg, _FILEINFO_);
1204  }
1205  return value;
1206  }
1207 
1208 
1216  double SurfacePoint::LatToDouble(Latitude lat, CoordUnits units) {
1217  double value;
1218 
1219  switch (units) {
1220 
1221  case Radians:
1222  value = GetLatitude().radians();
1223  break;
1224 
1225  case Degrees:
1226  value = GetLatitude().degrees();
1227  break;
1228 
1229  default:
1230  IString msg = "Invalid unit for latitude (must be Radians or Degrees).";
1231  throw IException(IException::Programmer, msg, _FILEINFO_);
1232  }
1233  return value;
1234  }
1235 
1236 
1248  double SurfacePoint::MetersToLatitude(double latLength) {
1249  if (Valid() && !IsSpecial(latLength)) {
1250  // Convert angle measure in meters to radians relative to latitude of SurfacePoint.
1251  return latLength / GetLocalRadius().meters();
1252  }
1253  else {
1254  // Return Null to be consistent with the bundle classes
1255  return Isis::Null;
1256  }
1257  }
1258 
1259 
1276  double SurfacePoint::MetersToLongitude(double deltaLonMeters) {
1277 
1278  if (Valid() && !IsSpecial(deltaLonMeters)) {
1279  double convFactor = cos((double)GetLatitude().radians());
1280  double deltaLonRadians;
1281 
1282  // Convert angle displacement to radians relative to longitude of SurfacePoint.
1283  if (convFactor > 1.0e-50) {
1284  deltaLonRadians = deltaLonMeters / (convFactor*GetLocalRadius().meters());
1285  }
1286  else {
1287  // Brent Archinal suggested setting sigma to pi in the case of a point near the pole
1288  deltaLonRadians = PI;
1289  }
1290  return deltaLonRadians;
1291  }
1292  else {
1293  // Return Null to be consistent with the bundle classes
1294  return Isis::Null;
1295  }
1296  }
1297 
1298 
1310  double SurfacePoint::LatitudeToMeters(double relativeLat) const {
1311  // Returns are consistent with the bundle classes
1312  if (relativeLat == 0.) {
1313  return 0.;
1314  }
1315  else if (Valid() && !IsSpecial(relativeLat) && GetLocalRadius().isValid() ) {
1316  return relativeLat * GetLocalRadius().meters();
1317  }
1318  else {
1319  return Isis::Null;
1320  }
1321  }
1322 
1323 
1336  double SurfacePoint::LongitudeToMeters(double deltaLonRadians) const{
1337  // Returns are consistent with the bundle classes
1338  double deltaLonMeters = Isis::Null;
1339 
1340  if (deltaLonRadians == 0.) {
1341  deltaLonMeters = 0.;
1342  }
1343  else if (Valid() && !IsSpecial(deltaLonRadians) && GetLocalRadius().isValid() ) {
1344  // Convert from radians to meters and return
1345  double scalingRadius = cos(GetLatitude().radians()) * GetLocalRadius().meters();
1346  deltaLonMeters = deltaLonRadians * scalingRadius;
1347  }
1348 
1349  return deltaLonMeters;
1350  }
1351 
1352 
1363  SurfacePoint::stringToCoordinateType(QString type) {
1364  if (type.compare("LATITUDINAL", Qt::CaseInsensitive) == 0) {
1365  return SurfacePoint::Latitudinal;
1366  }
1367  else if (type.compare("RECTANGULAR", Qt::CaseInsensitive) == 0) {
1368  return SurfacePoint::Rectangular;
1369  }
1370  else {
1371  throw IException(IException::Programmer,
1372  "Unknown coordinate type for a SurfacePoint [" + type + "].",
1373  _FILEINFO_);
1374  }
1375  }
1376 
1377 
1389  QString SurfacePoint::coordinateTypeToString(
1391  switch (type) {
1392 
1393  case Latitudinal:
1394  return "Latitudinal";
1395  break;
1396 
1397  case Rectangular:
1398  return "Rectangular";
1399  break;
1400 
1401  default:
1402  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
1403  throw IException(IException::Programmer, msg, _FILEINFO_);
1404  }
1405  }
1406 
1407 
1415  double SurfacePoint::LonToDouble(Longitude lon, CoordUnits units) {
1416  double value;
1417 
1418  switch (units) {
1419 
1420  case Radians:
1421  value = GetLongitude().radians();
1422  break;
1423 
1424  case Degrees:
1425  value = GetLongitude().degrees();
1426  break;
1427 
1428  default:
1429  IString msg = "Invalid unit for longitude (must be Radians of Degrees).";
1430  throw IException(IException::Programmer, msg, _FILEINFO_);
1431  }
1432  return value;
1433  }
1434 
1435 
1436  Displacement SurfacePoint::GetX() const {
1437  if(!p_x) return Displacement();
1438 
1439  return *p_x;
1440  }
1441 
1442 
1443  Displacement SurfacePoint::GetY() const {
1444  if(!p_y) return Displacement();
1445 
1446  return *p_y;
1447  }
1448 
1449 
1450  Displacement SurfacePoint::GetZ() const {
1451  if(!p_z) return Displacement();
1452 
1453  return *p_z;
1454  }
1455 
1456 
1457  Distance SurfacePoint::GetXSigma() const {
1458  if(!p_rectCovar) return Distance();
1459 
1460  return Distance(sqrt((*p_rectCovar)(0, 0)), Distance::Kilometers);
1461  }
1462 
1463 
1464  Distance SurfacePoint::GetYSigma() const {
1465  if(!p_rectCovar) return Distance();
1466 
1467  return Distance(sqrt((*p_rectCovar)(1, 1)), Distance::Kilometers);
1468  }
1469 
1470 
1471  Distance SurfacePoint::GetZSigma() const {
1472  if(!p_rectCovar) return Distance();
1473 
1474  return Distance(sqrt((*p_rectCovar)(2, 2)), Distance::Kilometers);
1475  }
1476 
1477 
1491  double SurfacePoint::GetWeight(CoordinateType type, CoordIndex index) {
1492  double value = 0; // See first TODO in GetCoord
1493 
1494  switch (type) {
1495 
1496  case Latitudinal:
1497 
1498  switch (index) {
1499 
1500  case One:
1501  value = GetLatWeight(); // 1/radians**2
1502  break;
1503 
1504  case Two:
1505  value = GetLonWeight(); // 1/radians**2
1506  break;
1507 
1508  case Three:
1509  value = GetLocalRadiusWeight(); // 1/km**2
1510  break;
1511 
1512  default:
1513  IString msg = "Invalid coordinate index (must be less than 3).";
1514  throw IException(IException::Programmer, msg, _FILEINFO_);
1515  }
1516  break;
1517 
1518  case Rectangular:
1519 
1520  switch (index) {
1521 
1522  case One:
1523  value = GetXWeight(); // 1/km**2
1524  break;
1525 
1526  case Two:
1527  value = GetYWeight(); // 1/km**2
1528  break;
1529 
1530  case Three:
1531  value = GetZWeight(); // 1/km**2
1532  break;
1533 
1534  default:
1535  IString msg = "Invalid coordinate index (must be less than 3).";
1536  throw IException(IException::Programmer, msg, _FILEINFO_);
1537  }
1538  break;
1539 
1540  default:
1541  IString msg ="Unknown surface point coordinate type enum [" + toString(type) + "]." ;
1542  throw IException(IException::Programmer, msg, _FILEINFO_);
1543  }
1544  return value;
1545  }
1546 
1547 
1553  double SurfacePoint::GetXWeight() const {
1554 
1555  double dXSigma = GetXSigma().kilometers();
1556 
1557  if (dXSigma <= 0.0 ) {
1558  IString msg = "SurfacePoint::GetXWeight(): Sigma <= 0.0";
1559  throw IException(IException::Programmer, msg, _FILEINFO_);
1560  }
1561 
1562  return 1.0/(dXSigma*dXSigma);
1563  }
1564 
1565 
1571  double SurfacePoint::GetYWeight() const {
1572 
1573  double dYSigma = GetYSigma().kilometers();
1574 
1575  if (dYSigma <= 0.0 ) {
1576  IString msg = "SurfacePoint::GetYWeight(): Sigma <= 0.0";
1577  throw IException(IException::Programmer, msg, _FILEINFO_);
1578  }
1579 
1580  return 1.0/(dYSigma*dYSigma);
1581  }
1582 
1583 
1589  double SurfacePoint::GetZWeight() const {
1590 
1591  double dZSigma = GetZSigma().kilometers();
1592 
1593  if (dZSigma <= 0.0 ) {
1594  IString msg = "SurfacePoint::GetZWeight(): Sigma <= 0.0";
1595  throw IException(IException::Programmer, msg, _FILEINFO_);
1596  }
1597 
1598  return 1.0/(dZSigma*dZSigma);
1599  }
1600 
1601 
1602  symmetric_matrix<double, upper> SurfacePoint::GetRectangularMatrix
1603  (SurfacePoint::CoordUnits units) const {
1604  if(!p_rectCovar) {
1605  symmetric_matrix<double, upper> tmp(3);
1606  tmp.clear();
1607  return tmp;
1608  }
1609 
1610  // Make sure the units are valid
1611  if (units != Kilometers && units != Meters) {
1612  IString msg = "Units must be Kilometers or Meters";
1613  throw IException(IException::Programmer, msg, _FILEINFO_);
1614  }
1615 
1616  symmetric_matrix<double, upper> covar(3);
1617  covar.clear();
1618 
1619  switch (units) {
1620 
1621  case Meters:
1622  // Convert member matrix to Meters to return
1623  covar(0,0) = (*p_rectCovar)(0,0)*1.0e6;
1624  covar(0,1) = (*p_rectCovar)(0,1)*1.0e6;
1625  covar(0,2) = (*p_rectCovar)(0,2)*1.0e6;
1626  covar(1,1) = (*p_rectCovar)(1,1)*1.0e6;
1627  covar(1,2) = (*p_rectCovar)(1,2)*1.0e6;
1628  covar(2,2) = (*p_rectCovar)(2,2)*1.0e6;
1629  return covar;
1630  break;
1631 
1632  case Kilometers:
1633  return *p_rectCovar;
1634  break;
1635 
1636  default:
1637  IString msg = "Unrecognized unit for a Displacement (must be meters or kilometers).";
1638  throw IException(IException::Programmer, msg, _FILEINFO_);
1639  }
1640 
1641  return *p_rectCovar;
1642  }
1643 
1644 
1645  Angle SurfacePoint::GetLatSigma() const {
1646  if(!p_sphereCovar)
1647  return Angle();
1648 
1649  return Angle(sqrt((*p_sphereCovar)(0, 0)), Angle::Radians);
1650  }
1651 
1652 
1653  Angle SurfacePoint::GetLonSigma() const {
1654  if(!p_sphereCovar)
1655  return Angle();
1656 
1657  return Angle(sqrt((*p_sphereCovar)(1, 1)), Angle::Radians);
1658  }
1659 
1660 
1665  Latitude SurfacePoint::GetLatitude() const {
1666  if (!Valid())
1667  return Latitude();
1668 
1669  // TODO Scale for accuracy with coordinate of largest magnitude
1670  double x = p_x->meters();
1671  double y = p_y->meters();
1672  double z = p_z->meters();
1673 
1674  if (x != 0. || y != 0. || z != 0.)
1675  return Latitude(atan2(z, sqrt(x*x + y*y) ), Angle::Radians);
1676  else
1677  return Latitude();
1678  }
1679 
1680 
1685  Longitude SurfacePoint::GetLongitude() const {
1686  if (!Valid())
1687  return Longitude();
1688 
1689  double x = p_x->meters();
1690  double y = p_y->meters();
1691 
1692  if(x == 0.0 && y == 0.0) {
1693  return Longitude(0, Angle::Radians);
1694  }
1695 
1696  double lon = atan2(y, x);
1697  if (lon < 0) {
1698  lon += 2 * PI;
1699  }
1700 
1701  return Longitude(lon, Angle::Radians);
1702  }
1703 
1704 
1709  void SurfacePoint::ComputeLocalRadius() {
1710  static const Displacement zero(0, Displacement::Meters);
1711  if (Valid()) {
1712  double x = p_x->meters();
1713  double y = p_y->meters();
1714  double z = p_z->meters();
1715 
1716  p_localRadius = Distance(sqrt(x*x + y*y + z*z), Distance::Meters);
1717  }
1718  else if (*p_x == zero && *p_y == zero && *p_z == zero) { // for backwards compatability
1719  p_localRadius = Distance(0., Distance::Meters);
1720  }
1721  else { // Invalid point
1722  IString msg = "SurfacePoint::Can't compute local radius on invalid point";
1723  throw IException(IException::Programmer, msg, _FILEINFO_);
1724  }
1725  }
1726 
1727 
1732  Distance SurfacePoint::GetLocalRadius() const {
1733  return p_localRadius;
1734  }
1735 
1736 
1747  Distance SurfacePoint::GetLatSigmaDistance() const {
1748  double d = LatitudeToMeters(GetLatSigma().radians());
1749 
1750  if (d > 1.0e-50) {
1751  return Distance(d, Distance::Meters);
1752  }
1753  else {
1754  return Distance();
1755  }
1756  }
1757 
1758 
1763  Distance SurfacePoint::GetLonSigmaDistance() const{
1764  // return lonSigmaDistance;
1765  double d = LongitudeToMeters(GetLonSigma().radians());
1766 // TODO What do we do when the scaling radius is 0 (at the pole)?
1767  // if (d > DBL_EPSILON) {
1768  return Distance(d, Distance::Meters);
1769  // }
1770  // else { // Too close to the pole
1771  // return Distance();
1772  // }
1773  }
1774 
1775 
1776  Distance SurfacePoint::GetLocalRadiusSigma() const {
1777  if(!p_sphereCovar)
1778  return Distance();
1779 
1780  return Distance(sqrt((*p_sphereCovar)(2, 2)), Distance::Kilometers);
1781  }
1782 
1783 
1784  symmetric_matrix<double, upper> SurfacePoint::GetSphericalMatrix
1785  (SurfacePoint::CoordUnits units) const {
1786  if(!p_sphereCovar) {
1787  symmetric_matrix<double, upper> tmp(3);
1788  tmp.clear();
1789  return tmp;
1790  }
1791 
1792  // Make sure the units are valid
1793  if (units != Kilometers && units != Meters) {
1794  IString msg = "Units must be Kilometers or Meters";
1795  throw IException(IException::Programmer, msg, _FILEINFO_);
1796  }
1797 
1798  symmetric_matrix<double, upper> covar(3);
1799  covar.clear();
1800 
1801  switch (units) {
1802 
1803  case Meters:
1804  // Convert member matrix to Meters to return
1805  covar(0,0) = (*p_sphereCovar)(0,0);
1806  covar(0,1) = (*p_sphereCovar)(0,1);
1807  covar(0,2) = (*p_sphereCovar)(0,2)*1000.;
1808  covar(1,1) = (*p_sphereCovar)(1,1);
1809  covar(1,2) = (*p_sphereCovar)(1,2)*1000.;
1810  covar(2,2) = (*p_sphereCovar)(2,2)*1.0e6;
1811  return covar;
1812  break;
1813 
1814  case Kilometers:
1815  return *p_sphereCovar;
1816  break;
1817 
1818  default:
1819  IString msg = "Unrecognized unit for a Displacement (must be meters or kilometers).";
1820  throw IException(IException::Programmer, msg, _FILEINFO_);
1821  }
1822 
1823  return *p_sphereCovar;
1824  }
1825 
1826 
1832  double SurfacePoint::GetLatWeight() const {
1833  double dlatSigma = GetLatSigma().radians();
1834 
1835  if( dlatSigma <= 0.0 ) {
1836  IString msg = "SurfacePoint::GetLatWeight(): Sigma <= 0.0";
1837  throw IException(IException::Programmer, msg, _FILEINFO_);
1838  }
1839 
1840  return 1.0/(dlatSigma*dlatSigma);
1841  }
1842 
1848  double SurfacePoint::GetLonWeight() const {
1849  double dlonSigma = GetLonSigma().radians();
1850 
1851  if( dlonSigma <= 0.0 ) {
1852  IString msg = "SurfacePoint::GetLonWeight(): Sigma <= 0.0";
1853  throw IException(IException::Programmer, msg, _FILEINFO_);
1854  }
1855 
1856  return 1.0/(dlonSigma*dlonSigma);
1857  }
1858 
1864  double SurfacePoint::GetLocalRadiusWeight() const {
1865 
1866  double dlocalRadiusSigma = GetLocalRadiusSigma().kilometers();
1867 
1868  if (dlocalRadiusSigma <= 0.0 ) {
1869  IString msg = "SurfacePoint::GetRadWeight(): Sigma <= 0.0";
1870  throw IException(IException::Programmer, msg, _FILEINFO_);
1871  }
1872 
1873  return 1.0/(dlocalRadiusSigma*dlocalRadiusSigma);
1874  }
1875 
1880  Distance SurfacePoint::GetDistanceToPoint(const SurfacePoint &other) const {
1881 
1882  if(!Valid() || !other.Valid())
1883  return Distance();
1884 
1885  return GetDistanceToPoint(other,
1886  ((GetLocalRadius() + other.GetLocalRadius()) / 2.0));
1887  }
1888 
1889 
1897  Distance SurfacePoint::GetDistanceToPoint(const SurfacePoint &other,
1898  const Distance &sphereRadius) const {
1899  if(!Valid() || !other.Valid())
1900  return Distance();
1901 
1902  // Convert lat/lon values to radians
1903  const Angle &latitude = GetLatitude();
1904  const Angle &longitude = GetLongitude();
1905  const Angle &otherLatitude = other.GetLatitude();
1906  const Angle &otherLongitude = other.GetLongitude();
1907 
1908  // The harvestine method:
1909  // http://en.wikipedia.org/wiki/Haversine_formula
1910  Angle deltaLat = latitude - otherLatitude;
1911  Angle deltaLon = longitude - otherLongitude;
1912 
1913  double haversinLat = sin(deltaLat.radians() / 2.0);
1914  haversinLat *= haversinLat;
1915 
1916  double haversinLon = sin(deltaLon.radians() / 2.0);
1917  haversinLon *= haversinLon;
1918 
1919  double a = haversinLat + cos(latitude.radians()) *
1920  cos(otherLatitude.radians()) *
1921  haversinLon;
1922 
1923  double c = 2 * atan(sqrt(a) / sqrt(1 - a));
1924 
1925  return sphereRadius * c;
1926  }
1927 
1928 
1929  bool SurfacePoint::operator==(const SurfacePoint &other) const {
1930  bool equal = true;
1931 
1932  if(equal && p_x && p_y && p_z && other.p_x && other.p_y && other.p_z) {
1933  equal = equal && *p_x == *other.p_x;
1934  equal = equal && *p_y == *other.p_y;
1935  equal = equal && *p_z == *other.p_z;
1936  }
1937  else if(equal) {
1938  equal = equal && p_x == NULL && other.p_x == NULL;
1939  equal = equal && p_y == NULL && other.p_y == NULL;
1940  equal = equal && p_z == NULL && other.p_z == NULL;
1941  }
1942 
1943  if(equal && p_rectCovar) {
1944  equal = equal && (*p_rectCovar)(0, 0) == (*other.p_rectCovar)(0, 0);
1945  equal = equal && (*p_rectCovar)(0, 1) == (*other.p_rectCovar)(0, 1);
1946  equal = equal && (*p_rectCovar)(0, 2) == (*other.p_rectCovar)(0, 2);
1947  equal = equal && (*p_rectCovar)(1, 1) == (*other.p_rectCovar)(1, 1);
1948  equal = equal && (*p_rectCovar)(1, 2) == (*other.p_rectCovar)(1, 2);
1949  equal = equal && (*p_rectCovar)(2, 2) == (*other.p_rectCovar)(2, 2);
1950  }
1951  else if(equal) {
1952  equal = equal && p_rectCovar == NULL && other.p_rectCovar == NULL;
1953  }
1954 
1955  if(equal && p_sphereCovar) {
1956  equal = equal && (*p_sphereCovar)(0, 0) == (*other.p_sphereCovar)(0, 0);
1957  equal = equal && (*p_sphereCovar)(0, 1) == (*other.p_sphereCovar)(0, 1);
1958  equal = equal && (*p_sphereCovar)(0, 2) == (*other.p_sphereCovar)(0, 2);
1959  equal = equal && (*p_sphereCovar)(1, 1) == (*other.p_sphereCovar)(1, 1);
1960  equal = equal && (*p_sphereCovar)(1, 2) == (*other.p_sphereCovar)(1, 2);
1961  equal = equal && (*p_sphereCovar)(2, 2) == (*other.p_sphereCovar)(2, 2);
1962  }
1963  else if(equal) {
1964  equal = equal && p_sphereCovar == NULL && other.p_sphereCovar == NULL;
1965  }
1966 
1967  return equal;
1968  }
1969 
1970  SurfacePoint &SurfacePoint::operator=(const SurfacePoint &other) {
1971  // The lazy way of doing this (free all memory and copy) is too expensive
1972  // in the default case!
1973  if(p_x && other.p_x &&
1974  p_y && other.p_y &&
1975  p_z && other.p_z &&
1976  !p_rectCovar && !other.p_rectCovar &&
1977  !p_sphereCovar && !other.p_sphereCovar) {
1978  *p_x = *other.p_x;
1979  *p_y = *other.p_y;
1980  *p_z = *other.p_z;
1981  }
1982  else {
1983  FreeAllocatedMemory();
1984 
1985  if(other.p_x) {
1986  p_x = new Displacement(*other.p_x);
1987  }
1988 
1989  if(other.p_y) {
1990  p_y = new Displacement(*other.p_y);
1991  }
1992 
1993  if(other.p_z) {
1994  p_z = new Displacement(*other.p_z);
1995  }
1996 
1997  if(other.p_rectCovar) {
1998  p_rectCovar = new symmetric_matrix<double, upper>(*other.p_rectCovar);
1999  }
2000 
2001  if(other.p_sphereCovar) {
2002  p_sphereCovar = new symmetric_matrix<double, upper>(*other.p_sphereCovar);
2003  }
2004  }
2005 
2006  // Finally initialize local radius to avoid using a previous value
2007  p_localRadius = other.GetLocalRadius();
2008 
2009  return *this;
2010  }
2011 
2012  void SurfacePoint::FreeAllocatedMemory() {
2013  if(p_x) {
2014  delete p_x;
2015  p_x = NULL;
2016  }
2017 
2018  if(p_y) {
2019  delete p_y;
2020  p_y = NULL;
2021  }
2022 
2023  if(p_z) {
2024  delete p_z;
2025  p_z = NULL;
2026  }
2027 
2028  if(p_rectCovar) {
2029  delete p_rectCovar;
2030  p_rectCovar = NULL;
2031  }
2032 
2033  if(p_sphereCovar) {
2034  delete p_sphereCovar;
2035  p_sphereCovar = NULL;
2036  }
2037  }
2038 }
Isis::Distance::kilometers
double kilometers() const
Get the distance in kilometers.
Definition: Distance.cpp:106
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::Latitude
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:51
Isis::SurfacePoint::p_rectCovar
boost::numeric::ublas::symmetric_matrix< double, boost::numeric::ublas::upper > * p_rectCovar
3x3 upper triangular covariance matrix rectangular coordinates
Definition: SurfacePoint.h:312
Isis::SurfacePoint::GetLatitude
Latitude GetLatitude() const
Return the body-fixed latitude for the surface point.
Definition: SurfacePoint.cpp:1665
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::Distance
Distance measurement, usually in meters.
Definition: Distance.h:34
Isis::Longitude
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:40
Isis::Displacement
Displacement is a signed length, usually in meters.
Definition: Displacement.h:31
Isis::Displacement::meters
double meters() const
Get the displacement in meters.
Definition: Displacement.cpp:73
Isis::SurfacePoint::CoordinateType
CoordinateType
Defines the coordinate typ, units, and coordinate index for some of the output methods.
Definition: SurfacePoint.h:139
Isis::Distance::isValid
bool isValid() const
Test if this distance has been initialized or not.
Definition: Distance.cpp:192
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Angle
Defines an angle and provides unit conversions.
Definition: Angle.h:45
Isis::SurfacePoint::GetLongitude
Longitude GetLongitude() const
Return the body-fixed longitude for the surface point.
Definition: SurfacePoint.cpp:1685
Isis::Null
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:95
Isis::Displacement::kilometers
double kilometers() const
Get the displacement in kilometers.
Definition: Displacement.cpp:94
Isis::SurfacePoint::GetLocalRadius
Distance GetLocalRadius() const
Return the radius of the surface point.
Definition: SurfacePoint.cpp:1732
std
Namespace for the standard library.
Isis::Angle::isValid
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition: Angle.cpp:95
Isis::Displacement::isValid
bool isValid() const
Test if this displacement has been initialized or not.
Definition: Displacement.cpp:141
Isis::Distance::meters
double meters() const
Get the distance in meters.
Definition: Distance.cpp:85
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::SurfacePoint::p_sphereCovar
boost::numeric::ublas::symmetric_matrix< double, boost::numeric::ublas::upper > * p_sphereCovar
3x3 upper triangular covariance matrix ocentric coordinates
Definition: SurfacePoint.h:315
Isis::SurfacePoint
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:132
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::Angle::radians
double radians() const
Convert an angle to a double.
Definition: Angle.h:226