dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
polarst.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* RSC IDENTIFIER: POLAR STEREOGRAPHIC
3  *
4  *
5  * ABSTRACT
6  *
7  * This component provides conversions between geodetic (latitude and
8  * longitude) coordinates and Polar Stereographic (easting and northing)
9  * coordinates.
10  *
11  * ERROR HANDLING
12  *
13  * This component checks parameters for valid values. If an invalid
14  * value is found the error code is combined with the current error code
15  * using the bitwise or. This combining allows multiple error codes to
16  * be returned. The possible error codes are:
17  *
18  * POLAR_NO_ERROR : No errors occurred in function
19  * POLAR_LAT_ERROR : Latitude outside of valid range
20  * (-90 to 90 degrees)
21  * POLAR_LON_ERROR : longitude outside of valid range
22  * (-180 to 360 degrees)
23  * POLAR_ORIGIN_LAT_ERROR : Latitude of true scale outside of valid
24  * range (-90 to 90 degrees)
25  * POLAR_ORIGIN_LON_ERROR : longitude down from pole outside of valid
26  * range (-180 to 360 degrees)
27  * POLAR_EASTING_ERROR : Easting outside of valid range,
28  * depending on ellipsoid and
29  * projection parameters
30  * POLAR_NORTHING_ERROR : Northing outside of valid range,
31  * depending on ellipsoid and
32  * projection parameters
33  * POLAR_RADIUS_ERROR : Coordinates too far from pole,
34  * depending on ellipsoid and
35  * projection parameters
36  * POLAR_A_ERROR : Semi-major axis less than or equal to zero
37  * POLAR_INV_F_ERROR : Inverse flattening outside of valid range
38  * (250 to 350)
39  *
40  *
41  * REUSE NOTES
42  *
43  * POLAR STEREOGRAPHIC is intended for reuse by any application that
44  * performs a Polar Stereographic projection.
45  *
46  *
47  * REFERENCES
48  *
49  * Further information on POLAR STEREOGRAPHIC can be found in the
50  * Reuse Manual.
51  *
52  *
53  * POLAR STEREOGRAPHIC originated from :
54  * U.S. Army Topographic Engineering Center
55  * Geospatial Information Division
56  * 7701 Telegraph Road
57  * Alexandria, VA 22310-3864
58  *
59  *
60  * LICENSES
61  *
62  * None apply to this component.
63  *
64  *
65  * RESTRICTIONS
66  *
67  * POLAR STEREOGRAPHIC has no restrictions.
68  *
69  *
70  * ENVIRONMENT
71  *
72  * POLAR STEREOGRAPHIC was tested and certified in the following
73  * environments:
74  *
75  * 1. Solaris 2.5 with GCC, version 2.8.1
76  * 2. Window 95 with MS Visual C++, version 6
77  *
78  *
79  * MODIFICATIONS
80  *
81  * Date Description
82  * ---- -----------
83  * 06-11-95 Original Code
84  * 03-01-97 Original Code
85  *
86  *
87  */
88 
89 
90 /************************************************************************/
91 /*
92  * INCLUDES
93  */
94 
95 #include <math.h>
96 #include "polarst.h"
97 
98 /*
99  * math.h - Standard C math library
100  * polarst.h - Is for prototype error checking
101  */
102 
103 
104 /************************************************************************/
105 /* DEFINES
106  *
107  */
108 
109 
110 #define PI 3.14159265358979323e0 /* PI */
111 #define PI_OVER_2 (PI / 2.0)
112 #define TWO_PI (2.0 * PI)
113 #define POLAR_POW(EsSin) pow((1.0 - EsSin) / (1.0 + EsSin), es_OVER_2)
114 
115 /************************************************************************/
116 /* GLOBAL DECLARATIONS
117  *
118  */
119 
120 const double PI_Over_4 = (PI / 4.0);
121 
122 /* Ellipsoid Parameters, default to WGS 84 */
123 static double Polar_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */
124 static double Polar_f = 1 / 298.257223563; /* Flattening of ellipsoid */
125 static double es = 0.08181919084262188000; /* Eccentricity of ellipsoid */
126 static double es_OVER_2 = .040909595421311; /* es / 2.0 */
127 static double Southern_Hemisphere = 0; /* Flag variable */
128 static double tc = 1.0;
129 static double e4 = 1.0033565552493;
130 static double Polar_a_mc = 6378137.0; /* Polar_a * mc */
131 static double two_Polar_a = 12756274.0; /* 2.0 * Polar_a */
132 
133 /* Polar Stereographic projection Parameters */
134 static double Polar_Origin_Lat = ((PI * 90) / 180); /* Latitude of origin in radians */
135 static double Polar_Origin_int = 0.0; /* longitude of origin in radians */
136 static double Polar_False_Easting = 0.0; /* False easting in meters */
137 static double Polar_False_Northing = 0.0; /* False northing in meters */
138 
139 /* Maximum variance for easting and northing values for WGS 84. */
140 static double Polar_Delta_Easting = 12713601.0;
141 static double Polar_Delta_Northing = 12713601.0;
142 
143 /* These state variables are for optimization purposes. The only function
144  * that should modify them is Set_Polar_Stereographic_Parameters.
145  */
146 
147 
148 /************************************************************************/
149 /* FUNCTIONS
150  *
151  */
152 
153 
155  double f,
156  double Latitude_of_True_Scale,
157  double longitude_Down_from_Pole,
158  double False_Easting,
159  double False_Northing)
160 
161 { /* BEGIN Set_Polar_Stereographic_Parameters */
162 /*
163  * The function Set_Polar_Stereographic_Parameters receives the ellipsoid
164  * parameters and Polar Stereograpic projection parameters as inputs, and
165  * sets the corresponding state variables. If any errors occur, error
166  * code(s) are returned by the function, otherwise POLAR_NO_ERROR is returned.
167  *
168  * a : Semi-major axis of ellipsoid, in meters (input)
169  * f : Flattening of ellipsoid (input)
170  * Latitude_of_True_Scale : Latitude of true scale, in radians (input)
171  * longitude_Down_from_Pole : longitude down from pole, in radians (input)
172  * False_Easting : Easting (X) at center of projection, in meters (input)
173  * False_Northing : Northing (Y) at center of projection, in meters (input)
174  */
175 
176  double es2;
177  double slat, clat;
178  double essin;
179  double one_PLUS_es, one_MINUS_es;
180  double pow_es;
181  double temp, temp_northing;
182  double inv_f = 1 / f;
183  double mc;
184 // const double epsilon = 1.0e-2;
185  int Error_Code = POLAR_NO_ERROR;
186 
187  if (a <= 0.0)
188  { /* Semi-major axis must be greater than zero */
189  Error_Code |= POLAR_A_ERROR;
190  }
191  if ((inv_f < 250) || (inv_f > 350))
192  { /* Inverse flattening must be between 250 and 350 */
193  Error_Code |= POLAR_INV_F_ERROR;
194  }
195  if ((Latitude_of_True_Scale < -PI_OVER_2) || (Latitude_of_True_Scale > PI_OVER_2))
196  { /* Origin Latitude out of range */
197  Error_Code |= POLAR_ORIGIN_LAT_ERROR;
198  }
199  if ((longitude_Down_from_Pole < -PI) || (longitude_Down_from_Pole > TWO_PI))
200  { /* Origin longitude out of range */
201  Error_Code |= POLAR_ORIGIN_LON_ERROR;
202  }
203 
204  if (!Error_Code)
205  { /* no errors */
206 
207  Polar_a = a;
208  two_Polar_a = 2.0 * Polar_a;
209  Polar_f = f;
210 
211  if (longitude_Down_from_Pole > PI)
212  longitude_Down_from_Pole -= TWO_PI;
213  if (Latitude_of_True_Scale < 0)
214  {
216  Polar_Origin_Lat = -Latitude_of_True_Scale;
217  Polar_Origin_int = -longitude_Down_from_Pole;
218  }
219  else
220  {
222  Polar_Origin_Lat = Latitude_of_True_Scale;
223  Polar_Origin_int = longitude_Down_from_Pole;
224  }
225  Polar_False_Easting = False_Easting;
226  Polar_False_Northing = False_Northing;
227 
228  es2 = 2 * Polar_f - Polar_f * Polar_f;
229  es = sqrt(es2);
230  es_OVER_2 = es / 2.0;
231 
232  if (fabs(fabs(Polar_Origin_Lat) - PI_OVER_2) > 1.0e-10)
233  {
234  slat = sin(Polar_Origin_Lat);
235  essin = es * slat;
236  pow_es = POLAR_POW(essin);
237  clat = cos(Polar_Origin_Lat);
238  mc = clat / sqrt(1.0 - essin * essin);
239  Polar_a_mc = Polar_a * mc;
240  tc = tan(PI_Over_4 - Polar_Origin_Lat / 2.0) / pow_es;
241  }
242  else
243  {
244  one_PLUS_es = 1.0 + es;
245  one_MINUS_es = 1.0 - es;
246  e4 = sqrt(pow(one_PLUS_es, one_PLUS_es) * pow(one_MINUS_es, one_MINUS_es));
247  }
248 
249  /* Calculate Radius */
250  Convert_Geodetic_To_Polar_Stereographic(0, longitude_Down_from_Pole,
251  &temp, &temp_northing);
252 
253  Polar_Delta_Northing = temp_northing;
256  if (Polar_Delta_Northing < 0)
258  Polar_Delta_Northing *= 1.01;
259 
261 
262  /* Polar_Delta_Easting = temp_northing;
263  if(Polar_False_Easting)
264  Polar_Delta_Easting -= Polar_False_Easting;
265  if (Polar_Delta_Easting < 0)
266  Polar_Delta_Easting = -Polar_Delta_Easting;
267  Polar_Delta_Easting *= 1.01;*/
268  }
269 
270  return (Error_Code);
271 } /* END OF Set_Polar_Stereographic_Parameters */
272 
273 
274 
276  double *f,
277  double *Latitude_of_True_Scale,
278  double *longitude_Down_from_Pole,
279  double *False_Easting,
280  double *False_Northing)
281 
282 { /* BEGIN Get_Polar_Stereographic_Parameters */
283 /*
284  * The function Get_Polar_Stereographic_Parameters returns the current
285  * ellipsoid parameters and Polar projection parameters.
286  *
287  * a : Semi-major axis of ellipsoid, in meters (output)
288  * f : Flattening of ellipsoid (output)
289  * Latitude_of_True_Scale : Latitude of true scale, in radians (output)
290  * longitude_Down_from_Pole : longitude down from pole, in radians (output)
291  * False_Easting : Easting (X) at center of projection, in meters (output)
292  * False_Northing : Northing (Y) at center of projection, in meters (output)
293  */
294 
295  *a = Polar_a;
296  *f = Polar_f;
297  *Latitude_of_True_Scale = Polar_Origin_Lat;
298  *longitude_Down_from_Pole = Polar_Origin_int;
299  *False_Easting = Polar_False_Easting;
300  *False_Northing = Polar_False_Northing;
301  return;
302 } /* END OF Get_Polar_Stereographic_Parameters */
303 
304 
306  double longitude,
307  double *Easting,
308  double *Northing)
309 
310 { /* BEGIN Convert_Geodetic_To_Polar_Stereographic */
311 
312 /*
313  * The function Convert_Geodetic_To_Polar_Stereographic converts geodetic
314  * coordinates (latitude and longitude) to Polar Stereographic coordinates
315  * (easting and northing), according to the current ellipsoid
316  * and Polar Stereographic projection parameters. If any errors occur, error
317  * code(s) are returned by the function, otherwise POLAR_NO_ERROR is returned.
318  *
319  * Latitude : Latitude, in radians (input)
320  * longitude : longitude, in radians (input)
321  * Easting : Easting (X), in meters (output)
322  * Northing : Northing (Y), in meters (output)
323  */
324 
325  double dlam;
326  double slat;
327  double essin;
328  double t;
329  double rho;
330  double pow_es;
331  int Error_Code = POLAR_NO_ERROR;
332 
333  if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
334  { /* Latitude out of range */
335  Error_Code |= POLAR_LAT_ERROR;
336  }
337  if ((Latitude < 0) && (Southern_Hemisphere == 0))
338  { /* Latitude and Origin Latitude in different hemispheres */
339  Error_Code |= POLAR_LAT_ERROR;
340  }
341  if ((Latitude > 0) && (Southern_Hemisphere == 1))
342  { /* Latitude and Origin Latitude in different hemispheres */
343  Error_Code |= POLAR_LAT_ERROR;
344  }
345  if ((longitude < -PI) || (longitude > TWO_PI))
346  { /* longitude out of range */
347  Error_Code |= POLAR_LON_ERROR;
348  }
349 
350 
351  if (!Error_Code)
352  { /* no errors */
353 
354  if (fabs(fabs(Latitude) - PI_OVER_2) < 1.0e-10)
355  {
356  *Easting = Polar_False_Easting;
357  *Northing = Polar_False_Northing;
358  }
359  else
360  {
361  if (Southern_Hemisphere != 0)
362  {
363  longitude *= -1.0;
364  Latitude *= -1.0;
365  }
366  dlam = longitude - Polar_Origin_int;
367  if (dlam > PI)
368  {
369  dlam -= TWO_PI;
370  }
371  if (dlam < -PI)
372  {
373  dlam += TWO_PI;
374  }
375  slat = sin(Latitude);
376  essin = es * slat;
377  pow_es = POLAR_POW(essin);
378  t = tan(PI_Over_4 - Latitude / 2.0) / pow_es;
379 
380  if (fabs(fabs(Polar_Origin_Lat) - PI_OVER_2) > 1.0e-10)
381  rho = Polar_a_mc * t / tc;
382  else
383  rho = two_Polar_a * t / e4;
384 
385 
386  if (Southern_Hemisphere != 0)
387  {
388  *Easting = -(rho * sin(dlam) - Polar_False_Easting);
389  // *Easting *= -1.0;
390  *Northing = rho * cos(dlam) + Polar_False_Northing;
391  }
392  else
393  {
394  *Easting = rho * sin(dlam) + Polar_False_Easting;
395  *Northing = -rho * cos(dlam) + Polar_False_Northing;
396  }
397 
398  }
399  }
400  return (Error_Code);
401 } /* END OF Convert_Geodetic_To_Polar_Stereographic */
402 
403 
405  double Northing,
406  double *Latitude,
407  double *longitude)
408 
409 { /* BEGIN Convert_Polar_Stereographic_To_Geodetic */
410 /*
411  * The function Convert_Polar_Stereographic_To_Geodetic converts Polar
412  * Stereographic coordinates (easting and northing) to geodetic
413  * coordinates (latitude and longitude) according to the current ellipsoid
414  * and Polar Stereographic projection Parameters. If any errors occur, the
415  * code(s) are returned by the function, otherwise POLAR_NO_ERROR
416  * is returned.
417  *
418  * Easting : Easting (X), in meters (input)
419  * Northing : Northing (Y), in meters (input)
420  * Latitude : Latitude, in radians (output)
421  * longitude : longitude, in radians (output)
422  *
423  */
424 
425  double dy = 0, dx = 0;
426  double rho = 0;
427  double t;
428  double PHI, sin_PHI;
429  double tempPHI = 0.0;
430  double essin;
431  double pow_es;
432  double delta_radius;
433  int Error_Code = POLAR_NO_ERROR;
434  double min_easting = Polar_False_Easting - Polar_Delta_Easting;
435  double max_easting = Polar_False_Easting + Polar_Delta_Easting;
436  double min_northing = Polar_False_Northing - Polar_Delta_Northing;
437  double max_northing = Polar_False_Northing + Polar_Delta_Northing;
438 
439  if (Easting > max_easting || Easting < min_easting)
440  { /* Easting out of range */
441  Error_Code |= POLAR_EASTING_ERROR;
442  }
443  if (Northing > max_northing || Northing < min_northing)
444  { /* Northing out of range */
445  Error_Code |= POLAR_NORTHING_ERROR;
446  }
447 
448  if (!Error_Code)
449  {
450  dy = Northing - Polar_False_Northing;
451  dx = Easting - Polar_False_Easting;
452 
453  /* Radius of point with origin of false easting, false northing */
454  rho = sqrt(dx * dx + dy * dy);
455 
456  delta_radius = sqrt(Polar_Delta_Easting * Polar_Delta_Easting + Polar_Delta_Northing * Polar_Delta_Northing);
457 
458  if(rho > delta_radius)
459  { /* Point is outside of projection area */
460  Error_Code |= POLAR_RADIUS_ERROR;
461  }
462 
463  if (!Error_Code)
464  { /* no errors */
465  if ((dy == 0.0) && (dx == 0.0))
466  {
467  *Latitude = PI_OVER_2;
468  *longitude = Polar_Origin_int;
469 
470  }
471  else
472  {
473  if (Southern_Hemisphere != 0)
474  {
475  dy *= -1.0;
476  dx *= -1.0;
477  }
478 
479  if (fabs(fabs(Polar_Origin_Lat) - PI_OVER_2) > 1.0e-10)
480  t = rho * tc / (Polar_a_mc);
481  else
482  t = rho * e4 / (two_Polar_a);
483  PHI = PI_OVER_2 - 2.0 * atan(t);
484  while (fabs(PHI - tempPHI) > 1.0e-10)
485  {
486  tempPHI = PHI;
487  sin_PHI = sin(PHI);
488  essin = es * sin_PHI;
489  pow_es = POLAR_POW(essin);
490  PHI = PI_OVER_2 - 2.0 * atan(t * pow_es);
491  }
492  *Latitude = PHI;
493  *longitude = Polar_Origin_int + atan2(dx, -dy);
494 
495  if (*longitude > PI)
496  *longitude -= TWO_PI;
497  else if (*longitude < -PI)
498  *longitude += TWO_PI;
499 
500 
501  if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
502  *Latitude = PI_OVER_2;
503  else if (*Latitude < -PI_OVER_2)
504  *Latitude = -PI_OVER_2;
505 
506  if (*longitude > PI) /* force distorted values to 180, -180 degrees */
507  *longitude = PI;
508  else if (*longitude < -PI)
509  *longitude = -PI;
510 
511  }
512  if (Southern_Hemisphere != 0)
513  {
514  *Latitude *= -1.0;
515  *longitude *= -1.0;
516  }
517  }
518  }
519  return (Error_Code);
520 } /* END OF Convert_Polar_Stereographic_To_Geodetic */
521 
522 
523 
int Convert_Geodetic_To_Polar_Stereographic(double Latitude, double longitude, double *Easting, double *Northing)
Definition: polarst.c:305
#define POLAR_RADIUS_ERROR
Definition: polarst.h:106
#define POLAR_EASTING_ERROR
Definition: polarst.h:102
#define POLAR_LAT_ERROR
Definition: polarst.h:98
static double Polar_Delta_Northing
Definition: polarst.c:141
int Set_Polar_Stereographic_Parameters(double a, double f, double Latitude_of_True_Scale, double longitude_Down_from_Pole, double False_Easting, double False_Northing)
Definition: polarst.c:154
#define PI_OVER_2
Definition: polarst.c:111
static double Polar_a
Definition: polarst.c:123
static double Polar_Origin_Lat
Definition: polarst.c:134
static double Polar_False_Easting
Definition: polarst.c:136
#define POLAR_LON_ERROR
Definition: polarst.h:99
static double Polar_Delta_Easting
Definition: polarst.c:140
int32_t longitude
static double tc
Definition: polarst.c:128
static double Southern_Hemisphere
Definition: polarst.c:127
static double e4
Definition: polarst.c:129
int Convert_Polar_Stereographic_To_Geodetic(double Easting, double Northing, double *Latitude, double *longitude)
Definition: polarst.c:404
#define POLAR_NO_ERROR
Definition: polarst.h:97
#define POLAR_ORIGIN_LAT_ERROR
Definition: polarst.h:100
static double Polar_a_mc
Definition: polarst.c:130
#define POLAR_POW(EsSin)
Definition: polarst.c:113
#define POLAR_INV_F_ERROR
Definition: polarst.h:105
static double two_Polar_a
Definition: polarst.c:131
static double Polar_Origin_int
Definition: polarst.c:135
#define POLAR_ORIGIN_LON_ERROR
Definition: polarst.h:101
static double es_OVER_2
Definition: polarst.c:126
tuple f
Definition: px_mkfw.py:81
static double Polar_False_Northing
Definition: polarst.c:137
#define TWO_PI
Definition: polarst.c:112
#define PI
Definition: polarst.c:110
void Get_Polar_Stereographic_Parameters(double *a, double *f, double *Latitude_of_True_Scale, double *longitude_Down_from_Pole, double *False_Easting, double *False_Northing)
Definition: polarst.c:275
const double PI_Over_4
Definition: polarst.c:120
static double Polar_f
Definition: polarst.c:124
#define POLAR_NORTHING_ERROR
Definition: polarst.h:103
#define POLAR_A_ERROR
Definition: polarst.h:104
static double es
Definition: polarst.c:125