OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimLambertConformalConicProjection.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 //
3 // License: See top LICENSE.txt file.
4 //
5 // Author: Garrett Potts
6 //
7 // Description:
8 //
9 // Calls Lamberts Conformal Conic projection code.
10 //*******************************************************************
11 // $Id: ossimLambertConformalConicProjection.cpp 19640 2011-05-25 15:58:00Z oscarkramer $
12 
13 #include <iostream>
14 #include <iomanip>
17 
18 RTTI_DEF1(ossimLambertConformalConicProjection, "ossimLambertConformalConicProjection", ossimMapProjection)
19 
20 /***************************************************************************/
21 /* DEFINES
22  *
23  */
24 #ifndef PI_OVER_2
25 # define PI_OVER_2 ( M_PI / 2.0)
26 #endif
27 #ifndef TWO_PI
28 # define TWO_PI (2.0 * M_PI)
29 #endif
30 #define MAX_LAT (( M_PI * 89.99972222222222) / 180.0) /* 89 59 59.0 degrees in radians */
31 #define LAMBERT_m(clat,essin) (clat / sqrt(1.0 - essin * essin))
32 #define LAMBERT_t(lat,essin) tan(PI_OVER_4 - lat / 2) / \
33  pow((1.0 - essin) / (1.0 + essin), es_OVER_2)
34 #define ES_SIN(sinlat) (es * sinlat)
35 /**************************************************************************/
36 /* GLOBAL DECLARATIONS
37  *
38  */
39 
40 const double PI_OVER_4 = (M_PI / 4.0);
41 
42 #define LAMBERT_NO_ERROR 0x0000
43 #define LAMBERT_LAT_ERROR 0x0001
44 #define LAMBERT_LON_ERROR 0x0002
45 #define LAMBERT_EASTING_ERROR 0x0004
46 #define LAMBERT_NORTHING_ERROR 0x0008
47 #define LAMBERT_FIRST_STDP_ERROR 0x0010
48 #define LAMBERT_SECOND_STDP_ERROR 0x0020
49 #define LAMBERT_ORIGIN_LAT_ERROR 0x0040
50 #define LAMBERT_CENT_MER_ERROR 0x0080
51 #define LAMBERT_A_ERROR 0x0100
52 #define LAMBERT_B_ERROR 0x0200
53 #define LAMBERT_A_LESS_B_ERROR 0x0400
54 #define LAMBERT_HEMISPHERE_ERROR 0x0800
55 #define LAMBERT_FIRST_SECOND_ERROR 0x1000
56 
58  const ossimGpt& origin)
59  :ossimMapProjection(ellipsoid, origin)
60 {
61  setDefaults();
62  update();
63 }
64 
66  const ossimGpt& origin,
67  double stdParallel1,
68  double stdParallel2,
69  double falseEasting,
70  double falseNorthing)
71  :ossimMapProjection(ellipsoid, origin)
72 {
73  Lambert_Std_Parallel_1 = stdParallel1*RAD_PER_DEG;
74  Lambert_Std_Parallel_2 = stdParallel2*RAD_PER_DEG;
75  Lambert_False_Easting = falseEasting;
76  Lambert_False_Northing = falseNorthing;
77 
78  update();
79 }
80 
82 {
83 }
84 
86 {
87  return new ossimLambertConformalConicProjection(*this);
88 }
89 
91 {
94  theOrigin.latr(),
95  theOrigin.lonr(),
100 
103 
105 }
106 
108 {
110  update();
111 }
112 
114 {
116  update();
117 }
118 
120  double parallel2Degree)
121 {
122  Lambert_Std_Parallel_1 = parallel1Degree*RAD_PER_DEG;
123  Lambert_Std_Parallel_2 = parallel2Degree*RAD_PER_DEG;
124  update();
125 
126 }
127 
129 {
130  Lambert_False_Easting = falseEasting;
131  update();
132 }
133 
135 {
136  Lambert_False_Northing = falseNorthing;
137  update();
138 }
139 
141  double falseNorthing)
142 {
143  Lambert_False_Easting = falseEasting;
144  Lambert_False_Northing = falseNorthing;
145  update();
146 }
147 
149  double parallel2,
150  double falseEasting,
151  double falseNorthing)
152 {
153  Lambert_False_Easting = falseEasting;
154  Lambert_False_Northing = falseNorthing;
157  update();
158 }
159 
160 
162 {
166  Lambert_False_Easting = 0.0;
167 }
168 
170 {
171  double lat = 0.0;
172  double lon = 0.0;
173 
174  Convert_Lambert_To_Geodetic(eastingNorthing.x,
175  eastingNorthing.y,
176  &lat,
177  &lon);
178 
179  return ossimGpt(lat*DEG_PER_RAD, lon*DEG_PER_RAD, 0.0, theDatum);
180 }
181 
183 {
184  double easting = 0.0;
185  double northing = 0.0;
186  ossimGpt gpt = latLon;
187 
188  if (theDatum)
189  {
190  if (theDatum->code() != latLon.datum()->code())
191  {
192  gpt.changeDatum(theDatum); // Shift to our datum.
193  }
194  }
195 
197  gpt.lonr(),
198  &easting,
199  &northing);
200 
201  return ossimDpt(easting, northing);
202 }
203 
205 {
206  kwl.add(prefix,
209  true);
210 
211  kwl.add(prefix,
214  true);
215 
216  return ossimMapProjection::saveState(kwl, prefix);
217 }
218 
220 {
221  bool flag = ossimMapProjection::loadState(kwl, prefix);
222 
223  const char* type = kwl.find(prefix, ossimKeywordNames::TYPE_KW);
224  const char* stdParallel1 = kwl.find(prefix, ossimKeywordNames::STD_PARALLEL_1_KW);
225  const char* stdParallel2 = kwl.find(prefix, ossimKeywordNames::STD_PARALLEL_2_KW);
226 
227  setDefaults();
228 
230  {
233 
234  if(stdParallel1)
235  {
237  }
238  if(stdParallel2)
239  {
241  }
242  }
243  update();
244  return flag;
245 }
246 
248  std::ostream& out) const
249 {
250  // Capture the original flags.
251  std::ios_base::fmtflags f = out.flags();
252 
253  out << setiosflags(ios::fixed) << setprecision(15);
254 
255  out << "// ossimLambertConformalConicProjection::print\n"
259  << Lambert_Std_Parallel_2*DEG_PER_RAD << std::endl;
260 
261  // Reset flags.
262  out.setf(f);
263 
264  return ossimMapProjection::print(out);
265 }
266 
267 /************************************************************************/
268 /* FUNCTIONS
269  *
270  */
271 
273  double f,
274  double Origin_Latitude,
275  double Central_Meridian,
276  double Std_Parallel_1,
277  double Std_Parallel_2,
278  double False_Easting,
279  double False_Northing)
280 
281 { /* BEGIN Set_Lambert_Parameters */
282 /*
283  * The function Set_Lambert_Parameters receives the ellipsoid parameters and
284  * Lambert Conformal Conic projection parameters as inputs, and sets the
285  * corresponding state variables. If any errors occur, the error code(s)
286  * are returned by the function, otherwise LAMBERT_NO_ERROR is returned.
287  *
288  * a : Semi-major axis of ellipsoid, in meters (input)
289  * f : Flattening of ellipsoid (input)
290  * Origin_Latitude : Latitude of origin, in radians (input)
291  * Central_Meridian : Longitude of origin, in radians (input)
292  * Std_Parallel_1 : First standard parallel, in radians (input)
293  * Std_Parallel_2 : Second standard parallel, in radians (input)
294  * False_Easting : False easting, in meters (input)
295  * False_Northing : False northing, in meters (input)
296  */
297 
298  double slat, slat1, clat;
299  double es_sin;
300  double t0, t1, t2;
301  double m1, m2;
302 // double inv_f = 1 / f;
303  long Error_Code = LAMBERT_NO_ERROR;
304 
305 // if (a <= 0.0)
306 // { /* Semi-major axis must be greater than zero */
307 // Error_Code |= LAMBERT_A_ERROR;
308 // }
309 // if ((inv_f < 250) || (inv_f > 350))
310 // { /* Inverse flattening must be between 250 and 350 */
311 // Error_Code |= LAMBERT_INV_F_ERROR;
312 // }
313 // if ((Origin_Latitude < -MAX_LAT) || (Origin_Latitude > MAX_LAT))
314 // { /* Origin Latitude out of range */
315 // Error_Code |= LAMBERT_ORIGIN_LAT_ERROR;
316 // }
317 // if ((Std_Parallel_1 < -MAX_LAT) || (Std_Parallel_1 > MAX_LAT))
318 // { /* First Standard Parallel out of range */
319 // Error_Code |= LAMBERT_FIRST_STDP_ERROR;
320 // }
321 // if ((Std_Parallel_2 < -MAX_LAT) || (Std_Parallel_2 > MAX_LAT))
322 // { /* Second Standard Parallel out of range */
323 // Error_Code |= LAMBERT_SECOND_STDP_ERROR;
324 // }
325 // if ((Std_Parallel_1 == 0) && (Std_Parallel_2 == 0))
326 // { /* First & Second Standard Parallels are both 0 */
327 // Error_Code |= LAMBERT_FIRST_SECOND_ERROR;
328 // }
329 // if (Std_Parallel_1 == -Std_Parallel_2)
330 // { /* Parallels are the negation of each other */
331 // Error_Code |= LAMBERT_HEMISPHERE_ERROR;
332 // }
333 // if ((Central_Meridian < -PI) || (Central_Meridian > TWO_PI))
334 // { /* Origin Longitude out of range */
335 // Error_Code |= LAMBERT_CENT_MER_ERROR;
336 // }
337 
338  if (!Error_Code)
339  { /* no errors */
340 
341  Lambert_a = a;
342  Lambert_f = f;
343  Lambert_Origin_Lat = Origin_Latitude;
344  Lambert_Std_Parallel_1 = Std_Parallel_1;
345  Lambert_Std_Parallel_2 = Std_Parallel_2;
346 // if (Central_Meridian > PI)
347 // Central_Meridian -= TWO_PI;
348  Lambert_Origin_Long = Central_Meridian;
349  Lambert_False_Easting = False_Easting;
350  Lambert_False_Northing = False_Northing;
351 
352  es2 = 2 * Lambert_f - Lambert_f * Lambert_f;
353  es = sqrt(es2);
354  es_OVER_2 = es / 2.0;
355 
356  slat = sin(Lambert_Origin_Lat);
357  es_sin = ES_SIN(slat);
358  t0 = LAMBERT_t(Lambert_Origin_Lat, es_sin);
359 
360  slat1 = sin(Lambert_Std_Parallel_1);
361  clat = cos(Lambert_Std_Parallel_1);
362  es_sin = ES_SIN(slat1);
363  m1 = LAMBERT_m(clat, es_sin);
364  t1 = LAMBERT_t(Lambert_Std_Parallel_1, es_sin);
365 
366 
367  if (fabs(Lambert_Std_Parallel_1 - Lambert_Std_Parallel_2) > 1.0e-10)
368  {
369  slat = sin(Lambert_Std_Parallel_2);
370  clat = cos(Lambert_Std_Parallel_2);
371  es_sin = ES_SIN(slat);
372  m2 = LAMBERT_m(clat, es_sin);
373  t2 = LAMBERT_t(Lambert_Std_Parallel_2, es_sin);
374  n = log(m1 / m2) / log(t1 / t2);
375  }
376  else
377  n = slat1;
378  F = m1 / (n * pow(t1, n));
379  Lambert_aF = Lambert_a * F;
380  if ((t0 == 0) && (n < 0))
381  rho0 = 0.0;
382  else
383  rho0 = Lambert_aF * pow(t0, n);
384 
385  }
386  return (Error_Code);
387 } /* END OF Set_Lambert_Parameters */
388 
389 
391  double *f,
392  double *Origin_Latitude,
393  double *Central_Meridian,
394  double *Std_Parallel_1,
395  double *Std_Parallel_2,
396  double *False_Easting,
397  double *False_Northing)const
398 
399 { /* BEGIN Get_Lambert_Parameters */
400 /*
401  * The function Get_Lambert_Parameters returns the current ellipsoid
402  * parameters and Lambert Conformal Conic projection parameters.
403  *
404  * a : Semi-major axis of ellipsoid, in meters (output)
405  * f : Flattening of ellipsoid (output)
406  * Origin_Latitude : Latitude of origin, in radians (output)
407  * Central_Meridian : Longitude of origin, in radians (output)
408  * Std_Parallel_1 : First standard parallel, in radians (output)
409  * Std_Parallel_2 : Second standard parallel, in radians (output)
410  * False_Easting : False easting, in meters (output)
411  * False_Northing : False northing, in meters (output)
412  */
413 
414 
415  *a = Lambert_a;
416  *f = Lambert_f;
417  *Std_Parallel_1 = Lambert_Std_Parallel_1;
418  *Std_Parallel_2 = Lambert_Std_Parallel_2;
419  *Origin_Latitude = Lambert_Origin_Lat;
420  *Central_Meridian = Lambert_Origin_Long;
421  *False_Easting = Lambert_False_Easting;
422  *False_Northing = Lambert_False_Northing;
423 
424  return;
425 } /* END OF Get_Lambert_Parameters */
426 
427 
429  double Longitude,
430  double *Easting,
431  double *Northing)const
432 
433 { /* BEGIN Convert_Geodetic_To_Lambert */
434 /*
435  * The function Convert_Geodetic_To_Lambert converts Geodetic (latitude and
436  * longitude) coordinates to Lambert Conformal Conic projection (easting
437  * and northing) coordinates, according to the current ellipsoid and
438  * Lambert Conformal Conic projection parameters. If any errors occur, the
439  * error code(s) are returned by the function, otherwise LAMBERT_NO_ERROR is
440  * returned.
441  *
442  * Latitude : Latitude, in radians (input)
443  * Longitude : Longitude, in radians (input)
444  * Easting : Easting (X), in meters (output)
445  * Northing : Northing (Y), in meters (output)
446  */
447 
448  double slat;
449  double es_sin;
450  double t;
451  double rho;
452  double dlam;
453  double theta;
454  long Error_Code = LAMBERT_NO_ERROR;
455 
456 // if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
457 // { /* Latitude out of range */
458 // Error_Code|= LAMBERT_LAT_ERROR;
459 // }
460 // if ((Longitude < -PI) || (Longitude > TWO_PI))
461 // { /* Longitude out of range */
462 // Error_Code|= LAMBERT_LON_ERROR;
463 // }
464 
465  if (!Error_Code)
466  { /* no errors */
467 
468  if (fabs(fabs(Latitude) - PI_OVER_2) > 1.0e-10)
469  {
470  slat = sin(Latitude);
471  es_sin = ES_SIN(slat);
472  t = LAMBERT_t(Latitude, es_sin);
473  rho = Lambert_aF * pow(t, n);
474  }
475  else
476  {
477  if ((Latitude * n) <= 0)
478  { /* Point can not be projected */
479  Error_Code |= LAMBERT_LAT_ERROR;
480  return (Error_Code);
481  }
482  rho = 0.0;
483  }
484 
485  dlam = Longitude - Lambert_Origin_Long;
486 
487 // if (dlam > PI)
488 // {
489 // dlam -= TWO_PI;
490 // }
491 // if (dlam < -PI)
492 // {
493 // dlam += TWO_PI;
494 // }
495 
496  theta = n * dlam;
497 
498  *Easting = rho * sin(theta) + Lambert_False_Easting;
499  *Northing = rho0 - rho * cos(theta) + Lambert_False_Northing;
500 
501  }
502  return (Error_Code);
503 } /* END OF Convert_Geodetic_To_Lambert */
504 
505 
506 
508  double Northing,
509  double *Latitude,
510  double *Longitude)const
511 
512 { /* BEGIN Convert_Lambert_To_Geodetic */
513 /*
514  * The function Convert_Lambert_To_Geodetic converts Lambert Conformal
515  * Conic projection (easting and northing) coordinates to Geodetic
516  * (latitude and longitude) coordinates, according to the current ellipsoid
517  * and Lambert Conformal Conic projection parameters. If any errors occur,
518  * the error code(s) are returned by the function, otherwise LAMBERT_NO_ERROR
519  * is returned.
520  *
521  * Easting : Easting (X), in meters (input)
522  * Northing : Northing (Y), in meters (input)
523  * Latitude : Latitude, in radians (output)
524  * Longitude : Longitude, in radians (output)
525  */
526 
527 
528  double dy, dx;
529  double rho, rho0_MINUS_dy;
530  double t;
531  double PHI;
532  double tempPHI = 0.0;
533  double sin_PHI;
534  double es_sin;
535  double theta = 0.0;
536  double tolerance = 4.85e-10;
537  long Error_Code = LAMBERT_NO_ERROR;
538 
539 // if ((Easting < (Lambert_False_Easting - Lambert_Delta_Easting))
540 // ||(Easting > (Lambert_False_Easting + Lambert_Delta_Easting)))
541 // { /* Easting out of range */
542 // Error_Code |= LAMBERT_EASTING_ERROR;
543 // }
544 // if ((Northing < (Lambert_False_Northing - Lambert_Delta_Northing))
545 // || (Northing > (Lambert_False_Northing + Lambert_Delta_Northing)))
546 // { /* Northing out of range */
547 // Error_Code |= LAMBERT_NORTHING_ERROR;
548 // }
549 
550  if (!Error_Code)
551  { /* no errors */
552 
553  dy = Northing - Lambert_False_Northing;
554  dx = Easting - Lambert_False_Easting;
555  rho0_MINUS_dy = rho0 - dy;
556  rho = sqrt(dx * dx + (rho0_MINUS_dy) * (rho0_MINUS_dy));
557 
558  if (n < 0.0)
559  {
560  rho *= -1.0;
561  dy *= -1.0;
562  dx *= -1.0;
563  rho0_MINUS_dy *= -1.0;
564  }
565 
566  if (rho != 0.0)
567  {
568  theta = atan2(dx, rho0_MINUS_dy);
569  t = pow(rho / (Lambert_aF) , 1.0 / n);
570  PHI = PI_OVER_2 - 2.0 * atan(t);
571  while (fabs(PHI - tempPHI) > tolerance)
572  {
573  tempPHI = PHI;
574  sin_PHI = sin(PHI);
575  es_sin = ES_SIN(sin_PHI);
576  PHI = PI_OVER_2 - 2.0 * atan(t * pow((1.0 - es_sin) / (1.0 + es_sin), es_OVER_2));
577  }
578  *Latitude = PHI;
579  *Longitude = theta / n + Lambert_Origin_Long;
580 
581  if (fabs(*Latitude) < 2.0e-7) /* force lat to 0 to avoid -0 degrees */
582  *Latitude = 0.0;
583  if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
584  *Latitude = PI_OVER_2;
585  else if (*Latitude < -PI_OVER_2)
586  *Latitude = -PI_OVER_2;
587 
588  if (*Longitude > M_PI)
589  {
590  if (*Longitude - M_PI < 3.5e-6)
591  *Longitude = M_PI;
592 // else
593 // *Longitude -= TWO_PI;
594  }
595  if (*Longitude < -M_PI)
596  {
597  if (fabs(*Longitude + M_PI) < 3.5e-6)
598  *Longitude = -M_PI;
599 // else
600 // *Longitude += TWO_PI;
601  }
602 
603  if (fabs(*Longitude) < 2.0e-7) /* force lon to 0 to avoid -0 degrees */
604  *Longitude = 0.0;
605  if (*Longitude > M_PI) /* force distorted values to 180, -180 degrees */
606  *Longitude = M_PI;
607  else if (*Longitude < -M_PI)
608  *Longitude = -M_PI;
609  }
610  else
611  {
612  if (n > 0.0)
613  *Latitude = PI_OVER_2;
614  else
615  *Latitude = -PI_OVER_2;
616  *Longitude = Lambert_Origin_Long;
617  }
618  }
619  return (Error_Code);
620 } /* END OF Convert_Lambert_To_Geodetic */
621 
623 {
625 }
626 
628 {
630 }
631 
632 //*************************************************************************************************
634 //*************************************************************************************************
636 {
637  if (!ossimMapProjection::operator==(proj))
638  return false;
639 
640  const ossimLambertConformalConicProjection* p = dynamic_cast<const ossimLambertConformalConicProjection*>(&proj);
641  if (!p) return false;
642 
645 
646  return true;
647 }
#define LAMBERT_m(clat, essin)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
long Convert_Geodetic_To_Lambert(double Latitude, double Longitude, double *Easting, double *Northing) const
#define DEG_PER_RAD
Represents serializable keyword/value map.
const char * find(const char *key) const
virtual bool operator==(const ossimProjection &projection) const
Returns TRUE if principal parameters are within epsilon tolerance.
bool almostEqual(T x, T y, T tolerance=FLT_EPSILON)
Definition: ossimCommon.h:53
double y
Definition: ossimDpt.h:165
virtual const ossimString & code() const
Definition: ossimDatum.h:57
ossimLambertConformalConicProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
#define ES_SIN(sinlat)
void setParameters(double parallel1, double parallel2, double falseEasting, double falseNorthing)
Allows one to set all parameters for this projections.
static const char * TYPE_KW
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
#define STATIC_TYPE_NAME(T)
Definition: ossimRtti.h:325
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual ossimDpt forward(const ossimGpt &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
virtual std::ostream & print(std::ostream &out) const
Prints data members to stream.
#define M_PI
void setStandardParallels(double parallel1Degree, double prallel2Degree)
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
double toDouble() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
static const char * STD_PARALLEL_1_KW
#define LAMBERT_t(lat, essin)
long Convert_Lambert_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
void Get_Lambert_Parameters(double *a, double *f, double *Origin_Latitude, double *Central_Meridian, double *Std_Parallel_1, double *Std_Parallel_2, double *False_Easting, double *False_Northing) const
double x
Definition: ossimDpt.h:164
double latr() const
latr().
Definition: ossimGpt.h:66
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
const double & getFlattening() const
ossimEllipsoid theEllipsoid
This method verifies that the projection parameters match the current pcs code.
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
virtual ossimGpt inverse(const ossimDpt &eastingNorthing) const
Will take a point in meters and convert it to ground.
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
static const char * STD_PARALLEL_2_KW
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
virtual std::ostream & print(std::ostream &out) const
Prints data members to stream.
long Set_Lambert_Parameters(double a, double f, double Origin_Latitude, double Central_Meridian, double Std_Parallel_1, double Std_Parallel_2, double False_Easting, double False_Northing)
#define RAD_PER_DEG
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.