OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimSinusoidalProjection.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 Sinusoidal projection code.
11 //*******************************************************************
12 // $Id: ossimSinusoidalProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
13 
14 #include <math.h>
17 
18 RTTI_DEF1(ossimSinusoidalProjection, "ossimSinusoidalProjection", ossimMapProjection)
19 /***************************************************************************/
20 /*
21  * DEFINES
22  */
23 
24 #define SINU_NO_ERROR 0x0000
25 #define SINU_LAT_ERROR 0x0001
26 #define SINU_LON_ERROR 0x0002
27 #define SINU_EASTING_ERROR 0x0004
28 #define SINU_NORTHING_ERROR 0x0008
29 #define SINU_CENT_MER_ERROR 0x0020
30 #define SINU_A_ERROR 0x0040
31 #define SINU_B_ERROR 0x0080
32 #define SINU_A_LESS_B_ERROR 0x0100
33 
34 #ifndef PI_OVER_2
35 # define PI_OVER_2 ( M_PI / 2.0)
36 #endif
37 #ifndef TWO_PI
38 # define TWO_PI (2.0 * M_PI)
39 #endif
40 
41 #define SINU_COEFF_TIMES_SIN(coeff, x, latit) (coeff * sin(x * latit))
42 #define FLOAT_EQ(x,v,epsilon) (((v - epsilon) < x) && (x < (v + epsilon)))
43 
44 /***************************************************************************/
45 /*
46  * FUNCTIONS
47  */
48 
50  const ossimGpt& origin)
51  :ossimMapProjection(ellipsoid, origin)
52 {
53  setDefaults();
54  update();
55 }
56 
58  const ossimGpt& origin,
59  double falseEasting,
60  double falseNorthing)
61  :ossimMapProjection(ellipsoid, origin)
62 {
63  Sinu_False_Easting = falseEasting;
64  Sinu_False_Northing = falseNorthing;
65  Sinu_Max_Easting = 20037509.0;
66  Sinu_Min_Easting = -20037509.0;
67  Sinu_Delta_Northing = 10001966.0;
68 
69  update();
70 }
71 
73 {
76  theOrigin.lonr(),
79 
82 
84 }
85 
87 {
88  Sinu_False_Easting = falseEasting;
89 
90  update();
91 }
92 
94 {
95  Sinu_False_Northing = falseNorthing;
96 
97  update();
98 }
99 
101 {
102  Sinu_Max_Easting = 20037509.0;
103  Sinu_Min_Easting = -20037509.0;
104  Sinu_Delta_Northing = 10001966.0;
105  Sinu_False_Easting = 0.0;
106  Sinu_False_Northing = 0.0;
107 }
108 
110 {
111  Sinu_Origin_Long = centralMeridian;
112  update();
113 }
114 
116  double falseNorthing)
117 {
118  Sinu_False_Easting = falseEasting;
119  Sinu_False_Northing = falseNorthing;
120 
121  update();
122 }
123 
125 {
126  double lat = 0.0;
127  double lon = 0.0;
128 
129  Convert_Sinusoidal_To_Geodetic(eastingNorthing.x,
130  eastingNorthing.y,
131  &lat,
132  &lon);
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 ossimSinusoidalProjection::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  * FUNCTIONS
184  */
185 
186 
188  double f,
189  double Central_Meridian,
190  double False_Easting,
191  double False_Northing)
192 { /* BEGIN Set_Sinusoidal_Parameters */
193 /*
194  * The function Set_Sinusoidal_Parameters receives the ellipsoid parameters and
195  * Sinusoidal projection parameters as inputs, and sets the corresponding state
196  * variables. If any errors occur, the error code(s) are returned by the function,
197  * otherwise SINU_NO_ERROR is returned.
198  *
199  * a : Semi-major axis of ellipsoid, in meters (input)
200  * f : Flattening of ellipsoid (input)
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;
210  double One_MINUS_es2, Sqrt_One_MINUS_es2, e1, e2, e3, e4;
211 // double inv_f = 1 / f;
212  long Error_Code = SINU_NO_ERROR;
213 
214 // if (a <= 0.0)
215 // { /* Semi-major axis must be greater than zero */
216 // Error_Code |= SINU_A_ERROR;
217 // }
218 // if ((inv_f < 250) || (inv_f > 350))
219 // { /* Inverse flattening must be between 250 and 350 */
220 // Error_Code |= SINU_INV_F_ERROR;
221 // }
222 // if ((Central_Meridian < -M_PI) || (Central_Meridian > TWO_PI))
223 // { /* origin longitude out of range */
224 // Error_Code |= SINU_CENT_MER_ERROR;
225 // }
226  if (!Error_Code)
227  { /* no errors */
228  Sinu_a = a;
229  Sinu_f = f;
230  es2 = 2 * Sinu_f - Sinu_f * Sinu_f;
231  es4 = es2 * es2;
232  es6 = es4 * es2;
233  j = 45.0 * es6 / 1024.0;
234  c0 = 1.0 - es2 / 4.0 - 3.0 * es4 / 64.0 - 5.0 * es6 / 256.0;
235  c1 = 3.0 * es2 / 8.0 + 3.0 * es4 / 32.0 + j;
236  c2 = 15.0 * es4 / 256.0 + j;
237  c3 = 35.0 * es6 / 3072.0;
238  One_MINUS_es2 = 1.0 - es2;
239  Sqrt_One_MINUS_es2 = sqrt(One_MINUS_es2);
240  e1 = (1.0 - Sqrt_One_MINUS_es2) / (1.0 + Sqrt_One_MINUS_es2);
241  e2 = e1 * e1;
242  e3 = e2 * e1;
243  e4 = e3 * e1;
244  a0 = 3.0 * e1 / 2.0 - 27.0 * e3 / 32.0 ;
245  a1 = 21.0 * e2 / 16.0 - 55.0 * e4 / 32.0;
246  a2 = 151.0 * e3 / 96.0;
247  a3 = 1097.0 * e4 / 512.0;
248 // if (Central_Meridian > M_PI)
249 // Central_Meridian -= TWO_PI;
250  Sinu_Origin_Long = Central_Meridian;
251  Sinu_False_Northing = False_Northing;
252  Sinu_False_Easting = False_Easting;
253 
254  if (Sinu_Origin_Long > 0)
255  {
256  Sinu_Max_Easting = 19926189.0;
257  Sinu_Min_Easting = -20037509.0;
258  }
259  else if (Sinu_Origin_Long < 0)
260  {
261  Sinu_Max_Easting = 20037509.0;
262  Sinu_Min_Easting = -19926189.0;
263  }
264  else
265  {
266  Sinu_Max_Easting = 20037509.0;
267  Sinu_Min_Easting = -20037509.0;
268  }
269  } /* END OF if(!Error_Code) */
270  return (Error_Code);
271 } /* END OF Set_Sinusoidal_Parameters */
272 
274  double *f,
275  double *Central_Meridian,
276  double *False_Easting,
277  double *False_Northing)const
278 { /* BEGIN Get_Sinusoidal_Parameters */
279 /*
280  * The function Get_Sinusoidal_Parameters returns the current ellipsoid
281  * parameters, and Sinusoidal projection parameters.
282  *
283  * a : Semi-major axis of ellipsoid, in meters (output)
284  * f : Flattening of ellipsoid (output)
285  * Central_Meridian : Longitude in radians at the center of (output)
286  * the projection
287  * False_Easting : A coordinate value in meters assigned to the
288  * central meridian of the projection. (output)
289  * False_Northing : A coordinate value in meters assigned to the
290  * origin latitude of the projection (output)
291  */
292 
293  *a = Sinu_a;
294  *f = Sinu_f;
295  *Central_Meridian = Sinu_Origin_Long;
296  *False_Easting = Sinu_False_Easting;
297  *False_Northing = Sinu_False_Northing;
298 
299  return;
300 } /* END OF Get_Sinusoidal_Parameters */
301 
302 
304  double Longitude,
305  double *Easting,
306  double *Northing)const
307 { /* BEGIN Convert_Geodetic_To_Sinusoidal */
308 /*
309  * The function Convert_Geodetic_To_Sinusoidal converts geodetic (latitude and
310  * longitude) coordinates to Sinusoidal projection (easting and northing)
311  * coordinates, according to the current ellipsoid and Sinusoidal projection
312  * parameters. If any errors occur, the error code(s) are returned by the
313  * function, otherwise SINU_NO_ERROR is returned.
314  *
315  * Latitude : Latitude (phi) in radians (input)
316  * Longitude : Longitude (lambda) in radians (input)
317  * Easting : Easting (X) in meters (output)
318  * Northing : Northing (Y) in meters (output)
319  */
320 
321  double slat = sin(Latitude);
322  double sin2lat, sin4lat, sin6lat;
323  double dlam; /* Longitude - Central Meridan */
324  double mm;
325  double MM;
326  long Error_Code = SINU_NO_ERROR;
327 
328 // if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
329 // { /* Latitude out of range */
330 // Error_Code |= SINU_LAT_ERROR;
331 // }
332 // if ((Longitude < -M_PI) || (Longitude > TWO_PI))
333 // { /* Longitude out of range */
334 // Error_Code |= SINU_LON_ERROR;
335 // }
336  if (!Error_Code)
337  { /* no errors */
338  dlam = Longitude - Sinu_Origin_Long;
339 // if (dlam > M_PI)
340 // {
341 // dlam -= TWO_PI;
342 // }
343 // if (dlam < -M_PI)
344 // {
345 // dlam += TWO_PI;
346 // }
347  mm = sqrt(1.0 - es2 * slat * slat);
348 
349  sin2lat = SINU_COEFF_TIMES_SIN(c1, 2.0, Latitude);
350  sin4lat = SINU_COEFF_TIMES_SIN(c2, 4.0, Latitude);
351  sin6lat = SINU_COEFF_TIMES_SIN(c3, 6.0, Latitude);
352  MM = Sinu_a * (c0 * Latitude - sin2lat + sin4lat - sin6lat);
353 
354  *Easting = Sinu_a * dlam * cos(Latitude) / mm + Sinu_False_Easting;
355  *Northing = MM + Sinu_False_Northing;
356  }
357  return (Error_Code);
358 } /* END OF Convert_Geodetic_To_Sinusoidal */
359 
360 
362  double Northing,
363  double *Latitude,
364  double *Longitude)const
365 { /* BEGIN Convert_Sinusoidal_To_Geodetic */
366 /*
367  * The function Convert_Sinusoidal_To_Geodetic converts Sinusoidal projection
368  * (easting and northing) coordinates to geodetic (latitude and longitude)
369  * coordinates, according to the current ellipsoid and Sinusoidal projection
370  * coordinates. If any errors occur, the error code(s) are returned by the
371  * function, otherwise SINU_NO_ERROR is returned.
372  *
373  * Easting : Easting (X) in meters (input)
374  * Northing : Northing (Y) in meters (input)
375  * Latitude : Latitude (phi) in radians (output)
376  * Longitude : Longitude (lambda) in radians (output)
377  */
378 
379  double dx; /* Delta easting - Difference in easting (easting-FE) */
380  double dy; /* Delta northing - Difference in northing (northing-FN) */
381  double mu;
382  double sin2mu, sin4mu, sin6mu, sin8mu;
383  double sin_lat;
384  long Error_Code = SINU_NO_ERROR;
385 
386 // if ((Easting < (Sinu_False_Easting + Sinu_Min_Easting))
387 // || (Easting > (Sinu_False_Easting + Sinu_Max_Easting)))
388 // { /* Easting out of range */
389 // Error_Code |= SINU_EASTING_ERROR;
390 // }
391 // if ((Northing < (Sinu_False_Northing - Sinu_Delta_Northing))
392 // || (Northing > (Sinu_False_Northing + Sinu_Delta_Northing)))
393 // { /* Northing out of range */
394 // Error_Code |= SINU_NORTHING_ERROR;
395 // }
396  if (!Error_Code)
397  { /* no errors */
398  dy = Northing - Sinu_False_Northing;
399  dx = Easting - Sinu_False_Easting;
400 
401  mu = dy / (Sinu_a * c0);
402  sin2mu = SINU_COEFF_TIMES_SIN(a0, 2.0, mu);
403  sin4mu = SINU_COEFF_TIMES_SIN(a1, 4.0, mu);
404  sin6mu = SINU_COEFF_TIMES_SIN(a2, 6.0, mu);
405  sin8mu = SINU_COEFF_TIMES_SIN(a3, 8.0, mu);
406  *Latitude = mu + sin2mu + sin4mu + sin6mu + sin8mu;
407 
408  if (*Latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
409  *Latitude = PI_OVER_2;
410  else if (*Latitude < -PI_OVER_2)
411  *Latitude = -PI_OVER_2;
412 
413  if (FLOAT_EQ(fabs(*Latitude),PI_OVER_2,1.0e-8))
414  *Longitude = Sinu_Origin_Long;
415  else
416  {
417  sin_lat = sin(*Latitude);
418  *Longitude = Sinu_Origin_Long + dx * sqrt(1.0 - es2 *
419  sin_lat * sin_lat) / (Sinu_a * cos(*Latitude));
420 
421 
422 // if (*Longitude > M_PI)
423 // *Longitude -= TWO_PI;
424 // if (*Longitude < -M_PI)
425 // *Longitude += TWO_PI;
426 
427 // if (*Longitude > M_PI) /* force distorted values to 180, -180 degrees */
428 // *Longitude = M_PI;
429 // else if (*Longitude < -M_PI)
430 // *Longitude = -M_PI;
431  }
432  }
433  return (Error_Code);
434 } /* END OF Convert_Sinusoidal_To_Geodetic */
435 
436 //*************************************************************************************************
438 //*************************************************************************************************
440 {
441  if (!ossimMapProjection::operator==(proj))
442  return false;
443 
444  const ossimSinusoidalProjection* p = dynamic_cast<const ossimSinusoidalProjection*>(&proj);
445  if (!p) return false;
446 
448 
449  return true;
450 }
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
void setFalseNorthing(double falseNorthing)
#define DEG_PER_RAD
Represents serializable keyword/value map.
#define FLOAT_EQ(x, v, epsilon)
long Convert_Geodetic_To_Sinusoidal(double Latitude, double Longitude, double *Easting, double *Northing) const
const char * find(const char *key) const
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
#define SINU_NO_ERROR
void setFalseEasting(double falseEasting)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
static const char * TYPE_KW
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
virtual ossimGpt inverse(const ossimDpt &eastingNorthing) const
Will take a point in meters and convert it to ground.
void setCentralMeridian(double centralMeridian)
#define STATIC_TYPE_NAME(T)
Definition: ossimRtti.h:325
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
virtual bool operator==(const ossimProjection &projection) const
Returns TRUE if principal parameters are within epsilon tolerance.
ossimSinusoidalProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
#define PI_OVER_2
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
long Convert_Sinusoidal_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
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 &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
#define SINU_COEFF_TIMES_SIN(coeff, x, latit)
double x
Definition: ossimDpt.h:164
double latr() const
latr().
Definition: ossimGpt.h:66
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 bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
long Set_Sinusoidal_Parameters(double a, double f, double Central_Meridian, double False_Easting, double False_Northing)
void Get_Sinusoidal_Parameters(double *a, double *f, double *Central_Meridian, double *False_Easting, double *False_Northing) const
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.