41#define snprintf mysnprintf
45static const long long lNaN = 0xfff8000000000000;
46#define NAN (*(double *)&lNaN)
65struct DATUM const gDatum[] = {
67 {
"Adindan", 5, -162, -12, 206},
68 {
"Afgooye", 15, -43, -163, 45},
69 {
"Ain el Abd 1970", 14, -150, -251, -2},
70 {
"Anna 1 Astro 1965", 2, -491, -22, 435},
71 {
"Arc 1950", 5, -143, -90, -294},
72 {
"Arc 1960", 5, -160, -8, -300},
73 {
"Ascension Island 58", 14, -207, 107, 52},
74 {
"Astro B4 Sorol Atoll", 14, 114, -116, -333},
75 {
"Astro Beacon E ", 14, 145, 75, -272},
76 {
"Astro DOS 71/4", 14, -320, 550, -494},
77 {
"Astronomic Stn 52", 14, 124, -234, -25},
78 {
"Australian Geod 66", 2, -133, -48, 148},
79 {
"Australian Geod 84", 2, -134, -48, 149},
80 {
"Bellevue (IGN)", 14, -127, -769, 472},
81 {
"Bermuda 1957", 4, -73, 213, 296},
82 {
"Bogota Observatory", 14, 307, 304, -318},
83 {
"Campo Inchauspe", 14, -148, 136, 90},
84 {
"Canton Astro 1966", 14, 298, -304, -375},
85 {
"Cape", 5, -136, -108, -292},
86 {
"Cape Canaveral", 4, -2, 150, 181},
87 {
"Carthage", 5, -263, 6, 431},
88 {
"CH-1903", 3, 674, 15, 405},
89 {
"Chatham 1971", 14, 175, -38, 113},
90 {
"Chua Astro", 14, -134, 229, -29},
91 {
"Corrego Alegre", 14, -206, 172, -6},
92 {
"Djakarta (Batavia)", 3, -377, 681, -50},
93 {
"DOS 1968", 14, 230, -199, -752},
94 {
"Easter Island 1967", 14, 211, 147, 111},
95 {
"European 1950", 14, -87, -98, -121},
96 {
"European 1979", 14, -86, -98, -119},
97 {
"Finland Hayford", 14, -78, -231, -97},
98 {
"Gandajika Base", 14, -133, -321, 50},
99 {
"Geodetic Datum 49", 14, 84, -22, 209},
100 {
"Guam 1963", 4, -100, -248, 259},
101 {
"GUX 1 Astro", 14, 252, -209, -751},
102 {
"Hermannskogel Datum", 3, 682, -203, 480},
103 {
"Hjorsey 1955", 14, -73, 46, -86},
104 {
"Hong Kong 1963", 14, -156, -271, -189},
105 {
"Indian Bangladesh", 6, 289, 734, 257},
106 {
"Indian Thailand", 6, 214, 836, 303},
107 {
"Ireland 1965", 1, 506, -122, 611},
108 {
"ISTS 073 Astro 69", 14, 208, -435, -229},
109 {
"Johnston Island", 14, 191, -77, -204},
110 {
"Kandawala", 6, -97, 787, 86},
111 {
"Kerguelen Island", 14, 145, -187, 103},
112 {
"Kertau 1948", 7, -11, 851, 5},
113 {
"L.C. 5 Astro", 4, 42, 124, 147},
114 {
"Liberia 1964", 5, -90, 40, 88},
115 {
"Luzon Mindanao", 4, -133, -79, -72},
116 {
"Luzon Philippines", 4, -133, -77, -51},
117 {
"Mahe 1971", 5, 41, -220, -134},
118 {
"Marco Astro", 14, -289, -124, 60},
119 {
"Massawa", 3, 639, 405, 60},
120 {
"Merchich", 5, 31, 146, 47},
121 {
"Midway Astro 1961", 14, 912, -58, 1227},
122 {
"Minna", 5, -92, -93, 122},
123 {
"NAD27 Alaska", 4, -5, 135, 172},
124 {
"NAD27 Bahamas", 4, -4, 154, 178},
125 {
"NAD27 Canada", 4, -10, 158, 187},
126 {
"NAD27 Canal Zone", 4, 0, 125, 201},
127 {
"NAD27 Caribbean", 4, -7, 152, 178},
128 {
"NAD27 Central", 4, 0, 125, 194},
129 {
"NAD27 CONUS", 4, -8, 160, 176},
130 {
"NAD27 Cuba", 4, -9, 152, 178},
131 {
"NAD27 Greenland", 4, 11, 114, 195},
132 {
"NAD27 Mexico", 4, -12, 130, 190},
133 {
"NAD27 San Salvador", 4, 1, 140, 165},
134 {
"NAD83", 11, 0, 0, 0},
135 {
"Nahrwn Masirah Ilnd", 5, -247, -148, 369},
136 {
"Nahrwn Saudi Arbia", 5, -231, -196, 482},
137 {
"Nahrwn United Arab", 5, -249, -156, 381},
138 {
"Naparima BWI", 14, -2, 374, 172},
139 {
"Observatorio 1966", 14, -425, -169, 81},
140 {
"Old Egyptian", 12, -130, 110, -13},
141 {
"Old Hawaiian", 4, 61, -285, -181},
142 {
"Oman", 5, -346, -1, 224},
143 {
"Ord Srvy Grt Britn", 0, 375, -111, 431},
144 {
"Pico De Las Nieves", 14, -307, -92, 127},
145 {
"Pitcairn Astro 1967", 14, 185, 165, 42},
146 {
"Prov So Amrican 56", 14, -288, 175, -376},
147 {
"Prov So Chilean 63", 14, 16, 196, 93},
148 {
"Puerto Rico", 4, 11, 72, -101},
149 {
"Qatar National", 14, -128, -283, 22},
150 {
"Qornoq", 14, 164, 138, -189},
151 {
"Reunion", 14, 94, -948, -1262},
152 {
"Rome 1940", 14, -225, -65, 9},
153 {
"RT 90", 3, 498, -36, 568},
154 {
"Santo (DOS)", 14, 170, 42, 84},
155 {
"Sao Braz", 14, -203, 141, 53},
156 {
"Sapper Hill 1943", 14, -355, 16, 74},
157 {
"Schwarzeck", 21, 616, 97, -251},
158 {
"South American 69", 16, -57, 1, -41},
159 {
"South Asia", 8, 7, -10, -26},
160 {
"Southeast Base", 14, -499, -249, 314},
161 {
"Southwest Base", 14, -104, 167, -38},
162 {
"Timbalai 1948", 6, -689, 691, -46},
163 {
"Tokyo", 3, -128, 481, 664},
164 {
"Tristan Astro 1968", 14, -632, 438, -609},
165 {
"Viti Levu 1916", 5, 51, 391, -36},
166 {
"Wake-Eniwetok 60", 13, 101, 52, -39},
167 {
"WGS 72", 19, 0, 0, 5},
168 {
"WGS 84", 20, 0, 0, 0},
169 {
"Zanderij", 14, -265, 120, -358},
170 {
"WGS_84", 20, 0, 0, 0},
171 {
"WGS-84", 20, 0, 0, 0},
172 {
"EUROPEAN DATUM 1950", 14, -87, -98, -121},
173 {
"European 1950 (Norway Finland)", 14, -87, -98, -121},
174 {
"ED50", 14, -87, -98, -121},
175 {
"RT90 (Sweden)", 3, 498, -36, 568},
176 {
"Monte Mario 1940", 14, -104, -49, 10},
177 {
"Ord Surv of Gr Britain 1936", 0, 375, -111, 431},
178 {
"South American 1969", 16, -57, 1, -41},
179 {
"PULKOVO 1942 (2)", 15, 25, -141, -79},
180 {
"EUROPEAN DATUM", 14, -87, -98, -121},
181 {
"BERMUDA DATUM 1957", 4, -73, 213, 296},
182 {
"COA", 14, -206, 172, -6},
183 {
"COABR", 14, -206, 172, -6},
184 {
"Roma 1940", 14, -225, -65, 9},
185 {
"ITALIENISCHES LANDESNETZ", 14, -87, -98, -121},
186 {
"HERMANSKOGEL DATUM", 3, 682, -203, 480},
187 {
"AGD66", 2, -128, -52, 153},
188 {
"ED", 14, -87, -98, -121},
189 {
"EUROPEAN 1950 (SPAIN AND PORTUGAL)", 14, -87, -98, -121},
190 {
"ED-50", 14, -87, -98, -121},
191 {
"EUROPEAN", 14, -87, -98, -121},
192 {
"POTSDAM", 14, -87, -98, -121},
193 {
"GRACIOSA SW BASE DATUM", 14, -104, 167, -38},
194 {
"WGS 1984", 20, 0, 0, 0},
195 {
"WGS 1972", 19, 0, 0, 5},
201 {
"Airy 1830", 6377563.396, 299.3249646},
202 {
"Modified Airy", 6377340.189, 299.3249646},
203 {
"Australian National", 6378160.0, 298.25},
204 {
"Bessel 1841", 6377397.155, 299.1528128},
205 {
"Clarke 1866", 6378206.4, 294.9786982},
206 {
"Clarke 1880", 6378249.145, 293.465},
207 {
"Everest (India 1830)", 6377276.345, 300.8017},
208 {
"Everest (1948)", 6377304.063, 300.8017},
209 {
"Modified Fischer 1960", 6378155.0, 298.3},
210 {
"Everest (Pakistan)", 6377309.613, 300.8017},
211 {
"Indonesian 1974", 6378160.0, 298.247},
212 {
"GRS 80", 6378137.0, 298.257222101},
213 {
"Helmert 1906", 6378200.0, 298.3},
214 {
"Hough 1960", 6378270.0, 297.0},
215 {
"International 1924", 6378388.0, 297.0},
216 {
"Krassovsky 1940", 6378245.0, 298.3},
217 {
"South American 1969", 6378160.0, 298.25},
218 {
"Everest (Malaysia 1969)", 6377295.664, 300.8017},
219 {
"Everest (Sabah Sarawak)", 6377298.556, 300.8017},
220 {
"WGS 72", 6378135.0, 298.26},
221 {
"WGS 84", 6378137.0, 298.257223563},
222 {
"Bessel 1841 (Namibia)", 6377483.865, 299.1528128},
223 {
"Everest (India 1956)", 6377301.243, 300.8017},
224 {
"Struve 1860", 6378298.3, 294.73}
228short nDatums =
sizeof(gDatum) /
sizeof(
struct DATUM);
232void datumParams(
short datum,
double *a,
double *es) {
233 extern struct DATUM const gDatum[];
234 extern struct ELLIPSOID const gEllipsoid[];
236 if (datum < nDatums) {
237 double f = 1.0 / gEllipsoid[gDatum[datum].ellipsoid].invf;
238 if (es) *es = 2 * f - f * f;
239 if (a) *a = gEllipsoid[gDatum[datum].ellipsoid].a;
241 double f = 1.0 / 298.257223563;
242 if (es) *es = 2 * f - f * f;
243 if (a) *a = 6378137.0;
247static int datumNameCmp(
const char *n1,
const char *n2) {
253 else if (toupper(*n1) == toupper(*n2))
260static int isWGS84(
int i) {
263 if (i == DATUM_INDEX_WGS84)
return i;
265 if (gDatum[i].ellipsoid != gDatum[DATUM_INDEX_WGS84].ellipsoid)
return i;
267 if (gDatum[i].dx != gDatum[DATUM_INDEX_WGS84].dx)
return i;
269 if (gDatum[i].dy != gDatum[DATUM_INDEX_WGS84].dy)
return i;
271 if (gDatum[i].dz != gDatum[DATUM_INDEX_WGS84].dz)
return i;
273 return DATUM_INDEX_WGS84;
276int GetDatumIndex(
const char *str) {
278 while (i < (
int)nDatums) {
279 if (!datumNameCmp(str, gDatum[i].name)) {
291void toDMS(
double a,
char *bufp,
int bufplen) {
294 int n = (int)((a - (
int)a) * 36000.0);
297 sprintf(bufp,
"%d%02d'%02d.%01d\"", (
int)(neg ? -a : a), m, s / 10, s % 10);
304double fromDMS(
char *dms) {
307 char buf[20] = {
'\0'};
309 sscanf(dms,
"%d%[ ]%d%[ ']%lf%[ \"NSWEnswe]", &d, buf, &m, buf, &s, buf);
311 s = (double)(abs(d)) + ((
double)m + s / 60.0) / 60.0;
313 if (d >= 0 && strpbrk(buf,
"SWsw") == NULL)
return s;
322void todmm(
int flag,
double a,
char *bufp,
int bufplen) {
326 int m = (int)((a - (
int)a) * 60000.0);
329 snprintf(bufp, bufplen,
"%d %02d.%03d'", (
int)a, m / 1000, m % 1000);
332 snprintf(bufp, bufplen,
"%02d %02d.%03d %c", (
int)a, m / 1000, (m % 1000),
334 }
else if (flag == 2) {
335 snprintf(bufp, bufplen,
"%03d %02d.%03d %c", (
int)a, m / 1000, (m % 1000),
341void toDMM(
double a,
char *bufp,
int bufplen) {
342 todmm(0, a, bufp, bufplen);
351void toSM(
double lat,
double lon,
double lat0,
double lon0,
double *x,
357 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
358 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
361 const double z = WGS84_semimajor_axis_meters * mercator_k0;
363 *x = (xlon - lon0) * DEGREE * z;
366 const double s = sin(lat * DEGREE);
367 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
369 const double s0 = sin(lat0 * DEGREE);
370 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
374double toSMcache_y30(
double lat0) {
375 const double z = WGS84_semimajor_axis_meters * mercator_k0;
376 const double s0 = sin(lat0 * DEGREE);
377 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
381void toSMcache(
double lat,
double lon,
double y30,
double lon0,
double *x,
387 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
388 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
391 const double z = WGS84_semimajor_axis_meters * mercator_k0;
393 *x = (xlon - lon0) * DEGREE * z;
396 const double s = sin(lat * DEGREE);
397 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
402void fromSM(
double x,
double y,
double lat0,
double lon0,
double *lat,
404 const double z = WGS84_semimajor_axis_meters * mercator_k0;
417 const double s0 = sin(lat0 * DEGREE);
418 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * z;
420 *lat = (2.0 * atan(exp((y0 + y) / z)) - PI / 2.) / DEGREE;
423 *lon = lon0 + (x / (DEGREE * z));
426void fromSMR(
double x,
double y,
double lat0,
double lon0,
double axis_meters,
427 double *lat,
double *lon) {
428 const double s0 = sin(lat0 * DEGREE);
429 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * axis_meters;
431 *lat = (2.0 * atan(exp((y0 + y) / axis_meters)) - PI / 2.) / DEGREE;
434 *lon = lon0 + (x / (DEGREE * axis_meters));
437void toSM_ECC(
double lat,
double lon,
double lat0,
double lon0,
double *x,
439 const double f = 1.0 / WGSinvf;
440 const double e2 = 2 * f - f * f;
441 const double e = sqrt(e2);
443 const double z = WGS84_semimajor_axis_meters * mercator_k0;
445 *x = (lon - lon0) * DEGREE * z;
448 const double s = sin(lat * DEGREE);
451 const double s0 = sin(lat0 * DEGREE);
456 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
457 pow((1. - e * s0) / (1. + e * s0), e / 2.));
458 const double test = z * log(tan(PI / 4 + lat * DEGREE / 2) *
459 pow((1. - e * s) / (1. + e * s), e / 2.));
463void fromSM_ECC(
double x,
double y,
double lat0,
double lon0,
double *lat,
465 const double f = 1.0 / WGSinvf;
466 const double es = 2 * f - f * f;
467 const double e = sqrt(es);
469 const double z = WGS84_semimajor_axis_meters * mercator_k0;
471 *lon = lon0 + (x / (DEGREE * z));
473 const double s0 = sin(lat0 * DEGREE);
475 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
476 pow((1. - e * s0) / (1. + e * s0), e / 2.));
477 const double t = exp((y + falsen) / (z));
478 const double xi = (PI / 2.) - 2.0 * atan(t);
482 double esf = (es / 2. + (5 * es * es / 24.) + (es * es * es / 12.) +
483 (13.0 * es * es * es * es / 360.)) *
485 esf += ((7. * es * es / 48.) + (29. * es * es * es / 240.) +
486 (811. * es * es * es * es / 11520.)) *
488 esf += ((7. * es * es * es / 120.) + (81 * es * es * es * es / 1120.) +
489 (4279. * es * es * es * es / 161280.)) *
492 *lat = -(xi + esf) / DEGREE;
501void toPOLY(
double lat,
double lon,
double lat0,
double lon0,
double *x,
503 const double z = WGS84_semimajor_axis_meters * mercator_k0;
505 if (fabs((lat - lat0) * DEGREE) <= TOL) {
506 *x = (lon - lon0) * DEGREE * z;
510 const double E = (lon - lon0) * DEGREE * sin(lat * DEGREE);
511 const double cot = 1. / tan(lat * DEGREE);
513 *y = (lat * DEGREE) - (lat0 * DEGREE) + cot * (1. - cos(E));
529void fromPOLY(
double x,
double y,
double lat0,
double lon0,
double *lat,
531 const double z = WGS84_semimajor_axis_meters * mercator_k0;
533 double yp = y - (lat0 * DEGREE * z);
534 if (fabs(yp) <= TOL) {
535 *lon = lon0 + (x / (DEGREE * z));
539 const double xp = x / z;
542 const double B = (xp * xp) + (yp * yp);
546 double tp = tan(lat3);
547 dphi = (yp * (lat3 * tp + 1.) - lat3 - .5 * (lat3 * lat3 + B) * tp) /
548 ((lat3 - yp) / tp - 1.);
550 }
while (fabs(dphi) > CONV && --i);
555 *lon = asin(xp * tan(lat3)) / sin(lat3);
559 *lat = lat3 / DEGREE;
575void toTM(
float lat,
float lon,
float lat0,
float lon0,
double *x,
double *y) {
577 const double f = 1.0 / WGSinvf;
578 const double a = WGS84_semimajor_axis_meters;
579 const double k0 = 1.;
581 const double eccSquared = 2 * f - f * f;
582 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
583 const double LatRad = lat * DEGREE;
584 const double LongOriginRad = lon0 * DEGREE;
585 const double LongRad = lon * DEGREE;
587 const double N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad));
588 const double T = tan(LatRad) * tan(LatRad);
589 const double C = eccPrimeSquared * cos(LatRad) * cos(LatRad);
590 const double A = cos(LatRad) * (LongRad - LongOriginRad);
594 ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
595 5 * eccSquared * eccSquared * eccSquared / 256) *
597 (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 +
598 45 * eccSquared * eccSquared * eccSquared / 1024) *
600 (15 * eccSquared * eccSquared / 256 +
601 45 * eccSquared * eccSquared * eccSquared / 1024) *
603 (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad));
606 (A + (1 - T + C) * A * A * A / 6 +
607 (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A *
612 (MM + N * tan(LatRad) *
613 (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
614 (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A *
615 A * A * A * A * A / 720)));
628void fromTM(
double x,
double y,
double lat0,
double lon0,
double *lat,
630 const double rad2deg = 1. / DEGREE;
633 const double f = 1.0 / WGSinvf;
634 const double a = WGS84_semimajor_axis_meters;
635 const double k0 = 1.;
637 const double eccSquared = 2 * f - f * f;
639 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
641 (1.0 - sqrt(1.0 - eccSquared)) / (1.0 + sqrt(1.0 - eccSquared));
643 const double MM = y / k0;
645 MM / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
646 5 * eccSquared * eccSquared * eccSquared / 256));
648 const double phi1Rad =
649 mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) +
650 (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) +
651 (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
653 const double N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad));
654 const double T1 = tan(phi1Rad) * tan(phi1Rad);
655 const double C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
656 const double R1 = a * (1 - eccSquared) /
657 pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5);
658 const double D = x / (N1 * k0);
661 (N1 * tan(phi1Rad) / R1) *
663 (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D *
665 (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared -
667 D * D * D * D * D * D / 720);
668 *lat = lat0 + (*lat * rad2deg);
670 *lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 +
671 (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared +
673 D * D * D * D * D / 120) /
675 *lon = lon0 + *lon * rad2deg;
683void cache_phi0(
double lat0,
double *sin_phi0,
double *cos_phi0) {
684 double phi0 = lat0 * DEGREE;
685 *sin_phi0 = sin(phi0);
686 *cos_phi0 = cos(phi0);
689void toORTHO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
690 double lon0,
double *x,
double *y) {
691 const double z = WGS84_semimajor_axis_meters * mercator_k0;
695 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
696 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
698 double theta = (xlon - lon0) * DEGREE;
699 double phi = lat * DEGREE;
700 double cos_phi = cos(phi);
702 double vy = sin(phi), vz = cos(theta) * cos_phi;
704 if (vy * sin_phi0 + vz * cos_phi0 < 0) {
709 double vx = sin(theta) * cos_phi;
710 double vw = vy * cos_phi0 - vz * sin_phi0;
716void fromORTHO(
double x,
double y,
double lat0,
double lon0,
double *lat,
718 const double z = WGS84_semimajor_axis_meters * mercator_k0;
723 double phi0 = lat0 * DEGREE;
724 double d = 1 - vx * vx - vw * vw;
731 double sin_phi0 = sin(phi0), cos_phi0 = cos(phi0);
732 double vy = vw * cos_phi0 + sqrt(d) * sin_phi0;
733 double phi = asin(vy);
735 double vz = (vy * cos_phi0 - vw) / sin_phi0;
736 double theta = atan2(vx, vz);
739 *lon = theta / DEGREE + lon0;
742double toPOLARcache_e(
double lat0) {
743 double pole = lat0 > 0 ? 90 : -90;
744 return tan((pole - lat0) * DEGREE / 2);
747void toPOLAR(
double lat,
double lon,
double e,
double lat0,
double lon0,
748 double *x,
double *y) {
749 const double z = WGS84_semimajor_axis_meters * mercator_k0;
753 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
754 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
756 double theta = (xlon - lon0) * DEGREE;
757 double pole = lat0 > 0 ? 90 : -90;
759 double d = tan((pole - lat) * DEGREE / 2);
761 *x = fabs(d) * sin(theta) * z;
762 *y = (e - d * cos(theta)) * z;
765void fromPOLAR(
double x,
double y,
double lat0,
double lon0,
double *lat,
767 const double z = WGS84_semimajor_axis_meters * mercator_k0;
768 double pole = lat0 > 0 ? 90 : -90;
770 double e = tan((pole - lat0) * DEGREE / 2);
773 double yn = e - y / z;
774 double d = sqrt(xn * xn + yn * yn);
778 *lat = pole - atan(d) * 2 / DEGREE;
780 double theta = atan2(xn, yn);
781 *lon = theta / DEGREE + lon0;
784static inline void toSTEREO1(
double &u,
double &v,
double &w,
double lat,
785 double lon,
double sin_phi0,
double cos_phi0,
789 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
790 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
792 double theta = (xlon - lon0) * DEGREE, phi = lat * DEGREE;
793 double cos_phi = cos(phi), v0 = sin(phi), w0 = cos(theta) * cos_phi;
795 u = sin(theta) * cos_phi;
796 v = cos_phi0 * v0 - sin_phi0 * w0;
797 w = sin_phi0 * v0 + cos_phi0 * w0;
800static inline void fromSTEREO1(
double *lat,
double *lon,
double lat0,
801 double lon0,
double u,
double v,
double w) {
802 double phi0 = lat0 * DEGREE;
803 double v0 = sin(phi0) * w + cos(phi0) * v;
804 double w0 = cos(phi0) * w - sin(phi0) * v;
805 double phi = asin(v0);
806 double theta = atan2(u, w0);
809 *lon = theta / DEGREE + lon0;
812void toSTEREO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
813 double lon0,
double *x,
double *y) {
814 const double z = WGS84_semimajor_axis_meters * mercator_k0;
817 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
819 double t = 2 / (w + 1);
824void fromSTEREO(
double x,
double y,
double lat0,
double lon0,
double *lat,
826 const double z = WGS84_semimajor_axis_meters * mercator_k0;
830 double t = (x * x + y * y) / 4 + 1;
834 double w = 2 / t - 1;
836 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
839void toGNO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
840 double lon0,
double *x,
double *y) {
841 const double z = WGS84_semimajor_axis_meters * mercator_k0;
844 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
855void fromGNO(
double x,
double y,
double lat0,
double lon0,
double *lat,
857 const double z = WGS84_semimajor_axis_meters * mercator_k0;
861 double w = 1 / sqrt(x * x + y * y + 1);
865 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
868void toEQUIRECT(
double lat,
double lon,
double lat0,
double lon0,
double *x,
870 const double z = WGS84_semimajor_axis_meters * mercator_k0;
873 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
874 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
876 *x = (xlon - lon0) * DEGREE * z;
877 *y = (lat - lat0) * DEGREE * z;
880void fromEQUIRECT(
double x,
double y,
double lat0,
double lon0,
double *lat,
882 const double z = WGS84_semimajor_axis_meters * mercator_k0;
884 *lat = lat0 + (y / (DEGREE * z));
886 *lon = lon0 + (x / (DEGREE * z));
906void MolodenskyTransform(
double lat,
double lon,
double *to_lat,
double *to_lon,
907 int from_datum_index,
int to_datum_index) {
911 if (from_datum_index < nDatums) {
912 const double from_lat = lat * DEGREE;
913 const double from_lon = lon * DEGREE;
914 const double from_f =
916 gEllipsoid[gDatum[from_datum_index].ellipsoid].invf;
917 const double from_esq = 2 * from_f - from_f * from_f;
918 const double from_a =
919 gEllipsoid[gDatum[from_datum_index].ellipsoid].a;
920 const double dx = gDatum[from_datum_index].dx;
921 const double dy = gDatum[from_datum_index].dy;
922 const double dz = gDatum[from_datum_index].dz;
924 1.0 / gEllipsoid[gDatum[to_datum_index].ellipsoid].invf;
926 gEllipsoid[gDatum[to_datum_index].ellipsoid].a;
927 const double da = to_a - from_a;
928 const double df = to_f - from_f;
929 const double from_h = 0;
931 const double slat = sin(from_lat);
932 const double clat = cos(from_lat);
933 const double slon = sin(from_lon);
934 const double clon = cos(from_lon);
935 const double ssqlat = slat * slat;
936 const double adb = 1.0 / (1.0 - from_f);
938 const double rn = from_a / sqrt(1.0 - from_esq * ssqlat);
940 from_a * (1. - from_esq) / pow((1.0 - from_esq * ssqlat), 1.5);
942 dlat = (((((-dx * slat * clon - dy * slat * slon) + dz * clat) +
943 (da * ((rn * from_esq * slat * clat) / from_a))) +
944 (df * (rm * adb + rn / adb) * slat * clat))) /
947 dlon = (-dx * slon + dy * clon) / ((rn + from_h) * clat);
950 *to_lon = lon + dlon / DEGREE;
951 *to_lat = lat + dlat / DEGREE;
989#define HALFPI 1.5707963267948966
990#define SPI 3.14159265359
991#define TWOPI 6.2831853071795864769
992#define ONEPI 3.14159265358979323846
995double adjlon(
double lon) {
996 if (fabs(lon) <= SPI)
return (lon);
998 lon -= TWOPI * floor(lon / TWOPI);
1012void ll_gc_ll(
double lat,
double lon,
double brg,
double dist,
double *dlat,
1014 double th1, costh1, sinth1, sina12, cosa12, M, N, c1, c2, D, P, s1;
1017 if ((brg == 90.) || (brg == 180.)) {
1025 double phi1, lam1, phi2, lam2;
1030 double es, onef, f, f4;
1033 phi1 = lat * DEGREE;
1034 lam1 = lon * DEGREE;
1035 al12 = brg * DEGREE;
1036 geod_S = dist * 1852.0;
1045 geod_a = WGS84_semimajor_axis_meters;
1048 onef = sqrt(1. - es);
1052 al12 = adjlon(al12);
1053 signS = fabs(al12) > HALFPI ? 1 : 0;
1054 th1 = ellipse ? atan(onef * tan(phi1)) : phi1;
1057 if ((merid = fabs(sina12 = sin(al12)) < MERI_TOL)) {
1059 cosa12 = fabs(al12) < HALFPI ? 1. : -1.;
1063 M = costh1 * sina12;
1065 N = costh1 * cosa12;
1075 c2 = f4 * (1. - M * M);
1076 D = (1. - c2) * (1. - c2 - c1 * M);
1077 P = (1. + .5 * c1 * M) * c2 / D;
1083 s1 = (fabs(M) >= 1.) ? 0. : acos(M);
1084 s1 = sinth1 / sin(s1);
1085 s1 = (fabs(s1) >= 1.) ? 0. : acos(s1);
1091 double d, sind, u, V, X, ds, cosds, sinds, ss, de;
1096 d = geod_S / (D * geod_a);
1100 X = c2 * c2 * (sind = sin(d)) * cos(d) * (2. * V * V - 1.);
1101 ds = d + X - 2. * P * V * (1. - 2. * P * cos(u)) * sind;
1104 ds = geod_S / geod_a;
1105 if (signS) ds = -ds;
1109 if (signS) sinds = -sinds;
1110 al21 = N * cosds - sinth1 * sinds;
1112 phi2 = atan(tan(HALFPI + s1 - ds) / onef);
1130 al21 = atan(M / al21);
1131 if (al21 > 0) al21 += PI;
1132 if (al12 < 0.) al21 -= PI;
1133 al21 = adjlon(al21);
1134 phi2 = atan(-(sinth1 * cosds + N * sinds) * sin(al21) /
1135 (ellipse ? onef * M : M));
1136 de = atan2(sinds * sina12, (costh1 * cosds - sinth1 * sinds * cosa12));
1139 de += c1 * ((1. - c2) * ds + c2 * sinds * cos(ss));
1141 de -= c1 * ((1. - c2) * ds - c2 * sinds * cos(ss));
1144 lam2 = adjlon(lam1 + de);
1147 *dlat = phi2 / DEGREE;
1148 *dlon = lam2 / DEGREE;
1151void ll_gc_ll_reverse(
double lat1,
double lon1,
double lat2,
double lon2,
1152 double *bearing,
double *dist) {
1155 if ((fabs(lon2 - lon1) < 0.1) && (fabs(lat2 - lat1) < 0.1)) {
1156 DistanceBearingMercator(lat2, lon2, lat1, lon1, bearing, dist);
1163 double phi1, lam1, phi2, lam2;
1168 double es, onef, f, f64, f2, f4;
1171 phi1 = lat1 * DEGREE;
1172 lam1 = lon1 * DEGREE;
1173 phi2 = lat2 * DEGREE;
1174 lam2 = lon2 * DEGREE;
1178 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm,
1179 cosdthm, sindthm, L, E, cosd, d, X, Y, T, sind, tandlammp, u, v, D, A,
1188 geod_a = WGS84_semimajor_axis_meters;
1191 onef = sqrt(1. - es);
1195 f64 = geod_f * geod_f / 64;
1198 th1 = atan(onef * tan(phi1));
1199 th2 = atan(onef * tan(phi2));
1204 thm = .5 * (th1 + th2);
1205 dthm = .5 * (th2 - th1);
1206 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1207 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1208 al12 = al21 = geod_S = 0.;
1209 if (bearing) *bearing = 0.;
1210 if (dist) *dist = 0.;
1213 sindlamm = sin(dlamm);
1216 cosdthm = cos(dthm);
1217 sindthm = sin(dthm);
1218 L = sindthm * sindthm +
1219 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1220 d = acos(cosd = 1 - L - L);
1224 Y = sinthm * cosdthm;
1225 Y *= (Y + Y) / (1. - L);
1226 T = sindthm * costhm;
1234 geod_S = geod_a * sind *
1235 (T - f4 * (T * X - Y) +
1236 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1239 tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X)) *
1240 (f2 * T + f64 * (32. * T - (20. * T - A) * X -
1244 geod_S = geod_a * d;
1245 tandlammp = tan(dlamm);
1247 u = atan2(sindthm, (tandlammp * costhm));
1248 v = atan2(cosdthm, (tandlammp * sinthm));
1249 al12 = adjlon(TWOPI + v - u);
1250 al21 = adjlon(TWOPI - v - u);
1251 if (al12 < 0) al12 += 2 * PI;
1252 if (bearing) *bearing = al12 / DEGREE;
1253 if (dist) *dist = geod_S / 1852.0;
1258void PositionBearingDistanceMercator(
double lat,
double lon,
double brg,
1259 double dist,
double *dlat,
double *dlon) {
1260 ll_gc_ll(lat, lon, brg, dist, dlat, dlon);
1263double DistLoxodrome(
double slat,
double slon,
double dlat,
double dlon) {
1265 60 * sqrt(pow(slat - dlat, 2) +
1266 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1268 if (slon * dlon < 0) {
1274 60 * sqrt(pow(slat - dlat, 2) +
1275 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1276 return (std::min)(dist, distrtw);
1291double DistGreatCircle(
double slat,
double slon,
double dlat,
double dlon) {
1293 d5 = DistLoxodrome(slat, slon, dlat, dlon);
1301 double phi1, lam1, phi2, lam2;
1306 double es, onef, f, f64, f4;
1308 phi1 = slat * DEGREE;
1309 lam1 = slon * DEGREE;
1310 phi2 = dlat * DEGREE;
1311 lam2 = dlon * DEGREE;
1315 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm, cosdthm,
1316 sindthm, L, E, cosd, d, X, Y, T, sind, D, A, B;
1325 geod_a = WGS84_semimajor_axis_meters;
1328 onef = sqrt(1. - es);
1332 f64 = geod_f * geod_f / 64;
1335 th1 = atan(onef * tan(phi1));
1336 th2 = atan(onef * tan(phi2));
1341 thm = .5 * (th1 + th2);
1342 dthm = .5 * (th2 - th1);
1343 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1344 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1347 sindlamm = sin(dlamm);
1350 cosdthm = cos(dthm);
1351 sindthm = sin(dthm);
1352 L = sindthm * sindthm +
1353 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1354 d = acos(cosd = 1 - L - L);
1359 Y = sinthm * cosdthm;
1360 Y *= (Y + Y) / (1. - L);
1361 T = sindthm * costhm;
1369 geod_S = geod_a * sind *
1370 (T - f4 * (T * X - Y) +
1371 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1378 geod_S = geod_a * d;
1387 d5 = geod_S / 1852.0;
1392void DistanceBearingMercator(
double lat1,
double lon1,
double lat0,
double lon0,
1393 double *brg,
double *dist) {
1395 double latm = (lat0 + lat1) / 2 * DEGREE;
1396 double delta_lat = (lat1 - lat0);
1397 double delta_lon = (lon1 - lon0);
1398 double ex_lat0, ex_lat1;
1399 double bearing, distance;
1401 if (delta_lon < -180) delta_lon += 360;
1402 if (delta_lon > 180) delta_lon -= 360;
1406 else if (fabs(delta_lat) != .0)
1407 bearing = atan(delta_lon * cos(latm) / delta_lat);
1411 distance = sqrt(pow(delta_lat, 2) + pow(delta_lon * cos(latm), 2));
1416 if (delta_lat != 0.) {
1417 ex_lat0 = 10800 / PI * log(tan(PI / 4 + lat0 * DEGREE / 2));
1418 ex_lat1 = 10800 / PI * log(tan(PI / 4 + lat1 * DEGREE / 2));
1419 bearing = atan(delta_lon * 60 / (ex_lat1 - ex_lat0));
1420 distance = fabs(delta_lat / cos(bearing));
1426 bearing = fabs(bearing);
1428 if (delta_lon < 0) bearing = 2 * PI - bearing;
1432 bearing = PI - bearing;
1434 bearing = PI + bearing;
1437 if (brg) *brg = bearing * RADIAN;
1438 if (dist) *dist = distance * 60;
1465 double ret = p[0] + p[1] * tx;
1467 if (n_par > 2) ret += p[2] * ty;
1469 ret += p[3] * tx * tx;
1470 ret += p[4] * tx * ty;
1471 ret += p[5] * ty * ty;
1474 ret += p[6] * tx * tx * tx;
1475 ret += p[7] * tx * tx * ty;
1476 ret += p[8] * tx * ty * ty;
1477 ret += p[9] * ty * ty * ty;
1483int Georef_Calculate_Coefficients_Onedir(
int n_points,
int n_par,
double *tx,
1484 double *ty,
double *y,
double *p,
1485 double hintp0,
double hintp1,
1502 for (i = 0; i < 12; i++) p[i] = 0.;
1516 data.print_flag = 0;
1520 lm_minimize(n_points, n_par, p, lm_evaluate_default, lm_print_default, &data,
1528 return control.info;
1531int Georef_Calculate_Coefficients(
struct GeoRef *cp,
int nlin_lon) {
1533 for (
int i = 0; i < 10; ++i)
1534 cp->
pwx[i] = cp->
pwy[i] = cp->
wpx[i] = cp->
wpy[i] = 0.0;
1538 switch (cp->
order) {
1553 const int mp_lat = mp;
1556 const int mp_lon = nlin_lon ? 2 : mp;
1559 std::vector<double> pnull(cp->
count, 1.0);
1564 int r1 = Georef_Calculate_Coefficients_Onedir(
1572 double *px = nlin_lon ? &pnull[0] : cp->
tx;
1574 int r2 = Georef_Calculate_Coefficients_Onedir(
1583 int r3 = Georef_Calculate_Coefficients_Onedir(
1591 px = nlin_lon ? &pnull[0] : cp->
lon;
1593 int r4 = Georef_Calculate_Coefficients_Onedir(
1599 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1606int Georef_Calculate_Coefficients_Proj(
struct GeoRef *cp) {
1611 cp->
pwx[6] = cp->
pwy[6] = cp->
wpx[6] = cp->
wpy[6] = 0.;
1612 cp->
pwx[7] = cp->
pwy[7] = cp->
wpx[7] = cp->
wpy[7] = 0.;
1613 cp->
pwx[8] = cp->
pwy[8] = cp->
wpx[8] = cp->
wpy[8] = 0.;
1614 cp->
pwx[9] = cp->
pwy[9] = cp->
wpx[9] = cp->
wpy[9] = 0.;
1615 cp->
pwx[3] = cp->
pwy[3] = cp->
wpx[3] = cp->
wpy[3] = 0.;
1616 cp->
pwx[4] = cp->
pwy[4] = cp->
wpx[4] = cp->
wpy[4] = 0.;
1617 cp->
pwx[5] = cp->
pwy[5] = cp->
wpx[5] = cp->
wpy[5] = 0.;
1618 cp->
pwx[0] = cp->
pwy[0] = cp->
wpx[0] = cp->
wpy[0] = 0.;
1619 cp->
pwx[1] = cp->
pwy[1] = cp->
wpx[1] = cp->
wpy[1] = 0.;
1620 cp->
pwx[2] = cp->
pwy[2] = cp->
wpx[2] = cp->
wpy[2] = 0.;
1627 r1 = Georef_Calculate_Coefficients_Onedir(
1633 r2 = Georef_Calculate_Coefficients_Onedir(
1642 r3 = Georef_Calculate_Coefficients_Onedir(
1648 r4 = Georef_Calculate_Coefficients_Onedir(
1654 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1667void lm_evaluate_default(
double *par,
int m_dat,
double *fvec,
void *data,
1687 for (
int i = 0; i < m_dat; i++) {
1688 fvec[i] = mydata->user_y[i] - mydata->user_func(mydata->user_tx[i],
1690 mydata->n_par, par);
1696void lm_print_default(
int n_par,
double *par,
int m_dat,
double *fvec,
1697 void *data,
int iflag,
int iter,
int nfev)
1708 if (mydata->print_flag) {
1710 printf(
"trying step in gradient direction\n");
1711 }
else if (iflag == 1) {
1712 printf(
"determining gradient (iteration %d)\n", iter);
1713 }
else if (iflag == 0) {
1714 printf(
"starting minimization\n");
1715 }
else if (iflag == -1) {
1716 printf(
"terminated after %d evaluations\n", nfev);
1720 for (
int i = 0; i < n_par; ++i) printf(
" %12g", par[i]);
1721 printf(
" => norm: %12g\n", lm_enorm(m_dat, fvec));
1724 printf(
" fitting data as follows:\n");
1725 for (
int i = 0; i < m_dat; ++i) {
1726 const double tx = (mydata->user_tx)[i];
1727 const double ty = (mydata->user_ty)[i];
1728 const double y = (mydata->user_y)[i];
1729 const double f = mydata->user_func(tx, ty, mydata->n_par, par);
1731 " tx[%2d]=%8g ty[%2d]=%8g y=%12g fit=%12g "
1733 i, tx, i, ty, y, f, y - f);
1744 control->maxcall = 100;
1745 control->epsilon = 1.e-10;
1746 control->stepbound = 100;
1747 control->ftol = 1.e-14;
1748 control->xtol = 1.e-14;
1749 control->gtol = 1.e-14;
1752void lm_minimize(
int m_dat,
int n_par,
double *par, lm_evaluate_ftype *evaluate,
1753 lm_print_ftype *printout,
void *data,
1755 std::vector<double> fvec(m_dat);
1756 std::vector<double> diag(n_par);
1757 std::vector<double> qtf(n_par);
1758 std::vector<double> fjac(n_par * m_dat);
1759 std::vector<double> wa1(n_par);
1760 std::vector<double> wa2(n_par);
1761 std::vector<double> wa3(n_par);
1762 std::vector<double> wa4(m_dat);
1763 std::vector<int> ipvt(n_par);
1771 lm_lmdif(m_dat, n_par, par, &fvec[0], control->ftol, control->xtol,
1772 control->gtol, control->maxcall * (n_par + 1), control->epsilon,
1773 &diag[0], 1, control->stepbound, &(control->info), &(control->nfev),
1774 &fjac[0], &ipvt[0], &qtf[0], &wa1[0], &wa2[0], &wa3[0], &wa4[0],
1775 evaluate, printout, data);
1777 (*printout)(n_par, par, m_dat, &fvec[0], data, -1, 0, control->nfev);
1778 control->fnorm = lm_enorm(m_dat, &fvec[0]);
1779 if (control->info < 0) control->info = 10;
1784const char *lm_infmsg[] = {
1785 "improper input parameters",
1786 "the relative error in the sum of squares is at most tol",
1787 "the relative error between x and the solution is at most tol",
1788 "both errors are at most tol",
1789 "fvec is orthogonal to the columns of the jacobian to machine precision",
1790 "number of calls to fcn has reached or exceeded 200*(n+1)",
1791 "ftol is too small. no further reduction in the sum of squares is possible",
1792 "xtol too small. no further improvement in approximate solution x possible",
1793 "gtol too small. no further improvement in approximate solution x possible",
1794 "not enough memory",
1795 "break requested within function evaluation"};
1797const char *lm_shortmsg[] = {
"invalid input",
"success (f)",
"success (p)",
1798 "success (f,p)",
"degenerate",
"call limit",
1799 "failed (f)",
"failed (p)",
"failed (o)",
1800 "no memory",
"user break"};
1813#define LM_MACHEP 1.2e-16
1814#define LM_DWARF 1.0e-38
1821#define LM_SQRT_DWARF 3.834e-20
1822#define LM_SQRT_GIANT 1.304e19
1824void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
1825 double *acnorm,
double *wa);
1826void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1827 double *x,
double *sdiag,
double *wa);
1828void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1829 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
1832#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
1833#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
1834#define SQR(x) (x) * (x)
1838void lm_lmdif(
int m,
int n,
double *x,
double *fvec,
double ftol,
double xtol,
1839 double gtol,
int maxfev,
double epsfcn,
double *diag,
int mode,
1840 double factor,
int *info,
int *nfev,
double *fjac,
int *ipvt,
1841 double *qtf,
double *wa1,
double *wa2,
double *wa3,
double *wa4,
1842 lm_evaluate_ftype *evaluate, lm_print_ftype *printout,
2024 if ((n <= 0) || (m < n) || (ftol < 0.) || (xtol < 0.) || (gtol < 0.) ||
2025 (maxfev <= 0) || (factor <= 0.)) {
2032 for (
int j = 0; j < n; j++)
2034 if (diag[j] <= 0.0) {
2047 (*evaluate)(x, m, fvec, data, info);
2048 (*printout)(n, x, m, fvec, data, 0, 0, ++(*nfev));
2049 if (*info < 0)
return;
2056 double fnorm = lm_enorm(m, fvec);
2057 const double eps = sqrt(MAX(
2063 printf(
"lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n", iter, *nfev,
2069 for (
int j = 0; j < n; j++) {
2070 const double temp = x[j];
2071 const double step = eps * fabs(temp) == 0.0 ? eps : eps * fabs(temp);
2075 (*evaluate)(x, m, wa4, data, info);
2076 (*printout)(n, x, m, wa4, data, 1, iter, ++(*nfev));
2077 if (*info < 0)
return;
2079 for (
int i = 0; i < m; i++) fjac[j * m + i] = (wa4[i] - fvec[i]) / step;
2083 for (i = 0; i < m; i++) {
2084 for (j = 0; j < n; j++) printf(
"%.5e ", y[j * m + i]);
2091 lm_qrfac(m, n, fjac, 1, ipvt, wa1, wa2, wa3);
2100 for (
int j = 0; j < n; j++) {
2102 if (wa2[j] == 0.) diag[j] = 1.;
2109 for (
int j = 0; j < n; j++) wa3[j] = diag[j] * x[j];
2111 xnorm = lm_enorm(n, wa3);
2112 delta = factor * xnorm;
2113 if (delta == 0.) delta = factor;
2118 for (
int i = 0; i < m; i++) wa4[i] = fvec[i];
2120 for (
int j = 0; j < n; j++) {
2121 double temp3 = fjac[j * m + j];
2124 for (
int i = j; i < m; i++) sum += fjac[j * m + i] * wa4[i];
2125 double temp = -sum / temp3;
2126 for (
int i = j; i < m; i++) wa4[i] += fjac[j * m + i] * temp;
2128 fjac[j * m + j] = wa1[j];
2136 for (
int j = 0; j < n; j++) {
2137 if (wa2[ipvt[j]] == 0)
continue;
2140 for (
int i = 0; i <= j; i++) sum += fjac[j * m + i] * qtf[i] / fnorm;
2141 gnorm = MAX(gnorm, fabs(sum / wa2[ipvt[j]]));
2145 if (gnorm <= gtol) {
2153 for (
int j = 0; j < n; j++) diag[j] = MAX(diag[j], wa2[j]);
2157 const double kP0001 = 1.0e-4;
2161 printf(
"lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev);
2166 lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &par, wa1, wa2, wa3, wa4);
2170 for (
int j = 0; j < n; j++) {
2172 wa2[j] = x[j] + wa1[j];
2173 wa3[j] = diag[j] * wa1[j];
2175 double pnorm = lm_enorm(n, wa3);
2180 delta = MIN(delta, pnorm);
2185 (*evaluate)(wa2, m, wa4, data, info);
2186 (*printout)(n, x, m, wa4, data, 2, iter, ++(*nfev));
2187 if (*info < 0)
return;
2189 double fnorm1 = lm_enorm(m, wa4);
2192 "lmdif/ pnorm %.10e fnorm1 %.10e fnorm %.10e"
2193 " delta=%.10e par=%.10e\n",
2194 pnorm, fnorm1, fnorm, delta, par);
2198 const double kP1 = 0.1;
2199 const double actred = kP1 * fnorm1 < fnorm ? 1 - SQR(fnorm1 / fnorm) : -1;
2204 for (
int j = 0; j < n; j++) {
2206 for (
int i = 0; i <= j; i++) wa3[i] += fjac[j * m + i] * wa1[ipvt[j]];
2208 const double temp1 = lm_enorm(n, wa3) / fnorm;
2209 const double temp2 = sqrt(par) * pnorm / fnorm;
2210 const double prered = SQR(temp1) + 2 * SQR(temp2);
2211 const double dirder = -(SQR(temp1) + SQR(temp2));
2215 ratio = prered != 0 ? actred / prered : 0.0;
2218 "lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
2219 " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
2220 actred, prered, prered != 0 ? ratio : 0., SQR(temp1), SQR(temp2),
2225 const double kP5 = 0.5;
2226 const double kP25 = 0.25;
2227 const double kP75 = 0.75;
2229 if (ratio <= kP25) {
2231 actred >= 0.0 ? kP5 : kP5 * dirder / (dirder + kP5 * actred);
2232 if (kP1 * fnorm1 >= fnorm || temp < kP1) temp = kP1;
2233 delta = temp * MIN(delta, pnorm / kP1);
2235 }
else if (par == 0. || ratio >= kP75) {
2236 delta = pnorm / kP5;
2241 if (ratio >= kP0001) {
2244 for (
int j = 0; j < n; j++) {
2246 wa2[j] = diag[j] * x[j];
2248 for (
int i = 0; i < m; i++) fvec[i] = wa4[i];
2249 xnorm = lm_enorm(n, wa2);
2255 printf(
"ATTN: iteration considered unsuccessful\n");
2262 if (fabs(actred) <= ftol && prered <= ftol && kP5 * ratio <= 1) *info = 1;
2263 if (delta <= xtol * xnorm) *info += 2;
2264 if (*info != 0)
return;
2268 if (*nfev >= maxfev) *info = 5;
2269 if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && kP5 * ratio <= 1)
2271 if (delta <= LM_MACHEP * xnorm) *info = 7;
2272 if (gnorm <= LM_MACHEP) *info = 8;
2273 if (*info != 0)
return;
2277 }
while (ratio < kP0001);
2284void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2285 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
2372 for (
int j = 0; j < n; j++) {
2374 if (r[j * ldr + j] == 0 && nsing == n) nsing = j;
2375 if (nsing < n) wa1[j] = 0;
2378 printf(
"nsing %d ", nsing);
2380 for (
int j = nsing - 1; j >= 0; j--) {
2381 wa1[j] = wa1[j] / r[j + ldr * j];
2382 const double temp = wa1[j];
2383 for (
int i = 0; i < j; i++) wa1[i] -= r[j * ldr + i] * temp;
2386 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa1[j];
2393 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2395 double dxnorm = lm_enorm(n, wa2);
2396 double fp = dxnorm - delta;
2397 const double kP1 = 0.1;
2398 if (fp <= kP1 * delta) {
2400 printf(
"lmpar/ terminate (fp<delta/10\n");
2412 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2414 for (
int j = 0; j < n; j++) {
2416 for (
int i = 0; i < j; i++) sum += r[j * ldr + i] * wa1[i];
2417 wa1[j] = (wa1[j] - sum) / r[j + ldr * j];
2419 const double temp = lm_enorm(n, wa1);
2420 parl = fp / delta / temp / temp;
2425 for (
int j = 0; j < n; j++) {
2427 for (
int i = 0; i <= j; i++) sum += r[j * ldr + i] * qtb[i];
2428 wa1[j] = sum / diag[ipvt[j]];
2430 const double gnorm = lm_enorm(n, wa1);
2432 gnorm / delta == 0.0 ? LM_DWARF / MIN(delta, kP1) : gnorm / delta;
2437 *par = MAX(*par, parl);
2438 *par = MIN(*par, paru);
2439 if (*par == 0.) *par = gnorm / dxnorm;
2441 printf(
"lmpar/ parl %.4e par %.4e paru %.4e\n", parl, *par, paru);
2448 const double kP001 = 0.001;
2449 if (*par == 0.) *par = MAX(LM_DWARF, kP001 * paru);
2450 double temp = sqrt(*par);
2451 for (
int j = 0; j < n; j++) wa1[j] = temp * diag[j];
2452 lm_qrsolv(n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2);
2453 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2454 dxnorm = lm_enorm(n, wa2);
2455 const double fp_old = fp;
2456 fp = dxnorm - delta;
2462 if (fabs(fp) <= kP1 * delta ||
2463 (parl == 0. && fp <= fp_old && fp_old < 0.) || iter == 10)
2468 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2470 for (
int j = 0; j < n; j++) {
2471 wa1[j] = wa1[j] / sdiag[j];
2472 for (
int i = j + 1; i < n; i++) wa1[i] -= r[j * ldr + i] * wa1[j];
2474 temp = lm_enorm(n, wa1);
2475 double parc = fp / delta / temp / temp;
2480 parl = MAX(parl, *par);
2482 paru = MIN(paru, *par);
2487 *par = MAX(parl, *par + parc);
2491void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
2492 double *acnorm,
double *wa) {
2548 for (
int j = 0; j < n; j++) {
2549 acnorm[j] = lm_enorm(m, &a[j * m]);
2550 rdiag[j] = acnorm[j];
2552 if (pivot) ipvt[j] = j;
2560 const int minmn = MIN(m, n);
2561 for (
int j = 0; j < minmn; j++) {
2563 if (!pivot)
goto pivot_ok;
2567 for (k = j + 1; k < n; k++)
2568 if (rdiag[k] > rdiag[kmax]) kmax = k;
2569 if (kmax == j)
goto pivot_ok;
2571 for (
int i = 0; i < m; i++) {
2572 std::swap(a[j * m + i], a[kmax * m + i]);
2577 rdiag[kmax] = rdiag[j];
2579 std::swap(ipvt[j], ipvt[kmax]);
2589 double ajnorm = lm_enorm(m - j, &a[j * m + j]);
2595 if (a[j * m + j] < 0.) ajnorm = -ajnorm;
2596 for (
int i = j; i < m; i++) a[j * m + i] /= ajnorm;
2602 for (k = j + 1; k < n; k++) {
2605 for (
int i = j; i < m; i++) sum += a[j * m + i] * a[k * m + i];
2607 double temp = sum / a[j + m * j];
2609 for (
int i = j; i < m; i++) a[k * m + i] -= temp * a[j * m + i];
2611 if (pivot && rdiag[k] != 0.) {
2612 temp = a[m * k + j] / rdiag[k];
2613 temp = MAX(0., 1 - temp * temp);
2614 rdiag[k] *= sqrt(temp);
2615 temp = rdiag[k] / wa[k];
2616 const double kP05 = 0.05;
2617 if (kP05 * SQR(temp) <= LM_MACHEP) {
2618 rdiag[k] = lm_enorm(m - j - 1, &a[m * k + j + 1]);
2628void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2629 double *x,
double *sdiag,
double *wa) {
2697 for (
int j = 0; j < n; j++) {
2698 for (
int i = j; i < n; i++) r[j * ldr + i] = r[i * ldr + j];
2699 x[j] = r[j * ldr + j];
2708 for (
int j = 0; j < n; j++) {
2714 if (diag[ipvt[j]] == 0.)
goto L90;
2715 for (
int k = j; k < n; k++) sdiag[k] = 0.;
2716 sdiag[j] = diag[ipvt[j]];
2722 for (
int k = j; k < n; k++) {
2723 const double p25 = 0.25;
2724 const double p5 = 0.5;
2729 if (sdiag[k] == 0.)
continue;
2730 const int kk = k + ldr * k;
2733 if (fabs(r[kk]) < fabs(sdiag[k])) {
2734 const double cotan = r[kk] / sdiag[k];
2735 sin = p5 / sqrt(p25 + p25 * SQR(cotan));
2738 const double tan = sdiag[k] / r[kk];
2739 cos = p5 / sqrt(p25 + p25 * SQR(tan));
2746 r[kk] = cos * r[kk] + sin * sdiag[k];
2747 double temp = cos * wa[k] + sin * qtbpj;
2748 qtbpj = -sin * wa[k] + cos * qtbpj;
2753 for (
int i = k + 1; i < n; i++) {
2754 temp = cos * r[k * ldr + i] + sin * sdiag[i];
2755 sdiag[i] = -sin * r[k * ldr + i] + cos * sdiag[i];
2756 r[k * ldr + i] = temp;
2764 sdiag[j] = r[j * ldr + j];
2765 r[j * ldr + j] = x[j];
2772 for (
int j = 0; j < n; j++) {
2773 if (sdiag[j] == 0. && nsing == n) nsing = j;
2774 if (nsing < n) wa[j] = 0;
2777 for (
int j = nsing - 1; j >= 0; j--) {
2779 for (
int i = j + 1; i < nsing; i++) sum += r[j * ldr + i] * wa[i];
2780 wa[j] = (wa[j] - sum) / sdiag[j];
2785 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa[j];
2788double lm_enorm(
int n,
double *x) {
2810 double s1 = 0.0, s2 = 0.0, s3 = 0.0;
2811 double x1max = 0.0, x3max = 0.0;
2812 const double agiant = LM_SQRT_GIANT / ((double)n);
2814 for (
int i = 0; i < n; i++) {
2815 double xabs = fabs(x[i]);
2816 if (xabs > LM_SQRT_DWARF && xabs < agiant) {
2822 if (xabs > LM_SQRT_DWARF) {
2825 s1 = 1 + s1 * SQR(x1max / xabs);
2828 s1 += SQR(xabs / x1max);
2834 s3 = 1 + s3 * SQR(x3max / xabs);
2838 s3 += SQR(xabs / x3max);
2845 if (s1 != 0)
return x1max * sqrt(s1 + (s2 / x1max) / x1max);
2847 if (s2 >= x3max)
return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
2848 return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
2851 return x3max * sqrt(s3);
2854double lat_gc_crosses_meridian(
double lat1,
double lon1,
double lat2,
2855 double lon2,
double lon) {
2861 double dlon = lon * DEGREE;
2862 double dlat1 = lat1 * DEGREE;
2863 double dlat2 = lat2 * DEGREE;
2864 double dlon1 = lon1 * DEGREE;
2865 double dlon2 = lon2 * DEGREE;
2867 return RADIAN * atan((sin(dlat1) * cos(dlat2) * sin(dlon - dlon2) -
2868 sin(dlat2) * cos(dlat1) * sin(dlon - dlon1)) /
2869 (cos(dlat1) * cos(dlat2) * sin(dlon1 - dlon2)));
2872double lat_rl_crosses_meridian(
double lat1,
double lon1,
double lat2,
2873 double lon2,
double lon) {
2881 DistanceBearingMercator(lat2, lon2, lat1, lon1, &brg, NULL);
2884 toSM(lat1, lon1, 0., lon, &x1, &y1);
2885 toSM(lat1, lon, 0., lon, &x, &y1);
2890 }
else if (brg >= 180.) {
2893 }
else if (brg >= 90.) {
2900 double ydelta = fabs(x1) * tan(brg * DEGREE);
2902 double crosslat, crosslon;
2903 fromSM(x, y1 + dir * ydelta, 0., lon, &crosslat, &crosslon);
Extern C linked utilities.
double my_fit_function(double tx, double ty, int n_par, double *p)
================================================================================= Customized section ...
void lm_initialize_control(lm_control_type *control)
=================================================================================
Structure containing georeferencing information for transforming between geographic and projected/pix...
double lonmin
Minimum longitude in reference data.
int order
Polynomial order for the transformation (1, 2, or 3)
int count
Number of reference points used.
double lonmax
Maximum longitude in reference data.
int txmin
Minimum x value in target space.
double * pwx
Polynomial coefficients for pixel-to-world longitude transformation.
double * tx
Array of x-coordinates in target (typically pixel) space.
double * wpx
Polynomial coefficients for world-to-pixel x transformation.
double * lat
Array of latitudes corresponding to reference points.
double * lon
Array of longitudes corresponding to reference points.
int tymin
Minimum y value in target space.
double * ty
Array of y-coordinates in target (typically pixel) space.
int tymax
Maximum y value in target space.
double latmin
Minimum latitude in reference data.
int txmax
Maximum x value in target space.
double latmax
Maximum latitude in reference data.
double * wpy
Polynomial coefficients for world-to-pixel y transformation.
double * pwy
Polynomial coefficients for pixel-to-world latitude transformation.