Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/rst/source/explain_line_draw.rst_
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@
- For gragraphic projections, *x* and *y* are parallels and meridians.
- For polar projections, *x* and *y* are theta and radius.

When used together with |-S|\ **v** (Cartesian vectors), the **x** and **y**
directives produce *broken* (right-angle elbow) arrows: instead of a straight line
from tail to tip, the vector is drawn along two perpendicular legs meeting at a
corner. **x** draws the horizontal leg first, then the vertical leg; **y** draws
the vertical leg first, then the horizontal leg. The arrowhead is placed at the tip.

**Note**: In :doc:`plot3d`, the |-A| option requires constant *z*-coordinates.
8 changes: 8 additions & 0 deletions doc/rst/source/plot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,14 @@ to cm given the scale 3.60::

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

To draw the same Cartesian vectors as broken (right-angle elbow) arrows, traveling
horizontally first and then vertically to reach the tip, use |-A|\ **x**::

gmt plot -R0/50/-50/50 -JX6i -Sv0.15i+e -Gred -W0.5p -Baf -Ax -pdf map << EOF
10 10 45 2i
30 -20 0 1.5i
EOF

To plot a triangle with smooth color gradients using RGB values directly::

cat << EOF > triangle.txt
Expand Down
50 changes: 47 additions & 3 deletions src/psxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -2279,11 +2279,11 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) {
v4_rgb = current_fill.rgb;
else
v4_rgb = GMT->session.no_rgb;
if (v4_outline) gmt_setpen (GMT, &Ctrl->W.pen);
if (v4_outline) gmt_setpen(GMT, &Ctrl->W.pen);
if (S.v.status & PSL_VEC_BEGIN) v4_outline += 8; /* Double-headed */
dim[PSL_VEC_HEAD_SHAPE] = GMT->current.setting.map_vector_shape;
dim[PSL_VEC_HEAD_WIDTH] *= 0.5; /* Since it was double in the parsing */
psl_vector_v4 (PSL, xpos[item], plot_y, dim, v4_rgb, v4_outline);
psl_vector_v4(PSL, xpos[item], plot_y, dim, v4_rgb, v4_outline);
}
else { /* Current vector model */
dim[PSL_VEC_HEAD_SHAPE] = S.v.v_shape;
Expand All @@ -2293,7 +2293,51 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) {
dim[PSL_VEC_TRIM_BEGIN] = (double)S.v.v_trim[0];
dim[PSL_VEC_TRIM_END] = (double)S.v.v_trim[1];
dim[PSL_VEC_HEAD_PENWIDTH] = s * headpen_width; /* Possibly shrunk head pen width */
PSL_plotsymbol (PSL, xpos[item], plot_y, dim, PSL_VECTOR);
if (Ctrl->A.active && (Ctrl->A.mode == GMT_STAIRS_X || Ctrl->A.mode == GMT_STAIRS_Y)) {
/* Broken (right-angle elbow) arrow: two legs meeting at a corner point.
* Round line caps are used so each leg's semicircular endpoint fills the
* outer-corner gap that butt caps would leave at the elbow. */
double elbow_x, elbow_y, leg1_length, leg2_length, s1, s2;
unsigned int leg1_status, leg2_status;
if (Ctrl->A.mode == GMT_STAIRS_X) { /* Horizontal first, then vertical */
elbow_x = x_2; elbow_y = plot_y;
}
else { /* GMT_STAIRS_Y: vertical first, then horizontal */
elbow_x = xpos[item]; elbow_y = y_2;
}
leg1_length = hypot(elbow_x - xpos[item], elbow_y - plot_y);
leg2_length = hypot(x_2 - elbow_x, y_2 - elbow_y);
s1 = gmt_get_vector_shrinking(GMT, &(S.v), data_magnitude, leg1_length);
s2 = gmt_get_vector_shrinking(GMT, &(S.v), data_magnitude, leg2_length);
PSL_setlinecap(PSL, PSL_ROUND_CAP); /* Round ends fill the elbow corner */
/* Leg 1: tail → elbow. Keep begin-head (if any); no end-head. */
leg1_status = S.v.status & ~(PSL_VEC_END | PSL_VEC_END_L | PSL_VEC_END_R | PSL_VEC_OFF_END);
dim[PSL_VEC_XTIP] = elbow_x;
dim[PSL_VEC_YTIP] = elbow_y;
dim[PSL_VEC_TAIL_WIDTH] = s1 * S.v.v_width;
dim[PSL_VEC_HEAD_LENGTH] = s1 * S.v.h_length;
dim[PSL_VEC_HEAD_WIDTH] = s1 * S.v.h_width;
dim[PSL_VEC_HEAD_PENWIDTH] = s1 * headpen_width;
dim[PSL_VEC_TRIM_BEGIN] = (double)S.v.v_trim[0];
dim[PSL_VEC_TRIM_END] = 0.0;
dim[PSL_VEC_STATUS] = (double)leg1_status;
PSL_plotsymbol(PSL, xpos[item], plot_y, dim, PSL_VECTOR);
/* Leg 2: elbow → tip. Keep end-head (if any); no begin-head. */
leg2_status = S.v.status & ~(PSL_VEC_BEGIN | PSL_VEC_BEGIN_L | PSL_VEC_BEGIN_R | PSL_VEC_OFF_BEGIN);
dim[PSL_VEC_XTIP] = x_2;
dim[PSL_VEC_YTIP] = y_2;
dim[PSL_VEC_TAIL_WIDTH] = s2 * S.v.v_width;
dim[PSL_VEC_HEAD_LENGTH] = s2 * S.v.h_length;
dim[PSL_VEC_HEAD_WIDTH] = s2 * S.v.h_width;
dim[PSL_VEC_HEAD_PENWIDTH] = s2 * headpen_width;
dim[PSL_VEC_TRIM_BEGIN] = 0.0;
dim[PSL_VEC_TRIM_END] = (double)S.v.v_trim[1];
dim[PSL_VEC_STATUS] = (double)leg2_status;
PSL_plotsymbol(PSL, elbow_x, elbow_y, dim, PSL_VECTOR);
PSL_setlinecap(PSL, PSL_BUTT_CAP); /* Restore default */
}
else
PSL_plotsymbol(PSL, xpos[item], plot_y, dim, PSL_VECTOR);
}
break;
case GMT_SYMBOL_GEOVECTOR:
Expand Down
6 changes: 3 additions & 3 deletions test/baseline/psxy.dvc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
outs:
- md5: 887b912ced405376a548ce0a575b8c18.dir
nfiles: 144
- md5: 510204715a512de392ee93ea016a172f.dir
nfiles: 145
path: psxy
hash: md5
size: 9428273
size: 9459764
28 changes: 28 additions & 0 deletions test/psxy/elbowvec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Test broken/elbow arrows: -Sv combined with -Ax (horizontal-first) or -Ay (vertical-first).
# Three arrows 120 degrees apart (30/150/330 deg Cartesian CCW-from-E).
# Tails at three corners, tips all near centre, so the L-legs are clearly visible
# and non-overlapping in both -Ax and -Ay modes.
#
# With -JX3i/-R-3/3/-3/3: scale = 0.5 in/unit, 1.5i = 3 data units.
# Arrow 1: tail(-2,-2) angle=30 tip( 0.60,-0.50) -Ax elbow at( 0.60,-2)
# Arrow 2: tail( 2, 0) angle=150 tip(-0.60, 1.50) -Ax elbow at(-0.60, 0)
# Arrow 3: tail( 0, 2) angle=330 tip( 2.60, 0.50) -Ax elbow at( 2.60, 2)
ps=elbowvec.ps

cat << EOF > elbowvec.txt
-2 -2 30 1.5i
2 0 150 1.5i
0 2 330 1.5i
EOF

R=-R-3/3/-3/3
J=-JX3i

# Left panel: horizontal-first elbow (-Ax)
gmt psxy elbowvec.txt $R $J -P -Bafg1 -BWSne+t"Ax" \
-Sv0.2i+e -Gred -W1p -Ax -K -X1.25i -Y4.5i > $ps

# Right panel: vertical-first elbow (-Ay)
gmt psxy elbowvec.txt $R $J -O -Bafg1 -BWSne+t"Ay" \
-Sv0.2i+e -Gred -W1p -Ay -X3.75i >> $ps
Loading