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
27 changes: 14 additions & 13 deletions src/gmt_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -4933,7 +4933,7 @@ GMT_LOCAL int gmtinit_parse5_B_option (struct GMT_CTRL *GMT, char *in) {

char string[GMT_BUFSIZ] = {""}, orig_string[GMT_BUFSIZ] = {""}, text[GMT_BUFSIZ] = {""}, *mod = NULL, *the_axes = "xyz";
struct GMT_PLOT_AXIS *A = NULL;
unsigned int no;
unsigned int no, pr;
int k, error = 0;
bool side[3] = {false, false, false}, implicit = false;

Expand Down Expand Up @@ -4976,8 +4976,8 @@ GMT_LOCAL int gmtinit_parse5_B_option (struct GMT_CTRL *GMT, char *in) {
k++;
}
if (!(side[GMT_X] || side[GMT_Y] || side[GMT_Z])) GMT->current.map.frame.set_both = side[GMT_X] = side[GMT_Y] = implicit = true; /* If no axis were named we default to both x and y */
GMT->current.map.frame.axis[GMT_Z].angle = 0.0; /* Default is plotting normal to axis for Z, i.e., will look horizontal on the plot */
GMT->current.map.frame.axis[GMT_Z].use_angle = true;
GMT->current.map.frame.axis[GMT_Z].angle[GMT_PRIMARY] = GMT->current.map.frame.axis[GMT_Z].angle[GMT_SECONDARY] = 0.0; /* Default is plotting normal to axis for Z, i.e., will look horizontal on the plot */
GMT->current.map.frame.axis[GMT_Z].use_angle[GMT_PRIMARY] = GMT->current.map.frame.axis[GMT_Z].use_angle[GMT_SECONDARY] = true;
strncpy (text, &in[k], GMT_BUFSIZ-1); /* Make a copy of the input, starting after the leading -B[p|s][xyz] indicators */
gmt_handle5_plussign(GMT, text, GMT_AXIS_MODIFIERS, 0); /* Temporarily change any +<letter> except +L|l, +f, +p, +S|s, +u to ASCII 1 to avoid interference with +modifiers */
k = 0; /* Start at beginning of text and look for first occurrence of +L|l, +e, +f, +p, +S|s or +u */
Expand Down Expand Up @@ -5011,35 +5011,36 @@ GMT_LOCAL int gmtinit_parse5_B_option (struct GMT_CTRL *GMT, char *in) {
char p[GMT_BUFSIZ];
while ((gmt_strtok (mod, "+", &pos, p))) { /* Parse any +<modifier> statements */
switch (p[0]) {
case 'a': /* Set annotation angle */
case 'a': /* Set annotation angle - independently for primary (-Bp, default) and secondary (-Bs) annotations */
if (gmt_M_is_geographic (GMT, GMT_IN)) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Option -B: Cannot use +a for geographic basemaps\n");
error++;
continue;
}
pr = (GMT->current.map.frame.primary) ? GMT_PRIMARY : GMT_SECONDARY;
if (no == GMT_X) { /* Variable angles for the x-axis */
if (p[1] == 'n') /* +an is short for +a90 or normal to x-axis */
GMT->current.map.frame.axis[no].angle = 90.0;
GMT->current.map.frame.axis[no].angle[pr] = 90.0;
else if (p[1] == 'p') /* +ap is short for +a0 or parallel to x-axis */
GMT->current.map.frame.axis[no].angle = 0.0;
GMT->current.map.frame.axis[no].angle[pr] = 0.0;
else /* Assume a variable angle */
GMT->current.map.frame.axis[no].angle = atof (&p[1]);
GMT->current.map.frame.axis[no].angle[pr] = atof (&p[1]);
}
else { /* Variable angles for the y/z-axis */
GMT->current.map.frame.axis[no].use_angle = true;
GMT->current.map.frame.axis[no].use_angle[pr] = true;
if (p[1] == 'n') /* +an is code for normal to y/z-axis;*/
GMT->current.map.frame.axis[no].angle = 0.0;
GMT->current.map.frame.axis[no].angle[pr] = 0.0;
else if (p[1] == 'p') /* +ap is code for normal to y/z-axis; this triggers ortho=false later */
GMT->current.map.frame.axis[no].angle = 90.0;
GMT->current.map.frame.axis[no].angle[pr] = 90.0;
else /* Assume a variable angle */
GMT->current.map.frame.axis[no].angle = atof (&p[1]);
GMT->current.map.frame.axis[no].angle[pr] = atof (&p[1]);
}
if (GMT->current.map.frame.axis[no].angle < -90.0 || GMT->current.map.frame.axis[no].angle > 90.0) {
if (GMT->current.map.frame.axis[no].angle[pr] < -90.0 || GMT->current.map.frame.axis[no].angle[pr] > 90.0) {
GMT_Report (GMT->parent, GMT_MSG_ERROR, "Option -B: +a<angle> must be in the -90 to +90 range\n");
error++;
}
else
GMT->current.map.frame.axis[no].use_angle = true;
GMT->current.map.frame.axis[no].use_angle[pr] = true;
break;
case 'f': /* Select fancy annotations with trailing W|E|S|N */
if (gmt_M_x_is_lon(GMT,GMT_IN) || gmt_M_y_is_lat(GMT,GMT_IN))
Expand Down
106 changes: 60 additions & 46 deletions src/gmt_plot.c
Original file line number Diff line number Diff line change
Expand Up @@ -5657,7 +5657,7 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
unsigned int annot_pos; /* Either 0 for upper annotation or 1 for lower annotation */
unsigned int primary; /* Axis item number of annotation with largest interval/unit */
unsigned int axis = A->id; /* Axis id (GMT_X, GMT_Y, GMT_Z) */
unsigned int justify;
unsigned int justify[2]; /* Text justification for primary [0] and secondary [1] annotations */
unsigned int lx_just = PSL_BC, ly_just = PSL_BC;
bool horizontal; /* true if axis is horizontal */
bool annotate = ((side & GMT_AXIS_ANNOT) > 0);
Expand All @@ -5668,16 +5668,18 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
bool do_annot; /* true unless we are dealing with Gregorian weeks */
bool do_tick; /* true unless we are dealing with bits of weeks */
bool form; /* true for outline font */
bool ortho = false; /* true if annotations are orthogonal to axes */
bool ortho = false; /* true if annotations are orthogonal to axes (based on primary settings; drives axis-wide layout) */
bool ortho2[2]; /* Same, but independently for primary [0] and secondary [1] annotations */
bool flip = false; /* true if annotations are inside axes */
bool MM_set = false; /* true after we define the MM PS macro for label offsets */
bool angled = false; /* True if user used +angle to select a slanted annotation */
bool skip = false, just_set = false;
bool angled[2] = {false, false}; /* True if user used +angle to select a slanted annotation, per primary/secondary */
bool skip2[2] = {false, false}, just_set2[2] = {false, false};
bool save_pi = GMT->current.plot.substitute_pi;
bool skip_center_annot = false; /* May be set to true to avoid annotation where two graph axes intersect */
bool center_reset = false;
unsigned int pr; /* Loop variable over GMT_PRIMARY/GMT_SECONDARY */
double *knots = NULL, *knots_p = NULL; /* Array pointers with tick/annotation knots, the latter for primary annotations */
double x, t_use, text_angle, cos_a = 0.0, sin_a = 0.0, delta; /* Misc. variables */
double x, t_use, text_angle[2], cos_a[2] = {0.0, 0.0}, sin_a[2] = {0.0, 0.0}, delta; /* Misc. variables, now per primary [0] / secondary [1] */
double x_angle_add = 0.0, y_angle_add = 0.0; /* Used when dealing with perspectives */
double x_axis_pos = 0.0, y_axis_pos = 0.0; /* Normal starting points for drawing x or y axis */
double skip_val = 0.0; /* Knot value to be skipped if graph-centered is selected */
Expand Down Expand Up @@ -5705,10 +5707,9 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
horizontal = (axis == GMT_X); /* This is a horizontal axis */
xyz_fwd = ((axis == GMT_X) ? &gmt_x_to_xx : (axis == GMT_Y) ? &gmt_y_to_yy : &gmt_z_to_zz);
primary = gmtplot_get_primary_annot (A); /* Find primary axis items */
if (A->use_angle) { /* Must honor the +a modifier */
if (axis != GMT_X && doubleAlmostEqualZero (A->angle, 90.0)) ortho = false, just_set = true; /* Y/Z-Annotations are parallel */
else if (axis != GMT_X && doubleAlmostEqualZero (A->angle, 0.0)) ortho = true, just_set = true; /* Y/Z-Annotations are normal */
if (doubleAlmostEqualZero (A->angle, 0.0)) skip = true; /* Annotations are parallel so do nothing */
if (A->use_angle[GMT_PRIMARY]) { /* Must honor the +a modifier - use primary setting to drive axis-wide layout (side, offsets) */
if (axis != GMT_X && doubleAlmostEqualZero (A->angle[GMT_PRIMARY], 90.0)) ortho = false; /* Y/Z-Annotations are parallel */
else if (axis != GMT_X && doubleAlmostEqualZero (A->angle[GMT_PRIMARY], 0.0)) ortho = true; /* Y/Z-Annotations are normal */
}
else if (strchr (GMT->current.setting.map_annot_ortho, axis_chr[axis][below]))
ortho = true; /* Annotations are orthogonal for this axis */
Expand All @@ -5723,34 +5724,47 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
strncpy (format, format_w_phase, GMT_LEN256);
}
}
text_angle = (ortho == horizontal) ? 90.0 : 0.0;
justify = (ortho) ? PSL_MR : PSL_BC;
if (A->use_angle && !skip) { /* User override annotation angle */
text_angle = A->angle;
angled = true;
if (!just_set) {
if (text_angle > 0.0)
justify = (below) ? PSL_MR : PSL_ML;
else
justify = (below) ? PSL_ML : PSL_MR;
}
if (axis == GMT_Y) {
ortho = true;
if (just_set && !below) justify = PSL_TC;
}
if (axis == GMT_X) {
cos_a = 0.5 * cosd (text_angle); /* Half-height of text at an angle */
sin_a = fabs (sind (text_angle)); /* Fraction of y offset due to slanted annotation */
}
else {
cos_a = cosd (text_angle); /* Full-height of text at an angle */
sin_a = fabs (sind (text_angle)); /* The y offset due to slanted annotation */
/* Compute angle/justify/ortho independently for primary [GMT_PRIMARY] and secondary [GMT_SECONDARY] annotations,
* so -Bp...+a<angle1> and -Bs...+a<angle2> can differ (see issue #7036). */
for (pr = GMT_PRIMARY; pr <= GMT_SECONDARY; pr++) {
ortho2[pr] = ortho; /* Start from the axis-wide default */
skip2[pr] = just_set2[pr] = false;
if (A->use_angle[pr]) {
if (axis != GMT_X && doubleAlmostEqualZero (A->angle[pr], 90.0)) ortho2[pr] = false, just_set2[pr] = true;
else if (axis != GMT_X && doubleAlmostEqualZero (A->angle[pr], 0.0)) ortho2[pr] = true, just_set2[pr] = true;
if (doubleAlmostEqualZero (A->angle[pr], 0.0)) skip2[pr] = true; /* Annotations are parallel so do nothing */
}
text_angle[pr] = (ortho2[pr] == horizontal) ? 90.0 : 0.0;
justify[pr] = (ortho2[pr]) ? PSL_MR : PSL_BC;
if (A->use_angle[pr] && !skip2[pr]) { /* User override annotation angle for this level */
text_angle[pr] = A->angle[pr];
angled[pr] = true;
if (!just_set2[pr]) {
if (text_angle[pr] > 0.0)
justify[pr] = (below) ? PSL_MR : PSL_ML;
else
justify[pr] = (below) ? PSL_ML : PSL_MR;
}
if (axis == GMT_Y) {
ortho2[pr] = true;
if (just_set2[pr] && !below) justify[pr] = PSL_TC;
}
if (axis == GMT_X) {
cos_a[pr] = 0.5 * cosd (text_angle[pr]); /* Half-height of text at an angle */
sin_a[pr] = fabs (sind (text_angle[pr])); /* Fraction of y offset due to slanted annotation */
}
else {
cos_a[pr] = cosd (text_angle[pr]); /* Full-height of text at an angle */
sin_a[pr] = fabs (sind (text_angle[pr])); /* The y offset due to slanted annotation */
}
}
}
flip = (GMT->current.setting.map_frame_type & GMT_IS_INSIDE); /* Inside annotation */
if (axis != GMT_Z && GMT->current.proj.three_D && GMT->current.proj.z_project.cos_az > 0) { /* Rotate x/y-annotations when seen "from North" */
if (!flip) justify = gmt_flip_justify (GMT, justify);
text_angle += 180.0;
for (pr = GMT_PRIMARY; pr <= GMT_SECONDARY; pr++) {
if (!flip) justify[pr] = gmt_flip_justify (GMT, justify[pr]);
text_angle[pr] += 180.0;
}
}
// else if (flip)
// justify = gmt_flip_justify (GMT, justify);
Expand Down Expand Up @@ -5919,24 +5933,24 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
}
else
gmtlib_get_coordinate_label (GMT, string, &GMT->current.plot.calclock, format, T, knots[i], delta); /* Get annotation string */
PSL_deftextdim (PSL, ortho ? "-w" : "-h", font.size, string);
PSL_deftextdim (PSL, ortho2[annot_pos] ? "-w" : "-h", font.size, string);
PSL_command (PSL, "mx\n"); /* Update the longest annotation stored in PSL_AH? */
}
PSL_command (PSL, "def\n"); /* Finalize the definition of longest (y-axis) or tallest (x-annotation) found */
if (angled && axis == GMT_X) { /* Also need annotation width since a component of length is projected in the y-direction so label and title must be displaced by this amount */
if (angled[annot_pos] && axis == GMT_X) { /* Also need annotation width since a component of length is projected in the y-direction so label and title must be displaced by this amount */
/* Note: PSL_slant_y will also be used when placing a Cartesian frame title */
PSL_command (PSL, "/PSL_slant_y ");
if (label_c && label_c[nx1-1] && label_c[nx1-1][0]) /* We only use the string for the max annotation value at index nx1-1 */
strncpy (string, label_c[nx1-1], GMT_LEN256-1);
else
gmtlib_get_coordinate_label (GMT, string, &GMT->current.plot.calclock, format, T, knots[nx1-1], delta); /* Get annotation string */
PSL_deftextdim (PSL, "-w", font.size, string); /* Compute the width */
PSL_command (PSL, " %.12g mul def\n", sin_a); /* Multiply this width by sine of the angle to get the y-component */
//PSL_command (PSL, " %.12g mul %g add def\n", sin_a, PSL_IZ (PSL, 72.0 * GMT->current.setting.font_annot[GMT_PRIMARY].size)); /* Multiply this width by sine of the angle to get the y-component */
PSL_command (PSL, " %.12g mul def\n", sin_a[annot_pos]); /* Multiply this width by sine of the angle to get the y-component */
//PSL_command (PSL, " %.12g mul %g add def\n", sin_a[annot_pos], PSL_IZ (PSL, 72.0 * GMT->current.setting.font_annot[GMT_PRIMARY].size)); /* Multiply this width by sine of the angle to get the y-component */
}
else if (angled && axis == GMT_Y) { /* Need a slant in x and reset PSL_AH? to 0 */
//PSL_command (PSL, "/PSL_slant_x PSL_AH%d %.12g mul %g add def\n", annot_pos, cos_a, PSL_IZ (PSL, 72.0 * GMT->current.setting.font_annot[GMT_PRIMARY].size)); /* Largest annotation width (or height) so far */
PSL_command (PSL, "/PSL_slant_x PSL_AH%d %.12g mul def\n", annot_pos, cos_a); /* Largest annotation width (or height) so far */
else if (angled[annot_pos] && axis == GMT_Y) { /* Need a slant in x and reset PSL_AH? to 0 */
//PSL_command (PSL, "/PSL_slant_x PSL_AH%d %.12g mul %g add def\n", annot_pos, cos_a[annot_pos], PSL_IZ (PSL, 72.0 * GMT->current.setting.font_annot[GMT_PRIMARY].size)); /* Largest annotation width (or height) so far */
PSL_command (PSL, "/PSL_slant_x PSL_AH%d %.12g mul def\n", annot_pos, cos_a[annot_pos]); /* Largest annotation width (or height) so far */
PSL_command (PSL, "/PSL_AH%d 0 def\n", annot_pos); /* Largest annotation width (or height) so far */
}

Expand All @@ -5956,17 +5970,17 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
if (!is_interval && gmtplot_skip_second_annot (k, knots[i], knots_p, np, primary)) continue; /* Secondary annotation skipped when coinciding with primary annotation */
/* Move to new anchor point */
PSL_command (PSL, "%d PSL_A%d_y MM\n", PSL_IZ (PSL, x), annot_pos);
if (angled) { /* Must compensate for rotated textbox sticking too close to axis */
if (angled[annot_pos]) { /* Must compensate for rotated textbox sticking too close to axis */
if (below) /* S axis */
PSL_command (PSL, "0 PSL_AH%d 1 %.12g sub mul G\n", annot_pos, cos_a);
PSL_command (PSL, "0 PSL_AH%d 1 %.12g sub mul G\n", annot_pos, cos_a[annot_pos]);
else /* N axis */
PSL_command (PSL, "0 PSL_AH%d %.12g mul G\n", annot_pos, cos_a);
PSL_command (PSL, "0 PSL_AH%d %.12g mul G\n", annot_pos, cos_a[annot_pos]);
}
if (label_c && label_c[i] && label_c[i][0])
strncpy (string, label_c[i], GMT_LEN256-1);
else
gmtlib_get_coordinate_label (GMT, string, &GMT->current.plot.calclock, format, T, knots[i], delta); /* Get annotation string */
PSL_plottext (PSL, 0.0, 0.0, -font.size, string, text_angle, justify, form);
PSL_plottext (PSL, 0.0, 0.0, -font.size, string, text_angle[annot_pos], justify[annot_pos], form);
}
if (!faro) PSL_command (PSL, "/PSL_A%d_y PSL_A%d_y PSL_AH%d add def\n", annot_pos, annot_pos, annot_pos);
}
Expand Down Expand Up @@ -6006,9 +6020,9 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou
else
PSL_command (PSL, "/PSL_L_y PSL_A0_y PSL_A1_y mx %d add %sdef\n", PSL_IZ (PSL, GMT->current.setting.map_label_offset[L_axis]), (neg == horizontal) ? "PSL_LH add " : "");
/* Move to new anchor point for label */
if (angled && axis == GMT_X) /* Add offset due to angled x-annotations */
if ((angled[GMT_PRIMARY] || angled[GMT_SECONDARY]) && axis == GMT_X) /* Add offset due to angled x-annotations */
PSL_command (PSL, "%d PSL_L_y PSL_slant_y add MM\n", PSL_IZ (PSL, 0.5 * length));
else if (angled && axis == GMT_Y)
else if ((angled[GMT_PRIMARY] || angled[GMT_SECONDARY]) && axis == GMT_Y)
PSL_command (PSL, "%d PSL_L_y PSL_slant_x add MM\n", PSL_IZ (PSL, 0.5 * length));
else
PSL_command (PSL, "%d PSL_L_y MM\n", PSL_IZ (PSL, 0.5 * length));
Expand Down
4 changes: 2 additions & 2 deletions src/gmt_project.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,11 +502,11 @@ struct GMT_PLOT_AXIS { /* Information for one time axis */
unsigned int special; /* See gmt_enum_annot values */
unsigned int label_mode; /* 0 = parallel to all axes, 1 = always horizontal on map */
bool substitute_pi; /* True if we need to plot fractions of pi on this axis */
bool use_angle; /* True if we got +a<angle>|n|p for this axis */
bool use_angle[2]; /* True if we got +a<angle>|n|p for this axis, for [GMT_PRIMARY] and [GMT_SECONDARY] annotations */
bool skip[2]; /* Determines if we skip annotations at the lower or upper bounds of an axis [false/false] */
struct GMT_PLOT_AXIS_ITEM item[8]; /* see above defines for which is which */
double phase; /* Phase offset for strides: (knot-phase)%interval = 0 */
double angle; /* Annotations angle set by user */
double angle[2]; /* Annotations angle set by user, for [GMT_PRIMARY] and [GMT_SECONDARY] annotations (issue #7036) */
char label[GMT_LEN256]; /* Label of the axis */
char secondary_label[GMT_LEN256]; /* Optionally use this label when axis is right or top */
char unit[GMT_LEN64]; /* Axis unit appended to annotations */
Expand Down
Loading