Skip to content

Commit 44d1af5

Browse files
joa-quimEsteban82
andauthored
psxy: Add broken arrows (#8967)
* Broken arrow baseline PSfile * psxy: Add broken arrows * Broken arrows test * Add execute permission for elvowvec.sh --------- Co-authored-by: Esteban82 <federico.esteban@gmail.com>
1 parent db194fe commit 44d1af5

5 files changed

Lines changed: 92 additions & 6 deletions

File tree

doc/rst/source/explain_line_draw.rst_

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@
1313
- For gragraphic projections, *x* and *y* are parallels and meridians.
1414
- For polar projections, *x* and *y* are theta and radius.
1515

16+
When used together with |-S|\ **v** (Cartesian vectors), the **x** and **y**
17+
directives produce *broken* (right-angle elbow) arrows: instead of a straight line
18+
from tail to tip, the vector is drawn along two perpendicular legs meeting at a
19+
corner. **x** draws the horizontal leg first, then the vertical leg; **y** draws
20+
the vertical leg first, then the horizontal leg. The arrowhead is placed at the tip.
21+
1622
**Note**: In :doc:`plot3d`, the |-A| option requires constant *z*-coordinates.

doc/rst/source/plot.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,14 @@ to cm given the scale 3.60::
468468

469469
gmt plot -R20/40/-20/0 -JM6i -Sv0.15i+e+z3.6c -Gred -W0.25p -Baf data.txt -pdf map
470470

471+
To draw the same Cartesian vectors as broken (right-angle elbow) arrows, traveling
472+
horizontally first and then vertically to reach the tip, use |-A|\ **x**::
473+
474+
gmt plot -R0/50/-50/50 -JX6i -Sv0.15i+e -Gred -W0.5p -Baf -Ax -pdf map << EOF
475+
10 10 45 2i
476+
30 -20 0 1.5i
477+
EOF
478+
471479
To plot a triangle with smooth color gradients using RGB values directly::
472480

473481
cat << EOF > triangle.txt

src/psxy.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,11 +2279,11 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) {
22792279
v4_rgb = current_fill.rgb;
22802280
else
22812281
v4_rgb = GMT->session.no_rgb;
2282-
if (v4_outline) gmt_setpen (GMT, &Ctrl->W.pen);
2282+
if (v4_outline) gmt_setpen(GMT, &Ctrl->W.pen);
22832283
if (S.v.status & PSL_VEC_BEGIN) v4_outline += 8; /* Double-headed */
22842284
dim[PSL_VEC_HEAD_SHAPE] = GMT->current.setting.map_vector_shape;
22852285
dim[PSL_VEC_HEAD_WIDTH] *= 0.5; /* Since it was double in the parsing */
2286-
psl_vector_v4 (PSL, xpos[item], plot_y, dim, v4_rgb, v4_outline);
2286+
psl_vector_v4(PSL, xpos[item], plot_y, dim, v4_rgb, v4_outline);
22872287
}
22882288
else { /* Current vector model */
22892289
dim[PSL_VEC_HEAD_SHAPE] = S.v.v_shape;
@@ -2293,7 +2293,51 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) {
22932293
dim[PSL_VEC_TRIM_BEGIN] = (double)S.v.v_trim[0];
22942294
dim[PSL_VEC_TRIM_END] = (double)S.v.v_trim[1];
22952295
dim[PSL_VEC_HEAD_PENWIDTH] = s * headpen_width; /* Possibly shrunk head pen width */
2296-
PSL_plotsymbol (PSL, xpos[item], plot_y, dim, PSL_VECTOR);
2296+
if (Ctrl->A.active && (Ctrl->A.mode == GMT_STAIRS_X || Ctrl->A.mode == GMT_STAIRS_Y)) {
2297+
/* Broken (right-angle elbow) arrow: two legs meeting at a corner point.
2298+
* Round line caps are used so each leg's semicircular endpoint fills the
2299+
* outer-corner gap that butt caps would leave at the elbow. */
2300+
double elbow_x, elbow_y, leg1_length, leg2_length, s1, s2;
2301+
unsigned int leg1_status, leg2_status;
2302+
if (Ctrl->A.mode == GMT_STAIRS_X) { /* Horizontal first, then vertical */
2303+
elbow_x = x_2; elbow_y = plot_y;
2304+
}
2305+
else { /* GMT_STAIRS_Y: vertical first, then horizontal */
2306+
elbow_x = xpos[item]; elbow_y = y_2;
2307+
}
2308+
leg1_length = hypot(elbow_x - xpos[item], elbow_y - plot_y);
2309+
leg2_length = hypot(x_2 - elbow_x, y_2 - elbow_y);
2310+
s1 = gmt_get_vector_shrinking(GMT, &(S.v), data_magnitude, leg1_length);
2311+
s2 = gmt_get_vector_shrinking(GMT, &(S.v), data_magnitude, leg2_length);
2312+
PSL_setlinecap(PSL, PSL_ROUND_CAP); /* Round ends fill the elbow corner */
2313+
/* Leg 1: tail → elbow. Keep begin-head (if any); no end-head. */
2314+
leg1_status = S.v.status & ~(PSL_VEC_END | PSL_VEC_END_L | PSL_VEC_END_R | PSL_VEC_OFF_END);
2315+
dim[PSL_VEC_XTIP] = elbow_x;
2316+
dim[PSL_VEC_YTIP] = elbow_y;
2317+
dim[PSL_VEC_TAIL_WIDTH] = s1 * S.v.v_width;
2318+
dim[PSL_VEC_HEAD_LENGTH] = s1 * S.v.h_length;
2319+
dim[PSL_VEC_HEAD_WIDTH] = s1 * S.v.h_width;
2320+
dim[PSL_VEC_HEAD_PENWIDTH] = s1 * headpen_width;
2321+
dim[PSL_VEC_TRIM_BEGIN] = (double)S.v.v_trim[0];
2322+
dim[PSL_VEC_TRIM_END] = 0.0;
2323+
dim[PSL_VEC_STATUS] = (double)leg1_status;
2324+
PSL_plotsymbol(PSL, xpos[item], plot_y, dim, PSL_VECTOR);
2325+
/* Leg 2: elbow → tip. Keep end-head (if any); no begin-head. */
2326+
leg2_status = S.v.status & ~(PSL_VEC_BEGIN | PSL_VEC_BEGIN_L | PSL_VEC_BEGIN_R | PSL_VEC_OFF_BEGIN);
2327+
dim[PSL_VEC_XTIP] = x_2;
2328+
dim[PSL_VEC_YTIP] = y_2;
2329+
dim[PSL_VEC_TAIL_WIDTH] = s2 * S.v.v_width;
2330+
dim[PSL_VEC_HEAD_LENGTH] = s2 * S.v.h_length;
2331+
dim[PSL_VEC_HEAD_WIDTH] = s2 * S.v.h_width;
2332+
dim[PSL_VEC_HEAD_PENWIDTH] = s2 * headpen_width;
2333+
dim[PSL_VEC_TRIM_BEGIN] = 0.0;
2334+
dim[PSL_VEC_TRIM_END] = (double)S.v.v_trim[1];
2335+
dim[PSL_VEC_STATUS] = (double)leg2_status;
2336+
PSL_plotsymbol(PSL, elbow_x, elbow_y, dim, PSL_VECTOR);
2337+
PSL_setlinecap(PSL, PSL_BUTT_CAP); /* Restore default */
2338+
}
2339+
else
2340+
PSL_plotsymbol(PSL, xpos[item], plot_y, dim, PSL_VECTOR);
22972341
}
22982342
break;
22992343
case GMT_SYMBOL_GEOVECTOR:

test/baseline/psxy.dvc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
outs:
2-
- md5: 887b912ced405376a548ce0a575b8c18.dir
3-
nfiles: 144
2+
- md5: 510204715a512de392ee93ea016a172f.dir
3+
nfiles: 145
44
path: psxy
55
hash: md5
6-
size: 9428273
6+
size: 9459764

test/psxy/elbowvec.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
# Test broken/elbow arrows: -Sv combined with -Ax (horizontal-first) or -Ay (vertical-first).
3+
# Three arrows 120 degrees apart (30/150/330 deg Cartesian CCW-from-E).
4+
# Tails at three corners, tips all near centre, so the L-legs are clearly visible
5+
# and non-overlapping in both -Ax and -Ay modes.
6+
#
7+
# With -JX3i/-R-3/3/-3/3: scale = 0.5 in/unit, 1.5i = 3 data units.
8+
# Arrow 1: tail(-2,-2) angle=30 tip( 0.60,-0.50) -Ax elbow at( 0.60,-2)
9+
# Arrow 2: tail( 2, 0) angle=150 tip(-0.60, 1.50) -Ax elbow at(-0.60, 0)
10+
# Arrow 3: tail( 0, 2) angle=330 tip( 2.60, 0.50) -Ax elbow at( 2.60, 2)
11+
ps=elbowvec.ps
12+
13+
cat << EOF > elbowvec.txt
14+
-2 -2 30 1.5i
15+
2 0 150 1.5i
16+
0 2 330 1.5i
17+
EOF
18+
19+
R=-R-3/3/-3/3
20+
J=-JX3i
21+
22+
# Left panel: horizontal-first elbow (-Ax)
23+
gmt psxy elbowvec.txt $R $J -P -Bafg1 -BWSne+t"Ax" \
24+
-Sv0.2i+e -Gred -W1p -Ax -K -X1.25i -Y4.5i > $ps
25+
26+
# Right panel: vertical-first elbow (-Ay)
27+
gmt psxy elbowvec.txt $R $J -O -Bafg1 -BWSne+t"Ay" \
28+
-Sv0.2i+e -Gred -W1p -Ay -X3.75i >> $ps

0 commit comments

Comments
 (0)