00001 #include "vpgl_lvcs.h"
00002
00003
00004 #include <vcl_string.h>
00005 #include <vcl_cstring.h>
00006 #include <vsl/vsl_basic_xml_element.h>
00007 #include <vpgl/vpgl_datum_conversion.h>
00008 #include <vpgl/vpgl_earth_constants.h>
00009 #include <vpgl/vpgl_utm.h>
00010
00011 #define SMALL_STEP 1.0e-6 // assumed to be in radians
00012
00013 const char* vpgl_lvcs::cs_name_strings[] = { "wgs84", "nad27n", "wgs72", "utm"};
00014
00015 vpgl_lvcs::cs_names vpgl_lvcs::str_to_enum(const char* s)
00016 {
00017 for (int i=0; i < vpgl_lvcs::NumNames; i++)
00018 if (vcl_strcmp(s, vpgl_lvcs::cs_name_strings[i]) == 0)
00019 return (vpgl_lvcs::cs_names) i;
00020 return vpgl_lvcs::NumNames;
00021 }
00022
00023 void vpgl_lvcs::set_angle_conversions(AngUnits ang_unit, double& to_radians,
00024 double& to_degrees)
00025 {
00026 to_radians=1.0;
00027 to_degrees=1.0;
00028 if (ang_unit == DEG)
00029 to_radians = DEGREES_TO_RADIANS;
00030 else
00031 to_degrees = RADIANS_TO_DEGREES;
00032 }
00033
00034 void vpgl_lvcs::set_length_conversions(LenUnits len_unit, double& to_meters,
00035 double& to_feet)
00036 {
00037 to_meters = 1.0;
00038 to_feet = 1.0;
00039 if (len_unit == FEET)
00040 to_meters = FEET_TO_METERS;
00041 else
00042 to_feet = METERS_TO_FEET;
00043 }
00044
00045 vpgl_lvcs::vpgl_lvcs(const vpgl_lvcs& lvcs)
00046 : vbl_ref_count(),
00047 local_cs_name_(lvcs.local_cs_name_),
00048 localCSOriginLat_(lvcs.localCSOriginLat_),
00049 localCSOriginLon_(lvcs.localCSOriginLon_),
00050 localCSOriginElev_(lvcs.localCSOriginElev_),
00051 lat_scale_(lvcs.lat_scale_),
00052 lon_scale_(lvcs.lon_scale_),
00053 geo_angle_unit_(lvcs.geo_angle_unit_),
00054 localXYZUnit_(lvcs.localXYZUnit_),
00055 lox_(lvcs.lox_),
00056 loy_(lvcs.loy_),
00057 theta_(lvcs.theta_),
00058 localUTMOrigin_X_East_(lvcs.localUTMOrigin_X_East_),
00059 localUTMOrigin_Y_North_(lvcs.localUTMOrigin_Y_North_),
00060 localUTMOrigin_Zone_(lvcs.localUTMOrigin_Zone_)
00061 {
00062 if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00063 this->compute_scale();
00064 }
00065
00066
00067 vpgl_lvcs& vpgl_lvcs::operator=(const vpgl_lvcs& lvcs)
00068 {
00069 local_cs_name_ = lvcs.local_cs_name_;
00070 localCSOriginLat_ = lvcs.localCSOriginLat_;
00071 localCSOriginLon_ = lvcs.localCSOriginLon_;
00072 localCSOriginElev_ = lvcs.localCSOriginElev_;
00073 lat_scale_ = lvcs.lat_scale_;
00074 lon_scale_ = lvcs.lon_scale_;
00075 geo_angle_unit_ = lvcs.geo_angle_unit_,
00076 localXYZUnit_ = lvcs.localXYZUnit_;
00077 lox_ = lvcs.lox_;
00078 loy_ = lvcs.loy_;
00079 theta_ = lvcs.theta_;
00080 localUTMOrigin_X_East_ = lvcs.localUTMOrigin_X_East_;
00081 localUTMOrigin_Y_North_ = lvcs.localUTMOrigin_Y_North_;
00082 localUTMOrigin_Zone_ = lvcs.localUTMOrigin_Zone_;
00083 if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00084 this->compute_scale();
00085 return *this;
00086 }
00087
00088 vpgl_lvcs::vpgl_lvcs(double orig_lat, double orig_lon, double orig_elev,
00089 cs_names cs_name,
00090 double lat_scale, double lon_scale,
00091 AngUnits ang_unit,
00092 LenUnits len_unit,
00093 double lox,
00094 double loy,
00095 double theta)
00096 :local_cs_name_(cs_name),
00097 localCSOriginLat_(orig_lat),
00098 localCSOriginLon_(orig_lon),
00099 localCSOriginElev_(orig_elev),
00100 lat_scale_(lat_scale),
00101 lon_scale_(lon_scale),
00102 geo_angle_unit_(ang_unit),
00103 localXYZUnit_(len_unit),
00104 lox_(lox),
00105 loy_(loy),
00106 theta_(theta)
00107 {
00108 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00109 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00110 local_to_degrees);
00111 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00112
00113 if (cs_name == vpgl_lvcs::utm) {
00114
00115 vpgl_utm u;
00116 u.transform(localCSOriginLat_*local_to_degrees, localCSOriginLon_*local_to_degrees, localUTMOrigin_X_East_, localUTMOrigin_Y_North_, localUTMOrigin_Zone_);
00117 vcl_cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << vcl_endl;
00118 lat_scale_ = 0.0; lon_scale_ = 0.0;
00119 }
00120 if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
00121 this->compute_scale();
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131 vpgl_lvcs::vpgl_lvcs(double orig_lat, double orig_lon, double orig_elev,
00132 cs_names cs_name,
00133 AngUnits ang_unit,
00134 LenUnits len_unit)
00135 : local_cs_name_(cs_name),
00136 localCSOriginLat_(orig_lat), localCSOriginLon_(orig_lon),
00137 localCSOriginElev_(orig_elev),
00138 geo_angle_unit_(ang_unit), localXYZUnit_(len_unit), lox_(0), loy_(0), theta_(0)
00139 {
00140 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00141 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00142 local_to_degrees);
00143 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00144
00145 if (cs_name == vpgl_lvcs::utm) {
00146
00147 vpgl_utm u;
00148 u.transform(localCSOriginLat_*local_to_degrees, localCSOriginLon_*local_to_degrees, localUTMOrigin_X_East_, localUTMOrigin_Y_North_, localUTMOrigin_Zone_);
00149 vcl_cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North elev: " << localCSOriginElev_ << vcl_endl;
00150 }
00151 lat_scale_ = 0;
00152 lon_scale_ = 0;
00153 this->compute_scale();
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163 vpgl_lvcs::vpgl_lvcs(double lat_low, double lon_low,
00164 double lat_high, double lon_high,
00165 double elev,
00166 cs_names cs_name, AngUnits ang_unit, LenUnits elev_unit)
00167 : local_cs_name_(cs_name), localCSOriginElev_(elev),
00168 geo_angle_unit_(ang_unit), localXYZUnit_(elev_unit)
00169 {
00170 double average_lat = (lat_low + lat_high)/2.0;
00171 double average_lon = (lon_low + lon_high)/2.0;
00172 localCSOriginLat_ = average_lat;
00173 localCSOriginLon_ = average_lon;
00174
00175 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00176 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00177 local_to_degrees);
00178 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00179
00180 if (cs_name == vpgl_lvcs::utm) {
00181
00182 vpgl_utm u;
00183 u.transform(localCSOriginLat_*local_to_degrees, localCSOriginLon_*local_to_degrees, localUTMOrigin_X_East_, localUTMOrigin_Y_North_, localUTMOrigin_Zone_);
00184 vcl_cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << vcl_endl;
00185 }
00186
00187
00188 lat_scale_ = 0;
00189 lon_scale_ = 0;
00190 this->compute_scale();
00191 }
00192
00193 double vpgl_lvcs::radians_to_degrees(const double val)
00194 {
00195 return val*RADIANS_TO_DEGREES;
00196 }
00197
00198 void vpgl_lvcs::radians_to_degrees(double& x, double& y, double& z)
00199 {
00200 x = x * RADIANS_TO_DEGREES;
00201 y = y * RADIANS_TO_DEGREES;
00202 z = z * RADIANS_TO_DEGREES;
00203 }
00204
00205 void vpgl_lvcs::degrees_to_dms(double geoval, int& degrees, int& minutes, double& seconds)
00206 {
00207 double fmin = vcl_fabs(geoval - (int)geoval)*60.0;
00208 int isec = (int) ((fmin - (int)fmin)*60.0 + .5);
00209 int imin = (int) ((isec == 60) ? fmin+1 : fmin) ;
00210 int extra = (geoval>0) ? 1 : -1;
00211 degrees = (int) ( (imin == 60) ? geoval+extra : geoval);
00212 minutes = ( imin== 60 ? 0 : imin);
00213 seconds = (fmin - (int)fmin)*60.0;
00214 }
00215
00216
00217 void vpgl_lvcs::compute_scale()
00218 {
00219 double wgs84_phi, wgs84_lamda, wgs84_hgt;
00220 double grs80_x, grs80_y, grs80_z;
00221 double grs80_x1, grs80_y1, grs80_z1;
00222 double to_meters, to_feet, to_radians, to_degrees;
00223 this->set_angle_conversions(geo_angle_unit_, to_radians, to_degrees);
00224 this->set_length_conversions(localXYZUnit_, to_meters, to_feet);
00225
00226 switch (local_cs_name_)
00227 {
00228 case vpgl_lvcs::utm:
00229 case vpgl_lvcs::wgs84:
00230 wgs84_phi = localCSOriginLat_*to_radians;
00231 wgs84_lamda = localCSOriginLon_*to_radians;
00232 wgs84_hgt = localCSOriginElev_*to_meters;
00233 break;
00234
00235 case vpgl_lvcs::nad27n:
00236
00237 nad27n_to_wgs84(localCSOriginLat_*to_degrees,
00238 localCSOriginLon_*to_degrees,
00239 localCSOriginElev_*to_meters,
00240 &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00241 wgs84_phi *= to_radians;
00242 wgs84_lamda *= to_radians;
00243 break;
00244 case vpgl_lvcs::wgs72:
00245
00246 wgs72_to_wgs84(localCSOriginLat_*to_degrees,
00247 localCSOriginLon_*to_degrees,
00248 localCSOriginElev_*to_meters,
00249 &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00250 wgs84_phi *= to_radians;
00251 wgs84_lamda *= to_radians;
00252 break;
00253 case vpgl_lvcs::NumNames:
00254 default:
00255 wgs84_phi = wgs84_lamda = wgs84_hgt = 0.0;
00256 break;
00257 }
00258
00259
00260
00261
00262 latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00263 &grs80_x, &grs80_y, &grs80_z, GRS80_a, GRS80_b);
00264
00265 if (lat_scale_ == 0.0)
00266 {
00267 switch (local_cs_name_)
00268 {
00269 case vpgl_lvcs::nad27n:
00270
00271
00272 nad27n_to_wgs84(
00273 (localCSOriginLat_*to_radians+SMALL_STEP)*to_degrees,
00274 localCSOriginLon_*to_degrees,
00275 localCSOriginElev_*to_meters,
00276 &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00277 wgs84_phi *= to_radians;
00278 wgs84_lamda *= to_radians;
00279 break;
00280 case vpgl_lvcs::utm:
00281 case vpgl_lvcs::wgs84:
00282 wgs84_phi = localCSOriginLat_*to_radians + SMALL_STEP;
00283 wgs84_lamda = localCSOriginLon_*to_radians;
00284 wgs84_hgt = localCSOriginElev_*to_meters;
00285 break;
00286 case vpgl_lvcs::wgs72:
00287 break;
00288 case vpgl_lvcs::NumNames:
00289 break;
00290 default:
00291 break;
00292 }
00293
00294 latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00295 &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
00296
00297 lat_scale_ = SMALL_STEP/vcl_sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
00298 (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
00299 (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
00300
00301 }
00302
00303 if (lon_scale_ == 0.0)
00304 {
00305 switch (local_cs_name_)
00306 {
00307 case vpgl_lvcs::nad27n:
00308 nad27n_to_wgs84(localCSOriginLat_*to_degrees,
00309 (localCSOriginLon_*to_radians+SMALL_STEP)*to_degrees,
00310 localCSOriginElev_*to_meters,
00311 &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
00312 wgs84_phi *= to_radians;
00313 wgs84_lamda *= to_radians;
00314 break;
00315 case vpgl_lvcs::utm:
00316 case vpgl_lvcs::wgs84:
00317 wgs84_phi = localCSOriginLat_*to_radians;
00318 wgs84_lamda = localCSOriginLon_*to_radians + SMALL_STEP;
00319 wgs84_hgt = localCSOriginElev_*to_meters;
00320 break;
00321 case vpgl_lvcs::wgs72:
00322 break;
00323 case vpgl_lvcs::NumNames:
00324 break;
00325 default:
00326 break;
00327 }
00328
00329 latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
00330 &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
00331
00332 lon_scale_ = SMALL_STEP/vcl_sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
00333 (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
00334 (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
00335
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346 void vpgl_lvcs::local_to_global(const double pointin_x,
00347 const double pointin_y,
00348 const double pointin_z,
00349 cs_names global_cs_name,
00350 double& pointout_lon,
00351 double& pointout_lat,
00352 double& pointout_z,
00353 AngUnits output_ang_unit,
00354 LenUnits output_len_unit
00355 )
00356 {
00357 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00358 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00359 local_to_degrees);
00360 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00361
00362 double local_lat, local_lon, local_elev;
00363 double global_lat, global_lon, global_elev;
00364
00365
00366 double aligned_x = pointin_x;
00367 double aligned_y = pointin_y;
00368 local_transform(aligned_x, aligned_y);
00369
00370 if (local_cs_name_ == vpgl_lvcs::utm) {
00371
00372
00373 if (global_cs_name == vpgl_lvcs::utm) {
00374 if (output_len_unit == METERS) {
00375 pointout_lon = aligned_x*local_to_meters + localUTMOrigin_X_East_;
00376 pointout_lat = aligned_y*local_to_meters + localUTMOrigin_Y_North_;
00377 pointout_z = pointin_z*local_to_meters + localCSOriginElev_*local_to_meters;
00378 }
00379 else {
00380 pointout_lon = aligned_x*local_to_feet + localUTMOrigin_X_East_*local_to_feet;
00381 pointout_lat = aligned_y*local_to_feet + localUTMOrigin_Y_North_*local_to_feet;
00382 pointout_z = pointin_z*local_to_feet + localCSOriginElev_*local_to_feet;
00383 }
00384 return;
00385 }
00386
00387 vpgl_utm u;
00388 u.transform(localUTMOrigin_Zone_, pointin_x*local_to_meters + localUTMOrigin_X_East_,
00389 pointin_y*local_to_meters + localUTMOrigin_Y_North_,
00390 pointin_z*local_to_meters + localCSOriginElev_*local_to_meters,
00391 local_lat, local_lon, local_elev);
00392
00393 if (global_cs_name == vpgl_lvcs::wgs84) {
00394 global_lat = local_lat;
00395 global_lon = local_lon;
00396 global_elev = local_elev;
00397 }
00398 else if (global_cs_name == vpgl_lvcs::nad27n)
00399 {
00400 wgs84_to_nad27n(local_lat,
00401 local_lon,
00402 local_elev,
00403 &global_lat, &global_lon, &global_elev);
00404 }
00405 else if (global_cs_name == vpgl_lvcs::wgs72)
00406 {
00407 wgs84_to_wgs72(local_lat,
00408 local_lon,
00409 local_elev,
00410 &global_lat, &global_lon, &global_elev);
00411 }
00412 else {
00413 vcl_cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
00414 << " unrecognized." << '\n';
00415 global_lat = global_lon = global_elev = 0.0;
00416 }
00417 }
00418 else {
00419
00420 local_lat = aligned_y*local_to_meters*lat_scale_ + localCSOriginLat_*local_to_radians;
00421 local_lon = aligned_x*local_to_meters*lon_scale_ + localCSOriginLon_*local_to_radians;
00422 local_elev = pointin_z*local_to_meters + localCSOriginElev_*local_to_meters;
00423
00424 local_lat *= RADIANS_TO_DEGREES;
00425 local_lon *= RADIANS_TO_DEGREES;
00426
00427
00428
00429 if (local_cs_name_ == global_cs_name)
00430 {
00431
00432 global_lat = local_lat;
00433 global_lon = local_lon;
00434 global_elev = local_elev;
00435 }
00436 else if (local_cs_name_ == vpgl_lvcs::nad27n)
00437 {
00438
00439 if (global_cs_name == vpgl_lvcs::wgs84)
00440 {
00441 nad27n_to_wgs84(local_lat,
00442 local_lon,
00443 local_elev,
00444 &global_lat, &global_lon, &global_elev);
00445 }
00446 else if (global_cs_name == vpgl_lvcs::wgs72)
00447 {
00448 nad27n_to_wgs72(local_lat, local_lon,
00449 local_elev,
00450 &global_lat, &global_lon, &global_elev);
00451 }
00452 else {
00453 vcl_cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
00454 << " unrecognized." << '\n';
00455 global_lat = global_lon = global_elev = 0.0;
00456 }
00457 }
00458 else if (local_cs_name_ == vpgl_lvcs::wgs72)
00459 {
00460
00461 if (global_cs_name == vpgl_lvcs::nad27n)
00462 {
00463 wgs72_to_nad27n(local_lat,
00464 local_lon,
00465 local_elev,
00466 &global_lat, &global_lon, &global_elev);
00467 }
00468 else if (global_cs_name == vpgl_lvcs::wgs84)
00469 {
00470 wgs72_to_wgs84(local_lat,
00471 local_lon,
00472 local_elev,
00473 &global_lat, &global_lon, &global_elev);
00474 }
00475 else {
00476 vcl_cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
00477 << " unrecognized." << '\n';
00478 global_lat = global_lon = global_elev = 0.0;
00479 }
00480 }
00481 else if (local_cs_name_ == vpgl_lvcs::wgs84)
00482 {
00483
00484 if (global_cs_name == vpgl_lvcs::nad27n)
00485 {
00486 wgs84_to_nad27n(local_lat,
00487 local_lon,
00488 local_elev,
00489 &global_lat, &global_lon, &global_elev);
00490 }
00491 else if (global_cs_name == vpgl_lvcs::wgs72)
00492 {
00493 wgs84_to_wgs72(local_lat,
00494 local_lon,
00495 local_elev,
00496 &global_lat, &global_lon, &global_elev);
00497 }
00498 else {
00499 vcl_cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
00500 << " unrecognized." << '\n';
00501 global_lat = global_lon = global_elev = 0.0;
00502 }
00503 }
00504 else {
00505 vcl_cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
00506 << " unrecognized." << '\n';
00507 global_lat = global_lon = global_elev = 0.0;
00508 }
00509 }
00510
00511
00512
00513 if (output_ang_unit==DEG)
00514 {
00515 pointout_lon = global_lon;
00516 pointout_lat = global_lat;
00517 }
00518 else
00519 {
00520 pointout_lon = global_lon*DEGREES_TO_RADIANS;
00521 pointout_lat = global_lat*DEGREES_TO_RADIANS;
00522 }
00523
00524 if (output_len_unit == METERS)
00525 pointout_z = global_elev;
00526 else
00527 pointout_z = global_elev*METERS_TO_FEET;
00528
00529 #ifdef LVCS_DEBUG
00530 vcl_cout << "Local " << vpgl_lvcs::cs_name_strings[local_cs_name_]
00531 << " [" << pointin_y << ", " << pointin_x << ", " << pointin_z
00532 << "] MAPS TO Global "
00533 << vpgl_lvcs::cs_name_strings[global_cs_name]
00534 << " [" << pointout_lat << ", " << pointout_lon << ", " << pointout_z << "]\n";
00535 #endif
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 void vpgl_lvcs::global_to_local(const double pointin_lon,
00547 const double pointin_lat,
00548 const double pointin_z,
00549 cs_names global_cs_name,
00550 double& pointout_x,
00551 double& pointout_y,
00552 double& pointout_z,
00553 AngUnits input_ang_unit,
00554 LenUnits input_len_unit)
00555 {
00556 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00557 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00558 local_to_degrees);
00559 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00560 double global_lat, global_lon, global_elev;
00561 double local_lat, local_lon, local_elev;
00562
00563 global_lat = pointin_lat;
00564 global_lon = pointin_lon;
00565 global_elev = pointin_z;
00566
00567 if (global_cs_name == vpgl_lvcs::utm) {
00568 if (local_cs_name_ == vpgl_lvcs::utm) {
00569 if (input_len_unit == METERS) {
00570 pointout_x = pointin_lon - localUTMOrigin_X_East_;
00571 pointout_y = pointin_lat - localUTMOrigin_Y_North_;
00572 pointout_z = pointin_z - localCSOriginElev_*local_to_meters;
00573 }
00574 else {
00575 pointout_x = pointin_lon*FEET_TO_METERS + localUTMOrigin_X_East_;
00576 pointout_y = pointin_lat*FEET_TO_METERS + localUTMOrigin_Y_North_;
00577 pointout_z = pointin_z*FEET_TO_METERS + localCSOriginElev_*local_to_meters;
00578 }
00579 if (localXYZUnit_==FEET)
00580 {
00581 pointout_x *= METERS_TO_FEET;
00582 pointout_y *= METERS_TO_FEET;
00583 pointout_z *= METERS_TO_FEET;
00584 }
00585
00586 inverse_local_transform(pointout_x,pointout_y);
00587 return;
00588 }
00589 else {
00590 vcl_cerr << "global cs UTM is not supported with other local cs like wgs84, etc.!\n";
00591 return;
00592 }
00593 }
00594
00595
00596
00597 if (input_ang_unit==RADIANS)
00598 {
00599 global_lat *= RADIANS_TO_DEGREES;
00600 global_lon *= RADIANS_TO_DEGREES;
00601 }
00602
00603 if (input_len_unit==FEET)
00604 global_elev *= FEET_TO_METERS;
00605
00606
00607 if (global_cs_name == local_cs_name_)
00608 {
00609
00610 local_lat = global_lat;
00611 local_lon = global_lon;
00612 local_elev = global_elev;
00613 }
00614 else if (global_cs_name == vpgl_lvcs::nad27n)
00615 {
00616
00617 if (local_cs_name_ == vpgl_lvcs::wgs84)
00618 {
00619 nad27n_to_wgs84(global_lat, global_lon, global_elev,
00620 &local_lat, &local_lon, &local_elev);
00621 }
00622 else if (local_cs_name_ == vpgl_lvcs::wgs72)
00623 {
00624 nad27n_to_wgs72(global_lat, global_lon, global_elev,
00625 &local_lat, &local_lon, &local_elev);
00626 }
00627 else if (local_cs_name_ == vpgl_lvcs::utm)
00628 {
00629 nad27n_to_wgs84(global_lat, global_lon, global_elev,
00630 &local_lat, &local_lon, &local_elev);
00631
00632 vpgl_utm u; int zone;
00633 u.transform(local_lat, local_lon, pointout_x, pointout_y, zone);
00634 if (zone != localUTMOrigin_Zone_) {
00635 vcl_cerr << "In vpgl_lvcs::global_to_local() -- the UTM zone of the input point is not the same as the zone of the lvcs origin!\n";
00636 return;
00637 }
00638 pointout_x -= localUTMOrigin_X_East_;
00639 pointout_y -= localUTMOrigin_Y_North_;
00640 pointout_z = global_elev - localCSOriginElev_*local_to_meters;
00641 if (localXYZUnit_==FEET)
00642 {
00643 pointout_x *= METERS_TO_FEET;
00644 pointout_y *= METERS_TO_FEET;
00645 pointout_z *= METERS_TO_FEET;
00646 }
00647
00648 inverse_local_transform(pointout_x,pointout_y);
00649 return;
00650 }
00651 else {
00652 vcl_cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
00653 << " unrecognized." << '\n';
00654 local_lat = local_lon = local_elev = 0.0;
00655 }
00656 }
00657 else if (global_cs_name == vpgl_lvcs::wgs72)
00658 {
00659
00660 if (local_cs_name_ == vpgl_lvcs::nad27n)
00661 {
00662 wgs72_to_nad27n(global_lat, global_lon, global_elev,
00663 &local_lat, &local_lon, &local_elev);
00664 }
00665 else if (local_cs_name_ == vpgl_lvcs::wgs84)
00666 {
00667 wgs72_to_wgs84(global_lat, global_lon, global_elev,
00668 &local_lat, &local_lon, &local_elev);
00669 }
00670 else if (local_cs_name_ == vpgl_lvcs::utm)
00671 {
00672 wgs72_to_wgs84(global_lat, global_lon, global_elev,
00673 &local_lat, &local_lon, &local_elev);
00674
00675 vpgl_utm u; int zone;
00676 u.transform(local_lat, local_lon, pointout_x, pointout_y, zone);
00677 if (zone != localUTMOrigin_Zone_) {
00678 vcl_cerr << "In vpgl_lvcs::global_to_local() -- the UTM zone of the input point is not the same as the zone of the lvcs origin!\n";
00679 return;
00680 }
00681 pointout_x -= localUTMOrigin_X_East_;
00682 pointout_y -= localUTMOrigin_Y_North_;
00683 pointout_z = global_elev - localCSOriginElev_*local_to_meters;
00684 if (localXYZUnit_==FEET)
00685 {
00686 pointout_x *= METERS_TO_FEET;
00687 pointout_y *= METERS_TO_FEET;
00688 pointout_z *= METERS_TO_FEET;
00689 }
00690
00691 inverse_local_transform(pointout_x,pointout_y);
00692 return;
00693 }
00694 else {
00695 vcl_cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
00696 << " unrecognized." << '\n';
00697 local_lat = local_lon = local_elev = 0.0;
00698 }
00699 }
00700 else if (global_cs_name == vpgl_lvcs::wgs84)
00701 {
00702
00703 if (local_cs_name_ == vpgl_lvcs::nad27n)
00704 {
00705 wgs84_to_nad27n(global_lat, global_lon, global_elev,
00706 &local_lat, &local_lon, &local_elev);
00707 }
00708 else if (local_cs_name_ == vpgl_lvcs::wgs72)
00709 {
00710 wgs84_to_wgs72(global_lat, global_lon, global_elev,
00711 &local_lat, &local_lon, &local_elev);
00712 }
00713 else if (local_cs_name_ == vpgl_lvcs::utm)
00714 {
00715 vpgl_utm u; int zone;
00716 u.transform(global_lat, global_lon, pointout_x, pointout_y, zone);
00717 if (zone != localUTMOrigin_Zone_) {
00718 vcl_cerr << "In vpgl_lvcs::global_to_local() -- the UTM zone of the input point is not the same as the zone of the lvcs origin!\n";
00719 return;
00720 }
00721 pointout_x -= localUTMOrigin_X_East_;
00722 pointout_y -= localUTMOrigin_Y_North_;
00723 pointout_z = global_elev - localCSOriginElev_*local_to_meters;
00724 if (localXYZUnit_ == FEET)
00725 {
00726 pointout_x *= METERS_TO_FEET;
00727 pointout_y *= METERS_TO_FEET;
00728 pointout_z *= METERS_TO_FEET;
00729 }
00730
00731 inverse_local_transform(pointout_x,pointout_y);
00732 return;
00733 }
00734 else {
00735 vcl_cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
00736 << " unrecognized." << '\n';
00737 local_lat = local_lon = local_elev = 0.0;
00738 }
00739 }
00740 else {
00741 vcl_cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
00742 << " unrecognized." << '\n';
00743 local_lat = local_lon = local_elev = 0.0;
00744 }
00745
00746
00747
00748 pointout_y =
00749 (local_lat*DEGREES_TO_RADIANS -
00750 localCSOriginLat_*local_to_radians)/lat_scale_;
00751 pointout_x =
00752 (local_lon*DEGREES_TO_RADIANS -
00753 localCSOriginLon_*local_to_radians)/lon_scale_;
00754
00755 pointout_z = local_elev - localCSOriginElev_*local_to_meters;
00756
00757 if (localXYZUnit_==FEET)
00758 {
00759 pointout_x *= METERS_TO_FEET;
00760 pointout_y *= METERS_TO_FEET;
00761 pointout_z *= METERS_TO_FEET;
00762 }
00763
00764 inverse_local_transform(pointout_x,pointout_y);
00765
00766 #ifdef LVCS_DEBUG
00767 vcl_cout << "Global " << vpgl_lvcs::cs_name_strings[global_cs_name]
00768 << " [" << pointin_lon << ", " << pointin_lat << ", " << pointin_z
00769 << "] MAPS TO Local "
00770 << vpgl_lvcs::cs_name_strings[local_cs_name_]
00771 << " [" << pointout_x << ", " << pointout_lat << ", " << pointout_z << "]\n";
00772 #endif
00773 }
00774
00775
00776
00777 void vpgl_lvcs::print(vcl_ostream& strm) const
00778 {
00779 vcl_string len_u = "meters", ang_u="degrees";
00780 if (localXYZUnit_ == FEET)
00781 len_u = "feet";
00782 if (geo_angle_unit_ == RADIANS)
00783 ang_u= "radians";
00784 strm << "lvcs [\n"
00785 << "coordinate system name : " << cs_name_strings[local_cs_name_] << '\n'
00786 << "angle unit " << ang_u << '\n'
00787 << "length unit " << len_u << '\n'
00788 << "local origin(lat, lon, elev) : (" << localCSOriginLat_ << ' '
00789 << localCSOriginLon_ << ' ' << localCSOriginElev_ << ")\n"
00790 << "scales(lat lon) : (" << lat_scale_ << ' ' << lon_scale_ << ")\n"
00791 << "local transform(lox loy theta) : (" << lox_ << ' ' << loy_
00792 << ' ' << theta_ << ")\n]\n";
00793 }
00794
00795
00796 void vpgl_lvcs::read(vcl_istream& strm)
00797 {
00798 vcl_string len_u = "meters", ang_u="degrees";
00799
00800 vcl_string local_cs_name_str;
00801 strm >> local_cs_name_str;
00802 if (local_cs_name_str.compare("wgs84") == 0)
00803 local_cs_name_ = wgs84;
00804 else if (local_cs_name_str.compare("nad27n") == 0)
00805 local_cs_name_ = nad27n;
00806 else if (local_cs_name_str.compare("wgs72") == 0)
00807 local_cs_name_ = wgs72;
00808 else if (local_cs_name_str.compare("utm") == 0)
00809 local_cs_name_ = utm;
00810 else
00811 vcl_cerr << "undefined local_cs_name\n";
00812
00813 strm >> len_u >> ang_u;
00814 if (len_u.compare("feet") == 0)
00815 localXYZUnit_ = FEET;
00816 else if (len_u.compare("meters") == 0)
00817 localXYZUnit_ = METERS;
00818 else
00819 vcl_cerr << "undefined localXYZUnit_ " << len_u << '\n';
00820
00821 if (ang_u.compare("degrees") == 0)
00822 geo_angle_unit_ = DEG;
00823 else if (ang_u.compare("radians") == 0)
00824 geo_angle_unit_ = RADIANS;
00825 else
00826 vcl_cerr << "undefined geo_angle_unit_ " << ang_u << '\n';
00827
00828 strm >> localCSOriginLat_ >> localCSOriginLon_ >> localCSOriginElev_;
00829 strm >> lat_scale_ >> lon_scale_;
00830 strm >> lox_ >> loy_ >> theta_;
00831
00832 if (local_cs_name_ == vpgl_lvcs::utm) {
00833 double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
00834 this->set_angle_conversions(geo_angle_unit_, local_to_radians,
00835 local_to_degrees);
00836 this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
00837
00838
00839 vpgl_utm u;
00840 u.transform(localCSOriginLat_*local_to_degrees, localCSOriginLon_*local_to_degrees, localUTMOrigin_X_East_, localUTMOrigin_Y_North_, localUTMOrigin_Zone_);
00841 vcl_cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << vcl_endl;
00842 }
00843
00844 if (lat_scale_==0.0 && lon_scale_==0.0) {
00845 this->compute_scale();
00846 }
00847 }
00848
00849
00850
00851 void vpgl_lvcs::local_transform(double& x, double& y)
00852 {
00853 double theta=theta_;
00854 if (geo_angle_unit_ == DEG)
00855 theta=theta_*DEGREES_TO_RADIANS;
00856
00857
00858 double xo = x - lox_;
00859 double yo = y - loy_;
00860
00861
00862 double ct,st;
00863 if (vcl_fabs(theta) < 1e-5)
00864 {
00865 ct = 1.0;
00866 st = theta;
00867 }
00868 else
00869 {
00870 ct = vcl_cos(-theta);
00871 st = vcl_sin(-theta);
00872 }
00873 x = ct*xo + st*yo;
00874 y = -st*xo + ct*yo;
00875 }
00876
00877
00878
00879 void vpgl_lvcs::inverse_local_transform(double& x, double& y)
00880 {
00881 double theta=theta_;
00882 if (geo_angle_unit_ == DEG)
00883 theta=theta_*DEGREES_TO_RADIANS;
00884
00885
00886 double ct,st;
00887 if (vcl_fabs(theta) < 1e-5)
00888 {
00889 ct = 1.0;
00890 st = theta;
00891 }
00892 else
00893 {
00894 ct = vcl_cos(-theta);
00895 st = vcl_sin(-theta);
00896 }
00897 double xo = ct*x + st*y;
00898 double yo = -st*x + ct*y;
00899
00900
00901 x = xo + lox_;
00902 y = yo + loy_;
00903 }
00904
00905 vcl_ostream& operator << (vcl_ostream& os, const vpgl_lvcs& local_coord_sys)
00906 {
00907 local_coord_sys.print(os);
00908 return os;
00909 }
00910
00911 vcl_istream& operator >> (vcl_istream& is, vpgl_lvcs& local_coord_sys)
00912 {
00913 local_coord_sys.read(is);
00914 return is;
00915 }
00916
00917 bool vpgl_lvcs::operator==(vpgl_lvcs const& r) const
00918 {
00919 bool eq = true;
00920 eq = eq && (this->local_cs_name_ == r.local_cs_name_);
00921 eq = eq && (this->localCSOriginLat_ == r.localCSOriginLat_);
00922 eq = eq && (this->localCSOriginLon_ == r.localCSOriginLon_);
00923 eq = eq && (this->localCSOriginElev_ == r.localCSOriginElev_);
00924 eq = eq && (this->lat_scale_ == r.lat_scale_);
00925 eq = eq && (this->lon_scale_ == r.lon_scale_);
00926 eq = eq && (this->geo_angle_unit_ == r.geo_angle_unit_);
00927 eq = eq && (this->localXYZUnit_ == r.localXYZUnit_);
00928 eq = eq && (this->lox_ == r.lox_);
00929 eq = eq && (this->loy_ == r.loy_);
00930 eq = eq && (this->theta_ == r.theta_);
00931 return eq;
00932 }