OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimSpaceObliqueMercatorProjection.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 //*******************************************************************
9 // $Id: ossimSpaceObliqueMercatorProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
11 #include <math.h>
13 
14 #define PI_OVER_2 (M_PI/2)
15 #define PI (M_PI)
16 #define TWOPI (2*M_PI)
17 #define HALFPI (M_PI/2.0)
18 #define TOL 1e-7
19 #define PI_HALFPI 4.71238898038468985766
20 #define TWOPI_HALFPI 7.85398163397448309610
21 #define ONE_TOL 1.00000000000001
22 #define ATOL 1e-50
23 #define FORTPI 0.78539816339744833
24 
25 double aasin(double v)
26 {
27  double av;
28 
29  if ((av = fabs(v)) >= 1.)
30  {
31  return (v < 0. ? -HALFPI : HALFPI);
32  }
33  return asin(v);
34 }
35 double aacos(double v)
36 {
37  double av;
38 
39  if ((av = fabs(v)) >= 1.)
40  {
41  return (v < 0. ? PI : 0.);
42  }
43  return acos(v);
44 }
45 double asqrt(double v)
46 {
47  return ((v <= 0) ? 0. : sqrt(v));
48 }
49 double aatan2(double n, double d)
50 {
51  return ((fabs(n) < ATOL && fabs(d) < ATOL) ? 0. : atan2(n,d));
52 }
53 
54 static const char* PATH_KW = "path";
55 static const char* SATELLITE_TYPE_KW = "satellite_type";
56 
57 #if 0
58 static const char* ANGLE_OF_INCLINATION_KW = "angle_of_inclination";
59 static const char* REVOLUTION_TIME_KW = "earth_rev_time";
60 static const char* EARTH_ROTATION_LENGTH_KW = "earth_rot_length";
61 static const char* LONGITUDE_ASCENDING_NODE_KW = "lon_ascending_node";
62 static const char* J_COEFFICIENT_KW = "j_coeff";
63 static const char* W_COEFFICIENT_KW = "w_coeff";
64 static const char* Q_COEFFICIENT_KW = "q_coeff";
65 static const char* T_COEFFICIENT_KW = "t_coeff";
66 static const char* A2_COEFFICIENT_KW = "a2_coeff";
67 static const char* A4_COEFFICIENT_KW = "a4_coeff";
68 static const char* B_COEFFICIENT_KW = "b_coeff";
69 static const char* C1_COEFFICIENT_KW = "c1_coeff";
70 static const char* C3_COEFFICIENT_KW = "c3_coeff";
71 static const char* ECCENTRICITY_KW = "eccentricity";
72 #endif
73 
74 RTTI_DEF1(ossimSpaceObliqueMercatorProjection, "ossimSpaceObliqueMercatorProjection", ossimMapProjection);
75 
76 
77 //*****************************************************************************
78 // CONSTRUCTOR
79 //*****************************************************************************
82  double pathNumber,
83  const ossimEllipsoid& ellipsoid)
84  :
85  ossimMapProjection(ellipsoid)
86 {
87  setParameters(type, pathNumber);
88 }
89 
90 //*****************************************************************************
91 // METHOD
92 //*****************************************************************************
94  double path)
95 {
96  thePath = path;
97  theSatelliteType = type;
98  double lam = 0.0;
99  double alf = 0.0;
100  double esc = 0.0;
101  double ess = 0.0;
102 
104  es = e*e;
105  one_es = 1- es;
106  rone_es = 1.0/one_es;
107  a = theEllipsoid.a();
108 
109  switch(theSatelliteType)
110  {
111  case SOM_TYPE_LANDSAT_1:
112  case SOM_TYPE_LANDSAT_2:
113  case SOM_TYPE_LANDSAT_3:
114  {
115  lam0 = RAD_PER_DEG*(128.87 - (360.0/251.0)*path);
116  p22 = 103.2669323;
117  alf = RAD_PER_DEG * 99.092;
118  break;
119  }
120  case SOM_TYPE_LANDSAT_4:
121  case SOM_TYPE_LANDSAT_5:
122  case SOM_TYPE_LANDSAT_7:
123  {
124 
125  lam0 = RAD_PER_DEG*(129.305582487 - (360.0/233.0)*path);
126  p22 = 98.8841202;
127  alf = RAD_PER_DEG * 98.2;
128  break;
129  }
130  }
131  p22 /= 1440.;
132  sa = sin(alf);
133  ca = cos(alf);
134  if (fabs(ca) < 1e-9)
135  ca = 1e-9;
136  esc = es * ca * ca;
137  ess = es * sa * sa;
138  w = (1. - esc) * rone_es;
139  w = w * w - 1.;
140  q = ess * rone_es;
141  t = ess * (2. - es) * rone_es * rone_es;
142  u = esc * rone_es;
143  xj = one_es * one_es * one_es;
144  rlm = PI * (1. / 248. + .5161290322580645);
145  rlm2 = rlm + TWOPI;
146  a2 = a4 = b = c1 = c3 = 0.;
147  seraz0(0.0, 1.0);
148  for (lam = 9.; lam <= 81.0001; lam += 18.)
149  seraz0(lam, 4.0);
150  for (lam = 18; lam <= 72.0001; lam += 18.)
151  seraz0(lam, 2.0);
152  seraz0(90.0, 1.0);
153  a2 /= 30.0;
154  a4 /= 60.0;
155  b /= 30.0;
156  c1 /= 15.0;
157  c3 /= 45.0;
158 
159  update();
160 }
161 
162 //*****************************************************************************
163 // METHOD
164 //*****************************************************************************
166  double mult)
167 {
168  double sdsq, h, s, fc, sd, sq, d__1;
169 
170  lam *= RAD_PER_DEG;
171  sd = sin(lam);
172  sdsq = sd * sd;
173  s = p22 * sa * cos(lam) * sqrt((1. + t * sdsq) / ((
174  1. + w * sdsq) * (1. + q * sdsq)));
175  d__1 = 1. + q * sdsq;
176  h = sqrt((1. + q * sdsq) / (1. + w * sdsq)) * ((1. +
177  w * sdsq) / (d__1 * d__1) - p22 * ca);
178  sq = sqrt(xj * xj + s * s);
179  b += fc = mult * (h * xj - s * s) / sq;
180  a2 += fc * cos(lam + lam);
181  a4 += fc * cos(lam * 4.);
182  fc = mult * s * (h + xj) / sq;
183  c1 += fc * cos(lam);
184  c3 += fc * cos(lam * 3.);
185 
186 }
187 
188 //*****************************************************************************
189 // METHOD
190 //*****************************************************************************
191 ossimDpt
193 {
194  ossimGpt gpt = worldPoint;
195 
196  if (theDatum)
197  {
198  if (theDatum->code() != worldPoint.datum()->code())
199  {
200  gpt.changeDatum(theDatum); // Shift to our datum.
201  }
202  }
203 
204  ossimDpt xy;
205 
206  int l, nn;
207  double lamt, xlam, sdsq, c, d, s, lamdp, phidp, lampp, tanph,
208  lamtp, cl, sd, sp, fac, sav, tanphi;
209  double phi = gpt.latr();
210  double lam = gpt.lonr() - lam0;
211 
212  if (phi > HALFPI)
213  phi = HALFPI;
214  else if (phi < -HALFPI)
215  phi = -HALFPI;
216  lampp = phi >= 0. ? HALFPI : PI_HALFPI;
217  tanphi = tan(phi);
218  for (nn = 0;;)
219  {
220  sav = lampp;
221  lamtp = lam + p22 * lampp;
222  cl = cos(lamtp);
223  if (fabs(cl) < TOL)
224  lamtp -= TOL;
225  fac = lampp - sin(lampp) * (cl < 0. ? -HALFPI : HALFPI);
226  for (l = 50; l; --l) {
227  lamt = lam + p22 * sav;
228  if (fabs(c = cos(lamt)) < TOL)
229  lamt -= TOL;
230  xlam = (one_es * tanphi * sa + sin(lamt) * ca) / c;
231  lamdp = atan(xlam) + fac;
232  if (fabs(fabs(sav) - fabs(lamdp)) < TOL)
233  break;
234  sav = lamdp;
235  }
236  if (!l || ++nn >= 3 || (lamdp > rlm && lamdp < rlm2))
237  break;
238  if (lamdp <= rlm)
239  lampp = TWOPI_HALFPI;
240  else if (lamdp >= rlm2)
241  lampp = HALFPI;
242  }
243  if (l) {
244  sp = sin(phi);
245  phidp = aasin((one_es * ca * sp - sa * cos(phi) *
246  sin(lamt)) / sqrt(1. - es * sp * sp));
247  tanph = log(tan(FORTPI + .5 * phidp));
248  sd = sin(lamdp);
249  sdsq = sd * sd;
250  s = p22 * sa * cos(lamdp) * sqrt((1. + t * sdsq)
251  / ((1. + w * sdsq) * (1. + q * sdsq)));
252  d = sqrt(xj * xj + s * s);
253  xy.x = b * lamdp + a2 * sin(2. * lamdp) + a4 *
254  sin(lamdp * 4.) - tanph * s / d;
255  xy.y = c1 * sd + c3 * sin(lamdp * 3.) + tanph * xj / d;
256  }
257  else
258  {
259  xy.makeNan();
260  return xy;
261 // xy.x = xy.y = 1.0/DBL_EPSILON; // st to large number
262  }
263 
264  xy.x*=a;
265  xy.y*=a;
266  return xy;
267 }
268 
269 //*****************************************************************************
270 // METHOD
271 //*****************************************************************************
272 ossimGpt
274  const
275 {
276  int nn;
277  double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp;
278  double lam, phi;
279 
280  ossimDpt xy = projectedPoint;
281  xy.x/=a;
282  xy.y/=a;
283 
284  lamdp = xy.x / b;
285  nn = 50;
286  do {
287  sav = lamdp;
288  sd = sin(lamdp);
289  sdsq = sd * sd;
290  s = p22 * sa * cos(lamdp) * sqrt((1. + t * sdsq)
291  / ((1. + w * sdsq) * (1. + q * sdsq)));
292  lamdp = xy.x + xy.y * s / xj - a2 * sin(
293  2. * lamdp) - a4 * sin(lamdp * 4.) - s / xj * (
294  c1 * sin(lamdp) + c3 * sin(lamdp * 3.));
295  lamdp /= b;
296  } while (fabs(lamdp - sav) >= TOL && --nn);
297  sl = sin(lamdp);
298  fac = exp(sqrt(1. + s * s / xj / xj) * (xy.y -
299  c1 * sl - c3 * sin(lamdp * 3.)));
300  phidp = 2. * (atan(fac) - FORTPI);
301  dd = sl * sl;
302  if (fabs(cos(lamdp)) < TOL)
303  lamdp -= TOL;
304  spp = sin(phidp);
305  sppsq = spp * spp;
306  lamt = atan(((1. - sppsq * rone_es) * tan(lamdp) * ca -
307  spp * sa * sqrt((1. + q * dd) * (1. - sppsq) - sppsq * u) /
308  cos(lamdp)) / (1. - sppsq * (1. + u)));
309  sl = lamt >= 0. ? 1. : -1.;
310  scl = cos(lamdp) >= 0. ? 1. : -1;
311  lamt -= HALFPI * (1. - scl) * sl;
312 
313  lam = lamt - p22 * lamdp;
314  if (fabs(sa) < TOL)
315  phi = aasin(spp / sqrt(one_es * one_es + es * sppsq));
316  else
317  phi = atan((tan(lamdp) * cos(lamt) - ca * sin(lamt)) /
318  (one_es * sa));
319  return ossimGpt(phi*DEG_PER_RAD,
320  (lam+lam0)*DEG_PER_RAD, 0.0, theDatum);
321 
322 }
323 
324 //*****************************************************************************
325 // METHOD
326 //*****************************************************************************
328 {
329 // theMetersPerPixel.x = 1.0;
330 // theMetersPerPixel.y = 1.0;
331 
332 // theUlEastingNorthing.x = 0.0;
333 // theUlEastingNorthing.y = 0.0;
334 }
335 
336 
337 //*****************************************************************************
338 // METHOD
339 //*****************************************************************************
341  const char* prefix) const
342 {
343  kwl.add(prefix,
344  PATH_KW,
345  thePath,
346  true);
347 
348  kwl.add(prefix,
349  SATELLITE_TYPE_KW,
350  (int)theSatelliteType,
351  true);
352  return ossimMapProjection::saveState(kwl, prefix);
353 }
354 
355 //*****************************************************************************
356 // METHOD
357 //*****************************************************************************
359  const char* prefix)
360 {
361  bool result = true;
362 
363  const char* path = kwl.find(prefix, PATH_KW);
364  const char* type = kwl.find(prefix, SATELLITE_TYPE_KW);
365 
366  if(path)
367  {
368  thePath = ossimString(path).toDouble();
369  }
370  else
371  {
372  result = false;
373  }
374  if(type)
375  {
377  }
378  else
379  {
380  result = false;
381  }
382 
384 
385  if(result)
386  {
387  result = ossimMapProjection::loadState(kwl, prefix);
388  }
389  else
390  {
391  ossimMapProjection::loadState(kwl, prefix);
392  }
393 
394  return result;
395 }
396 
397 //*************************************************************************************************
399 //*************************************************************************************************
401 {
402  if (!ossimMapProjection::operator==(proj))
403  return false;
404 
406  dynamic_cast<const ossimSpaceObliqueMercatorProjection*>(&proj);
407  if (!p) return false;
408 
409  if (theSatelliteType != p->theSatelliteType) return false;
410  if (!ossim::almostEqual(thePath,p->thePath)) return false;
411 
412  return true;
413 }
double eccentricity() const
double aatan2(double n, double d)
virtual void setParameters(ossimSatelliteType type, double path)
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
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
double asqrt(double v)
#define sq(a)
Definition: auxiliary.h:77
double aasin(double v)
RTTI_DEF1(ossimSpaceObliqueMercatorProjection, "ossimSpaceObliqueMercatorProjection", ossimMapProjection)
ossimSpaceObliqueMercatorProjection(ossimSatelliteType type=SOM_TYPE_LANDSAT_7, double pathNumber=34, const ossimEllipsoid &ellipsoid=ossimEllipsoid())
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
const double & a() const
os2<< "> n<< " > nendobj n
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
double toDouble() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual bool operator==(const ossimProjection &projection) const
Returns TRUE if principal parameters are within epsilon tolerance.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
double aacos(double v)
virtual ossimDpt forward(const ossimGpt &worldPoint) const
All map projections will convert the world coordinate to an easting northing (Meters).
virtual ossimGpt inverse(const ossimDpt &projectedPoint) const
Will take a point in meters and convert it to ground.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
double x
Definition: ossimDpt.h:164
double latr() const
latr().
Definition: ossimGpt.h:66
ossimEllipsoid theEllipsoid
This method verifies that the projection parameters match the current pcs code.
#define RAD_PER_DEG
int toInt() const
void makeNan()
Definition: ossimDpt.h:65
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.