OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimNewZealandMapGridProjection.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: ossimNewZealandMapGridProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
15 
16 RTTI_DEF1(ossimNewZealandMapGridProjection, "ossimNewZealandMapGridProjection", ossimMapProjection)
17 
18 #ifndef PI_OVER_2
19 # define PI_OVER_2 ( M_PI / 2.0)
20 #endif
21 #ifndef TWO_PI
22 # define TWO_PI (2.0 * M_PI)
23 #endif
24 
25 #define MAX_LAT (-33.5 * M_PI / 180.0) /* -33.5 degrees */
26 #define MIN_LAT (-48.5 * M_PI / 180.0) /* -48.5 degrees */
27 #define MAX_LON (180.0 * M_PI / 180.0) /* 180 degrees */
28 #define MIN_LON (165.5 * M_PI / 180.0) /* 165.5 degrees */
29 
30 #define NZMG_NO_ERROR 0x0000
31 #define NZMG_LAT_ERROR 0x0001
32 #define NZMG_LON_ERROR 0x0002
33 #define NZMG_EASTING_ERROR 0x0004
34 #define NZMG_NORTHING_ERROR 0x0008
35 #define NZMG_ELLIPSOID_ERROR 0x0010
36 
37 typedef struct ComplexNumber
38 {
39  double real;
40  double imag;
41 } Complex;
42 
43 static double A[] = { 0.6399175073, -0.1358797613, 0.063294409,
44  -0.02526853, 0.0117879, -0.0055161,
45  0.0026906, -0.001333, 0.00067, -0.00034 };
46 
47 static Complex B[] = { { 0.7557853228, 0.0 },
48  { 0.249204646, 0.003371507 },
49  { -0.001541739, 0.041058560 },
50  { -0.10162907, 0.01727609 },
51  { -0.26623489, -0.36249218 },
52  { -0.6870983, -1.1651967 } };
53 
54 static Complex C[] = { { 1.3231270439, 0.0 },
55  { -0.577245789, -0.007809598 },
56  { 0.508307513, -0.112208952 },
57  { -0.15094762, 0.18200602 },
58  { 1.01418179, 1.64497696 },
59  { 1.9660549, 2.5127645 } };
60 
61 static double D[] = { 1.5627014243, 0.5185406398, -0.03333098,
62  -0.1052906, -0.0368594, 0.007317,
63  0.01220, 0.00394, -0.0013 };
64 
65 /* These state variables are for optimization purposes. The only function
66  * that should modify them is Set_NZMG_Parameters. */
67 
68 /************************************************************************/
69 /* FUNCTIONS
70  *
71  */
72 
73 /* Add two complex numbers */
74 static Complex Add(Complex z1, Complex z2)
75 {
76  Complex z;
77 
78  z.real = z1.real + z2.real;
79  z.imag = z1.imag + z2.imag;
80 
81  return z;
82 }
83 
84 
85 /* Multiply two complex numbers */
86 static Complex Multiply(Complex z1, Complex z2)
87 {
88  Complex z;
89 
90  z.real = z1.real * z2.real - z1.imag * z2.imag;
91  z.imag = z1.imag * z2.real + z1.real * z2.imag;
92 
93  return z;
94 }
95 
96 
97 /* Divide two complex numbers */
98 static Complex Divide(Complex z1, Complex z2)
99 {
100  Complex z;
101  double denom;
102 
103  denom = z2.real * z2.real + z2.imag * z2.imag;
104  z.real = (z1.real * z2.real + z1.imag * z2.imag) / denom;
105  z.imag = (z1.imag * z2.real - z1.real * z2.imag) / denom;
106 
107  return z;
108 }
109 
111  :ossimMapProjection(*ossimEllipsoidFactory::instance()->create("IN"),
112  ossimGpt(-41, 173.0))
113 {
114  setDefaults();
115  update();
116 }
117 
119 {
120 }
121 
123 {
124  NZMG_False_Easting = falseEasting;
125  update();
126 }
127 
129 {
130  NZMG_False_Northing = falseNorthing;
131  update();
132 }
133 
134 void ossimNewZealandMapGridProjection::setFalseEastingNorthing(double falseEasting, double falseNorthing)
135 {
136  NZMG_False_Easting = falseEasting;
137  NZMG_False_Northing = falseNorthing;
138 
139  update();
140 }
141 
143 {
144  theOrigin.latd(-41.0);
145  theOrigin.lond(173.0);
146 
147  // origin of lat needs to be in degrees
149 
150  // origin of lon is in radians
152  NZMG_Max_Easting = 3170000.0;
153  NZMG_Max_Northing = 6900000.0;
154  NZMG_Min_Easting = 1810000.0;
155  NZMG_Min_Northing = 5160000.0;
156 
157  NZMG_False_Easting = 2510000.0;
158  NZMG_False_Northing = 6023150.0;
159 }
160 
162 {
163  theOrigin = ossimGpt(-41, 173);
164 
165  // create the new zealand datum.
167 
168  if(theDatum)
169  {
171  }
172  else
173  {
174  ossimNotify(ossimNotifyLevel_WARN) << "WARNING ossimNewZealandMapGridProjection::update(): Was unable to locate the newzealand datum!" << std::endl;
175  }
176 
180 
183 
185 }
186 
188 {
189  double lat = 0.0;
190  double lon = 0.0;
191 
192  Convert_NZMG_To_Geodetic(eastingNorthing.x,
193  eastingNorthing.y,
194  &lat,
195  &lon);
196 
197  return ossimGpt(lat*DEG_PER_RAD, lon*DEG_PER_RAD, 0.0, theDatum);
198 }
199 
201 {
202  double easting = 0.0;
203  double northing = 0.0;
204  ossimGpt gpt = latLon;
205 
206  if (theDatum)
207  {
208  if (theDatum->code() != latLon.datum()->code())
209  {
210  gpt.changeDatum(theDatum); // Shift to our datum.
211  }
212  }
213 
215  gpt.lonr(),
216  &easting,
217  &northing);
218 
219  return ossimDpt(easting, northing);
220 }
221 
223  const char* prefix)const
224 {
225  ossimMapProjection::saveState(kwl, prefix);
226 
227  return true;
228 }
229 
231  const char* prefix)
232 {
233  ossimKeywordlist newKwl = kwl;
234 
235  // force a New Zealand Datum and the origin of lat and lon
236  // to the New Zealand.
237  newKwl.add(prefix,
239  "GEO",
240  true);
241 
242  newKwl.add(prefix,
244  -41,
245  true);
246 
247  newKwl.add(prefix,
249  173.0,
250  true);
251 
252  setDefaults();
253 
254  ossimMapProjection::loadState(newKwl, prefix);
255  update();
256 
257  return true;
258 }
259 
261  double Longitude,
262  double *Easting,
263  double *Northing)const
264 
265 { /* BEGIN Convert_Geodetic_To_NZMG */
266 /*
267  * The function Convert_Geodetic_To_NZMG converts geodetic (latitude and
268  * longitude) coordinates to New Zealand Map Grid projection (easting and northing)
269  * coordinates, according to the current ellipsoid and New Zealand Map Grid
270  * projection parameters. If any errors occur, the error code(s) are returned
271  * by the function, otherwise NZMG_NO_ERROR is returned.
272  *
273  * Latitude : Latitude (phi), in radians (input)
274  * Longitude : Longitude (lambda), in radians (input)
275  * Easting : Easting (X), in meters (output)
276  * Northing : Northing (Y), in meters (output)
277  */
278 
279  Complex Zeta, z;
280  int n;
281  double dphi;
282  double du, dlam;
283  long Error_Code = NZMG_NO_ERROR;
284 
285 // if ((Latitude < MIN_LAT) || (Latitude > MAX_LAT))
286 // { /* Latitude out of range */
287 // Error_Code|= NZMG_LAT_ERROR;
288 // }
289 // if ((Longitude < MIN_LON) || (Longitude > MAX_LON))
290 // { /* Longitude out of range */
291 // Error_Code|= NZMG_LON_ERROR;
292 // }
293 
294  if (!Error_Code)
295  { /* no errors */
296  dphi = (Latitude * (180.0 / M_PI) - NZMG_Origin_Lat) * 3600.0 * 1.0e-5;
297  du = A[9];
298  for (n = 8; n >= 0; n--)
299  du = du * dphi + A[n];
300  du *= dphi;
301 
302  dlam = Longitude - NZMG_Origin_Long;
303 
304  Zeta.real = du;
305  Zeta.imag = dlam;
306 
307  z.real = B[5].real;
308  z.imag = B[5].imag;
309  for (n = 4; n >= 0; n--)
310  {
311  z = Multiply(z, Zeta);
312  z = Add(B[n], z);
313  }
314  z = Multiply(z, Zeta);
315 
316  *Easting = (z.imag * NZMG_a) + NZMG_False_Easting;
317  *Northing = (z.real * NZMG_a) + NZMG_False_Northing;
318 
319 // if ((*Easting < NZMG_Min_Easting) || (*Easting > NZMG_Max_Easting))
320 // Error_Code |= NZMG_EASTING_ERROR;
321 // if ((*Northing < NZMG_Min_Northing) || (*Northing > NZMG_Max_Northing))
322 // Error_Code |= NZMG_NORTHING_ERROR;
323  }
324  return (Error_Code);
325 } /* END OF Convert_Geodetic_To_NZMG */
326 
327 
329  double Northing,
330  double *Latitude,
331  double *Longitude)const
332 
333 { /* Begin Convert_NZMG_To_Geodetic */
334 /*
335  * The function Convert_NZMG_To_Geodetic converts New Zealand Map Grid projection
336  * (easting and northing) coordinates to geodetic (latitude and longitude)
337  * coordinates, according to the current ellipsoid and New Zealand Map Grid projection
338  * coordinates. If any errors occur, the error code(s) are returned by the
339  * function, otherwise NZMG_NO_ERROR is returned.
340  *
341  * Easting : Easting (X), in meters (input)
342  * Northing : Northing (Y), in meters (input)
343  * Latitude : Latitude (phi), in radians (output)
344  * Longitude : Longitude (lambda), in radians (output)
345  */
346 
347  int i, n;
348  Complex coeff;
349  Complex z, Zeta, Zeta_Numer, Zeta_Denom, Zeta_sqr;
350  double dphi;
351  long Error_Code = NZMG_NO_ERROR;
352 
353 // if ((Easting < NZMG_Min_Easting) || (Easting > NZMG_Max_Easting))
354 // { /* Easting out of range */
355 // Error_Code |= NZMG_EASTING_ERROR;
356 // }
357 // if ((Northing < NZMG_Min_Northing) || (Northing > NZMG_Max_Northing))
358 // { /* Northing out of range */
359 // Error_Code |= NZMG_NORTHING_ERROR;
360 // }
361 
362  if (!Error_Code)
363  { /* no errors */
364  z.real = (Northing - NZMG_False_Northing) / NZMG_a;
365  z.imag = (Easting - NZMG_False_Easting) / NZMG_a;
366 
367  Zeta.real = C[5].real;
368  Zeta.imag = C[5].imag;
369  for (n = 4; n >= 0; n--)
370  {
371  Zeta = Multiply(Zeta, z);
372  Zeta = Add(C[n], Zeta);
373  }
374  Zeta = Multiply(Zeta, z);
375 
376  for (i = 0; i < 2; i++)
377  {
378  Zeta_Numer.real = 5.0 * B[5].real;
379  Zeta_Numer.imag = 5.0 * B[5].imag;
380  Zeta_Denom.real = 6.0 * B[5].real;
381  Zeta_Denom.imag = 6.0 * B[5].imag;
382  for (n = 4; n >= 1; n--)
383  {
384  Zeta_Numer = Multiply(Zeta_Numer, Zeta);
385  coeff.real = n * B[n].real;
386  coeff.imag = n * B[n].imag;
387  Zeta_Numer = Add(coeff, Zeta_Numer);
388 
389  Zeta_Denom = Multiply(Zeta_Denom, Zeta);
390  coeff.real = (n+1) * B[n].real;
391  coeff.imag = (n+1) * B[n].imag;
392  Zeta_Denom = Add(coeff, Zeta_Denom);
393  }
394  Zeta_sqr = Multiply(Zeta, Zeta);
395 
396  Zeta_Numer = Multiply(Zeta_Numer, Zeta_sqr);
397  Zeta_Numer = Add(z, Zeta_Numer);
398 
399  Zeta_Denom = Multiply(Zeta_Denom, Zeta);
400  Zeta_Denom = Add(B[0], Zeta_Denom);
401 
402  Zeta = Divide(Zeta_Numer, Zeta_Denom);
403  }
404  dphi = D[8];
405  for (n = 7; n >= 0; n--)
406  dphi = dphi * Zeta.real + D[n];
407  dphi *= Zeta.real;
408 
409  *Latitude = NZMG_Origin_Lat + (dphi * 1.0e5 / 3600.0);
410  *Latitude *= M_PI / 180.0;
411  *Longitude = NZMG_Origin_Long + Zeta.imag;
412 
413 // if ((*Longitude > M_PI) && (*Longitude - M_PI < 1.0e-6))
414 // *Longitude = M_PI;
415 
416 // if ((*Latitude < MIN_LAT) || (*Latitude > MAX_LAT))
417 // Error_Code|= NZMG_LAT_ERROR;
418 // if ((*Longitude < MIN_LON) || (*Longitude > MAX_LON))
419 // Error_Code|= NZMG_LON_ERROR;
420  }
421  return (Error_Code);
422 } /* END OF Convert_NZMG_To_Geodetic */
virtual const ossimDatum * create(const ossimString &code) const
create method
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
static const char * DATUM_KW
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
static const char * CENTRAL_MERIDIAN_KW
#define DEG_PER_RAD
Represents serializable keyword/value map.
double y
Definition: ossimDpt.h:165
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
virtual const ossimString & code() const
Definition: ossimDatum.h:57
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
#define A(r, c)
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)
long Convert_Geodetic_To_NZMG(double Latitude, double Longitude, double *Easting, double *Northing) const
#define M_PI
os2<< "> n<< " > nendobj n
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
virtual const ossimEllipsoid * ellipsoid() const
Definition: ossimDatum.h:60
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
static ossimDatumFactory * instance()
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual ossimGpt inverse(const ossimDpt &eastingNorthing) const
Will take a point in meters and convert it to ground.
static const char * ORIGIN_LATITUDE_KW
virtual ossimDpt forward(const ossimGpt &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
struct ComplexNumber Complex
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 RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
long Convert_NZMG_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.