Skip to content
Open
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: 5 additions & 1 deletion src/gmt_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -6858,7 +6858,11 @@ EXTERN_MSC void gmtinit_conf_classic (struct GMT_CTRL *GMT) {
GMT->current.setting.given_unit[GMTCASE_MAP_ANNOT_OFFSET_PRIMARY] = 'p';
GMT->current.setting.given_unit[GMTCASE_MAP_ANNOT_OFFSET_SECONDARY] = 'p';
/* MAP_ANNOT_OBLIQUE */
GMT->current.setting.map_annot_oblique = GMT_OBL_ANNOT_LON_HORIZONTAL | GMT_OBL_ANNOT_LAT_HORIZONTAL | GMT_OBL_ANNOT_EXTEND_TICKS;
/* The anywhere bit was lost when this setting went from a bit-sum to a keyword list; without it an oblique frame
* only annotates longitudes on the S/N borders and latitudes on the W/E borders, which throws away most of the
* annotations as soon as the graticule is rotated far from the frame axes. The documentation has said "default
* is anywhere" all along, and that is what GMT 6.1.0 did [issue #8418] */
GMT->current.setting.map_annot_oblique = GMT_OBL_ANNOT_ANYWHERE | GMT_OBL_ANNOT_LON_HORIZONTAL | GMT_OBL_ANNOT_LAT_HORIZONTAL | GMT_OBL_ANNOT_EXTEND_TICKS;
/* MAP_ANNOT_MIN_ANGLE */
GMT->current.setting.map_annot_min_angle = 20;
/* MAP_ANNOT_MIN_SPACING */
Expand Down
25 changes: 21 additions & 4 deletions src/gmt_plot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,11 +1837,12 @@ GMT_LOCAL void gmtplot_map_symbol (struct GMT_CTRL *GMT, struct PSL_CTRL *PSL, s
double line_angle, text_angle, div, tick_length, o_len, len, ca, sa, boost;
double *xx = xings->xx, *yy = xings->yy, *line_angles = xings->angle;
unsigned int i, annot_type, justify, *sides = xings->sides, nx = xings->nx;
bool flip;
bool flip, no_tick;
len = gmtplot_get_annot_offset (GMT, &flip, level); /* Get annotation offset, and flip justification if "inside" */
annot_type = 2 << type; /* 2 = NS, 4 = EW */

for (i = 0; i < nx; i++) {
no_tick = false;
if (!(GMT->current.setting.map_annot_oblique & GMT_OBL_ANNOT_ANYWHERE) && ((type == 0 && (sides[i] % 2)) || (type == 1 && !(sides[i] % 2)))) continue;

if (gmtlib_prepare_label (GMT, line_angles[i], sides[i], xx[i], yy[i], type, &line_angle, &text_angle, &justify)) continue;
Expand All @@ -1853,12 +1854,28 @@ GMT_LOCAL void gmtplot_map_symbol (struct GMT_CTRL *GMT, struct PSL_CTRL *PSL, s
if (!flip && GMT->current.setting.map_annot_oblique & annot_type) o_len = tick_length;
if (GMT->current.setting.map_annot_oblique & GMT_OBL_ANNOT_EXTEND_TICKS) {
div = ((sides[i] % 2) ? fabs (ca) : fabs (sa));
o_len /= div;
/* We only ride out to the tip of the extended tick if there actually is one: gmtplot_map_tick skips
* ticks whose gridline meets the border at less than MAP_ANNOT_MIN_ANGLE, and dividing by that same
* tiny div here would fling the annotation far along the border, away from the crossing it belongs
* to and with no tick to connect the two. Below that angle we step straight out from the border
* instead, so the annotation stays where its gridline meets the frame [issue #8418] */
if (div > sind (GMT->current.setting.map_annot_min_angle))
o_len /= div;
else
no_tick = true;
}
else
o_len += copysign (boost, o_len);
xx[i] += o_len * ca;
yy[i] += o_len * sa;
if (no_tick) { /* Offset normal to the border since there is no oblique tick to follow */
if (sides[i] % 2)
xx[i] += (sides[i] == 1) ? o_len : -o_len;
else
yy[i] += (sides[i] == 2) ? o_len : -o_len;
}
else {
xx[i] += o_len * ca;
yy[i] += o_len * sa;
}
if (!flip && (GMT->current.setting.map_annot_oblique & annot_type) && GMT->current.setting.map_annot_offset[level] > 0.0) {
if (sides[i] % 2)
xx[i] += (sides[i] == 1) ? GMT->current.setting.map_annot_offset[level] : -GMT->current.setting.map_annot_offset[level];
Expand Down
34 changes: 34 additions & 0 deletions test/psbasemap/oblique_annot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
#
# Oblique frames must annotate a gridline where it actually meets the border.
#
# With MAP_ANNOT_OBLIQUE's tick_extend the annotation goes at the tip of the tick that is extended
# along the gridline. gmtplot_map_tick draws no such tick once the gridline meets the border at
# less than MAP_ANNOT_MIN_ANGLE, but the annotation code used to extend regardless, dividing its
# offset by a vanishing sine and flinging the label far along the border, detached from the crossing
# it belongs to. Here the 175E meridian meets the N border at about 6 degrees: its annotation
# belongs at x = 3.1 cm and used to be drawn at x = 2.0 cm on a map only 6 cm wide. See issue #8418.
#
# The positions below were checked against the crossings computed independently with gmt mapproject.

# Pin everything the extracted table depends on, so that it is the annotation placement being tested
gmt set FORMAT_GEO_MAP ddd:mm:ssF MAP_ANNOT_MIN_SPACING 0 \
MAP_ANNOT_OBLIQUE anywhere,lon_horizontal,lat_horizontal,tick_extend

gmt psbasemap -JOb168/51/172/32.5/6c -R-500/2300/-400/400+uk -BeNsW -Bxa5f1 -Bya5f1 -P > map.ps

# Pull the annotations out of the PostScript as "label border position_along_that_border_in_cm".
# PSL units are 1/1200 inch measured from the lower left map corner, hence the 2.54/1200 scaling.
tr '\r' '\n' < map.ps | awk '
{ for (i = 3; i <= NF; i++) if ($i == "M") { x = $(i-2); y = $(i-1) } } # Remember latest moveto
/\([0-9]+.[EN]\) [a-z][a-z] Z/ {
for (i = 1; i <= NF; i++) if ($i ~ /^\(/) { lab = $i; just = $(i+1) }
if (just == "bc") printf "%s N %.1f\n", lab, x*2.54/1200
else if (just == "tc") printf "%s S %.1f\n", lab, x*2.54/1200
else if (just == "mr") printf "%s W %.1f\n", lab, y*2.54/1200
else if (just == "ml") printf "%s E %.1f\n", lab, y*2.54/1200
}' | sort > result.txt

printf '%b' '(165\260E) W 0.7\n(170\260E) W 1.4\n(175\260E) N 3.1\n(35\260N) N 5.1\n(40\260N) N 3.9\n(45\260N) N 2.7\n(50\260N) N 1.5\n(55\260N) N 0.3\n(55\260N) W 0.4\n' > answer.txt

diff -q --strip-trailing-cr answer.txt result.txt
Loading