vpgl_lvcs.cxx
Go to the documentation of this file.
1 #include <string>
2 #include <cstring>
3 #include "vpgl_lvcs.h"
4 //:
5 // \file
6 #ifdef _MSC_VER
7 # include <vcl_msvc_warnings.h>
8 #endif
12 #include <vpgl/vpgl_utm.h>
13 
14 #define SMALL_STEP 1.0e-6 // assumed to be in radians
15 
16 const char* vpgl_lvcs::cs_name_strings[] = { "wgs84", "nad27n", "wgs72", "utm"};
17 
19 {
20  for (int i=0; i < vpgl_lvcs::NumNames; i++)
21  if (std::strcmp(s, vpgl_lvcs::cs_name_strings[i]) == 0)
22  return (vpgl_lvcs::cs_names) i;
23  return vpgl_lvcs::NumNames;
24 }
25 
26 void vpgl_lvcs::set_angle_conversions(AngUnits ang_unit, double& to_radians,
27  double& to_degrees)
28 {
29  to_radians=1.0;
30  to_degrees=1.0;
31  if (ang_unit == DEG)
32  to_radians = DEGREES_TO_RADIANS;
33  else
34  to_degrees = RADIANS_TO_DEGREES;
35 }
36 
37 void vpgl_lvcs::set_length_conversions(LenUnits len_unit, double& to_meters,
38  double& to_feet)
39 {
40  to_meters = 1.0;
41  to_feet = 1.0;
42  if (len_unit == FEET)
43  to_meters = FEET_TO_METERS;
44  else
45  to_feet = METERS_TO_FEET;
46 }
47 
49  : vbl_ref_count(),
50  local_cs_name_(lvcs.local_cs_name_),
51  localCSOriginLat_(lvcs.localCSOriginLat_),
52  localCSOriginLon_(lvcs.localCSOriginLon_),
53  localCSOriginElev_(lvcs.localCSOriginElev_),
54  lat_scale_(lvcs.lat_scale_),
55  lon_scale_(lvcs.lon_scale_),
56  geo_angle_unit_(lvcs.geo_angle_unit_),
57  localXYZUnit_(lvcs.localXYZUnit_),
58  lox_(lvcs.lox_),
59  loy_(lvcs.loy_),
60  theta_(lvcs.theta_),
61  localUTMOrigin_X_East_(lvcs.localUTMOrigin_X_East_),
62  localUTMOrigin_Y_North_(lvcs.localUTMOrigin_Y_North_),
63  localUTMOrigin_Zone_(lvcs.localUTMOrigin_Zone_)
64 {
65  if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
66  this->compute_scale();
67 }
68 
69 
71 {
76  lat_scale_ = lvcs.lat_scale_;
77  lon_scale_ = lvcs.lon_scale_;
80  lox_ = lvcs.lox_;
81  loy_ = lvcs.loy_;
82  theta_ = lvcs.theta_;
86  if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
87  this->compute_scale();
88  return *this;
89 }
90 
91 vpgl_lvcs::vpgl_lvcs(double orig_lat, double orig_lon, double orig_elev,
92  cs_names cs_name,
93  double lat_scale, double lon_scale,
94  AngUnits ang_unit, // = DEG
95  LenUnits len_unit, // = METERS
96  double lox,
97  double loy,
98  double theta)
99  :local_cs_name_(cs_name),
100  localCSOriginLat_(orig_lat),
101  localCSOriginLon_(orig_lon),
102  localCSOriginElev_(orig_elev),
103  lat_scale_(lat_scale),
104  lon_scale_(lon_scale),
105  geo_angle_unit_(ang_unit),
106  localXYZUnit_(len_unit),
107  lox_(lox),
108  loy_(loy),
109  theta_(theta)
110 {
111  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
112  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
113  local_to_degrees);
114  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
115 
116  if (cs_name == vpgl_lvcs::utm) {
117  //: the origin is still given in wgs84
118  vpgl_utm u;
120  //std::cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << std::endl;
121  lat_scale_ = 0.0; lon_scale_ = 0.0;
122  }
123  if (lat_scale_ == 0.0 || lon_scale_ == 0.0)
124  this->compute_scale();
125 }
126 
127 //--------------------------------------------------------------------------
128 //: A simplified constructor that takes the origin and specified coordinate system.
129 // The units of the input latitude and longitude values are assumed to be
130 // the same as specified by ang_unit.
131 // Similarly, the unit of elevation is specified by elev_unit.
132 // The local cartesian system is aligned with North and East
133 //
134 vpgl_lvcs::vpgl_lvcs(double orig_lat, double orig_lon, double orig_elev,
135  cs_names cs_name,
136  AngUnits ang_unit,
137  LenUnits len_unit)
138  : local_cs_name_(cs_name),
139  localCSOriginLat_(orig_lat), localCSOriginLon_(orig_lon),
140  localCSOriginElev_(orig_elev),
141  geo_angle_unit_(ang_unit), localXYZUnit_(len_unit), lox_(0), loy_(0), theta_(0)
142 {
143  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
144  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
145  local_to_degrees);
146  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
147 
148  if (cs_name == vpgl_lvcs::utm) {
149  //: the origin is still given in wgs84
150  vpgl_utm u;
152  //std::cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North elev: " << localCSOriginElev_ << std::endl;
153  }
154  lat_scale_ = 0;
155  lon_scale_ = 0;
156  this->compute_scale();
157 }
158 
159 //--------------------------------------------------------------------------
160 //: This constructor takes a lat-lon bounding box and erects a local vertical coordinate system at the center.
161 // The units of the input latitude and longitude values are assumed to be
162 // the same as specified by ang_unit.
163 // Similarly, the unit of elevation is specified by elev_unit.
164 // The local cartesian system is aligned with North and East
165 //
166 vpgl_lvcs::vpgl_lvcs(double lat_low, double lon_low,
167  double lat_high, double lon_high,
168  double elev,
169  cs_names cs_name, AngUnits ang_unit, LenUnits elev_unit)
170  : local_cs_name_(cs_name), localCSOriginElev_(elev),
171  geo_angle_unit_(ang_unit), localXYZUnit_(elev_unit)
172 {
173  double average_lat = (lat_low + lat_high)/2.0;
174  double average_lon = (lon_low + lon_high)/2.0;
175  localCSOriginLat_ = average_lat;
176  localCSOriginLon_ = average_lon;
177 
178  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
179  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
180  local_to_degrees);
181  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
182 
183  if (cs_name == vpgl_lvcs::utm) {
184  //: the origin is still given in wgs84
185  vpgl_utm u;
187  //std::cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << std::endl;
188  }
189 
190 
191  lat_scale_ = 0;
192  lon_scale_ = 0;
193  this->compute_scale();
194 }
195 
196 double vpgl_lvcs::radians_to_degrees(const double val)
197 {
198  return val*RADIANS_TO_DEGREES;
199 }
200 
201 void vpgl_lvcs::radians_to_degrees(double& x, double& y, double& z)
202 {
203  x = x * RADIANS_TO_DEGREES;
204  y = y * RADIANS_TO_DEGREES;
205  z = z * RADIANS_TO_DEGREES;
206 }
207 
208 void vpgl_lvcs::degrees_to_dms(double geoval, int& degrees, int& minutes, double& seconds)
209 {
210  double fmin = std::fabs(geoval - (int)geoval)*60.0;
211  int isec = (int) ((fmin - (int)fmin)*60.0 + .5);
212  int imin = (int) ((isec == 60) ? fmin+1 : fmin) ;
213  int extra = (geoval>0) ? 1 : -1;
214  degrees = (int) ( (imin == 60) ? geoval+extra : geoval);
215  minutes = ( imin== 60 ? 0 : imin);
216  seconds = (fmin - (int)fmin)*60.0;
217 }
218 
219 // compute the scales for the given coordinate system.
221 {
222  double wgs84_phi, wgs84_lamda, wgs84_hgt; // WGS84 coords of the origin
223  double grs80_x, grs80_y, grs80_z; // GRS80 coords of the origin
224  double grs80_x1, grs80_y1, grs80_z1;
225  double to_meters, to_feet, to_radians, to_degrees;
226  this->set_angle_conversions(geo_angle_unit_, to_radians, to_degrees);
227  this->set_length_conversions(localXYZUnit_, to_meters, to_feet);
228  // Convert origin to WGS84
229  switch (local_cs_name_)
230  {
231  case vpgl_lvcs::utm:
232  case vpgl_lvcs::wgs84:
233  wgs84_phi = localCSOriginLat_*to_radians;
234  wgs84_lamda = localCSOriginLon_*to_radians;
235  wgs84_hgt = localCSOriginElev_*to_meters;
236  break;
237 
238  case vpgl_lvcs::nad27n:
239  //The inputs, phi and lamda, are assumed to be in degrees
241  localCSOriginLon_*to_degrees,
242  localCSOriginElev_*to_meters,
243  &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
244  wgs84_phi *= to_radians;
245  wgs84_lamda *= to_radians;
246  break;
247  case vpgl_lvcs::wgs72:
248  //The inputs, phi and lamda, are assumed to be in degrees
250  localCSOriginLon_*to_degrees,
251  localCSOriginElev_*to_meters,
252  &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
253  wgs84_phi *= to_radians;
254  wgs84_lamda *= to_radians;
255  break;
256  case vpgl_lvcs::NumNames:
257  default:
258  wgs84_phi = wgs84_lamda = wgs84_hgt = 0.0; // dummy initialisation
259  break;
260  }
261 
262  //The inputs, wgs84_phi, wgs84_lamda, are assumed to be in radians
263  //The inputs wgs84_hgt, GRS80a, GRS80b, are assumed to be in meters
264  //The outputs grs80_x, grs80_y, grs80_z, are in meters
265  latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
266  &grs80_x, &grs80_y, &grs80_z, GRS80_a, GRS80_b);
267 
268  if (lat_scale_ == 0.0)
269  {
270  switch (local_cs_name_)
271  {
272  case vpgl_lvcs::nad27n:
273  //lat, lon inputs are in degrees. elevation is in meters.
274  //SMALL_STEP is in radians
276  (localCSOriginLat_*to_radians+SMALL_STEP)*to_degrees,
277  localCSOriginLon_*to_degrees,
278  localCSOriginElev_*to_meters,
279  &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
280  wgs84_phi *= to_radians;
281  wgs84_lamda *= to_radians;
282  break;
283  case vpgl_lvcs::utm:
284  case vpgl_lvcs::wgs84:
285  wgs84_phi = localCSOriginLat_*to_radians + SMALL_STEP;
286  wgs84_lamda = localCSOriginLon_*to_radians;
287  wgs84_hgt = localCSOriginElev_*to_meters;
288  break;
289  case vpgl_lvcs::wgs72://Why empty?
290  break;
291  case vpgl_lvcs::NumNames:
292  break;
293  default:
294  break;
295  }
296 
297  latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
298  &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
299 
300  lat_scale_ = SMALL_STEP/std::sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
301  (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
302  (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
303  //lat_scale_ is in radians/meter.
304  }
305 
306  if (lon_scale_ == 0.0)
307  {
308  switch (local_cs_name_)
309  {
310  case vpgl_lvcs::nad27n:
312  (localCSOriginLon_*to_radians+SMALL_STEP)*to_degrees,
313  localCSOriginElev_*to_meters,
314  &wgs84_phi, &wgs84_lamda, &wgs84_hgt);
315  wgs84_phi *= to_radians;
316  wgs84_lamda *= to_radians;
317  break;
318  case vpgl_lvcs::utm:
319  case vpgl_lvcs::wgs84:
320  wgs84_phi = localCSOriginLat_*to_radians;
321  wgs84_lamda = localCSOriginLon_*to_radians + SMALL_STEP;
322  wgs84_hgt = localCSOriginElev_*to_meters;
323  break;
324  case vpgl_lvcs::wgs72:
325  break;
326  case vpgl_lvcs::NumNames:
327  break;
328  default:
329  break;
330  }
331 
332  latlong_to_GRS(wgs84_phi, wgs84_lamda, wgs84_hgt,
333  &grs80_x1, &grs80_y1, &grs80_z1, GRS80_a, GRS80_b);
334 
335  lon_scale_ = SMALL_STEP/std::sqrt((grs80_x - grs80_x1)*(grs80_x - grs80_x1) +
336  (grs80_y - grs80_y1)*(grs80_y - grs80_y1) +
337  (grs80_z - grs80_z1)*(grs80_z - grs80_z1));
338  //lon_scale_ is in radians/meter
339  }
340 }
341 
342 //------------------------------------------------------------------------------
343 //: Converts pointin, given in local vertical coord system, to pointout in the global coord system given by the string lobalcs_name.
344 // X, Y, Z in pointin are assumed to be lengths, in the units specified
345 // by this->localXYZUnit_.
346 // pointout is written out in [angle, angle, length], as specified by
347 // the specified units
348 // If global_cs_name == UTM, pointout_lon is X_East, pointout_lat is Y_North
349 // If global_cs_name == WGS84, the pointin needs to be at same hemisphere (north or south) as the lvcs origin
350 void vpgl_lvcs::local_to_global(const double pointin_x,
351  const double pointin_y,
352  const double pointin_z,
353  cs_names global_cs_name,
354  double& pointout_lon,
355  double& pointout_lat,
356  double& pointout_z,
357  AngUnits output_ang_unit,
358  LenUnits output_len_unit
359  )
360 {
361  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
362  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
363  local_to_degrees);
364  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
365 
366  double local_lat, local_lon, local_elev;
367  double global_lat, global_lon, global_elev;
368 
369  // First apply transform to align axes with compass.
370  double aligned_x = pointin_x;
371  double aligned_y = pointin_y;
372  local_transform(aligned_x, aligned_y);
373 
374  // Check current system is in south hemisphere or north hemisphere
375  bool south_flag = false;
376  if (localCSOriginLat_ < 0)
377  south_flag = true;
378 
380 
381 
382  if (global_cs_name == vpgl_lvcs::utm) {
383  if (output_len_unit == METERS) {
384  pointout_lon = aligned_x*local_to_meters + localUTMOrigin_X_East_;
385  pointout_lat = aligned_y*local_to_meters + localUTMOrigin_Y_North_;
386  pointout_z = pointin_z*local_to_meters + localCSOriginElev_*local_to_meters;
387  }
388  else {
389  pointout_lon = aligned_x*local_to_feet + localUTMOrigin_X_East_*local_to_feet;
390  pointout_lat = aligned_y*local_to_feet + localUTMOrigin_Y_North_*local_to_feet;
391  pointout_z = pointin_z*local_to_feet + localCSOriginElev_*local_to_feet;
392  }
393  return;
394  }
395 
396  vpgl_utm u;
397  u.transform(localUTMOrigin_Zone_, pointin_x*local_to_meters + localUTMOrigin_X_East_,
398  pointin_y*local_to_meters + localUTMOrigin_Y_North_,
399  pointin_z*local_to_meters + localCSOriginElev_*local_to_meters,
400  local_lat, local_lon, local_elev, south_flag);
401 
402  if (global_cs_name == vpgl_lvcs::wgs84) { // global values will be in degrees and in meters
403  global_lat = local_lat;
404  global_lon = local_lon;
405  global_elev = local_elev;
406  }
407  else if (global_cs_name == vpgl_lvcs::nad27n)
408  {
409  wgs84_to_nad27n(local_lat,
410  local_lon,
411  local_elev,
412  &global_lat, &global_lon, &global_elev);
413  }
414  else if (global_cs_name == vpgl_lvcs::wgs72)
415  {
416  wgs84_to_wgs72(local_lat,
417  local_lon,
418  local_elev,
419  &global_lat, &global_lon, &global_elev);
420  }
421  else {
422  std::cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
423  << " unrecognized." << '\n';
424  global_lat = global_lon = global_elev = 0.0; // dummy initialisation
425  }
426  }
427  else {
428  // Now compute the lat, lon, elev of the output point in Local CS
429  local_lat = aligned_y*local_to_meters*lat_scale_ + localCSOriginLat_*local_to_radians;
430  local_lon = aligned_x*local_to_meters*lon_scale_ + localCSOriginLon_*local_to_radians;
431  local_elev = pointin_z*local_to_meters + localCSOriginElev_*local_to_meters;
432 
433  local_lat *= RADIANS_TO_DEGREES;
434  local_lon *= RADIANS_TO_DEGREES;
435 
436  //at this point local_lat, local_lon are in degrees
437  //local_elev is in meters
438  if (local_cs_name_ == global_cs_name)
439  {
440  // Local and global coord systems are the same
441  global_lat = local_lat;
442  global_lon = local_lon;
443  global_elev = local_elev;
444  }
445  else if (local_cs_name_ == vpgl_lvcs::nad27n)
446  {
447  // Convert from "nad27n" to whatever
448  if (global_cs_name == vpgl_lvcs::wgs84)
449  {
450  nad27n_to_wgs84(local_lat,
451  local_lon,
452  local_elev,
453  &global_lat, &global_lon, &global_elev);
454  }
455  else if (global_cs_name == vpgl_lvcs::wgs72)
456  {
457  nad27n_to_wgs72(local_lat, local_lon,
458  local_elev,
459  &global_lat, &global_lon, &global_elev);
460  }
461  else {
462  std::cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
463  << " unrecognized." << '\n';
464  global_lat = global_lon = global_elev = 0.0; // dummy initialisation
465  }
466  }
467  else if (local_cs_name_ == vpgl_lvcs::wgs72)
468  {
469  // Convert from "wgs72" to whatever
470  if (global_cs_name == vpgl_lvcs::nad27n)
471  {
472  wgs72_to_nad27n(local_lat,
473  local_lon,
474  local_elev,
475  &global_lat, &global_lon, &global_elev);
476  }
477  else if (global_cs_name == vpgl_lvcs::wgs84)
478  {
479  wgs72_to_wgs84(local_lat,
480  local_lon,
481  local_elev,
482  &global_lat, &global_lon, &global_elev);
483  }
484  else {
485  std::cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
486  << " unrecognized." << '\n';
487  global_lat = global_lon = global_elev = 0.0; // dummy initialisation
488  }
489  }
490  else if (local_cs_name_ == vpgl_lvcs::wgs84)
491  {
492  // Convert from "wgs84" to whatever
493  if (global_cs_name == vpgl_lvcs::nad27n)
494  {
495  wgs84_to_nad27n(local_lat,
496  local_lon,
497  local_elev,
498  &global_lat, &global_lon, &global_elev);
499  }
500  else if (global_cs_name == vpgl_lvcs::wgs72)
501  {
502  wgs84_to_wgs72(local_lat,
503  local_lon,
504  local_elev,
505  &global_lat, &global_lon, &global_elev);
506  }
507  else {
508  std::cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
509  << " unrecognized." << '\n';
510  global_lat = global_lon = global_elev = 0.0; // dummy initialisation
511  }
512  }
513  else {
514  std::cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
515  << " unrecognized." << '\n';
516  global_lat = global_lon = global_elev = 0.0; // dummy initialisation
517  }
518  }
519 
520  //at this point, global_lat and global_lon are in degrees.
521 
522  if (output_ang_unit==DEG)
523  {
524  pointout_lon = global_lon;
525  pointout_lat = global_lat;
526  }
527  else
528  {
529  pointout_lon = global_lon*DEGREES_TO_RADIANS;
530  pointout_lat = global_lat*DEGREES_TO_RADIANS;
531  }
532 
533  if (output_len_unit == METERS)
534  pointout_z = global_elev;
535  else
536  pointout_z = global_elev*METERS_TO_FEET;
537 
538 #ifdef LVCS_DEBUG
539  std::cout << "Local " << vpgl_lvcs::cs_name_strings[local_cs_name_]
540  << " [" << pointin_y << ", " << pointin_x << ", " << pointin_z
541  << "] MAPS TO Global "
542  << vpgl_lvcs::cs_name_strings[global_cs_name]
543  << " [" << pointout_lat << ", " << pointout_lon << ", " << pointout_z << "]\n";
544 #endif
545 }
546 
547 
548 //----------------------------------------------------------------------------
549 //: Converts pointin, given in a global coord system described by global_cs_name, to pointout in the local vertical coord system.
550 // The units of X, Y, Z are specified by input_ang_unit and input_len_unit
551 // to define lon, lat, elev in (angle, angle, length).
552 // The output point is returned in the units specified by
553 // this->localXYZUnit_.
554 // If global_cs_name == UTM, pointin_lon is X_East, pointin_lat is Y_North
555 void vpgl_lvcs::global_to_local(const double pointin_lon,
556  const double pointin_lat,
557  const double pointin_z,
558  cs_names global_cs_name,
559  double& pointout_x,
560  double& pointout_y,
561  double& pointout_z,
562  AngUnits input_ang_unit,
563  LenUnits input_len_unit)
564 {
565  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
566  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
567  local_to_degrees);
568  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
569  double global_lat, global_lon, global_elev;
570  double local_lat, local_lon, local_elev;
571 
572  global_lat = pointin_lat;
573  global_lon = pointin_lon;
574  global_elev = pointin_z;
575 
576  if (global_cs_name == vpgl_lvcs::utm) {
578  if (input_len_unit == METERS) {
579  pointout_x = pointin_lon - localUTMOrigin_X_East_; // these are always in meters
580  pointout_y = pointin_lat - localUTMOrigin_Y_North_;
581  pointout_z = pointin_z - localCSOriginElev_*local_to_meters;
582  }
583  else {
584  pointout_x = pointin_lon*FEET_TO_METERS + localUTMOrigin_X_East_;
585  pointout_y = pointin_lat*FEET_TO_METERS + localUTMOrigin_Y_North_;
586  pointout_z = pointin_z*FEET_TO_METERS + localCSOriginElev_*local_to_meters;
587  }
588  if (localXYZUnit_==FEET)
589  {
590  pointout_x *= METERS_TO_FEET;
591  pointout_y *= METERS_TO_FEET;
592  pointout_z *= METERS_TO_FEET;
593  }
594  // Transform from compass aligned into local co-ordinates.
595  inverse_local_transform(pointout_x,pointout_y);
596  return;
597  }
598  else {
599  std::cerr << "global cs UTM is not supported with other local cs like wgs84, etc.!\n";
600  return;
601  }
602  }
603 
604  //convert input global point to degrees and meters
605 
606  if (input_ang_unit==RADIANS)
607  {
608  global_lat *= RADIANS_TO_DEGREES;
609  global_lon *= RADIANS_TO_DEGREES;
610  }
611 
612  if (input_len_unit==FEET)
613  global_elev *= FEET_TO_METERS;
614 
615  // Convert from global CS to local CS of the origin of LVCS
616  if (global_cs_name == local_cs_name_)
617  {
618  // Global and local coord systems are the same
619  local_lat = global_lat;
620  local_lon = global_lon;
621  local_elev = global_elev;
622  }
623  else if (global_cs_name == vpgl_lvcs::nad27n)
624  {
625  // Convert from "nad27n" to whatever
627  {
628  nad27n_to_wgs84(global_lat, global_lon, global_elev,
629  &local_lat, &local_lon, &local_elev);
630  }
631  else if (local_cs_name_ == vpgl_lvcs::wgs72)
632  {
633  nad27n_to_wgs72(global_lat, global_lon, global_elev,
634  &local_lat, &local_lon, &local_elev);
635  }
636  else if (local_cs_name_ == vpgl_lvcs::utm)
637  {
638  nad27n_to_wgs84(global_lat, global_lon, global_elev,
639  &local_lat, &local_lon, &local_elev);
640 
641  vpgl_utm u; int zone;
642  u.transform(local_lat, local_lon, pointout_x, pointout_y, zone);
643  if (zone != localUTMOrigin_Zone_) {
644  std::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";
645  return;
646  }
647  pointout_x -= localUTMOrigin_X_East_;
648  pointout_y -= localUTMOrigin_Y_North_;
649  pointout_z = global_elev - localCSOriginElev_*local_to_meters;
650  if (localXYZUnit_==FEET)
651  {
652  pointout_x *= METERS_TO_FEET;
653  pointout_y *= METERS_TO_FEET;
654  pointout_z *= METERS_TO_FEET;
655  }
656  // Transform from compass aligned into local co-ordinates.
657  inverse_local_transform(pointout_x,pointout_y);
658  return;
659  }
660  else {
661  std::cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
662  << " unrecognized." << '\n';
663  local_lat = local_lon = local_elev = 0.0; // dummy initialisation
664  }
665  }
666  else if (global_cs_name == vpgl_lvcs::wgs72)
667  {
668  // Convert from "wgs72" to whatever
670  {
671  wgs72_to_nad27n(global_lat, global_lon, global_elev,
672  &local_lat, &local_lon, &local_elev);
673  }
674  else if (local_cs_name_ == vpgl_lvcs::wgs84)
675  {
676  wgs72_to_wgs84(global_lat, global_lon, global_elev,
677  &local_lat, &local_lon, &local_elev);
678  }
679  else if (local_cs_name_ == vpgl_lvcs::utm)
680  {
681  wgs72_to_wgs84(global_lat, global_lon, global_elev,
682  &local_lat, &local_lon, &local_elev);
683 
684  vpgl_utm u; int zone;
685  u.transform(local_lat, local_lon, pointout_x, pointout_y, zone);
686  if (zone != localUTMOrigin_Zone_) {
687  std::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";
688  return;
689  }
690  pointout_x -= localUTMOrigin_X_East_;
691  pointout_y -= localUTMOrigin_Y_North_;
692  pointout_z = global_elev - localCSOriginElev_*local_to_meters;
693  if (localXYZUnit_==FEET)
694  {
695  pointout_x *= METERS_TO_FEET;
696  pointout_y *= METERS_TO_FEET;
697  pointout_z *= METERS_TO_FEET;
698  }
699  // Transform from compass aligned into local co-ordinates.
700  inverse_local_transform(pointout_x,pointout_y);
701  return;
702  }
703  else {
704  std::cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
705  << " unrecognized." << '\n';
706  local_lat = local_lon = local_elev = 0.0; // dummy initialisation
707  }
708  }
709  else if (global_cs_name == vpgl_lvcs::wgs84)
710  {
711  // Convert from "wgs84" to whatever
713  {
714  wgs84_to_nad27n(global_lat, global_lon, global_elev,
715  &local_lat, &local_lon, &local_elev);
716  }
717  else if (local_cs_name_ == vpgl_lvcs::wgs72)
718  {
719  wgs84_to_wgs72(global_lat, global_lon, global_elev,
720  &local_lat, &local_lon, &local_elev);
721  }
722  else if (local_cs_name_ == vpgl_lvcs::utm)
723  {
724  vpgl_utm u; int zone;
725  u.transform(global_lat, global_lon, pointout_x, pointout_y, zone);
726  if (zone != localUTMOrigin_Zone_) {
727  std::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";
728  return;
729  }
730  pointout_x -= localUTMOrigin_X_East_;
731  pointout_y -= localUTMOrigin_Y_North_;
732  pointout_z = global_elev - localCSOriginElev_*local_to_meters;
733  if (localXYZUnit_ == FEET)
734  {
735  pointout_x *= METERS_TO_FEET;
736  pointout_y *= METERS_TO_FEET;
737  pointout_z *= METERS_TO_FEET;
738  }
739  // Transform from compass aligned into local co-ordinates.
740  inverse_local_transform(pointout_x,pointout_y);
741  return;
742  }
743  else {
744  std::cout << "Error: Local CS " << vpgl_lvcs::cs_name_strings[local_cs_name_]
745  << " unrecognized." << '\n';
746  local_lat = local_lon = local_elev = 0.0; // dummy initialisation
747  }
748  }
749  else {
750  std::cout << "Error: Global CS " << vpgl_lvcs::cs_name_strings[global_cs_name]
751  << " unrecognized." << '\n';
752  local_lat = local_lon = local_elev = 0.0; // dummy initialisation
753  }
754 
755  // Now compute the x, y, z of the point in local vetical CS
756  //first convert the local_lat to radians and local cs origin to meters
757  pointout_y =
758  (local_lat*DEGREES_TO_RADIANS -
759  localCSOriginLat_*local_to_radians)/lat_scale_;
760  pointout_x =
761  (local_lon*DEGREES_TO_RADIANS -
762  localCSOriginLon_*local_to_radians)/lon_scale_;
763 
764  pointout_z = local_elev - localCSOriginElev_*local_to_meters;
765 
766  if (localXYZUnit_==FEET)
767  {
768  pointout_x *= METERS_TO_FEET;
769  pointout_y *= METERS_TO_FEET;
770  pointout_z *= METERS_TO_FEET;
771  }
772  // Transform from compass aligned into local co-ordinates.
773  inverse_local_transform(pointout_x,pointout_y);
774 
775 #ifdef LVCS_DEBUG
776  std::cout << "Global " << vpgl_lvcs::cs_name_strings[global_cs_name]
777  << " [" << pointin_lon << ", " << pointin_lat << ", " << pointin_z
778  << "] MAPS TO Local "
780  << " [" << pointout_x << ", " << pointout_lat << ", " << pointout_z << "]\n";
781 #endif
782 }
783 
784 
785 //: Print internals on strm.
786 void vpgl_lvcs::print(std::ostream& strm) const
787 {
788  std::string len_u = "meters", ang_u="degrees";
789  if (localXYZUnit_ == FEET)
790  len_u = "feet";
791  if (geo_angle_unit_ == RADIANS)
792  ang_u= "radians";
793  strm << "lvcs [\n"
794  << "coordinate system name : " << cs_name_strings[local_cs_name_] << '\n'
795  << "angle unit " << ang_u << '\n'
796  << "length unit " << len_u << '\n'
797  << "local origin(lat, lon, elev) : (" << localCSOriginLat_ << ' '
798  << localCSOriginLon_ << ' ' << localCSOriginElev_ << ")\n"
799  << "scales(lat lon) : (" << lat_scale_ << ' ' << lon_scale_ << ")\n"
800  << "local transform(lox loy theta) : (" << lox_ << ' ' << loy_
801  << ' ' << theta_ << ")\n]\n";
802 }
803 
804 //: Read internals from strm.
805 void vpgl_lvcs::read(std::istream& strm)
806 {
807  std::string len_u = "meters", ang_u="degrees";
808 
809  std::string local_cs_name_str;
810  strm >> local_cs_name_str;
811  if (local_cs_name_str.compare("wgs84") == 0)
813  else if (local_cs_name_str.compare("nad27n") == 0)
815  else if (local_cs_name_str.compare("wgs72") == 0)
817  else if (local_cs_name_str.compare("utm") == 0)
819  else
820  std::cerr << "undefined local_cs_name\n";
821 
822  strm >> len_u >> ang_u;
823  if (len_u.compare("feet") == 0)
825  else if (len_u.compare("meters") == 0)
827  else
828  std::cerr << "undefined localXYZUnit_ " << len_u << '\n';
829 
830  if (ang_u.compare("degrees") == 0)
832  else if (ang_u.compare("radians") == 0)
834  else
835  std::cerr << "undefined geo_angle_unit_ " << ang_u << '\n';
836 
838  strm >> lat_scale_ >> lon_scale_;
839  strm >> lox_ >> loy_ >> theta_;
840 
842  double local_to_meters, local_to_feet, local_to_radians, local_to_degrees;
843  this->set_angle_conversions(geo_angle_unit_, local_to_radians,
844  local_to_degrees);
845  this->set_length_conversions(localXYZUnit_, local_to_meters, local_to_feet);
846 
847  //: the origin is still given in wgs84
848  vpgl_utm u;
850  //std::cout << "utm origin zone: " << localUTMOrigin_Zone_ << ' ' << localUTMOrigin_X_East_ << " East " << localUTMOrigin_Y_North_ << " North" << std::endl;
851  }
852 
853  if (lat_scale_==0.0 && lon_scale_==0.0) {
854  this->compute_scale();
855  }
856 }
857 
858 void vpgl_lvcs::write(std::ostream& strm) // write just "read" would read
859 {
860  strm.precision(12);
861 
862  if (local_cs_name_ == wgs84)
863  strm << "wgs84" << '\n';
864  else if (local_cs_name_ == nad27n)
865  strm << "nad27n" << '\n';
866  else if (local_cs_name_ == wgs72)
867  strm << "wgs72" << '\n';
868  else if (local_cs_name_ == utm)
869  strm << "utm" << '\n';
870  else
871  std::cerr << "undefined local_cs_name\n";
872 
873  if (localXYZUnit_ == FEET)
874  strm << "feet ";
875  else if (localXYZUnit_ == METERS)
876  strm << "meters ";
877 
878  if (geo_angle_unit_ == DEG)
879  strm << "degrees\n";
880  else if (geo_angle_unit_ == RADIANS)
881  strm << "radians\n";
882 
883  strm << localCSOriginLat_ << ' ' << localCSOriginLon_ << ' ' << localCSOriginElev_ << '\n';
884  strm << "0.0 0.0\n";
885  strm << lox_ << ' ' << loy_ << ' ' << theta_ << '\n';
886 }
887 
888 //------------------------------------------------------------
889 //: Transform from local co-ordinates to north=y,east=x.
890 void vpgl_lvcs::local_transform(double& x, double& y)
891 {
892  double theta=theta_;
893  if (geo_angle_unit_ == DEG)
895 
896  // Offset to real origin - ie. the point whose lat/long was given.
897  double xo = x - lox_;
898  double yo = y - loy_;
899 
900  // Rotate about that point to align y with north.
901  double ct,st;
902  if (std::fabs(theta) < 1e-5)
903  {
904  ct = 1.0;
905  st = theta;
906  }
907  else
908  {
909  ct = std::cos(-theta);
910  st = std::sin(-theta);
911  }
912  x = ct*xo + st*yo;
913  y = -st*xo + ct*yo;
914 }
915 
916 //------------------------------------------------------------
917 //: Transform from north=y,east=x aligned axes to local co-ordinates.
918 void vpgl_lvcs::inverse_local_transform(double& x, double& y)
919 {
920  double theta=theta_;
921  if (geo_angle_unit_ == DEG)
923 
924  // Rotate about that point to align y with north.
925  double ct,st;
926  if (std::fabs(theta) < 1e-5)
927  {
928  ct = 1.0;
929  st = theta;
930  }
931  else
932  {
933  ct = std::cos(-theta);
934  st = std::sin(-theta);
935  }
936  double xo = ct*x + st*y;
937  double yo = -st*x + ct*y;
938 
939  // Offset to local co-ordinate system origin.
940  x = xo + lox_;
941  y = yo + loy_;
942 }
943 
944 std::ostream& operator << (std::ostream& os, const vpgl_lvcs& local_coord_sys)
945 {
946  local_coord_sys.print(os);
947  return os;
948 }
949 
950 std::istream& operator >> (std::istream& is, vpgl_lvcs& local_coord_sys)
951 {
952  local_coord_sys.read(is);
953  return is;
954 }
955 
956 bool vpgl_lvcs::operator==(vpgl_lvcs const& r) const
957 {
958  bool eq = true;
959  eq = eq && (this->local_cs_name_ == r.local_cs_name_);
960  eq = eq && (this->localCSOriginLat_ == r.localCSOriginLat_);
961  eq = eq && (this->localCSOriginLon_ == r.localCSOriginLon_);
962  eq = eq && (this->localCSOriginElev_ == r.localCSOriginElev_);
963  eq = eq && (this->lat_scale_ == r.lat_scale_);
964  eq = eq && (this->lon_scale_ == r.lon_scale_);
965  eq = eq && (this->geo_angle_unit_ == r.geo_angle_unit_);
966  eq = eq && (this->localXYZUnit_ == r.localXYZUnit_);
967  eq = eq && (this->lox_ == r.lox_);
968  eq = eq && (this->loy_ == r.loy_);
969  eq = eq && (this->theta_ == r.theta_);
970  return eq;
971 }
972 
973 //: Binary save self to stream.
975 {
976  vsl_b_write(os, version());
977  vsl_b_write(os, (int)local_cs_name_);
981  vsl_b_write(os, lat_scale_);
982  vsl_b_write(os, lon_scale_);
983  vsl_b_write(os, (int)geo_angle_unit_);
984  vsl_b_write(os, (int)localXYZUnit_);
985  vsl_b_write(os, lox_);
986  vsl_b_write(os, loy_);
987  vsl_b_write(os, theta_);
991 }
992 
993 
994 //: Binary load self from stream.
996 {
997  if (!is) return;
998  short ver;
999  vsl_b_read(is, ver);
1000  switch (ver)
1001  {
1002  case 1:
1003  int val;
1008  vsl_b_read(is, lat_scale_);
1009  vsl_b_read(is, lon_scale_);
1011  vsl_b_read(is, val); localXYZUnit_ = (vpgl_lvcs::LenUnits)val;
1012  vsl_b_read(is, lox_);
1013  vsl_b_read(is, loy_);
1014  vsl_b_read(is, theta_);
1018  break;
1019 
1020  default:
1021  std::cerr << "I/O ERROR: vpgl_lvcs::b_read(vsl_b_istream&)\n"
1022  << " Unknown version number "<< ver << '\n';
1023  is.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
1024  return;
1025  }
1026 }
#define RADIANS_TO_DEGREES
double localCSOriginLon_
Lon (in geo_angle_unit_) of the origin.
Definition: vpgl_lvcs.h:161
short version() const
Return IO version number;.
Definition: vpgl_lvcs.h:141
#define FEET_TO_METERS
double localCSOriginElev_
Elev (in localXYZUnit_) of the origin.
Definition: vpgl_lvcs.h:162
A geographic coordinate system.
void write(std::ostream &strm)
Definition: vpgl_lvcs.cxx:858
void radians_to_degrees(double &lon, double &lat, double &z)
Definition: vpgl_lvcs.cxx:201
void local_to_global(const double lx, const double ly, const double lz, cs_names cs_name, double &lon, double &lat, double &gz, AngUnits output_ang_unit=DEG, LenUnits output_len_unit=METERS)
Converts pointin, given in local vertical coord system, to pointout in the global coord system given ...
Definition: vpgl_lvcs.cxx:350
double localUTMOrigin_Y_North_
Definition: vpgl_lvcs.h:172
void print(std::ostream &) const
Print internals on strm.
Definition: vpgl_lvcs.cxx:786
void vsl_b_write(vsl_b_ostream &os, vpgl_affine_camera< T > const &camera)
Binary save camera to stream.
double localUTMOrigin_X_East_
Definition: vpgl_lvcs.h:171
void global_to_local(const double lon, const double lat, const double gz, cs_names cs_name, double &lx, double &ly, double &lz, AngUnits output_ang_unit=DEG, LenUnits output_len_unit=METERS)
Converts pointin, given in a global coord system described by global_cs_name, to pointout in the loca...
Definition: vpgl_lvcs.cxx:555
void latlong_to_GRS(double geodetic_lat, double lon, double el, double *x, double *y, double *z, double A, double B)
Major and minor axes of earth.
#define METERS_TO_FEET
double theta_
Direction of north in radians.
Definition: vpgl_lvcs.h:169
void degrees_to_dms(double, int &degrees, int &minutes, double &seconds)
Definition: vpgl_lvcs.cxx:208
void nad27n_to_wgs72(double phi, double lamda, double height, double *wgs72_phi, double *wgs72_lamda, double *wgs72_hgt)
elev in wgs72 (meters)
double loy_
Origin in local co-ordinates.
Definition: vpgl_lvcs.h:168
void set_length_conversions(LenUnits len_unit, double &to_meters, double &to_feet)
Definition: vpgl_lvcs.cxx:37
std::istream & is() const
void b_write(vsl_b_ostream &os) const
Binary save self to stream.
Definition: vpgl_lvcs.cxx:974
void vsl_b_read(vsl_b_istream &is, vpgl_affine_camera< T > &camera)
Binary load camera from stream.
void wgs84_to_nad27n(double phi, double lamda, double height, double *nad27n_phi, double *nad27n_lamda, double *nad27n_hgt)
elev new (meters)
double lox_
Origin in local co-ordinates.
Definition: vpgl_lvcs.h:167
void local_transform(double &x, double &y)
Transform from local co-ordinates to north=y,east=x.
Definition: vpgl_lvcs.cxx:890
A rip-off of the IUE utm_geodedic and geodetic_utm transform classes which allows the GeoPt to suppor...
LenUnits localXYZUnit_
Input (x,y,z) unit (meters or feet) in local CS.
Definition: vpgl_lvcs.h:166
void b_read(vsl_b_istream &is)
Binary load self from stream.
Definition: vpgl_lvcs.cxx:995
static vpgl_lvcs::cs_names str_to_enum(const char *)
Definition: vpgl_lvcs.cxx:18
double localCSOriginLat_
Lat (in geo_angle_unit_) of the origin.
Definition: vpgl_lvcs.h:160
vpgl_lvcs(double orig_lat=0, double orig_lon=0, double orig_elev=0, cs_names cs_name=wgs84, double lat_scale=0, double lon_scale=0, AngUnits ang_unit=DEG, LenUnits len_unit=METERS, double lox=0, double loy=0, double theta=0)
Radians from y axis to north in local co-ordinates.
Definition: vpgl_lvcs.cxx:91
void read(std::istream &strm)
Read internals from strm.
Definition: vpgl_lvcs.cxx:805
AngUnits geo_angle_unit_
lat lon angle unit (degrees or radians)
Definition: vpgl_lvcs.h:165
bool operator==(vpgl_lvcs const &r) const
Definition: vpgl_lvcs.cxx:956
double lat_scale_
radians/meter along lat at the origin)
Definition: vpgl_lvcs.h:163
void inverse_local_transform(double &x, double &y)
Transform from north=y,east=x aligned axes to local co-ordinates.
Definition: vpgl_lvcs.cxx:918
cs_names local_cs_name_
Name of local frame's coord system ("nad27n", "wgs84" etc.)
Definition: vpgl_lvcs.h:159
vpgl_lvcs & operator=(const vpgl_lvcs &)
Definition: vpgl_lvcs.cxx:70
std::ostream & operator<<(std::ostream &s, const vpgl_local_rational_camera< T > &p)
Write to stream.
void wgs72_to_wgs84(double phi, double lamda, double height, double *wgs84_phi, double *wgs84_lamda, double *wgs84_hgt)
elev new (meters)
#define GRS80_a
#define SMALL_STEP
Definition: vpgl_lvcs.cxx:14
void set_angle_conversions(AngUnits ang_unit, double &to_radians, double &to_degrees)
Definition: vpgl_lvcs.cxx:26
void nad27n_to_wgs84(double phi, double lamda, double height, double *wgs84_phi, double *wgs84_lamda, double *wgs84_hgt)
elev new (meters)
#define DEGREES_TO_RADIANS
double lon_scale_
radians/meter along lon at the origin)
Definition: vpgl_lvcs.h:164
void wgs72_to_nad27n(double phi, double lamda, double height, double *nad27n_phi, double *nad27n_lamda, double *nad27n_hgt)
elev in nad27n (meters)
void wgs84_to_wgs72(double phi, double lamda, double height, double *wgs72_phi, double *wgs72_lamda, double *wgs72_hgt)
elev new (meters)
#define GRS80_b
void compute_scale()
Definition: vpgl_lvcs.cxx:220
void transform(int utm_zone, double x, double y, double z, double &lat, double &lon, double &elev, bool south_flag=false, double utm_central_meridian=0)
Definition: vpgl_utm.cxx:155
std::istream & operator >>(std::istream &is, vpgl_lvcs &local_coord_sys)
Definition: vpgl_lvcs.cxx:950
int localUTMOrigin_Zone_
Definition: vpgl_lvcs.h:173
static VPGL_EXPORT const char * cs_name_strings[]
Definition: vpgl_lvcs.h:56