OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimVanDerGrintenProjection.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 // Copyright (C) 2000 ImageLinks Inc.
3 //
4 // License: See top LICENSE.txt file.
5 //
6 // Author: Garrett Potts
7 //
8 // Description:
9 //
10 // Calls Grinten projection code.
11 //*******************************************************************
12 // $Id: ossimVanDerGrintenProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
15 
16 RTTI_DEF1(ossimVanDerGrintenProjection, "ossimVanDerGrintenProjection", ossimMapProjection)
17 
18 /***************************************************************************/
19 /*
20  * DEFINES
21  */
22 
23 #ifndef PI_OVER_2
24 # define PI_OVER_2 ( M_PI / 2.0)
25 #endif
26 #ifndef TWO_PI
27 # define TWO_PI (2.0 * M_PI)
28 #endif
29 
30 #define MAX_LAT ( 90.0 * (M_PI / 180.0) ) /* 90 degrees in radians */
31 #define FLOAT_EQ(x,v,epsilon) (((v - epsilon) < x) && (x < (v + epsilon)))
32 
33 #define GRIN_NO_ERROR 0x0000
34 #define GRIN_LAT_ERROR 0x0001
35 #define GRIN_LON_ERROR 0x0002
36 #define GRIN_EASTING_ERROR 0x0004
37 #define GRIN_NORTHING_ERROR 0x0008
38 #define GRIN_CENT_MER_ERROR 0x0020
39 #define GRIN_A_ERROR 0x0040
40 #define GRIN_B_ERROR 0x0080
41 #define GRIN_A_LESS_B_ERROR 0x0100
42 #define GRIN_RADIUS_ERROR 0x0200
43 
44 /***************************************************************************/
45 /*
46  * GLOBALS
47  */
48 
49 const double TWO_OVER_PI = (2.0 / M_PI);
50 const double PI_OVER_3 = (M_PI / 3.0);
51 const double ONE_THIRD = (1.0 / 3.0);
52 
53 
55  const ossimGpt& origin)
56  :ossimMapProjection(ellipsoid, origin)
57 {
58  setDefaults();
59  update();
60 }
61 
63  const ossimGpt& origin,
64  double falseEasting,
65  double falseNorthing)
66  :ossimMapProjection(ellipsoid, origin)
67 {
68  Grin_False_Easting = falseEasting;
69  Grin_False_Northing = falseNorthing;
70 
71  update();
72 }
73 
75 {
78  theOrigin.lonr(),
81 
84 
86 }
87 
89 {
90  Grin_False_Easting = falseEasting;
91 
92  update();
93 }
94 
96 {
97  Grin_False_Northing = falseNorthing;
98 
99  update();
100 }
101 
103 {
104  Grin_False_Easting = 0.0;
105  Grin_False_Northing = 0.0;
106 }
107 
109 {
110  Grin_Origin_Long = centralMeridian;
111  update();
112 }
113 
115  double falseNorthing)
116 {
117  Grin_False_Easting = falseEasting;
118  Grin_False_Northing = falseNorthing;
119 
120  update();
121 }
122 
124 {
125  double lat = 0.0;
126  double lon = 0.0;
127 
128  Convert_Van_der_Grinten_To_Geodetic(eastingNorthing.x,
129  eastingNorthing.y,
130  &lat,
131  &lon);
132 
133  return ossimGpt(lat*DEG_PER_RAD, lon*DEG_PER_RAD, 0.0, theDatum);
134 }
135 
137 {
138  double easting = 0.0;
139  double northing = 0.0;
140  ossimGpt gpt = latLon;
141 
142  if (theDatum)
143  {
144  if (theDatum->code() != latLon.datum()->code())
145  {
146  gpt.changeDatum(theDatum); // Shift to our datum.
147  }
148  }
149 
151  gpt.lonr(),
152  &easting,
153  &northing);
154  return ossimDpt(easting, northing);
155 }
156 
157 bool ossimVanDerGrintenProjection::saveState(ossimKeywordlist& kwl, const char* prefix) const
158 {
159  return ossimMapProjection::saveState(kwl, prefix);
160 }
161 
163  const char* prefix)
164 {
165  bool flag = ossimMapProjection::loadState(kwl, prefix);
166  const char* type = kwl.find(prefix, ossimKeywordNames::TYPE_KW);
167 
168  setDefaults();
169 
171  {
174  }
175 
176  update();
177 
178  return flag;
179 
180 }
181 
182 /***************************************************************************/
183 /*
184  * FUNCTIONS
185  */
186 
187 
189  double f,
190  double Central_Meridian,
191  double False_Easting,
192  double False_Northing)
193 
194 { /* BEGIN Set_Van_der_Grinten_Parameters */
195 /*
196  * The function Set_Van_der_Grinten_Parameters receives the ellipsoid parameters and
197  * projection parameters as inputs, and sets the corresponding state
198  * variables. If any errors occur, the error code(s) are returned by the function,
199  * otherwise Grin_NO_ERROR is returned.
200  *
201  * a : Semi-major axis of ellipsoid, in meters (input)
202  * f : Flattening of ellipsoid (input)
203  * Central_Meridian : Longitude in radians at the center of (input)
204  * the projection
205  * False_Easting : A coordinate value in meters assigned to the
206  * central meridian of the projection. (input)
207  * False_Northing : A coordinate value in meters assigned to the
208  * origin latitude of the projection (input)
209  */
210 
211 // double inv_f = 1 / f;
212  long Error_Code = GRIN_NO_ERROR;
213 
214 // if (a <= 0.0)
215 // { /* Semi-major axis must be greater than zero */
216 // Error_Code |= GRIN_A_ERROR;
217 // }
218 // if ((inv_f < 250) || (inv_f > 350))
219 // { /* Inverse flattening must be between 250 and 350 */
220 // Error_Code |= GRIN_INV_F_ERROR;
221 // }
222 // if ((Central_Meridian < -M_PI) || (Central_Meridian > TWO_PI))
223 // { /* origin longitude out of range */
224 // Error_Code |= GRIN_CENT_MER_ERROR;
225 // }
226  if (!Error_Code)
227  { /* no errors */
228  Grin_a = a;
229  Grin_f = f;
230  es2 = 2 * Grin_f - Grin_f * Grin_f;
231  es4 = es2 * es2;
232  es6 = es4 * es2;
233  /* spherical radius */
234  Ra = Grin_a * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0 * es6 /3024.0);
235  PI_Ra = M_PI * Ra;
236 // if (Central_Meridian > M_PI)
237 // Central_Meridian -= TWO_PI;
238  Grin_Origin_Long = Central_Meridian;
239  Grin_False_Easting = False_Easting;
240  Grin_False_Northing = False_Northing;
241 
242  } /* END OF if(!Error_Code) */
243  return (Error_Code);
244 } /* END OF Set_Van_der_Grinten_Parameters */
245 
246 
248  double *f,
249  double *Central_Meridian,
250  double *False_Easting,
251  double *False_Northing)const
252 
253 { /* BEGIN Get_Van_der_Grinten_Parameters */
254 /*
255  * The function Get_Van_der_Grinten_Parameters returns the current ellipsoid
256  * parameters, and Van Der Grinten projection parameters.
257  *
258  * a : Semi-major axis of ellipsoid, in meters (output)
259  * f : Flattening of ellipsoid (output)
260  * Central_Meridian : Longitude in radians at the center of (output)
261  * the projection
262  * False_Easting : A coordinate value in meters assigned to the
263  * central meridian of the projection. (output)
264  * False_Northing : A coordinate value in meters assigned to the
265  * origin latitude of the projection (output)
266  */
267 
268  *a = Grin_a;
269  *f = Grin_f;
270  *Central_Meridian = Grin_Origin_Long;
271  *False_Easting = Grin_False_Easting;
272  *False_Northing = Grin_False_Northing;
273 
274  return;
275 } /* END OF Get_Van_der_Grinten_Parameters */
276 
277 
279  double Longitude,
280  double *Easting,
281  double *Northing)const
282 
283 { /* BEGIN Convert_Geodetic_To_Van_der_Grinten */
284 /*
285  * The function Convert_Geodetic_To_Van_der_Grinten converts geodetic (latitude and
286  * longitude) coordinates to Van Der Grinten projection (easting and northing)
287  * coordinates, according to the current ellipsoid and Van Der Grinten projection
288  * parameters. If any errors occur, the error code(s) are returned by the
289  * function, otherwise GRIN_NO_ERROR is returned.
290  *
291  * Latitude : Latitude (phi) in radians (input)
292  * Longitude : Longitude (lambda) in radians (input)
293  * Easting : Easting (X) in meters (output)
294  * Northing : Northing (Y) in meters (output)
295  */
296 
297  double dlam; /* Longitude - Central Meridan */
298  double aa, aasqr;
299  double gg;
300  double pp, ppsqr;
301  double gg_MINUS_ppsqr, ppsqr_PLUS_aasqr;
302  double in_theta;
303  double theta;
304  double sin_theta, cos_theta;
305  double qq;
306  long Error_Code = GRIN_NO_ERROR;
307 
308 // if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
309 // { /* Latitude out of range */
310 // Error_Code |= GRIN_LAT_ERROR;
311 // }
312 // if ((Longitude < -M_PI) || (Longitude > TWO_PI))
313 // { /* Longitude out of range */
314 // Error_Code|= GRIN_LON_ERROR;
315 // }
316 
317  if (!Error_Code)
318  { /* no errors */
319 
320  dlam = Longitude - Grin_Origin_Long;
321 // if (dlam > M_PI)
322 // {
323 // dlam -= TWO_PI;
324 // }
325 // if (dlam < -M_PI)
326 // {
327 // dlam += TWO_PI;
328 // }
329 
330  if (Latitude == 0.0)
331  {
332  *Easting = Ra * dlam + Grin_False_Easting;
333  *Northing = 0.0;
334  }
335  else if (dlam == 0.0 || FLOAT_EQ(Latitude,MAX_LAT,.00001) || FLOAT_EQ(Latitude,-MAX_LAT,.00001))
336  {
337  in_theta = fabs(TWO_OVER_PI * Latitude);
338 
339  if (in_theta > 1.0)
340  in_theta = 1.0;
341  else if (in_theta < -1.0)
342  in_theta = -1.0;
343 
344  theta = asin(in_theta);
345  *Easting = 0.0;
346  *Northing = PI_Ra * tan(theta / 2) + Grin_False_Northing;
347  if (Latitude < 0.0)
348  *Northing *= -1.0;
349  }
350  else
351  {
352  aa = 0.5 * fabs(M_PI / dlam - dlam / M_PI);
353  in_theta = fabs(TWO_OVER_PI * Latitude);
354 
355  if (in_theta > 1.0)
356  in_theta = 1.0;
357  else if (in_theta < -1.0)
358  in_theta = -1.0;
359 
360  theta = asin(in_theta);
361  sin_theta = sin(theta);
362  cos_theta = cos(theta);
363  gg = cos_theta / (sin_theta + cos_theta - 1);
364  pp = gg * (2 / sin_theta - 1);
365  aasqr = aa * aa;
366  ppsqr = pp * pp;
367  gg_MINUS_ppsqr = gg - ppsqr;
368  ppsqr_PLUS_aasqr = ppsqr + aasqr;
369  qq = aasqr + gg;
370  *Easting = PI_Ra * (aa * (gg_MINUS_ppsqr) +
371  sqrt(aasqr * (gg_MINUS_ppsqr) * (gg_MINUS_ppsqr) -
372  (ppsqr_PLUS_aasqr) * (gg * gg - ppsqr))) /
373  (ppsqr_PLUS_aasqr) + Grin_False_Easting;
374  if (dlam < 0.0)
375  *Easting *= -1.0;
376  *Northing = PI_Ra * (pp * qq - aa * sqrt ((aasqr + 1) * (ppsqr_PLUS_aasqr) - qq * qq)) /
377  (ppsqr_PLUS_aasqr) + Grin_False_Northing;
378  if (Latitude < 0.0)
379  *Northing *= -1.0;
380  }
381  }
382  return (Error_Code);
383 
384 } /* END OF Convert_Geodetic_To_Van_der_Grinten */
385 
386 
388  double Northing,
389  double *Latitude,
390  double *Longitude)const
391 { /* BEGIN Convert_Van_der_Grinten_To_Geodetic */
392 /*
393  * The function Convert_Van_der_Grinten_To_Geodetic converts Grinten projection
394  * (easting and northing) coordinates to geodetic (latitude and longitude)
395  * coordinates, according to the current ellipsoid and Grinten projection
396  * coordinates. If any errors occur, the error code(s) are returned by the
397  * function, otherwise GRIN_NO_ERROR is returned.
398  *
399  * Easting : Easting (X) in meters (input)
400  * Northing : Northing (Y) in meters (input)
401  * Latitude : Latitude (phi) in radians (output)
402  * Longitude : Longitude (lambda) in radians (output)
403  */
404 
405  double dx, dy;
406  double xx, xxsqr;
407  double yy, yysqr, two_yysqr;
408  double xxsqr_PLUS_yysqr;
409  double c1;
410  double c2;
411  double c3, c3sqr;
412  double c2_OVER_3c3;
413  double dd;
414  double a1;
415  double m1;
416  double i;
417  double theta1;
418 // double temp;
419 // const double epsilon = 1.0e-2;
420 
421  long Error_Code = GRIN_NO_ERROR;
422 
423 // if ((Easting > (Grin_False_Easting + PI_Ra + epsilon)) ||
424 // (Easting < (Grin_False_Easting - PI_Ra - epsilon)))
425 // { /* Easting out of range */
426 // Error_Code |= GRIN_EASTING_ERROR;
427 // }
428 // if ((Northing > (Grin_False_Northing + PI_Ra + epsilon)) ||
429 // (Northing < (Grin_False_Northing - PI_Ra - epsilon)))
430 // { /* Northing out of range */
431 // Error_Code |= GRIN_NORTHING_ERROR;
432 // }
433 // if (!Error_Code)
434 // {
435 // temp = sqrt(Easting * Easting + Northing * Northing);
436 
437 // if ((temp > (Grin_False_Easting + PI_Ra + epsilon)) ||
438 // (temp > (Grin_False_Northing + PI_Ra + epsilon)) ||
439 // (temp < (Grin_False_Easting - PI_Ra - epsilon)) ||
440 // (temp < (Grin_False_Northing - PI_Ra - epsilon)))
441 // { /* Point is outside of projection area */
442 // Error_Code |= GRIN_RADIUS_ERROR;
443 // }
444 // }
445 
446  if (!Error_Code)
447  {
448  dy = Northing - Grin_False_Northing;
449  dx = Easting - Grin_False_Easting;
450  xx = dx / PI_Ra;
451  yy = dy / PI_Ra;
452  xxsqr = xx * xx;
453  yysqr = yy * yy;
454  xxsqr_PLUS_yysqr = xxsqr + yysqr;
455  two_yysqr = 2 * yysqr;
456 
457  if (Northing == 0.0)
458  *Latitude = 0.0;
459 
460  else
461  {
462  c1 = - fabs(yy) * (1 + xxsqr_PLUS_yysqr);
463  c2 = c1 - two_yysqr + xxsqr;
464  c3 = - 2 * c1 + 1 + two_yysqr + (xxsqr_PLUS_yysqr) * (xxsqr_PLUS_yysqr);
465  c2_OVER_3c3 = c2 / (3.0 * c3);
466  c3sqr = c3 * c3;
467  dd = yysqr / c3 + ((2 * c2 * c2 * c2) / (c3sqr * c3) - (9 * c1 * c2) / (c3sqr)) / 27;
468  a1 = (c1 - c2 * c2_OVER_3c3) /c3;
469  m1 = 2 * sqrt(-ONE_THIRD * a1);
470  i = 3 * dd/ (a1 * m1);
471  if ((i > 1.0)||(i < -1.0))
472  *Latitude = MAX_LAT;
473  else
474  {
475  theta1 = ONE_THIRD * acos(3 * dd / (a1 * m1));
476  *Latitude = M_PI * (-m1 * cos(theta1 + PI_OVER_3) - c2_OVER_3c3);
477  }
478  }
479  if (Northing < 0.0)
480  *Latitude *= -1.0;
481 
482  if (xx == 0.0)
483  *Longitude = Grin_Origin_Long;
484  else
485  {
486  *Longitude = M_PI * (xxsqr_PLUS_yysqr - 1 +
487  sqrt(1 + (2 * xxsqr - two_yysqr) + (xxsqr_PLUS_yysqr) * (xxsqr_PLUS_yysqr))) /
488  (2 * xx) + Grin_Origin_Long;
489  }
490 // if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
491 // *Latitude = PI_OVER_2;
492 // else if (*Latitude < -PI_OVER_2)
493 // *Latitude = -PI_OVER_2;
494 
495 // if (*Longitude > M_PI)
496 // *Longitude -= TWO_PI;
497 // if (*Longitude < -M_PI)
498 // *Longitude += TWO_PI;
499 
500 // if (*Longitude > M_PI) /* force distorted values to 180, -180 degrees */
501 // *Longitude = M_PI;
502 // else if (*Longitude < -M_PI)
503 // *Longitude = -M_PI;
504 
505  }
506  return (Error_Code);
507 
508 } /* END OF Convert_Van_der_Grinten_To_Geodetic */
509 
510 //*************************************************************************************************
512 //*************************************************************************************************
514 {
515  if (!ossimMapProjection::operator==(proj))
516  return false;
517 
519  dynamic_cast<const ossimVanDerGrintenProjection*>(&proj);
520  if (!p) return false;
521 
523 
524  return true;
525 }
virtual ossimDpt forward(const ossimGpt &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
#define DEG_PER_RAD
Represents serializable keyword/value map.
void Get_Van_der_Grinten_Parameters(double *a, double *f, double *Central_Meridian, double *False_Easting, double *False_Northing) const
const char * find(const char *key) const
virtual ossimGpt inverse(const ossimDpt &eastingNorthing) const
Will take a point in meters and convert it to ground.
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
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
void setFalseNorthing(double falseNorthing)
#define M_PI
void setCentralMeridian(double centralMeridian)
const double & getA() const
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
const double ONE_THIRD
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
const double TWO_OVER_PI
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
long Convert_Geodetic_To_Van_der_Grinten(double Latitude, double Longitude, double *Easting, double *Northing) const
#define GRIN_NO_ERROR
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
double x
Definition: ossimDpt.h:164
double latr() const
latr().
Definition: ossimGpt.h:66
ossimVanDerGrintenProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
const double & getFlattening() const
long Convert_Van_der_Grinten_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) 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
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
#define FLOAT_EQ(x, v, epsilon)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
long Set_Van_der_Grinten_Parameters(double a, double f, double Central_Meridian, double False_Easting, double False_Northing)
const double PI_OVER_3
virtual bool operator==(const ossimProjection &projection) const
Returns TRUE if principal parameters are within epsilon tolerance.
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.