1 /*--------------------------------------------------------------------
2 *
3 * Copyright (c) 1991-2021 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
4 * See LICENSE.TXT file for copying and redistribution conditions.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; version 3 or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * Contact info: www.generic-mapping-tools.org
16 *--------------------------------------------------------------------*/
17 /*
18 * Author: G. Patau, IGPG, w/ Kurt Feigl
19 * Date: 1-JAN-2010
20 * Version: 6 API
21 * Copyright (c) 1996-2012 by G. Patau, then donated to the GMT project
22 * by G. Patau upon her retirement from IGPG
23 *
24 * Roots: based on psxy.c
25 * Adapted to version 3.3 by Genevieve Patau (25 June 1999)
26 * Last modified : 18 February 2000. Ported to GMT 5 by P. Wessel in 2013.
27 * Updated 3 March 2021 to add color enhancements by P. Wessel
28 *
29 * Brief synopsis: psvelo will read coordinates and plot geodetic symbols
30 * such as velocity ellipses, strain crosses, or strain wedges on maps.
31 */
32
33 #include "gmt_dev.h"
34
35 #define THIS_MODULE_CLASSIC_NAME "psvelo"
36 #define THIS_MODULE_MODERN_NAME "velo"
37 #define THIS_MODULE_LIB "geodesy"
38 #define THIS_MODULE_PURPOSE "Plot velocity vectors, crosses, anisotropy bars and wedges"
39 #define THIS_MODULE_KEYS "<D{,>X}"
40 #define THIS_MODULE_NEEDS "Jd"
41 #define THIS_MODULE_OPTIONS "-:>BJKOPRUVXYdehipqt" GMT_OPT("c")
42
43 #define CINE 1
44 #define ANISO 2
45 #define WEDGE 3
46 #define CROSS 4
47
48 #define DEFAULT_FONTSIZE 9.0 /* In points */
49
50 #define READ_ELLIPSE 0
51 #define READ_ROTELLIPSE 1
52 #define READ_ANISOTROPY 2
53 #define READ_WEDGE 4
54 #define READ_CROSS 8
55
56 /* parameters for writing text */
57 #define ANGLE 0.0
58 #define FORM 0
59
60 /* Control structure for psvelo */
61
62 struct PSVELO_CTRL {
63 struct PSVELO_A { /* -A */
64 bool active;
65 struct GMT_SYMBOL S;
66 } A;
67 struct PSVELO_C { /* -C<cpt> */
68 bool active;
69 char *file;
70 } C;
71 struct PSVELO_D { /* -D */
72 bool active;
73 double scale;
74 } D;
75 struct PSVELO_E { /* -E<fill> */
76 bool active;
77 struct GMT_FILL fill;
78 } E;
79 struct PSVELO_G { /* -G<fill> */
80 bool active;
81 struct GMT_FILL fill;
82 } G;
83 struct PSVELO_H { /* -H read overall scaling factor for symbol size and pen width */
84 bool active;
85 unsigned int mode;
86 double value;
87 } H;
88 struct PSVELO_I { /* -I[<intensity>] */
89 bool active;
90 unsigned int mode; /* 0 if constant, 1 if read from file */
91 double value;
92 } I;
93 struct PSVELO_L { /* -L[<pen>] */
94 bool active;
95 bool error_pen;
96 struct GMT_PEN pen;
97 } L;
98 struct PSVELO_N { /* -N */
99 bool active;
100 } N;
101 struct PSVELO_S { /* -S<symbol> */
102 bool active;
103 bool read; /* True if no scale given; must be first column after the required ones */
104 int symbol;
105 unsigned int readmode;
106 unsigned int n_cols;
107 double scale, wedge_amp, conrad;
108 double confidence;
109 struct GMT_FILL fill;
110 struct GMT_FONT font;
111 } S;
112 struct PSVELO_W { /* -W<pen> */
113 bool active;
114 struct GMT_PEN pen;
115 } W;
116 struct PSVELO_Z { /* -Z */
117 bool active;
118 unsigned int mode;
119 unsigned int item;
120 } Z;
121 };
122
123 enum Psvelo_scaletype {
124 PSVELO_READ_SCALE = 0,
125 PSVELO_CONST_SCALE = 1};
126
127 enum psvelo_types {
128 PSVELO_G_FILL = 0,
129 PSVELO_E_FILL = 1,
130 PSVELO_V_MAG = 0,
131 PSVELO_V_EAST,
132 PSVELO_V_NORTH,
133 PSVELO_R_MAG,
134 PSVELO_V_USER
135 };
136
137 /* Content of old utilvelo.c is here */
138
139 #define squared(x) ((x) * (x))
140 #define EPSIL 0.0001
141
142 /************************************************************************/
psvelo_get_trans(struct GMT_CTRL * GMT,double slon,double slat,double * t11,double * t12,double * t21,double * t22)143 GMT_LOCAL void psvelo_get_trans (struct GMT_CTRL *GMT, double slon, double slat, double *t11, double *t12, double *t21, double *t22) {
144 /* determine local transformation between (lon,lat) and (x,y) */
145 /* return this in the 2 x 2 matrix t */
146 /* this is useful for drawing velocity vectors in X,Y coordinates */
147 /* even on a map which is not a Cartesian projection */
148
149 /* Kurt Feigl, from code by T. Herring */
150
151 /* INPUT */
152 /* slat - latitude, in degrees */
153 /* slon - longitude in degrees */
154
155 /* OUTPUT (returned) */
156 /* t11,t12,t21,t22 transformation matrix */
157 /* COMMENT BY PW: Fails as provided if slat > 89.0 and for projection that
158 * gives the same x-coordinates for two different longitudes, as might happen
159 * at the N or S pole. Some minor protections were added below to handle this.
160 */
161
162 /* LOCAL VARIABLES */
163 double su, sv, udlat, vdlat, udlon, vdlon, dudlat, dvdlat, dudlon, dvdlon, dl;
164 int flip = 0;
165
166 /* how much does x,y change for a 1 degree change in lon,lon ? */
167 gmt_geo_to_xy (GMT, slon, slat, &su, &sv );
168 if ((slat+1.0) >= 90.0) { /* PW: Must do something different at/near NP */
169 gmt_geo_to_xy (GMT, slon, slat-1.0, &udlat, &vdlat);
170 flip = 1;
171 }
172 else
173 gmt_geo_to_xy (GMT, slon, slat+1.0, &udlat, &vdlat);
174 gmt_geo_to_xy (GMT, slon+1.0, slat , &udlon, &vdlon);
175
176 /* Compute dudlat, dudlon, dvdlat, dvdlon */
177 dudlat = udlat - su;
178 dvdlat = vdlat - sv;
179 dudlon = udlon - su;
180 dvdlon = vdlon - sv;
181 if (flip) { /* Fix what we did above */
182 dudlat = -dudlat;
183 dvdlat = -dvdlat;
184 }
185
186 /* Make unit vectors for the long (e/x) and lat (n/y) */
187 /* to construct local transformation matrix */
188
189 dl = sqrt (dudlon*dudlon + dvdlon*dvdlon);
190 *t11 = (dl == 0.0) ? 0.0 : dudlon/dl;
191 *t21 = (dl == 0.0) ? 0.0 : dvdlon/dl;
192
193 dl = sqrt (dudlat*dudlat + dvdlat*dvdlat);
194 *t12 = (dl == 0.0) ? 0.0 : dudlat/dl;
195 *t22 = (dl == 0.0) ? 0.0 : dvdlat/dl;
196 }
197
psvelo_transform_local(double x0,double y0,double dxp,double dyp,double scale,double t11,double t12,double t21,double t22,double * x1,double * y1)198 GMT_LOCAL void psvelo_transform_local (double x0, double y0, double dxp, double dyp, double scale, double t11, double t12, double t21, double t22, double *x1, double *y1) {
199 /* perform local transformation on offsets (dxp,dyp) from */
200 /* "origin point" x0,y0 given transformation matrix T */
201
202 /* Kurt Feigl, from code by T. Herring */
203
204 /* INPUT */
205 /* x0,y0 - dxp,dyp with respect to this point */
206 /* dxp - x component of arrow */
207 /* dyp - y component of arrow */
208 /* scale - scaling for arrow */
209 /* t11,t12,t21,t22 transformation matrix */
210
211 /* OUTPUT (returned) */
212 /* x1,y1 - paper coordinates of arrow tail */
213
214 /* LOCAL VARIABLES */
215 double du, dv;
216
217 /* perform local transformation */
218 du = scale * (t11*dxp + t12*dyp);
219 dv = scale * (t21*dxp + t22*dyp);
220
221 /* Now add to origin and return values */
222 *x1 = x0 + du;
223 *y1 = y0 + dv;
224
225 }
226
psvelo_trace_arrow(struct GMT_CTRL * GMT,double slon,double slat,double dxp,double dyp,double scale,double * x1,double * y1,double * x2,double * y2)227 GMT_LOCAL void psvelo_trace_arrow (struct GMT_CTRL *GMT, double slon, double slat, double dxp, double dyp, double scale, double *x1, double *y1, double *x2, double *y2) {
228 /* convert a vector arrow (delx,dely) arrow from (lat,lon) */
229
230 /* Kurt Feigl, from code by T. Herring */
231
232 /* INPUT */
233 /* slat - latitude, in degrees of arrow tail */
234 /* slon - longitude in degrees of arrow tail */
235 /* dxp - x component of arrow */
236 /* dyp - y component of arrow */
237 /* scale - scaling for arrow */
238
239 /* OUTPUT (returned) */
240 /* x1,y1 - paper coordinates of arrow tail */
241 /* x2,y2 - paper coordinates of arrow head */
242
243 /* local */
244 double t11, t12, t21, t22, xt, yt;
245
246 /* determine local transformation between (lon, lat) and (x, y) */
247 /* return this in the 2 x 2 matrix t */
248 psvelo_get_trans (GMT, slon, slat, &t11, &t12, &t21, &t22);
249
250 /* map start of arrow from lat, lon to x, y */
251 gmt_geo_to_xy (GMT, slon, slat, &xt, &yt);
252
253 /* perform the transformation */
254 psvelo_transform_local (xt, yt, dxp, dyp, scale, t11, t12, t21, t22, x2, y2);
255
256 /* return values */
257
258 *x1 = xt;
259 *y1 = yt;
260 }
261
psvelo_trace_ellipse(double angle,double major,double minor,int npoints,double * x,double * y)262 GMT_LOCAL void psvelo_trace_ellipse (double angle, double major, double minor, int npoints, double *x, double *y) {
263 /* Given specs for an ellipse, return it in x,y */
264 double phi = 0.0, sd, cd, s, c;
265 int i;
266
267 sincosd (angle, &sd, &cd);
268
269 for (i = 0; i < 360; i++) {
270 sincos (phi, &s, &c);
271 *x++ = major * c * cd - minor * s * sd;
272 *y++ = major * c * sd + minor * s * cd;
273 phi += M_PI*2.0/(npoints-2);
274 }
275 }
276
psvelo_ellipse_convert(double sigx,double sigy,double rho,double conrad,double * eigen1,double * eigen2,double * ang)277 GMT_LOCAL void psvelo_ellipse_convert (double sigx, double sigy, double rho, double conrad, double *eigen1, double *eigen2, double *ang) {
278 /* convert from one parameterization of an ellipse to another
279
280 * Kurt Feigl, from code by T. Herring
281
282 * INPUT
283 * sigx, sigy - Sigmas in the x and y directions.
284 * rho - Correlation coefficient between x and y
285
286 * OUTPUT (returned)
287 * eigen1 - the smaller eigenvalue
288 * eigen2 - the larger eigenvalue
289 * ang - Orientation of ellipse relative to X axis in radians
290 * - should be counter-clockwise from X axis
291
292 * LOCAL VARIABLES
293
294 * a,b,c,d,e - Constants used in getting eigenvalues
295 * conrad - Radius for the confidence interval
296 */
297
298 double a, b, c, d, e;
299
300 /* confidence scaling */
301 /* confid - Confidence interval wanted (0-1) */
302 /* conrad = sqrt( -2.0 * log(1.0 - confid)); */
303
304 /* the formulas for this part may be found in Bomford, p. 719 */
305
306 a = squared (sigy*sigy - sigx*sigx);
307 b = 4. * squared (rho*sigx*sigy);
308 c = squared (sigx) + squared (sigy);
309
310 /* minimum eigenvector (semi-minor axis) */
311 *eigen1 = conrad * sqrt ((c - sqrt(a + b))/2.0);
312
313 /* maximu eigenvector (semi-major axis) */
314 *eigen2 = conrad * sqrt ((c + sqrt(a + b))/2.0);
315
316 d = 2. * rho * sigx * sigy;
317 e = squared (sigx) - squared (sigy);
318
319 *ang = atan2 (d, e)/2.0;
320
321 /* that is all */
322 }
323
psvelo_paint_ellipse(struct GMT_CTRL * GMT,double x0,double y0,double angle,double major,double minor,double scale,double t11,double t12,double t21,double t22,int polygon,struct GMT_FILL * fill,int outline)324 GMT_LOCAL void psvelo_paint_ellipse (struct GMT_CTRL *GMT, double x0, double y0, double angle, double major, double minor, double scale, double t11, double t12, double t21, double t22, int polygon, struct GMT_FILL *fill, int outline) {
325 /* Make an ellipse at center x0,y0 */
326 #define NPOINTS_ELLIPSE 362
327
328 int npoints = NPOINTS_ELLIPSE, i;
329 /* relative to center of ellipse */
330 double dxe[NPOINTS_ELLIPSE],dye[NPOINTS_ELLIPSE];
331 /* absolute paper coordinates */
332 double axe[NPOINTS_ELLIPSE],aye[NPOINTS_ELLIPSE];
333
334 psvelo_trace_ellipse (angle, major, minor, npoints, dxe, dye);
335
336 for (i = 0; i < npoints - 2; i++) psvelo_transform_local (x0, y0, dxe[i], dye[i], scale, t11, t12, t21, t22, &axe[i], &aye[i]);
337 if (polygon) {
338 gmt_setfill (GMT, fill, outline);
339 PSL_plotpolygon (GMT->PSL, axe, aye, npoints - 2);
340 }
341 else
342 PSL_plotline (GMT->PSL, axe, aye, npoints - 2, PSL_MOVE|PSL_STROKE|PSL_CLOSE);
343 }
344
345 /************************************************************************/
psvelo_trace_cross(struct GMT_CTRL * GMT,double slon,double slat,double eps1,double eps2,double theta,double sscale,double v_width,double h_length,double h_width,double vector_shape,int outline,struct GMT_PEN * pen)346 GMT_LOCAL int psvelo_trace_cross (struct GMT_CTRL *GMT, double slon, double slat, double eps1, double eps2, double theta, double sscale, double v_width, double h_length, double h_width, double vector_shape, int outline, struct GMT_PEN *pen) {
347 /* make a Strain rate cross at(slat,slon) */
348
349 /* Kurt Feigl, from code by D. Dong */
350
351 /* INPUT VARIABLES: */
352 /* slat - latitude, in degrees of arrow tail */
353 /* slon - longitude in degrees of arrow tail */
354 /* sscale : scaling factor for size of cloverleaf */
355 /* theta : azimuth of more compressive eigenvector (deg) */
356 /* eps1,eps2 : eigenvalues of strain rate (1/yr) */
357 /* v_width, h_length,h_width,vector_shape: arrow characteristics */
358
359 /* local */
360 double dx, dy, x1, x2, y1, y2, hl, hw, vw, s, c, dim[PSL_MAX_DIMS];
361 gmt_M_unused(outline);
362
363 gmt_M_memset (dim, PSL_MAX_DIMS, double);
364 gmt_setpen (GMT, pen); /* Pen for segment line */
365 PSL_setfill (GMT->PSL, pen->rgb, 0); /* Same color for arrow head fill with no outline */
366 sincosd (theta, &s, &c);
367
368 /* extension component */
369 dx = eps1 * c;
370 dy = -eps1 * s;
371
372 /* arrow is outward from slat,slon */
373 psvelo_trace_arrow (GMT, slon, slat, dx, dy, sscale, &x1, &y1, &x2, &y2);
374
375 if (eps1 < 0.0) {
376 gmt_M_double_swap (x1, x2);
377 gmt_M_double_swap (y1, y2);
378 }
379
380 if (hypot (x1-x2,y1-y2) <= 1.5 * h_length) {
381 hl = hypot (x1-x2, y1-y2) * 0.6;
382 hw = hl * h_width / h_length;
383 vw = hl * v_width / h_length;
384 if (vw < 2.0/PSL_DOTS_PER_INCH) vw = 2.0/PSL_DOTS_PER_INCH;
385 }
386 else {
387 hw = h_width;
388 hl = h_length;
389 vw = v_width;
390 }
391
392 dim[PSL_VEC_XTIP] = x2;
393 dim[PSL_VEC_YTIP] = y2;
394 dim[PSL_VEC_TAIL_WIDTH] = vw;
395 dim[PSL_VEC_HEAD_LENGTH] = hl;
396 dim[PSL_VEC_HEAD_WIDTH] = hw;
397 dim[PSL_VEC_HEAD_SHAPE] = vector_shape, dim[PSL_VEC_STATUS] = PSL_VEC_END | PSL_VEC_FILL;
398 PSL_plotsymbol (GMT->PSL, x1, y1, dim, PSL_VECTOR);
399
400 /* second, extensional arrow in opposite direction */
401
402 psvelo_trace_arrow (GMT, slon, slat, -dx, -dy, sscale, &x1, &y1, &x2, &y2);
403
404 if (eps1 < 0.0) {
405 gmt_M_double_swap (x1, x2);
406 gmt_M_double_swap (y1, y2);
407 }
408
409 if (hypot (x1-x2,y1-y2) <= 1.5 * h_length) {
410 hl = hypot (x1-x2,y1-y2) * 0.6;
411 hw = hl * h_width / h_length;
412 vw = hl * v_width / h_length;
413 if (vw < 2.0/PSL_DOTS_PER_INCH) vw = 2.0/PSL_DOTS_PER_INCH;
414 }
415 else {
416 hw = h_width;
417 hl = h_length;
418 vw = v_width;
419 }
420
421 dim[PSL_VEC_XTIP] = x2;
422 dim[PSL_VEC_YTIP] = y2;
423 dim[PSL_VEC_TAIL_WIDTH] = vw;
424 dim[PSL_VEC_HEAD_LENGTH] = hl;
425 dim[PSL_VEC_HEAD_WIDTH] = hw;
426 PSL_plotsymbol (GMT->PSL, x1, y1, dim, PSL_VECTOR);
427
428 /* compression component */
429 dx = eps2 * s;
430 dy = eps2 * c;
431 dim[PSL_VEC_STATUS] = PSL_VEC_BEGIN | PSL_VEC_FILL;
432 psvelo_trace_arrow (GMT, slon, slat, dx, dy, sscale, &x1, &y1, &x2, &y2);
433
434 if (eps2 > 0.0) {
435 gmt_M_double_swap (x1, x2);
436 gmt_M_double_swap (y1, y2);
437 }
438
439 /* arrow should go toward slat, slon */
440 if (hypot (x1-x2,y1-y2) <= 1.5 * h_length) {
441 hl = hypot (x1-x2,y1-y2) * 0.6;
442 hw = hl * h_width / h_length;
443 vw = hl * v_width / h_length;
444 if (vw < 2.0/PSL_DOTS_PER_INCH) vw = 2.0/PSL_DOTS_PER_INCH;
445 }
446 else {
447 hw = h_width;
448 hl = h_length;
449 vw = v_width;
450 }
451
452 dim[PSL_VEC_XTIP] = x2;
453 dim[PSL_VEC_YTIP] = y2;
454 dim[PSL_VEC_TAIL_WIDTH] = vw;
455 dim[PSL_VEC_HEAD_LENGTH] = hl;
456 dim[PSL_VEC_HEAD_WIDTH] = hw;
457 PSL_plotsymbol (GMT->PSL, x1, y1, dim, PSL_VECTOR);
458
459 /* second, compressional arrow in opposite direction */
460
461 psvelo_trace_arrow (GMT, slon, slat, -dx, -dy, sscale, &x1, &y1, &x2, &y2);
462
463 if (eps2 > 0.0) {
464 gmt_M_double_swap (x1, x2);
465 gmt_M_double_swap (y1, y2);
466 }
467
468 /* arrow should go toward slat, slon */
469
470 if (hypot (x1-x2,y1-y2) <= 1.5 * h_length) {
471 hl = hypot (x1-x2,y1-y2) * 0.6;
472 hw = hl * h_width / h_length;
473 vw = hl * v_width / h_length;
474 if (vw < 2.0/PSL_DOTS_PER_INCH) vw = 2.0/PSL_DOTS_PER_INCH;
475 }
476 else {
477 hw = h_width;
478 hl = h_length;
479 vw = v_width;
480 }
481
482 dim[PSL_VEC_XTIP] = x2;
483 dim[PSL_VEC_YTIP] = y2;
484 dim[PSL_VEC_TAIL_WIDTH] = vw;
485 dim[PSL_VEC_HEAD_LENGTH] = hl;
486 dim[PSL_VEC_HEAD_WIDTH] = hw;
487 PSL_plotsymbol (GMT->PSL, x1, y1, dim, PSL_VECTOR);
488
489 return 0;
490 }
491
psvelo_trace_wedge(double spin,double sscale,double wedge_amp,int lines,double * x,double * y)492 GMT_LOCAL int psvelo_trace_wedge (double spin, double sscale, double wedge_amp, int lines, double *x, double *y) {
493 /* make a rotation rate wedge and return in x,y */
494
495 /* Kurt Feigl, from code by D. Dong */
496
497 /* INPUT VARIABLES: */
498 /* slat - latitude, in degrees of arrow tail */
499 /* slon - longitude in degrees of arrow tail */
500 /* sscale : scaling factor for size (radius) of wedge */
501 /* wedge_amp : scaling factor for angular size of wedge */
502 /* spin : CW spin rate in rad/yr */
503 /* line : if true, draw lines */
504
505 int nstep, i1, i, nump;
506 double th, x0, y0, spin10, th0, x1, y1, s, c;
507
508 /* How far would we spin */
509 spin10 = wedge_amp * spin;
510
511 /* set origin */
512 th0 = x0 = y0 = 0.0;
513
514 /* go to zero */
515 nump = 1;
516 *x++ = x0;
517 *y++ = y0;
518 nstep = 100;
519
520 /* make a wedge as wide as the rotation in 10 Myr, */
521 /* with a line for every 0.2 microrad/yr */
522
523 i1 = nstep;
524 for (i = 0; i <= i1 ; ++i) {
525 th = i * spin10 / nstep;
526 sincos (th, &s, &c);
527 x1 = x0 + s * sscale;
528 y1 = y0 + c * sscale;
529 ++nump;
530 *x++ = x1;
531 *y++ = y1;
532 if (lines && fabs (th-th0) >= 0.2) {
533 /* draw a line to the middle */
534 /* go to zero and come back */
535 ++nump;
536 *x++ = x0;
537 *y++ = y0;
538 ++nump;
539 *x++ = x1;
540 *y++ = y1;
541 th0 = th;
542 }
543 }
544
545 /* go to zero */
546 ++nump;
547 *x++ = x0;
548 *y++ = y0;
549
550 return nump;
551 }
552
psvelo_trace_sigwedge(double spin,double spinsig,double sscale,double wedge_amp,double * x,double * y)553 GMT_LOCAL int psvelo_trace_sigwedge (double spin, double spinsig, double sscale, double wedge_amp, double *x, double *y) {
554 /* make a rotation rate uncertainty wedge and return in x,y */
555
556 /* Kurt Feigl, from code by D. Dong */
557
558 /* INPUT VARIABLES: */
559 /* slat - latitude, in degrees of arrow tail */
560 /* slon - longitude in degrees of arrow tail */
561 /* sscale : scaling factor for size (radius) of wedge */
562 /* wedge_amp : scaling factor for angular size of wedge */
563 /* spin,spinsig:CW rotation rate and sigma in rad/yr */
564
565 int nstep, i, nump;
566 double th, x0, y0, spin10, sig10, th0, x1, y1, s, c;
567
568 /* How far would we spin */
569 spin10 = wedge_amp * spin;
570 sig10 = wedge_amp * spinsig;
571
572 /* set origin */
573 x0 = y0 = th0 = 0.0;
574
575 /* go to zero */
576 nump = 1;
577 *x++ = x0;
578 *y++ = y0;
579
580 /* make a dense wedge to show the uncertainty */
581 nstep = 30;
582 for (i = -nstep; i <= nstep; ++i) {
583 th = spin10 + i * sig10 / nstep;
584 sincos (th, &s, &c);
585 x1 = x0 + s * sscale * .67;
586 y1 = y0 + c * sscale * .67;
587 ++nump;
588 *x++ = x1;
589 *y++ = y1;
590 }
591
592 /* return to zero */
593
594 ++nump;
595 *x++ = x0;
596 *y++ = y0;
597 return nump;
598 }
599
psvelo_paint_wedge(struct PSL_CTRL * PSL,double x0,double y0,double spin,double spinsig,double sscale,double wedge_amp,double t11,double t12,double t21,double t22,int polygon,double * rgb,int epolygon,double * ergb,int outline)600 GMT_LOCAL void psvelo_paint_wedge (struct PSL_CTRL *PSL, double x0, double y0, double spin, double spinsig, double sscale, double wedge_amp, double t11, double t12, double t21, double t22, int polygon, double *rgb, int epolygon, double *ergb, int outline) {
601
602 /* Make a wedge at center x0,y0 */
603
604 #define NPOINTS 1000
605
606 int npoints = NPOINTS, i;
607
608 /* relative to center of ellipse */
609 double dxe[NPOINTS], dye[NPOINTS];
610 /* absolute paper coordinates */
611 double axe[NPOINTS], aye[NPOINTS];
612 gmt_M_unused(outline);
613
614 /* draw wedge */
615
616 npoints = psvelo_trace_wedge (spin, 1.0, wedge_amp, true, dxe, dye);
617
618 for (i = 0; i <= npoints - 1; i++)
619 psvelo_transform_local (x0, y0, dxe[i], dye[i], sscale, t11, t12, t21, t22, &axe[i], &aye[i]);
620
621 if (polygon) {
622 PSL_setfill (PSL, rgb, 1);
623 PSL_plotpolygon (PSL, axe, aye, npoints);
624 }
625 else
626 PSL_plotline (PSL, axe, aye, npoints, PSL_MOVE|PSL_STROKE|PSL_CLOSE);
627
628 /* draw uncertainty wedge */
629
630 npoints = psvelo_trace_sigwedge (spin, spinsig, 1.0,wedge_amp, dxe, dye);
631
632 for (i = 0; i < npoints - 1; i++) psvelo_transform_local (x0, y0, dxe[i], dye[i], sscale, t11, t12, t21, t22, &axe[i], &aye[i]);
633
634 if (epolygon) {
635 PSL_setfill (PSL, ergb, 1);
636 PSL_plotpolygon (PSL, axe, aye, npoints - 1);
637 }
638 else
639 PSL_plotline (PSL, axe, aye, npoints - 1, PSL_MOVE|PSL_STROKE|PSL_CLOSE);
640 }
641
642 /* end of utilvelo.c */
643
New_Ctrl(struct GMT_CTRL * GMT)644 static void *New_Ctrl (struct GMT_CTRL *GMT) { /* Allocate and initialize a new control structure */
645 struct PSVELO_CTRL *C;
646
647 C = gmt_M_memory (GMT, NULL, 1, struct PSVELO_CTRL);
648
649 /* Initialize values whose defaults are not 0/false/NULL */
650
651 C->A.S.size_x = VECTOR_HEAD_LENGTH * GMT->session.u2u[GMT_PT][GMT_INCH]; /* 9p */
652 C->A.S.v.h_length = (float)C->A.S.size_x; /* 9p */
653 C->A.S.v.v_angle = 30.0f;
654 C->A.S.v.status = PSL_VEC_END + PSL_VEC_FILL + PSL_VEC_OUTLINE;
655 C->A.S.v.pen = GMT->current.setting.map_default_pen;
656 if (gmt_M_compat_check (GMT, 4)) GMT->current.setting.map_vector_shape = 0.4; /* Historical reasons */
657 C->A.S.v.v_shape = (float)GMT->current.setting.map_vector_shape;
658 C->D.scale = 1.0;
659 gmt_init_fill (GMT, &C->E.fill, 1.0, 1.0, 1.0);
660 gmt_init_fill (GMT, &C->G.fill, 0.0, 0.0, 0.0);
661 C->S.wedge_amp = 1.e7;
662 C->S.conrad = 1.0;
663 C->S.font = GMT->current.setting.font_annot[GMT_PRIMARY];
664 C->S.font.size = 9;
665 C->W.pen = GMT->current.setting.map_default_pen;
666 return (C);
667 }
668
Free_Ctrl(struct GMT_CTRL * GMT,struct PSVELO_CTRL * C)669 static void Free_Ctrl (struct GMT_CTRL *GMT, struct PSVELO_CTRL *C) { /* Deallocate control structure */
670 if (!C) return;
671 gmt_M_free (GMT, C);
672 }
673
usage(struct GMTAPI_CTRL * API,int level)674 static int usage (struct GMTAPI_CTRL *API, int level) {
675 /* This displays the psvelo synopsis and optionally full usage information */
676
677 const char *name = gmt_show_name_and_purpose (API, THIS_MODULE_LIB, THIS_MODULE_CLASSIC_NAME, THIS_MODULE_PURPOSE);
678 if (level == GMT_MODULE_PURPOSE) return (GMT_NOERROR);
679 GMT_Usage (API, 0, "usage: %s [<table>] %s %s -S<symbol>[<scale>][</args>][+f<font>] [-A<vecpar>] [%s] [-C<cpt>] [-D<scale>] [-E<fill>] "
680 "[-G<fill>] [-H[<scale>]] [-I[<intens>]] %s[-L[<pen>][+c[f|l]]] [-N] %s%s[%s] [%s] "
681 "[-W[<pen>][+c[f|l]]] [%s] [%s] [-Z[m|e|n|u][+e]] %s[%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s] [%s]\n",
682 name, GMT_J_OPT, GMT_Rgeo_OPT, GMT_B_OPT, API->K_OPT, API->O_OPT, API->P_OPT, GMT_U_OPT, GMT_V_OPT, GMT_X_OPT,
683 GMT_Y_OPT, API->c_OPT, GMT_di_OPT, GMT_e_OPT, GMT_h_OPT, GMT_i_OPT, GMT_p_OPT, GMT_qi_OPT, GMT_tv_OPT, GMT_colon_OPT, GMT_PAR_OPT);
684
685 if (level == GMT_SYNOPSIS) return (GMT_MODULE_SYNOPSIS);
686
687 GMT_Message (API, GMT_TIME_NONE, " REQUIRED ARGUMENTS:\n");
688 GMT_Option (API, "<");
689 GMT_Option (API, "J-,R");
690 GMT_Usage (API, 1, "\n-S<symbol>[<scale>][</args>][+f<font>]");
691 GMT_Usage (API, -2, "Select symbol type and <scale> (plus optional font; see documentation). "
692 "If <scale> is not given then it is read from the first column after the required columns. "
693 "Choose from the following geodetic symbols:");
694 GMT_Usage (API, 3, "e: Velocity ellipses: in X,Y,Vx,Vy,SigX,SigY,CorXY,name format. "
695 "Append <confidence> value (0-1) for error ellipse or give 0 to not draw the ellipse.");
696 GMT_Usage (API, 3, "r: Velocity ellipses: in X,Y,Vx,Vy,a,b,theta,name format. "
697 "Append <confidence> value (0-1) for error ellipse or give 0 to not draw the ellipse.");
698 GMT_Usage (API, 3, "n: Anisotropy: in X,Y,Vx,Vy.");
699 GMT_Usage (API, 3, "w: Rotational wedges: in X,Y,Spin,Spinsig. "
700 "Append <wedgemag> value to scale the the Spin values [1].");
701 GMT_Usage (API, 3, "x: Strain crosses: in X,Y,Eps1,Eps2,Theta.n");
702 GMT_Message (API, GMT_TIME_NONE, "\n OPTIONAL ARGUMENTS:\n");
703 GMT_Option (API, "B-");
704 GMT_Usage (API, 1, "\n-A<vecpar>");
705 GMT_Usage (API, -2, "Specify arrow head attributes:");
706 gmt_vector_syntax (API->GMT, 15, 3);
707 GMT_Usage (API, -2, "Default is %gp+gblack+p1p", VECTOR_HEAD_LENGTH);
708 GMT_Usage (API, 1, "\n-C<cpt>");
709 GMT_Usage (API, -2, "Use CPT to assign colors based on vector magnitude. "
710 "For other coloring options, see -W and -Z.");
711 GMT_Usage (API, 1, "\n-D<scale>");
712 GMT_Usage (API, -2, "Multiply uncertainties by <scale> (for -Se and -Sw options only).");
713 GMT_Usage (API, 1, "\n-E<fill>");
714 GMT_Usage (API, -2, "Set color used for uncertainty ellipses and wedges [no fill]; see -G for syntax. "
715 "For other coloring options, see -L and -Z.");
716 gmt_fill_syntax (API->GMT, 'G', NULL, "Specify color or pattern for symbol fill [no fill].");
717 GMT_Usage (API, 1, "\n-H[<scale>]");
718 GMT_Usage (API, -2, "Scale symbol sizes (set via -S or input column) and pen attributes by factors read from scale column. "
719 "he scale column follows the symbol size column. Alternatively, append a fixed <scale>.");
720 GMT_Usage (API, 1, "\n-I[<intens>]");
721 GMT_Usage (API, -2, "Use the intensity to modulate the symbol fill color (requires -C or -G). "
722 "If no intensity is given we expect it to follow the required columns in the data record.");
723 GMT_Option (API, "K");
724 GMT_Usage (API, 1, "\n-L[<pen>][+c[f|l]]");
725 GMT_Usage (API, -2, "Draw line or symbol outline using the current pen (see -W). "
726 "Optionally, append separate pen for error outlines [Same as -W].");
727 GMT_Usage (API, 1, "\n-N Do Not skip/clip symbols that fall outside map border [Default will ignore those outside].");
728 GMT_Option (API, "O,P");
729 GMT_Option (API, "U,V");
730 GMT_Usage (API, 1, "\n-W[<pen>][+c[f|l]]");
731 GMT_Usage (API, -2, "Set pen attributes [%s].", gmt_putpen (API->GMT, &API->GMT->current.setting.map_default_pen));
732 GMT_Option (API, "X");
733 GMT_Usage (API, 1, "\n-Z[m|e|n|u][+e]");
734 GMT_Usage (API, -2, "Select quantity to use with -C to look-up colors. Choose among:");
735 GMT_Usage (API, 3, "m: Magnitude of vector or rotation [Default].");
736 GMT_Usage (API, 3, "e: East velocity component.");
737 GMT_Usage (API, 3, "n: North velocity component.");
738 GMT_Usage (API, 3, "u: User column (given after required columns).");
739 GMT_Usage (API, -2, "Note: Color selected will replace -G<fill>. Append +e to instead act as -E<fill>.");
740 GMT_Option (API, "c,di,e,h,i,p,qi,T,:,.");
741
742 return (GMT_MODULE_USAGE);
743 }
744
parse(struct GMT_CTRL * GMT,struct PSVELO_CTRL * Ctrl,struct GMT_OPTION * options)745 static int parse (struct GMT_CTRL *GMT, struct PSVELO_CTRL *Ctrl, struct GMT_OPTION *options) {
746 /* This parses the options provided to psvelo and sets parameters in Ctrl.
747 * Note Ctrl has already been initialized and non-zero default values set.
748 * Any GMT common options will override values set previously by other commands.
749 * It also replaces any file names specified as input or output with the data ID
750 * returned when registering these sources/destinations with the API.
751 */
752
753 unsigned int n_errors = 0, n_set;
754 int n;
755 bool got_A = false, got_shape = false;
756 char txt[GMT_LEN256] = {""}, txt_b[GMT_LEN256] = {""}, txt_c[GMT_LEN256] = {""}, symbol, *c = NULL;
757 struct GMT_OPTION *opt = NULL;
758 struct GMTAPI_CTRL *API = GMT->parent;
759
760 symbol = (gmt_M_is_geographic (GMT, GMT_IN)) ? '=' : 'v'; /* Type of vector */
761
762 for (opt = options; opt; opt = opt->next) { /* Process all the options given */
763
764 switch (opt->option) {
765
766 case '<': /* Skip input files */
767 if (GMT_Get_FilePath (API, GMT_IS_DATASET, GMT_IN, GMT_FILE_REMOTE, &(opt->arg))) n_errors++;;
768 break;
769
770 /* Processes program-specific parameters */
771
772 case 'A': /* Change size of arrow head */
773 n_errors += gmt_M_repeated_module_option (API, Ctrl->A.active);
774 got_A = true;
775 if (gmt_M_compat_check (GMT, 4) && (strchr (opt->arg, '/') && !strchr (opt->arg, '+'))) { /* Old-style args */
776 sscanf (opt->arg, "%[^/]/%[^/]/%s", txt, txt_b, txt_c);
777 Ctrl->A.S.v.v_width = (float)gmt_M_to_inch (GMT, txt);
778 Ctrl->A.S.v.h_length = (float)gmt_M_to_inch (GMT, txt_b);
779 Ctrl->A.S.v.h_width = (float)gmt_M_to_inch (GMT, txt_c);
780 Ctrl->A.S.v.v_angle = (float)atand (0.5 * Ctrl->A.S.v.h_width / Ctrl->A.S.v.h_length);
781 Ctrl->A.S.v.status |= PSL_VEC_OUTLINE2;
782 Ctrl->A.S.symbol = GMT_SYMBOL_VECTOR_V4;
783 }
784 else {
785 if (opt->arg[0] == '+') { /* No size (use default), just attributes */
786 n_errors += gmt_parse_vector (GMT, symbol, opt->arg, &Ctrl->A.S);
787 }
788 else { /* Size, plus possible attributes */
789 n = sscanf (opt->arg, "%[^+]%s", txt, txt_b); /* txt_a should be symbols size with any +<modifiers> in txt_b */
790 if (n == 1) txt_b[0] = 0; /* No modifiers present, set txt_b to empty */
791 Ctrl->A.S.size_x = gmt_M_to_inch (GMT, txt); /* Length of vector */
792 n_errors += gmt_parse_vector (GMT, symbol, txt_b, &Ctrl->A.S);
793 }
794 Ctrl->A.S.symbol = PSL_VECTOR;
795 if (strstr (opt->arg, "+h")) got_shape = true; /* User specified vector head shape */
796 }
797 break;
798 case 'C': /* Select CPT for coloring */
799 n_errors += gmt_M_repeated_module_option (API, Ctrl->C.active);
800 Ctrl->C.active = true;
801 if (opt->arg[0]) Ctrl->C.file = strdup (opt->arg);
802 break;
803 case 'D': /* Rescale sigmas */
804 n_errors += gmt_M_repeated_module_option (API, Ctrl->D.active);
805 Ctrl->D.active = true;
806 Ctrl->D.scale = atof (opt->arg);
807 break;
808 case 'E': /* Set color for error ellipse */
809 n_errors += gmt_M_repeated_module_option (API, Ctrl->E.active);
810 if (gmt_getfill (GMT, opt->arg, &Ctrl->E.fill)) {
811 gmt_fill_syntax (GMT, 'E', NULL, " ");
812 n_errors++;
813 }
814 Ctrl->E.active = true;
815 break;
816 case 'G': /* Set Gray shade for polygon */
817 n_errors += gmt_M_repeated_module_option (API, Ctrl->G.active);
818 Ctrl->G.active = true;
819 if (gmt_getfill (GMT, opt->arg, &Ctrl->G.fill)) {
820 gmt_fill_syntax (GMT, 'G', NULL, " ");
821 n_errors++;
822 }
823 break;
824 case 'H': /* Overall symbol/pen scale column provided */
825 n_errors += gmt_M_repeated_module_option (API, Ctrl->H.active);
826 Ctrl->H.active = true;
827 if (opt->arg[0]) { /* Gave a fixed scale - no reading from file */
828 Ctrl->H.value = atof (opt->arg);
829 Ctrl->H.mode = PSVELO_CONST_SCALE;
830 }
831 break;
832 case 'I': /* Adjust symbol color via intensity */
833 n_errors += gmt_M_repeated_module_option (API, Ctrl->I.active);
834 Ctrl->I.active = true;
835 if (opt->arg[0])
836 Ctrl->I.value = atof (opt->arg);
837 else
838 Ctrl->I.mode = 1;
839 break;
840 case 'L': /* Draw the outline */
841 n_errors += gmt_M_repeated_module_option (API, Ctrl->L.active);
842 Ctrl->L.active = true;
843 if (opt->arg[0]) {
844 Ctrl->L.error_pen = true;
845 if (gmt_getpen (GMT, opt->arg, &Ctrl->L.pen)) {
846 gmt_pen_syntax (GMT, 'L', NULL, " ", NULL, 0);
847 n_errors++;
848 }
849 }
850 break;
851 case 'N': /* Do not skip points outside border */
852 n_errors += gmt_M_repeated_module_option (API, Ctrl->N.active);
853 Ctrl->N.active = true;
854 break;
855 case 'S': /* Get symbol [and size] */
856 n_errors += gmt_M_repeated_module_option (API, Ctrl->S.active);
857 txt_b[0] = '\0';
858 if ((c = strstr (opt->arg, "+f"))) { /* Gave font directly so handle that first */
859 if (c[2] == '0')
860 Ctrl->S.font.size = 0;
861 else
862 n_errors += gmt_getfont (GMT, &c[2], &(Ctrl->S.font));
863 c[0] = '\0'; /* Temporarily chop off the font specification */
864 }
865 if (strchr ("er", opt->arg[0])) { /* Error ellipse with vector symbol for -Se and -Sr */
866 strncpy (txt, &opt->arg[1], GMT_LEN256); /* Copy of the args after -Se|r */
867 n = 0;
868 if (strchr (txt, '/')) { /* We clearly have scale/confidence and possibly /fontsize (deprecated) */
869 while (txt[n] && txt[n] != '/') n++; txt[n++] = 0; /* Hide the /confidence part */
870 Ctrl->S.scale = gmt_M_to_inch (GMT, txt); /* Get symbol size */
871 }
872 sscanf (&txt[n], "%lf/%s", &Ctrl->S.confidence, txt_b);
873 /* confidence scaling */
874 Ctrl->S.conrad = sqrt (-2.0 * log (1.0 - Ctrl->S.confidence));
875 /* Check for deprecated font syntax */
876 if (txt_b[0]) Ctrl->S.font.size = gmt_convert_units (GMT, txt_b, GMT_PT, GMT_PT);
877 }
878 else if (strchr ("nx", opt->arg[0])) { /* Simple one-parameter argument for -Sn and -Sx */
879 if (opt->arg[1]) Ctrl->S.scale = gmt_M_to_inch (GMT, &opt->arg[1]);
880 }
881 else if (opt->arg[0] == 'w') { /* Rotational wedge */
882 strncpy (txt, &opt->arg[1], GMT_LEN256);
883 n = 0;
884 if (strchr (txt, '/')) { /* We clearly have scale/wedgemag */
885 while (txt[n] && txt[n] != '/') n++; txt[n++] = 0; /* Hide the /wedgemag part */
886 Ctrl->S.scale = gmt_M_to_inch (GMT, txt); /* Get symbol size */
887 }
888 Ctrl->S.wedge_amp = (txt[n]) ? atof (&txt[n]) : 1.0;
889 }
890 switch (opt->arg[0]) { /* Set modes and expected input columns */
891 case 'e':
892 Ctrl->S.symbol = CINE; Ctrl->S.n_cols = 7;
893 Ctrl->S.readmode = READ_ELLIPSE;
894 break;
895 case 'r':
896 Ctrl->S.symbol = CINE; Ctrl->S.n_cols = 7;
897 Ctrl->S.readmode = READ_ROTELLIPSE;
898 break;
899 case 'n':
900 Ctrl->S.symbol = ANISO; Ctrl->S.n_cols = 4;
901 Ctrl->S.readmode = READ_ANISOTROPY;
902 break;
903 case 'w':
904 Ctrl->S.symbol = WEDGE; Ctrl->S.n_cols = 4;
905 Ctrl->S.readmode = READ_WEDGE;
906 break;
907 case 'x':
908 Ctrl->S.symbol = CROSS; Ctrl->S.n_cols = 5;
909 Ctrl->S.readmode = READ_CROSS;
910 break;
911 default:
912 GMT_Report (API, GMT_MSG_ERROR, "Option -S: Unrecognized symbol code %s\n", opt->arg);
913 n_errors++;
914 break;
915 }
916 if (c) c[0] = '+'; /* Restore font specification */
917 if (gmt_M_is_zero (Ctrl->S.scale)) Ctrl->S.read = true; /* Must get size from input file */
918 break;
919 case 'W': /* Set line attributes */
920 n_errors += gmt_M_repeated_module_option (API, Ctrl->W.active);
921 Ctrl->W.active = true;
922 if (opt->arg[0] && gmt_getpen (GMT, opt->arg, &Ctrl->W.pen)) {
923 gmt_pen_syntax (GMT, 'W', NULL, " ", NULL, 0);
924 n_errors++;
925 }
926 break;
927 case 'Z': /* Set items to control CPT coloring */
928 n_errors += gmt_M_repeated_module_option (API, Ctrl->Z.active);
929 Ctrl->Z.active = true;
930 if (opt->arg[0] && (c = strstr (opt->arg, "+e"))) { /* Paint error part of symbol instead (-E) */
931 Ctrl->Z.item = PSVELO_E_FILL;
932 c[0] = '\0'; /* Temporarily chop off the modifier */
933 }
934 switch (opt->arg[0]) {
935 case 'm': case '\0': Ctrl->Z.mode = PSVELO_V_MAG; break;
936 case 'e': Ctrl->Z.mode = PSVELO_V_EAST; break;
937 case 'n': Ctrl->Z.mode = PSVELO_V_NORTH; break;
938 case 'r': Ctrl->Z.mode = PSVELO_R_MAG; break;
939 case 'u': Ctrl->Z.mode = PSVELO_V_USER; break;
940 default:
941 GMT_Report (API, GMT_MSG_ERROR, "Option -Z: Unrecognized mode %s\n", opt->arg);
942 n_errors++;
943 break;
944 }
945 if (c) c[0] = '+'; /* Restore modifier */
946 break;
947
948 /* Illegal options */
949
950 }
951 }
952
953 if (Ctrl->S.symbol == CROSS && !got_shape) Ctrl->A.S.v.v_shape = 0.1; /* Traditional default cross vector shape if none given */
954 gmt_consider_current_cpt (API, &Ctrl->C.active, &(Ctrl->C.file));
955
956 /* Only one allowed */
957 n_set = (Ctrl->S.readmode == READ_ELLIPSE) + (Ctrl->S.readmode == READ_ROTELLIPSE) + (Ctrl->S.readmode == READ_ANISOTROPY) + (Ctrl->S.readmode == READ_CROSS) + (Ctrl->S.readmode == READ_WEDGE);
958 n_errors += gmt_M_check_condition (GMT, !GMT->common.R.active[RSET], "Must specify -R option\n");
959 n_errors += gmt_M_check_condition (GMT, n_set > 1, "Only one -S setting is allowed.\n");
960 n_errors += gmt_M_check_condition (GMT, Ctrl->D.active && ! (Ctrl->S.readmode == READ_ELLIPSE || Ctrl->S.readmode == READ_WEDGE), "Option -D requires -Se|w.\n");
961 n_errors += gmt_M_check_condition (GMT, Ctrl->Z.active && !Ctrl->C.active, "Option -Z requires -C.\n");
962 n_errors += gmt_M_check_condition (GMT, Ctrl->C.active && Ctrl->Z.item == PSVELO_E_FILL && Ctrl->E.active, "Options -C -Z+e cannot be combined with -E.\n");
963 n_errors += gmt_M_check_condition (GMT, Ctrl->C.active && Ctrl->Z.item == PSVELO_G_FILL && Ctrl->G.active, "Options -C -Z cannot be combined with -G.\n");
964
965 if (!got_A && Ctrl->W.active) Ctrl->A.S.v.pen = Ctrl->W.pen; /* Set vector pen to that given by -W if -A was not set */
966 return (n_errors ? GMT_PARSE_ERROR : GMT_NOERROR);
967 }
968
969 #define bailout(code) {gmt_M_free_options (mode); return (code);}
970 #define Return(code) {Free_Ctrl (GMT, Ctrl); gmt_end_module (GMT, GMT_cpy); bailout (code);}
971
psvelo_set_colorfill(struct GMT_CTRL * GMT,struct PSVELO_CTRL * Ctrl,struct GMT_PALETTE * P,double value,double ival)972 GMT_LOCAL void psvelo_set_colorfill (struct GMT_CTRL *GMT, struct PSVELO_CTRL *Ctrl, struct GMT_PALETTE *P, double value, double ival) {
973 /* Called if -C was given. Selects and updates color fills and possibly pen colors */
974 struct GMT_FILL *F = (Ctrl->Z.item == PSVELO_G_FILL) ? &Ctrl->G.fill : &Ctrl->E.fill;
975 if (P) gmt_get_fill_from_z (GMT, P, value, F); /* Update color based on value and CPT */
976 if (Ctrl->I.active) { /* Modulate color based on intensity ival */
977 gmt_illuminate (GMT, ival, F->rgb);
978 GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Illumination value used is %h\n", ival);
979 }
980 if (Ctrl->L.pen.cptmode & 1) { /* Also change error pen color via CPT */
981 gmt_M_rgb_copy (Ctrl->L.pen.rgb, F->rgb);
982 gmt_setpen (GMT, &Ctrl->L.pen);
983 }
984 if (Ctrl->W.pen.cptmode & 1) { /* Also change pen color via CPT */
985 gmt_M_rgb_copy (Ctrl->W.pen.rgb, F->rgb);
986 gmt_setpen (GMT, &Ctrl->W.pen);
987 if (!Ctrl->L.error_pen) /* No -L pen so duplicate the change */
988 gmt_M_rgb_copy (Ctrl->L.pen.rgb, Ctrl->W.pen.rgb);
989 }
990 }
991
GMT_psvelo(void * V_API,int mode,void * args)992 EXTERN_MSC int GMT_psvelo (void *V_API, int mode, void *args) {
993 int ix = 0, iy = 1, n_rec = 0, justify;
994 int plot_ellipse = true, plot_vector = true, error = false;
995 unsigned int xcol = 0, tcol_f = 0, tcol_s = 0, scol = 0, icol = 0, n_warn = 0;
996 bool set_g_fill, set_e_fill;
997
998 double plot_x, plot_y, vxy[2], plot_vx, plot_vy, length, s, dim[PSL_MAX_DIMS];
999 double eps1 = 0.0, eps2 = 0.0, spin = 0.0, spinsig = 0.0, theta = 0.0, *in = NULL;
1000 double direction = 0, small_axis = 0, great_axis = 0, sigma_x, sigma_y, corr_xy;
1001 double t11 = 1.0, t12 = 0.0, t21 = 0.0, t22 = 1.0, hl, hw, vw, ssize, headpen_width = 0.0;
1002 double z_val, e_val, value, scale, size, i_value, nominal_size;
1003
1004 char *station_name = NULL;
1005
1006 struct GMT_RECORD *In = NULL;
1007 struct GMT_PALETTE *CPT = NULL;
1008 struct GMT_PEN current_pen;
1009 struct PSVELO_CTRL *Ctrl = NULL;
1010 struct GMT_CTRL *GMT = NULL, *GMT_cpy = NULL; /* General GMT internal parameters */
1011 struct GMT_OPTION *options = NULL;
1012 struct PSL_CTRL *PSL = NULL; /* General PSL internal parameters */
1013 struct GMTAPI_CTRL *API = gmt_get_api_ptr (V_API); /* Cast from void to GMTAPI_CTRL pointer */
1014
1015 /*----------------------- Standard module initialization and parsing ----------------------*/
1016
1017 if (API == NULL) return (GMT_NOT_A_SESSION);
1018 if (mode == GMT_MODULE_PURPOSE) return (usage (API, GMT_MODULE_PURPOSE)); /* Return the purpose of program */
1019 options = GMT_Create_Options (API, mode, args); if (API->error) return (API->error); /* Set or get option list */
1020
1021 if ((error = gmt_report_usage (API, options, 0, usage)) != GMT_NOERROR) bailout (error); /* Give usage if requested */
1022
1023 /* Parse the command-line arguments; return if errors are encountered */
1024
1025 if ((GMT = gmt_init_module (API, THIS_MODULE_LIB, THIS_MODULE_CLASSIC_NAME, THIS_MODULE_KEYS, THIS_MODULE_NEEDS, NULL, &options, &GMT_cpy)) == NULL) bailout (API->error); /* Save current state */
1026 if (GMT_Parse_Common (API, THIS_MODULE_OPTIONS, options)) Return (API->error);
1027 Ctrl = New_Ctrl (GMT); /* Allocate and initialize a new control structure */
1028 if ((error = parse (GMT, Ctrl, options)) != 0) Return (error);
1029
1030 /*---------------------------- This is the psvelo main code ----------------------------*/
1031
1032 set_e_fill = Ctrl->E.active; set_g_fill = Ctrl->G.active;
1033 if (Ctrl->C.active) {
1034 if ((CPT = GMT_Read_Data (API, GMT_IS_PALETTE, GMT_IS_FILE, GMT_IS_NONE, GMT_READ_NORMAL, NULL, Ctrl->C.file, NULL)) == NULL) {
1035 Return (API->error);
1036 }
1037 if (Ctrl->Z.item == PSVELO_G_FILL) set_g_fill = true; /* Since we will set it via CPT lookup */
1038 if (Ctrl->Z.item == PSVELO_E_FILL) set_e_fill = true; /* Since we will set it via CPT lookup */
1039 }
1040 else if (Ctrl->I.active && Ctrl->I.mode == 0) { /* Constant illumination with constant intensity can be done once before data loop */
1041 gmt_illuminate (GMT, Ctrl->I.value, Ctrl->E.fill.rgb);
1042 gmt_illuminate (GMT, Ctrl->I.value, Ctrl->G.fill.rgb);
1043 Ctrl->I.active = false; /* So we don't do this again */
1044 }
1045 i_value = Ctrl->I.value; /* May be replaced in the loop if variable intensity was given */
1046 if (Ctrl->S.symbol == CINE && Ctrl->S.confidence > 0.0 && !(Ctrl->E.active || Ctrl->L.active))
1047 Ctrl->L.active = true; /* If confidence is > 0 but neither -E or -L is set then we turn on -L to pick up -W pen (below) */
1048 if (Ctrl->L.active && !Ctrl->L.error_pen) /* Duplicate -W to -L */
1049 gmt_M_memcpy (&Ctrl->L.pen, &Ctrl->W.pen, 1, struct GMT_PEN);
1050
1051 if (gmt_map_setup (GMT, GMT->common.R.wesn)) Return (GMT_PROJECTION_ERROR);
1052
1053 if ((PSL = gmt_plotinit (GMT, options)) == NULL) Return (GMT_RUNTIME_ERROR);
1054 gmt_set_basemap_orders (GMT, Ctrl->N.active ? GMT_BASEMAP_FRAME_BEFORE : GMT_BASEMAP_FRAME_AFTER, GMT_BASEMAP_GRID_BEFORE, GMT_BASEMAP_ANNOT_AFTER);
1055 gmt_plane_perspective (GMT, GMT->current.proj.z_project.view_plane, GMT->current.proj.z_level);
1056 gmt_plotcanvas (GMT); /* Fill canvas if requested */
1057 gmt_map_basemap (GMT); /* Basemap before data */
1058
1059 gmt_M_memset (¤t_pen, 1, struct GMT_PEN);
1060 gmt_M_memset (dim, PSL_MAX_DIMS, double);
1061 gmt_setpen (GMT, &Ctrl->W.pen);
1062 PSL_setfont (PSL, GMT->current.setting.font_annot[GMT_PRIMARY].id);
1063
1064 if (!Ctrl->N.active) gmt_map_clip_on (GMT, GMT->session.no_rgb, 3);
1065 gmt_init_vector_param (GMT, &Ctrl->A.S, true, Ctrl->W.active, &Ctrl->W.pen, Ctrl->G.active, &Ctrl->G.fill);
1066 if (Ctrl->A.S.symbol == PSL_VECTOR) Ctrl->A.S.v.v_width = (float)(Ctrl->W.pen.width * GMT->session.u2u[GMT_PT][GMT_INCH]);
1067
1068 ix = (GMT->current.setting.io_lonlat_toggle[0]); iy = 1 - ix; /* Deal with -: */
1069
1070 /* 1. Add user column for coloring, if requested */
1071 if (Ctrl->Z.mode == PSVELO_V_USER) Ctrl->S.n_cols++; /* Need to read one extra column */
1072 /* 2. Add scale from file, if missing */
1073 if (Ctrl->S.read) { /* Read symbol size from file */
1074 scol = Ctrl->S.n_cols; /* Column ID with scales */
1075 Ctrl->S.n_cols++; /* Must read an extra column */
1076 gmt_set_column_type (GMT, GMT_IN, scol, GMT_IS_DIMENSION);
1077 }
1078 else /* Fixed symbol scale */
1079 nominal_size = scale = Ctrl->S.scale;
1080 /* 3. Add scaling from file, if requested */
1081 if (Ctrl->H.active && Ctrl->H.mode == PSVELO_READ_SCALE) {
1082 xcol = Ctrl->S.n_cols;
1083 Ctrl->S.n_cols++; /* Read scaling from data file */
1084 gmt_set_column_type (GMT, GMT_IN, xcol, GMT_IS_FLOAT);
1085 }
1086 /* 4. Add intensity from file, if requested */
1087 if (Ctrl->I.mode) { /* Read intensity from data file */
1088 icol = Ctrl->S.n_cols; /* Column id for intensity */
1089 Ctrl->S.n_cols++; /* One more data column required */
1090 gmt_set_column_type (GMT, GMT_IN, icol, GMT_IS_FLOAT);
1091 }
1092 /* 5. Add transparencies from file, if requested */
1093 if (GMT->common.t.variable) { /* Need one or two transparencies from file */
1094 if (GMT->common.t.mode & GMT_SET_FILL_TRANSP) {
1095 tcol_f = Ctrl->S.n_cols;
1096 Ctrl->S.n_cols++; /* Read fill transparencies from data file */
1097 gmt_set_column_type (GMT, GMT_IN, tcol_f, GMT_IS_FLOAT);
1098 }
1099 if (GMT->common.t.mode & GMT_SET_PEN_TRANSP) {
1100 tcol_s = Ctrl->S.n_cols;
1101 Ctrl->S.n_cols++; /* Read stroke transparencies from data file */
1102 gmt_set_column_type (GMT, GMT_IN, tcol_s, GMT_IS_FLOAT);
1103 }
1104 }
1105
1106 GMT_Set_Columns (API, GMT_IN, Ctrl->S.n_cols, GMT_COL_FIX);
1107
1108 if (GMT_Init_IO (API, GMT_IS_DATASET, GMT_IS_POINT, GMT_IN, GMT_ADD_DEFAULT, 0, options) != GMT_NOERROR) { /* Register data input */
1109 Return (API->error);
1110 }
1111 if (GMT_Begin_IO (API, GMT_IS_DATASET, GMT_IN, GMT_HEADER_ON) != GMT_NOERROR) { /* Enables data input and sets access mode */
1112 Return (API->error);
1113 }
1114
1115 if (Ctrl->S.readmode == READ_ELLIPSE || Ctrl->S.readmode == READ_ROTELLIPSE) GMT_Report (API, GMT_MSG_INFORMATION, "psvelo: 2-D confidence interval and scaling factor %f %f\n", Ctrl->S.confidence, Ctrl->S.conrad);
1116
1117 if (Ctrl->D.active) GMT_Report (API, GMT_MSG_INFORMATION, "Rescaling uncertainties by a factor of %f\n", Ctrl->D.scale);
1118
1119 if (Ctrl->S.symbol == CINE || Ctrl->S.symbol == CROSS) {
1120 if (Ctrl->A.S.v.status & PSL_VEC_OUTLINE2) { /* Vector head outline pen specified separately */
1121 PSL_defpen (PSL, "PSL_vecheadpen", Ctrl->A.S.v.pen.width, Ctrl->A.S.v.pen.style, Ctrl->A.S.v.pen.offset, Ctrl->A.S.v.pen.rgb);
1122 headpen_width = 0.5 * Ctrl->A.S.v.pen.width;
1123 }
1124 else { /* Reset to default pen */
1125 if (Ctrl->W.active) { /* Vector head outline pen default is half that of stem pen */
1126 PSL_defpen (PSL, "PSL_vecheadpen", Ctrl->W.pen.width, Ctrl->W.pen.style, Ctrl->W.pen.offset, Ctrl->W.pen.rgb);
1127 headpen_width = 0.5 * Ctrl->W.pen.width;
1128 }
1129 }
1130 }
1131 do { /* Keep returning records until we reach EOF */
1132 if ((In = GMT_Get_Record (API, GMT_READ_MIXED, NULL)) == NULL) { /* Read next record, get NULL if special case */
1133 if (gmt_M_rec_is_error (GMT)) /* Bail if there are any read errors */
1134 Return (GMT_RUNTIME_ERROR);
1135 if (gmt_M_rec_is_any_header (GMT)) /* Skip all table and segment headers */
1136 continue;
1137 if (gmt_M_rec_is_eof (GMT)) /* Reached end of file */
1138 break;
1139 assert (In->text != NULL); /* Should never get here */
1140 }
1141 if (In->data == NULL) {
1142 gmt_quit_bad_record (API, In);
1143 Return (API->error);
1144 }
1145
1146 if (gmt_M_is_dnan (In->data[GMT_X]) || gmt_M_is_dnan (In->data[GMT_Y])) /* Probably a non-recognized header since we got NaNs */
1147 continue;
1148
1149 in = In->data;
1150 station_name = In->text;
1151
1152 /* Data record to process */
1153
1154 n_rec++;
1155
1156 if (Ctrl->S.readmode == READ_ELLIPSE) {
1157 vxy[ix] = in[2]; vxy[iy] = in[3];
1158 sigma_x = in[4]; sigma_y = in[5];
1159 corr_xy = in[6];
1160 if (Ctrl->C.active) { /* Compute/select the value parameters */
1161 switch (Ctrl->Z.mode) {
1162 case PSVELO_V_MAG: z_val = hypot (vxy[0], vxy[1]); e_val = hypot (sigma_x, sigma_y); break;
1163 case PSVELO_V_EAST: z_val = vxy[0]; e_val = sigma_x; break;
1164 case PSVELO_V_NORTH: z_val = vxy[1]; e_val = sigma_y; break;
1165 case PSVELO_V_USER: z_val = e_val = in[Ctrl->S.n_cols-1]; break;
1166 }
1167 }
1168 /* rescale uncertainties if necessary */
1169 if (Ctrl->D.active) {
1170 sigma_x = Ctrl->D.scale * sigma_x;
1171 sigma_y = Ctrl->D.scale * sigma_y;
1172 }
1173 if (fabs (sigma_x) < EPSIL && fabs (sigma_y) < EPSIL)
1174 plot_ellipse = false;
1175 else {
1176 plot_ellipse = true;
1177 psvelo_ellipse_convert (sigma_x, sigma_y, corr_xy, Ctrl->S.conrad, &small_axis, &great_axis, &direction);
1178
1179 /* convert to degrees */
1180 direction = direction * R2D;
1181 }
1182 }
1183 else if (Ctrl->S.readmode == READ_ROTELLIPSE) {
1184 vxy[ix] = in[2]; vxy[iy] = in[3];
1185 great_axis = Ctrl->S.conrad*in[4];
1186 small_axis = Ctrl->S.conrad*in[5];
1187 direction = in[6];
1188 if (Ctrl->C.active) { /* Compute/select the value parameters */
1189 switch (Ctrl->Z.mode) {
1190 case PSVELO_V_MAG: z_val = hypot (vxy[0], vxy[1]); e_val = hypot (great_axis, small_axis); break;
1191 case PSVELO_V_EAST: z_val = vxy[0]; e_val = great_axis; break;
1192 case PSVELO_V_NORTH: z_val = vxy[1]; e_val = small_axis; break;
1193 case PSVELO_V_USER: z_val = e_val = in[Ctrl->S.n_cols-1]; break;
1194 }
1195 }
1196 if (fabs (great_axis) < EPSIL && fabs (small_axis) < EPSIL)
1197 plot_ellipse = false;
1198 else
1199 plot_ellipse = true;
1200 }
1201 else if (Ctrl->S.readmode == READ_ANISOTROPY) {
1202 vxy[ix] = in[2];
1203 vxy[iy] = in[3];
1204 }
1205 else if (Ctrl->S.readmode == READ_CROSS) {
1206 eps1 = in[2];
1207 eps2 = in[3];
1208 theta = in[4];
1209 }
1210 else if (Ctrl->S.readmode == READ_WEDGE) {
1211 spin = in[2];
1212 spinsig = in[3];
1213 if (Ctrl->C.active) {
1214 switch (Ctrl->Z.mode) {
1215 case PSVELO_V_MAG: z_val = spin; e_val = spinsig; break;
1216 case PSVELO_V_USER: z_val = e_val = in[Ctrl->S.n_cols-1]; break;
1217 }
1218 }
1219 if (Ctrl->D.active) spinsig = spinsig * Ctrl->D.scale;
1220 }
1221 if (Ctrl->S.read) nominal_size = scale = in[scol];
1222
1223 if (!Ctrl->N.active) {
1224 gmt_map_outside (GMT, in[GMT_X], in[GMT_Y]);
1225 if (abs (GMT->current.map.this_x_status) > 1 || abs (GMT->current.map.this_y_status) > 1) continue;
1226 }
1227
1228 gmt_geo_to_xy (GMT, in[GMT_X], in[GMT_Y], &plot_x, &plot_y);
1229
1230 value = (Ctrl->Z.item == PSVELO_E_FILL) ? e_val : z_val; /* Select which value for color lookup - if active */
1231 if (Ctrl->I.mode) i_value = in[icol];
1232 /* Possibly update E or G fills based on value and/ore intensities, then set updated colors in PS */
1233 psvelo_set_colorfill (GMT, Ctrl, CPT, value, i_value);
1234 gmt_init_vector_param (GMT, &Ctrl->A.S, true, Ctrl->W.active, &Ctrl->W.pen, Ctrl->G.active, &Ctrl->G.fill);
1235
1236 if (GMT->common.t.variable) { /* Update the transparency for current symbol (or -t was given) */
1237 double transp[2] = {0.0, 0.0};
1238 if (GMT->common.t.n_transparencies == 2) { /* Requested two separate values to be read from file */
1239 transp[GMT_FILL_TRANSP] = 0.01 * in[tcol_f];
1240 transp[GMT_PEN_TRANSP] = 0.01 * in[tcol_s];
1241 }
1242 else if (GMT->common.t.mode & GMT_SET_FILL_TRANSP) { /* Gave fill transparency */
1243 transp[GMT_FILL_TRANSP] = 0.01 * in[tcol_f];
1244 if (GMT->common.t.n_transparencies == 0) transp[GMT_PEN_TRANSP] = transp[GMT_FILL_TRANSP]; /* Implied to be used for stroke also */
1245 }
1246 else { /* Gave stroke transparency */
1247 transp[GMT_PEN_TRANSP] = 0.01 * in[tcol_s];
1248 if (GMT->common.t.n_transparencies == 0) transp[GMT_FILL_TRANSP] = transp[GMT_PEN_TRANSP]; /* Implied to be used for fill also */
1249 }
1250 PSL_settransparencies (PSL, transp);
1251 }
1252 size = scale;
1253 if (Ctrl->H.active) { /* Variable scaling of symbol size and pen width */
1254 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1255 size *= scl;
1256 }
1257
1258 switch (Ctrl->S.symbol) {
1259 case CINE:
1260 plot_vector = (hypot (vxy[0], vxy[1]) < 1.e-8) ? false : true;
1261 psvelo_trace_arrow (GMT, in[GMT_X], in[GMT_Y], vxy[0], vxy[1], size, &plot_x, &plot_y, &plot_vx, &plot_vy);
1262 psvelo_get_trans (GMT, in[GMT_X], in[GMT_Y], &t11, &t12, &t21, &t22);
1263 if (plot_ellipse) { /* Optionally fill [-E] and optionally outline [-L] the error ellipse */
1264 if (Ctrl->L.active) { /* Draw ellipse outline */
1265 current_pen = Ctrl->L.pen;
1266 if (Ctrl->H.active) {
1267 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1268 gmt_scale_pen (GMT, ¤t_pen, scl);
1269 }
1270 gmt_setpen (GMT, ¤t_pen);
1271 }
1272 /* Draw the ellipse */
1273 psvelo_paint_ellipse (GMT, plot_vx, plot_vy, direction, great_axis, small_axis, size,
1274 t11, t12, t21, t22, Ctrl->E.active, &Ctrl->E.fill, Ctrl->L.active);
1275 }
1276 if (plot_vector) { /* Verify that vector length is not ridiculously small */
1277 length = hypot (plot_x-plot_vx, plot_y-plot_vy); /* Length of arrow */
1278 if (length < Ctrl->A.S.v.h_length && Ctrl->A.S.v.v_norm < 0.0) { /* No shrink requested yet head length exceeds total vector length */
1279 GMT_Report (API, GMT_MSG_INFORMATION, "Vector head length exceeds overall vector length near line %d. Consider adding +n<norm> to -A\n", n_rec);
1280 n_warn++;
1281 }
1282 s = (length < Ctrl->A.S.v.v_norm) ? length / Ctrl->A.S.v.v_norm : 1.0;
1283 hw = s * Ctrl->A.S.v.h_width;
1284 hl = s * Ctrl->A.S.v.h_length;
1285 vw = s * Ctrl->A.S.v.v_width;
1286 if (vw < (2.0/PSL_DOTS_PER_INCH)) vw = 2.0/PSL_DOTS_PER_INCH; /* Minimum width set */
1287 if (Ctrl->A.S.v.status & PSL_VEC_OUTLINE2) {
1288 current_pen = Ctrl->A.S.v.pen;
1289 if (Ctrl->H.active) {
1290 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1291 gmt_scale_pen (GMT, ¤t_pen, scl);
1292 }
1293 gmt_setpen (GMT, ¤t_pen);
1294 }
1295 dim[PSL_VEC_XTIP] = plot_vx;
1296 dim[PSL_VEC_YTIP] = plot_vy;
1297 dim[PSL_VEC_TAIL_WIDTH] = vw;
1298 dim[PSL_VEC_HEAD_LENGTH] = hl;
1299 dim[PSL_VEC_HEAD_WIDTH] = hw;
1300 dim[PSL_VEC_HEAD_SHAPE] = Ctrl->A.S.v.v_shape;
1301 if (Ctrl->W.active) {
1302 current_pen = Ctrl->W.pen;
1303 if (Ctrl->H.active) {
1304 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1305 gmt_scale_pen (GMT, ¤t_pen, scl);
1306 }
1307 gmt_setpen (GMT, ¤t_pen);
1308 }
1309 if (Ctrl->A.S.symbol == GMT_SYMBOL_VECTOR_V4) { /* Old GMT4 vector selected */
1310 double *this_rgb = (set_g_fill) ? Ctrl->G.fill.rgb : GMT->session.no_rgb;
1311 psl_vector_v4 (PSL, plot_x, plot_y, dim, this_rgb, Ctrl->L.active);
1312 }
1313 else {
1314 dim[PSL_VEC_STATUS] = (double)Ctrl->A.S.v.status;
1315 dim[PSL_VEC_HEAD_TYPE_BEGIN] = (double)Ctrl->A.S.v.v_kind[0];
1316 dim[PSL_VEC_HEAD_TYPE_END] = (double)Ctrl->A.S.v.v_kind[1];
1317 dim[PSL_VEC_HEAD_PENWIDTH] = (headpen_width > 0.0) ? headpen_width : 0.5 * Ctrl->W.pen.width;
1318 if (Ctrl->A.S.v.status & PSL_VEC_FILL2)
1319 gmt_setfill (GMT, &Ctrl->A.S.v.fill, Ctrl->W.active);
1320 else if (set_g_fill)
1321 gmt_setfill (GMT, &Ctrl->G.fill, Ctrl->W.active);
1322 PSL_plotsymbol (PSL, plot_x, plot_y, dim, PSL_VECTOR);
1323 }
1324 justify = ((plot_vx - plot_x) > 0.0) ? PSL_MR : PSL_ML;
1325 if (Ctrl->S.font.size > 0.0 && station_name && station_name[0]) /* 1 inch = 2.54 cm */
1326 PSL_plottext (PSL, plot_x + (PSL_MC - justify) / 25.4 , plot_y, Ctrl->S.font.size, station_name, ANGLE, justify, FORM);
1327 }
1328 else { /* vector too small, just place an circle there instead */
1329 if (set_g_fill)
1330 gmt_setfill (GMT, &Ctrl->G.fill, 1);
1331 ssize = GMT_DOT_SIZE;
1332 PSL_plotsymbol (PSL, plot_x, plot_y, &ssize, PSL_CIRCLE);
1333 justify = PSL_TC;
1334 if (Ctrl->S.font.size > 0.0 && station_name && station_name[0]) /* Place station name */
1335 PSL_plottext (PSL, plot_x, plot_y - 1.0 / 25.4, Ctrl->S.font.size, station_name, ANGLE, justify, FORM);
1336 }
1337 break;
1338 case ANISO:
1339 psvelo_trace_arrow (GMT, in[GMT_X], in[GMT_Y], vxy[0], vxy[1], size, &plot_x, &plot_y, &plot_vx, &plot_vy);
1340 current_pen = Ctrl->W.pen;
1341 if (Ctrl->H.active) {
1342 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1343 gmt_scale_pen (GMT, ¤t_pen, scl);
1344 }
1345 gmt_setpen (GMT, ¤t_pen);
1346 PSL_plotsegment (PSL, plot_x, plot_y, plot_vx, plot_vy);
1347 break;
1348 case CROSS:
1349 /* triangular arrowheads */
1350 current_pen = Ctrl->W.pen;
1351 if (Ctrl->H.active) {
1352 double scl = (Ctrl->H.mode == PSVELO_READ_SCALE) ? in[xcol] : Ctrl->H.value;
1353 gmt_scale_pen (GMT, ¤t_pen, scl);
1354 }
1355 psvelo_trace_cross (GMT, in[GMT_X],in[GMT_Y],eps1,eps2,theta,size,Ctrl->A.S.v.v_width,Ctrl->A.S.v.h_length,
1356 Ctrl->A.S.v.h_width,Ctrl->A.S.v.v_shape,Ctrl->L.active,&(current_pen));
1357 break;
1358 case WEDGE:
1359 PSL_comment (PSL, "begin wedge number %li", n_rec);
1360 gmt_geo_to_xy (GMT, in[GMT_X], in[GMT_Y], &plot_x, &plot_y);
1361 psvelo_get_trans (GMT, in[GMT_X], in[GMT_Y], &t11, &t12, &t21, &t22);
1362 psvelo_paint_wedge (PSL, plot_x, plot_y, spin, spinsig, size, Ctrl->S.wedge_amp, t11, t12, t21, t22,
1363 set_g_fill, Ctrl->G.fill.rgb, set_e_fill, Ctrl->E.fill.rgb, Ctrl->L.active);
1364 break;
1365 }
1366 } while (true);
1367
1368 if (GMT_End_IO (API, GMT_IN, 0) != GMT_NOERROR) { /* Disables further data input */
1369 Return (API->error);
1370 }
1371
1372 if (GMT->common.t.variable) { /* Reset the transparencies */
1373 double transp[2] = {0.0, 0.0};
1374 PSL_settransparencies (PSL, transp);
1375 }
1376
1377 if (n_warn) GMT_Report (API, GMT_MSG_INFORMATION, "%d vector heads had length exceeding the vector length and were skipped. Consider the +n<norm> modifier to -A\n", n_warn);
1378 GMT_Report (API, GMT_MSG_INFORMATION, "Number of records read: %li\n", n_rec);
1379
1380 if (!Ctrl->N.active) gmt_map_clip_off (GMT);
1381
1382 PSL_setdash (PSL, NULL, 0);
1383
1384 gmt_map_basemap (GMT); /* Basemap after data */
1385 gmt_plane_perspective (GMT, -1, 0.0);
1386 gmt_plotend (GMT);
1387
1388 Return (GMT_NOERROR);
1389 }
1390
GMT_velo(void * V_API,int mode,void * args)1391 EXTERN_MSC int GMT_velo (void *V_API, int mode, void *args) {
1392 /* This is the GMT6 modern mode name */
1393 struct GMTAPI_CTRL *API = gmt_get_api_ptr (V_API); /* Cast from void to GMTAPI_CTRL pointer */
1394 if (API->GMT->current.setting.run_mode == GMT_CLASSIC && !API->usage) {
1395 GMT_Report (API, GMT_MSG_ERROR, "Shared GMT module not found: velo\n");
1396 return (GMT_NOT_A_VALID_MODULE);
1397 }
1398 return GMT_psvelo (V_API, mode, args);
1399 }
1400