OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimCassiniProjection.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 Cassini projection code.
11 //*******************************************************************
12 // $Id: ossimCassiniProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
13 
14 #include <math.h>
17 
18 RTTI_DEF1(ossimCassiniProjection, "ossimCassiniProjection", ossimMapProjection)
19 
20 
21 
22 /***************************************************************************/
23 /*
24  * DEFINES
25  */
26 
27 #ifdef PI_OVER_2
28 # undef PI_OVER_2
29 #endif
30 
31 #define CASS_NO_ERROR 0x0000
32 #define CASS_LAT_ERROR 0x0001
33 #define CASS_LON_ERROR 0x0002
34 #define CASS_EASTING_ERROR 0x0004
35 #define CASS_NORTHING_ERROR 0x0008
36 #define CASS_ORIGIN_LAT_ERROR 0x0010
37 #define CASS_CENT_MER_ERROR 0x0020
38 #define CASS_A_ERROR 0x0040
39 #define CASS_B_ERROR 0x0080
40 #define CASS_A_LESS_B_ERROR 0x0100
41 #define CASS_LON_WARNING 0x0200
42 
43 #define PI_OVER_2 ( M_PI / 2.0)
44 #define CASS_M(c0lat, c1s2lat, c2s4lat, c3s6lat) (Cass_a*(c0lat-c1s2lat+c2s4lat-c3s6lat))
45 #define CASS_RD(sinlat) (sqrt(1.0 - es2 * (sinlat * sinlat)))
46 #define CASS_COEFF_TIMES_SIN(coeff, x, latit) (coeff * (sin (x * latit)))
47 #define FLOAT_EQ(x,v,epsilon) (((v - epsilon) < x) && (x < (v + epsilon)))
48 #define THIRTY_ONE (31.0 * M_PI / 180.0) /* 31 degrees in radians */
49 
50 
51 
53  const ossimGpt& origin)
54  :ossimMapProjection(ellipsoid, origin)
55 {
56  setDefaults();
57  update();
58 }
59 
61  const ossimGpt& origin,
62  const double falseEasting,
63  const double falseNorthing)
64  :ossimMapProjection(ellipsoid, origin)
65 {
66  Cass_False_Easting = falseEasting;
67  Cass_False_Northing = falseNorthing;
68  Cass_Min_Easting = -20037508.4;
69  Cass_Max_Easting = 20037508.4;
70  Cass_Min_Northing = -56575846.0;
71  Cass_Max_Northing = 56575846.0;
72 
73  update();
74 }
75 
77 {
80  theOrigin.latr(),
81  theOrigin.lonr(),
84 
87 
88 
90 }
91 
92 void ossimCassiniProjection::setFalseEasting(double falseEasting)
93 {
94  Cass_False_Easting = falseEasting;
95  update();
96 }
97 
98 void ossimCassiniProjection::setFalseNorthing(double falseNorthing)
99 {
100  Cass_False_Northing = falseNorthing;
101  update();
102 }
103 
105  double falseNorthing)
106 {
107  Cass_False_Easting = falseEasting;
108  Cass_False_Northing = falseNorthing;
109  update();
110 }
111 
113 {
114 
115  Cass_Min_Easting = -20037508.4;
116  Cass_Max_Easting = 20037508.4;
117  Cass_Min_Northing = -56575846.0;
118  Cass_Max_Northing = 56575846.0;
119  Cass_False_Easting = 0.0;
120  Cass_False_Northing = 0.0;
121 }
122 
124 {
125  double lat = 0.0;
126  double lon = 0.0;
127 
128  Convert_Cassini_To_Geodetic(eastingNorthing.x,
129  eastingNorthing.y,
130  &lat,
131  &lon);
132 
133  return ossimGpt(lat*DEG_PER_RAD, lon*DEG_PER_RAD, 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 
158 bool ossimCassiniProjection::saveState(ossimKeywordlist& kwl, const char* prefix) const
159 {
160  return ossimMapProjection::saveState(kwl, prefix);
161 }
162 
164  const char* prefix)
165 {
166  // Must do this first.
167  bool flag = ossimMapProjection::loadState(kwl, prefix);
168 
169  const char* type = kwl.find(prefix, ossimKeywordNames::TYPE_KW);
170 
171  setDefaults();
172 
174  {
177  }
178 
179  update();
180 
181  return flag;
182 }
183 
184 /***************************************************************************/
185 /*
186  * FUNCTIONS
187  */
188 
189 
191  double f,
192  double Origin_Latitude,
193  double Central_Meridian,
194  double False_Easting,
195  double False_Northing)
196 { /* Begin Set_Cassini_Parameters */
197 /*
198  * The function Set_Cassini_Parameters receives the ellipsoid parameters and
199  * Cassini projection parameters as inputs, and sets the corresponding state
200  * variables. If any errors occur, the error code(s) are returned by the
201  * function, otherwise CASS_NO_ERROR is returned.
202  *
203  * a : Semi-major axis of ellipsoid, in meters (input)
204  * f : Flattening of ellipsoid (input)
205  * Origin_Latitude : Latitude in radians at which the (input)
206  * point scale factor is 1.0
207  * Central_Meridian : Longitude in radians at the center of (input)
208  * the projection
209  * False_Easting : A coordinate value in meters assigned to the
210  * central meridian of the projection. (input)
211  * False_Northing : A coordinate value in meters assigned to the
212  * origin latitude of the projection (input)
213  */
214 
215  double j,three_es4;
216  double x, e1, e2, e3, e4;
217  double lat, sin2lat, sin4lat, sin6lat;
218  double temp;
219 // double inv_f = 1 / f;
220  long Error_Code = CASS_NO_ERROR;
221 
222 // if (a <= 0.0)
223 // { /* Semi-major axis must be greater than zero */
224 // Error_Code |= CASS_A_ERROR;
225 // }
226 // if ((inv_f < 250) || (inv_f > 350))
227 // { /* Inverse flattening must be between 250 and 350 */
228 // Error_Code |= CASS_INV_F_ERROR;
229 // }
230 // if ((Origin_Latitude < -PI_OVER_2) || (Origin_Latitude > PI_OVER_2))
231 // { /* origin latitude out of range */
232 // Error_Code |= CASS_ORIGIN_LAT_ERROR;
233 // }
234 // if ((Central_Meridian < -PI) || (Central_Meridian > TWO_PI))
235 // { /* origin longitude out of range */
236 // Error_Code |= CASS_CENT_MER_ERROR;
237 // }
238  if (!Error_Code)
239  { /* no errors */
240  Cass_a = a;
241  Cass_f = f;
242  Cass_Origin_Lat = Origin_Latitude;
243 // if (Central_Meridian > PI)
244 // Central_Meridian -= TWO_PI;
245  Cass_Origin_Long = Central_Meridian;
246  Cass_False_Northing = False_Northing;
247  Cass_False_Easting = False_Easting;
248  es2 = 2 * Cass_f - Cass_f * Cass_f;
249  es4 = es2 * es2;
250  es6 = es4 * es2;
251  j = 45.0 * es6 / 1024.0;
252  three_es4 = 3.0 * es4;
253  c0 = 1 - es2 / 4.0 - three_es4 / 64.0 - 5.0 * es6 / 256.0;
254  c1 = 3.0 * es2 /8.0 + three_es4 / 32.0 + j;
255  c2 = 15.0 * es4 / 256.0 + j;
256  c3 = 35.0 * es6 / 3072.0;
257  lat = c0 * Cass_Origin_Lat;
258  sin2lat = CASS_COEFF_TIMES_SIN(c1, 2.0, Cass_Origin_Lat);
259  sin4lat = CASS_COEFF_TIMES_SIN(c2, 4.0, Cass_Origin_Lat);
260  sin6lat = CASS_COEFF_TIMES_SIN(c3, 6.0, Cass_Origin_Lat);
261  M0 = CASS_M(lat, sin2lat, sin4lat, sin6lat);
262 
263  One_Minus_es2 = 1.0 - es2;
264  x = sqrt (One_Minus_es2);
265  e1 = (1 - x) / (1 + x);
266  e2 = e1 * e1;
267  e3 = e2 * e1;
268  e4 = e3 * e1;
269  a0 = 3.0 * e1 / 2.0 - 27.0 * e3 / 32.0;
270  a1 = 21.0 * e2 / 16.0 - 55.0 * e4 / 32.0;
271  a2 = 151.0 * e3 / 96.0;
272  a3 = 1097.0 * e4 /512.0;
273 
274  if (Cass_Origin_Long > 0)
275  {
278  Cass_Max_Easting = 19926188.9;
279  Cass_Min_Easting = -20037508.4;
280  }
281  else if (Cass_Origin_Long < 0)
282  {
285  Cass_Max_Easting = 20037508.4;
286  Cass_Min_Easting = -19926188.9;
287  }
288  else
289  {
292  Cass_Max_Easting = 20037508.4;
293  Cass_Min_Easting = -20037508.4;
294  }
295 
296  } /* End if(!Error_Code) */
297  return (Error_Code);
298 } /* End Set_Cassini_Parameters */
299 
300 
302  double *f,
303  double *Origin_Latitude,
304  double *Central_Meridian,
305  double *False_Easting,
306  double *False_Northing)const
307 { /* Begin Get_Cassini_Parameters */
308 /*
309  * The function Get_Cassini_Parameters returns the current ellipsoid
310  * parameters, Cassini projection parameters.
311  *
312  * a : Semi-major axis of ellipsoid, in meters (output)
313  * f : Flattening of ellipsoid (output)
314  * Origin_Latitude : Latitude in radians at which the (output)
315  * point scale factor is 1.0
316  * Central_Meridian : Longitude in radians at the center of (output)
317  * the projection
318  * False_Easting : A coordinate value in meters assigned to the
319  * central meridian of the projection. (output)
320  * False_Northing : A coordinate value in meters assigned to the
321  * origin latitude of the projection (output)
322  */
323 
324  *a = Cass_a;
325  *f = Cass_f;
326  *Origin_Latitude = Cass_Origin_Lat;
327  *Central_Meridian = Cass_Origin_Long;
328  *False_Easting = Cass_False_Easting;
329  *False_Northing = Cass_False_Northing;
330 
331  return;
332 } /* End Get_Cassini_Parameters */
333 
334 
336  double Longitude,
337  double *Easting,
338  double *Northing)const
339 { /* Begin Convert_Geodetic_To_Cassini */
340 /*
341  * The function Convert_Geodetic_To_Cassini converts geodetic (latitude and
342  * longitude) coordinates to Cassini projection (easting and northing)
343  * coordinates, according to the current ellipsoid and Cassini projection
344  * parameters. If any errors occur, the error code(s) are returned by the
345  * function, otherwise CASS_NO_ERROR is returned.
346  *
347  * Latitude : Latitude (phi) in radians (input)
348  * Longitude : Longitude (lambda) in radians (input)
349  * Easting : Easting (X) in meters (output)
350  * Northing : Northing (Y) in meters (output)
351  */
352 
353  double lat, sin2lat, sin4lat, sin6lat;
354  double RD;
355  double tlat = tan(Latitude);
356  double clat = cos(Latitude);
357  double slat = sin(Latitude);
358  double dlam; /* Longitude - Central Meridan */
359  double NN;
360  double TT;
361  double AA, A2, A3, A4, A5;
362  double CC;
363  double MM;
364  long Error_Code = CASS_NO_ERROR;
365 
366 // if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
367 // { /* Latitude out of range */
368 // Error_Code |= CASS_LAT_ERROR;
369 // }
370 // if ((Longitude < -PI) || (Longitude > TWO_PI))
371 // { /* Longitude out of range */
372 // Error_Code |= CASS_LON_ERROR;
373 // }
374  if (!Error_Code)
375  { /* no errors */
376  dlam = Longitude - Cass_Origin_Long;
377 
378  if (fabs(dlam) > (4.0 * M_PI / 180.0))
379  { /* Distortion will result if Longitude is more than 4 degrees from the Central Meridian */
380  Error_Code |= CASS_LON_WARNING;
381  }
382 
383  if (dlam > M_PI)
384  {
385  dlam -= TWO_PI;
386  }
387  if (dlam < -M_PI)
388  {
389  dlam += TWO_PI;
390  }
391  RD = CASS_RD(slat);
392  NN = Cass_a / RD;
393  TT = tlat * tlat;
394  AA = dlam * clat;
395  A2 = AA * AA;
396  A3 = AA * A2;
397  A4 = AA * A3;
398  A5 = AA * A4;
399  CC = es2 * clat * clat / One_Minus_es2;
400  lat = c0 * Latitude;
401  sin2lat = CASS_COEFF_TIMES_SIN(c1, 2.0, Latitude);
402  sin4lat = CASS_COEFF_TIMES_SIN(c2, 4.0, Latitude);
403  sin6lat = CASS_COEFF_TIMES_SIN(c3, 6.0, Latitude);
404  MM = CASS_M(lat, sin2lat, sin4lat, sin6lat);
405 
406  *Easting = NN * (AA - (TT * A3 / 6.0) - (8.0 - TT + 8.0 * CC) *
407  (TT * A5 / 120.0)) + Cass_False_Easting;
408  *Northing = MM - M0 + NN * tlat * ((A2 / 2.0) + (5.0 - TT +
409  6.0 * CC) * A4 / 24.0) + Cass_False_Northing;
410  }
411  return (Error_Code);
412 } /* End Convert_Geodetic_To_Cassini */
413 
414 
416  double Northing,
417  double *Latitude,
418  double *Longitude)const
419 { /* Begin Convert_Cassini_To_Geodetic */
420 /*
421  * The function Convert_Cassini_To_Geodetic converts Cassini projection
422  * (easting and northing) coordinates to geodetic (latitude and longitude)
423  * coordinates, according to the current ellipsoid and Cassini projection
424  * coordinates. If any errors occur, the error code(s) are returned by the
425  * function, otherwise CASS_NO_ERROR is returned.
426  *
427  * Easting : Easting (X) in meters (input)
428  * Northing : Northing (Y) in meters (input)
429  * Latitude : Latitude (phi) in radians (output)
430  * Longitude : Longitude (lambda) in radians (output)
431  */
432 
433  double dx; /* Delta easting - Difference in easting (easting-FE) */
434  double dy; /* Delta northing - Difference in northing (northing-FN) */
435  double mu1;
436  double sin2mu, sin4mu, sin6mu, sin8mu;
437  double M1;
438  double phi1;
439  double tanphi1, sinphi1, cosphi1;
440  double T1, T;
441  double N1;
442  double RD, R1;
443  double DD, D2, D3, D4, D5;
444 // const double epsilon = 1.0e-1;
445  long Error_Code = CASS_NO_ERROR;
446 
447 // if ((Easting < (Cass_False_Easting + Cass_Min_Easting))
448 // || (Easting > (Cass_False_Easting + Cass_Max_Easting)))
449 // { /* Easting out of range */
450 // Error_Code |= CASS_EASTING_ERROR;
451 // }
452 // if ((Northing < (Cass_False_Northing + Cass_Min_Northing - epsilon))
453 // || (Northing > (Cass_False_Northing + Cass_Max_Northing + epsilon)))
454 // { /* Northing out of range */
455 // Error_Code |= CASS_NORTHING_ERROR;
456 // }
457  if (!Error_Code)
458  { /* no errors */
459  dy = Northing - Cass_False_Northing;
460  dx = Easting - Cass_False_Easting;
461  M1 = M0 + dy;
462  mu1 = M1 / (Cass_a * c0);
463 
464  sin2mu = CASS_COEFF_TIMES_SIN(a0, 2.0, mu1);
465  sin4mu = CASS_COEFF_TIMES_SIN(a1, 4.0, mu1);
466  sin6mu = CASS_COEFF_TIMES_SIN(a2, 6.0, mu1);
467  sin8mu = CASS_COEFF_TIMES_SIN(a3, 8.0, mu1);
468  phi1 = mu1 + sin2mu + sin4mu + sin6mu + sin8mu;
469 
470  if (FLOAT_EQ(phi1,PI_OVER_2,.00001))
471  {
472  *Latitude = PI_OVER_2;
473  *Longitude = Cass_Origin_Long;
474  }
475  else if (FLOAT_EQ(phi1,-PI_OVER_2,.00001))
476  {
477  *Latitude = -PI_OVER_2;
478  *Longitude = Cass_Origin_Long;
479  }
480  else
481  {
482  tanphi1 = tan(phi1);
483  sinphi1 = sin(phi1);
484  cosphi1 = cos(phi1);
485  T1 = tanphi1 * tanphi1;
486  RD = CASS_RD(sinphi1);
487  N1 = Cass_a / RD;
488  R1 = N1 * One_Minus_es2 / (RD * RD);
489  DD = dx / N1;
490  D2 = DD * DD;
491  D3 = D2 * DD;
492  D4 = D3 * DD;
493  D5 = D4 * DD;
494  T = (1.0 + 3.0 * T1);
495  *Latitude = phi1 - (N1 * tanphi1 / R1) * (D2 / 2.0 - T * D4 / 24.0);
496 
497  *Longitude = Cass_Origin_Long + (DD - T1 * D3 / 3.0 + T * T1 * D5 / 15.0) / cosphi1;
498 
499  if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
500  *Latitude = PI_OVER_2;
501  else if (*Latitude < -PI_OVER_2)
502  *Latitude = -PI_OVER_2;
503 
504 // if (*Longitude > PI)
505 // *Longitude -= TWO_PI;
506 // if (*Longitude < -PI)
507 // *Longitude += TWO_PI;
508 
509  if (*Longitude > M_PI) /* force distorted values to 180, -180 degrees */
510  *Longitude = M_PI;
511  else if (*Longitude < -M_PI)
512  *Longitude = -M_PI;
513  }
514  if (fabs(*Longitude - Cass_Origin_Long) > (4.0 * M_PI / 180.0))
515  { /* Distortion will result if Longitude is more than 4 degrees from the Central Meridian */
516  Error_Code |= CASS_LON_WARNING;
517  }
518  }
519  return (Error_Code);
520 } /* End Convert_Cassini_To_Geodetic */
521 
ossim_uint32 x
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.
const char * find(const char *key) const
#define CASS_LON_WARNING
#define CASS_RD(sinlat)
double y
Definition: ossimDpt.h:165
ossimCassiniProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
virtual const ossimString & code() const
Definition: ossimDatum.h:57
long Convert_Cassini_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
#define CASS_COEFF_TIMES_SIN(coeff, x, latit)
#define PI_OVER_2
virtual ossimGpt inverse(const ossimDpt &projectedPoint) const
Will take a point in meters and convert it to ground.
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 loadState(const ossimKeywordlist &kwl, const char *prefix=0)
#define M_PI
long Set_Cassini_Parameters(double a, double f, double Origin_Latitude, double Central_Meridian, double False_Easting, double False_Northing)
#define CASS_M(c0lat, c1s2lat, c2s4lat, c3s6lat)
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual ossimDpt forward(const ossimGpt &worldPoint) const
All map projections will convert the world coordinate to an easting northing (Meters).
void setFalseEasting(double falseEasting)
double x
Definition: ossimDpt.h:164
#define TWO_PI
double latr() const
latr().
Definition: ossimGpt.h:66
#define CASS_NO_ERROR
void Get_Cassini_Parameters(double *a, double *f, double *Origin_Latitude, double *Central_Meridian, double *False_Easting, double *False_Northing) const
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.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
#define THIRTY_ONE
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
long Convert_Geodetic_To_Cassini(double Latitude, double Longitude, double *Easting, double *Northing) const
#define FLOAT_EQ(x, v, epsilon)
void setFalseNorthing(double falseNorthing)
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.