41#include "model/georef.h"
42#include "model/cutil.h"
45#define snprintf mysnprintf
49static const long long lNaN = 0xfff8000000000000;
50#define NAN (*(double *)&lNaN)
69struct DATUM const gDatum[] = {
71 {
"Adindan", 5, -162, -12, 206},
72 {
"Afgooye", 15, -43, -163, 45},
73 {
"Ain el Abd 1970", 14, -150, -251, -2},
74 {
"Anna 1 Astro 1965", 2, -491, -22, 435},
75 {
"Arc 1950", 5, -143, -90, -294},
76 {
"Arc 1960", 5, -160, -8, -300},
77 {
"Ascension Island 58", 14, -207, 107, 52},
78 {
"Astro B4 Sorol Atoll", 14, 114, -116, -333},
79 {
"Astro Beacon E ", 14, 145, 75, -272},
80 {
"Astro DOS 71/4", 14, -320, 550, -494},
81 {
"Astronomic Stn 52", 14, 124, -234, -25},
82 {
"Australian Geod 66", 2, -133, -48, 148},
83 {
"Australian Geod 84", 2, -134, -48, 149},
84 {
"Bellevue (IGN)", 14, -127, -769, 472},
85 {
"Bermuda 1957", 4, -73, 213, 296},
86 {
"Bogota Observatory", 14, 307, 304, -318},
87 {
"Campo Inchauspe", 14, -148, 136, 90},
88 {
"Canton Astro 1966", 14, 298, -304, -375},
89 {
"Cape", 5, -136, -108, -292},
90 {
"Cape Canaveral", 4, -2, 150, 181},
91 {
"Carthage", 5, -263, 6, 431},
92 {
"CH-1903", 3, 674, 15, 405},
93 {
"Chatham 1971", 14, 175, -38, 113},
94 {
"Chua Astro", 14, -134, 229, -29},
95 {
"Corrego Alegre", 14, -206, 172, -6},
96 {
"Djakarta (Batavia)", 3, -377, 681, -50},
97 {
"DOS 1968", 14, 230, -199, -752},
98 {
"Easter Island 1967", 14, 211, 147, 111},
99 {
"European 1950", 14, -87, -98, -121},
100 {
"European 1979", 14, -86, -98, -119},
101 {
"Finland Hayford", 14, -78, -231, -97},
102 {
"Gandajika Base", 14, -133, -321, 50},
103 {
"Geodetic Datum 49", 14, 84, -22, 209},
104 {
"Guam 1963", 4, -100, -248, 259},
105 {
"GUX 1 Astro", 14, 252, -209, -751},
106 {
"Hermannskogel Datum", 3, 682, -203, 480},
107 {
"Hjorsey 1955", 14, -73, 46, -86},
108 {
"Hong Kong 1963", 14, -156, -271, -189},
109 {
"Indian Bangladesh", 6, 289, 734, 257},
110 {
"Indian Thailand", 6, 214, 836, 303},
111 {
"Ireland 1965", 1, 506, -122, 611},
112 {
"ISTS 073 Astro 69", 14, 208, -435, -229},
113 {
"Johnston Island", 14, 191, -77, -204},
114 {
"Kandawala", 6, -97, 787, 86},
115 {
"Kerguelen Island", 14, 145, -187, 103},
116 {
"Kertau 1948", 7, -11, 851, 5},
117 {
"L.C. 5 Astro", 4, 42, 124, 147},
118 {
"Liberia 1964", 5, -90, 40, 88},
119 {
"Luzon Mindanao", 4, -133, -79, -72},
120 {
"Luzon Philippines", 4, -133, -77, -51},
121 {
"Mahe 1971", 5, 41, -220, -134},
122 {
"Marco Astro", 14, -289, -124, 60},
123 {
"Massawa", 3, 639, 405, 60},
124 {
"Merchich", 5, 31, 146, 47},
125 {
"Midway Astro 1961", 14, 912, -58, 1227},
126 {
"Minna", 5, -92, -93, 122},
127 {
"NAD27 Alaska", 4, -5, 135, 172},
128 {
"NAD27 Bahamas", 4, -4, 154, 178},
129 {
"NAD27 Canada", 4, -10, 158, 187},
130 {
"NAD27 Canal Zone", 4, 0, 125, 201},
131 {
"NAD27 Caribbean", 4, -7, 152, 178},
132 {
"NAD27 Central", 4, 0, 125, 194},
133 {
"NAD27 CONUS", 4, -8, 160, 176},
134 {
"NAD27 Cuba", 4, -9, 152, 178},
135 {
"NAD27 Greenland", 4, 11, 114, 195},
136 {
"NAD27 Mexico", 4, -12, 130, 190},
137 {
"NAD27 San Salvador", 4, 1, 140, 165},
138 {
"NAD83", 11, 0, 0, 0},
139 {
"Nahrwn Masirah Ilnd", 5, -247, -148, 369},
140 {
"Nahrwn Saudi Arbia", 5, -231, -196, 482},
141 {
"Nahrwn United Arab", 5, -249, -156, 381},
142 {
"Naparima BWI", 14, -2, 374, 172},
143 {
"Observatorio 1966", 14, -425, -169, 81},
144 {
"Old Egyptian", 12, -130, 110, -13},
145 {
"Old Hawaiian", 4, 61, -285, -181},
146 {
"Oman", 5, -346, -1, 224},
147 {
"Ord Srvy Grt Britn", 0, 375, -111, 431},
148 {
"Pico De Las Nieves", 14, -307, -92, 127},
149 {
"Pitcairn Astro 1967", 14, 185, 165, 42},
150 {
"Prov So Amrican 56", 14, -288, 175, -376},
151 {
"Prov So Chilean 63", 14, 16, 196, 93},
152 {
"Puerto Rico", 4, 11, 72, -101},
153 {
"Qatar National", 14, -128, -283, 22},
154 {
"Qornoq", 14, 164, 138, -189},
155 {
"Reunion", 14, 94, -948, -1262},
156 {
"Rome 1940", 14, -225, -65, 9},
157 {
"RT 90", 3, 498, -36, 568},
158 {
"Santo (DOS)", 14, 170, 42, 84},
159 {
"Sao Braz", 14, -203, 141, 53},
160 {
"Sapper Hill 1943", 14, -355, 16, 74},
161 {
"Schwarzeck", 21, 616, 97, -251},
162 {
"South American 69", 16, -57, 1, -41},
163 {
"South Asia", 8, 7, -10, -26},
164 {
"Southeast Base", 14, -499, -249, 314},
165 {
"Southwest Base", 14, -104, 167, -38},
166 {
"Timbalai 1948", 6, -689, 691, -46},
167 {
"Tokyo", 3, -128, 481, 664},
168 {
"Tristan Astro 1968", 14, -632, 438, -609},
169 {
"Viti Levu 1916", 5, 51, 391, -36},
170 {
"Wake-Eniwetok 60", 13, 101, 52, -39},
171 {
"WGS 72", 19, 0, 0, 5},
172 {
"WGS 84", 20, 0, 0, 0},
173 {
"Zanderij", 14, -265, 120, -358},
174 {
"WGS_84", 20, 0, 0, 0},
175 {
"WGS-84", 20, 0, 0, 0},
176 {
"EUROPEAN DATUM 1950", 14, -87, -98, -121},
177 {
"European 1950 (Norway Finland)", 14, -87, -98, -121},
178 {
"ED50", 14, -87, -98, -121},
179 {
"RT90 (Sweden)", 3, 498, -36, 568},
180 {
"Monte Mario 1940", 14, -104, -49, 10},
181 {
"Ord Surv of Gr Britain 1936", 0, 375, -111, 431},
182 {
"South American 1969", 16, -57, 1, -41},
183 {
"PULKOVO 1942 (2)", 15, 25, -141, -79},
184 {
"EUROPEAN DATUM", 14, -87, -98, -121},
185 {
"BERMUDA DATUM 1957", 4, -73, 213, 296},
186 {
"COA", 14, -206, 172, -6},
187 {
"COABR", 14, -206, 172, -6},
188 {
"Roma 1940", 14, -225, -65, 9},
189 {
"ITALIENISCHES LANDESNETZ", 14, -87, -98, -121},
190 {
"HERMANSKOGEL DATUM", 3, 682, -203, 480},
191 {
"AGD66", 2, -128, -52, 153},
192 {
"ED", 14, -87, -98, -121},
193 {
"EUROPEAN 1950 (SPAIN AND PORTUGAL)", 14, -87, -98, -121},
194 {
"ED-50", 14, -87, -98, -121},
195 {
"EUROPEAN", 14, -87, -98, -121},
196 {
"POTSDAM", 14, -87, -98, -121},
197 {
"GRACIOSA SW BASE DATUM", 14, -104, 167, -38},
198 {
"WGS 1984", 20, 0, 0, 0},
199 {
"WGS 1972", 19, 0, 0, 5},
205 {
"Airy 1830", 6377563.396, 299.3249646},
206 {
"Modified Airy", 6377340.189, 299.3249646},
207 {
"Australian National", 6378160.0, 298.25},
208 {
"Bessel 1841", 6377397.155, 299.1528128},
209 {
"Clarke 1866", 6378206.4, 294.9786982},
210 {
"Clarke 1880", 6378249.145, 293.465},
211 {
"Everest (India 1830)", 6377276.345, 300.8017},
212 {
"Everest (1948)", 6377304.063, 300.8017},
213 {
"Modified Fischer 1960", 6378155.0, 298.3},
214 {
"Everest (Pakistan)", 6377309.613, 300.8017},
215 {
"Indonesian 1974", 6378160.0, 298.247},
216 {
"GRS 80", 6378137.0, 298.257222101},
217 {
"Helmert 1906", 6378200.0, 298.3},
218 {
"Hough 1960", 6378270.0, 297.0},
219 {
"International 1924", 6378388.0, 297.0},
220 {
"Krassovsky 1940", 6378245.0, 298.3},
221 {
"South American 1969", 6378160.0, 298.25},
222 {
"Everest (Malaysia 1969)", 6377295.664, 300.8017},
223 {
"Everest (Sabah Sarawak)", 6377298.556, 300.8017},
224 {
"WGS 72", 6378135.0, 298.26},
225 {
"WGS 84", 6378137.0, 298.257223563},
226 {
"Bessel 1841 (Namibia)", 6377483.865, 299.1528128},
227 {
"Everest (India 1956)", 6377301.243, 300.8017},
228 {
"Struve 1860", 6378298.3, 294.73}
232short nDatums =
sizeof(gDatum) /
sizeof(
struct DATUM);
236void datumParams(
short datum,
double *a,
double *es) {
237 extern struct DATUM const gDatum[];
238 extern struct ELLIPSOID const gEllipsoid[];
240 if (datum < nDatums) {
241 double f = 1.0 / gEllipsoid[gDatum[datum].ellipsoid].invf;
242 if (es) *es = 2 * f - f * f;
243 if (a) *a = gEllipsoid[gDatum[datum].ellipsoid].a;
245 double f = 1.0 / 298.257223563;
246 if (es) *es = 2 * f - f * f;
247 if (a) *a = 6378137.0;
251static int datumNameCmp(
const char *n1,
const char *n2) {
257 else if (toupper(*n1) == toupper(*n2))
264static int isWGS84(
int i) {
267 if (i == DATUM_INDEX_WGS84)
return i;
269 if (gDatum[i].ellipsoid != gDatum[DATUM_INDEX_WGS84].ellipsoid)
return i;
271 if (gDatum[i].dx != gDatum[DATUM_INDEX_WGS84].dx)
return i;
273 if (gDatum[i].dy != gDatum[DATUM_INDEX_WGS84].dy)
return i;
275 if (gDatum[i].dz != gDatum[DATUM_INDEX_WGS84].dz)
return i;
277 return DATUM_INDEX_WGS84;
280int GetDatumIndex(
const char *str) {
282 while (i < (
int)nDatums) {
283 if (!datumNameCmp(str, gDatum[i].name)) {
294void toDMS(
double a,
char *bufp,
int bufplen) {
297 int n = (int)((a - (
int)a) * 36000.0);
300 sprintf(bufp,
"%d%02d'%02d.%01d\"", (
int)(neg ? -a : a), m, s / 10, s % 10);
307double fromDMS(
char *dms) {
310 char buf[20] = {
'\0'};
312 sscanf(dms,
"%d%[ ]%d%[ ']%lf%[ \"NSWEnswe]", &d, buf, &m, buf, &s, buf);
314 s = (double)(abs(d)) + ((
double)m + s / 60.0) / 60.0;
316 if (d >= 0 && strpbrk(buf,
"SWsw") == NULL)
return s;
325void todmm(
int flag,
double a,
char *bufp,
int bufplen) {
329 int m = (int)((a - (
int)a) * 60000.0);
332 snprintf(bufp, bufplen,
"%d %02d.%03d'", (
int)a, m / 1000, m % 1000);
335 snprintf(bufp, bufplen,
"%02d %02d.%03d %c", (
int)a, m / 1000, (m % 1000),
337 }
else if (flag == 2) {
338 snprintf(bufp, bufplen,
"%03d %02d.%03d %c", (
int)a, m / 1000, (m % 1000),
344void toDMM(
double a,
char *bufp,
int bufplen) {
345 todmm(0, a, bufp, bufplen);
354void toSM(
double lat,
double lon,
double lat0,
double lon0,
double *x,
360 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
361 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
364 const double z = WGS84_semimajor_axis_meters * mercator_k0;
366 *x = (xlon - lon0) * DEGREE * z;
369 const double s = sin(lat * DEGREE);
370 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
372 const double s0 = sin(lat0 * DEGREE);
373 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
377double toSMcache_y30(
double lat0) {
378 const double z = WGS84_semimajor_axis_meters * mercator_k0;
379 const double s0 = sin(lat0 * DEGREE);
380 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
384void toSMcache(
double lat,
double lon,
double y30,
double lon0,
double *x,
390 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
391 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
394 const double z = WGS84_semimajor_axis_meters * mercator_k0;
396 *x = (xlon - lon0) * DEGREE * z;
399 const double s = sin(lat * DEGREE);
400 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
405void fromSM(
double x,
double y,
double lat0,
double lon0,
double *lat,
407 const double z = WGS84_semimajor_axis_meters * mercator_k0;
420 const double s0 = sin(lat0 * DEGREE);
421 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * z;
423 *lat = (2.0 * atan(exp((y0 + y) / z)) - PI / 2.) / DEGREE;
426 *lon = lon0 + (x / (DEGREE * z));
429void fromSMR(
double x,
double y,
double lat0,
double lon0,
double axis_meters,
430 double *lat,
double *lon) {
431 const double s0 = sin(lat0 * DEGREE);
432 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * axis_meters;
434 *lat = (2.0 * atan(exp((y0 + y) / axis_meters)) - PI / 2.) / DEGREE;
437 *lon = lon0 + (x / (DEGREE * axis_meters));
440void toSM_ECC(
double lat,
double lon,
double lat0,
double lon0,
double *x,
442 const double f = 1.0 / WGSinvf;
443 const double e2 = 2 * f - f * f;
444 const double e = sqrt(e2);
446 const double z = WGS84_semimajor_axis_meters * mercator_k0;
448 *x = (lon - lon0) * DEGREE * z;
451 const double s = sin(lat * DEGREE);
454 const double s0 = sin(lat0 * DEGREE);
459 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
460 pow((1. - e * s0) / (1. + e * s0), e / 2.));
461 const double test = z * log(tan(PI / 4 + lat * DEGREE / 2) *
462 pow((1. - e * s) / (1. + e * s), e / 2.));
466void fromSM_ECC(
double x,
double y,
double lat0,
double lon0,
double *lat,
468 const double f = 1.0 / WGSinvf;
469 const double es = 2 * f - f * f;
470 const double e = sqrt(es);
472 const double z = WGS84_semimajor_axis_meters * mercator_k0;
474 *lon = lon0 + (x / (DEGREE * z));
476 const double s0 = sin(lat0 * DEGREE);
478 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
479 pow((1. - e * s0) / (1. + e * s0), e / 2.));
480 const double t = exp((y + falsen) / (z));
481 const double xi = (PI / 2.) - 2.0 * atan(t);
485 double esf = (es / 2. + (5 * es * es / 24.) + (es * es * es / 12.) +
486 (13.0 * es * es * es * es / 360.)) *
488 esf += ((7. * es * es / 48.) + (29. * es * es * es / 240.) +
489 (811. * es * es * es * es / 11520.)) *
491 esf += ((7. * es * es * es / 120.) + (81 * es * es * es * es / 1120.) +
492 (4279. * es * es * es * es / 161280.)) *
495 *lat = -(xi + esf) / DEGREE;
504void toPOLY(
double lat,
double lon,
double lat0,
double lon0,
double *x,
506 const double z = WGS84_semimajor_axis_meters * mercator_k0;
508 if (fabs((lat - lat0) * DEGREE) <= TOL) {
509 *x = (lon - lon0) * DEGREE * z;
513 const double E = (lon - lon0) * DEGREE * sin(lat * DEGREE);
514 const double cot = 1. / tan(lat * DEGREE);
516 *y = (lat * DEGREE) - (lat0 * DEGREE) + cot * (1. - cos(E));
532void fromPOLY(
double x,
double y,
double lat0,
double lon0,
double *lat,
534 const double z = WGS84_semimajor_axis_meters * mercator_k0;
536 double yp = y - (lat0 * DEGREE * z);
537 if (fabs(yp) <= TOL) {
538 *lon = lon0 + (x / (DEGREE * z));
542 const double xp = x / z;
545 const double B = (xp * xp) + (yp * yp);
549 double tp = tan(lat3);
550 dphi = (yp * (lat3 * tp + 1.) - lat3 - .5 * (lat3 * lat3 + B) * tp) /
551 ((lat3 - yp) / tp - 1.);
553 }
while (fabs(dphi) > CONV && --i);
558 *lon = asin(xp * tan(lat3)) / sin(lat3);
562 *lat = lat3 / DEGREE;
578void toTM(
float lat,
float lon,
float lat0,
float lon0,
double *x,
double *y) {
580 const double f = 1.0 / WGSinvf;
581 const double a = WGS84_semimajor_axis_meters;
582 const double k0 = 1.;
584 const double eccSquared = 2 * f - f * f;
585 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
586 const double LatRad = lat * DEGREE;
587 const double LongOriginRad = lon0 * DEGREE;
588 const double LongRad = lon * DEGREE;
590 const double N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad));
591 const double T = tan(LatRad) * tan(LatRad);
592 const double C = eccPrimeSquared * cos(LatRad) * cos(LatRad);
593 const double A = cos(LatRad) * (LongRad - LongOriginRad);
597 ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
598 5 * eccSquared * eccSquared * eccSquared / 256) *
600 (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 +
601 45 * eccSquared * eccSquared * eccSquared / 1024) *
603 (15 * eccSquared * eccSquared / 256 +
604 45 * eccSquared * eccSquared * eccSquared / 1024) *
606 (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad));
609 (A + (1 - T + C) * A * A * A / 6 +
610 (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A *
615 (MM + N * tan(LatRad) *
616 (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
617 (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A *
618 A * A * A * A * A / 720)));
631void fromTM(
double x,
double y,
double lat0,
double lon0,
double *lat,
633 const double rad2deg = 1. / DEGREE;
636 const double f = 1.0 / WGSinvf;
637 const double a = WGS84_semimajor_axis_meters;
638 const double k0 = 1.;
640 const double eccSquared = 2 * f - f * f;
642 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
644 (1.0 - sqrt(1.0 - eccSquared)) / (1.0 + sqrt(1.0 - eccSquared));
646 const double MM = y / k0;
648 MM / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
649 5 * eccSquared * eccSquared * eccSquared / 256));
651 const double phi1Rad =
652 mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) +
653 (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) +
654 (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
656 const double N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad));
657 const double T1 = tan(phi1Rad) * tan(phi1Rad);
658 const double C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
659 const double R1 = a * (1 - eccSquared) /
660 pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5);
661 const double D = x / (N1 * k0);
664 (N1 * tan(phi1Rad) / R1) *
666 (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D *
668 (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared -
670 D * D * D * D * D * D / 720);
671 *lat = lat0 + (*lat * rad2deg);
673 *lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 +
674 (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared +
676 D * D * D * D * D / 120) /
678 *lon = lon0 + *lon * rad2deg;
686void cache_phi0(
double lat0,
double *sin_phi0,
double *cos_phi0) {
687 double phi0 = lat0 * DEGREE;
688 *sin_phi0 = sin(phi0);
689 *cos_phi0 = cos(phi0);
692void toORTHO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
693 double lon0,
double *x,
double *y) {
694 const double z = WGS84_semimajor_axis_meters * mercator_k0;
698 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
699 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
701 double theta = (xlon - lon0) * DEGREE;
702 double phi = lat * DEGREE;
703 double cos_phi = cos(phi);
705 double vy = sin(phi), vz = cos(theta) * cos_phi;
707 if (vy * sin_phi0 + vz * cos_phi0 < 0) {
712 double vx = sin(theta) * cos_phi;
713 double vw = vy * cos_phi0 - vz * sin_phi0;
719void fromORTHO(
double x,
double y,
double lat0,
double lon0,
double *lat,
721 const double z = WGS84_semimajor_axis_meters * mercator_k0;
726 double phi0 = lat0 * DEGREE;
727 double d = 1 - vx * vx - vw * vw;
734 double sin_phi0 = sin(phi0), cos_phi0 = cos(phi0);
735 double vy = vw * cos_phi0 + sqrt(d) * sin_phi0;
736 double phi = asin(vy);
738 double vz = (vy * cos_phi0 - vw) / sin_phi0;
739 double theta = atan2(vx, vz);
742 *lon = theta / DEGREE + lon0;
745double toPOLARcache_e(
double lat0) {
746 double pole = lat0 > 0 ? 90 : -90;
747 return tan((pole - lat0) * DEGREE / 2);
750void toPOLAR(
double lat,
double lon,
double e,
double lat0,
double lon0,
751 double *x,
double *y) {
752 const double z = WGS84_semimajor_axis_meters * mercator_k0;
756 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
757 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
759 double theta = (xlon - lon0) * DEGREE;
760 double pole = lat0 > 0 ? 90 : -90;
762 double d = tan((pole - lat) * DEGREE / 2);
764 *x = fabs(d) * sin(theta) * z;
765 *y = (e - d * cos(theta)) * z;
768void fromPOLAR(
double x,
double y,
double lat0,
double lon0,
double *lat,
770 const double z = WGS84_semimajor_axis_meters * mercator_k0;
771 double pole = lat0 > 0 ? 90 : -90;
773 double e = tan((pole - lat0) * DEGREE / 2);
776 double yn = e - y / z;
777 double d = sqrt(xn * xn + yn * yn);
781 *lat = pole - atan(d) * 2 / DEGREE;
783 double theta = atan2(xn, yn);
784 *lon = theta / DEGREE + lon0;
787static inline void toSTEREO1(
double &u,
double &v,
double &w,
double lat,
788 double lon,
double sin_phi0,
double cos_phi0,
792 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
793 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
795 double theta = (xlon - lon0) * DEGREE, phi = lat * DEGREE;
796 double cos_phi = cos(phi), v0 = sin(phi), w0 = cos(theta) * cos_phi;
798 u = sin(theta) * cos_phi;
799 v = cos_phi0 * v0 - sin_phi0 * w0;
800 w = sin_phi0 * v0 + cos_phi0 * w0;
803static inline void fromSTEREO1(
double *lat,
double *lon,
double lat0,
804 double lon0,
double u,
double v,
double w) {
805 double phi0 = lat0 * DEGREE;
806 double v0 = sin(phi0) * w + cos(phi0) * v;
807 double w0 = cos(phi0) * w - sin(phi0) * v;
808 double phi = asin(v0);
809 double theta = atan2(u, w0);
812 *lon = theta / DEGREE + lon0;
815void toSTEREO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
816 double lon0,
double *x,
double *y) {
817 const double z = WGS84_semimajor_axis_meters * mercator_k0;
820 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
822 double t = 2 / (w + 1);
827void fromSTEREO(
double x,
double y,
double lat0,
double lon0,
double *lat,
829 const double z = WGS84_semimajor_axis_meters * mercator_k0;
833 double t = (x * x + y * y) / 4 + 1;
837 double w = 2 / t - 1;
839 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
842void toGNO(
double lat,
double lon,
double sin_phi0,
double cos_phi0,
843 double lon0,
double *x,
double *y) {
844 const double z = WGS84_semimajor_axis_meters * mercator_k0;
847 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
858void fromGNO(
double x,
double y,
double lat0,
double lon0,
double *lat,
860 const double z = WGS84_semimajor_axis_meters * mercator_k0;
864 double w = 1 / sqrt(x * x + y * y + 1);
868 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
871void toEQUIRECT(
double lat,
double lon,
double lat0,
double lon0,
double *x,
873 const double z = WGS84_semimajor_axis_meters * mercator_k0;
876 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
877 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
879 *x = (xlon - lon0) * DEGREE * z;
880 *y = (lat - lat0) * DEGREE * z;
883void fromEQUIRECT(
double x,
double y,
double lat0,
double lon0,
double *lat,
885 const double z = WGS84_semimajor_axis_meters * mercator_k0;
887 *lat = lat0 + (y / (DEGREE * z));
889 *lon = lon0 + (x / (DEGREE * z));
909void MolodenskyTransform(
double lat,
double lon,
double *to_lat,
double *to_lon,
910 int from_datum_index,
int to_datum_index) {
914 if (from_datum_index < nDatums) {
915 const double from_lat = lat * DEGREE;
916 const double from_lon = lon * DEGREE;
917 const double from_f =
919 gEllipsoid[gDatum[from_datum_index].ellipsoid].invf;
920 const double from_esq = 2 * from_f - from_f * from_f;
921 const double from_a =
922 gEllipsoid[gDatum[from_datum_index].ellipsoid].a;
923 const double dx = gDatum[from_datum_index].dx;
924 const double dy = gDatum[from_datum_index].dy;
925 const double dz = gDatum[from_datum_index].dz;
927 1.0 / gEllipsoid[gDatum[to_datum_index].ellipsoid].invf;
929 gEllipsoid[gDatum[to_datum_index].ellipsoid].a;
930 const double da = to_a - from_a;
931 const double df = to_f - from_f;
932 const double from_h = 0;
934 const double slat = sin(from_lat);
935 const double clat = cos(from_lat);
936 const double slon = sin(from_lon);
937 const double clon = cos(from_lon);
938 const double ssqlat = slat * slat;
939 const double adb = 1.0 / (1.0 - from_f);
941 const double rn = from_a / sqrt(1.0 - from_esq * ssqlat);
943 from_a * (1. - from_esq) / pow((1.0 - from_esq * ssqlat), 1.5);
945 dlat = (((((-dx * slat * clon - dy * slat * slon) + dz * clat) +
946 (da * ((rn * from_esq * slat * clat) / from_a))) +
947 (df * (rm * adb + rn / adb) * slat * clat))) /
950 dlon = (-dx * slon + dy * clon) / ((rn + from_h) * clat);
953 *to_lon = lon + dlon / DEGREE;
954 *to_lat = lat + dlat / DEGREE;
992#define HALFPI 1.5707963267948966
993#define SPI 3.14159265359
994#define TWOPI 6.2831853071795864769
995#define ONEPI 3.14159265358979323846
998double adjlon(
double lon) {
999 if (fabs(lon) <= SPI)
return (lon);
1001 lon -= TWOPI * floor(lon / TWOPI);
1015void ll_gc_ll(
double lat,
double lon,
double brg,
double dist,
double *dlat,
1017 double th1, costh1, sinth1, sina12, cosa12, M, N, c1, c2, D, P, s1;
1020 if ((brg == 90.) || (brg == 180.)) {
1028 double phi1, lam1, phi2, lam2;
1033 double es, onef, f, f4;
1036 phi1 = lat * DEGREE;
1037 lam1 = lon * DEGREE;
1038 al12 = brg * DEGREE;
1039 geod_S = dist * 1852.0;
1048 geod_a = WGS84_semimajor_axis_meters;
1051 onef = sqrt(1. - es);
1055 al12 = adjlon(al12);
1056 signS = fabs(al12) > HALFPI ? 1 : 0;
1057 th1 = ellipse ? atan(onef * tan(phi1)) : phi1;
1060 if ((merid = fabs(sina12 = sin(al12)) < MERI_TOL)) {
1062 cosa12 = fabs(al12) < HALFPI ? 1. : -1.;
1066 M = costh1 * sina12;
1068 N = costh1 * cosa12;
1078 c2 = f4 * (1. - M * M);
1079 D = (1. - c2) * (1. - c2 - c1 * M);
1080 P = (1. + .5 * c1 * M) * c2 / D;
1086 s1 = (fabs(M) >= 1.) ? 0. : acos(M);
1087 s1 = sinth1 / sin(s1);
1088 s1 = (fabs(s1) >= 1.) ? 0. : acos(s1);
1094 double d, sind, u, V, X, ds, cosds, sinds, ss, de;
1099 d = geod_S / (D * geod_a);
1103 X = c2 * c2 * (sind = sin(d)) * cos(d) * (2. * V * V - 1.);
1104 ds = d + X - 2. * P * V * (1. - 2. * P * cos(u)) * sind;
1107 ds = geod_S / geod_a;
1108 if (signS) ds = -ds;
1112 if (signS) sinds = -sinds;
1113 al21 = N * cosds - sinth1 * sinds;
1115 phi2 = atan(tan(HALFPI + s1 - ds) / onef);
1133 al21 = atan(M / al21);
1134 if (al21 > 0) al21 += PI;
1135 if (al12 < 0.) al21 -= PI;
1136 al21 = adjlon(al21);
1137 phi2 = atan(-(sinth1 * cosds + N * sinds) * sin(al21) /
1138 (ellipse ? onef * M : M));
1139 de = atan2(sinds * sina12, (costh1 * cosds - sinth1 * sinds * cosa12));
1142 de += c1 * ((1. - c2) * ds + c2 * sinds * cos(ss));
1144 de -= c1 * ((1. - c2) * ds - c2 * sinds * cos(ss));
1147 lam2 = adjlon(lam1 + de);
1150 *dlat = phi2 / DEGREE;
1151 *dlon = lam2 / DEGREE;
1154void ll_gc_ll_reverse(
double lat1,
double lon1,
double lat2,
double lon2,
1155 double *bearing,
double *dist) {
1158 if ((fabs(lon2 - lon1) < 0.1) && (fabs(lat2 - lat1) < 0.1)) {
1159 DistanceBearingMercator(lat2, lon2, lat1, lon1, bearing, dist);
1166 double phi1, lam1, phi2, lam2;
1171 double es, onef, f, f64, f2, f4;
1174 phi1 = lat1 * DEGREE;
1175 lam1 = lon1 * DEGREE;
1176 phi2 = lat2 * DEGREE;
1177 lam2 = lon2 * DEGREE;
1181 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm,
1182 cosdthm, sindthm, L, E, cosd, d, X, Y, T, sind, tandlammp, u, v, D, A,
1191 geod_a = WGS84_semimajor_axis_meters;
1194 onef = sqrt(1. - es);
1198 f64 = geod_f * geod_f / 64;
1201 th1 = atan(onef * tan(phi1));
1202 th2 = atan(onef * tan(phi2));
1207 thm = .5 * (th1 + th2);
1208 dthm = .5 * (th2 - th1);
1209 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1210 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1211 al12 = al21 = geod_S = 0.;
1212 if (bearing) *bearing = 0.;
1213 if (dist) *dist = 0.;
1216 sindlamm = sin(dlamm);
1219 cosdthm = cos(dthm);
1220 sindthm = sin(dthm);
1221 L = sindthm * sindthm +
1222 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1223 d = acos(cosd = 1 - L - L);
1227 Y = sinthm * cosdthm;
1228 Y *= (Y + Y) / (1. - L);
1229 T = sindthm * costhm;
1237 geod_S = geod_a * sind *
1238 (T - f4 * (T * X - Y) +
1239 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1242 tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X)) *
1243 (f2 * T + f64 * (32. * T - (20. * T - A) * X -
1247 geod_S = geod_a * d;
1248 tandlammp = tan(dlamm);
1250 u = atan2(sindthm, (tandlammp * costhm));
1251 v = atan2(cosdthm, (tandlammp * sinthm));
1252 al12 = adjlon(TWOPI + v - u);
1253 al21 = adjlon(TWOPI - v - u);
1254 if (al12 < 0) al12 += 2 * PI;
1255 if (bearing) *bearing = al12 / DEGREE;
1256 if (dist) *dist = geod_S / 1852.0;
1261void PositionBearingDistanceMercator(
double lat,
double lon,
double brg,
1262 double dist,
double *dlat,
double *dlon) {
1263 ll_gc_ll(lat, lon, brg, dist, dlat, dlon);
1266double DistLoxodrome(
double slat,
double slon,
double dlat,
double dlon) {
1268 60 * sqrt(pow(slat - dlat, 2) +
1269 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1271 if (slon * dlon < 0) {
1277 60 * sqrt(pow(slat - dlat, 2) +
1278 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1279 return (std::min)(dist, distrtw);
1294double DistGreatCircle(
double slat,
double slon,
double dlat,
double dlon) {
1296 d5 = DistLoxodrome(slat, slon, dlat, dlon);
1304 double phi1, lam1, phi2, lam2;
1309 double es, onef, f, f64, f4;
1311 phi1 = slat * DEGREE;
1312 lam1 = slon * DEGREE;
1313 phi2 = dlat * DEGREE;
1314 lam2 = dlon * DEGREE;
1318 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm, cosdthm,
1319 sindthm, L, E, cosd, d, X, Y, T, sind, D, A, B;
1328 geod_a = WGS84_semimajor_axis_meters;
1331 onef = sqrt(1. - es);
1335 f64 = geod_f * geod_f / 64;
1338 th1 = atan(onef * tan(phi1));
1339 th2 = atan(onef * tan(phi2));
1344 thm = .5 * (th1 + th2);
1345 dthm = .5 * (th2 - th1);
1346 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1347 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1350 sindlamm = sin(dlamm);
1353 cosdthm = cos(dthm);
1354 sindthm = sin(dthm);
1355 L = sindthm * sindthm +
1356 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1357 d = acos(cosd = 1 - L - L);
1362 Y = sinthm * cosdthm;
1363 Y *= (Y + Y) / (1. - L);
1364 T = sindthm * costhm;
1372 geod_S = geod_a * sind *
1373 (T - f4 * (T * X - Y) +
1374 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1381 geod_S = geod_a * d;
1390 d5 = geod_S / 1852.0;
1395void DistanceBearingMercator(
double lat1,
double lon1,
double lat0,
double lon0,
1396 double *brg,
double *dist) {
1398 double latm = (lat0 + lat1) / 2 * DEGREE;
1399 double delta_lat = (lat1 - lat0);
1400 double delta_lon = (lon1 - lon0);
1401 double ex_lat0, ex_lat1;
1402 double bearing, distance;
1404 if (delta_lon < -180) delta_lon += 360;
1405 if (delta_lon > 180) delta_lon -= 360;
1409 else if (fabs(delta_lat) != .0)
1410 bearing = atan(delta_lon * cos(latm) / delta_lat);
1414 distance = sqrt(pow(delta_lat, 2) + pow(delta_lon * cos(latm), 2));
1419 if (delta_lat != 0.) {
1420 ex_lat0 = 10800 / PI * log(tan(PI / 4 + lat0 * DEGREE / 2));
1421 ex_lat1 = 10800 / PI * log(tan(PI / 4 + lat1 * DEGREE / 2));
1422 bearing = atan(delta_lon * 60 / (ex_lat1 - ex_lat0));
1423 distance = fabs(delta_lat / cos(bearing));
1429 bearing = fabs(bearing);
1431 if (delta_lon < 0) bearing = 2 * PI - bearing;
1435 bearing = PI - bearing;
1437 bearing = PI + bearing;
1440 if (brg) *brg = bearing * RADIAN;
1441 if (dist) *dist = distance * 60;
1467double my_fit_function(
double tx,
double ty,
int n_par,
double *p) {
1468 double ret = p[0] + p[1] * tx;
1470 if (n_par > 2) ret += p[2] * ty;
1472 ret += p[3] * tx * tx;
1473 ret += p[4] * tx * ty;
1474 ret += p[5] * ty * ty;
1477 ret += p[6] * tx * tx * tx;
1478 ret += p[7] * tx * tx * ty;
1479 ret += p[8] * tx * ty * ty;
1480 ret += p[9] * ty * ty * ty;
1486int Georef_Calculate_Coefficients_Onedir(
int n_points,
int n_par,
double *tx,
1487 double *ty,
double *y,
double *p,
1488 double hintp0,
double hintp1,
1503 lm_initialize_control(&control);
1505 for (i = 0; i < 12; i++) p[i] = 0.;
1514 data.user_func = my_fit_function;
1519 data.print_flag = 0;
1523 lm_minimize(n_points, n_par, p, lm_evaluate_default, lm_print_default, &data,
1531 return control.info;
1534int Georef_Calculate_Coefficients(
struct GeoRef *cp,
int nlin_lon) {
1536 for (
int i = 0; i < 10; ++i)
1537 cp->pwx[i] = cp->pwy[i] = cp->wpx[i] = cp->wpy[i] = 0.0;
1541 switch (cp->order) {
1556 const int mp_lat = mp;
1559 const int mp_lon = nlin_lon ? 2 : mp;
1562 std::vector<double> pnull(cp->count, 1.0);
1567 int r1 = Georef_Calculate_Coefficients_Onedir(
1568 cp->count, mp_lon, cp->tx, cp->ty, cp->lon, cp->pwx,
1570 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1571 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1575 double *px = nlin_lon ? &pnull[0] : cp->tx;
1577 int r2 = Georef_Calculate_Coefficients_Onedir(
1578 cp->count, mp_lat, px, cp->ty, cp->lat, cp->pwy,
1580 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1581 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1586 int r3 = Georef_Calculate_Coefficients_Onedir(
1587 cp->count, mp_lon, cp->lon, cp->lat, cp->tx, cp->wpx,
1589 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1590 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1594 px = nlin_lon ? &pnull[0] : cp->lon;
1596 int r4 = Georef_Calculate_Coefficients_Onedir(
1597 cp->count, mp_lat, &pnull[0] , cp->lat, cp->ty, cp->wpy,
1599 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1600 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1602 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1609int Georef_Calculate_Coefficients_Proj(
struct GeoRef *cp) {
1614 cp->pwx[6] = cp->pwy[6] = cp->wpx[6] = cp->wpy[6] = 0.;
1615 cp->pwx[7] = cp->pwy[7] = cp->wpx[7] = cp->wpy[7] = 0.;
1616 cp->pwx[8] = cp->pwy[8] = cp->wpx[8] = cp->wpy[8] = 0.;
1617 cp->pwx[9] = cp->pwy[9] = cp->wpx[9] = cp->wpy[9] = 0.;
1618 cp->pwx[3] = cp->pwy[3] = cp->wpx[3] = cp->wpy[3] = 0.;
1619 cp->pwx[4] = cp->pwy[4] = cp->wpx[4] = cp->wpy[4] = 0.;
1620 cp->pwx[5] = cp->pwy[5] = cp->wpx[5] = cp->wpy[5] = 0.;
1621 cp->pwx[0] = cp->pwy[0] = cp->wpx[0] = cp->wpy[0] = 0.;
1622 cp->pwx[1] = cp->pwy[1] = cp->wpx[1] = cp->wpy[1] = 0.;
1623 cp->pwx[2] = cp->pwy[2] = cp->wpx[2] = cp->wpy[2] = 0.;
1630 r1 = Georef_Calculate_Coefficients_Onedir(
1631 cp->count, mp, cp->tx, cp->ty, cp->lon, cp->pwx,
1633 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1634 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1636 r2 = Georef_Calculate_Coefficients_Onedir(
1637 cp->count, mp, cp->tx, cp->ty, cp->lat, cp->pwy,
1639 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1640 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1645 r3 = Georef_Calculate_Coefficients_Onedir(
1646 cp->count, mp, cp->lon, cp->lat, cp->tx, cp->wpx,
1648 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1649 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1651 r4 = Georef_Calculate_Coefficients_Onedir(
1652 cp->count, mp, cp->lon, cp->lat, cp->ty, cp->wpy,
1654 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1655 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1657 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1670void lm_evaluate_default(
double *par,
int m_dat,
double *fvec,
void *data,
1690 for (
int i = 0; i < m_dat; i++) {
1691 fvec[i] = mydata->user_y[i] - mydata->user_func(mydata->user_tx[i],
1693 mydata->n_par, par);
1699void lm_print_default(
int n_par,
double *par,
int m_dat,
double *fvec,
1700 void *data,
int iflag,
int iter,
int nfev)
1711 if (mydata->print_flag) {
1713 printf(
"trying step in gradient direction\n");
1714 }
else if (iflag == 1) {
1715 printf(
"determining gradient (iteration %d)\n", iter);
1716 }
else if (iflag == 0) {
1717 printf(
"starting minimization\n");
1718 }
else if (iflag == -1) {
1719 printf(
"terminated after %d evaluations\n", nfev);
1723 for (
int i = 0; i < n_par; ++i) printf(
" %12g", par[i]);
1724 printf(
" => norm: %12g\n", lm_enorm(m_dat, fvec));
1727 printf(
" fitting data as follows:\n");
1728 for (
int i = 0; i < m_dat; ++i) {
1729 const double tx = (mydata->user_tx)[i];
1730 const double ty = (mydata->user_ty)[i];
1731 const double y = (mydata->user_y)[i];
1732 const double f = mydata->user_func(tx, ty, mydata->n_par, par);
1734 " tx[%2d]=%8g ty[%2d]=%8g y=%12g fit=%12g "
1736 i, tx, i, ty, y, f, y - f);
1747 control->maxcall = 100;
1748 control->epsilon = 1.e-10;
1749 control->stepbound = 100;
1750 control->ftol = 1.e-14;
1751 control->xtol = 1.e-14;
1752 control->gtol = 1.e-14;
1755void lm_minimize(
int m_dat,
int n_par,
double *par, lm_evaluate_ftype *evaluate,
1756 lm_print_ftype *printout,
void *data,
1758 std::vector<double> fvec(m_dat);
1759 std::vector<double> diag(n_par);
1760 std::vector<double> qtf(n_par);
1761 std::vector<double> fjac(n_par * m_dat);
1762 std::vector<double> wa1(n_par);
1763 std::vector<double> wa2(n_par);
1764 std::vector<double> wa3(n_par);
1765 std::vector<double> wa4(m_dat);
1766 std::vector<int> ipvt(n_par);
1774 lm_lmdif(m_dat, n_par, par, &fvec[0], control->ftol, control->xtol,
1775 control->gtol, control->maxcall * (n_par + 1), control->epsilon,
1776 &diag[0], 1, control->stepbound, &(control->info), &(control->nfev),
1777 &fjac[0], &ipvt[0], &qtf[0], &wa1[0], &wa2[0], &wa3[0], &wa4[0],
1778 evaluate, printout, data);
1780 (*printout)(n_par, par, m_dat, &fvec[0], data, -1, 0, control->nfev);
1781 control->fnorm = lm_enorm(m_dat, &fvec[0]);
1782 if (control->info < 0) control->info = 10;
1787const char *lm_infmsg[] = {
1788 "improper input parameters",
1789 "the relative error in the sum of squares is at most tol",
1790 "the relative error between x and the solution is at most tol",
1791 "both errors are at most tol",
1792 "fvec is orthogonal to the columns of the jacobian to machine precision",
1793 "number of calls to fcn has reached or exceeded 200*(n+1)",
1794 "ftol is too small. no further reduction in the sum of squares is possible",
1795 "xtol too small. no further improvement in approximate solution x possible",
1796 "gtol too small. no further improvement in approximate solution x possible",
1797 "not enough memory",
1798 "break requested within function evaluation"};
1800const char *lm_shortmsg[] = {
"invalid input",
"success (f)",
"success (p)",
1801 "success (f,p)",
"degenerate",
"call limit",
1802 "failed (f)",
"failed (p)",
"failed (o)",
1803 "no memory",
"user break"};
1816#define LM_MACHEP 1.2e-16
1817#define LM_DWARF 1.0e-38
1824#define LM_SQRT_DWARF 3.834e-20
1825#define LM_SQRT_GIANT 1.304e19
1827void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
1828 double *acnorm,
double *wa);
1829void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1830 double *x,
double *sdiag,
double *wa);
1831void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1832 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
1835#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
1836#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
1837#define SQR(x) (x) * (x)
1841void lm_lmdif(
int m,
int n,
double *x,
double *fvec,
double ftol,
double xtol,
1842 double gtol,
int maxfev,
double epsfcn,
double *diag,
int mode,
1843 double factor,
int *info,
int *nfev,
double *fjac,
int *ipvt,
1844 double *qtf,
double *wa1,
double *wa2,
double *wa3,
double *wa4,
1845 lm_evaluate_ftype *evaluate, lm_print_ftype *printout,
2027 if ((n <= 0) || (m < n) || (ftol < 0.) || (xtol < 0.) || (gtol < 0.) ||
2028 (maxfev <= 0) || (factor <= 0.)) {
2035 for (
int j = 0; j < n; j++)
2037 if (diag[j] <= 0.0) {
2050 (*evaluate)(x, m, fvec, data, info);
2051 (*printout)(n, x, m, fvec, data, 0, 0, ++(*nfev));
2052 if (*info < 0)
return;
2059 double fnorm = lm_enorm(m, fvec);
2060 const double eps = sqrt(MAX(
2066 printf(
"lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n", iter, *nfev,
2072 for (
int j = 0; j < n; j++) {
2073 const double temp = x[j];
2074 const double step = eps * fabs(temp) == 0.0 ? eps : eps * fabs(temp);
2078 (*evaluate)(x, m, wa4, data, info);
2079 (*printout)(n, x, m, wa4, data, 1, iter, ++(*nfev));
2080 if (*info < 0)
return;
2082 for (
int i = 0; i < m; i++) fjac[j * m + i] = (wa4[i] - fvec[i]) / step;
2086 for (i = 0; i < m; i++) {
2087 for (j = 0; j < n; j++) printf(
"%.5e ", y[j * m + i]);
2094 lm_qrfac(m, n, fjac, 1, ipvt, wa1, wa2, wa3);
2103 for (
int j = 0; j < n; j++) {
2105 if (wa2[j] == 0.) diag[j] = 1.;
2112 for (
int j = 0; j < n; j++) wa3[j] = diag[j] * x[j];
2114 xnorm = lm_enorm(n, wa3);
2115 delta = factor * xnorm;
2116 if (delta == 0.) delta = factor;
2121 for (
int i = 0; i < m; i++) wa4[i] = fvec[i];
2123 for (
int j = 0; j < n; j++) {
2124 double temp3 = fjac[j * m + j];
2127 for (
int i = j; i < m; i++) sum += fjac[j * m + i] * wa4[i];
2128 double temp = -sum / temp3;
2129 for (
int i = j; i < m; i++) wa4[i] += fjac[j * m + i] * temp;
2131 fjac[j * m + j] = wa1[j];
2139 for (
int j = 0; j < n; j++) {
2140 if (wa2[ipvt[j]] == 0)
continue;
2143 for (
int i = 0; i <= j; i++) sum += fjac[j * m + i] * qtf[i] / fnorm;
2144 gnorm = MAX(gnorm, fabs(sum / wa2[ipvt[j]]));
2148 if (gnorm <= gtol) {
2156 for (
int j = 0; j < n; j++) diag[j] = MAX(diag[j], wa2[j]);
2160 const double kP0001 = 1.0e-4;
2164 printf(
"lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev);
2169 lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &par, wa1, wa2, wa3, wa4);
2173 for (
int j = 0; j < n; j++) {
2175 wa2[j] = x[j] + wa1[j];
2176 wa3[j] = diag[j] * wa1[j];
2178 double pnorm = lm_enorm(n, wa3);
2183 delta = MIN(delta, pnorm);
2188 (*evaluate)(wa2, m, wa4, data, info);
2189 (*printout)(n, x, m, wa4, data, 2, iter, ++(*nfev));
2190 if (*info < 0)
return;
2192 double fnorm1 = lm_enorm(m, wa4);
2195 "lmdif/ pnorm %.10e fnorm1 %.10e fnorm %.10e"
2196 " delta=%.10e par=%.10e\n",
2197 pnorm, fnorm1, fnorm, delta, par);
2201 const double kP1 = 0.1;
2202 const double actred = kP1 * fnorm1 < fnorm ? 1 - SQR(fnorm1 / fnorm) : -1;
2207 for (
int j = 0; j < n; j++) {
2209 for (
int i = 0; i <= j; i++) wa3[i] += fjac[j * m + i] * wa1[ipvt[j]];
2211 const double temp1 = lm_enorm(n, wa3) / fnorm;
2212 const double temp2 = sqrt(par) * pnorm / fnorm;
2213 const double prered = SQR(temp1) + 2 * SQR(temp2);
2214 const double dirder = -(SQR(temp1) + SQR(temp2));
2218 ratio = prered != 0 ? actred / prered : 0.0;
2221 "lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
2222 " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
2223 actred, prered, prered != 0 ? ratio : 0., SQR(temp1), SQR(temp2),
2228 const double kP5 = 0.5;
2229 const double kP25 = 0.25;
2230 const double kP75 = 0.75;
2232 if (ratio <= kP25) {
2234 actred >= 0.0 ? kP5 : kP5 * dirder / (dirder + kP5 * actred);
2235 if (kP1 * fnorm1 >= fnorm || temp < kP1) temp = kP1;
2236 delta = temp * MIN(delta, pnorm / kP1);
2238 }
else if (par == 0. || ratio >= kP75) {
2239 delta = pnorm / kP5;
2244 if (ratio >= kP0001) {
2247 for (
int j = 0; j < n; j++) {
2249 wa2[j] = diag[j] * x[j];
2251 for (
int i = 0; i < m; i++) fvec[i] = wa4[i];
2252 xnorm = lm_enorm(n, wa2);
2258 printf(
"ATTN: iteration considered unsuccessful\n");
2265 if (fabs(actred) <= ftol && prered <= ftol && kP5 * ratio <= 1) *info = 1;
2266 if (delta <= xtol * xnorm) *info += 2;
2267 if (*info != 0)
return;
2271 if (*nfev >= maxfev) *info = 5;
2272 if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && kP5 * ratio <= 1)
2274 if (delta <= LM_MACHEP * xnorm) *info = 7;
2275 if (gnorm <= LM_MACHEP) *info = 8;
2276 if (*info != 0)
return;
2280 }
while (ratio < kP0001);
2287void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2288 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
2375 for (
int j = 0; j < n; j++) {
2377 if (r[j * ldr + j] == 0 && nsing == n) nsing = j;
2378 if (nsing < n) wa1[j] = 0;
2381 printf(
"nsing %d ", nsing);
2383 for (
int j = nsing - 1; j >= 0; j--) {
2384 wa1[j] = wa1[j] / r[j + ldr * j];
2385 const double temp = wa1[j];
2386 for (
int i = 0; i < j; i++) wa1[i] -= r[j * ldr + i] * temp;
2389 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa1[j];
2396 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2398 double dxnorm = lm_enorm(n, wa2);
2399 double fp = dxnorm - delta;
2400 const double kP1 = 0.1;
2401 if (fp <= kP1 * delta) {
2403 printf(
"lmpar/ terminate (fp<delta/10\n");
2415 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2417 for (
int j = 0; j < n; j++) {
2419 for (
int i = 0; i < j; i++) sum += r[j * ldr + i] * wa1[i];
2420 wa1[j] = (wa1[j] - sum) / r[j + ldr * j];
2422 const double temp = lm_enorm(n, wa1);
2423 parl = fp / delta / temp / temp;
2428 for (
int j = 0; j < n; j++) {
2430 for (
int i = 0; i <= j; i++) sum += r[j * ldr + i] * qtb[i];
2431 wa1[j] = sum / diag[ipvt[j]];
2433 const double gnorm = lm_enorm(n, wa1);
2435 gnorm / delta == 0.0 ? LM_DWARF / MIN(delta, kP1) : gnorm / delta;
2440 *par = MAX(*par, parl);
2441 *par = MIN(*par, paru);
2442 if (*par == 0.) *par = gnorm / dxnorm;
2444 printf(
"lmpar/ parl %.4e par %.4e paru %.4e\n", parl, *par, paru);
2451 const double kP001 = 0.001;
2452 if (*par == 0.) *par = MAX(LM_DWARF, kP001 * paru);
2453 double temp = sqrt(*par);
2454 for (
int j = 0; j < n; j++) wa1[j] = temp * diag[j];
2455 lm_qrsolv(n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2);
2456 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2457 dxnorm = lm_enorm(n, wa2);
2458 const double fp_old = fp;
2459 fp = dxnorm - delta;
2465 if (fabs(fp) <= kP1 * delta ||
2466 (parl == 0. && fp <= fp_old && fp_old < 0.) || iter == 10)
2471 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2473 for (
int j = 0; j < n; j++) {
2474 wa1[j] = wa1[j] / sdiag[j];
2475 for (
int i = j + 1; i < n; i++) wa1[i] -= r[j * ldr + i] * wa1[j];
2477 temp = lm_enorm(n, wa1);
2478 double parc = fp / delta / temp / temp;
2483 parl = MAX(parl, *par);
2485 paru = MIN(paru, *par);
2490 *par = MAX(parl, *par + parc);
2494void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
2495 double *acnorm,
double *wa) {
2551 for (
int j = 0; j < n; j++) {
2552 acnorm[j] = lm_enorm(m, &a[j * m]);
2553 rdiag[j] = acnorm[j];
2555 if (pivot) ipvt[j] = j;
2563 const int minmn = MIN(m, n);
2564 for (
int j = 0; j < minmn; j++) {
2566 if (!pivot)
goto pivot_ok;
2570 for (k = j + 1; k < n; k++)
2571 if (rdiag[k] > rdiag[kmax]) kmax = k;
2572 if (kmax == j)
goto pivot_ok;
2574 for (
int i = 0; i < m; i++) {
2575 std::swap(a[j * m + i], a[kmax * m + i]);
2580 rdiag[kmax] = rdiag[j];
2582 std::swap(ipvt[j], ipvt[kmax]);
2592 double ajnorm = lm_enorm(m - j, &a[j * m + j]);
2598 if (a[j * m + j] < 0.) ajnorm = -ajnorm;
2599 for (
int i = j; i < m; i++) a[j * m + i] /= ajnorm;
2605 for (k = j + 1; k < n; k++) {
2608 for (
int i = j; i < m; i++) sum += a[j * m + i] * a[k * m + i];
2610 double temp = sum / a[j + m * j];
2612 for (
int i = j; i < m; i++) a[k * m + i] -= temp * a[j * m + i];
2614 if (pivot && rdiag[k] != 0.) {
2615 temp = a[m * k + j] / rdiag[k];
2616 temp = MAX(0., 1 - temp * temp);
2617 rdiag[k] *= sqrt(temp);
2618 temp = rdiag[k] / wa[k];
2619 const double kP05 = 0.05;
2620 if (kP05 * SQR(temp) <= LM_MACHEP) {
2621 rdiag[k] = lm_enorm(m - j - 1, &a[m * k + j + 1]);
2631void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2632 double *x,
double *sdiag,
double *wa) {
2700 for (
int j = 0; j < n; j++) {
2701 for (
int i = j; i < n; i++) r[j * ldr + i] = r[i * ldr + j];
2702 x[j] = r[j * ldr + j];
2711 for (
int j = 0; j < n; j++) {
2717 if (diag[ipvt[j]] == 0.)
goto L90;
2718 for (
int k = j; k < n; k++) sdiag[k] = 0.;
2719 sdiag[j] = diag[ipvt[j]];
2725 for (
int k = j; k < n; k++) {
2726 const double p25 = 0.25;
2727 const double p5 = 0.5;
2732 if (sdiag[k] == 0.)
continue;
2733 const int kk = k + ldr * k;
2736 if (fabs(r[kk]) < fabs(sdiag[k])) {
2737 const double cotan = r[kk] / sdiag[k];
2738 sin = p5 / sqrt(p25 + p25 * SQR(cotan));
2741 const double tan = sdiag[k] / r[kk];
2742 cos = p5 / sqrt(p25 + p25 * SQR(tan));
2749 r[kk] = cos * r[kk] + sin * sdiag[k];
2750 double temp = cos * wa[k] + sin * qtbpj;
2751 qtbpj = -sin * wa[k] + cos * qtbpj;
2756 for (
int i = k + 1; i < n; i++) {
2757 temp = cos * r[k * ldr + i] + sin * sdiag[i];
2758 sdiag[i] = -sin * r[k * ldr + i] + cos * sdiag[i];
2759 r[k * ldr + i] = temp;
2767 sdiag[j] = r[j * ldr + j];
2768 r[j * ldr + j] = x[j];
2775 for (
int j = 0; j < n; j++) {
2776 if (sdiag[j] == 0. && nsing == n) nsing = j;
2777 if (nsing < n) wa[j] = 0;
2780 for (
int j = nsing - 1; j >= 0; j--) {
2782 for (
int i = j + 1; i < nsing; i++) sum += r[j * ldr + i] * wa[i];
2783 wa[j] = (wa[j] - sum) / sdiag[j];
2788 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa[j];
2791double lm_enorm(
int n,
double *x) {
2813 double s1 = 0.0, s2 = 0.0, s3 = 0.0;
2814 double x1max = 0.0, x3max = 0.0;
2815 const double agiant = LM_SQRT_GIANT / ((double)n);
2817 for (
int i = 0; i < n; i++) {
2818 double xabs = fabs(x[i]);
2819 if (xabs > LM_SQRT_DWARF && xabs < agiant) {
2825 if (xabs > LM_SQRT_DWARF) {
2828 s1 = 1 + s1 * SQR(x1max / xabs);
2831 s1 += SQR(xabs / x1max);
2837 s3 = 1 + s3 * SQR(x3max / xabs);
2841 s3 += SQR(xabs / x3max);
2848 if (s1 != 0)
return x1max * sqrt(s1 + (s2 / x1max) / x1max);
2850 if (s2 >= x3max)
return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
2851 return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
2854 return x3max * sqrt(s3);
2857double lat_gc_crosses_meridian(
double lat1,
double lon1,
double lat2,
2858 double lon2,
double lon) {
2864 double dlon = lon * DEGREE;
2865 double dlat1 = lat1 * DEGREE;
2866 double dlat2 = lat2 * DEGREE;
2867 double dlon1 = lon1 * DEGREE;
2868 double dlon2 = lon2 * DEGREE;
2870 return RADIAN * atan((sin(dlat1) * cos(dlat2) * sin(dlon - dlon2) -
2871 sin(dlat2) * cos(dlat1) * sin(dlon - dlon1)) /
2872 (cos(dlat1) * cos(dlat2) * sin(dlon1 - dlon2)));
2875double lat_rl_crosses_meridian(
double lat1,
double lon1,
double lat2,
2876 double lon2,
double lon) {
2884 DistanceBearingMercator(lat2, lon2, lat1, lon1, &brg, NULL);
2887 toSM(lat1, lon1, 0., lon, &x1, &y1);
2888 toSM(lat1, lon, 0., lon, &x, &y1);
2893 }
else if (brg >= 180.) {
2896 }
else if (brg >= 90.) {
2903 double ydelta = fabs(x1) * tan(brg * DEGREE);
2905 double crosslat, crosslon;
2906 fromSM(x, y1 + dir * ydelta, 0., lon, &crosslat, &crosslon);