From 9ff015e1c869aabb8561f3987e48466b8e355d2f Mon Sep 17 00:00:00 2001 From: Joaquim Date: Thu, 28 May 2026 16:24:35 +0100 Subject: [PATCH 01/10] Try fixing again #529 --- src/gmt_map.c | 36 ++++++++++++++++++++++++++---------- src/gmt_plot.c | 8 +++++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/gmt_map.c b/src/gmt_map.c index 3a1f92f89c0..d4cbd998e19 100644 --- a/src/gmt_map.c +++ b/src/gmt_map.c @@ -6374,21 +6374,37 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { /* z_level == DBL_MAX is signaling that it was not set by the user. In that case we change it to the lower z level */ if (GMT->current.proj.z_level == DBL_MAX) GMT->current.proj.z_level = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[ZLO] : GMT->common.R.wesn[ZHI]; - switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ - case GMT_X: - i_min = XLO, i_max = XHI; - break; - case GMT_Y: - i_min = YLO, i_max = YHI; - break; - case GMT_Z: - i_min = ZLO, i_max = ZHI; + if (GMT->common.J.zactive) { /* True 3-D plot via -JZ: z-axis range is always ZLO/ZHI regardless of -p[x|y] view plane; view_plane retains user value so -px/-py target the x/y wall */ + i_min = ZLO, i_max = ZHI; + switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ + case GMT_X: + i_min = XLO, i_max = XHI; + break; + case GMT_Y: + i_min = YLO, i_max = YHI; + break; + case GMT_Z: + i_min = ZLO, i_max = ZHI; + } + } + else { + switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ + case GMT_X: + i_min = XLO, i_max = XHI; + break; + case GMT_Y: + i_min = YLO, i_max = YHI; + break; + case GMT_Z: + i_min = ZLO, i_max = ZHI; + } } switch (GMT->current.proj.xyz_projection[GMT_Z]%3) { /* Modulo 3 so that GMT_TIME (3) maps to GMT_LINEAR (0) */ case GMT_LINEAR: /* Regular scaling */ zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[i_min] : GMT->common.R.wesn[i_max]; zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[i_max] : GMT->common.R.wesn[i_min]; + z_range = (GMT->current.proj.xyz_pos[GMT_Z]) ? (GMT->common.R.wesn[ZHI] - GMT->common.R.wesn[ZLO]) : (GMT->common.R.wesn[ZLO] - GMT->common.R.wesn[ZHI]); GMT->current.proj.fwd_z = &gmtlib_translin; GMT->current.proj.inv_z = &gmtlib_itranslin; break; @@ -6411,7 +6427,7 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { GMT->current.proj.fwd_z = &gmtproj_transpowz; GMT->current.proj.inv_z = &gmtproj_itranspowz; } - z_range = zmax - zmin; + //z_range = zmax - zmin; if (z_range == 0.0 && GMT->current.proj.compute_scale[GMT_Z]) GMT->current.proj.scale[GMT_Z] = 0.0; /* No range given, just flat projected map */ else if (GMT->current.proj.compute_scale[GMT_Z]) diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 7392e55a75b..1c5f307912e 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -10582,7 +10582,13 @@ void gmt_plane_perspective (struct GMT_CTRL *GMT, int plane, double level) { if (plane < 0) /* Reset to original matrix */ PSL_command (PSL, "PSL_GPP setmatrix\n"); /* Return to normal current transformation matrix */ else { /* New perspective plane: compute all derivatives and use full matrix */ - if (plane >= GMT_ZW) level = gmt_z_to_zz (GMT, level); /* First convert world z coordinate to projected z coordinate */ + if (plane >= GMT_ZW) { /* World coordinate: pick the axis perpendicular to the plane so the correct scale (X/Y/Z) is applied */ + switch (plane % 3) { + case GMT_X: level = gmt_x_to_xx(GMT, level); break; /* Constant-X plane: level is in user X units */ + case GMT_Y: level = gmt_y_to_yy(GMT, level); break; /* Constant-Y plane: level is in user Y units */ + case GMT_Z: level = gmt_z_to_zz(GMT, level); break; /* Constant-Z plane: level is in user Z units */ + } + } switch (plane % 3) { case GMT_X: /* Constant x, Convert y,z to x',y' */ a = GMT->current.proj.z_project.sin_az; From 2741c2cac1d6ae9ee708d687dafeca99db0cb687 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Thu, 28 May 2026 20:37:48 +0100 Subject: [PATCH 02/10] One more step towards the goal --- src/gmt_plot.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 1c5f307912e..80cfbd41b97 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -10595,6 +10595,8 @@ void gmt_plane_perspective (struct GMT_CTRL *GMT, int plane, double level) { b = -GMT->current.proj.z_project.cos_az * GMT->current.proj.z_project.sin_el; c = 0.0; d = GMT->current.proj.z_project.cos_el; + if (plane >= GMT_ZW && GMT->current.map.height > 0.0) /* User -px plan: stretch in_y so plan height matches Z axis height (proj.zmax) */ + d *= GMT->current.proj.zmax / GMT->current.map.height; e = GMT->current.proj.z_project.x_off - level * GMT->current.proj.z_project.cos_az; f = GMT->current.proj.z_project.y_off - level * GMT->current.proj.z_project.sin_az * GMT->current.proj.z_project.sin_el; break; @@ -10603,6 +10605,8 @@ void gmt_plane_perspective (struct GMT_CTRL *GMT, int plane, double level) { b = -GMT->current.proj.z_project.sin_az * GMT->current.proj.z_project.sin_el; c = 0.0; d = GMT->current.proj.z_project.cos_el; + if (plane >= GMT_ZW && GMT->current.map.height > 0.0) /* User -py plan: stretch in_y so plan height matches Z axis height (proj.zmax) */ + d *= GMT->current.proj.zmax / GMT->current.map.height; e = GMT->current.proj.z_project.x_off + level * GMT->current.proj.z_project.sin_az; f = GMT->current.proj.z_project.y_off - level * GMT->current.proj.z_project.cos_az * GMT->current.proj.z_project.sin_el; break; From 1faab340f67008f8190125eb932aaff28f8b106e Mon Sep 17 00:00:00 2001 From: Joaquim Date: Thu, 28 May 2026 23:13:51 +0100 Subject: [PATCH 03/10] Finally (?) fix the different scales issues --- src/gmt_parse.c | 1 + src/gmt_plot.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/gmt_parse.c b/src/gmt_parse.c index b235a18a5bb..24cf7bd1059 100644 --- a/src/gmt_parse.c +++ b/src/gmt_parse.c @@ -98,6 +98,7 @@ GMT_LOCAL int gmtparse_B_arg_inspector (struct GMT_CTRL *GMT, char *in) { k = (in[0] == 'p' || in[0] == 's') ? 1 : 0; /* Skip p|s in -Bp|s */ if (strchr ("xyz", in[k])) gmt5++; /* Definitively GMT5 */ if (k == 0 && !isdigit (in[0]) && strchr ("WESNwesn", in[1])) gmt5++; /* Definitively GMT5 */ + if (in[0] == 's' && in[1] && strchr ("WESNZwenzlrbtu", in[1])) gmt5++; /* -Bs is GMT5 frame (south + other axes), not -B[s] secondary prefix */ j = k; while (j < last && (in[j] == 'x' || in[j] == 'y' || in[j] == 'z')) j++; custom = (in[j] == 'c'); /* Got -B[p|s][xyz]c */ diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 80cfbd41b97..9247f44e24a 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -6648,6 +6648,26 @@ void gmt_map_basemap (struct GMT_CTRL *GMT) { bool clip_on = false, too_crowded = false; char *order[2] = {"before", "after"}; struct PSL_CTRL *PSL= GMT->PSL; + /* For -px/-py world-coord wall plan, vertical of basemap is the Z axis. Swap only Y annotation state with Z + * (labels and range), scale Y so labels still land within plan's projected y-box [0,map.height]; matrix d-stretch + * then maps that visually to Z height. Restore before gmt_vertical_axis. */ + bool swap_yz = (GMT->current.proj.z_project.plane >= GMT_ZW && (GMT->current.proj.z_project.plane % 3) != GMT_Z); + double saved_y_wesn[2] = {0.0, 0.0}, saved_y_scale = 0.0, saved_y_origin = 0.0; + struct GMT_PLOT_AXIS saved_axis_y; + if (swap_yz) { + double z_range = GMT->common.R.wesn[ZHI] - GMT->common.R.wesn[ZLO]; + saved_y_wesn[0] = GMT->common.R.wesn[YLO]; + saved_y_wesn[1] = GMT->common.R.wesn[YHI]; + saved_y_scale = GMT->current.proj.scale[GMT_Y]; + saved_y_origin = GMT->current.proj.origin[GMT_Y]; + saved_axis_y = GMT->current.map.frame.axis[GMT_Y]; + GMT->common.R.wesn[YLO] = GMT->common.R.wesn[ZLO]; + GMT->common.R.wesn[YHI] = GMT->common.R.wesn[ZHI]; + GMT->current.proj.scale[GMT_Y] = (z_range > 0.0) ? GMT->current.map.height / z_range : saved_y_scale; + GMT->current.proj.origin[GMT_Y] = -GMT->common.R.wesn[ZLO] * GMT->current.proj.scale[GMT_Y]; + GMT->current.map.frame.axis[GMT_Y] = GMT->current.map.frame.axis[GMT_Z]; + GMT->current.map.frame.axis[GMT_Y].id = GMT_Y; /* So gmt_xy_axis uses gmt_y_to_yy(with our swapped scale[Y]) not gmt_z_to_zz */ + } /* 0. Determine if we need to be here and set a few parameters */ @@ -6712,6 +6732,14 @@ void gmt_map_basemap (struct GMT_CTRL *GMT) { if (GMT->current.proj.got_azimuths) gmt_M_uint_swap (GMT->current.map.frame.side[E_SIDE], GMT->current.map.frame.side[W_SIDE]); /* Undo temporary swap */ + if (swap_yz) { /* Restore Y-axis state we swapped with Z for the vertical wall plan */ + GMT->common.R.wesn[YLO] = saved_y_wesn[0]; + GMT->common.R.wesn[YHI] = saved_y_wesn[1]; + GMT->current.proj.scale[GMT_Y] = saved_y_scale; + GMT->current.proj.origin[GMT_Y] = saved_y_origin; + GMT->current.map.frame.axis[GMT_Y] = saved_axis_y; + } + if (GMT->current.proj.three_D && GMT->current.map.frame.drawz) GMT->current.map.frame.plotted_header = false; /* Now we can plot the title [if selected via -B+t] */ if ((GMT->current.map.frame.order == GMT_BASEMAP_BEFORE && (GMT->current.plot.mode_3D & 1)) || (GMT->current.map.frame.order == GMT_BASEMAP_AFTER && (GMT->current.plot.mode_3D & 2))) From 8316a393bf6101fa0901cfd8e648f3b6231bfa08 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Thu, 28 May 2026 23:49:24 +0100 Subject: [PATCH 04/10] Fix the non-closing cune (+b) at the base. --- src/gmt_map.c | 34 ++++++++++++++++++++++++++++------ src/gmt_plot.c | 2 +- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/gmt_map.c b/src/gmt_map.c index d4cbd998e19..4aa9eb608ff 100644 --- a/src/gmt_map.c +++ b/src/gmt_map.c @@ -6367,6 +6367,7 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { unsigned int i, i_min = 0, i_max = 0; bool easy, positive; double x, y, zmin = 0.0, zmax = 0.0, z_range; + double _zmin = 0.0, _zmax = 0.0; GMT->current.proj.three_D = (GMT->current.proj.z_project.view_azimuth != 180.0 || GMT->current.proj.z_project.view_elevation != 90.0); GMT->current.proj.scale[GMT_Z] = GMT->current.proj.z_pars[0]; @@ -6374,6 +6375,7 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { /* z_level == DBL_MAX is signaling that it was not set by the user. In that case we change it to the lower z level */ if (GMT->current.proj.z_level == DBL_MAX) GMT->current.proj.z_level = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[ZLO] : GMT->common.R.wesn[ZHI]; +#if 0 if (GMT->common.J.zactive) { /* True 3-D plot via -JZ: z-axis range is always ZLO/ZHI regardless of -p[x|y] view plane; view_plane retains user value so -px/-py target the x/y wall */ i_min = ZLO, i_max = ZHI; switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ @@ -6399,12 +6401,26 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { i_min = ZLO, i_max = ZHI; } } +#endif + + switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ + case GMT_X: + i_min = XLO, i_max = XHI; + break; + case GMT_Y: + i_min = YLO, i_max = YHI; + break; + case GMT_Z: + i_min = ZLO, i_max = ZHI; + } switch (GMT->current.proj.xyz_projection[GMT_Z]%3) { /* Modulo 3 so that GMT_TIME (3) maps to GMT_LINEAR (0) */ case GMT_LINEAR: /* Regular scaling */ zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[i_min] : GMT->common.R.wesn[i_max]; zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[i_max] : GMT->common.R.wesn[i_min]; - z_range = (GMT->current.proj.xyz_pos[GMT_Z]) ? (GMT->common.R.wesn[ZHI] - GMT->common.R.wesn[ZLO]) : (GMT->common.R.wesn[ZLO] - GMT->common.R.wesn[ZHI]); + _zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[ZLO] : GMT->common.R.wesn[ZHI]; + _zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[ZHI] : GMT->common.R.wesn[ZLO]; + GMT->current.proj.fwd_z = &gmtlib_translin; GMT->current.proj.inv_z = &gmtlib_itranslin; break; @@ -6413,8 +6429,11 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { GMT_Report (GMT->parent, GMT_MSG_ERROR, "Option -Jz -JZ: limits must be positive for log10 projection\n"); return GMT_PROJECTION_ERROR; } - zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10 (GMT, GMT->common.R.wesn[i_min]) : d_log10 (GMT, GMT->common.R.wesn[i_max]); - zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10 (GMT, GMT->common.R.wesn[i_max]) : d_log10 (GMT, GMT->common.R.wesn[i_min]); + zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10(GMT, GMT->common.R.wesn[i_min]) : d_log10(GMT, GMT->common.R.wesn[i_max]); + zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10(GMT, GMT->common.R.wesn[i_max]) : d_log10(GMT, GMT->common.R.wesn[i_min]); + _zmin = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10(GMT, GMT->common.R.wesn[ZLO]) : d_log10(GMT, GMT->common.R.wesn[ZHI]); + _zmax = (GMT->current.proj.xyz_pos[GMT_Z]) ? d_log10(GMT, GMT->common.R.wesn[ZHI]) : d_log10(GMT, GMT->common.R.wesn[ZLO]); + GMT->current.proj.fwd_z = &gmtproj_translog10; GMT->current.proj.inv_z = &gmtproj_itranslog10; break; @@ -6422,12 +6441,15 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { GMT->current.proj.xyz_pow[GMT_Z] = GMT->current.proj.z_pars[1]; GMT->current.proj.xyz_ipow[GMT_Z] = 1.0 / GMT->current.proj.z_pars[1]; positive = !((GMT->current.proj.xyz_pos[GMT_Z] + (GMT->current.proj.xyz_pow[GMT_Z] > 0.0)) % 2); - zmin = (positive) ? pow (GMT->common.R.wesn[ZLO], GMT->current.proj.xyz_pow[GMT_Z]) : pow (GMT->common.R.wesn[i_max], GMT->current.proj.xyz_pow[GMT_Z]); - zmax = (positive) ? pow (GMT->common.R.wesn[i_max], GMT->current.proj.xyz_pow[GMT_Z]) : pow (GMT->common.R.wesn[i_min], GMT->current.proj.xyz_pow[GMT_Z]); + zmin = (positive) ? pow(GMT->common.R.wesn[i_min], GMT->current.proj.xyz_pow[GMT_Z]) : pow(GMT->common.R.wesn[i_max], GMT->current.proj.xyz_pow[GMT_Z]); + zmax = (positive) ? pow(GMT->common.R.wesn[i_max], GMT->current.proj.xyz_pow[GMT_Z]) : pow(GMT->common.R.wesn[i_min], GMT->current.proj.xyz_pow[GMT_Z]); + _zmin = (positive) ? pow(GMT->common.R.wesn[ZLO], GMT->current.proj.xyz_pow[GMT_Z]) : pow(GMT->common.R.wesn[ZHI], GMT->current.proj.xyz_pow[GMT_Z]); + _zmax = (positive) ? pow(GMT->common.R.wesn[ZHI], GMT->current.proj.xyz_pow[GMT_Z]) : pow(GMT->common.R.wesn[ZLO], GMT->current.proj.xyz_pow[GMT_Z]); + GMT->current.proj.fwd_z = &gmtproj_transpowz; GMT->current.proj.inv_z = &gmtproj_itranspowz; } - //z_range = zmax - zmin; + z_range = _zmax - _zmin; /* This one is for the Z-axis scale. zmin & zmax are for -p[x|y] levels */ if (z_range == 0.0 && GMT->current.proj.compute_scale[GMT_Z]) GMT->current.proj.scale[GMT_Z] = 0.0; /* No range given, just flat projected map */ else if (GMT->current.proj.compute_scale[GMT_Z]) diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 9247f44e24a..902ab4b70b7 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -3186,7 +3186,7 @@ GMT_LOCAL void gmtplot_cube_box (struct GMT_CTRL *GMT, struct PSL_CTRL *PSL, int xx[0] = xx[1] = nesw[(quadrant+1)%4]; xx[2] = xx[3] = nesw[(quadrant+3)%4]; yy[0] = yy[3] = GMT->current.proj.zmin; yy[1] = yy[2] = GMT->current.proj.zmax; gmt_setpen (GMT, &GMT->current.map.frame.pen); - PSL_plotline (PSL, xx, yy, 4, PSL_MOVE|PSL_STROKE); + PSL_plotline (PSL, xx, yy, 4, PSL_MOVE|PSL_STROKE|PSL_CLOSE); } GMT_LOCAL void gmtplot_timestamp(struct GMT_CTRL *GMT, struct PSL_CTRL *PSL, double x, double y, unsigned int justify, char *U_label) { From 8fa3ab753f0cc4ed728e81613fc0b9d575229a7d Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 29 May 2026 00:21:12 +0100 Subject: [PATCH 05/10] Do not skip Z-annotation label equal to plane level. --- src/gmt_plot.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 902ab4b70b7..85ca25aa51b 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -5909,10 +5909,10 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou for (i = 0; i < nx1; i++) { if (gmtlib_annot_pos (GMT, val0, val1, T, &knots[i], &t_use)) continue; /* Outside range */ - if (axis == GMT_Z && fabs (knots[i] - GMT->current.proj.z_level) < GMT_CONV8_LIMIT) continue; /* Skip z annotation coinciding with z-level plane */ + if (axis == GMT_Z && (GMT->current.proj.z_project.view_plane % 3) == GMT_Z && fabs (knots[i] - GMT->current.proj.z_level) < GMT_CONV8_LIMIT) continue; /* Skip z annotation coinciding with z-level plane (only for -pz) */ x = (*xyz_fwd) (GMT, knots[i]); /* Convert to inches on the page */ - if (skip_center_annot && doubleAlmostEqualZero (knots[i], skip_val)) continue; /* Don't want annotations exactly at intersection between graph axes */ - if (gmtplot_skip_end_annotation (GMT, axis, x, length)) continue; /* Don't want annotations exactly at one or both ends of the axis */ + if (skip_center_annot && doubleAlmostEqualZero(knots[i], skip_val)) continue; /* Don't want annotations exactly at intersection between graph axes */ + if (gmtplot_skip_end_annotation(GMT, axis, x, length)) continue; /* Don't want annotations exactly at one or both ends of the axis */ if (!is_interval && gmtplot_skip_second_annot (k, knots[i], knots_p, np, primary)) continue; /* Secondary annotation skipped when coinciding with primary annotation */ if (label_c && label_c[i] && label_c[i][0]) { strncpy (string, label_c[i], GMT_LEN256-1); @@ -5949,7 +5949,7 @@ void gmt_xy_axis (struct GMT_CTRL *GMT, double x0, double y0, double length, dou for (i = 0; i < nx1; i++) { if (gmtlib_annot_pos (GMT, val0, val1, T, &knots[i], &t_use)) continue; /* Outside range */ - if (axis == GMT_Z && fabs (knots[i] - GMT->current.proj.z_level) < GMT_CONV8_LIMIT) continue; /* Skip z annotation coinciding with z-level plane */ + if (axis == GMT_Z && (GMT->current.proj.z_project.view_plane % 3) == GMT_Z && fabs(knots[i] - GMT->current.proj.z_level) < GMT_CONV8_LIMIT) continue; /* Skip z annotation coinciding with z-level plane (only for -pz) */ x = (*xyz_fwd) (GMT, t_use); /* Convert to inches on the page */ if (skip_center_annot && doubleAlmostEqualZero (knots[i], skip_val)) continue; /* Don't want annotations exactly at intersection between graph axes */ if (gmtplot_skip_end_annotation (GMT, axis, x, length)) continue; /* Don't want annotations exactly at one or both ends of the axis */ From e113c3d2c8f009fbea56bc36c3cf10f925c5f37a Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 29 May 2026 00:48:53 +0100 Subject: [PATCH 06/10] Fix for last the Y-scales/annotations --- src/gmt_plot.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/gmt_plot.c b/src/gmt_plot.c index 85ca25aa51b..29aae382a06 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -6652,8 +6652,11 @@ void gmt_map_basemap (struct GMT_CTRL *GMT) { * (labels and range), scale Y so labels still land within plan's projected y-box [0,map.height]; matrix d-stretch * then maps that visually to Z height. Restore before gmt_vertical_axis. */ bool swap_yz = (GMT->current.proj.z_project.plane >= GMT_ZW && (GMT->current.proj.z_project.plane % 3) != GMT_Z); + bool swap_xy = (GMT->current.proj.z_project.plane >= GMT_ZW && (GMT->current.proj.z_project.plane % 3) == GMT_X); double saved_y_wesn[2] = {0.0, 0.0}, saved_y_scale = 0.0, saved_y_origin = 0.0; - struct GMT_PLOT_AXIS saved_axis_y; + double saved_x_wesn[2] = {0.0, 0.0}, saved_x_scale = 0.0, saved_x_origin = 0.0; + double saved_rect_x[2] = {0.0, 0.0}, saved_map_width = 0.0; + struct GMT_PLOT_AXIS saved_axis_y, saved_axis_x; if (swap_yz) { double z_range = GMT->common.R.wesn[ZHI] - GMT->common.R.wesn[ZLO]; saved_y_wesn[0] = GMT->common.R.wesn[YLO]; @@ -6668,6 +6671,25 @@ void gmt_map_basemap (struct GMT_CTRL *GMT) { GMT->current.map.frame.axis[GMT_Y] = GMT->current.map.frame.axis[GMT_Z]; GMT->current.map.frame.axis[GMT_Y].id = GMT_Y; /* So gmt_xy_axis uses gmt_y_to_yy(with our swapped scale[Y]) not gmt_z_to_zz */ } + if (swap_xy) { /* -px: plan horizontal is the Y direction; swap X annotation state with original Y so plan top/bottom show Y range */ + saved_x_wesn[0] = GMT->common.R.wesn[XLO]; + saved_x_wesn[1] = GMT->common.R.wesn[XHI]; + saved_x_scale = GMT->current.proj.scale[GMT_X]; + saved_x_origin = GMT->current.proj.origin[GMT_X]; + saved_axis_x = GMT->current.map.frame.axis[GMT_X]; + saved_rect_x[0] = GMT->current.proj.rect[XLO]; + saved_rect_x[1] = GMT->current.proj.rect[XHI]; + saved_map_width = GMT->current.map.width; + GMT->common.R.wesn[XLO] = saved_y_wesn[0]; + GMT->common.R.wesn[XHI] = saved_y_wesn[1]; + GMT->current.proj.scale[GMT_X] = saved_y_scale; + GMT->current.proj.origin[GMT_X] = saved_y_origin; + GMT->current.map.frame.axis[GMT_X] = saved_axis_y; + GMT->current.map.frame.axis[GMT_X].id = GMT_X; + GMT->current.proj.rect[XLO] = GMT->current.proj.rect[YLO]; + GMT->current.proj.rect[XHI] = GMT->current.proj.rect[YHI]; + GMT->current.map.width = GMT->current.map.height; + } /* 0. Determine if we need to be here and set a few parameters */ @@ -6732,6 +6754,16 @@ void gmt_map_basemap (struct GMT_CTRL *GMT) { if (GMT->current.proj.got_azimuths) gmt_M_uint_swap (GMT->current.map.frame.side[E_SIDE], GMT->current.map.frame.side[W_SIDE]); /* Undo temporary swap */ + if (swap_xy) { /* Restore X-axis state we swapped with Y for the plan horizontal */ + GMT->common.R.wesn[XLO] = saved_x_wesn[0]; + GMT->common.R.wesn[XHI] = saved_x_wesn[1]; + GMT->current.proj.scale[GMT_X] = saved_x_scale; + GMT->current.proj.origin[GMT_X] = saved_x_origin; + GMT->current.map.frame.axis[GMT_X] = saved_axis_x; + GMT->current.proj.rect[XLO] = saved_rect_x[0]; + GMT->current.proj.rect[XHI] = saved_rect_x[1]; + GMT->current.map.width = saved_map_width; + } if (swap_yz) { /* Restore Y-axis state we swapped with Z for the vertical wall plan */ GMT->common.R.wesn[YLO] = saved_y_wesn[0]; GMT->common.R.wesn[YHI] = saved_y_wesn[1]; From b8b89a564edb09aa5d80c23416ce4a2f0bafd1ed Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 29 May 2026 01:16:51 +0100 Subject: [PATCH 07/10] Remove commented lines --- src/gmt_map.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/gmt_map.c b/src/gmt_map.c index 4aa9eb608ff..373c46c9980 100644 --- a/src/gmt_map.c +++ b/src/gmt_map.c @@ -6375,34 +6375,6 @@ GMT_LOCAL int gmtmap_init_three_D (struct GMT_CTRL *GMT) { /* z_level == DBL_MAX is signaling that it was not set by the user. In that case we change it to the lower z level */ if (GMT->current.proj.z_level == DBL_MAX) GMT->current.proj.z_level = (GMT->current.proj.xyz_pos[GMT_Z]) ? GMT->common.R.wesn[ZLO] : GMT->common.R.wesn[ZHI]; -#if 0 - if (GMT->common.J.zactive) { /* True 3-D plot via -JZ: z-axis range is always ZLO/ZHI regardless of -p[x|y] view plane; view_plane retains user value so -px/-py target the x/y wall */ - i_min = ZLO, i_max = ZHI; - switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ - case GMT_X: - i_min = XLO, i_max = XHI; - break; - case GMT_Y: - i_min = YLO, i_max = YHI; - break; - case GMT_Z: - i_min = ZLO, i_max = ZHI; - } - } - else { - switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ - case GMT_X: - i_min = XLO, i_max = XHI; - break; - case GMT_Y: - i_min = YLO, i_max = YHI; - break; - case GMT_Z: - i_min = ZLO, i_max = ZHI; - } - } -#endif - switch (GMT->current.proj.z_project.view_plane % 3) { /* This fixes the problem reported in #529 */ case GMT_X: i_min = XLO, i_max = XHI; From 52d8abab0f013819ae953af729fc98677671a1ea Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 29 May 2026 01:48:56 +0100 Subject: [PATCH 08/10] Add a test --- test/psbasemap/perspective_planes.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/psbasemap/perspective_planes.sh diff --git a/test/psbasemap/perspective_planes.sh b/test/psbasemap/perspective_planes.sh new file mode 100644 index 00000000000..b405d14b42c --- /dev/null +++ b/test/psbasemap/perspective_planes.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# +# Test 3D perspective basemap with -px, -py, -pz view planes side by side. +# Each cube uses -BwsENZ1+b to draw all 12 cube edges. Y range 0-20, X range 0-10, Z range 0-30. +# -px: looking along X (plan = YZ); -py: looking along Y (plan = XZ); -pz: looking along Z (plan = XY). + +ps=perspective_planes.ps + +common="-R0/10/0/20/0/30 -JX2.5c/5c -JZ7.5c -Bxa+lx -Bya+ly -Bza+lz -BwsENZ1+b --PS_MEDIA=A4" + +gmt psbasemap $common -px135/40/5 -P -K -Xf1c -Yf2c > $ps +gmt psbasemap $common -py135/40/10 -O -K -Xf8c >> $ps +gmt psbasemap $common -pz135/40/20 -O -Xf14c >> $ps From 4b2520fdef80b9a01a978fa2006e4c1b18e8ab18 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Fri, 29 May 2026 01:59:47 +0100 Subject: [PATCH 09/10] Planes test --- test/baseline/psbasemap.dvc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/baseline/psbasemap.dvc b/test/baseline/psbasemap.dvc index 24dbccf2829..aaba432be0a 100644 --- a/test/baseline/psbasemap.dvc +++ b/test/baseline/psbasemap.dvc @@ -1,6 +1,6 @@ outs: -- md5: 6f6177c3673dc054c5489c208a9d072a.dir - nfiles: 57 +- md5: 499cd79959131cb42466afb2ba0bda90.dir + nfiles: 58 path: psbasemap hash: md5 - size: 2936773 + size: 2981097 From a402ba3141b74b21521ef721fca326083aafcbac Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 29 May 2026 09:31:41 +0800 Subject: [PATCH 10/10] Add execut permission --- test/psbasemap/perspective_planes.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/psbasemap/perspective_planes.sh diff --git a/test/psbasemap/perspective_planes.sh b/test/psbasemap/perspective_planes.sh old mode 100644 new mode 100755