OpenCPN Partial API docs
Loading...
Searching...
No Matches
georef.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
27#include <vector>
28#include <utility>
29#include <stdlib.h>
30#include <string.h>
31#include <ctype.h>
32#include <math.h>
33#include <algorithm>
34
35#include <wx/debug.h>
36
37#include "model/georef.h"
38#include "model/cutil.h"
39
40#ifdef __MSVC__
41#define snprintf mysnprintf
42#endif
43
44#if !defined(NAN)
45static const long long lNaN = 0xfff8000000000000;
46#define NAN (*(double *)&lNaN)
47#endif
48
49// ellipsoid: index into the gEllipsoid[] array, in which
50// a is the ellipsoid semimajor axis
51// invf is the inverse of the ellipsoid flattening f
52// dx, dy, dz: ellipsoid center with respect to WGS84 ellipsoid center
53// x axis is the prime meridian
54// y axis is 90 degrees east longitude
55// z axis is the axis of rotation of the ellipsoid
56
57// The following values for dx, dy and dz were extracted from the output of
58// the GARMIN PCX5 program. The output also includes values for da and df, the
59// difference between the reference ellipsoid and the WGS84 ellipsoid semi-
60// major axis and flattening, respectively. These are replaced by the
61// data contained in the structure array gEllipsoid[], which was obtained from
62// the Defence Mapping Agency document number TR8350.2, "Department of Defense
63// World Geodetic System 1984."
64
65struct DATUM const gDatum[] = {
66 // name ellipsoid dx dy dz
67 {"Adindan", 5, -162, -12, 206}, // 0
68 {"Afgooye", 15, -43, -163, 45}, // 1
69 {"Ain el Abd 1970", 14, -150, -251, -2}, // 2
70 {"Anna 1 Astro 1965", 2, -491, -22, 435}, // 3
71 {"Arc 1950", 5, -143, -90, -294}, // 4
72 {"Arc 1960", 5, -160, -8, -300}, // 5
73 {"Ascension Island 58", 14, -207, 107, 52}, // 6
74 {"Astro B4 Sorol Atoll", 14, 114, -116, -333}, // 7
75 {"Astro Beacon E ", 14, 145, 75, -272}, // 8
76 {"Astro DOS 71/4", 14, -320, 550, -494}, // 9
77 {"Astronomic Stn 52", 14, 124, -234, -25}, // 10
78 {"Australian Geod 66", 2, -133, -48, 148}, // 11
79 {"Australian Geod 84", 2, -134, -48, 149}, // 12
80 {"Bellevue (IGN)", 14, -127, -769, 472}, // 13
81 {"Bermuda 1957", 4, -73, 213, 296}, // 14
82 {"Bogota Observatory", 14, 307, 304, -318}, // 15
83 {"Campo Inchauspe", 14, -148, 136, 90}, // 16
84 {"Canton Astro 1966", 14, 298, -304, -375}, // 17
85 {"Cape", 5, -136, -108, -292}, // 18
86 {"Cape Canaveral", 4, -2, 150, 181}, // 19
87 {"Carthage", 5, -263, 6, 431}, // 20
88 {"CH-1903", 3, 674, 15, 405}, // 21
89 {"Chatham 1971", 14, 175, -38, 113}, // 22
90 {"Chua Astro", 14, -134, 229, -29}, // 23
91 {"Corrego Alegre", 14, -206, 172, -6}, // 24
92 {"Djakarta (Batavia)", 3, -377, 681, -50}, // 25
93 {"DOS 1968", 14, 230, -199, -752}, // 26
94 {"Easter Island 1967", 14, 211, 147, 111}, // 27
95 {"European 1950", 14, -87, -98, -121}, // 28
96 {"European 1979", 14, -86, -98, -119}, // 29
97 {"Finland Hayford", 14, -78, -231, -97}, // 30
98 {"Gandajika Base", 14, -133, -321, 50}, // 31
99 {"Geodetic Datum 49", 14, 84, -22, 209}, // 32
100 {"Guam 1963", 4, -100, -248, 259}, // 33
101 {"GUX 1 Astro", 14, 252, -209, -751}, // 34
102 {"Hermannskogel Datum", 3, 682, -203, 480}, // 35
103 {"Hjorsey 1955", 14, -73, 46, -86}, // 36
104 {"Hong Kong 1963", 14, -156, -271, -189}, // 37
105 {"Indian Bangladesh", 6, 289, 734, 257}, // 38
106 {"Indian Thailand", 6, 214, 836, 303}, // 39
107 {"Ireland 1965", 1, 506, -122, 611}, // 40
108 {"ISTS 073 Astro 69", 14, 208, -435, -229}, // 41
109 {"Johnston Island", 14, 191, -77, -204}, // 42
110 {"Kandawala", 6, -97, 787, 86}, // 43
111 {"Kerguelen Island", 14, 145, -187, 103}, // 44
112 {"Kertau 1948", 7, -11, 851, 5}, // 45
113 {"L.C. 5 Astro", 4, 42, 124, 147}, // 46
114 {"Liberia 1964", 5, -90, 40, 88}, // 47
115 {"Luzon Mindanao", 4, -133, -79, -72}, // 48
116 {"Luzon Philippines", 4, -133, -77, -51}, // 49
117 {"Mahe 1971", 5, 41, -220, -134}, // 50
118 {"Marco Astro", 14, -289, -124, 60}, // 51
119 {"Massawa", 3, 639, 405, 60}, // 52
120 {"Merchich", 5, 31, 146, 47}, // 53
121 {"Midway Astro 1961", 14, 912, -58, 1227}, // 54
122 {"Minna", 5, -92, -93, 122}, // 55
123 {"NAD27 Alaska", 4, -5, 135, 172}, // 56
124 {"NAD27 Bahamas", 4, -4, 154, 178}, // 57
125 {"NAD27 Canada", 4, -10, 158, 187}, // 58
126 {"NAD27 Canal Zone", 4, 0, 125, 201}, // 59
127 {"NAD27 Caribbean", 4, -7, 152, 178}, // 60
128 {"NAD27 Central", 4, 0, 125, 194}, // 61
129 {"NAD27 CONUS", 4, -8, 160, 176}, // 62
130 {"NAD27 Cuba", 4, -9, 152, 178}, // 63
131 {"NAD27 Greenland", 4, 11, 114, 195}, // 64
132 {"NAD27 Mexico", 4, -12, 130, 190}, // 65
133 {"NAD27 San Salvador", 4, 1, 140, 165}, // 66
134 {"NAD83", 11, 0, 0, 0}, // 67
135 {"Nahrwn Masirah Ilnd", 5, -247, -148, 369}, // 68
136 {"Nahrwn Saudi Arbia", 5, -231, -196, 482}, // 69
137 {"Nahrwn United Arab", 5, -249, -156, 381}, // 70
138 {"Naparima BWI", 14, -2, 374, 172}, // 71
139 {"Observatorio 1966", 14, -425, -169, 81}, // 72
140 {"Old Egyptian", 12, -130, 110, -13}, // 73
141 {"Old Hawaiian", 4, 61, -285, -181}, // 74
142 {"Oman", 5, -346, -1, 224}, // 75
143 {"Ord Srvy Grt Britn", 0, 375, -111, 431}, // 76
144 {"Pico De Las Nieves", 14, -307, -92, 127}, // 77
145 {"Pitcairn Astro 1967", 14, 185, 165, 42}, // 78
146 {"Prov So Amrican 56", 14, -288, 175, -376}, // 79
147 {"Prov So Chilean 63", 14, 16, 196, 93}, // 80
148 {"Puerto Rico", 4, 11, 72, -101}, // 81
149 {"Qatar National", 14, -128, -283, 22}, // 82
150 {"Qornoq", 14, 164, 138, -189}, // 83
151 {"Reunion", 14, 94, -948, -1262}, // 84
152 {"Rome 1940", 14, -225, -65, 9}, // 85
153 {"RT 90", 3, 498, -36, 568}, // 86
154 {"Santo (DOS)", 14, 170, 42, 84}, // 87
155 {"Sao Braz", 14, -203, 141, 53}, // 88
156 {"Sapper Hill 1943", 14, -355, 16, 74}, // 89
157 {"Schwarzeck", 21, 616, 97, -251}, // 90
158 {"South American 69", 16, -57, 1, -41}, // 91
159 {"South Asia", 8, 7, -10, -26}, // 92
160 {"Southeast Base", 14, -499, -249, 314}, // 93
161 {"Southwest Base", 14, -104, 167, -38}, // 94
162 {"Timbalai 1948", 6, -689, 691, -46}, // 95
163 {"Tokyo", 3, -128, 481, 664}, // 96
164 {"Tristan Astro 1968", 14, -632, 438, -609}, // 97
165 {"Viti Levu 1916", 5, 51, 391, -36}, // 98
166 {"Wake-Eniwetok 60", 13, 101, 52, -39}, // 99
167 {"WGS 72", 19, 0, 0, 5}, // 100
168 {"WGS 84", 20, 0, 0, 0}, // 101
169 {"Zanderij", 14, -265, 120, -358}, // 102
170 {"WGS_84", 20, 0, 0, 0}, // 103
171 {"WGS-84", 20, 0, 0, 0}, // 104
172 {"EUROPEAN DATUM 1950", 14, -87, -98, -121},
173 {"European 1950 (Norway Finland)", 14, -87, -98, -121},
174 {"ED50", 14, -87, -98, -121},
175 {"RT90 (Sweden)", 3, 498, -36, 568},
176 {"Monte Mario 1940", 14, -104, -49, 10},
177 {"Ord Surv of Gr Britain 1936", 0, 375, -111, 431},
178 {"South American 1969", 16, -57, 1, -41},
179 {"PULKOVO 1942 (2)", 15, 25, -141, -79},
180 {"EUROPEAN DATUM", 14, -87, -98, -121},
181 {"BERMUDA DATUM 1957", 4, -73, 213, 296},
182 {"COA", 14, -206, 172, -6},
183 {"COABR", 14, -206, 172, -6},
184 {"Roma 1940", 14, -225, -65, 9},
185 {"ITALIENISCHES LANDESNETZ", 14, -87, -98, -121},
186 {"HERMANSKOGEL DATUM", 3, 682, -203, 480},
187 {"AGD66", 2, -128, -52, 153},
188 {"ED", 14, -87, -98, -121},
189 {"EUROPEAN 1950 (SPAIN AND PORTUGAL)", 14, -87, -98, -121},
190 {"ED-50", 14, -87, -98, -121},
191 {"EUROPEAN", 14, -87, -98, -121},
192 {"POTSDAM", 14, -87, -98, -121},
193 {"GRACIOSA SW BASE DATUM", 14, -104, 167, -38},
194 {"WGS 1984", 20, 0, 0, 0},
195 {"WGS 1972", 19, 0, 0, 5},
196 {"WGS", 19, 0, 0, 5}
197
198};
199struct ELLIPSOID const gEllipsoid[] = {
200 // name a 1/f
201 {"Airy 1830", 6377563.396, 299.3249646}, // 0
202 {"Modified Airy", 6377340.189, 299.3249646}, // 1
203 {"Australian National", 6378160.0, 298.25}, // 2
204 {"Bessel 1841", 6377397.155, 299.1528128}, // 3
205 {"Clarke 1866", 6378206.4, 294.9786982}, // 4
206 {"Clarke 1880", 6378249.145, 293.465}, // 5
207 {"Everest (India 1830)", 6377276.345, 300.8017}, // 6
208 {"Everest (1948)", 6377304.063, 300.8017}, // 7
209 {"Modified Fischer 1960", 6378155.0, 298.3}, // 8
210 {"Everest (Pakistan)", 6377309.613, 300.8017}, // 9
211 {"Indonesian 1974", 6378160.0, 298.247}, // 10
212 {"GRS 80", 6378137.0, 298.257222101}, // 11
213 {"Helmert 1906", 6378200.0, 298.3}, // 12
214 {"Hough 1960", 6378270.0, 297.0}, // 13
215 {"International 1924", 6378388.0, 297.0}, // 14
216 {"Krassovsky 1940", 6378245.0, 298.3}, // 15
217 {"South American 1969", 6378160.0, 298.25}, // 16
218 {"Everest (Malaysia 1969)", 6377295.664, 300.8017}, // 17
219 {"Everest (Sabah Sarawak)", 6377298.556, 300.8017}, // 18
220 {"WGS 72", 6378135.0, 298.26}, // 19
221 {"WGS 84", 6378137.0, 298.257223563}, // 20
222 {"Bessel 1841 (Namibia)", 6377483.865, 299.1528128}, // 21
223 {"Everest (India 1956)", 6377301.243, 300.8017}, // 22
224 {"Struve 1860", 6378298.3, 294.73} // 23
225
226};
227
228short nDatums = sizeof(gDatum) / sizeof(struct DATUM);
229
230/* define constants */
231
232void datumParams(short datum, double *a, double *es) {
233 extern struct DATUM const gDatum[];
234 extern struct ELLIPSOID const gEllipsoid[];
235
236 if (datum < nDatums) {
237 double f = 1.0 / gEllipsoid[gDatum[datum].ellipsoid].invf; // flattening
238 if (es) *es = 2 * f - f * f; // eccentricity^2
239 if (a) *a = gEllipsoid[gDatum[datum].ellipsoid].a; // semimajor axis
240 } else {
241 double f = 1.0 / 298.257223563; // WGS84
242 if (es) *es = 2 * f - f * f;
243 if (a) *a = 6378137.0;
244 }
245}
246
247static int datumNameCmp(const char *n1, const char *n2) {
248 while (*n1 || *n2) {
249 if (*n1 == ' ')
250 n1++;
251 else if (*n2 == ' ')
252 n2++;
253 else if (toupper(*n1) == toupper(*n2))
254 n1++, n2++;
255 else
256 return 1; // No string match
257 }
258 return 0; // String match
259}
260static int isWGS84(int i) {
261 // DATUM_INDEX_WGS84 is an optimization
262 // but there's more than on in gDatum table
263 if (i == DATUM_INDEX_WGS84) return i;
264
265 if (gDatum[i].ellipsoid != gDatum[DATUM_INDEX_WGS84].ellipsoid) return i;
266
267 if (gDatum[i].dx != gDatum[DATUM_INDEX_WGS84].dx) return i;
268
269 if (gDatum[i].dy != gDatum[DATUM_INDEX_WGS84].dy) return i;
270
271 if (gDatum[i].dz != gDatum[DATUM_INDEX_WGS84].dz) return i;
272
273 return DATUM_INDEX_WGS84;
274}
275
276int GetDatumIndex(const char *str) {
277 int i = 0;
278 while (i < (int)nDatums) {
279 if (!datumNameCmp(str, gDatum[i].name)) {
280 return isWGS84(i);
281 }
282 i++;
283 }
284
285 return -1;
286}
287
288/****************************************************************************/
289/* Convert degrees to dd mm'ss.s" (DMS-Format) */
290/****************************************************************************/
291void toDMS(double a, char *bufp, int bufplen) {
292 bool neg = a < 0.0;
293 a = fabs(a);
294 int n = (int)((a - (int)a) * 36000.0);
295 int m = n / 600;
296 int s = n % 600;
297 sprintf(bufp, "%d%02d'%02d.%01d\"", (int)(neg ? -a : a), m, s / 10, s % 10);
298}
299
300/****************************************************************************/
301/* Convert dd mm'ss.s" (DMS-Format) to degrees. */
302/****************************************************************************/
303
304double fromDMS(char *dms) {
305 int d = 0, m = 0;
306 double s = 0.0;
307 char buf[20] = {'\0'};
308
309 sscanf(dms, "%d%[ ]%d%[ ']%lf%[ \"NSWEnswe]", &d, buf, &m, buf, &s, buf);
310
311 s = (double)(abs(d)) + ((double)m + s / 60.0) / 60.0;
312
313 if (d >= 0 && strpbrk(buf, "SWsw") == NULL) return s;
314
315 return -s;
316}
317
318/****************************************************************************/
319/* Convert degrees to dd mm.mmm' (DMM-Format) */
320/****************************************************************************/
321
322void todmm(int flag, double a, char *bufp, int bufplen) {
323 bool bNeg = a < 0.0;
324 a = fabs(a);
325
326 int m = (int)((a - (int)a) * 60000.0);
327
328 if (!flag)
329 snprintf(bufp, bufplen, "%d %02d.%03d'", (int)a, m / 1000, m % 1000);
330 else {
331 if (flag == 1) {
332 snprintf(bufp, bufplen, "%02d %02d.%03d %c", (int)a, m / 1000, (m % 1000),
333 bNeg ? 'S' : 'N');
334 } else if (flag == 2) {
335 snprintf(bufp, bufplen, "%03d %02d.%03d %c", (int)a, m / 1000, (m % 1000),
336 bNeg ? 'W' : 'E');
337 }
338 }
339}
340
341void toDMM(double a, char *bufp, int bufplen) {
342 todmm(0, a, bufp, bufplen);
343 return;
344}
345
346/* ---------------------------------------------------------------------------------
347 */
348/****************************************************************************/
349/* Convert Lat/Lon <-> Simple Mercator */
350/****************************************************************************/
351void toSM(double lat, double lon, double lat0, double lon0, double *x,
352 double *y) {
353 double xlon = lon;
354
355 /* Make sure lon and lon0 are same phase */
356
357 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
358 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
359 }
360
361 const double z = WGS84_semimajor_axis_meters * mercator_k0;
362
363 *x = (xlon - lon0) * DEGREE * z;
364
365 // y =.5 ln( (1 + sin t) / (1 - sin t) )
366 const double s = sin(lat * DEGREE);
367 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
368
369 const double s0 = sin(lat0 * DEGREE);
370 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
371 *y = y3 - y30;
372}
373
374double toSMcache_y30(double lat0) {
375 const double z = WGS84_semimajor_axis_meters * mercator_k0;
376 const double s0 = sin(lat0 * DEGREE);
377 const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
378 return y30;
379}
380
381void toSMcache(double lat, double lon, double y30, double lon0, double *x,
382 double *y) {
383 double xlon = lon;
384
385 /* Make sure lon and lon0 are same phase */
386
387 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.)) {
388 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
389 }
390
391 const double z = WGS84_semimajor_axis_meters * mercator_k0;
392
393 *x = (xlon - lon0) * DEGREE * z;
394
395 // y =.5 ln( (1 + sin t) / (1 - sin t) )
396 const double s = sin(lat * DEGREE);
397 const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
398
399 *y = y3 - y30;
400}
401
402void fromSM(double x, double y, double lat0, double lon0, double *lat,
403 double *lon) {
404 const double z = WGS84_semimajor_axis_meters * mercator_k0;
405
406 // lat = arcsin((e^2(y+y0) - 1)/(e^2(y+y0) + 1))
407 /*
408 double s0 = sin(lat0 * DEGREE);
409 double y0 = (.5 * log((1 + s0) / (1 - s0))) * z;
410
411 double e = exp(2 * (y0 + y) / z);
412 double e11 = (e - 1)/(e + 1);
413 double lat2 =(atan2(e11, sqrt(1 - e11 * e11))) / DEGREE;
414 */
415 // which is the same as....
416
417 const double s0 = sin(lat0 * DEGREE);
418 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * z;
419
420 *lat = (2.0 * atan(exp((y0 + y) / z)) - PI / 2.) / DEGREE;
421
422 // lon = x + lon0
423 *lon = lon0 + (x / (DEGREE * z));
424}
425
426void fromSMR(double x, double y, double lat0, double lon0, double axis_meters,
427 double *lat, double *lon) {
428 const double s0 = sin(lat0 * DEGREE);
429 const double y0 = (.5 * log((1 + s0) / (1 - s0))) * axis_meters;
430
431 *lat = (2.0 * atan(exp((y0 + y) / axis_meters)) - PI / 2.) / DEGREE;
432
433 // lon = x + lon0
434 *lon = lon0 + (x / (DEGREE * axis_meters));
435}
436
437void toSM_ECC(double lat, double lon, double lat0, double lon0, double *x,
438 double *y) {
439 const double f = 1.0 / WGSinvf; // WGS84 ellipsoid flattening parameter
440 const double e2 = 2 * f - f * f; // eccentricity^2 .006700
441 const double e = sqrt(e2);
442
443 const double z = WGS84_semimajor_axis_meters * mercator_k0;
444
445 *x = (lon - lon0) * DEGREE * z;
446
447 // y =.5 ln( (1 + sin t) / (1 - sin t) )
448 const double s = sin(lat * DEGREE);
449 // const double y3 = (.5 * log((1 + s) / (1 - s))) * z;
450
451 const double s0 = sin(lat0 * DEGREE);
452 // const double y30 = (.5 * log((1 + s0) / (1 - s0))) * z;
453
454 // Add eccentricity terms
455
456 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
457 pow((1. - e * s0) / (1. + e * s0), e / 2.));
458 const double test = z * log(tan(PI / 4 + lat * DEGREE / 2) *
459 pow((1. - e * s) / (1. + e * s), e / 2.));
460 *y = test - falsen;
461}
462
463void fromSM_ECC(double x, double y, double lat0, double lon0, double *lat,
464 double *lon) {
465 const double f = 1.0 / WGSinvf; // WGS84 ellipsoid flattening parameter
466 const double es = 2 * f - f * f; // eccentricity^2 .006700
467 const double e = sqrt(es);
468
469 const double z = WGS84_semimajor_axis_meters * mercator_k0;
470
471 *lon = lon0 + (x / (DEGREE * z));
472
473 const double s0 = sin(lat0 * DEGREE);
474
475 const double falsen = z * log(tan(PI / 4 + lat0 * DEGREE / 2) *
476 pow((1. - e * s0) / (1. + e * s0), e / 2.));
477 const double t = exp((y + falsen) / (z));
478 const double xi = (PI / 2.) - 2.0 * atan(t);
479
480 // Add eccentricity terms
481
482 double esf = (es / 2. + (5 * es * es / 24.) + (es * es * es / 12.) +
483 (13.0 * es * es * es * es / 360.)) *
484 sin(2 * xi);
485 esf += ((7. * es * es / 48.) + (29. * es * es * es / 240.) +
486 (811. * es * es * es * es / 11520.)) *
487 sin(4. * xi);
488 esf += ((7. * es * es * es / 120.) + (81 * es * es * es * es / 1120.) +
489 (4279. * es * es * es * es / 161280.)) *
490 sin(8. * xi);
491
492 *lat = -(xi + esf) / DEGREE;
493}
494
495#define TOL 1e-10
496#define CONV 1e-10
497#define N_ITER 10
498#define I_ITER 20
499#define ITOL 1.e-12
500
501void toPOLY(double lat, double lon, double lat0, double lon0, double *x,
502 double *y) {
503 const double z = WGS84_semimajor_axis_meters * mercator_k0;
504
505 if (fabs((lat - lat0) * DEGREE) <= TOL) {
506 *x = (lon - lon0) * DEGREE * z;
507 *y = 0.;
508
509 } else {
510 const double E = (lon - lon0) * DEGREE * sin(lat * DEGREE);
511 const double cot = 1. / tan(lat * DEGREE);
512 *x = sin(E) * cot;
513 *y = (lat * DEGREE) - (lat0 * DEGREE) + cot * (1. - cos(E));
514
515 *x *= z;
516 *y *= z;
517 }
518
519 /*
520 if (fabs(lp.phi) <= TOL) { xy.x = lp.lam; xy.y = P->ml0; }
521 else {
522 cot = 1. / tan(lp.phi);
523 xy.x = sin(E = lp.lam * sin(lp.phi)) * cot;
524 xy.y = lp.phi - P->phi0 + cot * (1. - cos(E));
525 }
526 */
527}
528
529void fromPOLY(double x, double y, double lat0, double lon0, double *lat,
530 double *lon) {
531 const double z = WGS84_semimajor_axis_meters * mercator_k0;
532
533 double yp = y - (lat0 * DEGREE * z);
534 if (fabs(yp) <= TOL) {
535 *lon = lon0 + (x / (DEGREE * z));
536 *lat = lat0;
537 } else {
538 yp = y / z;
539 const double xp = x / z;
540
541 double lat3 = yp;
542 const double B = (xp * xp) + (yp * yp);
543 int i = N_ITER;
544 double dphi;
545 do {
546 double tp = tan(lat3);
547 dphi = (yp * (lat3 * tp + 1.) - lat3 - .5 * (lat3 * lat3 + B) * tp) /
548 ((lat3 - yp) / tp - 1.);
549 lat3 -= dphi;
550 } while (fabs(dphi) > CONV && --i);
551 if (!i) {
552 *lon = 0.;
553 *lat = 0.;
554 } else {
555 *lon = asin(xp * tan(lat3)) / sin(lat3);
556 *lon /= DEGREE;
557 *lon += lon0;
558
559 *lat = lat3 / DEGREE;
560 }
561 }
562}
563
564/****************************************************************************/
565/* Convert Lat/Lon <-> Transverse Mercator */
566/****************************************************************************/
567
568// converts lat/long to TM coords. Equations from USGS Bulletin 1532
569// East Longitudes are positive, West longitudes are negative.
570// North latitudes are positive, South latitudes are negative
571// Lat and Long are in decimal degrees.
572// Written by Chuck Gantz- chuck.gantz@globalstar.com
573// Adapted for opencpn by David S. Register
574
575void toTM(float lat, float lon, float lat0, float lon0, double *x, double *y) {
576 // constants for WGS-84
577 const double f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */
578 const double a = WGS84_semimajor_axis_meters;
579 const double k0 = 1.; /* Scaling factor */
580
581 const double eccSquared = 2 * f - f * f;
582 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
583 const double LatRad = lat * DEGREE;
584 const double LongOriginRad = lon0 * DEGREE;
585 const double LongRad = lon * DEGREE;
586
587 const double N = a / sqrt(1 - eccSquared * sin(LatRad) * sin(LatRad));
588 const double T = tan(LatRad) * tan(LatRad);
589 const double C = eccPrimeSquared * cos(LatRad) * cos(LatRad);
590 const double A = cos(LatRad) * (LongRad - LongOriginRad);
591
592 const double MM =
593 a *
594 ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
595 5 * eccSquared * eccSquared * eccSquared / 256) *
596 LatRad -
597 (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 +
598 45 * eccSquared * eccSquared * eccSquared / 1024) *
599 sin(2 * LatRad) +
600 (15 * eccSquared * eccSquared / 256 +
601 45 * eccSquared * eccSquared * eccSquared / 1024) *
602 sin(4 * LatRad) -
603 (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * LatRad));
604
605 *x = (k0 * N *
606 (A + (1 - T + C) * A * A * A / 6 +
607 (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A *
608 A / 120));
609
610 *y =
611 (k0 *
612 (MM + N * tan(LatRad) *
613 (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
614 (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A *
615 A * A * A * A * A / 720)));
616}
617
618/* ---------------------------------------------------------------------------------
619 */
620
621// converts TM coords to lat/long. Equations from USGS Bulletin 1532
622// East Longitudes are positive, West longitudes are negative.
623// North latitudes are positive, South latitudes are negative
624// Lat and Long are in decimal degrees
625// Written by Chuck Gantz- chuck.gantz@globalstar.com
626// Adapted for opencpn by David S. Register
627
628void fromTM(double x, double y, double lat0, double lon0, double *lat,
629 double *lon) {
630 const double rad2deg = 1. / DEGREE;
631 // constants for WGS-84
632
633 const double f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */
634 const double a = WGS84_semimajor_axis_meters;
635 const double k0 = 1.; /* Scaling factor */
636
637 const double eccSquared = 2 * f - f * f;
638
639 const double eccPrimeSquared = (eccSquared) / (1 - eccSquared);
640 const double e1 =
641 (1.0 - sqrt(1.0 - eccSquared)) / (1.0 + sqrt(1.0 - eccSquared));
642
643 const double MM = y / k0;
644 const double mu =
645 MM / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 -
646 5 * eccSquared * eccSquared * eccSquared / 256));
647
648 const double phi1Rad =
649 mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) +
650 (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) +
651 (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
652
653 const double N1 = a / sqrt(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad));
654 const double T1 = tan(phi1Rad) * tan(phi1Rad);
655 const double C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
656 const double R1 = a * (1 - eccSquared) /
657 pow(1 - eccSquared * sin(phi1Rad) * sin(phi1Rad), 1.5);
658 const double D = x / (N1 * k0);
659
660 *lat = phi1Rad -
661 (N1 * tan(phi1Rad) / R1) *
662 (D * D / 2 -
663 (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D *
664 D * D * D / 24 +
665 (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared -
666 3 * C1 * C1) *
667 D * D * D * D * D * D / 720);
668 *lat = lat0 + (*lat * rad2deg);
669
670 *lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 +
671 (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared +
672 24 * T1 * T1) *
673 D * D * D * D * D / 120) /
674 cos(phi1Rad);
675 *lon = lon0 + *lon * rad2deg;
676}
677
678/* orthographic, polar, stereographic, gnomonic and equirectangular projection
679 * routines, contributed by Sean D'Epagnier */
680/****************************************************************************/
681/* Convert Lat/Lon <-> Simple Polar */
682/****************************************************************************/
683void cache_phi0(double lat0, double *sin_phi0, double *cos_phi0) {
684 double phi0 = lat0 * DEGREE;
685 *sin_phi0 = sin(phi0);
686 *cos_phi0 = cos(phi0);
687}
688
689void toORTHO(double lat, double lon, double sin_phi0, double cos_phi0,
690 double lon0, double *x, double *y) {
691 const double z = WGS84_semimajor_axis_meters * mercator_k0;
692
693 double xlon = lon;
694 /* Make sure lon and lon0 are same phase */
695 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
696 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
697
698 double theta = (xlon - lon0) * DEGREE;
699 double phi = lat * DEGREE;
700 double cos_phi = cos(phi);
701
702 double vy = sin(phi), vz = cos(theta) * cos_phi;
703
704 if (vy * sin_phi0 + vz * cos_phi0 < 0) { // on the far side of the earth
705 *x = *y = NAN;
706 return;
707 }
708
709 double vx = sin(theta) * cos_phi;
710 double vw = vy * cos_phi0 - vz * sin_phi0;
711
712 *x = vx * z;
713 *y = vw * z;
714}
715
716void fromORTHO(double x, double y, double lat0, double lon0, double *lat,
717 double *lon) {
718 const double z = WGS84_semimajor_axis_meters * mercator_k0;
719
720 double vx = x / z;
721 double vw = y / z;
722
723 double phi0 = lat0 * DEGREE;
724 double d = 1 - vx * vx - vw * vw;
725
726 if (d < 0) { // position is outside of the earth
727 *lat = *lon = NAN;
728 return;
729 }
730
731 double sin_phi0 = sin(phi0), cos_phi0 = cos(phi0);
732 double vy = vw * cos_phi0 + sqrt(d) * sin_phi0;
733 double phi = asin(vy);
734
735 double vz = (vy * cos_phi0 - vw) / sin_phi0;
736 double theta = atan2(vx, vz);
737
738 *lat = phi / DEGREE;
739 *lon = theta / DEGREE + lon0;
740}
741
742double toPOLARcache_e(double lat0) {
743 double pole = lat0 > 0 ? 90 : -90;
744 return tan((pole - lat0) * DEGREE / 2);
745}
746
747void toPOLAR(double lat, double lon, double e, double lat0, double lon0,
748 double *x, double *y) {
749 const double z = WGS84_semimajor_axis_meters * mercator_k0;
750
751 double xlon = lon;
752 /* Make sure lon and lon0 are same phase */
753 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
754 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
755
756 double theta = (xlon - lon0) * DEGREE;
757 double pole = lat0 > 0 ? 90 : -90;
758
759 double d = tan((pole - lat) * DEGREE / 2);
760
761 *x = fabs(d) * sin(theta) * z;
762 *y = (e - d * cos(theta)) * z;
763}
764
765void fromPOLAR(double x, double y, double lat0, double lon0, double *lat,
766 double *lon) {
767 const double z = WGS84_semimajor_axis_meters * mercator_k0;
768 double pole = lat0 > 0 ? 90 : -90;
769
770 double e = tan((pole - lat0) * DEGREE / 2);
771
772 double xn = x / z;
773 double yn = e - y / z;
774 double d = sqrt(xn * xn + yn * yn);
775 if (pole < 0) // south polar (negative root and correct branch from cosine)
776 d = -d, yn = -yn;
777
778 *lat = pole - atan(d) * 2 / DEGREE;
779
780 double theta = atan2(xn, yn);
781 *lon = theta / DEGREE + lon0;
782}
783
784static inline void toSTEREO1(double &u, double &v, double &w, double lat,
785 double lon, double sin_phi0, double cos_phi0,
786 double lon0) {
787 double xlon = lon;
788 /* Make sure lon and lon0 are same phase */
789 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
790 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
791
792 double theta = (xlon - lon0) * DEGREE, phi = lat * DEGREE;
793 double cos_phi = cos(phi), v0 = sin(phi), w0 = cos(theta) * cos_phi;
794
795 u = sin(theta) * cos_phi;
796 v = cos_phi0 * v0 - sin_phi0 * w0;
797 w = sin_phi0 * v0 + cos_phi0 * w0;
798}
799
800static inline void fromSTEREO1(double *lat, double *lon, double lat0,
801 double lon0, double u, double v, double w) {
802 double phi0 = lat0 * DEGREE;
803 double v0 = sin(phi0) * w + cos(phi0) * v;
804 double w0 = cos(phi0) * w - sin(phi0) * v;
805 double phi = asin(v0);
806 double theta = atan2(u, w0);
807
808 *lat = phi / DEGREE;
809 *lon = theta / DEGREE + lon0;
810}
811
812void toSTEREO(double lat, double lon, double sin_phi0, double cos_phi0,
813 double lon0, double *x, double *y) {
814 const double z = WGS84_semimajor_axis_meters * mercator_k0;
815
816 double u, v, w;
817 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
818
819 double t = 2 / (w + 1);
820 *x = u * t * z;
821 *y = v * t * z;
822}
823
824void fromSTEREO(double x, double y, double lat0, double lon0, double *lat,
825 double *lon) {
826 const double z = WGS84_semimajor_axis_meters * mercator_k0;
827
828 x /= z, y /= z;
829
830 double t = (x * x + y * y) / 4 + 1;
831
832 double u = x / t;
833 double v = y / t;
834 double w = 2 / t - 1;
835
836 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
837}
838
839void toGNO(double lat, double lon, double sin_phi0, double cos_phi0,
840 double lon0, double *x, double *y) {
841 const double z = WGS84_semimajor_axis_meters * mercator_k0;
842
843 double u, v, w;
844 toSTEREO1(u, v, w, lat, lon, sin_phi0, cos_phi0, lon0);
845
846 if (w <= 0) {
847 *x = *y = NAN; // far side of world
848 return;
849 }
850
851 *x = u / w * z;
852 *y = v / w * z;
853}
854
855void fromGNO(double x, double y, double lat0, double lon0, double *lat,
856 double *lon) {
857 const double z = WGS84_semimajor_axis_meters * mercator_k0;
858
859 x /= z, y /= z;
860
861 double w = 1 / sqrt(x * x + y * y + 1);
862 double u = x * w;
863 double v = y * w;
864
865 fromSTEREO1(lat, lon, lat0, lon0, u, v, w);
866}
867
868void toEQUIRECT(double lat, double lon, double lat0, double lon0, double *x,
869 double *y) {
870 const double z = WGS84_semimajor_axis_meters * mercator_k0;
871 double xlon = lon;
872 /* Make sure lon and lon0 are same phase */
873 if ((lon * lon0 < 0.) && (fabs(lon - lon0) > 180.))
874 lon < 0.0 ? xlon += 360.0 : xlon -= 360.0;
875
876 *x = (xlon - lon0) * DEGREE * z;
877 *y = (lat - lat0) * DEGREE * z;
878}
879
880void fromEQUIRECT(double x, double y, double lat0, double lon0, double *lat,
881 double *lon) {
882 const double z = WGS84_semimajor_axis_meters * mercator_k0;
883
884 *lat = lat0 + (y / (DEGREE * z));
885 // if(fabs(*lat) > 90) *lat = NAN;
886 *lon = lon0 + (x / (DEGREE * z));
887}
888
889/* ---------------------------------------------------------------------------------
890 *
891
892 *Molodensky
893 *In the listing below, the class GeodeticPosition has three members, lon, lat,
894 and h. *They are double-precision values indicating the longitude and latitude
895 in radians,
896 * and height in meters above the ellipsoid.
897
898 * The source code in the listing below may be copied and reused without
899 restriction,
900 * but it is offered AS-IS with NO WARRANTY.
901
902 * Adapted for opencpn by David S. Register
903
904 * --------------------------------------------------------------------------------- */
905
906void MolodenskyTransform(double lat, double lon, double *to_lat, double *to_lon,
907 int from_datum_index, int to_datum_index) {
908 double dlat = 0;
909 double dlon = 0;
910
911 if (from_datum_index < nDatums) {
912 const double from_lat = lat * DEGREE;
913 const double from_lon = lon * DEGREE;
914 const double from_f =
915 1.0 /
916 gEllipsoid[gDatum[from_datum_index].ellipsoid].invf; // flattening
917 const double from_esq = 2 * from_f - from_f * from_f; // eccentricity^2
918 const double from_a =
919 gEllipsoid[gDatum[from_datum_index].ellipsoid].a; // semimajor axis
920 const double dx = gDatum[from_datum_index].dx;
921 const double dy = gDatum[from_datum_index].dy;
922 const double dz = gDatum[from_datum_index].dz;
923 const double to_f =
924 1.0 / gEllipsoid[gDatum[to_datum_index].ellipsoid].invf; // flattening
925 const double to_a =
926 gEllipsoid[gDatum[to_datum_index].ellipsoid].a; // semimajor axis
927 const double da = to_a - from_a;
928 const double df = to_f - from_f;
929 const double from_h = 0;
930
931 const double slat = sin(from_lat);
932 const double clat = cos(from_lat);
933 const double slon = sin(from_lon);
934 const double clon = cos(from_lon);
935 const double ssqlat = slat * slat;
936 const double adb = 1.0 / (1.0 - from_f); // "a divided by b"
937
938 const double rn = from_a / sqrt(1.0 - from_esq * ssqlat);
939 const double rm =
940 from_a * (1. - from_esq) / pow((1.0 - from_esq * ssqlat), 1.5);
941
942 dlat = (((((-dx * slat * clon - dy * slat * slon) + dz * clat) +
943 (da * ((rn * from_esq * slat * clat) / from_a))) +
944 (df * (rm * adb + rn / adb) * slat * clat))) /
945 (rm + from_h);
946
947 dlon = (-dx * slon + dy * clon) / ((rn + from_h) * clat);
948 }
949
950 *to_lon = lon + dlon / DEGREE;
951 *to_lat = lat + dlat / DEGREE;
952 //
953 return;
954}
955
956/* ---------------------------------------------------------------------------------
957 */
958/*
959 Geodesic Forward and Reverse calculation functions
960 Abstracted and adapted from PROJ-4.5.0 by David S.Register
961
962 Original source code contains the following license:
963
964 Copyright (c) 2000, Frank Warmerdam
965
966 Permission is hereby granted, free of charge, to any person obtaining a
967 copy of this software and associated documentation files (the "Software"),
968 to deal in the Software without restriction, including without limitation
969 the rights to use, copy, modify, merge, publish, distribute, sublicense,
970 and/or sell copies of the Software, and to permit persons to whom the
971 Software is furnished to do so, subject to the following conditions:
972
973 The above copyright notice and this permission notice shall be included
974 in all copies or substantial portions of the Software.
975
976 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
977 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
978 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
979 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
980 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
981 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
982 DEALINGS IN THE SOFTWARE.
983*/
984/* ---------------------------------------------------------------------------------
985 */
986
987#define DTOL 1e-12
988
989#define HALFPI 1.5707963267948966
990#define SPI 3.14159265359
991#define TWOPI 6.2831853071795864769
992#define ONEPI 3.14159265358979323846
993#define MERI_TOL 1e-9
994
995double adjlon(double lon) {
996 if (fabs(lon) <= SPI) return (lon);
997 lon += ONEPI; /* adjust to 0..2pi rad */
998 lon -= TWOPI * floor(lon / TWOPI); /* remove integral # of 'revolutions'*/
999 lon -= ONEPI; /* adjust back to -pi..pi rad */
1000 return (lon);
1001}
1002
1003/* ---------------------------------------------------------------------------------
1004 */
1005/*
1006// Given the lat/long of starting point, and traveling a specified distance,
1007// at an initial bearing, calculates the lat/long of the resulting location.
1008// using sphere earth model.
1009*/
1010/* ---------------------------------------------------------------------------------
1011 */
1012void ll_gc_ll(double lat, double lon, double brg, double dist, double *dlat,
1013 double *dlon) {
1014 double th1, costh1, sinth1, sina12, cosa12, M, N, c1, c2, D, P, s1;
1015 int merid, signS;
1016
1017 if ((brg == 90.) || (brg == 180.)) {
1018 brg += 1e-9;
1019 }
1020
1021 /* Input/Output from geodesic functions */
1022 double al12; /* Forward azimuth */
1023 double al21; /* Back azimuth */
1024 double geod_S; /* Distance */
1025 double phi1, lam1, phi2, lam2;
1026
1027 int ellipse;
1028 double geod_f;
1029 double geod_a;
1030 double es, onef, f, f4;
1031
1032 /* Setup the static parameters */
1033 phi1 = lat * DEGREE; /* Initial Position */
1034 lam1 = lon * DEGREE;
1035 al12 = brg * DEGREE; /* Forward azimuth */
1036 geod_S = dist * 1852.0; /* Distance */
1037
1038 // void geod_pre(struct georef_state *state)
1039 {
1040 /* Stuff the WGS84 projection parameters as necessary
1041 * To avoid having to include <geodesic,h>
1042 */
1043 ellipse = 1;
1044 f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */
1045 geod_a = WGS84_semimajor_axis_meters;
1046
1047 es = 2 * f - f * f;
1048 onef = sqrt(1. - es);
1049 geod_f = 1 - onef;
1050 f4 = geod_f / 4;
1051
1052 al12 = adjlon(al12); /* reduce to +- 0-PI */
1053 signS = fabs(al12) > HALFPI ? 1 : 0;
1054 th1 = ellipse ? atan(onef * tan(phi1)) : phi1;
1055 costh1 = cos(th1);
1056 sinth1 = sin(th1);
1057 if ((merid = fabs(sina12 = sin(al12)) < MERI_TOL)) {
1058 sina12 = 0.;
1059 cosa12 = fabs(al12) < HALFPI ? 1. : -1.;
1060 M = 0.;
1061 } else {
1062 cosa12 = cos(al12);
1063 M = costh1 * sina12;
1064 }
1065 N = costh1 * cosa12;
1066 if (ellipse) {
1067 if (merid) {
1068 c1 = 0.;
1069 c2 = f4;
1070 D = 1. - c2;
1071 D *= D;
1072 P = c2 / D;
1073 } else {
1074 c1 = geod_f * M;
1075 c2 = f4 * (1. - M * M);
1076 D = (1. - c2) * (1. - c2 - c1 * M);
1077 P = (1. + .5 * c1 * M) * c2 / D;
1078 }
1079 }
1080 if (merid)
1081 s1 = HALFPI - th1;
1082 else {
1083 s1 = (fabs(M) >= 1.) ? 0. : acos(M);
1084 s1 = sinth1 / sin(s1);
1085 s1 = (fabs(s1) >= 1.) ? 0. : acos(s1);
1086 }
1087 }
1088
1089 // void geod_for(struct georef_state *state)
1090 {
1091 double d, sind, u, V, X, ds, cosds, sinds, ss, de;
1092
1093 ss = 0.;
1094
1095 if (ellipse) {
1096 d = geod_S / (D * geod_a);
1097 if (signS) d = -d;
1098 u = 2. * (s1 - d);
1099 V = cos(u + d);
1100 X = c2 * c2 * (sind = sin(d)) * cos(d) * (2. * V * V - 1.);
1101 ds = d + X - 2. * P * V * (1. - 2. * P * cos(u)) * sind;
1102 ss = s1 + s1 - ds;
1103 } else {
1104 ds = geod_S / geod_a;
1105 if (signS) ds = -ds;
1106 }
1107 cosds = cos(ds);
1108 sinds = sin(ds);
1109 if (signS) sinds = -sinds;
1110 al21 = N * cosds - sinth1 * sinds;
1111 if (merid) {
1112 phi2 = atan(tan(HALFPI + s1 - ds) / onef);
1113 if (al21 > 0.) {
1114 al21 = PI;
1115 if (signS)
1116 de = PI;
1117 else {
1118 phi2 = -phi2;
1119 de = 0.;
1120 }
1121 } else {
1122 al21 = 0.;
1123 if (signS) {
1124 phi2 = -phi2;
1125 de = 0;
1126 } else
1127 de = PI;
1128 }
1129 } else {
1130 al21 = atan(M / al21);
1131 if (al21 > 0) al21 += PI;
1132 if (al12 < 0.) al21 -= PI;
1133 al21 = adjlon(al21);
1134 phi2 = atan(-(sinth1 * cosds + N * sinds) * sin(al21) /
1135 (ellipse ? onef * M : M));
1136 de = atan2(sinds * sina12, (costh1 * cosds - sinth1 * sinds * cosa12));
1137 if (ellipse) {
1138 if (signS)
1139 de += c1 * ((1. - c2) * ds + c2 * sinds * cos(ss));
1140 else
1141 de -= c1 * ((1. - c2) * ds - c2 * sinds * cos(ss));
1142 }
1143 }
1144 lam2 = adjlon(lam1 + de);
1145 }
1146
1147 *dlat = phi2 / DEGREE;
1148 *dlon = lam2 / DEGREE;
1149}
1150
1151void ll_gc_ll_reverse(double lat1, double lon1, double lat2, double lon2,
1152 double *bearing, double *dist) {
1153 // For small distances do an ordinary mercator calc. (To prevent return of
1154 // nan's )
1155 if ((fabs(lon2 - lon1) < 0.1) && (fabs(lat2 - lat1) < 0.1)) {
1156 DistanceBearingMercator(lat2, lon2, lat1, lon1, bearing, dist);
1157 return;
1158 } else {
1159 /* Input/Output from geodesic functions */
1160 double al12; /* Forward azimuth */
1161 double al21; /* Back azimuth */
1162 double geod_S; /* Distance */
1163 double phi1, lam1, phi2, lam2;
1164
1165 int ellipse;
1166 double geod_f;
1167 double geod_a;
1168 double es, onef, f, f64, f2, f4;
1169
1170 /* Setup the static parameters */
1171 phi1 = lat1 * DEGREE; /* Initial Position */
1172 lam1 = lon1 * DEGREE;
1173 phi2 = lat2 * DEGREE;
1174 lam2 = lon2 * DEGREE;
1175
1176 // void geod_inv(struct georef_state *state)
1177 {
1178 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm,
1179 cosdthm, sindthm, L, E, cosd, d, X, Y, T, sind, tandlammp, u, v, D, A,
1180 B;
1181
1182 /* Stuff the WGS84 projection parameters as necessary
1183 * To avoid having to include <geodesic,h>
1184 */
1185
1186 ellipse = 1;
1187 f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */
1188 geod_a = WGS84_semimajor_axis_meters;
1189
1190 es = 2 * f - f * f;
1191 onef = sqrt(1. - es);
1192 geod_f = 1 - onef;
1193 f2 = geod_f / 2;
1194 f4 = geod_f / 4;
1195 f64 = geod_f * geod_f / 64;
1196
1197 if (ellipse) {
1198 th1 = atan(onef * tan(phi1));
1199 th2 = atan(onef * tan(phi2));
1200 } else {
1201 th1 = phi1;
1202 th2 = phi2;
1203 }
1204 thm = .5 * (th1 + th2);
1205 dthm = .5 * (th2 - th1);
1206 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1207 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1208 al12 = al21 = geod_S = 0.;
1209 if (bearing) *bearing = 0.;
1210 if (dist) *dist = 0.;
1211 return;
1212 }
1213 sindlamm = sin(dlamm);
1214 costhm = cos(thm);
1215 sinthm = sin(thm);
1216 cosdthm = cos(dthm);
1217 sindthm = sin(dthm);
1218 L = sindthm * sindthm +
1219 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1220 d = acos(cosd = 1 - L - L);
1221 if (ellipse) {
1222 E = cosd + cosd;
1223 sind = sin(d);
1224 Y = sinthm * cosdthm;
1225 Y *= (Y + Y) / (1. - L);
1226 T = sindthm * costhm;
1227 T *= (T + T) / L;
1228 X = Y + T;
1229 Y -= T;
1230 T = d / sind;
1231 D = 4. * T * T;
1232 A = D * E;
1233 B = D + D;
1234 geod_S = geod_a * sind *
1235 (T - f4 * (T * X - Y) +
1236 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1237 D * X * Y));
1238 tandlammp =
1239 tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X)) *
1240 (f2 * T + f64 * (32. * T - (20. * T - A) * X -
1241 (B + 4.) * Y)) *
1242 tan(dlam)));
1243 } else {
1244 geod_S = geod_a * d;
1245 tandlammp = tan(dlamm);
1246 }
1247 u = atan2(sindthm, (tandlammp * costhm));
1248 v = atan2(cosdthm, (tandlammp * sinthm));
1249 al12 = adjlon(TWOPI + v - u);
1250 al21 = adjlon(TWOPI - v - u);
1251 if (al12 < 0) al12 += 2 * PI;
1252 if (bearing) *bearing = al12 / DEGREE;
1253 if (dist) *dist = geod_S / 1852.0;
1254 }
1255 }
1256}
1257
1258void PositionBearingDistanceMercator(double lat, double lon, double brg,
1259 double dist, double *dlat, double *dlon) {
1260 ll_gc_ll(lat, lon, brg, dist, dlat, dlon);
1261}
1262
1263double DistLoxodrome(double slat, double slon, double dlat, double dlon) {
1264 double dist =
1265 60 * sqrt(pow(slat - dlat, 2) +
1266 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1267 // Crossing IDL or Greenwich?
1268 if (slon * dlon < 0) {
1269 if (slon < 0)
1270 slon += 360.;
1271 else if (dlon < 0)
1272 dlon += 360.;
1273 double distrtw =
1274 60 * sqrt(pow(slat - dlat, 2) +
1275 pow((slon - dlon) * cos((slat + dlat) / 2 * DEGREE), 2));
1276 return (std::min)(dist, distrtw);
1277 }
1278 return dist;
1279}
1280
1281/* ---------------------------------------------------------------------------------
1282 */
1283/*
1284// Given the lat/long of starting point and ending point,
1285// calculates the distance (in Nm) along a geodesic curve, using sphere earth
1286model.
1287*/
1288/* ---------------------------------------------------------------------------------
1289 */
1290
1291double DistGreatCircle(double slat, double slon, double dlat, double dlon) {
1292 double d5;
1293 d5 = DistLoxodrome(slat, slon, dlat, dlon);
1294 if (d5 < 10) // Miles
1295 return d5;
1296
1297 /* Input/Output from geodesic functions */
1298 // double al12; /* Forward azimuth */
1299 // double al21; /* Back azimuth */
1300 double geod_S; /* Distance */
1301 double phi1, lam1, phi2, lam2;
1302
1303 int ellipse;
1304 double geod_f;
1305 double geod_a;
1306 double es, onef, f, f64, f4;
1307
1308 phi1 = slat * DEGREE;
1309 lam1 = slon * DEGREE;
1310 phi2 = dlat * DEGREE;
1311 lam2 = dlon * DEGREE;
1312
1313 // void geod_inv(struct georef_state *state)
1314 {
1315 double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm, cosdthm,
1316 sindthm, L, E, cosd, d, X, Y, T, sind, D, A, B;
1317 // double tandlammp,u,v;
1318
1319 /* Stuff the WGS84 projection parameters as necessary
1320 * To avoid having to include <geodesic,h>
1321 */
1322
1323 ellipse = 0;
1324 f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */
1325 geod_a = WGS84_semimajor_axis_meters;
1326
1327 es = 2 * f - f * f;
1328 onef = sqrt(1. - es);
1329 geod_f = 1 - onef;
1330 // f2 = geod_f/2;
1331 f4 = geod_f / 4;
1332 f64 = geod_f * geod_f / 64;
1333
1334 if (ellipse) {
1335 th1 = atan(onef * tan(phi1));
1336 th2 = atan(onef * tan(phi2));
1337 } else {
1338 th1 = phi1;
1339 th2 = phi2;
1340 }
1341 thm = .5 * (th1 + th2);
1342 dthm = .5 * (th2 - th1);
1343 dlamm = .5 * (dlam = adjlon(lam2 - lam1));
1344 if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) {
1345 return 0.0;
1346 }
1347 sindlamm = sin(dlamm);
1348 costhm = cos(thm);
1349 sinthm = sin(thm);
1350 cosdthm = cos(dthm);
1351 sindthm = sin(dthm);
1352 L = sindthm * sindthm +
1353 (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm;
1354 d = acos(cosd = 1 - L - L);
1355
1356 if (ellipse) {
1357 E = cosd + cosd;
1358 sind = sin(d);
1359 Y = sinthm * cosdthm;
1360 Y *= (Y + Y) / (1. - L);
1361 T = sindthm * costhm;
1362 T *= (T + T) / L;
1363 X = Y + T;
1364 Y -= T;
1365 T = d / sind;
1366 D = 4. * T * T;
1367 A = D * E;
1368 B = D + D;
1369 geod_S = geod_a * sind *
1370 (T - f4 * (T * X - Y) +
1371 f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) +
1372 D * X * Y));
1373 // tandlammp = tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X))
1374 // *
1375 // (f2 * T + f64 * (32. * T - (20. * T - A)
1376 // * X - (B + 4.) * Y)) * tan(dlam)));
1377 } else {
1378 geod_S = geod_a * d;
1379 // tandlammp = tan(dlamm);
1380 }
1381 // u = atan2(sindthm , (tandlammp * costhm));
1382 // v = atan2(cosdthm , (tandlammp * sinthm));
1383 // al12 = adjlon(TWOPI + v - u);
1384 // al21 = adjlon(TWOPI - v - u);
1385 }
1386
1387 d5 = geod_S / 1852.0;
1388
1389 return d5;
1390}
1391
1392void DistanceBearingMercator(double lat1, double lon1, double lat0, double lon0,
1393 double *brg, double *dist) {
1394 // Calculate bearing and distance between two points
1395 double latm = (lat0 + lat1) / 2 * DEGREE; // median of latitude
1396 double delta_lat = (lat1 - lat0);
1397 double delta_lon = (lon1 - lon0);
1398 double ex_lat0, ex_lat1;
1399 double bearing, distance;
1400 // make sure we calc the shortest route, even if this across the date line.
1401 if (delta_lon < -180) delta_lon += 360;
1402 if (delta_lon > 180) delta_lon -= 360;
1403
1404 if (delta_lon == 0)
1405 bearing = .0; // delta lon = 0 so course is due N or S
1406 else if (fabs(delta_lat) != .0)
1407 bearing = atan(delta_lon * cos(latm) / delta_lat);
1408 else
1409 bearing = PI / 2; // delta lat = 0 so course must be E or W
1410
1411 distance = sqrt(pow(delta_lat, 2) + pow(delta_lon * cos(latm), 2));
1412
1413 if (distance >
1414 0.01745) // > 1 degree we use exaggerated latitude to be more exact
1415 {
1416 if (delta_lat != 0.) {
1417 ex_lat0 = 10800 / PI * log(tan(PI / 4 + lat0 * DEGREE / 2));
1418 ex_lat1 = 10800 / PI * log(tan(PI / 4 + lat1 * DEGREE / 2));
1419 bearing = atan(delta_lon * 60 / (ex_lat1 - ex_lat0));
1420 distance = fabs(delta_lat / cos(bearing));
1421 } else {
1422 bearing = PI / 2;
1423 }
1424 }
1425
1426 bearing = fabs(bearing);
1427 if (lat1 > lat0) {
1428 if (delta_lon < 0) bearing = 2 * PI - bearing;
1429 } // NW
1430 else {
1431 if (delta_lon > 0)
1432 bearing = PI - bearing; // SE
1433 else
1434 bearing = PI + bearing;
1435 } // SW
1436
1437 if (brg) *brg = bearing * RADIAN; // in degrees
1438 if (dist) *dist = distance * 60; // in NM
1439}
1440
1441/* ---------------------------------------------------------------------------------
1442 */
1443/*
1444 * lmfit
1445 *
1446 * Solves or minimizes the sum of squares of m nonlinear
1447 * functions of n variables.
1448 *
1449 * From public domain Fortran version
1450 * of Argonne National Laboratories MINPACK
1451 * argonne national laboratory. minpack project. march 1980.
1452 * burton s. garbow, kenneth e. hillstrom, jorge j. more
1453 * C translation by Steve Moshier
1454 * Joachim Wuttke converted the source into C++ compatible ANSI style
1455 * and provided a simplified interface
1456 */
1457
1458// #include "lmmin.h" // all moved to georef.h
1459#define _LMDIF
1460
1463
1464double my_fit_function(double tx, double ty, int n_par, double *p) {
1465 double ret = p[0] + p[1] * tx;
1466
1467 if (n_par > 2) ret += p[2] * ty;
1468 if (n_par > 3) {
1469 ret += p[3] * tx * tx;
1470 ret += p[4] * tx * ty;
1471 ret += p[5] * ty * ty;
1472 }
1473 if (n_par > 6) {
1474 ret += p[6] * tx * tx * tx;
1475 ret += p[7] * tx * tx * ty;
1476 ret += p[8] * tx * ty * ty;
1477 ret += p[9] * ty * ty * ty;
1478 }
1479
1480 return ret;
1481}
1482
1483int Georef_Calculate_Coefficients_Onedir(int n_points, int n_par, double *tx,
1484 double *ty, double *y, double *p,
1485 double hintp0, double hintp1,
1486 double hintp2)
1487/*
1488n_points : number of sample points
1489n_par : 3, 6, or 10, 6 is probably good
1490tx: sample data independent variable 1
1491ty: sample data independent variable 2
1492y: sample data dependent result
1493p: curve fit result coefficients
1494*/
1495{
1496 int i;
1497 lm_control_type control;
1498 lm_data_type data;
1499
1500 lm_initialize_control(&control);
1501
1502 for (i = 0; i < 12; i++) p[i] = 0.;
1503
1504 // memset(p, 0, 12 * sizeof(double));
1505
1506 // Insert hints
1507 p[0] = hintp0;
1508 p[1] = hintp1;
1509 p[2] = hintp2;
1510
1511 data.user_func = my_fit_function;
1512 data.user_tx = tx;
1513 data.user_ty = ty;
1514 data.user_y = y;
1515 data.n_par = n_par;
1516 data.print_flag = 0;
1517
1518 // perform the fit:
1519
1520 lm_minimize(n_points, n_par, p, lm_evaluate_default, lm_print_default, &data,
1521 &control);
1522
1523 // print results:
1524 // printf( "status: %s after %d evaluations\n",
1525 // lm_infmsg[control.info], control.nfev );
1526
1527 // Control.info results [1,2,3] are success, other failure
1528 return control.info;
1529}
1530
1531int Georef_Calculate_Coefficients(struct GeoRef *cp, int nlin_lon) {
1532 // Zero out the points
1533 for (int i = 0; i < 10; ++i)
1534 cp->pwx[i] = cp->pwy[i] = cp->wpx[i] = cp->wpy[i] = 0.0;
1535
1536 int mp = 3;
1537
1538 switch (cp->order) {
1539 case 1:
1540 mp = 3;
1541 break;
1542 case 2:
1543 mp = 6;
1544 break;
1545 case 3:
1546 mp = 10;
1547 break;
1548 default:
1549 mp = 3;
1550 break;
1551 }
1552
1553 const int mp_lat = mp;
1554
1555 // Force linear fit for longitude if nlin_lon > 0
1556 const int mp_lon = nlin_lon ? 2 : mp;
1557
1558 // Make a dummy double array
1559 std::vector<double> pnull(cp->count, 1.0);
1560
1561 // pixel(tx,ty) to (lat,lon)
1562 // Calculate and use a linear equation for p[0..2] to hint the solver
1563
1564 int r1 = Georef_Calculate_Coefficients_Onedir(
1565 cp->count, mp_lon, cp->tx, cp->ty, cp->lon, cp->pwx,
1566 cp->lonmin -
1567 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1568 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1569
1570 // if blin_lon > 0, force cross terms in latitude equation coefficients
1571 // to be zero by making lat not dependent on tx,
1572 double *px = nlin_lon ? &pnull[0] : cp->tx;
1573
1574 int r2 = Georef_Calculate_Coefficients_Onedir(
1575 cp->count, mp_lat, px, cp->ty, cp->lat, cp->pwy,
1576 cp->latmin -
1577 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1578 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1579
1580 // (lat,lon) to pixel(tx,ty)
1581 // Calculate and use a linear equation for p[0..2] to hint the solver
1582
1583 int r3 = Georef_Calculate_Coefficients_Onedir(
1584 cp->count, mp_lon, cp->lon, cp->lat, cp->tx, cp->wpx,
1585 cp->txmin -
1586 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1587 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1588
1589 // if blin_lon > 0, force cross terms in latitude equation coefficients
1590 // to be zero by making ty not dependent on lon,
1591 px = nlin_lon ? &pnull[0] : cp->lon;
1592
1593 int r4 = Georef_Calculate_Coefficients_Onedir(
1594 cp->count, mp_lat, &pnull[0] /*cp->lon*/, cp->lat, cp->ty, cp->wpy,
1595 cp->tymin -
1596 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1597 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1598
1599 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1600 (r4 < 4))
1601 return 0;
1602
1603 return 1;
1604}
1605
1606int Georef_Calculate_Coefficients_Proj(struct GeoRef *cp) {
1607 int r1, r2, r3, r4;
1608 int mp;
1609
1610 // Zero out the points
1611 cp->pwx[6] = cp->pwy[6] = cp->wpx[6] = cp->wpy[6] = 0.;
1612 cp->pwx[7] = cp->pwy[7] = cp->wpx[7] = cp->wpy[7] = 0.;
1613 cp->pwx[8] = cp->pwy[8] = cp->wpx[8] = cp->wpy[8] = 0.;
1614 cp->pwx[9] = cp->pwy[9] = cp->wpx[9] = cp->wpy[9] = 0.;
1615 cp->pwx[3] = cp->pwy[3] = cp->wpx[3] = cp->wpy[3] = 0.;
1616 cp->pwx[4] = cp->pwy[4] = cp->wpx[4] = cp->wpy[4] = 0.;
1617 cp->pwx[5] = cp->pwy[5] = cp->wpx[5] = cp->wpy[5] = 0.;
1618 cp->pwx[0] = cp->pwy[0] = cp->wpx[0] = cp->wpy[0] = 0.;
1619 cp->pwx[1] = cp->pwy[1] = cp->wpx[1] = cp->wpy[1] = 0.;
1620 cp->pwx[2] = cp->pwy[2] = cp->wpx[2] = cp->wpy[2] = 0.;
1621
1622 mp = 3;
1623
1624 // pixel(tx,ty) to (northing,easting)
1625 // Calculate and use a linear equation for p[0..2] to hint the solver
1626
1627 r1 = Georef_Calculate_Coefficients_Onedir(
1628 cp->count, mp, cp->tx, cp->ty, cp->lon, cp->pwx,
1629 cp->lonmin -
1630 (cp->txmin * (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin)),
1631 (cp->lonmax - cp->lonmin) / (cp->txmax - cp->txmin), 0.);
1632
1633 r2 = Georef_Calculate_Coefficients_Onedir(
1634 cp->count, mp, cp->tx, cp->ty, cp->lat, cp->pwy,
1635 cp->latmin -
1636 (cp->tymin * (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin)),
1637 0., (cp->latmax - cp->latmin) / (cp->tymax - cp->tymin));
1638
1639 // (northing/easting) to pixel(tx,ty)
1640 // Calculate and use a linear equation for p[0..2] to hint the solver
1641
1642 r3 = Georef_Calculate_Coefficients_Onedir(
1643 cp->count, mp, cp->lon, cp->lat, cp->tx, cp->wpx,
1644 cp->txmin -
1645 ((cp->txmax - cp->txmin) * cp->lonmin / (cp->lonmax - cp->lonmin)),
1646 (cp->txmax - cp->txmin) / (cp->lonmax - cp->lonmin), 0.0);
1647
1648 r4 = Georef_Calculate_Coefficients_Onedir(
1649 cp->count, mp, cp->lon, cp->lat, cp->ty, cp->wpy,
1650 cp->tymin -
1651 ((cp->tymax - cp->tymin) * cp->latmin / (cp->latmax - cp->latmin)),
1652 0.0, (cp->tymax - cp->tymin) / (cp->latmax - cp->latmin));
1653
1654 if ((r1) && (r1 < 4) && (r2) && (r2 < 4) && (r3) && (r3 < 4) && (r4) &&
1655 (r4 < 4))
1656 return 0;
1657 else
1658 return 1;
1659}
1660
1661/*
1662 * This file contains default implementation of the evaluate and printout
1663 * routines. In most cases, customization of lmfit can be done by modifying
1664 * these two routines. Either modify them here, or copy and rename them.
1665 */
1666
1667void lm_evaluate_default(double *par, int m_dat, double *fvec, void *data,
1668 int *info)
1669/*
1670 * par is an input array. At the end of the minimization, it contains
1671 * the approximate solution vector.
1672 *
1673 * m_dat is a positive integer input variable set to the number
1674 * of functions.
1675 *
1676 * fvec is an output array of length m_dat which contains the function
1677 * values the square sum of which ought to be minimized.
1678 *
1679 * data is a read-only pointer to lm_data_type, as specified by lmuse.h.
1680 *
1681 * info is an integer output variable. If set to a negative value, the
1682 * minimization procedure will stop.
1683 */
1684{
1685 lm_data_type *mydata = (lm_data_type *)data;
1686
1687 for (int i = 0; i < m_dat; i++) {
1688 fvec[i] = mydata->user_y[i] - mydata->user_func(mydata->user_tx[i],
1689 mydata->user_ty[i],
1690 mydata->n_par, par);
1691 }
1692 *info = *info; /* to prevent a 'unused variable' warning */
1693 /* if <parameters drifted away> { *info = -1; } */
1694}
1695
1696void lm_print_default(int n_par, double *par, int m_dat, double *fvec,
1697 void *data, int iflag, int iter, int nfev)
1698/*
1699 * data : for soft control of printout behaviour, add control
1700 * variables to the data struct
1701 * iflag : 0 (init) 1 (outer loop) 2(inner loop) -1(terminated)
1702 * iter : outer loop counter
1703 * nfev : number of calls to *evaluate
1704 */
1705{
1706 lm_data_type *mydata = (lm_data_type *)data;
1707
1708 if (mydata->print_flag) {
1709 if (iflag == 2) {
1710 printf("trying step in gradient direction\n");
1711 } else if (iflag == 1) {
1712 printf("determining gradient (iteration %d)\n", iter);
1713 } else if (iflag == 0) {
1714 printf("starting minimization\n");
1715 } else if (iflag == -1) {
1716 printf("terminated after %d evaluations\n", nfev);
1717 }
1718
1719 printf(" par: ");
1720 for (int i = 0; i < n_par; ++i) printf(" %12g", par[i]);
1721 printf(" => norm: %12g\n", lm_enorm(m_dat, fvec));
1722
1723 if (iflag == -1) {
1724 printf(" fitting data as follows:\n");
1725 for (int i = 0; i < m_dat; ++i) {
1726 const double tx = (mydata->user_tx)[i];
1727 const double ty = (mydata->user_ty)[i];
1728 const double y = (mydata->user_y)[i];
1729 const double f = mydata->user_func(tx, ty, mydata->n_par, par);
1730 printf(
1731 " tx[%2d]=%8g ty[%2d]=%8g y=%12g fit=%12g "
1732 "residue=%12g\n",
1733 i, tx, i, ty, y, f, y - f);
1734 }
1735 }
1736 } // if print_flag
1737}
1738
1740
1741/* *********************** high-level interface **************************** */
1742
1744 control->maxcall = 100;
1745 control->epsilon = 1.e-10; // 1.e-14;
1746 control->stepbound = 100; // 100.;
1747 control->ftol = 1.e-14;
1748 control->xtol = 1.e-14;
1749 control->gtol = 1.e-14;
1750}
1751
1752void lm_minimize(int m_dat, int n_par, double *par, lm_evaluate_ftype *evaluate,
1753 lm_print_ftype *printout, void *data,
1754 lm_control_type *control) {
1755 std::vector<double> fvec(m_dat);
1756 std::vector<double> diag(n_par);
1757 std::vector<double> qtf(n_par);
1758 std::vector<double> fjac(n_par * m_dat);
1759 std::vector<double> wa1(n_par);
1760 std::vector<double> wa2(n_par);
1761 std::vector<double> wa3(n_par);
1762 std::vector<double> wa4(m_dat);
1763 std::vector<int> ipvt(n_par);
1764
1765 // *** perform fit.
1766
1767 control->info = 0;
1768 control->nfev = 0;
1769
1770 // this goes through the modified legacy interface:
1771 lm_lmdif(m_dat, n_par, par, &fvec[0], control->ftol, control->xtol,
1772 control->gtol, control->maxcall * (n_par + 1), control->epsilon,
1773 &diag[0], 1, control->stepbound, &(control->info), &(control->nfev),
1774 &fjac[0], &ipvt[0], &qtf[0], &wa1[0], &wa2[0], &wa3[0], &wa4[0],
1775 evaluate, printout, data);
1776
1777 (*printout)(n_par, par, m_dat, &fvec[0], data, -1, 0, control->nfev);
1778 control->fnorm = lm_enorm(m_dat, &fvec[0]);
1779 if (control->info < 0) control->info = 10;
1780}
1781
1782// ***** the following messages are referenced by the variable info.
1783
1784const char *lm_infmsg[] = {
1785 "improper input parameters",
1786 "the relative error in the sum of squares is at most tol",
1787 "the relative error between x and the solution is at most tol",
1788 "both errors are at most tol",
1789 "fvec is orthogonal to the columns of the jacobian to machine precision",
1790 "number of calls to fcn has reached or exceeded 200*(n+1)",
1791 "ftol is too small. no further reduction in the sum of squares is possible",
1792 "xtol too small. no further improvement in approximate solution x possible",
1793 "gtol too small. no further improvement in approximate solution x possible",
1794 "not enough memory",
1795 "break requested within function evaluation"};
1796
1797const char *lm_shortmsg[] = {"invalid input", "success (f)", "success (p)",
1798 "success (f,p)", "degenerate", "call limit",
1799 "failed (f)", "failed (p)", "failed (o)",
1800 "no memory", "user break"};
1801
1802/* ************************** implementation ******************************* */
1803
1804#define BUG 0
1805#if BUG
1806#include <stdio.h>
1807#endif
1808
1809// the following values seem good for an x86:
1810// #define LM_MACHEP .555e-16 /* resolution of arithmetic */
1811// #define LM_DWARF 9.9e-324 /* smallest nonzero number */
1812// the follwoing values should work on any machine:
1813#define LM_MACHEP 1.2e-16
1814#define LM_DWARF 1.0e-38
1815
1816// the squares of the following constants shall not under/overflow:
1817// these values seem good for an x86:
1818// #define LM_SQRT_DWARF 1.e-160
1819// #define LM_SQRT_GIANT 1.e150
1820// the following values should work on any machine:
1821#define LM_SQRT_DWARF 3.834e-20
1822#define LM_SQRT_GIANT 1.304e19
1823
1824void lm_qrfac(int m, int n, double *a, int pivot, int *ipvt, double *rdiag,
1825 double *acnorm, double *wa);
1826void lm_qrsolv(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb,
1827 double *x, double *sdiag, double *wa);
1828void lm_lmpar(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb,
1829 double delta, double *par, double *x, double *sdiag, double *wa1,
1830 double *wa2);
1831
1832#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
1833#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
1834#define SQR(x) (x) * (x)
1835
1836// ***** the low-level legacy interface for full control.
1837
1838void lm_lmdif(int m, int n, double *x, double *fvec, double ftol, double xtol,
1839 double gtol, int maxfev, double epsfcn, double *diag, int mode,
1840 double factor, int *info, int *nfev, double *fjac, int *ipvt,
1841 double *qtf, double *wa1, double *wa2, double *wa3, double *wa4,
1842 lm_evaluate_ftype *evaluate, lm_print_ftype *printout,
1843 void *data) {
1844 /*
1845 * the purpose of lmdif is to minimize the sum of the squares of
1846 * m nonlinear functions in n variables by a modification of
1847 * the levenberg-marquardt algorithm. the user must provide a
1848 * subroutine evaluate which calculates the functions. the jacobian
1849 * is then calculated by a forward-difference approximation.
1850 *
1851 * the multi-parameter interface lm_lmdif is for users who want
1852 * full control and flexibility. most users will be better off using
1853 * the simpler interface lmfit provided above.
1854 *
1855 * the parameters are the same as in the legacy FORTRAN implementation,
1856 * with the following exceptions:
1857 * the old parameter ldfjac which gave leading dimension of fjac has
1858 * been deleted because this C translation makes no use of two-
1859 * dimensional arrays;
1860 * the old parameter nprint has been deleted; printout is now controlled
1861 * by the user-supplied routine *printout;
1862 * the parameter field *data and the function parameters *evaluate and
1863 * *printout have been added; they help avoiding global variables.
1864 *
1865 * parameters:
1866 *
1867 * m is a positive integer input variable set to the number
1868 * of functions.
1869 *
1870 * n is a positive integer input variable set to the number
1871 * of variables. n must not exceed m.
1872 *
1873 * x is an array of length n. on input x must contain
1874 * an initial estimate of the solution vector. on output x
1875 * contains the final estimate of the solution vector.
1876 *
1877 * fvec is an output array of length m which contains
1878 * the functions evaluated at the output x.
1879 *
1880 * ftol is a nonnegative input variable. termination
1881 * occurs when both the actual and predicted relative
1882 * reductions in the sum of squares are at most ftol.
1883 * therefore, ftol measures the relative error desired
1884 * in the sum of squares.
1885 *
1886 * xtol is a nonnegative input variable. termination
1887 * occurs when the relative error between two consecutive
1888 * iterates is at most xtol. therefore, xtol measures the
1889 * relative error desired in the approximate solution.
1890 *
1891 * gtol is a nonnegative input variable. termination
1892 * occurs when the cosine of the angle between fvec and
1893 * any column of the jacobian is at most gtol in absolute
1894 * value. therefore, gtol measures the orthogonality
1895 * desired between the function vector and the columns
1896 * of the jacobian.
1897 *
1898 * maxfev is a positive integer input variable. termination
1899 * occurs when the number of calls to lm_fcn is at least
1900 * maxfev by the end of an iteration.
1901 *
1902 * epsfcn is an input variable used in determining a suitable
1903 * step length for the forward-difference approximation. this
1904 * approximation assumes that the relative errors in the
1905 * functions are of the order of epsfcn. if epsfcn is less
1906 * than the machine precision, it is assumed that the relative
1907 * errors in the functions are of the order of the machine
1908 * precision.
1909 *
1910 * diag is an array of length n. if mode = 1 (see below), diag is
1911 * internally set. if mode = 2, diag must contain positive entries
1912 * that serve as multiplicative scale factors for the variables.
1913 *
1914 * mode is an integer input variable. if mode = 1, the
1915 * variables will be scaled internally. if mode = 2,
1916 * the scaling is specified by the input diag. other
1917 * values of mode are equivalent to mode = 1.
1918 *
1919 * factor is a positive input variable used in determining the
1920 * initial step bound. this bound is set to the product of
1921 * factor and the euclidean norm of diag*x if nonzero, or else
1922 * to factor itself. in most cases factor should lie in the
1923 * interval (.1,100.). 100. is a generally recommended value.
1924 *
1925 * info is an integer output variable that indicates the termination
1926 * status of lm_lmdif as follows:
1927 *
1928 * info < 0 termination requested by user-supplied routine *evaluate;
1929 *
1930 * info = 0 improper input parameters;
1931 *
1932 * info = 1 both actual and predicted relative reductions
1933 * in the sum of squares are at most ftol;
1934 *
1935 * info = 2 relative error between two consecutive iterates
1936 * is at most xtol;
1937 *
1938 * info = 3 conditions for info = 1 and info = 2 both hold;
1939 *
1940 * info = 4 the cosine of the angle between fvec and any
1941 * column of the jacobian is at most gtol in
1942 * absolute value;
1943 *
1944 * info = 5 number of calls to lm_fcn has reached or
1945 * exceeded maxfev;
1946 *
1947 * info = 6 ftol is too small. no further reduction in
1948 * the sum of squares is possible;
1949 *
1950 * info = 7 xtol is too small. no further improvement in
1951 * the approximate solution x is possible;
1952 *
1953 * info = 8 gtol is too small. fvec is orthogonal to the
1954 * columns of the jacobian to machine precision;
1955 *
1956 * nfev is an output variable set to the number of calls to the
1957 * user-supplied routine *evaluate.
1958 *
1959 * fjac is an output m by n array. the upper n by n submatrix
1960 * of fjac contains an upper triangular matrix r with
1961 * diagonal elements of nonincreasing magnitude such that
1962 *
1963 * t t t
1964 * p *(jac *jac)*p = r *r,
1965 *
1966 * where p is a permutation matrix and jac is the final
1967 * calculated jacobian. column j of p is column ipvt(j)
1968 * (see below) of the identity matrix. the lower trapezoidal
1969 * part of fjac contains information generated during
1970 * the computation of r.
1971 *
1972 * ipvt is an integer output array of length n. ipvt
1973 * defines a permutation matrix p such that jac*p = q*r,
1974 * where jac is the final calculated jacobian, q is
1975 * orthogonal (not stored), and r is upper triangular
1976 * with diagonal elements of nonincreasing magnitude.
1977 * column j of p is column ipvt(j) of the identity matrix.
1978 *
1979 * qtf is an output array of length n which contains
1980 * the first n elements of the vector (q transpose)*fvec.
1981 *
1982 * wa1, wa2, and wa3 are work arrays of length n.
1983 *
1984 * wa4 is a work array of length m.
1985 *
1986 * the following parameters are newly introduced in this C translation:
1987 *
1988 * evaluate is the name of the subroutine which calculates the functions.
1989 * a default implementation lm_evaluate_default is provided in
1990 * lm_eval.c; alternatively, evaluate can be provided by a user calling
1991 * program. it should be written as follows:
1992 *
1993 * void evaluate ( double* par, int m_dat, double* fvec,
1994 * void *data, int *info )
1995 * {
1996 * // for ( i=0; i<m_dat; ++i )
1997 * // calculate fvec[i] for given parameters par;
1998 * // to stop the minimization,
1999 * // set *info to a negative integer.
2000 * }
2001 *
2002 * printout is the name of the subroutine which nforms about fit
2003 * progress. a default implementation lm_print_default is provided in
2004 * lm_eval.c; alternatively, printout can be provided by a user calling
2005 * program. it should be written as follows:
2006 *
2007 * void printout ( int n_par, double* par, int m_dat, double* fvec,
2008 * void *data, int iflag, int iter, int nfev )
2009 * {
2010 * // iflag : 0 (init) 1 (outer loop) 2(inner loop) -1(terminated)
2011 * // iter : outer loop counter
2012 * // nfev : number of calls to *evaluate
2013 * }
2014 *
2015 * data is an input pointer to an arbitrary structure that is passed to
2016 * evaluate. typically, it contains experimental data to be fitted.
2017 *
2018 */
2019
2020 *nfev = 0; // function evaluation counter
2021
2022 // *** check the input parameters for errors.
2023
2024 if ((n <= 0) || (m < n) || (ftol < 0.) || (xtol < 0.) || (gtol < 0.) ||
2025 (maxfev <= 0) || (factor <= 0.)) {
2026 *info = 0; // invalid parameter
2027 return;
2028 }
2029
2030 if (mode == 2) /* scaling by diag[] */
2031 {
2032 for (int j = 0; j < n; j++) /* check for non positive elements */
2033 {
2034 if (diag[j] <= 0.0) {
2035 *info = 0; // invalid parameter
2036 return;
2037 }
2038 }
2039 }
2040#if BUG
2041 printf("lmdif\n");
2042#endif
2043
2044 // *** evaluate the function at the starting point and calculate its norm.
2045
2046 *info = 0;
2047 (*evaluate)(x, m, fvec, data, info);
2048 (*printout)(n, x, m, fvec, data, 0, 0, ++(*nfev));
2049 if (*info < 0) return;
2050
2051 // *** the outer loop.
2052 int iter = 1; // outer loop counter
2053 double delta =
2054 0.0; // just to prevent a warning (initialization within if-clause)
2055 double xnorm = 0.0;
2056 double fnorm = lm_enorm(m, fvec);
2057 const double eps = sqrt(MAX(
2058 epsfcn,
2059 LM_MACHEP)); // used in calculating the Jacobian by forward differences
2060
2061 do {
2062#if BUG
2063 printf("lmdif/ outer loop iter=%d nfev=%d fnorm=%.10e\n", iter, *nfev,
2064 fnorm);
2065#endif
2066
2067 // O** calculate the jacobian matrix.
2068
2069 for (int j = 0; j < n; j++) {
2070 const double temp = x[j];
2071 const double step = eps * fabs(temp) == 0.0 ? eps : eps * fabs(temp);
2072
2073 x[j] = temp + step;
2074 *info = 0;
2075 (*evaluate)(x, m, wa4, data, info);
2076 (*printout)(n, x, m, wa4, data, 1, iter, ++(*nfev));
2077 if (*info < 0) return; // user requested break
2078 x[j] = temp;
2079 for (int i = 0; i < m; i++) fjac[j * m + i] = (wa4[i] - fvec[i]) / step;
2080 }
2081#if BUG > 1
2082 // DEBUG: print the entire matrix
2083 for (i = 0; i < m; i++) {
2084 for (j = 0; j < n; j++) printf("%.5e ", y[j * m + i]);
2085 printf("\n");
2086 }
2087#endif
2088
2089 // O** compute the qr factorization of the jacobian.
2090
2091 lm_qrfac(m, n, fjac, 1, ipvt, wa1, wa2, wa3);
2092
2093 // O** on the first iteration ...
2094
2095 if (iter == 1) {
2096 if (mode != 2)
2097 // ... scale according to the norms of the columns of the initial
2098 // jacobian.
2099 {
2100 for (int j = 0; j < n; j++) {
2101 diag[j] = wa2[j];
2102 if (wa2[j] == 0.) diag[j] = 1.;
2103 }
2104 }
2105
2106 // ... calculate the norm of the scaled x and
2107 // initialize the step bound delta.
2108
2109 for (int j = 0; j < n; j++) wa3[j] = diag[j] * x[j];
2110
2111 xnorm = lm_enorm(n, wa3);
2112 delta = factor * xnorm;
2113 if (delta == 0.) delta = factor;
2114 }
2115
2116 // O** form (q transpose)*fvec and store the first n components in qtf.
2117
2118 for (int i = 0; i < m; i++) wa4[i] = fvec[i];
2119
2120 for (int j = 0; j < n; j++) {
2121 double temp3 = fjac[j * m + j];
2122 if (temp3 != 0.) {
2123 double sum = 0.0;
2124 for (int i = j; i < m; i++) sum += fjac[j * m + i] * wa4[i];
2125 double temp = -sum / temp3;
2126 for (int i = j; i < m; i++) wa4[i] += fjac[j * m + i] * temp;
2127 }
2128 fjac[j * m + j] = wa1[j];
2129 qtf[j] = wa4[j];
2130 }
2131
2132 // O** compute the norm of the scaled gradient and test for convergence.
2133
2134 double gnorm = 0;
2135 if (fnorm != 0) {
2136 for (int j = 0; j < n; j++) {
2137 if (wa2[ipvt[j]] == 0) continue;
2138
2139 double sum = 0.0;
2140 for (int i = 0; i <= j; i++) sum += fjac[j * m + i] * qtf[i] / fnorm;
2141 gnorm = MAX(gnorm, fabs(sum / wa2[ipvt[j]]));
2142 }
2143 }
2144
2145 if (gnorm <= gtol) {
2146 *info = 4;
2147 return;
2148 }
2149
2150 // O** rescale if necessary.
2151
2152 if (mode != 2) {
2153 for (int j = 0; j < n; j++) diag[j] = MAX(diag[j], wa2[j]);
2154 }
2155
2156 // O** the inner loop.
2157 const double kP0001 = 1.0e-4;
2158 double ratio = 0.0;
2159 do {
2160#if BUG
2161 printf("lmdif/ inner loop iter=%d nfev=%d\n", iter, *nfev);
2162#endif
2163
2164 // OI* determine the levenberg-marquardt parameter.
2165 double par = 0; // levenberg-marquardt parameter
2166 lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &par, wa1, wa2, wa3, wa4);
2167
2168 // OI* store the direction p and x + p. calculate the norm of p.
2169
2170 for (int j = 0; j < n; j++) {
2171 wa1[j] = -wa1[j];
2172 wa2[j] = x[j] + wa1[j];
2173 wa3[j] = diag[j] * wa1[j];
2174 }
2175 double pnorm = lm_enorm(n, wa3);
2176
2177 // OI* on the first iteration, adjust the initial step bound.
2178
2179 if (*nfev <= 1 + n) // bug corrected by J. Wuttke in 2004
2180 delta = MIN(delta, pnorm);
2181
2182 // OI* evaluate the function at x + p and calculate its norm.
2183
2184 *info = 0;
2185 (*evaluate)(wa2, m, wa4, data, info);
2186 (*printout)(n, x, m, wa4, data, 2, iter, ++(*nfev));
2187 if (*info < 0) return; // user requested break
2188
2189 double fnorm1 = lm_enorm(m, wa4);
2190#if BUG
2191 printf(
2192 "lmdif/ pnorm %.10e fnorm1 %.10e fnorm %.10e"
2193 " delta=%.10e par=%.10e\n",
2194 pnorm, fnorm1, fnorm, delta, par);
2195#endif
2196
2197 // OI* compute the scaled actual reduction.
2198 const double kP1 = 0.1;
2199 const double actred = kP1 * fnorm1 < fnorm ? 1 - SQR(fnorm1 / fnorm) : -1;
2200
2201 // OI* compute the scaled predicted reduction and
2202 // the scaled directional derivative.
2203
2204 for (int j = 0; j < n; j++) {
2205 wa3[j] = 0;
2206 for (int i = 0; i <= j; i++) wa3[i] += fjac[j * m + i] * wa1[ipvt[j]];
2207 }
2208 const double temp1 = lm_enorm(n, wa3) / fnorm;
2209 const double temp2 = sqrt(par) * pnorm / fnorm;
2210 const double prered = SQR(temp1) + 2 * SQR(temp2);
2211 const double dirder = -(SQR(temp1) + SQR(temp2));
2212
2213 // OI* compute the ratio of the actual to the predicted reduction.
2214
2215 ratio = prered != 0 ? actred / prered : 0.0;
2216#if BUG
2217 printf(
2218 "lmdif/ actred=%.10e prered=%.10e ratio=%.10e"
2219 " sq(1)=%.10e sq(2)=%.10e dd=%.10e\n",
2220 actred, prered, prered != 0 ? ratio : 0., SQR(temp1), SQR(temp2),
2221 dirder);
2222#endif
2223
2224 // OI* update the step bound.
2225 const double kP5 = 0.5;
2226 const double kP25 = 0.25;
2227 const double kP75 = 0.75;
2228
2229 if (ratio <= kP25) {
2230 double temp =
2231 actred >= 0.0 ? kP5 : kP5 * dirder / (dirder + kP5 * actred);
2232 if (kP1 * fnorm1 >= fnorm || temp < kP1) temp = kP1;
2233 delta = temp * MIN(delta, pnorm / kP1);
2234 par /= temp;
2235 } else if (par == 0. || ratio >= kP75) {
2236 delta = pnorm / kP5;
2237 par *= kP5;
2238 }
2239
2240 // OI* test for successful iteration...
2241 if (ratio >= kP0001) {
2242 // ... successful iteration. update x, fvec, and their norms.
2243
2244 for (int j = 0; j < n; j++) {
2245 x[j] = wa2[j];
2246 wa2[j] = diag[j] * x[j];
2247 }
2248 for (int i = 0; i < m; i++) fvec[i] = wa4[i];
2249 xnorm = lm_enorm(n, wa2);
2250 fnorm = fnorm1;
2251 iter++;
2252 }
2253#if BUG
2254 else {
2255 printf("ATTN: iteration considered unsuccessful\n");
2256 }
2257#endif
2258
2259 // OI* tests for convergence ( otherwise *info = 1, 2, or 3 )
2260
2261 *info = 0; // do not terminate (unless overwritten by nonzero value)
2262 if (fabs(actred) <= ftol && prered <= ftol && kP5 * ratio <= 1) *info = 1;
2263 if (delta <= xtol * xnorm) *info += 2;
2264 if (*info != 0) return;
2265
2266 // OI* tests for termination and stringent tolerances.
2267
2268 if (*nfev >= maxfev) *info = 5;
2269 if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP && kP5 * ratio <= 1)
2270 *info = 6;
2271 if (delta <= LM_MACHEP * xnorm) *info = 7;
2272 if (gnorm <= LM_MACHEP) *info = 8;
2273 if (*info != 0) return;
2274
2275 // OI* end of the inner loop. repeat if iteration unsuccessful.
2276
2277 } while (ratio < kP0001);
2278
2279 // O** end of the outer loop.
2280
2281 } while (1);
2282}
2283
2284void lm_lmpar(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb,
2285 double delta, double *par, double *x, double *sdiag, double *wa1,
2286 double *wa2) {
2287 /* given an m by n matrix a, an n by n nonsingular diagonal
2288 * matrix d, an m-vector b, and a positive number delta,
2289 * the problem is to determine a value for the parameter
2290 * par such that if x solves the system
2291 *
2292 * a*x = b , sqrt(par)*d*x = 0 ,
2293 *
2294 * in the least squares sense, and dxnorm is the euclidean
2295 * norm of d*x, then either par is 0. and
2296 *
2297 * (dxnorm-delta) .le. 0.1*delta ,
2298 *
2299 * or par is positive and
2300 *
2301 * abs(dxnorm-delta) .le. 0.1*delta .
2302 *
2303 * this subroutine completes the solution of the problem
2304 * if it is provided with the necessary information from the
2305 * qr factorization, with column pivoting, of a. that is, if
2306 * a*p = q*r, where p is a permutation matrix, q has orthogonal
2307 * columns, and r is an upper triangular matrix with diagonal
2308 * elements of nonincreasing magnitude, then lmpar expects
2309 * the full upper triangle of r, the permutation matrix p,
2310 * and the first n components of (q transpose)*b. on output
2311 * lmpar also provides an upper triangular matrix s such that
2312 *
2313 * t t t
2314 * p *(a *a + par*d*d)*p = s *s .
2315 *
2316 * s is employed within lmpar and may be of separate interest.
2317 *
2318 * only a few iterations are generally needed for convergence
2319 * of the algorithm. if, however, the limit of 10 iterations
2320 * is reached, then the output par will contain the best
2321 * value obtained so far.
2322 *
2323 * parameters:
2324 *
2325 * n is a positive integer input variable set to the order of r.
2326 *
2327 * r is an n by n array. on input the full upper triangle
2328 * must contain the full upper triangle of the matrix r.
2329 * on output the full upper triangle is unaltered, and the
2330 * strict lower triangle contains the strict upper triangle
2331 * (transposed) of the upper triangular matrix s.
2332 *
2333 * ldr is a positive integer input variable not less than n
2334 * which specifies the leading dimension of the array r.
2335 *
2336 * ipvt is an integer input array of length n which defines the
2337 * permutation matrix p such that a*p = q*r. column j of p
2338 * is column ipvt(j) of the identity matrix.
2339 *
2340 * diag is an input array of length n which must contain the
2341 * diagonal elements of the matrix d.
2342 *
2343 * qtb is an input array of length n which must contain the first
2344 * n elements of the vector (q transpose)*b.
2345 *
2346 * delta is a positive input variable which specifies an upper
2347 * bound on the euclidean norm of d*x.
2348 *
2349 * par is a nonnegative variable. on input par contains an
2350 * initial estimate of the levenberg-marquardt parameter.
2351 * on output par contains the final estimate.
2352 *
2353 * x is an output array of length n which contains the least
2354 * squares solution of the system a*x = b, sqrt(par)*d*x = 0,
2355 * for the output par.
2356 *
2357 * sdiag is an output array of length n which contains the
2358 * diagonal elements of the upper triangular matrix s.
2359 *
2360 * wa1 and wa2 are work arrays of length n.
2361 *
2362 */
2363
2364#if BUG
2365 printf("lmpar\n");
2366#endif
2367
2368 // *** compute and store in x the gauss-newton direction. if the
2369 // jacobian is rank-deficient, obtain a least squares solution.
2370
2371 int nsing = n;
2372 for (int j = 0; j < n; j++) {
2373 wa1[j] = qtb[j];
2374 if (r[j * ldr + j] == 0 && nsing == n) nsing = j;
2375 if (nsing < n) wa1[j] = 0;
2376 }
2377#if BUG
2378 printf("nsing %d ", nsing);
2379#endif
2380 for (int j = nsing - 1; j >= 0; j--) {
2381 wa1[j] = wa1[j] / r[j + ldr * j];
2382 const double temp = wa1[j];
2383 for (int i = 0; i < j; i++) wa1[i] -= r[j * ldr + i] * temp;
2384 }
2385
2386 for (int j = 0; j < n; j++) x[ipvt[j]] = wa1[j];
2387
2388 // *** initialize the iteration counter.
2389 // evaluate the function at the origin, and test
2390 // for acceptance of the gauss-newton direction.
2391
2392 int iter = 0;
2393 for (int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2394
2395 double dxnorm = lm_enorm(n, wa2);
2396 double fp = dxnorm - delta;
2397 const double kP1 = 0.1;
2398 if (fp <= kP1 * delta) {
2399#if BUG
2400 printf("lmpar/ terminate (fp<delta/10\n");
2401#endif
2402 *par = 0;
2403 return;
2404 }
2405
2406 // *** if the jacobian is not rank deficient, the newton
2407 // step provides a lower bound, parl, for the 0. of
2408 // the function. otherwise set this bound to 0..
2409
2410 double parl = 0.0;
2411 if (nsing >= n) {
2412 for (int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2413
2414 for (int j = 0; j < n; j++) {
2415 double sum = 0.0;
2416 for (int i = 0; i < j; i++) sum += r[j * ldr + i] * wa1[i];
2417 wa1[j] = (wa1[j] - sum) / r[j + ldr * j];
2418 }
2419 const double temp = lm_enorm(n, wa1);
2420 parl = fp / delta / temp / temp;
2421 }
2422
2423 // *** calculate an upper bound, paru, for the 0. of the function.
2424
2425 for (int j = 0; j < n; j++) {
2426 double sum = 0;
2427 for (int i = 0; i <= j; i++) sum += r[j * ldr + i] * qtb[i];
2428 wa1[j] = sum / diag[ipvt[j]];
2429 }
2430 const double gnorm = lm_enorm(n, wa1);
2431 double paru =
2432 gnorm / delta == 0.0 ? LM_DWARF / MIN(delta, kP1) : gnorm / delta;
2433
2434 // *** if the input par lies outside of the interval (parl,paru),
2435 // set par to the closer endpoint.
2436
2437 *par = MAX(*par, parl);
2438 *par = MIN(*par, paru);
2439 if (*par == 0.) *par = gnorm / dxnorm;
2440#if BUG
2441 printf("lmpar/ parl %.4e par %.4e paru %.4e\n", parl, *par, paru);
2442#endif
2443
2444 // *** iterate.
2445
2446 for (;; iter++) {
2447 // *** evaluate the function at the current value of par.
2448 const double kP001 = 0.001;
2449 if (*par == 0.) *par = MAX(LM_DWARF, kP001 * paru);
2450 double temp = sqrt(*par);
2451 for (int j = 0; j < n; j++) wa1[j] = temp * diag[j];
2452 lm_qrsolv(n, r, ldr, ipvt, wa1, qtb, x, sdiag, wa2);
2453 for (int j = 0; j < n; j++) wa2[j] = diag[j] * x[j];
2454 dxnorm = lm_enorm(n, wa2);
2455 const double fp_old = fp;
2456 fp = dxnorm - delta;
2457
2458 // *** if the function is small enough, accept the current value
2459 // of par. also test for the exceptional cases where parl
2460 // is 0. or the number of iterations has reached 10.
2461
2462 if (fabs(fp) <= kP1 * delta ||
2463 (parl == 0. && fp <= fp_old && fp_old < 0.) || iter == 10)
2464 break; // the only exit from this loop
2465
2466 // *** compute the Newton correction.
2467
2468 for (int j = 0; j < n; j++) wa1[j] = diag[ipvt[j]] * wa2[ipvt[j]] / dxnorm;
2469
2470 for (int j = 0; j < n; j++) {
2471 wa1[j] = wa1[j] / sdiag[j];
2472 for (int i = j + 1; i < n; i++) wa1[i] -= r[j * ldr + i] * wa1[j];
2473 }
2474 temp = lm_enorm(n, wa1);
2475 double parc = fp / delta / temp / temp;
2476
2477 // *** depending on the sign of the function, update parl or paru.
2478
2479 if (fp > 0)
2480 parl = MAX(parl, *par);
2481 else if (fp < 0)
2482 paru = MIN(paru, *par);
2483 // the case fp==0 is precluded by the break condition
2484
2485 // *** compute an improved estimate for par.
2486
2487 *par = MAX(parl, *par + parc);
2488 }
2489}
2490
2491void lm_qrfac(int m, int n, double *a, int pivot, int *ipvt, double *rdiag,
2492 double *acnorm, double *wa) {
2493 /*
2494 * this subroutine uses householder transformations with column
2495 * pivoting (optional) to compute a qr factorization of the
2496 * m by n matrix a. that is, qrfac determines an orthogonal
2497 * matrix q, a permutation matrix p, and an upper trapezoidal
2498 * matrix r with diagonal elements of nonincreasing magnitude,
2499 * such that a*p = q*r. the householder transformation for
2500 * column k, k = 1,2,...,min(m,n), is of the form
2501 *
2502 * t
2503 * i - (1/u(k))*u*u
2504 *
2505 * where u has 0.s in the first k-1 positions. the form of
2506 * this transformation and the method of pivoting first
2507 * appeared in the corresponding linpack subroutine.
2508 *
2509 * parameters:
2510 *
2511 * m is a positive integer input variable set to the number
2512 * of rows of a.
2513 *
2514 * n is a positive integer input variable set to the number
2515 * of columns of a.
2516 *
2517 * a is an m by n array. on input a contains the matrix for
2518 * which the qr factorization is to be computed. on output
2519 * the strict upper trapezoidal part of a contains the strict
2520 * upper trapezoidal part of r, and the lower trapezoidal
2521 * part of a contains a factored form of q (the non-trivial
2522 * elements of the u vectors described above).
2523 *
2524 * pivot is a logical input variable. if pivot is set true,
2525 * then column pivoting is enforced. if pivot is set false,
2526 * then no column pivoting is done.
2527 *
2528 * ipvt is an integer output array of length lipvt. ipvt
2529 * defines the permutation matrix p such that a*p = q*r.
2530 * column j of p is column ipvt(j) of the identity matrix.
2531 * if pivot is false, ipvt is not referenced.
2532 *
2533 * rdiag is an output array of length n which contains the
2534 * diagonal elements of r.
2535 *
2536 * acnorm is an output array of length n which contains the
2537 * norms of the corresponding columns of the input matrix a.
2538 * if this information is not needed, then acnorm can coincide
2539 * with rdiag.
2540 *
2541 * wa is a work array of length n. if pivot is false, then wa
2542 * can coincide with rdiag.
2543 *
2544 */
2545
2546 // *** compute the initial column norms and initialize several arrays.
2547
2548 for (int j = 0; j < n; j++) {
2549 acnorm[j] = lm_enorm(m, &a[j * m]);
2550 rdiag[j] = acnorm[j];
2551 wa[j] = rdiag[j];
2552 if (pivot) ipvt[j] = j;
2553 }
2554#if BUG
2555 printf("qrfac\n");
2556#endif
2557
2558 // *** reduce a to r with householder transformations.
2559
2560 const int minmn = MIN(m, n);
2561 for (int j = 0; j < minmn; j++) {
2562 int kmax = j, k;
2563 if (!pivot) goto pivot_ok;
2564
2565 // *** bring the column of largest norm into the pivot position.
2566
2567 for (k = j + 1; k < n; k++)
2568 if (rdiag[k] > rdiag[kmax]) kmax = k;
2569 if (kmax == j) goto pivot_ok; // bug fixed in rel 2.1
2570
2571 for (int i = 0; i < m; i++) {
2572 std::swap(a[j * m + i], a[kmax * m + i]);
2573 // const double temp = a[j*m+i];
2574 // a[j*m+i] = a[kmax*m+i];
2575 // a[kmax*m+i] = temp;
2576 }
2577 rdiag[kmax] = rdiag[j];
2578 wa[kmax] = wa[j];
2579 std::swap(ipvt[j], ipvt[kmax]);
2580 // k = ipvt[j];
2581 // ipvt[j] = ipvt[kmax];
2582 // ipvt[kmax] = k;
2583
2584 pivot_ok:
2585
2586 // *** compute the Householder transformation to reduce the
2587 // j-th column of a to a multiple of the j-th unit vector.
2588
2589 double ajnorm = lm_enorm(m - j, &a[j * m + j]);
2590 if (ajnorm == 0.) {
2591 rdiag[j] = 0;
2592 continue;
2593 }
2594
2595 if (a[j * m + j] < 0.) ajnorm = -ajnorm;
2596 for (int i = j; i < m; i++) a[j * m + i] /= ajnorm;
2597 a[j * m + j] += 1;
2598
2599 // *** apply the transformation to the remaining columns
2600 // and update the norms.
2601
2602 for (k = j + 1; k < n; k++) {
2603 double sum = 0;
2604
2605 for (int i = j; i < m; i++) sum += a[j * m + i] * a[k * m + i];
2606
2607 double temp = sum / a[j + m * j];
2608
2609 for (int i = j; i < m; i++) a[k * m + i] -= temp * a[j * m + i];
2610
2611 if (pivot && rdiag[k] != 0.) {
2612 temp = a[m * k + j] / rdiag[k];
2613 temp = MAX(0., 1 - temp * temp);
2614 rdiag[k] *= sqrt(temp);
2615 temp = rdiag[k] / wa[k];
2616 const double kP05 = 0.05;
2617 if (kP05 * SQR(temp) <= LM_MACHEP) {
2618 rdiag[k] = lm_enorm(m - j - 1, &a[m * k + j + 1]);
2619 wa[k] = rdiag[k];
2620 }
2621 }
2622 }
2623
2624 rdiag[j] = -ajnorm;
2625 }
2626}
2627
2628void lm_qrsolv(int n, double *r, int ldr, int *ipvt, double *diag, double *qtb,
2629 double *x, double *sdiag, double *wa) {
2630 /*
2631 * given an m by n matrix a, an n by n diagonal matrix d,
2632 * and an m-vector b, the problem is to determine an x which
2633 * solves the system
2634 *
2635 * a*x = b , d*x = 0 ,
2636 *
2637 * in the least squares sense.
2638 *
2639 * this subroutine completes the solution of the problem
2640 * if it is provided with the necessary information from the
2641 * qr factorization, with column pivoting, of a. that is, if
2642 * a*p = q*r, where p is a permutation matrix, q has orthogonal
2643 * columns, and r is an upper triangular matrix with diagonal
2644 * elements of nonincreasing magnitude, then qrsolv expects
2645 * the full upper triangle of r, the permutation matrix p,
2646 * and the first n components of (q transpose)*b. the system
2647 * a*x = b, d*x = 0, is then equivalent to
2648 *
2649 * t t
2650 * r*z = q *b , p *d*p*z = 0 ,
2651 *
2652 * where x = p*z. if this system does not have full rank,
2653 * then a least squares solution is obtained. on output qrsolv
2654 * also provides an upper triangular matrix s such that
2655 *
2656 * t t t
2657 * p *(a *a + d*d)*p = s *s .
2658 *
2659 * s is computed within qrsolv and may be of separate interest.
2660 *
2661 * parameters
2662 *
2663 * n is a positive integer input variable set to the order of r.
2664 *
2665 * r is an n by n array. on input the full upper triangle
2666 * must contain the full upper triangle of the matrix r.
2667 * on output the full upper triangle is unaltered, and the
2668 * strict lower triangle contains the strict upper triangle
2669 * (transposed) of the upper triangular matrix s.
2670 *
2671 * ldr is a positive integer input variable not less than n
2672 * which specifies the leading dimension of the array r.
2673 *
2674 * ipvt is an integer input array of length n which defines the
2675 * permutation matrix p such that a*p = q*r. column j of p
2676 * is column ipvt(j) of the identity matrix.
2677 *
2678 * diag is an input array of length n which must contain the
2679 * diagonal elements of the matrix d.
2680 *
2681 * qtb is an input array of length n which must contain the first
2682 * n elements of the vector (q transpose)*b.
2683 *
2684 * x is an output array of length n which contains the least
2685 * squares solution of the system a*x = b, d*x = 0.
2686 *
2687 * sdiag is an output array of length n which contains the
2688 * diagonal elements of the upper triangular matrix s.
2689 *
2690 * wa is a work array of length n.
2691 *
2692 */
2693
2694 // *** copy r and (q transpose)*b to preserve input and initialize s.
2695 // in particular, save the diagonal elements of r in x.
2696
2697 for (int j = 0; j < n; j++) {
2698 for (int i = j; i < n; i++) r[j * ldr + i] = r[i * ldr + j];
2699 x[j] = r[j * ldr + j];
2700 wa[j] = qtb[j];
2701 }
2702#if BUG
2703 printf("qrsolv\n");
2704#endif
2705
2706 // *** eliminate the diagonal matrix d using a givens rotation.
2707
2708 for (int j = 0; j < n; j++) {
2709 // *** prepare the row of d to be eliminated, locating the
2710 // diagonal element using p from the qr factorization.
2711
2712 double qtbpj = 0.0;
2713
2714 if (diag[ipvt[j]] == 0.) goto L90;
2715 for (int k = j; k < n; k++) sdiag[k] = 0.;
2716 sdiag[j] = diag[ipvt[j]];
2717
2718 // *** the transformations to eliminate the row of d
2719 // modify only a single element of (q transpose)*b
2720 // beyond the first n, which is initially 0..
2721
2722 for (int k = j; k < n; k++) {
2723 const double p25 = 0.25;
2724 const double p5 = 0.5;
2725
2726 // determine a givens rotation which eliminates the
2727 // appropriate element in the current row of d.
2728
2729 if (sdiag[k] == 0.) continue;
2730 const int kk = k + ldr * k; // <! keep this shorthand !>
2731 double sin, cos; // these are local variables, not functions
2732
2733 if (fabs(r[kk]) < fabs(sdiag[k])) {
2734 const double cotan = r[kk] / sdiag[k];
2735 sin = p5 / sqrt(p25 + p25 * SQR(cotan));
2736 cos = sin * cotan;
2737 } else {
2738 const double tan = sdiag[k] / r[kk];
2739 cos = p5 / sqrt(p25 + p25 * SQR(tan));
2740 sin = cos * tan;
2741 }
2742
2743 // *** compute the modified diagonal element of r and
2744 // the modified element of ((q transpose)*b,0).
2745
2746 r[kk] = cos * r[kk] + sin * sdiag[k];
2747 double temp = cos * wa[k] + sin * qtbpj;
2748 qtbpj = -sin * wa[k] + cos * qtbpj;
2749 wa[k] = temp;
2750
2751 // *** accumulate the transformation in the row of s.
2752
2753 for (int i = k + 1; i < n; i++) {
2754 temp = cos * r[k * ldr + i] + sin * sdiag[i];
2755 sdiag[i] = -sin * r[k * ldr + i] + cos * sdiag[i];
2756 r[k * ldr + i] = temp;
2757 }
2758 }
2759 L90:
2760
2761 // *** store the diagonal element of s and restore
2762 // the corresponding diagonal element of r.
2763
2764 sdiag[j] = r[j * ldr + j];
2765 r[j * ldr + j] = x[j];
2766 }
2767
2768 // *** solve the triangular system for z. if the system is
2769 // singular, then obtain a least squares solution.
2770
2771 int nsing = n;
2772 for (int j = 0; j < n; j++) {
2773 if (sdiag[j] == 0. && nsing == n) nsing = j;
2774 if (nsing < n) wa[j] = 0;
2775 }
2776
2777 for (int j = nsing - 1; j >= 0; j--) {
2778 double sum = 0.0;
2779 for (int i = j + 1; i < nsing; i++) sum += r[j * ldr + i] * wa[i];
2780 wa[j] = (wa[j] - sum) / sdiag[j];
2781 }
2782
2783 // *** permute the components of z back to components of x.
2784
2785 for (int j = 0; j < n; j++) x[ipvt[j]] = wa[j];
2786}
2787
2788double lm_enorm(int n, double *x) {
2789 /* given an n-vector x, this function calculates the
2790 * euclidean norm of x.
2791 *
2792 * the euclidean norm is computed by accumulating the sum of
2793 * squares in three different sums. the sums of squares for the
2794 * small and large components are scaled so that no overflows
2795 * occur. non-destructive underflows are permitted. underflows
2796 * and overflows do not occur in the computation of the unscaled
2797 * sum of squares for the intermediate components.
2798 * the definitions of small, intermediate and large components
2799 * depend on two constants, LM_SQRT_DWARF and LM_SQRT_GIANT. the main
2800 * restrictions on these constants are that LM_SQRT_DWARF**2 not
2801 * underflow and LM_SQRT_GIANT**2 not overflow.
2802 *
2803 * parameters
2804 *
2805 * n is a positive integer input variable.
2806 *
2807 * x is an input array of length n.
2808 */
2809
2810 double s1 = 0.0, s2 = 0.0, s3 = 0.0;
2811 double x1max = 0.0, x3max = 0.0;
2812 const double agiant = LM_SQRT_GIANT / ((double)n);
2813
2814 for (int i = 0; i < n; i++) {
2815 double xabs = fabs(x[i]);
2816 if (xabs > LM_SQRT_DWARF && xabs < agiant) {
2817 // ** sum for intermediate components.
2818 s2 += xabs * xabs;
2819 continue;
2820 }
2821
2822 if (xabs > LM_SQRT_DWARF) {
2823 // ** sum for large components.
2824 if (xabs > x1max) {
2825 s1 = 1 + s1 * SQR(x1max / xabs);
2826 x1max = xabs;
2827 } else {
2828 s1 += SQR(xabs / x1max);
2829 }
2830 continue;
2831 }
2832 // ** sum for small components.
2833 if (xabs > x3max) {
2834 s3 = 1 + s3 * SQR(x3max / xabs);
2835 x3max = xabs;
2836 } else {
2837 if (xabs != 0.) {
2838 s3 += SQR(xabs / x3max);
2839 }
2840 }
2841 }
2842
2843 // *** calculation of norm.
2844
2845 if (s1 != 0) return x1max * sqrt(s1 + (s2 / x1max) / x1max);
2846 if (s2 != 0) {
2847 if (s2 >= x3max) return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
2848 return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
2849 }
2850
2851 return x3max * sqrt(s3);
2852}
2853
2854double lat_gc_crosses_meridian(double lat1, double lon1, double lat2,
2855 double lon2, double lon) {
2856 /*
2857 Calculates a latitude at which a GC route between two points crosses a given
2858 meridian
2859 */
2860
2861 double dlon = lon * DEGREE;
2862 double dlat1 = lat1 * DEGREE;
2863 double dlat2 = lat2 * DEGREE;
2864 double dlon1 = lon1 * DEGREE;
2865 double dlon2 = lon2 * DEGREE;
2866
2867 return RADIAN * atan((sin(dlat1) * cos(dlat2) * sin(dlon - dlon2) -
2868 sin(dlat2) * cos(dlat1) * sin(dlon - dlon1)) /
2869 (cos(dlat1) * cos(dlat2) * sin(dlon1 - dlon2)));
2870}
2871
2872double lat_rl_crosses_meridian(double lat1, double lon1, double lat2,
2873 double lon2, double lon) {
2874 /*
2875 Calculates a latitude at which a loxodromic route between two points crosses a
2876 given meridian
2877 */
2878
2879 double brg;
2880
2881 DistanceBearingMercator(lat2, lon2, lat1, lon1, &brg, NULL);
2882
2883 double x1, y1, x;
2884 toSM(lat1, lon1, 0., lon, &x1, &y1);
2885 toSM(lat1, lon, 0., lon, &x, &y1);
2886
2887 double dir = 1.0;
2888 if (brg >= 270.0) {
2889 brg -= 270.0;
2890 } else if (brg >= 180.) {
2891 brg = 270.0 - brg;
2892 dir = -1.0;
2893 } else if (brg >= 90.) {
2894 brg -= 90.0;
2895 dir = -1.0;
2896 } else {
2897 brg = 90.0 - brg;
2898 }
2899
2900 double ydelta = fabs(x1) * tan(brg * DEGREE);
2901
2902 double crosslat, crosslon;
2903 fromSM(x, y1 + dir * ydelta, 0., lon, &crosslat, &crosslon);
2904
2905 return crosslat;
2906}
Extern C linked utilities.
double my_fit_function(double tx, double ty, int n_par, double *p)
================================================================================= Customized section ...
Definition georef.cpp:1464
void lm_initialize_control(lm_control_type *control)
=================================================================================
Definition georef.cpp:1743
OpenCPN Georef utility.
Definition georef.h:35
Structure containing georeferencing information for transforming between geographic and projected/pix...
Definition georef.h:63
double lonmin
Minimum longitude in reference data.
Definition georef.h:83
int order
Polynomial order for the transformation (1, 2, or 3)
Definition georef.h:67
int count
Number of reference points used.
Definition georef.h:66
double lonmax
Maximum longitude in reference data.
Definition georef.h:82
int txmin
Minimum x value in target space.
Definition georef.h:80
double * pwx
Polynomial coefficients for pixel-to-world longitude transformation.
Definition georef.h:72
double * tx
Array of x-coordinates in target (typically pixel) space.
Definition georef.h:68
double * wpx
Polynomial coefficients for world-to-pixel x transformation.
Definition georef.h:76
double * lat
Array of latitudes corresponding to reference points.
Definition georef.h:71
double * lon
Array of longitudes corresponding to reference points.
Definition georef.h:70
int tymin
Minimum y value in target space.
Definition georef.h:81
double * ty
Array of y-coordinates in target (typically pixel) space.
Definition georef.h:69
int tymax
Maximum y value in target space.
Definition georef.h:79
double latmin
Minimum latitude in reference data.
Definition georef.h:85
int txmax
Maximum x value in target space.
Definition georef.h:78
double latmax
Maximum latitude in reference data.
Definition georef.h:84
double * wpy
Polynomial coefficients for world-to-pixel y transformation.
Definition georef.h:77
double * pwy
Polynomial coefficients for pixel-to-world latitude transformation.
Definition georef.h:74