USGS

Isis 3.0 Object Programmers' Reference

Home

SurfacePoint.cpp
1 #include "SurfacePoint.h"
2 
3 #include <SpiceUsr.h>
4 
5 #include "IException.h"
6 #include "IString.h"
7 #include "Latitude.h"
8 #include "Longitude.h"
9 
10 using namespace boost::numeric::ublas;
11 using namespace std;
12 
13 namespace Isis {
14 
19  SurfacePoint::SurfacePoint() {
20  InitCovariance();
21  InitPoint();
22  InitRadii();
23  }
24 
29  SurfacePoint::SurfacePoint(const SurfacePoint &other) {
30  if(other.p_majorAxis) {
31  p_majorAxis = new Distance(*other.p_majorAxis);
32  }
33  else {
34  p_majorAxis = NULL;
35  }
36 
37  if(other.p_minorAxis) {
38  p_minorAxis = new Distance(*other.p_minorAxis);
39  }
40  else {
41  p_minorAxis = NULL;
42  }
43 
44  if(other.p_polarAxis) {
45  p_polarAxis = new Distance(*other.p_polarAxis);
46  }
47  else {
48  p_polarAxis = NULL;
49  }
50 
51  if(other.p_x) {
52  p_x = new Displacement(*other.p_x);
53  }
54  else {
55  p_x = NULL;
56  }
57 
58  if(other.p_y) {
59  p_y = new Displacement(*other.p_y);
60  }
61  else {
62  p_y = NULL;
63  }
64 
65  if(other.p_z) {
66  p_z = new Displacement(*other.p_z);
67  }
68  else {
69  p_z = NULL;
70  }
71 
72  if(other.p_rectCovar) {
73  p_rectCovar = new symmetric_matrix<double, upper>(*other.p_rectCovar);
74  }
75  else {
76  p_rectCovar = NULL;
77  }
78 
79  if(other.p_sphereCovar) {
80  p_sphereCovar = new symmetric_matrix<double, upper>(*other.p_sphereCovar);
81  }
82  else {
83  p_sphereCovar = NULL;
84  }
85  }
86 
87 
95  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
96  const Distance &radius) {
97  InitCovariance();
98  InitPoint();
99  InitRadii();
100  SetSphericalPoint(lat, lon, radius);
101  }
102 
103 
104 
119  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
120  const Distance &radius, const Angle &latSigma, const Angle &lonSigma,
121  const Distance &radiusSigma) {
122  InitCovariance();
123  InitPoint();
124  InitRadii();
125  SetSpherical(lat, lon, radius, latSigma, lonSigma, radiusSigma);
126  }
127 
128 
134  SurfacePoint::SurfacePoint(const Latitude &lat, const Longitude &lon,
135  const Distance &radius, const symmetric_matrix<double, upper> &covar) {
136  InitCovariance();
137  InitPoint();
138  InitRadii();
139  SetSpherical(lat, lon, radius, covar);
140  }
141 
142 
150  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
151  const Displacement &z) {
152  InitCovariance();
153  InitPoint();
154  InitRadii();
155  SetRectangular(x, y, z);
156  }
157 
158 
173  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
174  const Displacement &z, const Distance &xSigma, const Distance &ySigma,
175  const Distance &zSigma) {
176  InitCovariance();
177  InitPoint();
178  InitRadii();
179  SetRectangular(x, y, z, xSigma, ySigma, zSigma);
180  }
181 
182 
192  SurfacePoint::SurfacePoint(const Displacement &x, const Displacement &y,
193  const Displacement &z, const symmetric_matrix<double, upper> &covar) {
194  InitCovariance();
195  InitPoint();
196  InitRadii();
197  SetRectangular(x, y, z, covar);
198  }
199 
200 
205  SurfacePoint::~SurfacePoint() {
206  FreeAllocatedMemory();
207  }
208 
209 
214  void SurfacePoint::InitCovariance() {
215  p_rectCovar = NULL;
216  p_sphereCovar = NULL;
217  }
218 
219 
224  void SurfacePoint::InitPoint() {
225  p_x = NULL;
226  p_y = NULL;
227  p_z = NULL;
228  }
229 
234  void SurfacePoint::InitRadii() {
235  p_majorAxis = NULL;
236  p_minorAxis = NULL;
237  p_polarAxis = NULL;
238  }
239 
240 
253  void SurfacePoint::SetRectangularPoint(const Displacement &x,
254  const Displacement &y, const Displacement &z) {
255 
256  if (!x.isValid() || !y.isValid() || !z.isValid()) {
257  IString msg = "x, y, and z must be set to valid displacements. One or "
258  "more coordinates have been set to an invalid displacement.";
259  throw IException(IException::User, msg, _FILEINFO_);
260  }
261 
262  if(p_x) {
263  *p_x = x;
264  }
265  else {
266  p_x = new Displacement(x);
267  }
268 
269  if(p_y) {
270  *p_y = y;
271  }
272  else {
273  p_y = new Displacement(y);
274  }
275 
276  if(p_z) {
277  *p_z = z;
278  }
279  else {
280  p_z = new Displacement(z);
281  }
282  }
283 
284 
299  void SurfacePoint::SetRectangular(const Displacement &x,
300  const Displacement &y, const Displacement &z, const Distance &xSigma,
301  const Distance &ySigma, const Distance &zSigma) {
302  SetRectangularPoint(x, y, z);
303 
304  if (xSigma.isValid() && ySigma.isValid() && zSigma.isValid())
305  SetRectangularSigmas(xSigma, ySigma, zSigma);
306  }
307 
308 
320  void SurfacePoint::SetRectangular(Displacement x, Displacement y, Displacement z,
321  const symmetric_matrix<double,upper>& covar) {
322  SetRectangularPoint(x, y, z);
323  SetRectangularMatrix(covar);
324  }
325 
326 
335  void SurfacePoint::SetRectangularSigmas(const Distance &xSigma,
336  const Distance &ySigma,
337  const Distance &zSigma) {
338  // Is this error checking necessary or should we just use Distance?????
339  if (!xSigma.isValid() || !ySigma.isValid() || !zSigma.isValid()) {
340  IString msg = "x sigma, y sigma , and z sigma must be set to valid "
341  "distances. One or more sigmas have been set to an invalid distance.";
342  throw IException(IException::User, msg, _FILEINFO_);
343  }
344 
345  symmetric_matrix<double,upper> covar(3);
346  covar.clear();
347  covar(0,0) = xSigma.meters() * xSigma.meters();
348  covar(1,1) = ySigma.meters() * ySigma.meters();
349  covar(2,2) = zSigma.meters() * zSigma.meters();
350  SetRectangularMatrix(covar);
351  }
352 
353 
361  void SurfacePoint::SetRectangularMatrix(
362  const symmetric_matrix<double, upper> &covar) {
363  // Make sure the point is set first
364  if (!Valid()) {
365  IString msg = "A point must be set before a variance/covariance matrix "
366  "can be set.";
367  throw IException(IException::Programmer, msg, _FILEINFO_);
368  }
369 
370  if(p_rectCovar) {
371  *p_rectCovar = covar;
372  }
373  else {
374  p_rectCovar = new symmetric_matrix<double, upper>(covar);
375  }
376 
377  SpiceDouble rectMat[3][3];
378 
379  // Compute the local radius of the surface point
380  double x2 = p_x->meters() * p_x->meters();
381  double y2 = p_y->meters() * p_y->meters();
382  double z = p_z->meters();
383  double radius = sqrt(x2 + y2 + z*z);
384 
385  // Should we use a matrix utility?
386  rectMat[0][0] = covar(0,0);
387  rectMat[0][1] = rectMat[1][0] = covar(0,1);
388  rectMat[0][2] = rectMat[2][0] = covar(0,2);
389  rectMat[1][1] = covar(1,1);
390  rectMat[1][2] = rectMat[2][1] = covar(1,2);
391  rectMat[2][2] = covar(2,2);
392 
393  // Compute the Jacobian
394  SpiceDouble J[3][3];
395  double zOverR = p_z->meters() / radius;
396  double r2 = radius*radius;
397  double denom = r2*radius*sqrt(1.0 - (zOverR*zOverR));
398  J[0][0] = -p_x->meters() * p_z->meters() / denom;
399  J[0][1] = -p_y->meters() * p_z->meters() / denom;
400  J[0][2] = (r2 - p_z->meters() * p_z->meters()) / denom;
401  J[1][0] = -p_y->meters() / (x2 + y2);
402  J[1][1] = p_x->meters() / (x2 + y2);
403  J[1][2] = 0.0;
404  J[2][0] = p_x->meters() / radius;
405  J[2][1] = p_y->meters() / radius;
406  J[2][2] = p_z->meters() / radius;
407 
408  if(!p_sphereCovar)
409  p_sphereCovar = new symmetric_matrix<double, upper>(3);
410 
411  SpiceDouble mat[3][3];
412  mxm_c (J, rectMat, mat);
413  mxmt_c (mat, J, mat);
414  (*p_sphereCovar)(0,0) = mat[0][0];
415  (*p_sphereCovar)(0,1) = mat[0][1];
416  (*p_sphereCovar)(0,2) = mat[0][2];
417  (*p_sphereCovar)(1,1) = mat[1][1];
418  (*p_sphereCovar)(1,2) = mat[1][2];
419  (*p_sphereCovar)(2,2) = mat[2][2];
420  }
421 
422 
434  void SurfacePoint::SetSphericalPoint(const Latitude &lat,
435  const Longitude &lon,
436  const Distance &radius) {
437 // Is error checking necessary or does Latitude, Longitude, and Distance handle it?????
438  if (!lat.isValid() || !lon.isValid() || !radius.isValid()) {
439  IString msg = "Latitude, longitude, or radius is an invalid value.";
440  throw IException(IException::User, msg, _FILEINFO_);
441  }
442 
443  SpiceDouble dlat = (double) lat.radians();
444  SpiceDouble dlon = (double) lon.radians();
445  SpiceDouble dradius = radius.kilometers();
446 
447  SpiceDouble rect[3];
448  latrec_c ( dradius, dlon, dlat, rect);
449 
450  SetRectangularPoint(Displacement(rect[0], Displacement::Kilometers),
451  Displacement(rect[1], Displacement::Kilometers),
452  Displacement(rect[2], Displacement::Kilometers));
453  }
454 
455 
469  void SurfacePoint::SetSpherical(const Latitude &lat, const Longitude &lon,
470  const Distance &radius, const Angle &latSigma, const Angle &lonSigma,
471  const Distance &radiusSigma) {
472  SetSphericalPoint(lat, lon, radius);
473 
474  if (latSigma.isValid() && lonSigma.isValid() && radiusSigma.isValid())
475  SetSphericalSigmas(latSigma, lonSigma, radiusSigma);
476  }
477 
478 
488  void SurfacePoint::SetSpherical(const Latitude &lat, const Longitude &lon,
489  const Distance &radius, const symmetric_matrix<double, upper> &covar) {
490  SetSphericalPoint(lat, lon, radius);
491  SetSphericalMatrix(covar);
492  }
493 
494 
503  void SurfacePoint::SetSphericalCoordinates(const Latitude &lat,
504  const Longitude &lon, const Distance &radius) {
505 
506  SetSphericalPoint(lat, lon, radius);
507  }
508 
509 
517  void SurfacePoint::SetSphericalSigmas(const Angle &latSigma,
518  const Angle &lonSigma,
519  const Distance &radiusSigma) {
520  if (latSigma.isValid() && lonSigma.isValid() && radiusSigma.isValid()) {
521  symmetric_matrix<double,upper> covar(3);
522  covar.clear();
523 
524  double sphericalCoordinate;
525  sphericalCoordinate = (double) latSigma.radians();
526  covar(0,0) = sphericalCoordinate*sphericalCoordinate;
527  sphericalCoordinate = (double) lonSigma.radians();
528  covar(1,1) = sphericalCoordinate*sphericalCoordinate;
529  sphericalCoordinate = (double) radiusSigma.meters();
530  covar(2,2) = sphericalCoordinate*sphericalCoordinate;
531 
532  SetSphericalMatrix(covar);
533  }
534  else {
535  delete p_sphereCovar;
536  p_sphereCovar = NULL;
537 
538  delete p_rectCovar;
539  p_rectCovar = NULL;
540  }
541  }
542 
543 
555  void SurfacePoint::SetSphericalSigmasDistance(const Distance &latSigma,
556  const Distance &lonSigma, const Distance &radiusSigma) {
557 
558  if (!p_majorAxis || !p_minorAxis || !p_polarAxis || !p_majorAxis->isValid() ||
559  !p_minorAxis->isValid() || !p_polarAxis->isValid()) {
560  IString msg = "In order to use sigmas in meter units, the equitorial "
561  "radius must be set with a call to SetRadii or an appropriate "
562  "constructor";
563  throw IException(IException::Programmer, msg, _FILEINFO_);
564  }
565 
566  if (!Valid()) {
567  IString msg = "Cannot set spherical sigmas on an invalid surface point";
568  throw IException(IException::Programmer, msg, _FILEINFO_);
569  }
570 
571  double scaledLatSig = latSigma / *p_majorAxis;
572  double scaledLonSig = lonSigma * cos((double)GetLatitude().radians())
573  / *p_majorAxis;
574  SetSphericalSigmas( Angle(scaledLatSig, Angle::Radians),
575  Angle(scaledLonSig, Angle::Radians), radiusSigma);
576  }
577 
578 
586  void SurfacePoint::SetSphericalMatrix(
587  const symmetric_matrix<double, upper> & covar) {
588 
589  // Make sure the point is set first
590  if (!Valid()) {
591  IString msg = "A point must be set before a variance/covariance matrix "
592  "can be set.";
593  throw IException(IException::Programmer, msg, _FILEINFO_);
594  }
595 
596  if(p_sphereCovar) {
597  *p_sphereCovar = covar;
598  }
599  else {
600  p_sphereCovar = new symmetric_matrix<double, upper>(covar);
601  }
602 
603  SpiceDouble sphereMat[3][3];
604 
605  sphereMat[0][0] = covar(0,0);
606  sphereMat[0][1] = sphereMat[1][0] = covar(0,1);
607  sphereMat[0][2] = sphereMat[2][0] = covar(0,2);
608  sphereMat[1][1] = covar(1,1);
609  sphereMat[1][2] = sphereMat[2][1] = covar(1,2);
610  sphereMat[2][2] = covar(2,2);
611 
612 // std::cout<<"Ocovar = "<<sphereMat[0][0]<<" "<<sphereMat[0][1]<<" "<<sphereMat[0][2]<<std::endl
613 // <<" "<<sphereMat[1][0]<<" "<<sphereMat[1][1]<<" "<<sphereMat[1][2]<<std::endl
614 // <<" "<<sphereMat[2][0]<<" "<<sphereMat[2][1]<<" "<<sphereMat[2][2]<<std::endl;
615 
616  // Get the lat/lon/radius of the point
617  double lat = (double) GetLatitude().radians();
618  double lon = (double) GetLongitude().radians();
619  double radius = (double) GetLocalRadius().meters();
620 
621  // Compute the Jacobian
622  SpiceDouble J[3][3];
623  double cosPhi = cos(lat);
624  double sinPhi = sin(lat);
625  double cosLamda = cos(lon);
626  double sinLamda = sin(lon);
627  double rcosPhi = radius*cosPhi;
628  double rsinPhi = radius*sinPhi;
629  J[0][0] = -rsinPhi * cosLamda;
630  J[0][1] = -rcosPhi * sinLamda;
631  J[0][2] = cosPhi * cosLamda;
632  J[1][0] = -rsinPhi * sinLamda;
633  J[1][1] = rcosPhi * cosLamda;
634  J[1][2] = cosPhi * sinLamda;
635  J[2][0] = rcosPhi;
636  J[2][1] = 0.0;
637  J[2][2] = sinPhi;
638 
639  if(!p_rectCovar)
640  p_rectCovar = new symmetric_matrix<double, upper>(3);
641 
642  SpiceDouble mat[3][3];
643  mxm_c (J, sphereMat, mat);
644  mxmt_c (mat, J, mat);
645  // TODO Test to see if only the upper triangular portion of the matrix needs to be set
646  (*p_rectCovar)(0,0) = mat[0][0];
647  (*p_rectCovar)(0,1) = mat[0][1];
648  (*p_rectCovar)(0,2) = mat[0][2];
649  (*p_rectCovar)(1,1) = mat[1][1];
650  (*p_rectCovar)(1,2) = mat[1][2];
651  (*p_rectCovar)(2,2) = mat[2][2];
652 
653 // std::cout<<"Rcovar = "<<p_rectCovar(0,0)<<" "<<p_rectCovar(0,1)<<" "<<p_rectCovar(0,2)<<std::endl
654 // <<" "<<p_rectCovar(1,0)<<" "<<p_rectCovar(1,1)<<" "<<p_rectCovar(1,2)<<std::endl
655 // <<" "<<p_rectCovar(2,0)<<" "<<p_rectCovar(2,1)<<" "<<p_rectCovar(2,2)<<std::endl;
656  }
657 
658 
668  void SurfacePoint::ToNaifArray(double naifOutput[3]) const {
669  if(Valid()) {
670  naifOutput[0] = p_x->kilometers();
671  naifOutput[1] = p_y->kilometers();
672  naifOutput[2] = p_z->kilometers();
673  }
674  else {
675  IString msg = "Cannot convert an invalid surface point to a naif array";
676  throw IException(IException::Programmer, msg, _FILEINFO_);
677  }
678  }
679 
689  void SurfacePoint::FromNaifArray(const double naifValues[3]) {
690  if(p_x && p_y && p_z) {
691  p_x->setKilometers(naifValues[0]);
692  p_y->setKilometers(naifValues[1]);
693  p_z->setKilometers(naifValues[2]);
694  }
695  else {
696  p_x = new Displacement(naifValues[0], Displacement::Kilometers);
697  p_y = new Displacement(naifValues[1], Displacement::Kilometers);
698  p_z = new Displacement(naifValues[2], Displacement::Kilometers);
699  }
700  }
701 
702 
710  void SurfacePoint::SetRadii(const Distance &majorRadius,
711  const Distance &minorRadius,
712  const Distance &polarRadius) {
713 
714  if (!majorRadius.isValid() ||
715  !minorRadius.isValid() ||
716  !polarRadius.isValid()) {
717  IString msg = "Radii must be set to valid distances. One or more radii "
718  "have been set to an invalid distance.";
719  throw IException(IException::Programmer, msg, _FILEINFO_);
720  }
721 
722  if(p_majorAxis) {
723  *p_majorAxis = majorRadius;
724  }
725  else {
726  p_majorAxis = new Distance(majorRadius);
727  }
728 
729  if(p_minorAxis) {
730  *p_minorAxis = minorRadius;
731  }
732  else {
733  p_minorAxis = new Distance(minorRadius);
734  }
735 
736  if(p_polarAxis) {
737  *p_polarAxis = polarRadius;
738  }
739  else {
740  p_polarAxis = new Distance(polarRadius);
741  }
742  }
743 
744 
751  void SurfacePoint::ResetLocalRadius(const Distance &radius) {
752 
753  if (!radius.isValid()) {
754  IString msg = "Radius value must be a valid Distance.";
755  throw IException(IException::Programmer, msg, _FILEINFO_);
756  }
757 
758  if (!p_x || !p_y || !p_z || !p_x->isValid() || !p_y->isValid() ||
759  !p_z->isValid()) {
760  IString msg = "In order to reset the local radius, a Surface Point must "
761  "already be set.";
762  throw IException(IException::Programmer, msg, _FILEINFO_);
763  }
764 
765  SpiceDouble lat = (double) GetLatitude().radians();
766  SpiceDouble lon = (double) GetLongitude().radians();
767  SpiceDouble rect[3];
768  latrec_c ((SpiceDouble) radius.kilometers(), lon, lat, rect);
769  p_x->setKilometers(rect[0]);
770  p_y->setKilometers(rect[1]);
771  p_z->setKilometers(rect[2]);
772 
773  // TODO What should be done to the variance/covariance matrix when the
774  // radius is reset??? With Bundle updates will this functionality be
775  // obsolete??? Ask Ken
776  }
777 
778 
779  bool SurfacePoint::Valid() const {
780  static const Displacement zero(0, Displacement::Meters);
781  return p_x && p_y && p_z && p_x->isValid() && p_y->isValid() && p_z->isValid() &&
782  (*p_x != zero || *p_y != zero || *p_z != zero);
783  }
784 
785 
786  Displacement SurfacePoint::GetX() const {
787  if(!p_x) return Displacement();
788 
789  return *p_x;
790  }
791 
792 
793  Displacement SurfacePoint::GetY() const {
794  if(!p_y) return Displacement();
795 
796  return *p_y;
797  }
798 
799 
800  Displacement SurfacePoint::GetZ() const {
801  if(!p_z) return Displacement();
802 
803  return *p_z;
804  }
805 
806 
807  Distance SurfacePoint::GetXSigma() const {
808  if(!p_rectCovar) return Distance();
809 
810  return Distance(sqrt((*p_rectCovar)(0, 0)), Distance::Meters);
811  }
812 
813 
814  Distance SurfacePoint::GetYSigma() const {
815  if(!p_rectCovar) return Distance();
816 
817  return Distance(sqrt((*p_rectCovar)(1, 1)), Distance::Meters);
818  }
819 
820 
821  Distance SurfacePoint::GetZSigma() const {
822  if(!p_rectCovar) return Distance();
823 
824  return Distance(sqrt((*p_rectCovar)(2, 2)), Distance::Meters);
825  }
826 
827 
828  symmetric_matrix<double, upper> SurfacePoint::GetRectangularMatrix()
829  const {
830  if(!p_rectCovar) {
831  symmetric_matrix<double, upper> tmp(3);
832  tmp.clear();
833  return tmp;
834  }
835 
836  return *p_rectCovar;
837  }
838 
839 
840  Angle SurfacePoint::GetLatSigma() const {
841  if(!p_sphereCovar)
842  return Angle();
843 
844  return Angle(sqrt((*p_sphereCovar)(0, 0)), Angle::Radians);
845  }
846 
847 
848  Angle SurfacePoint::GetLonSigma() const {
849  if(!p_sphereCovar)
850  return Angle();
851 
852  return Angle(sqrt((*p_sphereCovar)(1, 1)), Angle::Radians);
853  }
854 
855 
860  Latitude SurfacePoint::GetLatitude() const {
861  if (!Valid())
862  return Latitude();
863 
864  // TODO Scale for accuracy with coordinate of largest magnitude
865  double x = p_x->meters();
866  double y = p_y->meters();
867  double z = p_z->meters();
868 
869  if (x != 0. || y != 0. || z != 0.)
870  return Latitude(atan2(z, sqrt(x*x + y*y) ), Angle::Radians);
871  else
872  return Latitude();
873  }
874 
875 
880  Longitude SurfacePoint::GetLongitude() const {
881  if (!Valid())
882  return Longitude();
883 
884  double x = p_x->meters();
885  double y = p_y->meters();
886 
887  if(x == 0.0 && y == 0.0) {
888  return Longitude(0, Angle::Radians);
889  }
890 
891  double lon = atan2(y, x);
892  if (lon < 0) {
893  lon += 2 * PI;
894  }
895 
896  return Longitude(lon, Angle::Radians);
897  }
898 
899 
904  Distance SurfacePoint::GetLocalRadius() const {
905  if (!Valid())
906  return Distance();
907 
908  double x = p_x->meters();
909  double y = p_y->meters();
910  double z = p_z->meters();
911 
912  return Distance(sqrt(x*x + y*y + z*z), Distance::Meters);
913  }
914 
915 
920  Distance SurfacePoint::GetLatSigmaDistance() const {
921  Distance latSigmaDistance;
922 
923  if(Valid()) {
924  Angle latSigma = GetLatSigma();
925 
926  if (latSigma.isValid()) {
927  if (!p_majorAxis || !p_majorAxis->isValid()) {
928  IString msg = "In order to calculate sigmas in meter units, the "
929  "equitorial radius must be set with a call to SetRadii.";
930  throw IException(IException::Programmer, msg, _FILEINFO_);
931  }
932 
933  // Convert from radians to meters
934  latSigmaDistance = latSigma.radians() * *p_majorAxis;
935  }
936  }
937 
938  return latSigmaDistance;
939  }
940 
941 
946  Distance SurfacePoint::GetLonSigmaDistance() const {
947  Distance lonSigmaDistance;
948 
949  if(Valid()) {
950  Angle lonSigma = GetLonSigma();
951 
952  if (lonSigma.isValid()) {
953  if (!p_majorAxis || !p_majorAxis->isValid()) {
954  IString msg = "In order to calculate sigmas in meter units, the "
955  "equitorial radius must be set with a call to SetRadii.";
956  throw IException(IException::Programmer, msg, _FILEINFO_);
957  }
958 
959  Latitude lat = GetLatitude();
960  double scaler = cos(lat.radians());
961 
962  // Convert from radians to meters and return
963  if (scaler != 0.)
964  lonSigmaDistance = lonSigma.radians() * *p_majorAxis / scaler;
965  }
966  }
967 
968  return lonSigmaDistance;
969  }
970 
971 
972  Distance SurfacePoint::GetLocalRadiusSigma() const {
973  if(!p_sphereCovar)
974  return Distance();
975 
976  return Distance(sqrt((*p_sphereCovar)(2, 2)), Distance::Meters);
977  }
978 
979 
980  symmetric_matrix<double, upper> SurfacePoint::GetSphericalMatrix() const {
981  if(!p_sphereCovar) {
982  symmetric_matrix<double, upper> tmp(3);
983  tmp.clear();
984  return tmp;
985  }
986 
987  return *p_sphereCovar;
988  }
989 
990 
996  double SurfacePoint::GetLatWeight() const {
997  double dlatSigma = GetLatSigma().radians();
998 
999  if( dlatSigma <= 0.0 ) {
1000  IString msg = "SurfacePoint::GetLatWeight(): Sigma <= 0.0";
1001  throw IException(IException::Programmer, msg, _FILEINFO_);
1002  }
1003 
1004  return 1.0/(dlatSigma*dlatSigma);
1005  }
1006 
1012  double SurfacePoint::GetLonWeight() const {
1013  double dlonSigma = GetLonSigma().radians();
1014 
1015  if( dlonSigma <= 0.0 ) {
1016  IString msg = "SurfacePoint::GetLonWeight(): Sigma <= 0.0";
1017  throw IException(IException::Programmer, msg, _FILEINFO_);
1018  }
1019 
1020  return 1.0/(dlonSigma*dlonSigma);
1021  }
1022 
1028  double SurfacePoint::GetLocalRadiusWeight() const {
1029 
1030  double dlocalRadiusSigma = GetLocalRadiusSigma().kilometers();
1031 
1032  if (dlocalRadiusSigma <= 0.0 ) {
1033  IString msg = "SurfacePoint::GetRadWeight(): Sigma <= 0.0";
1034  throw IException(IException::Programmer, msg, _FILEINFO_);
1035  }
1036 
1037  return 1.0/(dlocalRadiusSigma*dlocalRadiusSigma);
1038  }
1039 
1046  Distance SurfacePoint::GetDistanceToPoint(const SurfacePoint &other) const {
1047  if(p_majorAxis || p_minorAxis || p_polarAxis ||
1048  other.p_majorAxis || other.p_minorAxis || other.p_polarAxis) {
1049  IString msg = "SurfacePoint::GetDistanceToPoint not yet implemented for "
1050  "ellipsoids";
1051  throw IException(IException::Programmer, msg, _FILEINFO_);
1052  }
1053 
1054  if(!Valid() || !other.Valid())
1055  return Distance();
1056 
1057  return GetDistanceToPoint(other,
1058  ((GetLocalRadius() + other.GetLocalRadius()) / 2.0));
1059  }
1060 
1061 
1069  Distance SurfacePoint::GetDistanceToPoint(const SurfacePoint &other,
1070  const Distance &sphereRadius) const {
1071  if(!Valid() || !other.Valid())
1072  return Distance();
1073 
1074  // Convert lat/lon values to radians
1075  const Angle &latitude = GetLatitude();
1076  const Angle &longitude = GetLongitude();
1077  const Angle &otherLatitude = other.GetLatitude();
1078  const Angle &otherLongitude = other.GetLongitude();
1079 
1080  // The harvestine method:
1081  // http://en.wikipedia.org/wiki/Haversine_formula
1082  Angle deltaLat = latitude - otherLatitude;
1083  Angle deltaLon = longitude - otherLongitude;
1084 
1085  double haversinLat = sin(deltaLat.radians() / 2.0);
1086  haversinLat *= haversinLat;
1087 
1088  double haversinLon = sin(deltaLon.radians() / 2.0);
1089  haversinLon *= haversinLon;
1090 
1091  double a = haversinLat + cos(latitude.radians()) *
1092  cos(otherLatitude.radians()) *
1093  haversinLon;
1094 
1095  double c = 2 * atan(sqrt(a) / sqrt(1 - a));
1096 
1097  return sphereRadius * c;
1098  }
1099 
1100 
1101  bool SurfacePoint::operator==(const SurfacePoint &other) const {
1102  bool equal = true;
1103 
1104  if(equal && p_x && p_y && p_z && other.p_x && other.p_y && other.p_z) {
1105  equal = equal && *p_x == *other.p_x;
1106  equal = equal && *p_y == *other.p_y;
1107  equal = equal && *p_z == *other.p_z;
1108  }
1109  else if(equal) {
1110  equal = equal && p_x == NULL && other.p_x == NULL;
1111  equal = equal && p_y == NULL && other.p_y == NULL;
1112  equal = equal && p_z == NULL && other.p_z == NULL;
1113  }
1114 
1115  if(equal && p_majorAxis && p_minorAxis && p_polarAxis) {
1116  equal = equal && *p_majorAxis == *other.p_majorAxis;
1117  equal = equal && *p_minorAxis == *other.p_minorAxis;
1118  equal = equal && *p_polarAxis == *other.p_polarAxis;
1119  }
1120  else if(equal) {
1121  equal = equal && p_majorAxis == NULL && other.p_majorAxis == NULL;
1122  equal = equal && p_minorAxis == NULL && other.p_minorAxis == NULL;
1123  equal = equal && p_polarAxis == NULL && other.p_polarAxis == NULL;
1124  }
1125 
1126  if(equal && p_rectCovar) {
1127  equal = equal && (*p_rectCovar)(0, 0) == (*other.p_rectCovar)(0, 0);
1128  equal = equal && (*p_rectCovar)(0, 1) == (*other.p_rectCovar)(0, 1);
1129  equal = equal && (*p_rectCovar)(0, 2) == (*other.p_rectCovar)(0, 2);
1130  equal = equal && (*p_rectCovar)(1, 1) == (*other.p_rectCovar)(1, 1);
1131  equal = equal && (*p_rectCovar)(1, 2) == (*other.p_rectCovar)(1, 2);
1132  equal = equal && (*p_rectCovar)(2, 2) == (*other.p_rectCovar)(2, 2);
1133  }
1134  else if(equal) {
1135  equal = equal && p_rectCovar == NULL && other.p_rectCovar == NULL;
1136  }
1137 
1138  if(equal && p_sphereCovar) {
1139  equal = equal && (*p_sphereCovar)(0, 0) == (*other.p_sphereCovar)(0, 0);
1140  equal = equal && (*p_sphereCovar)(0, 1) == (*other.p_sphereCovar)(0, 1);
1141  equal = equal && (*p_sphereCovar)(0, 2) == (*other.p_sphereCovar)(0, 2);
1142  equal = equal && (*p_sphereCovar)(1, 1) == (*other.p_sphereCovar)(1, 1);
1143  equal = equal && (*p_sphereCovar)(1, 2) == (*other.p_sphereCovar)(1, 2);
1144  equal = equal && (*p_sphereCovar)(2, 2) == (*other.p_sphereCovar)(2, 2);
1145  }
1146  else if(equal) {
1147  equal = equal && p_sphereCovar == NULL && other.p_sphereCovar == NULL;
1148  }
1149 
1150  return equal;
1151  }
1152 
1153  SurfacePoint &SurfacePoint::operator=(const SurfacePoint &other) {
1154  // The lazy way of doing this (free all memory and copy) is too expensive
1155  // in the default case!
1156  if(p_x && other.p_x &&
1157  p_y && other.p_y &&
1158  p_z && other.p_z &&
1159  !p_majorAxis && !other.p_majorAxis &&
1160  !p_minorAxis && !other.p_minorAxis &&
1161  !p_polarAxis && !other.p_polarAxis &&
1162  !p_rectCovar && !other.p_rectCovar &&
1163  !p_sphereCovar && !other.p_sphereCovar) {
1164  *p_x = *other.p_x;
1165  *p_y = *other.p_y;
1166  *p_z = *other.p_z;
1167  }
1168  else {
1169  FreeAllocatedMemory();
1170  if(other.p_majorAxis) {
1171  p_majorAxis = new Distance(*other.p_majorAxis);
1172  }
1173 
1174  if(other.p_minorAxis) {
1175  p_minorAxis = new Distance(*other.p_minorAxis);
1176  }
1177 
1178  if(other.p_polarAxis) {
1179  p_polarAxis = new Distance(*other.p_polarAxis);
1180  }
1181 
1182  if(other.p_x) {
1183  p_x = new Displacement(*other.p_x);
1184  }
1185 
1186  if(other.p_y) {
1187  p_y = new Displacement(*other.p_y);
1188  }
1189 
1190  if(other.p_z) {
1191  p_z = new Displacement(*other.p_z);
1192  }
1193 
1194  if(other.p_rectCovar) {
1195  p_rectCovar = new symmetric_matrix<double, upper>(*other.p_rectCovar);
1196  }
1197 
1198  if(other.p_sphereCovar) {
1199  p_sphereCovar = new symmetric_matrix<double, upper>(*other.p_sphereCovar);
1200  }
1201  }
1202 
1203  return *this;
1204  }
1205 
1206  void SurfacePoint::FreeAllocatedMemory() {
1207  if(p_x) {
1208  delete p_x;
1209  p_x = NULL;
1210  }
1211 
1212  if(p_y) {
1213  delete p_y;
1214  p_y = NULL;
1215  }
1216 
1217  if(p_z) {
1218  delete p_z;
1219  p_z = NULL;
1220  }
1221 
1222  if(p_majorAxis) {
1223  delete p_majorAxis;
1224  p_majorAxis = NULL;
1225  }
1226 
1227  if(p_minorAxis) {
1228  delete p_minorAxis;
1229  p_minorAxis = NULL;
1230  }
1231 
1232  if(p_polarAxis) {
1233  delete p_polarAxis;
1234  p_polarAxis = NULL;
1235  }
1236 
1237  if(p_rectCovar) {
1238  delete p_rectCovar;
1239  p_rectCovar = NULL;
1240  }
1241 
1242  if(p_sphereCovar) {
1243  delete p_sphereCovar;
1244  p_sphereCovar = NULL;
1245  }
1246  }
1247 }