44#define snprintf mysnprintf
48static const long long lNaN = 0xfff8000000000000;
49#define NAN (*(double *)&lNaN)
68struct DATUM const gDatum[] = {
70 {
"Adindan", 5, -162, -12, 206},
71 {
"Afgooye", 15, -43, -163, 45},
72 {
"Ain el Abd 1970", 14, -150, -251, -2},
73 {
"Anna 1 Astro 1965", 2, -491, -22, 435},
74 {
"Arc 1950", 5, -143, -90, -294},
75 {
"Arc 1960", 5, -160, -8, -300},
76 {
"Ascension Island 58", 14, -207, 107, 52},
77 {
"Astro B4 Sorol Atoll", 14, 114, -116, -333},
78 {
"Astro Beacon E ", 14, 145, 75, -272},
79 {
"Astro DOS 71/4", 14, -320, 550, -494},
80 {
"Astronomic Stn 52", 14, 124, -234, -25},
81 {
"Australian Geod 66", 2, -133, -48, 148},
82 {
"Australian Geod 84", 2, -134, -48, 149},
83 {
"Bellevue (IGN)", 14, -127, -769, 472},
84 {
"Bermuda 1957", 4, -73, 213, 296},
85 {
"Bogota Observatory", 14, 307, 304, -318},
86 {
"Campo Inchauspe", 14, -148, 136, 90},
87 {
"Canton Astro 1966", 14, 298, -304, -375},
88 {
"Cape", 5, -136, -108, -292},
89 {
"Cape Canaveral", 4, -2, 150, 181},
90 {
"Carthage", 5, -263, 6, 431},
91 {
"CH-1903", 3, 674, 15, 405},
92 {
"Chatham 1971", 14, 175, -38, 113},
93 {
"Chua Astro", 14, -134, 229, -29},
94 {
"Corrego Alegre", 14, -206, 172, -6},
95 {
"Djakarta (Batavia)", 3, -377, 681, -50},
96 {
"DOS 1968", 14, 230, -199, -752},
97 {
"Easter Island 1967", 14, 211, 147, 111},
98 {
"European 1950", 14, -87, -98, -121},
99 {
"European 1979", 14, -86, -98, -119},
100 {
"Finland Hayford", 14, -78, -231, -97},
101 {
"Gandajika Base", 14, -133, -321, 50},
102 {
"Geodetic Datum 49", 14, 84, -22, 209},
103 {
"Guam 1963", 4, -100, -248, 259},
104 {
"GUX 1 Astro", 14, 252, -209, -751},
105 {
"Hermannskogel Datum", 3, 682, -203, 480},
106 {
"Hjorsey 1955", 14, -73, 46, -86},
107 {
"Hong Kong 1963", 14, -156, -271, -189},
108 {
"Indian Bangladesh", 6, 289, 734, 257},
109 {
"Indian Thailand", 6, 214, 836, 303},
110 {
"Ireland 1965", 1, 506, -122, 611},
111 {
"ISTS 073 Astro 69", 14, 208, -435, -229},
112 {
"Johnston Island", 14, 191, -77, -204},
113 {
"Kandawala", 6, -97, 787, 86},
114 {
"Kerguelen Island", 14, 145, -187, 103},
115 {
"Kertau 1948", 7, -11, 851, 5},
116 {
"L.C. 5 Astro", 4, 42, 124, 147},
117 {
"Liberia 1964", 5, -90, 40, 88},
118 {
"Luzon Mindanao", 4, -133, -79, -72},
119 {
"Luzon Philippines", 4, -133, -77, -51},
120 {
"Mahe 1971", 5, 41, -220, -134},
121 {
"Marco Astro", 14, -289, -124, 60},
122 {
"Massawa", 3, 639, 405, 60},
123 {
"Merchich", 5, 31, 146, 47},
124 {
"Midway Astro 1961", 14, 912, -58, 1227},
125 {
"Minna", 5, -92, -93, 122},
126 {
"NAD27 Alaska", 4, -5, 135, 172},
127 {
"NAD27 Bahamas", 4, -4, 154, 178},
128 {
"NAD27 Canada", 4, -10, 158, 187},
129 {
"NAD27 Canal Zone", 4, 0, 125, 201},
130 {
"NAD27 Caribbean", 4, -7, 152, 178},
131 {
"NAD27 Central", 4, 0, 125, 194},
132 {
"NAD27 CONUS", 4, -8, 160, 176},
133 {
"NAD27 Cuba", 4, -9, 152, 178},
134 {
"NAD27 Greenland", 4, 11, 114, 195},
135 {
"NAD27 Mexico", 4, -12, 130, 190},
136 {
"NAD27 San Salvador", 4, 1, 140, 165},
137 {
"NAD83", 11, 0, 0, 0},
138 {
"Nahrwn Masirah Ilnd", 5, -247, -148, 369},
139 {
"Nahrwn Saudi Arbia", 5, -231, -196, 482},
140 {
"Nahrwn United Arab", 5, -249, -156, 381},
141 {
"Naparima BWI", 14, -2, 374, 172},
142 {
"Observatorio 1966", 14, -425, -169, 81},
143 {
"Old Egyptian", 12, -130, 110, -13},
144 {
"Old Hawaiian", 4, 61, -285, -181},
145 {
"Oman", 5, -346, -1, 224},
146 {
"Ord Srvy Grt Britn", 0, 375, -111, 431},
147 {
"Pico De Las Nieves", 14, -307, -92, 127},
148 {
"Pitcairn Astro 1967", 14, 185, 165, 42},
149 {
"Prov So Amrican 56", 14, -288, 175, -376},
150 {
"Prov So Chilean 63", 14, 16, 196, 93},
151 {
"Puerto Rico", 4, 11, 72, -101},
152 {
"Qatar National", 14, -128, -283, 22},
153 {
"Qornoq", 14, 164, 138, -189},
154 {
"Reunion", 14, 94, -948, -1262},
155 {
"Rome 1940", 14, -225, -65, 9},
156 {
"RT 90", 3, 498, -36, 568},
157 {
"Santo (DOS)", 14, 170, 42, 84},
158 {
"Sao Braz", 14, -203, 141, 53},
159 {
"Sapper Hill 1943", 14, -355, 16, 74},
160 {
"Schwarzeck", 21, 616, 97, -251},
161 {
"South American 69", 16, -57, 1, -41},
162 {
"South Asia", 8, 7, -10, -26},
163 {
"Southeast Base", 14, -499, -249, 314},
164 {
"Southwest Base", 14, -104, 167, -38},
165 {
"Timbalai 1948", 6, -689, 691, -46},
166 {
"Tokyo", 3, -128, 481, 664},
167 {
"Tristan Astro 1968", 14, -632, 438, -609},
168 {
"Viti Levu 1916", 5, 51, 391, -36},
169 {
"Wake-Eniwetok 60", 13, 101, 52, -39},
170 {
"WGS 72", 19, 0, 0, 5},
171 {
"WGS 84", 20, 0, 0, 0},
172 {
"Zanderij", 14, -265, 120, -358},
173 {
"WGS_84", 20, 0, 0, 0},
174 {
"WGS-84", 20, 0, 0, 0},
175 {
"EUROPEAN DATUM 1950", 14, -87, -98, -121},
176 {
"European 1950 (Norway Finland)", 14, -87, -98, -121},
177 {
"ED50", 14, -87, -98, -121},
178 {
"RT90 (Sweden)", 3, 498, -36, 568},
179 {
"Monte Mario 1940", 14, -104, -49, 10},
180 {
"Ord Surv of Gr Britain 1936", 0, 375, -111, 431},
181 {
"South American 1969", 16, -57, 1, -41},
182 {
"PULKOVO 1942 (2)", 15, 25, -141, -79},
183 {
"EUROPEAN DATUM", 14, -87, -98, -121},
184 {
"BERMUDA DATUM 1957", 4, -73, 213, 296},
185 {
"COA", 14, -206, 172, -6},
186 {
"COABR", 14, -206, 172, -6},
187 {
"Roma 1940", 14, -225, -65, 9},
188 {
"ITALIENISCHES LANDESNETZ", 14, -87, -98, -121},
189 {
"HERMANSKOGEL DATUM", 3, 682, -203, 480},
190 {
"AGD66", 2, -128, -52, 153},
191 {
"ED", 14, -87, -98, -121},
192 {
"EUROPEAN 1950 (SPAIN AND PORTUGAL)", 14, -87, -98, -121},
193 {
"ED-50", 14, -87, -98, -121},
194 {
"EUROPEAN", 14, -87, -98, -121},
195 {
"POTSDAM", 14, -87, -98, -121},
196 {
"GRACIOSA SW BASE DATUM", 14, -104, 167, -38},
197 {
"WGS 1984", 20, 0, 0, 0},
198 {
"WGS 1972", 19, 0, 0, 5},
204 {
"Airy 1830", 6377563.396, 299.3249646},
205 {
"Modified Airy", 6377340.189, 299.3249646},
206 {
"Australian National", 6378160.0, 298.25},
207 {
"Bessel 1841", 6377397.155, 299.1528128},
208 {
"Clarke 1866", 6378206.4, 294.9786982},
209 {
"Clarke 1880", 6378249.145, 293.465},
210 {
"Everest (India 1830)", 6377276.345, 300.8017},
211 {
"Everest (1948)", 6377304.063, 300.8017},
212 {
"Modified Fischer 1960", 6378155.0, 298.3},
213 {
"Everest (Pakistan)", 6377309.613, 300.8017},
214 {
"Indonesian 1974", 6378160.0, 298.247},
215 {
"GRS 80", 6378137.0, 298.257222101},
216 {
"Helmert 1906", 6378200.0, 298.3},
217 {
"Hough 1960", 6378270.0, 297.0},
218 {
"International 1924", 6378388.0, 297.0},
219 {
"Krassovsky 1940", 6378245.0, 298.3},
220 {
"South American 1969", 6378160.0, 298.25},
221 {
"Everest (Malaysia 1969)", 6377295.664, 300.8017},
222 {
"Everest (Sabah Sarawak)", 6377298.556, 300.8017},
223 {
"WGS 72", 6378135.0, 298.26},
224 {
"WGS 84", 6378137.0, 298.257223563},
225 {
"Bessel 1841 (Namibia)", 6377483.865, 299.1528128},
226 {
"Everest (India 1956)", 6377301.243, 300.8017},
227 {
"Struve 1860", 6378298.3, 294.73}
231short nDatums =
sizeof(gDatum) /
sizeof(
struct DATUM);
235void datumParams(
short datum,
double *a,
double *es) {
236 extern struct DATUM const gDatum[];
237 extern struct ELLIPSOID const gEllipsoid[];
239 if (datum < nDatums) {
240 double f = 1.0 / gEllipsoid[gDatum[datum].ellipsoid].invf;
241 if (es) *es = 2 * f - f * f;
242 if (a) *a = gEllipsoid[gDatum[datum].ellipsoid].a;
244 double f = 1.0 / 298.257223563;
245 if (es) *es = 2 * f - f * f;
246 if (a) *a = 6378137.0;
250static int datumNameCmp(
const char *n1,
const char *n2) {
256 else if (toupper(*n1) == toupper(*n2))
263static int isWGS84(
int i) {
266 if (i == DATUM_INDEX_WGS84)
return i;
268 if (gDatum[i].ellipsoid != gDatum[DATUM_INDEX_WGS84].ellipsoid)
return i;
270 if (gDatum[i].dx != gDatum[DATUM_INDEX_WGS84].dx)
return i;
272 if (gDatum[i].dy != gDatum[DATUM_INDEX_WGS84].dy)
return i;
274 if (gDatum[i].dz != gDatum[DATUM_INDEX_WGS84].dz)
return i;
276 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));
1283double DistGreatCircle(
double slat,
double slon,
double dlat,
double dlon) {
1285 d5 = DistLoxodrome(slat, slon, dlat, dlon);
1293 double phi1, lam1, phi2, lam2;
1298 double es, onef, f, f64, f4;
1300 phi1 = slat * DEGREE;
1301 lam1 = slon * DEGREE;
1302 phi2 = dlat * DEGREE;
1303 lam2 = dlon * DEGREE;
1307 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm, cosdthm,
1308 sindthm, L, E, cosd, d, X, Y, T, sind, D, A, B;
1317 geod_a = WGS84_semimajor_axis_meters;
1320 onef = sqrt(1. - es);
1324 f64 = geod_f * geod_f / 64;
1327 th1 = atan(onef * tan(phi1));
1328 th2 = atan(onef * tan(phi2));
1333 thm = .5 * (th1 + th2);
1334 dthm = .5 * (th2 - th1);
1335 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1336 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1339 sindlamm = sin(dlamm);
1342 cosdthm = cos(dthm);
1343 sindthm = sin(dthm);
1344 L = sindthm * sindthm +
1345 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1346 d = acos(cosd = 1 - L - L);
1351 Y = sinthm * cosdthm;
1352 Y *= (Y + Y) / (1. - L);
1353 T = sindthm * costhm;
1361 geod_S = geod_a * sind *
1362 (T - f4 * (T * X - Y) +
1363 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1370 geod_S = geod_a * d;
1379 d5 = geod_S / 1852.0;
1384void DistanceBearingMercator(
double lat1,
double lon1,
double lat0,
double lon0,
1385 double *brg,
double *dist) {
1387 double latm = (lat0 + lat1) / 2 * DEGREE;
1388 double delta_lat = (lat1 - lat0);
1389 double delta_lon = (lon1 - lon0);
1390 double ex_lat0, ex_lat1;
1391 double bearing, distance;
1393 if (delta_lon < -180) delta_lon += 360;
1394 if (delta_lon > 180) delta_lon -= 360;
1398 else if (fabs(delta_lat) != .0)
1399 bearing = atan(delta_lon * cos(latm) / delta_lat);
1403 distance = sqrt(pow(delta_lat, 2) + pow(delta_lon * cos(latm), 2));
1408 if (delta_lat != 0.) {
1409 ex_lat0 = 10800 / PI * log(tan(PI / 4 + lat0 * DEGREE / 2));
1410 ex_lat1 = 10800 / PI * log(tan(PI / 4 + lat1 * DEGREE / 2));
1411 bearing = atan(delta_lon * 60 / (ex_lat1 - ex_lat0));
1412 distance = fabs(delta_lat / cos(bearing));
1418 bearing = fabs(bearing);
1420 if (delta_lon < 0) bearing = 2 * PI - bearing;
1424 bearing = PI - bearing;
1426 bearing = PI + bearing;
1429 if (brg) *brg = bearing * RADIAN;
1430 if (dist) *dist = distance * 60;
1456double my_fit_function(
double tx,
double ty,
int n_par,
double *p) {
1457 double ret = p[0] + p[1] * tx;
1459 if (n_par > 2) ret += p[2] * ty;
1461 ret += p[3] * tx * tx;
1462 ret += p[4] * tx * ty;
1463 ret += p[5] * ty * ty;
1466 ret += p[6] * tx * tx * tx;
1467 ret += p[7] * tx * tx * ty;
1468 ret += p[8] * tx * ty * ty;
1469 ret += p[9] * ty * ty * ty;
1475int Georef_Calculate_Coefficients_Onedir(
int n_points,
int n_par,
double *tx,
1476 double *ty,
double *y,
double *p,
1477 double hintp0,
double hintp1,
1492 lm_initialize_control(&control);
1494 for (i = 0; i < 12; i++) p[i] = 0.;
1503 data.user_func = my_fit_function;
1508 data.print_flag = 0;
1512 lm_minimize(n_points, n_par, p, lm_evaluate_default, lm_print_default, &data,
1520 return control.info;
1523int Georef_Calculate_Coefficients(
struct GeoRef *cp,
int nlin_lon) {
1525 for (
int i = 0; i < 10; ++i)
1526 cp->pwx[i] = cp->pwy[i] = cp->wpx[i] = cp->wpy[i] = 0.0;
1530 switch (cp->order) {
1545 const int mp_lat = mp;
1548 const int mp_lon = nlin_lon ? 2 : mp;
1551 std::vector<double> pnull(cp->count, 1.0);
1556 int r1 = Georef_Calculate_Coefficients_Onedir(
1557 cp->count, mp_lon, cp->tx, cp->ty, cp->lon, cp->pwx,
1559 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1560 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1564 double *px = nlin_lon ? &pnull[0] : cp->tx;
1566 int r2 = Georef_Calculate_Coefficients_Onedir(
1567 cp->count, mp_lat, px, cp->ty, cp->lat, cp->pwy,
1569 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1570 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1575 int r3 = Georef_Calculate_Coefficients_Onedir(
1576 cp->count, mp_lon, cp->lon, cp->lat, cp->tx, cp->wpx,
1578 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1579 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1583 px = nlin_lon ? &pnull[0] : cp->lon;
1585 int r4 = Georef_Calculate_Coefficients_Onedir(
1586 cp->count, mp_lat, &pnull[0] , cp->lat, cp->ty, cp->wpy,
1588 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1589 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1591 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1598int Georef_Calculate_Coefficients_Proj(
struct GeoRef *cp) {
1603 cp->pwx[6] = cp->pwy[6] = cp->wpx[6] = cp->wpy[6] = 0.;
1604 cp->pwx[7] = cp->pwy[7] = cp->wpx[7] = cp->wpy[7] = 0.;
1605 cp->pwx[8] = cp->pwy[8] = cp->wpx[8] = cp->wpy[8] = 0.;
1606 cp->pwx[9] = cp->pwy[9] = cp->wpx[9] = cp->wpy[9] = 0.;
1607 cp->pwx[3] = cp->pwy[3] = cp->wpx[3] = cp->wpy[3] = 0.;
1608 cp->pwx[4] = cp->pwy[4] = cp->wpx[4] = cp->wpy[4] = 0.;
1609 cp->pwx[5] = cp->pwy[5] = cp->wpx[5] = cp->wpy[5] = 0.;
1610 cp->pwx[0] = cp->pwy[0] = cp->wpx[0] = cp->wpy[0] = 0.;
1611 cp->pwx[1] = cp->pwy[1] = cp->wpx[1] = cp->wpy[1] = 0.;
1612 cp->pwx[2] = cp->pwy[2] = cp->wpx[2] = cp->wpy[2] = 0.;
1619 r1 = Georef_Calculate_Coefficients_Onedir(
1620 cp->count, mp, cp->tx, cp->ty, cp->lon, cp->pwx,
1622 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1623 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1625 r2 = Georef_Calculate_Coefficients_Onedir(
1626 cp->count, mp, cp->tx, cp->ty, cp->lat, cp->pwy,
1628 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1629 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1634 r3 = Georef_Calculate_Coefficients_Onedir(
1635 cp->count, mp, cp->lon, cp->lat, cp->tx, cp->wpx,
1637 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1638 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1640 r4 = Georef_Calculate_Coefficients_Onedir(
1641 cp->count, mp, cp->lon, cp->lat, cp->ty, cp->wpy,
1643 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1644 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1646 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1659void lm_evaluate_default(
double *par,
int m_dat,
double *fvec,
void *data,
1679 for (
int i = 0; i < m_dat; i++) {
1680 fvec[i] = mydata->user_y[i] - mydata->user_func(mydata->user_tx[i],
1682 mydata->n_par, par);
1688void lm_print_default(
int n_par,
double *par,
int m_dat,
double *fvec,
1689 void *data,
int iflag,
int iter,
int nfev)
1700 if (mydata->print_flag) {
1702 printf(
"trying step in gradient direction\n");
1703 }
else if (iflag == 1) {
1704 printf(
"determining gradient (iteration %d)\n", iter);
1705 }
else if (iflag == 0) {
1706 printf(
"starting minimization\n");
1707 }
else if (iflag == -1) {
1708 printf(
"terminated after %d evaluations\n", nfev);
1712 for (
int i = 0; i < n_par; ++i) printf(
" %12g", par[i]);
1713 printf(
" => norm: %12g\n", lm_enorm(m_dat, fvec));
1716 printf(
" fitting data as follows:\n");
1717 for (
int i = 0; i < m_dat; ++i) {
1718 const double tx = (mydata->user_tx)[i];
1719 const double ty = (mydata->user_ty)[i];
1720 const double y = (mydata->user_y)[i];
1721 const double f = mydata->user_func(tx, ty, mydata->n_par, par);
1723 " tx[%2d]=%8g ty[%2d]=%8g y=%12g fit=%12g "
1725 i, tx, i, ty, y, f, y - f);
1736 control->maxcall = 100;
1737 control->epsilon = 1.e-10;
1738 control->stepbound = 100;
1739 control->ftol = 1.e-14;
1740 control->xtol = 1.e-14;
1741 control->gtol = 1.e-14;
1744void lm_minimize(
int m_dat,
int n_par,
double *par, lm_evaluate_ftype *evaluate,
1745 lm_print_ftype *printout,
void *data,
1747 std::vector<double> fvec(m_dat);
1748 std::vector<double> diag(n_par);
1749 std::vector<double> qtf(n_par);
1750 std::vector<double> fjac(n_par * m_dat);
1751 std::vector<double> wa1(n_par);
1752 std::vector<double> wa2(n_par);
1753 std::vector<double> wa3(n_par);
1754 std::vector<double> wa4(m_dat);
1755 std::vector<int> ipvt(n_par);
1763 lm_lmdif(m_dat, n_par, par, &fvec[0], control->ftol, control->xtol,
1764 control->gtol, control->maxcall * (n_par + 1), control->epsilon,
1765 &diag[0], 1, control->stepbound, &(control->info), &(control->nfev),
1766 &fjac[0], &ipvt[0], &qtf[0], &wa1[0], &wa2[0], &wa3[0], &wa4[0],
1767 evaluate, printout, data);
1769 (*printout)(n_par, par, m_dat, &fvec[0], data, -1, 0, control->nfev);
1770 control->fnorm = lm_enorm(m_dat, &fvec[0]);
1771 if (control->info < 0) control->info = 10;
1776const char *lm_infmsg[] = {
1777 "improper input parameters",
1778 "the relative error in the sum of squares is at most tol",
1779 "the relative error between x and the solution is at most tol",
1780 "both errors are at most tol",
1781 "fvec is orthogonal to the columns of the jacobian to machine precision",
1782 "number of calls to fcn has reached or exceeded 200*(n+1)",
1783 "ftol is too small. no further reduction in the sum of squares is possible",
1784 "xtol too small. no further improvement in approximate solution x possible",
1785 "gtol too small. no further improvement in approximate solution x possible",
1786 "not enough memory",
1787 "break requested within function evaluation"};
1789const char *lm_shortmsg[] = {
"invalid input",
"success (f)",
"success (p)",
1790 "success (f,p)",
"degenerate",
"call limit",
1791 "failed (f)",
"failed (p)",
"failed (o)",
1792 "no memory",
"user break"};
1805#define LM_MACHEP 1.2e-16
1806#define LM_DWARF 1.0e-38
1813#define LM_SQRT_DWARF 3.834e-20
1814#define LM_SQRT_GIANT 1.304e19
1816void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
1817 double *acnorm,
double *wa);
1818void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1819 double *x,
double *sdiag,
double *wa);
1820void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
1821 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
1824#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
1825#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
1826#define SQR(x) (x) * (x)
1830void lm_lmdif(
int m,
int n,
double *x,
double *fvec,
double ftol,
double xtol,
1831 double gtol,
int maxfev,
double epsfcn,
double *diag,
int mode,
1832 double factor,
int *info,
int *nfev,
double *fjac,
int *ipvt,
1833 double *qtf,
double *wa1,
double *wa2,
double *wa3,
double *wa4,
1834 lm_evaluate_ftype *evaluate, lm_print_ftype *printout,
2016 if ((n <= 0) || (m < n) || (ftol < 0.) || (xtol < 0.) || (gtol < 0.) ||
2017 (maxfev <= 0) || (factor <= 0.)) {
2024 for (
int j = 0; j < n; j++)
2026 if (diag[j] <= 0.0) {
2039 (*evaluate)(x, m, fvec, data, info);
2040 (*printout)(n, x, m, fvec, data, 0, 0, ++(*nfev));
2041 if (*info < 0)
return;
2048 double fnorm = lm_enorm(m, fvec);
2049 const double eps = sqrt(MAX(
2055 printf(
"lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n", iter, *nfev,
2061 for (
int j = 0; j < n; j++) {
2062 const double temp = x[j];
2063 const double step = eps * fabs(temp) == 0.0 ? eps : eps * fabs(temp);
2067 (*evaluate)(x, m, wa4, data, info);
2068 (*printout)(n, x, m, wa4, data, 1, iter, ++(*nfev));
2069 if (*info < 0)
return;
2071 for (
int i = 0; i < m; i++) fjac[j * m + i] = (wa4[i] - fvec[i]) / step;
2075 for (i = 0; i < m; i++) {
2076 for (j = 0; j < n; j++) printf(
"%.5e ", y[j * m + i]);
2083 lm_qrfac(m, n, fjac, 1, ipvt, wa1, wa2, wa3);
2092 for (
int j = 0; j < n; j++) {
2094 if (wa2[j] == 0.) diag[j] = 1.;
2101 for (
int j = 0; j < n; j++) wa3[j] = diag[j] * x[j];
2103 xnorm = lm_enorm(n, wa3);
2104 delta = factor * xnorm;
2105 if (delta == 0.) delta = factor;
2110 for (
int i = 0; i < m; i++) wa4[i] = fvec[i];
2112 for (
int j = 0; j < n; j++) {
2113 double temp3 = fjac[j * m + j];
2116 for (
int i = j; i < m; i++) sum += fjac[j * m + i] * wa4[i];
2117 double temp = -sum / temp3;
2118 for (
int i = j; i < m; i++) wa4[i] += fjac[j * m + i] * temp;
2120 fjac[j * m + j] = wa1[j];
2128 for (
int j = 0; j < n; j++) {
2129 if (wa2[ipvt[j]] == 0)
continue;
2132 for (
int i = 0; i <= j; i++) sum += fjac[j * m + i] * qtf[i] / fnorm;
2133 gnorm = MAX(gnorm, fabs(sum / wa2[ipvt[j]]));
2137 if (gnorm <= gtol) {
2145 for (
int j = 0; j < n; j++) diag[j] = MAX(diag[j], wa2[j]);
2149 const double kP0001 = 1.0e-4;
2153 printf(
"lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev);
2158 lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &par, wa1, wa2, wa3, wa4);
2162 for (
int j = 0; j < n; j++) {
2164 wa2[j] = x[j] + wa1[j];
2165 wa3[j] = diag[j] * wa1[j];
2167 double pnorm = lm_enorm(n, wa3);
2172 delta = MIN(delta, pnorm);
2177 (*evaluate)(wa2, m, wa4, data, info);
2178 (*printout)(n, x, m, wa4, data, 2, iter, ++(*nfev));
2179 if (*info < 0)
return;
2181 double fnorm1 = lm_enorm(m, wa4);
2184 "lmdif/ pnorm %.10e fnorm1 %.10e fnorm %.10e"
2185 " delta=%.10e par=%.10e\n",
2186 pnorm, fnorm1, fnorm, delta, par);
2190 const double kP1 = 0.1;
2191 const double actred = kP1 * fnorm1 < fnorm ? 1 - SQR(fnorm1 / fnorm) : -1;
2196 for (
int j = 0; j < n; j++) {
2198 for (
int i = 0; i <= j; i++) wa3[i] += fjac[j * m + i] * wa1[ipvt[j]];
2200 const double temp1 = lm_enorm(n, wa3) / fnorm;
2201 const double temp2 = sqrt(par) * pnorm / fnorm;
2202 const double prered = SQR(temp1) + 2 * SQR(temp2);
2203 const double dirder = -(SQR(temp1) + SQR(temp2));
2207 ratio = prered != 0 ? actred / prered : 0.0;
2210 "lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
2211 " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
2212 actred, prered, prered != 0 ? ratio : 0., SQR(temp1), SQR(temp2),
2217 const double kP5 = 0.5;
2218 const double kP25 = 0.25;
2219 const double kP75 = 0.75;
2221 if (ratio <= kP25) {
2223 actred >= 0.0 ? kP5 : kP5 * dirder / (dirder + kP5 * actred);
2224 if (kP1 * fnorm1 >= fnorm || temp < kP1) temp = kP1;
2225 delta = temp * MIN(delta, pnorm / kP1);
2227 }
else if (par == 0. || ratio >= kP75) {
2228 delta = pnorm / kP5;
2233 if (ratio >= kP0001) {
2236 for (
int j = 0; j < n; j++) {
2238 wa2[j] = diag[j] * x[j];
2240 for (
int i = 0; i < m; i++) fvec[i] = wa4[i];
2241 xnorm = lm_enorm(n, wa2);
2247 printf(
"ATTN: iteration considered unsuccessful\n");
2254 if (fabs(actred) <= ftol && prered <= ftol && kP5 * ratio <= 1) *info = 1;
2255 if (delta <= xtol * xnorm) *info += 2;
2256 if (*info != 0)
return;
2260 if (*nfev >= maxfev) *info = 5;
2261 if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && kP5 * ratio <= 1)
2263 if (delta <= LM_MACHEP * xnorm) *info = 7;
2264 if (gnorm <= LM_MACHEP) *info = 8;
2265 if (*info != 0)
return;
2269 }
while (ratio < kP0001);
2276void lm_lmpar(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2277 double delta,
double *par,
double *x,
double *sdiag,
double *wa1,
2364 for (
int j = 0; j < n; j++) {
2366 if (r[j * ldr + j] == 0 && nsing == n) nsing = j;
2367 if (nsing < n) wa1[j] = 0;
2370 printf(
"nsing %d ", nsing);
2372 for (
int j = nsing - 1; j >= 0; j--) {
2373 wa1[j] = wa1[j] / r[j + ldr * j];
2374 const double temp = wa1[j];
2375 for (
int i = 0; i < j; i++) wa1[i] -= r[j * ldr + i] * temp;
2378 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa1[j];
2385 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2387 double dxnorm = lm_enorm(n, wa2);
2388 double fp = dxnorm - delta;
2389 const double kP1 = 0.1;
2390 if (fp <= kP1 * delta) {
2392 printf(
"lmpar/ terminate (fp<delta/10\n");
2404 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2406 for (
int j = 0; j < n; j++) {
2408 for (
int i = 0; i < j; i++) sum += r[j * ldr + i] * wa1[i];
2409 wa1[j] = (wa1[j] - sum) / r[j + ldr * j];
2411 const double temp = lm_enorm(n, wa1);
2412 parl = fp / delta / temp / temp;
2417 for (
int j = 0; j < n; j++) {
2419 for (
int i = 0; i <= j; i++) sum += r[j * ldr + i] * qtb[i];
2420 wa1[j] = sum / diag[ipvt[j]];
2422 const double gnorm = lm_enorm(n, wa1);
2424 gnorm / delta == 0.0 ? LM_DWARF / MIN(delta, kP1) : gnorm / delta;
2429 *par = MAX(*par, parl);
2430 *par = MIN(*par, paru);
2431 if (*par == 0.) *par = gnorm / dxnorm;
2433 printf(
"lmpar/ parl %.4e par %.4e paru %.4e\n", parl, *par, paru);
2440 const double kP001 = 0.001;
2441 if (*par == 0.) *par = MAX(LM_DWARF, kP001 * paru);
2442 double temp = sqrt(*par);
2443 for (
int j = 0; j < n; j++) wa1[j] = temp * diag[j];
2444 lm_qrsolv(n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2);
2445 for (
int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2446 dxnorm = lm_enorm(n, wa2);
2447 const double fp_old = fp;
2448 fp = dxnorm - delta;
2454 if (fabs(fp) <= kP1 * delta ||
2455 (parl == 0. && fp <= fp_old && fp_old < 0.) || iter == 10)
2460 for (
int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2462 for (
int j = 0; j < n; j++) {
2463 wa1[j] = wa1[j] / sdiag[j];
2464 for (
int i = j + 1; i < n; i++) wa1[i] -= r[j * ldr + i] * wa1[j];
2466 temp = lm_enorm(n, wa1);
2467 double parc = fp / delta / temp / temp;
2472 parl = MAX(parl, *par);
2474 paru = MIN(paru, *par);
2479 *par = MAX(parl, *par + parc);
2483void lm_qrfac(
int m,
int n,
double *a,
int pivot,
int *ipvt,
double *rdiag,
2484 double *acnorm,
double *wa) {
2540 for (
int j = 0; j < n; j++) {
2541 acnorm[j] = lm_enorm(m, &a[j * m]);
2542 rdiag[j] = acnorm[j];
2544 if (pivot) ipvt[j] = j;
2552 const int minmn = MIN(m, n);
2553 for (
int j = 0; j < minmn; j++) {
2555 if (!pivot)
goto pivot_ok;
2559 for (k = j + 1; k < n; k++)
2560 if (rdiag[k] > rdiag[kmax]) kmax = k;
2561 if (kmax == j)
goto pivot_ok;
2563 for (
int i = 0; i < m; i++) {
2564 std::swap(a[j * m + i], a[kmax * m + i]);
2569 rdiag[kmax] = rdiag[j];
2571 std::swap(ipvt[j], ipvt[kmax]);
2581 double ajnorm = lm_enorm(m - j, &a[j * m + j]);
2587 if (a[j * m + j] < 0.) ajnorm = -ajnorm;
2588 for (
int i = j; i < m; i++) a[j * m + i] /= ajnorm;
2594 for (k = j + 1; k < n; k++) {
2597 for (
int i = j; i < m; i++) sum += a[j * m + i] * a[k * m + i];
2599 double temp = sum / a[j + m * j];
2601 for (
int i = j; i < m; i++) a[k * m + i] -= temp * a[j * m + i];
2603 if (pivot && rdiag[k] != 0.) {
2604 temp = a[m * k + j] / rdiag[k];
2605 temp = MAX(0., 1 - temp * temp);
2606 rdiag[k] *= sqrt(temp);
2607 temp = rdiag[k] / wa[k];
2608 const double kP05 = 0.05;
2609 if (kP05 * SQR(temp) <= LM_MACHEP) {
2610 rdiag[k] = lm_enorm(m - j - 1, &a[m * k + j + 1]);
2620void lm_qrsolv(
int n,
double *r,
int ldr,
int *ipvt,
double *diag,
double *qtb,
2621 double *x,
double *sdiag,
double *wa) {
2689 for (
int j = 0; j < n; j++) {
2690 for (
int i = j; i < n; i++) r[j * ldr + i] = r[i * ldr + j];
2691 x[j] = r[j * ldr + j];
2700 for (
int j = 0; j < n; j++) {
2706 if (diag[ipvt[j]] == 0.)
goto L90;
2707 for (
int k = j; k < n; k++) sdiag[k] = 0.;
2708 sdiag[j] = diag[ipvt[j]];
2714 for (
int k = j; k < n; k++) {
2715 const double p25 = 0.25;
2716 const double p5 = 0.5;
2721 if (sdiag[k] == 0.)
continue;
2722 const int kk = k + ldr * k;
2725 if (fabs(r[kk]) < fabs(sdiag[k])) {
2726 const double cotan = r[kk] / sdiag[k];
2727 sin = p5 / sqrt(p25 + p25 * SQR(cotan));
2730 const double tan = sdiag[k] / r[kk];
2731 cos = p5 / sqrt(p25 + p25 * SQR(tan));
2738 r[kk] = cos * r[kk] + sin * sdiag[k];
2739 double temp = cos * wa[k] + sin * qtbpj;
2740 qtbpj = -sin * wa[k] + cos * qtbpj;
2745 for (
int i = k + 1; i < n; i++) {
2746 temp = cos * r[k * ldr + i] + sin * sdiag[i];
2747 sdiag[i] = -sin * r[k * ldr + i] + cos * sdiag[i];
2748 r[k * ldr + i] = temp;
2756 sdiag[j] = r[j * ldr + j];
2757 r[j * ldr + j] = x[j];
2764 for (
int j = 0; j < n; j++) {
2765 if (sdiag[j] == 0. && nsing == n) nsing = j;
2766 if (nsing < n) wa[j] = 0;
2769 for (
int j = nsing - 1; j >= 0; j--) {
2771 for (
int i = j + 1; i < nsing; i++) sum += r[j * ldr + i] * wa[i];
2772 wa[j] = (wa[j] - sum) / sdiag[j];
2777 for (
int j = 0; j < n; j++) x[ipvt[j]] = wa[j];
2780double lm_enorm(
int n,
double *x) {
2802 double s1 = 0.0, s2 = 0.0, s3 = 0.0;
2803 double x1max = 0.0, x3max = 0.0;
2804 const double agiant = LM_SQRT_GIANT / ((double)n);
2806 for (
int i = 0; i < n; i++) {
2807 double xabs = fabs(x[i]);
2808 if (xabs > LM_SQRT_DWARF && xabs < agiant) {
2814 if (xabs > LM_SQRT_DWARF) {
2817 s1 = 1 + s1 * SQR(x1max / xabs);
2820 s1 += SQR(xabs / x1max);
2826 s3 = 1 + s3 * SQR(x3max / xabs);
2830 s3 += SQR(xabs / x3max);
2837 if (s1 != 0)
return x1max * sqrt(s1 + (s2 / x1max) / x1max);
2839 if (s2 >= x3max)
return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
2840 return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
2843 return x3max * sqrt(s3);
2846double lat_gc_crosses_meridian(
double lat1,
double lon1,
double lat2,
2847 double lon2,
double lon) {
2853 double dlon = lon * DEGREE;
2854 double dlat1 = lat1 * DEGREE;
2855 double dlat2 = lat2 * DEGREE;
2856 double dlon1 = lon1 * DEGREE;
2857 double dlon2 = lon2 * DEGREE;
2859 return RADIAN * atan((sin(dlat1) * cos(dlat2) * sin(dlon - dlon2) -
2860 sin(dlat2) * cos(dlat1) * sin(dlon - dlon1)) /
2861 (cos(dlat1) * cos(dlat2) * sin(dlon1 - dlon2)));
2864double lat_rl_crosses_meridian(
double lat1,
double lon1,
double lat2,
2865 double lon2,
double lon) {
2873 DistanceBearingMercator(lat2, lon2, lat1, lon1, &brg, NULL);
2876 toSM(lat1, lon1, 0., lon, &x1, &y1);
2877 toSM(lat1, lon, 0., lon, &x, &y1);
2882 }
else if (brg >= 180.) {
2885 }
else if (brg >= 90.) {
2892 double ydelta = fabs(x1) * tan(brg * DEGREE);
2894 double crosslat, crosslon;
2895 fromSM(x, y1 + dir * ydelta, 0., lon, &crosslat, &crosslon);