-
Notifications
You must be signed in to change notification settings - Fork 375
/
Copy pathgmt_sph.c
480 lines (430 loc) · 20.7 KB
/
gmt_sph.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/*--------------------------------------------------------------------
*
* Copyright (c) 2008-2025 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
* See LICENSE.TXT file for copying and redistribution conditions.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3 or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* Contact info: www.generic-mapping-tools.org
*--------------------------------------------------------------------*/
/*
* Spherical triangulation - Delaunay or Voronoi options.
* Relies on STRIPACK FORTRAN F77 library (Renka, 1997). Reference:
* Renka, R, J,, 1997, Algorithm 772: STRIPACK: Delaunay Triangulation
* and Voronoi Diagram on the Surface of a Sphere, AMC Trans. Math.
* Software, 23 (3), 416-434.
* Spherical interpolation - tension or smoothing.
* Relies on SSRFPACK FORTRAN F77 library (Renka, 1997). Reference:
* Renka, R, J,, 1997, Algorithm 773: SSRFPACK: Interpolation of
* Scattered Data on the Surface of a Sphere with a Surface under Tension,
* AMC Trans. Math. Software, 23 (3), 435-442.
* We translated both to C using f2c and removed/rewrite statements that needed -lf2c
*
* Author: Paul Wessel
* Date: 1-AUG-2011
* Version: API 5 64-bit
*
*/
/*
* A) List of exported gmt_* functions available to modules and libraries via gmt_dev.h:
*
* gmt_ssrfpack_grid
* gmt_stripack_areas
* gmt_stripack_lists
*
* B) List of exported gmtlib_* functions available to libraries via gmt_internals.h:
*
* gmtlib_geo_centroid_area
*/
#include "gmt_dev.h"
#include "gmt_sph.h"
typedef double doublereal;
typedef int64_t integer;
typedef uint32_t logical;
#ifndef min
#define min(x, y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef max
#define max(x, y) (((x) > (y)) ? (x) : (y))
#endif
#define FALSE_ 0
#define TRUE_ 1
/* define SPH_DEBUG to get more original verbose output from s*pack.c */
/* This makes all the static functions in the next to files local here */
#include "stripack.c"
#include "ssrfpack.c"
int gmt_stripack_lists (struct GMT_CTRL *GMT, uint64_t n_in, double *x, double *y, double *z, struct STRIPACK *T) {
/* n, the number of points.
* x, y, z, the arrays with coordinates of points
*
* xc, yc, zc: the coordinates of the Voronoi polygon vertices.
* lend, points to the "first" vertex in the Voronoi polygon around a particular node.
* lptr: given a vertex, returns the next vertex in the Voronoi polygon.
*
* NOTE: All indices returned are C (0->) adjusted from FORTRAN (1->).
*/
uint64_t kk;
int64_t *iwk = NULL, *list = NULL, *lptr = NULL, *lend = NULL;
int64_t n = n_in, n_out, k, ierror= 0, lnew, nrow = TRI_NROW; /* Since the FORTRAN funcs expect signed ints */
size_t n_alloc;
double *ds = NULL;
if ((ds = gmt_M_memory (GMT, NULL, n, double)) == NULL) return GMT_MEMORY_ERROR;
if ((lend = gmt_M_memory (GMT, NULL, n, int64_t)) == NULL) return GMT_MEMORY_ERROR;
if ((iwk = gmt_M_memory (GMT, NULL, 2*n, int64_t)) == NULL) return GMT_MEMORY_ERROR;
n_alloc = 6 * (n - 2);
if ((lptr = gmt_M_memory (GMT, NULL, n_alloc, int64_t)) == NULL) return GMT_MEMORY_ERROR;
if ((list = gmt_M_memory (GMT, NULL, n_alloc, int64_t)) == NULL) return GMT_MEMORY_ERROR;
/* Create the triangulation. Main output is (list, lptr, lend) */
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Call STRIPACK TRMESH subroutine\n");
trmesh_ (&n, x, y, z, list, lptr, lend, &lnew, iwk, &iwk[n], ds, &ierror);
gmt_M_free (GMT, ds);
gmt_M_free (GMT, iwk);
if (ierror == -2) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "STRIPACK: Failure in TRMESH. The first 3 nodes are collinear.\n");
gmt_M_free (GMT, lptr);
gmt_M_free (GMT, list);
gmt_M_free (GMT, lend);
return GMT_RUNTIME_ERROR;
}
if (ierror > 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "STRIPACK: Failure in TRMESH. Duplicate nodes encountered.\n");
gmt_M_free (GMT, lptr);
gmt_M_free (GMT, list);
gmt_M_free (GMT, lend);
return GMT_RUNTIME_ERROR;
}
if (T->mode == INTERPOLATE) { /* Pass back the three lists from trmesh_ */
T->I.list = list; /* Save these for output */
T->I.lptr = lptr;
T->I.lend = lend;
return GMT_OK;
}
/* Create a triangle list which returns the number of triangles and their node list tri */
n_alloc = 2 * (n - 2);
if ((T->D.tri = gmt_M_memory (GMT, NULL, TRI_NROW*n_alloc, int64_t)) == NULL) return GMT_MEMORY_ERROR;
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Call STRIPACK TRLIST subroutine\n");
trlist_ (&n, list, lptr, lend, &nrow, &n_out, T->D.tri, &ierror);
T->D.n = n_out;
if (ierror) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "STRIPACK: Failure in TRLIST.\n");
gmt_M_free (GMT, list); gmt_M_free (GMT, lend); gmt_M_free (GMT, lptr);
return GMT_RUNTIME_ERROR;
}
if (T->mode == VORONOI) { /* Construct the Voronoi diagram */
int64_t *lbtri = NULL;
double *rc = NULL;
double *xc = NULL, *yc = NULL, *zc = NULL; /* Voronoi polygon vertices */
/* Note that the triangulation data structure is altered if NB > 0 */
n_alloc = 2 * (n - 2);
if ((xc = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
if ((yc = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
if ((zc = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
if ((rc = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
n_alloc = 6 * (n - 2);
if ((T->V.listc = gmt_M_memory (GMT, NULL, n_alloc, int64_t)) == NULL) return GMT_MEMORY_ERROR;
if ((lbtri = gmt_M_memory (GMT, NULL, 6*n, int64_t)) == NULL) return GMT_MEMORY_ERROR;
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Call STRIPACK CRLIST subroutine\n");
crlist_ (&n, &n, x, y, z, list, lend, lptr, &lnew, lbtri, T->V.listc, &n_out, xc, yc, zc, rc, &ierror);
T->V.n = n_out;
gmt_M_free (GMT, lbtri);
gmt_M_free (GMT, rc);
T->V.lend = lend; /* Save these for output */
T->V.lptr = lptr;
/* Convert polygon vertices vectors to lon, lat */
n_alloc = 2 * (n - 2);
if ((T->V.lon = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
if ((T->V.lat = gmt_M_memory (GMT, NULL, n_alloc, double)) == NULL) return GMT_MEMORY_ERROR;
gmt_n_cart_to_geo (GMT, n_alloc, xc, yc, zc, T->V.lon, T->V.lat);
gmt_M_free (GMT, xc);
gmt_M_free (GMT, yc);
gmt_M_free (GMT, zc);
if (0 < ierror) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "STRIPACK: Failure in CRLIST. IERROR = %" PRId64 ".\n", ierror);
gmt_M_free (GMT, list);
return GMT_RUNTIME_ERROR;
}
/* Adjust FORTRAN to GMT indices */
n_alloc = 6 * (n - 2);
for (kk = 0; kk < n_alloc; kk++) T->V.listc[kk]--;
for (kk = 0; kk < n_alloc; kk++) T->V.lptr[kk]--;
for (k = 0; k < n; k++) T->V.lend[k]--;
}
else { /* Free things not needed */
gmt_M_free (GMT, lend);
gmt_M_free (GMT, lptr);
}
/* Adjust FORTRAN to GMT indices */
for (kk = 0; kk < TRI_NROW*T->D.n; kk++) T->D.tri[kk]--;
gmt_M_free (GMT, list);
return (GMT_OK);
}
double gmt_stripack_areas (double *V1, double *V2, double *V3) {
/* Wrapper for STRIPACK areas_ */
return (areas_ (V1, V2, V3));
}
/* Functions for spherical surface interpolation */
int gmt_ssrfpack_grid (struct GMT_CTRL *GMT, double *x, double *y, double *z, double *w, uint64_t n_in, unsigned int mode, double *par, bool vartens, struct GMT_GRID_HEADER *h, double *f) {
int error = GMT_NOERROR;
int64_t ierror, plus = 1, minus = -1, ij, nxp, k, n = n_in;
int64_t nm, n_sig, ist, iflgs, iter, itgs, n_columns = h->n_columns, n_rows = h->n_rows;
unsigned int row, col;
double *sigma = NULL, *grad = NULL, *plon = NULL, *plat = NULL, *wt = NULL, tol = 0.01, dsm, dgmx;
struct STRIPACK P;
n_sig = ((vartens) ? 6 * (n - 2) : 1);
/* Create the triangulation. Main output is (P.I->(list, lptr, lend) */
gmt_M_memset (&P, 1, struct STRIPACK);
P.mode = INTERPOLATE;
if (gmt_stripack_lists (GMT, n, x, y, z, &P)) return GMT_RUNTIME_ERROR;
/* Set out output nodes */
if ((plon = gmt_M_memory (GMT, NULL, h->n_columns, double)) == NULL) return GMT_MEMORY_ERROR;
if ((plat = gmt_M_memory (GMT, NULL, h->n_rows, double)) == NULL) return GMT_MEMORY_ERROR;
for (col = 0; col < h->n_columns; col++) plon[col] = D2R * gmt_M_grd_col_to_x (GMT, col, h);
for (row = 0; row < h->n_rows; row++) plat[row] = D2R * gmt_M_grd_row_to_y (GMT, row, h);
nm = h->n_columns * h->n_rows;
/* Time to work on the interpolation */
if ((sigma = gmt_M_memory (GMT, NULL, n_sig, double)) == NULL) return GMT_MEMORY_ERROR;
if (mode && (grad = gmt_M_memory (GMT, NULL, 3*n, double)) == NULL) return GMT_MEMORY_ERROR;
if (mode == 0) { /* C-0 interpolation (INTRC0). */
nxp = 0;
ist = 1;
for (row = 0; row < h->n_rows; row++) {
for (col = 0; col < h->n_columns; col++) {
ij = (uint64_t)col * (uint64_t)h->n_rows + (uint64_t)row; /* Use FORTRAN indexing since calling program will transpose to GMT order */
intrc0_ (&n, &plat[row], &plon[col], x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &ist, &f[ij], &ierror);
if (ierror > 0) nxp++;
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in INTRC0: I = %d, J = %d, IER = %" PRId64 "\n", row, col, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
}
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "INTRC0: Number of evaluations = %" PRId64 ", number of extrapolations = %" PRId64 "\n", nm, nxp);
}
else if (mode == 1) { /* C-1 interpolation (INTRC1) with local gradients GRADL. */
/* Accumulate the sum of the numbers of nodes used in the least squares fits in sum. */
int64_t k1;
double sum = 0.0;
for (k = 0; k < n; k++) {
k1 = k + 1; /* Since gradl expects FORTRAN indexing */
gradl_ (&n, &k1, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &grad[3*k], &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in GRADL: K = %" PRId64 " IER = %" PRId64 "\n", k1, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
sum += (double)ierror;
}
sum /= n;
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "GRADL: Average number of nodes used in the least squares fits = %g\n", sum);
if (vartens) { /* compute tension factors sigma (getsig). */
getsig_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, grad, &tol, sigma, &dsm, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in GETSIG: IER = %" PRId64 "\n", ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "GETSIG: %" PRId64 " tension factors altered; Max change = %g\n", ierror, dsm);
}
/* compute interpolated values on the uniform grid (unif). */
iflgs = 0;
if (vartens) iflgs = 1;
unif_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &iflgs, sigma, &n_rows, &n_rows, &n_columns, plat, plon, &plus, grad, f, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in UNIF: IER = %" PRId64 "\n", ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"UNIF: Number of evaluation points = %" PRId64 ", number of extrapolation points = %" PRId64 "\n", nm, ierror);
}
else if (mode == 2) { /* c-1 interpolation (intrc1) with global gradients gradg. */
int64_t maxit, nitg;
double dgmax;
/* initialize gradients grad to zeros. */
gmt_M_memset (grad, 3*n, double);
itgs = (par[0] == 0.0) ? 3 : lrint (par[0]);
maxit = (par[1] == 0.0) ? 10 : lrint (par[1]);
dgmax = (par[2] == 0.0) ? 0.01 : par[2];
if (!vartens) itgs = 1;
/* loop on gradg/getsig iterations. */
for (iter = iflgs = 0; iter < itgs; iter++) {
nitg = maxit;
dgmx = dgmax;
gradg_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &iflgs, sigma, &nitg, &dgmx, grad, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in GRADG (iteration %" PRId64 "): IER = %" PRId64 "\n", iter, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"GRADG (iteration %" PRId64 "): tolerance = %g max change = %g maxit = %" PRId64 " no. iterations = %" PRId64 " ier = %" PRId64 "\n",
iter, dgmax, dgmx, maxit, nitg, ierror);
if (vartens) {
/* compute tension factors sigma (getsig). iflgs > 0 if vartens = true */
iflgs = 1;
getsig_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, grad, &tol, sigma, &dsm, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in GETSIG (iteration %" PRId64 "): ier = %" PRId64 "\n", iter, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"GETSIG (iteration %" PRId64 "): %" PRId64 " tension factors altered; Max change = %g\n", iter, ierror, dsm);
}
}
/* compute interpolated values on the uniform grid (unif). */
unif_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &iflgs, sigma, &n_rows, &n_rows, &n_columns, plat, plon, &plus, grad, f, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in UNIF: IER = %" PRId64 "\n", ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"UNIF: Number of evaluations = %" PRId64 ", number of extrapolations = %" PRId64 "\n", nm, ierror);
}
else if (mode == 3) { /* c-1 smoothing method smsurf. */
double wtk, smtol, gstol, e, sm;
if ((wt = gmt_M_memory (GMT, NULL, n, double)) == NULL) return GMT_MEMORY_ERROR;
e = (par[0] == 0.0) ? 0.01 : par[0];
sm = (par[1] <= 0.0) ? (double)n : par[1];
itgs = (par[2] == 0.0) ? 3 : lrint (par[2]);
if (!vartens) itgs = 1;
wtk = 1.0 / e;
for (k = 0; k < n; k++) wt[k] = wtk; /* store the weights wt. */
/* compute and print smsurf parameters. */
smtol = sqrt (2.0 / sm);
gstol = 0.05 * e;
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"SMSURF parameters:\n\texpected squared error = %g\n\tsmoothing parameter sm = %g\n", e, sm);
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"\tgauss-seidel tolerance = %g\n\tsmoothing tolerance = %g\n\tweights = %g\n", gstol, smtol, wtk);
/* loop on smsurf/getsig iterations. */
for (iter = iflgs = 0; iter < itgs; iter++) {
smsurf_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &iflgs, sigma, wt, &sm, &smtol, &gstol, &minus, f, grad, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in SMSURF (iteration %" PRId64 "): IER = %" PRId64 "\n", iter, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
if (ierror == 1)
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"Failure in SMSURF: inactive constraint in SMSURF (iteration %" PRId64 "). f is a constant function\n", iter);
if (vartens) { /* compute tension factors sigma (getsig). iflgs > 0 if vt = true. */
iflgs = 1;
getsig_ (&n, x, y, z, f, P.I.list, P.I.lptr, P.I.lend, grad, &tol, sigma, &dsm, &ierror);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in GETSIG (iteration %" PRId64 "): IER = %" PRId64 "\n", iter, ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"GETSIG (iteration %" PRId64 "): %" PRId64 " tension factors altered; Max change = %g\n", iter, ierror, dsm);
}
}
/* compute interpolated values on the uniform grid (unif). */
unif_ (&n, x, y, z, w, P.I.list, P.I.lptr, P.I.lend, &iflgs, sigma, &n_rows, &n_rows, &n_columns, plat, plon, &plus, grad, f, &ierror);
gmt_M_free (GMT, wt);
if (ierror < 0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Failure in UNIF: ier = %" PRId64 "\n", ierror);
error = GMT_RUNTIME_ERROR;
goto free_mem;
}
GMT_Report (GMT->parent, GMT_MSG_INFORMATION,
"UNIF: Number of evaluations = %" PRId64 ", number of extrapolations = %" PRId64 "\n", nm, ierror);
}
free_mem: /* Time to free our memory */
gmt_M_free (GMT, plon);
gmt_M_free (GMT, plat);
gmt_M_free (GMT, P.I.list);
gmt_M_free (GMT, P.I.lptr);
gmt_M_free (GMT, P.I.lend);
gmt_M_free (GMT, sigma);
gmt_M_free (GMT, grad);
gmt_M_free (GMT, wt);
return (error);
}
/* Determine if spherical triangle is oriented clockwise or counter-clockwise */
GMT_LOCAL int gmtsph_orientation (struct GMT_CTRL *GMT, double A[], double B[], double C[]) {
double X[3];
gmt_cross3v (GMT, A, B, X);
return (gmt_dot3v (GMT, X, C) < 0.0 ? -1 : +1);
}
/* Compute spherical triangle area */
double gmtlib_geo_centroid_area (struct GMT_CTRL *GMT, double *lon, double *lat, uint64_t n, double *centroid) {
/* Based on ideas in http://www.jennessent.com/downloads/Graphics_Shapes_Online.pdf and Renka's area_ function.
* Compute area of a spherical polygon and its centroid. */
unsigned int k, kind;
int sgn;
uint64_t p;
double pol_area = 0.0, tri_area, clat, P0[3], P1[3], N[3], M[3], C[3] = {0.0, 0.0, 0.0}, center[2], R2;
static char *way[2] = {"CCW", "CW"};
/* pol_area is given in steradians and must be scaled by radius squared (R2) to yield a dimensioned area */
R2 = pow (GMT->current.proj.mean_radius * GMT->current.map.dist[GMT_MAP_DIST].scale, 2.0); /* R in desired length unit squared (R2) */
if (n == 4) { /* Apply directly on the spherical triangle (4 because of repeated point) */
clat = gmt_lat_swap (GMT, lat[0], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, lon[0], N, true); /* get x/y/z for first point*/
clat = gmt_lat_swap (GMT, lat[1], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, lon[1], P0, true); /* get x/y/z for 2nd point*/
clat = gmt_lat_swap (GMT, lat[2], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, lon[2], P1, true); /* get x/y/z for 3rd point*/
sgn = gmtsph_orientation (GMT, N, P0, P1);
pol_area = areas_ (N, P0, P1); /* Absolute area of this spherical triangle N-P0-P1 */
if (gmt_M_is_verbose (GMT, GMT_MSG_DEBUG)) {
kind = (sgn == -1) ? 0 : 1;
GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Spherical triangle %.4lg/%.4lg via %.4lg/%.4lg to %.4lg/%.4lg : Unit area %7.5lg oriented %3s\n", lon[0], lat[1], lon[1], lat[1], lon[2], lat[2], pol_area, way[kind]);
}
if (centroid) {
for (k = 0; k < 3; k++) C[k] = N[k] + P0[k] + P1[k];
gmt_normalize3v (GMT, C);
gmt_cart_to_geo (GMT, &clat, ¢roid[GMT_X], C, true);
centroid[GMT_Y] = gmt_lat_swap (GMT, clat, GMT_LATSWAP_G2O+1); /* Get geodetic latitude */
}
return (sgn * pol_area * R2); /* Signed area in selected unit squared [km^2] */
}
/* Must split up polygon in a series of triangles */
/* Pick a reference point. Here, we use the mean vector location N */
gmt_mean_point (GMT, lon, lat, n-1, 1, center); /* One less to skip repeated point */
GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Mean spherical polygon point is %lg/%lg\n", center[0], center[1]);
clat = gmt_lat_swap (GMT, center[GMT_Y], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, center[GMT_X], N, true); /* Get x/y/z for mean point */
/* Get first point in the polygon */
clat = gmt_lat_swap (GMT, lat[0], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, lon[0], P0, true); /* Get x/y/z for first point*/
/* In the loop compute the signed areas N-P0-P1 */
n--; /* So we can use <= in loop */
for (p = 1; p <= n; p++) {
/* Each spherical triangle is defined by point N to p-1 (P0) to p (P1) */
clat = gmt_lat_swap (GMT, lat[p], GMT_LATSWAP_G2O); /* Get geocentric latitude */
gmt_geo_to_cart (GMT, clat, lon[p], P1, true); /* Get x/y/z for next point P1 */
tri_area = areas_ (N, P0, P1); /* Absolute area of this spherical triangle N-P0-P1 */
sgn = gmtsph_orientation (GMT, N, P0, P1); /* Sign of this area */
if (gmt_M_is_verbose (GMT, GMT_MSG_DEBUG)) {
kind = (sgn == -1) ? 0 : 1;
GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Spherical triangle %.4lg/%.4lg via %.4lg/%.4lg to %.4lg/%.4lg : Unit area %7.5lg oriented %3s\n", center[0], center[1], lon[p-1], lat[p-1], lon[p], lat[p], tri_area, way[kind]);
}
/* Add up weighted contribution to polygon centroid */
tri_area *= sgn;
pol_area += tri_area;
if (centroid) { /* Compute centroid of this spherical triangle */
for (k = 0; k < 3; k++) M[k] = N[k] + P0[k] + P1[k];
gmt_normalize3v (GMT, M);
for (k = 0; k < 3; k++) C[k] += M[k] * tri_area;
}
if (p < n) gmt_M_memcpy (P0, P1, 3, double); /* Make P1 the next P0 except at end */
}
if (centroid) {
for (k = 0; k < 3; k++) C[k] /= pol_area; /* Get raw centroid */
gmt_normalize3v (GMT, C);
gmt_cart_to_geo (GMT, &clat, ¢roid[GMT_X], C, true);
centroid[GMT_Y] = gmt_lat_swap (GMT, clat, GMT_LATSWAP_G2O+1); /* Get geodetic latitude */
}
return (pol_area * R2); /* Signed area in selected unit squared [km^2] */
}