OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimPolyconicProjection.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 Geotrans Polyconic projection code.
11 //*******************************************************************
12 // $Id: ossimPolyconicProjection.cpp 9094 2006-06-13 19:12:40Z dburken $
13 
14 #include <math.h>
17 
18 RTTI_DEF1(ossimPolyconicProjection, "ossimPolyconicProjection", ossimMapProjection)
19 /***************************************************************************/
20 /*
21  * DEFINES
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 #define POLY_COEFF_TIMES_SIN(coeff, x, latit) (coeff * (sin (x * latit)))
30 #define POLY_M(c0lat,c1s2lat,c2s4lat,c3s6lat) (Poly_a*(c0lat - c1s2lat + c2s4lat - c3s6lat))
31 #define FLOAT_EQ(x,v,epsilon) (((v - epsilon) < x) && (x < (v + epsilon)))
32 #define FOURTY_ONE (41.0 * M_PI / 180.0) /* 41 degrees in radians */
33 
34 #define POLY_NO_ERROR 0x0000
35 #define POLY_LAT_ERROR 0x0001
36 #define POLY_LON_ERROR 0x0002
37 #define POLY_EASTING_ERROR 0x0004
38 #define POLY_NORTHING_ERROR 0x0008
39 #define POLY_ORIGIN_LAT_ERROR 0x0010
40 #define POLY_CENT_MER_ERROR 0x0020
41 #define POLY_A_ERROR 0x0040
42 #define POLY_B_ERROR 0x0080
43 #define POLY_A_LESS_B_ERROR 0x0100
44 #define POLY_LON_WARNING 0x0200
45 
47  const ossimGpt& origin)
48  :ossimMapProjection(ellipsoid, origin)
49 {
50  setDefaults();
51  update();
52 }
53 
55  const ossimGpt& origin,
56  double falseEasting,
57  double falseNorthing)
58  :ossimMapProjection(ellipsoid, origin)
59 {
60  Poly_False_Easting = falseEasting;
61  Poly_False_Northing = falseNorthing;
62  Poly_Max_Easting = 20037509.0;
63  Poly_Max_Northing = 15348215.0;
64  Poly_Min_Easting = -20037509.0;
65  Poly_Min_Northing = -15348215.0;
66 
67  update();
68 }
69 
71 {
74  theOrigin.latr(),
75  theOrigin.lonr(),
78 
81 
83 }
84 
86 {
87  Poly_False_Easting = falseEasting;
88 
89  update();
90 }
91 
93 {
94  Poly_False_Northing = falseNorthing;
95 
96  update();
97 }
98 
100 {
101  Poly_False_Easting = 0.0;
102  Poly_False_Northing = 0.0;
103  Poly_Max_Easting = 20037509.0;
104  Poly_Max_Northing = 15348215.0;
105  Poly_Min_Easting = -20037509.0;
106  Poly_Min_Northing = -15348215.0;
107 }
108 
110  double falseNorthing)
111 {
112  Poly_False_Easting = falseEasting;
113  Poly_False_Northing = falseNorthing;
114 
115  update();
116 }
117 
119 {
120  double lat = 0.0;
121  double lon = 0.0;
122 
123  Convert_Polyconic_To_Geodetic(eastingNorthing.x,
124  eastingNorthing.y,
125  &lat,
126  &lon);
127 
128  return ossimGpt(lat*DEG_PER_RAD, lon*DEG_PER_RAD, 0.0, theDatum);
129 }
130 
132 {
133  double easting = 0.0;
134  double northing = 0.0;
135  ossimGpt gpt = latLon;
136 
137  if (theDatum)
138  {
139  if (theDatum->code() != latLon.datum()->code())
140  {
141  gpt.changeDatum(theDatum); // Shift to our datum.
142  }
143  }
144 
146  gpt.lonr(),
147  &easting,
148  &northing);
149 
150  return ossimDpt(easting, northing);
151 }
152 
153 bool ossimPolyconicProjection::saveState(ossimKeywordlist& kwl, const char* prefix) const
154 {
155  return ossimMapProjection::saveState(kwl, prefix);
156 }
157 
159  const char* prefix)
160 {
161  bool flag = ossimMapProjection::loadState(kwl, prefix);
162  const char* type = kwl.find(prefix, ossimKeywordNames::TYPE_KW);
163 
164  setDefaults();
165 
167  {
170  }
171 
172  update();
173 
174  return flag;
175 }
176 
177 /***************************************************************************/
178 /*
179  * FUNCTIONS
180  */
181 
182 
184  double f,
185  double Origin_Latitude,
186  double Central_Meridian,
187  double False_Easting,
188  double False_Northing)
189 
190 { /* BEGIN Set_Polyconic_Parameters */
191 /*
192  * The function Set_Polyconic_Parameters receives the ellipsoid parameters and
193  * Polyconic projection parameters as inputs, and sets the corresponding state
194  * variables. If any errors occur, the error code(s) are returned by the function,
195  * otherwise POLY_NO_ERROR is returned.
196  *
197  * a : Semi-major axis of ellipsoid, in meters (input)
198  * f : Flattening of ellipsoid (input)
199  * Origin_Latitude : Latitude in radians at which the (input)
200  * point scale factor is 1.0
201  * Central_Meridian : Longitude in radians at the center of (input)
202  * the projection
203  * False_Easting : A coordinate value in meters assigned to the
204  * central meridian of the projection. (input)
205  * False_Northing : A coordinate value in meters assigned to the
206  * origin latitude of the projection (input)
207  */
208 
209  double j, three_es4;
210  double lat, sin2lat, sin4lat, sin6lat;
211  double temp;
212 // double inv_f = 1 / f;
213  long Error_Code = POLY_NO_ERROR;
214 
215 // if (a <= 0.0)
216 // { /* Semi-major axis must be greater than zero */
217 // Error_Code |= POLY_A_ERROR;
218 // }
219 // if ((inv_f < 250) || (inv_f > 350))
220 // { /* Inverse flattening must be between 250 and 350 */
221 // Error_Code |= POLY_INV_F_ERROR;
222 // }
223 // if ((Origin_Latitude < -PI_OVER_2) || (Origin_Latitude > PI_OVER_2))
224 // { /* origin latitude out of range */
225 // Error_Code |= POLY_ORIGIN_LAT_ERROR;
226 // }
227 // if ((Central_Meridian < -M_PI) || (Central_Meridian > TWO_PI))
228 // { /* origin longitude out of range */
229 // Error_Code |= POLY_CENT_MER_ERROR;
230 // }
231  if (!Error_Code)
232  { /* no errors */
233  Poly_a = a;
234  Poly_f = f;
235  Poly_Origin_Lat = Origin_Latitude;
236 // if (Central_Meridian > M_PI)
237 // Central_Meridian -= TWO_PI;
238  Poly_Origin_Long = Central_Meridian;
239  Poly_False_Northing = False_Northing;
240  Poly_False_Easting = False_Easting;
241  es2 = 2 * Poly_f - Poly_f * Poly_f;
242  es4 = es2 * es2;
243  es6 = es4 * es2;
244 
245  j = 45.0 * es6 / 1024.0;
246  three_es4 = 3.0 * es4;
247  c0 = 1.0 - es2 / 4.0 - three_es4 / 64.0 - 5.0 * es6 / 256.0;
248  c1 = 3.0 * es2 / 8.0 + three_es4 / 32.0 + j;
249  c2 = 15.0 * es4 / 256.0 + j;
250  c3 = 35.0 * es6 / 3072.0;
251 
252  lat = c0 * Poly_Origin_Lat;
253  sin2lat = POLY_COEFF_TIMES_SIN(c1, 2.0, Poly_Origin_Lat);
254  sin4lat = POLY_COEFF_TIMES_SIN(c2, 4.0, Poly_Origin_Lat);
255  sin6lat = POLY_COEFF_TIMES_SIN(c3, 6.0, Poly_Origin_Lat);
256  M0 = POLY_M(lat, sin2lat, sin4lat, sin6lat);
257 
258  if (Poly_Origin_Long > 0)
259  {
262  Poly_Max_Easting = 19926189.0;
263  Poly_Min_Easting = -20037509.0;
264  }
265  else if (Poly_Origin_Long < 0)
266  {
269  Poly_Max_Easting = 20037509.0;
270  Poly_Min_Easting = -19926189.0;
271  }
272  else
273  {
276  Poly_Max_Easting = 20037509.0;
277  Poly_Min_Easting = -20037509.0;
278  }
279 
280  } /* END OF if(!Error_Code) */
281  return (Error_Code);
282 } /* END OF Set_Polyconic_Parameters */
283 
285  double *f,
286  double *Origin_Latitude,
287  double *Central_Meridian,
288  double *False_Easting,
289  double *False_Northing)const
290 
291 { /* BEGIN Get_Polyconic_Parameters */
292 /*
293  * The function Get_Polyconic_Parameters returns the current ellipsoid
294  * parameters, and Polyconic projection parameters.
295  *
296  * a : Semi-major axis of ellipsoid, in meters (output)
297  * f : Flattening of ellipsoid (output)
298  * Origin_Latitude : Latitude in radians at which the (output)
299  * point scale factor is 1.0
300  * Central_Meridian : Longitude in radians at the center of (output)
301  * the projection
302  * False_Easting : A coordinate value in meters assigned to the
303  * central meridian of the projection. (output)
304  * False_Northing : A coordinate value in meters assigned to the
305  * origin latitude of the projection (output)
306  */
307 
308  *a = Poly_a;
309  *f = Poly_f;
310  *Origin_Latitude = Poly_Origin_Lat;
311  *Central_Meridian = Poly_Origin_Long;
312  *False_Easting = Poly_False_Easting;
313  *False_Northing = Poly_False_Northing;
314 
315  return;
316 } /* END OF Get_Polyconic_Parameters */
317 
318 
320  double Longitude,
321  double *Easting,
322  double *Northing)const
323 { /* BEGIN Convert_Geodetic_To_Polyconic */
324 /*
325  * The function Convert_Geodetic_To_Polyconic converts geodetic (latitude and
326  * longitude) coordinates to Polyconic projection (easting and northing)
327  * coordinates, according to the current ellipsoid and Polyconic projection
328  * parameters. If any errors occur, the error code(s) are returned by the
329  * function, otherwise POLY_NO_ERROR is returned.
330  *
331  * Latitude : Latitude (phi) in radians (input)
332  * Longitude : Longitude (lambda) in radians (input)
333  * Easting : Easting (X) in meters (output)
334  * Northing : Northing (Y) in meters (output)
335  */
336 
337  double slat = sin(Latitude);
338  double lat, sin2lat, sin4lat, sin6lat;
339  double dlam; /* Longitude - Central Meridan */
340  double NN;
341  double NN_OVER_tlat;
342  double MM;
343  double EE;
344  long Error_Code = POLY_NO_ERROR;
345 
346 // if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
347 // { /* Latitude out of range */
348 // Error_Code |= POLY_LAT_ERROR;
349 // }
350 // if ((Longitude < -M_PI) || (Longitude > TWO_PI))
351 // { /* Longitude out of range */
352 // Error_Code |= POLY_LON_ERROR;
353 // }
354  if (!Error_Code)
355  { /* no errors */
356  dlam = Longitude - Poly_Origin_Long;
357  if (fabs(dlam) > (M_PI / 2.0))
358  { /* Distortion will result if Longitude is more than 90 degrees from the Central Meridian */
359  Error_Code |= POLY_LON_WARNING;
360  }
361 // if (dlam > M_PI)
362 // {
363 // dlam -= TWO_PI;
364 // }
365 // if (dlam < -M_PI)
366 // {
367 // dlam += TWO_PI;
368 // }
369  if (Latitude == 0.0)
370  {
371  *Easting = Poly_a * dlam + Poly_False_Easting;
372  *Northing = -M0 + Poly_False_Northing;
373  }
374  else
375  {
376  NN = Poly_a / sqrt(1.0 - es2 * (slat * slat));
377  NN_OVER_tlat = NN / tan(Latitude);
378  lat = c0 * Latitude;
379  sin2lat = POLY_COEFF_TIMES_SIN(c1, 2.0, Latitude);
380  sin4lat = POLY_COEFF_TIMES_SIN(c2, 4.0, Latitude);
381  sin6lat = POLY_COEFF_TIMES_SIN(c3, 6.0, Latitude);
382  MM = POLY_M(lat, sin2lat, sin4lat, sin6lat);
383  EE = dlam * slat;
384  *Easting = NN_OVER_tlat * sin(EE) + Poly_False_Easting;
385  *Northing = MM - M0 + NN_OVER_tlat * (1.0 - cos(EE)) +
387  }
388  }
389  return (Error_Code);
390 } /* END OF Convert_Geodetic_To_Polyconic */
391 
392 
394  double Northing,
395  double *Latitude,
396  double *Longitude)const
397 { /* BEGIN Convert_Polyconic_To_Geodetic */
398 /*
399  * The function Convert_Polyconic_To_Geodetic converts Polyconic projection
400  * (easting and northing) coordinates to geodetic (latitude and longitude)
401  * coordinates, according to the current ellipsoid and Polyconic projection
402  * coordinates. If any errors occur, the error code(s) are returned by the
403  * function, otherwise POLY_NO_ERROR is returned.
404  *
405  * Easting : Easting (X) in meters (input)
406  * Northing : Northing (Y) in meters (input)
407  * Latitude : Latitude (phi) in radians (output)
408  * Longitude : Longitude (lambda) in radians (output)
409  */
410 
411  double dx; /* Delta easting - Difference in easting (easting-FE) */
412  double dy; /* Delta northing - Difference in northing (northing-FN) */
413  double dx_OVER_Poly_a;
414  double AA;
415  double BB;
416  double CC = 0.0;
417  double PHIn, Delta_PHI = 1.0;
418  double sin_PHIn;
419  double PHI, sin2PHI,sin4PHI, sin6PHI;
420  double Mn, Mn_prime, Ma;
421  double AA_Ma;
422  double Ma2_PLUS_BB;
423  double AA_MINUS_Ma;
424  double tolerance = 1.0e-12; /* approximately 1/1000th of
425  an arc second or 1/10th meter */
426  long Error_Code = POLY_NO_ERROR;
427 
428 // if ((Easting < (Poly_False_Easting + Poly_Min_Easting))
429 // || (Easting > (Poly_False_Easting + Poly_Max_Easting)))
430 // { /* Easting out of range */
431 // Error_Code |= POLY_EASTING_ERROR;
432 // }
433 // if ((Northing < (Poly_False_Northing + Poly_Min_Northing))
434 // || (Northing > (Poly_False_Northing + Poly_Max_Northing)))
435 // { /* Northing out of range */
436 // Error_Code |= POLY_NORTHING_ERROR;
437 // }
438  if (!Error_Code)
439  { /* no errors */
440  dy = Northing - Poly_False_Northing;
441  dx = Easting - Poly_False_Easting;
442  dx_OVER_Poly_a = dx / Poly_a;
443  if (FLOAT_EQ(dy,-M0,1))
444  {
445  *Latitude = 0.0;
446  *Longitude = dx_OVER_Poly_a + Poly_Origin_Long;
447  }
448  else
449  {
450  AA = (M0 + dy) / Poly_a;
451  BB = dx_OVER_Poly_a * dx_OVER_Poly_a + (AA * AA);
452  PHIn = AA;
453 
454  while (fabs(Delta_PHI) > tolerance)
455  {
456  sin_PHIn = sin(PHIn);
457  CC = sqrt(1.0 - es2 * sin_PHIn * sin_PHIn) * tan(PHIn);
458  PHI = c0 * PHIn;
459  sin2PHI = POLY_COEFF_TIMES_SIN(c1, 2.0, PHIn);
460  sin4PHI = POLY_COEFF_TIMES_SIN(c2, 4.0, PHIn);
461  sin6PHI = POLY_COEFF_TIMES_SIN(c3, 6.0, PHIn);
462  Mn = POLY_M(PHI, sin2PHI, sin4PHI, sin6PHI);
463  Mn_prime = c0 - 2.0 * c1 * cos(2.0 * PHIn) + 4.0 * c2 * cos(4.0 * PHIn) -
464  6.0 * c3 * cos(6.0 * PHIn);
465  Ma = Mn / Poly_a;
466  AA_Ma = AA * Ma;
467  Ma2_PLUS_BB = Ma * Ma + BB;
468  AA_MINUS_Ma = AA - Ma;
469  Delta_PHI = (AA_Ma * CC + AA_MINUS_Ma - 0.5 * (Ma2_PLUS_BB) * CC) /
470  (es2 * sin2PHI * (Ma2_PLUS_BB - 2.0 * AA_Ma) /
471  4.0 * CC + (AA_MINUS_Ma) * (CC * Mn_prime - 2.0 / sin2PHI) - Mn_prime);
472  PHIn -= Delta_PHI;
473  }
474  *Latitude = PHIn;
475 
476 // if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
477 // *Latitude = PI_OVER_2;
478 // else if (*Latitude < -PI_OVER_2)
479 // *Latitude = -PI_OVER_2;
480 
481  if (FLOAT_EQ(fabs(*Latitude),PI_OVER_2,.00001) || (*Latitude == 0))
482  *Longitude = Poly_Origin_Long;
483 
484  else
485  {
486  *Longitude = (asin(dx_OVER_Poly_a * CC)) / sin(*Latitude) +
488  }
489  }
490 // if (*Longitude > M_PI)
491 // *Longitude -= TWO_PI;
492 // if (*Longitude < -M_PI)
493 // *Longitude += TWO_PI;
494 
495 // if (*Longitude > M_PI) /* force distorted values to 180, -180 degrees */
496 // *Longitude = M_PI;
497 // else if (*Longitude < -M_PI)
498 // *Longitude = -M_PI;
499 
500  }
501  return (Error_Code);
502 } /* END OF Convert_Polyconic_To_Geodetic */
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 Set_Polyconic_Parameters(double a, double f, double Origin_Latitude, double Central_Meridian, double False_Easting, double False_Northing)
virtual ossimDpt forward(const ossimGpt &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
#define POLY_NO_ERROR
#define DEG_PER_RAD
Represents serializable keyword/value map.
ossimPolyconicProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
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.
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
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
void setFalseNorthing(double falseNorthing)
#define M_PI
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
#define POLY_LON_WARNING
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
#define PI_OVER_2
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
void setFalseEasting(double falseEasting)
long Convert_Polyconic_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
double x
Definition: ossimDpt.h:164
double latr() const
latr().
Definition: ossimGpt.h:66
#define FOURTY_ONE
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
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
#define POLY_COEFF_TIMES_SIN(coeff, x, latit)
#define FLOAT_EQ(x, v, epsilon)
long Convert_Geodetic_To_Polyconic(double Latitude, double Longitude, double *Easting, double *Northing) const
void Get_Polyconic_Parameters(double *a, double *f, double *Origin_Latitude, double *Central_Meridian, double *False_Easting, double *False_Northing) const
#define POLY_M(c0lat, c1s2lat, c2s4lat, c3s6lat)
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.