contrib/gel/mrc/vpgl/bgeo/bgeo_lvcs.cxx
Go to the documentation of this file.
00001 #include "bgeo_lvcs.h"
00002 //:
00003 // \file
00004 #include <vcl_string.h>
00005 #include <vcl_cstring.h>
00006 #include <vsl/vsl_basic_xml_element.h>
00007 #include <vpgl/bgeo/bgeo_datum_conversion.h>
00008 #include <vpgl/bgeo/bgeo_earth_constants.h>
00009 
00010 #define SMALL_STEP 1.0e-6 // assumed to be in radians
00011 
00012 const char* bgeo_lvcs::cs_name_strings[]  = { "wgs84", "nad27n", "wgs72"};
00013 
00014 bgeo_lvcs::cs_names bgeo_lvcs::str_to_enum(const char* s)
00015 {
00016   for (int i=0; i < bgeo_lvcs::NumNames; i++)
00017     if (vcl_strcmp(s, bgeo_lvcs::cs_name_strings[i]) == 0)
00018       return (bgeo_lvcs::cs_names) i;
00019   return bgeo_lvcs::NumNames;
00020 }
00021 
00022 void bgeo_lvcs::set_angle_conversions(AngUnits ang_unit, double& to_radians,
00023                                       double& to_degrees)
00024 {
00025   to_radians=1.0;
00026   to_degrees=1.0;
00027   if (ang_unit == DEG)
00028     to_radians = DEGREES_TO_RADIANS;
00029   else
00030     to_degrees = RADIANS_TO_DEGREES;
00031 }
00032 
00033 void bgeo_lvcs::set_length_conversions(LenUnits len_unit, double& to_meters,
00034                                        double& to_feet)
00035 {
00036   to_meters = 1.0;
00037   to_feet = 1.0;
00038   if (len_unit == FEET)
00039     to_meters = FEET_TO_METERS;
00040   else
00041     to_feet = METERS_TO_FEET;
00042 }
00043 
00044 bgeo_lvcs::bgeo_lvcs(const bgeo_lvcs& lvcs)
00045  : vbl_ref_count(),
00046    local_cs_name_(lvcs.local_cs_name_),
00047    localCSOriginLat_(lvcs.localCSOriginLat_),
00048    localCSOriginLon_(lvcs.localCSOriginLon_),
00049    localCSOriginElev_(lvcs.localCSOriginElev_),
00050    lat_scale_(lvcs.lat_scale_),
00051    lon_scale_(lvcs.lon_scale_),
00052    geo_angle_unit_(lvcs.geo_angle_unit_),
00053    localXYZUnit_(lvcs.localXYZUnit_),
00054    lox_(lvcs.lox_),
00055    loy_(lvcs.loy_),
00056    theta_(lvcs.theta_)
00057 {
00058   if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00059     this->compute_scale();
00060 }
00061 
00062 
00063 bgeo_lvcs& bgeo_lvcs::operator=(const bgeo_lvcs& lvcs)
00064 {
00065   local_cs_name_ = lvcs.local_cs_name_;
00066   localCSOriginLat_ = lvcs.localCSOriginLat_;
00067   localCSOriginLon_ = lvcs.localCSOriginLon_;
00068   localCSOriginElev_ = lvcs.localCSOriginElev_;
00069   lat_scale_ = lvcs.lat_scale_;
00070   lon_scale_ = lvcs.lon_scale_;
00071   geo_angle_unit_ = lvcs.geo_angle_unit_,
00072   localXYZUnit_ = lvcs.localXYZUnit_;
00073   lox_ = lvcs.lox_;
00074   loy_ = lvcs.loy_;
00075   theta_ = lvcs.theta_;
00076   if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00077   this->compute_scale();
00078   return *this;
00079 }
00080 
00081 bgeo_lvcs::bgeo_lvcs(double orig_lat, double orig_lon, double orig_elev,
00082                      cs_names cs_name,
00083                      double lat_scale, double lon_scale,
00084                      AngUnits ang_unit, /* = DEG */
00085                      LenUnits len_unit /* =METERS */,
00086                      double lox,
00087                      double loy,
00088                      double theta)
00089   :local_cs_name_(cs_name),
00090    localCSOriginLat_(orig_lat),
00091    localCSOriginLon_(orig_lon),
00092    localCSOriginElev_(orig_elev),
00093    lat_scale_(lat_scale),
00094    lon_scale_(lon_scale),
00095    geo_angle_unit_(ang_unit),
00096    localXYZUnit_(len_unit),
00097    lox_(lox),
00098    loy_(loy),
00099    theta_(theta)
00100 {
00101   if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00102     this->compute_scale();
00103 }
00104 
00105 //--------------------------------------------------------------------------
00106 //: A simplified constructor that takes the origin and specified coordinate system.
00107 //  The units of the input latitude and longitude values are assumed to be
00108 //  the same as specified by ang_unit.
00109 //  Similarly, the unit of elevation is specified by elev_unit.
00110 //  The local cartesian system is aligned with North and East
00111 //
00112 bgeo_lvcs::bgeo_lvcs(double orig_lat, double orig_lon, double orig_elev,
00113                      cs_names cs_name,
00114                      AngUnits  ang_unit,
00115                      LenUnits len_unit)
00116   : local_cs_name_(cs_name),
00117     localCSOriginLat_(orig_lat), localCSOriginLon_(orig_lon),
00118     localCSOriginElev_(orig_elev),
00119     geo_angle_unit_(ang_unit), localXYZUnit_(len_unit), lox_(0), loy_(0), theta_(0)
00120 {
00121   lat_scale_ = 0;
00122   lon_scale_ = 0;
00123   this->compute_scale();
00124 }
00125 
00126 //--------------------------------------------------------------------------
00127 //: This constructor takes a lat-lon bounding box and erects a local vertical coordinate system at the center.
00128 //  The units of the input latitude and longitude values are assumed to be
00129 //  the same as specified by ang_unit.
00130 //  Similarly, the unit of elevation is specified by elev_unit.
00131 //  The local cartesian system is aligned with North and East
00132 //
00133 bgeo_lvcs::bgeo_lvcs(double lat_low, double lon_low,
00134                      double lat_high, double lon_high,
00135                      double elev,
00136                      cs_names cs_name, AngUnits ang_unit, LenUnits elev_unit)
00137   :   local_cs_name_(cs_name), localCSOriginElev_(elev),
00138       geo_angle_unit_(ang_unit), localXYZUnit_(elev_unit)
00139 {
00140   double average_lat = (lat_low + lat_high)/2.0;
00141   double average_lon = (lon_low + lon_high)/2.0;
00142   localCSOriginLat_ = average_lat;
00143   localCSOriginLon_ = average_lon;
00144   lat_scale_ = 0;
00145   lon_scale_ = 0;
00146   this->compute_scale();
00147 }
00148 
00149 double bgeo_lvcs::radians_to_degrees(const double val)
00150 {
00151   return val*RADIANS_TO_DEGREES;
00152 }
00153 
00154 void  bgeo_lvcs::radians_to_degrees(double& x, double& y, double& z)
00155 {
00156   x = x * RADIANS_TO_DEGREES;
00157   y = y * RADIANS_TO_DEGREES;
00158   z = z * RADIANS_TO_DEGREES;
00159 }
00160 
00161 void bgeo_lvcs::degrees_to_dms(double geoval, int& degrees, int& minutes, double& seconds)
00162 {
00163   double fmin = vcl_fabs(geoval - (int)geoval)*60.0;
00164   int isec = (int) ((fmin - (int)fmin)*60.0 + .5);
00165   int imin = (int) ((isec == 60) ? fmin+1 : fmin) ;
00166   int extra = (geoval>0) ? 1 : -1;
00167   degrees = (int) ( (imin == 60) ? geoval+extra : geoval);
00168   minutes = ( imin== 60 ? 0 : imin);
00169   seconds = (fmin - (int)fmin)*60.0;
00170 }
00171 
00172 // compute the scales for the given coordinate system.
00173 void bgeo_lvcs::compute_scale()
00174 {
00175   double wgs84_phi, wgs84_lamda, wgs84_hgt;  /* WGS84 coords of the origin */
00176   double grs80_x, grs80_y, grs80_z;          /* GRS80 coords of the origin */
00177   double grs80_x1, grs80_y1, grs80_z1;
00178   double to_meters, to_feet, to_radians, to_degrees;
00179   this->set_angle_conversions(geo_angle_unit_, to_radians, to_degrees);
00180   this->set_length_conversions(localXYZUnit_, to_meters, to_feet);
00181   /* Convert origin to WGS84 */
00182   switch (local_cs_name_)
00183   {
00184    case bgeo_lvcs::wgs84:
00185     wgs84_phi = localCSOriginLat_*to_radians;
00186     wgs84_lamda = localCSOriginLon_*to_radians;
00187     wgs84_hgt = localCSOriginElev_*to_meters;
00188     break;
00189 
00190    case bgeo_lvcs::nad27n:
00191     //The inputs, phi and lamda, are assumed to be in degrees
00192     nad27n_to_wgs84(localCSOriginLat_*to_degrees,
00193                     localCSOriginLon_*to_degrees,
00194                     localCSOriginElev_*to_meters,
00195                     &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00196     wgs84_phi *= to_radians;
00197     wgs84_lamda *= to_radians;
00198     break;
00199    case bgeo_lvcs::wgs72:
00200     //The inputs, phi and lamda, are assumed to be in degrees
00201     wgs72_to_wgs84(localCSOriginLat_*to_degrees,
00202                    localCSOriginLon_*to_degrees,
00203                    localCSOriginElev_*to_meters,
00204                    &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00205     wgs84_phi *= to_radians;
00206     wgs84_lamda *= to_radians;
00207     break;
00208    case bgeo_lvcs::NumNames:
00209     break;
00210    default:
00211     break;
00212   }
00213 
00214   //The inputs, wgs84_phi, wgs84_lamda, are assumed to be in radians
00215   //The inputs wgs84_hgt, GRS80a, GRS80b, are assumed to be in meters
00216   //The outputs grs80_x, grs80_y, grs80_z, are in meters
00217   latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00218                  &grs80_x, &grs80_y, &grs80_z, GRS80_a, GRS80_b);
00219 
00220   if (lat_scale_ == 0.0)
00221   {
00222     switch (local_cs_name_)
00223     {
00224      case bgeo_lvcs::nad27n:
00225       //lat, lon inputs are in degrees. elevation is in meters.
00226       //SMALL_STEP is in radians
00227       nad27n_to_wgs84(
00228                       (localCSOriginLat_*to_radians+SMALL_STEP)*to_degrees,
00229                       localCSOriginLon_*to_degrees,
00230                       localCSOriginElev_*to_meters,
00231                       &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00232       wgs84_phi *= to_radians;
00233       wgs84_lamda *= to_radians;
00234       break;
00235      case bgeo_lvcs::wgs84:
00236       wgs84_phi = localCSOriginLat_*to_radians + SMALL_STEP;
00237       wgs84_lamda = localCSOriginLon_*to_radians;
00238       wgs84_hgt = localCSOriginElev_*to_meters;
00239       break;
00240      case bgeo_lvcs::wgs72://Why empty?
00241       break;
00242      case bgeo_lvcs::NumNames:
00243       break;
00244      default:
00245       break;
00246     }
00247 
00248     latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00249                    &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
00250 
00251     lat_scale_ = SMALL_STEP/vcl_sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
00252                                      (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
00253                                      (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
00254     //lat_scale_ is in radians/meter.
00255   }
00256 
00257   if (lon_scale_ == 0.0)
00258   {
00259     switch (local_cs_name_)
00260     {
00261      case bgeo_lvcs::nad27n:
00262       nad27n_to_wgs84(localCSOriginLat_*to_degrees,
00263                       (localCSOriginLon_*to_radians+SMALL_STEP)*to_degrees,
00264                       localCSOriginElev_*to_meters,
00265                       &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00266       wgs84_phi *= to_radians;
00267       wgs84_lamda *= to_radians;
00268       break;
00269      case bgeo_lvcs::wgs84:
00270       wgs84_phi = localCSOriginLat_*to_radians;
00271       wgs84_lamda = localCSOriginLon_*to_radians + SMALL_STEP;
00272       wgs84_hgt = localCSOriginElev_*to_meters;
00273       break;
00274      case bgeo_lvcs::wgs72:
00275       break;
00276      case bgeo_lvcs::NumNames:
00277       break;
00278      default:
00279       break;
00280     }
00281 
00282     latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00283                    &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
00284 
00285     lon_scale_ = SMALL_STEP/vcl_sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
00286                                      (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
00287                                      (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
00288     //lon_scale_ is in radians/meter
00289   }
00290 }
00291 
00292 //------------------------------------------------------------------------------
00293 //: Converts pointin, given in local vertical coord system, to pointout in the global coord system given by the string lobalcs_name.
00294 //  X, Y, Z in pointin are assumed to be lengths, in the units specified
00295 //  by this->localXYZUnit_.
00296 //  pointout is written out in [angle, angle, length], as specified by
00297 //  the specified units
00298 //
00299 void bgeo_lvcs::local_to_global(const double pointin_x,
00300                                 const double pointin_y,
00301                                 const double pointin_z,
00302                                 cs_names global_cs_name,
00303                                 double& pointout_lon,
00304                                 double& pointout_lat,
00305                                 double& pointout_z,
00306                                 AngUnits output_ang_unit,
00307                                 LenUnits output_len_unit
00308                                )
00309 {
00310   double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00311   this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00312                               local_to_degrees);
00313   this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00314 
00315   double local_lat, local_lon, local_elev;
00316   double global_lat, global_lon, global_elev;
00317 
00318   // First apply transform to align axes with compass.
00319   double aligned_x = pointin_x;
00320   double aligned_y = pointin_y;
00321   local_transform(aligned_x, aligned_y);
00322 
00323   /* Now compute the lat, lon, elev of the output point in Local CS*/
00324   local_lat =
00325     aligned_y*local_to_meters*lat_scale_ + localCSOriginLat_*local_to_radians;
00326 
00327   local_lon =
00328     aligned_x*local_to_meters*lon_scale_  + localCSOriginLon_*local_to_radians;
00329 
00330   local_elev = pointin_z*local_to_meters + localCSOriginElev_*local_to_meters;
00331 
00332   local_lat *= RADIANS_TO_DEGREES;
00333   local_lon *= RADIANS_TO_DEGREES;
00334 
00335   //at this point local_lat, local_lon are in degrees
00336   //local_elev is in meters
00337   if (local_cs_name_ == global_cs_name)
00338   {
00339     /* Local and global coord systems are the same */
00340     global_lat = local_lat;
00341     global_lon = local_lon;
00342     global_elev = local_elev;
00343   }
00344   else
00345     if (local_cs_name_ ==  bgeo_lvcs::nad27n)
00346     {
00347       /* Convert from "nad27n" to whatever */
00348       if (global_cs_name == bgeo_lvcs::wgs84)
00349       {
00350         nad27n_to_wgs84(local_lat,
00351                         local_lon,
00352                         local_elev,
00353                         &global_lat, &global_lon, &global_elev);
00354       }
00355       else if (global_cs_name ==  bgeo_lvcs::wgs72)
00356       {
00357         nad27n_to_wgs72(local_lat, local_lon,
00358                         local_elev,
00359                         &global_lat, &global_lon, &global_elev);
00360       }
00361       else
00362         vcl_cout << "Error: Global CS " << bgeo_lvcs::cs_name_strings[global_cs_name]
00363                  << " unrecognized." << '\n';
00364     }
00365     else if (local_cs_name_ == bgeo_lvcs::wgs72)
00366     {
00367       /* Convert from "wgs72" to whatever */
00368       if (global_cs_name == bgeo_lvcs::nad27n)
00369       {
00370         wgs72_to_nad27n(local_lat,
00371                         local_lon,
00372                         local_elev,
00373                         &global_lat, &global_lon, &global_elev);
00374       }
00375       else if (global_cs_name == bgeo_lvcs::wgs84)
00376       {
00377         wgs72_to_wgs84(local_lat,
00378                        local_lon,
00379                        local_elev,
00380                        &global_lat, &global_lon, &global_elev);
00381       }
00382       else
00383         vcl_cout << "Error: Global CS " << bgeo_lvcs::cs_name_strings[global_cs_name]
00384                  << " unrecognized." << '\n';
00385   }
00386     else if (local_cs_name_ == bgeo_lvcs::wgs84)
00387     {
00388       /* Convert from "wgs84" to whatever */
00389       if (global_cs_name == bgeo_lvcs::nad27n)
00390       {
00391         wgs84_to_nad27n(local_lat,
00392                         local_lon,
00393                         local_elev,
00394                         &global_lat, &global_lon, &global_elev);
00395       }
00396       else if (global_cs_name == bgeo_lvcs::wgs72)
00397       {
00398         wgs84_to_wgs72(local_lat,
00399                        local_lon,
00400                        local_elev,
00401                        &global_lat, &global_lon, &global_elev);
00402       }
00403       else
00404         vcl_cout << "Error: Global CS " << bgeo_lvcs::cs_name_strings[global_cs_name]
00405                  << " unrecognized." << '\n';
00406     }
00407     else
00408       vcl_cout << "Error: Local CS " << bgeo_lvcs::cs_name_strings[local_cs_name_]
00409                << " unrecognized." << '\n';
00410 
00411   //at this point, global_lat and global_lon are in degrees.
00412 
00413   if (output_ang_unit==DEG)
00414   {
00415     pointout_lon = global_lon;
00416     pointout_lat = global_lat;
00417   }
00418   else
00419   {
00420     pointout_lon = global_lon*DEGREES_TO_RADIANS;
00421     pointout_lat = global_lat*DEGREES_TO_RADIANS;
00422   }
00423 
00424   if (output_len_unit == METERS)
00425     pointout_z = global_elev;
00426   else
00427     pointout_z = global_elev*METERS_TO_FEET;
00428 
00429 #ifdef LVCS_DEBUG
00430   vcl_cout << "Local " << bgeo_lvcs::cs_name_strings[local_cs_name_]
00431            << " [" << pointin_y << ", " << pointin_x << ", "  << pointin_z
00432            << "]  MAPS TO Global "
00433            << bgeo_lvcs::cs_name_strings[global_cs_name]
00434            << " [" << pointout_lat << ", " << pointout_lon << ", " << pointout_z << "]\n";
00435 #endif
00436 }
00437 
00438 
00439 //----------------------------------------------------------------------------
00440 //: Converts pointin, given in a global coord system described by global_cs_name, to pointout in the local vertical coord system.
00441 //  The units of X, Y, Z are specified by input_ang_unit and input_len_unit
00442 //  to define lon, lat, elev in (angle, angle, length).
00443 //  The output point is returned in the units specified by
00444 //  this->localXYZUnit_.
00445 
00446 void bgeo_lvcs::global_to_local(const double pointin_lon,
00447                                 const double pointin_lat,
00448                                 const double pointin_z,
00449                                 cs_names global_cs_name,
00450                                 double& pointout_x,
00451                                 double& pointout_lat,
00452                                 double& pointout_z,
00453                                 AngUnits input_ang_unit,
00454                                 LenUnits input_len_unit)
00455 {
00456   double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00457   this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00458                               local_to_degrees);
00459   this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00460   double global_lat, global_lon, global_elev;
00461   double local_lat, local_lon, local_elev;
00462 
00463   global_lat  = pointin_lat;
00464   global_lon  = pointin_lon;
00465   global_elev = pointin_z;
00466 
00467   //convert input global point to degrees and meters
00468 
00469   if (input_ang_unit==RADIANS)
00470   {
00471    global_lat *= RADIANS_TO_DEGREES;
00472    global_lon *= RADIANS_TO_DEGREES;
00473   }
00474 
00475   if (input_len_unit==FEET)
00476     global_elev *= FEET_TO_METERS;
00477 
00478   /* Convert from global CS to local CS of the origin of LVCS */
00479   if (global_cs_name == local_cs_name_)
00480   {
00481     /* Global and local coord systems are the same */
00482     local_lat  = global_lat;
00483     local_lon  = global_lon;
00484     local_elev = global_elev;
00485   }
00486   else if (global_cs_name == bgeo_lvcs::nad27n)
00487   {
00488     /* Convert from "nad27n" to whatever */
00489     if (local_cs_name_ == bgeo_lvcs::wgs84)
00490     {
00491       nad27n_to_wgs84(global_lat, global_lon, global_elev,
00492                       &local_lat, &local_lon, &local_elev);
00493     }
00494     else if (local_cs_name_ == bgeo_lvcs::wgs72)
00495     {
00496       nad27n_to_wgs72(global_lat, global_lon, global_elev,
00497                       &local_lat, &local_lon, &local_elev);
00498     }
00499     else
00500       vcl_cout << "Error: Local CS " << bgeo_lvcs::cs_name_strings[local_cs_name_]
00501                << " unrecognized." << '\n';
00502   }
00503   else if (global_cs_name == bgeo_lvcs::wgs72)
00504   {
00505     /* Convert from "wgs72" to whatever */
00506     if (local_cs_name_ == bgeo_lvcs::nad27n)
00507     {
00508       wgs72_to_nad27n(global_lat, global_lon, global_elev,
00509                       &local_lat, &local_lon, &local_elev);
00510     }
00511     else if (local_cs_name_ == bgeo_lvcs::wgs84)
00512     {
00513       wgs72_to_wgs84(global_lat, global_lon, global_elev,
00514                      &local_lat, &local_lon, &local_elev);
00515     }
00516     else
00517       vcl_cout << "Error: Local CS " << bgeo_lvcs::cs_name_strings[local_cs_name_]
00518                << " unrecognized." << '\n';
00519   }
00520   else if (global_cs_name == bgeo_lvcs::wgs84)
00521   {
00522     /* Convert from "wgs84" to whatever */
00523     if (local_cs_name_ == bgeo_lvcs::nad27n)
00524     {
00525       wgs84_to_nad27n(global_lat, global_lon, global_elev,
00526                       &local_lat, &local_lon, &local_elev);
00527     }
00528     else if (local_cs_name_ ==  bgeo_lvcs::wgs72)
00529     {
00530       wgs84_to_wgs72(global_lat, global_lon, global_elev,
00531                      &local_lat, &local_lon, &local_elev);
00532     }
00533     else
00534       vcl_cout << "Error: Local CS " << bgeo_lvcs::cs_name_strings[local_cs_name_]
00535                << " unrecognized." << '\n';
00536   }
00537   else
00538     vcl_cout << "Error: Global CS " <<  bgeo_lvcs::cs_name_strings[global_cs_name]
00539              << " unrecognized." << '\n';
00540 
00541 
00542   /* Now compute the x, y, z of the point in local vetical CS*/
00543   //first convert the local_lat to radians and local cs origin to meters
00544   pointout_lat =
00545     (local_lat*DEGREES_TO_RADIANS -
00546      localCSOriginLat_*local_to_radians)/lat_scale_;
00547   pointout_x =
00548     (local_lon*DEGREES_TO_RADIANS -
00549      localCSOriginLon_*local_to_radians)/lon_scale_;
00550 
00551   pointout_z = local_elev - localCSOriginElev_*local_to_meters;
00552 
00553   if (localXYZUnit_==FEET)
00554   {
00555     pointout_x *= METERS_TO_FEET;
00556     pointout_lat *= METERS_TO_FEET;
00557     pointout_z *= METERS_TO_FEET;
00558   }
00559   // Transform from compass aligned into local co-ordinates.
00560   inverse_local_transform(pointout_x,pointout_lat);
00561 
00562 #ifdef LVCS_DEBUG
00563   vcl_cout << "Global " << bgeo_lvcs::cs_name_strings[global_cs_name]
00564            << " [" << pointin_lon << ", " << pointin_lat << ", "  << pointin_z
00565            << "]  MAPS TO Local "
00566            << bgeo_lvcs::cs_name_strings[local_cs_name_]
00567            << " [" << pointout_x << ", " << pointout_lat << ", " << pointout_z << "]\n";
00568 #endif
00569 }
00570 
00571 
00572 //: Print internals on strm.
00573 void bgeo_lvcs::print(vcl_ostream& strm) const
00574 {
00575   vcl_string len_u = "meters", ang_u="degrees";
00576   if (localXYZUnit_ == FEET)
00577     len_u = "feet";
00578   if (geo_angle_unit_ == RADIANS)
00579     ang_u= "radians";
00580   strm << "lvcs [\n"
00581        << "coordinate system name : " << cs_name_strings[local_cs_name_] << '\n'
00582        << "angle unit " << ang_u << '\n'
00583        << "length unit " << len_u << '\n'
00584        << "local origin(lat, lon, elev) : (" <<  localCSOriginLat_ << ' '
00585        << localCSOriginLon_ << ' ' << localCSOriginElev_  << ")\n"
00586        << "scales(lat lon) : (" << lat_scale_ << ' ' << lon_scale_ << ")\n"
00587        << "local transform(lox loy theta) : (" << lox_ << ' ' << loy_
00588        << ' ' << theta_ << ")\n]\n";
00589 }
00590 
00591 //: Read internals from strm.
00592 void bgeo_lvcs::read(vcl_istream& strm)
00593 {
00594   vcl_string len_u = "meters", ang_u="degrees";
00595 
00596   vcl_string local_cs_name_str;
00597   strm >> local_cs_name_str;
00598   if (local_cs_name_str.compare("wgs84") == 0)
00599     local_cs_name_ = wgs84;
00600   else if (local_cs_name_str.compare("nad27n") == 0)
00601     local_cs_name_ = nad27n;
00602   else if (local_cs_name_str.compare("wgs72") == 0)
00603     local_cs_name_ = wgs72;
00604   else
00605     vcl_cerr << "undefined local_cs_name\n";
00606 
00607   strm >> ang_u >> len_u;
00608   if (ang_u.compare("feet") == 0)
00609     localXYZUnit_ = FEET;
00610   else if (ang_u.compare("meters") == 0)
00611     localXYZUnit_ = METERS;
00612   else
00613     vcl_cerr << "undefined localXYZUnit_\n";
00614 
00615   if (len_u.compare("degrees") == 0)
00616     geo_angle_unit_ = DEG;
00617   else if (len_u.compare("radians") == 0)
00618     geo_angle_unit_ = RADIANS;
00619   else
00620     vcl_cerr << "undefined geo_angle_unit_\n";
00621 
00622   strm >> localCSOriginLat_ >> localCSOriginLon_ >> localCSOriginElev_;
00623   strm >> lat_scale_ >> lon_scale_;
00624   strm >> lox_ >> loy_ >> theta_;
00625 
00626   if (lat_scale_==0.0 && lon_scale_==0.0)
00627     this->compute_scale();
00628 }
00629 
00630 //------------------------------------------------------------
00631 //: Transform from local co-ordinates to north=y,east=x.
00632 void bgeo_lvcs::local_transform(double& x, double& y)
00633 {
00634   double theta=theta_;
00635   if (geo_angle_unit_ == DEG)
00636     theta=theta_*DEGREES_TO_RADIANS;
00637 
00638   // Offset to real origin - ie. the point whose lat/long was given.
00639   double xo = x - lox_;
00640   double yo = y - loy_;
00641 
00642   // Rotate about that point to align y with north.
00643   double ct,st;
00644   if (vcl_fabs(theta) < 1e-5)
00645   {
00646     ct = 1.0;
00647     st = theta;
00648   }
00649   else
00650   {
00651     ct = vcl_cos(-theta);
00652     st = vcl_sin(-theta);
00653   }
00654   x = ct*xo + st*yo;
00655   y = -st*xo + ct*yo;
00656 }
00657 
00658 //------------------------------------------------------------
00659 //: Transform from north=y,east=x aligned axes to local co-ordinates.
00660 void bgeo_lvcs::inverse_local_transform(double& x, double& y)
00661 {
00662   double theta=theta_;
00663   if (geo_angle_unit_ == DEG)
00664     theta=theta_*DEGREES_TO_RADIANS;
00665 
00666   // Rotate about that point to align y with north.
00667   double ct,st;
00668   if (vcl_fabs(theta) < 1e-5)
00669   {
00670     ct = 1.0;
00671     st = theta;
00672   }
00673   else
00674   {
00675     ct = vcl_cos(-theta);
00676     st = vcl_sin(-theta);
00677   }
00678   double xo = ct*x + st*y;
00679   double yo = -st*x + ct*y;
00680 
00681   // Offset to local co-ordinate system origin.
00682   x = xo + lox_;
00683   y = yo + loy_;
00684 }
00685 
00686 vcl_ostream& operator << (vcl_ostream& os, const bgeo_lvcs& local_coord_sys)
00687 {
00688   local_coord_sys.print(os);
00689   return os;
00690 }
00691 
00692 vcl_istream& operator >> (vcl_istream& is, bgeo_lvcs& local_coord_sys)
00693 {
00694   local_coord_sys.read(is);
00695   return is;
00696 }
00697 
00698 bool bgeo_lvcs::operator==(bgeo_lvcs const& r) const
00699 {
00700   bool eq = true;
00701   eq = eq && (this->local_cs_name_ == r.local_cs_name_);
00702   eq = eq && (this->localCSOriginLat_ == r.localCSOriginLat_);
00703   eq = eq && (this->localCSOriginLon_ == r.localCSOriginLon_);
00704   eq = eq && (this->localCSOriginElev_ == r.localCSOriginElev_);
00705   eq = eq && (this->lat_scale_ == r.lat_scale_);
00706   eq = eq && (this->lon_scale_ == r.lon_scale_);
00707   eq = eq && (this->geo_angle_unit_ == r.geo_angle_unit_);
00708   eq = eq && (this->localXYZUnit_ == r.localXYZUnit_);
00709   eq = eq && (this->lox_ == r.lox_);
00710   eq = eq && (this->loy_ == r.loy_);
00711   eq = eq && (this->theta_ == r.theta_);
00712   return eq;
00713 }
00714 // binary IO
00715 
00716 //: Binary save self to stream.
00717 void bgeo_lvcs::b_write(vsl_b_ostream &os) const
00718 {
00719   unsigned csn = static_cast<unsigned>(local_cs_name_);
00720   vsl_b_write(os, csn);
00721   vsl_b_write(os, localCSOriginLat_);
00722   vsl_b_write(os, localCSOriginLon_);
00723   vsl_b_write(os, localCSOriginElev_);
00724   vsl_b_write(os, lat_scale_);
00725   vsl_b_write(os, lon_scale_);
00726   unsigned gaunit = static_cast<unsigned>(geo_angle_unit_);
00727   vsl_b_write(os, gaunit);
00728   unsigned xyzunit = static_cast<unsigned>(localXYZUnit_);
00729   vsl_b_write(os, xyzunit);
00730   vsl_b_write(os, lox_);
00731   vsl_b_write(os, loy_);
00732   vsl_b_write(os, theta_);
00733 }
00734 
00735 //: Binary load self from stream.
00736 void bgeo_lvcs::b_read(vsl_b_istream &is)
00737 {
00738   unsigned cs_name;
00739   vsl_b_read(is, cs_name);
00740   local_cs_name_ = static_cast<cs_names>(cs_name);
00741   vsl_b_read(is, localCSOriginLat_);
00742   vsl_b_read(is, localCSOriginLon_);
00743   vsl_b_read(is, localCSOriginElev_);
00744   vsl_b_read(is, lat_scale_);
00745   vsl_b_read(is, lon_scale_);
00746   unsigned gaunit;
00747   vsl_b_read(is, gaunit);
00748   geo_angle_unit_ = static_cast<AngUnits>(gaunit);
00749   unsigned lunit;
00750   vsl_b_read(is, lunit);
00751   localXYZUnit_ = static_cast<LenUnits>(lunit);
00752   vsl_b_read(is, lox_);
00753   vsl_b_read(is, loy_);
00754   vsl_b_read(is, theta_);
00755 }
00756 
00757 void bgeo_lvcs::x_write(vcl_ostream &os, vcl_string element_name) const
00758 {
00759   vcl_string len_u = "meters", ang_u="degrees";
00760   if (localXYZUnit_ == FEET)
00761     len_u = "feet";
00762   if (geo_angle_unit_ == RADIANS)
00763     ang_u= "radians";
00764 
00765   vsl_basic_xml_element xml_element(element_name);
00766   xml_element.add_attribute("cs_name", cs_name_strings[local_cs_name_]);
00767   xml_element.add_attribute("origin_lon", localCSOriginLon_);
00768   xml_element.add_attribute("origin_lat", localCSOriginLat_);
00769   xml_element.add_attribute("origin_elev", localCSOriginElev_);
00770   xml_element.add_attribute("lon_scale", lon_scale_);
00771   xml_element.add_attribute("lat_scale", lat_scale_);
00772   xml_element.add_attribute("local_XYZ_unit", len_u);
00773   xml_element.add_attribute("geo_angle_unit", ang_u);
00774   xml_element.add_attribute("local_origin_x", lox_);
00775   xml_element.add_attribute("local_origin_y", loy_);
00776   xml_element.add_attribute("theta", theta_);
00777   xml_element.x_write(os);
00778 }