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
58 changes: 58 additions & 0 deletions src/postscriptlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -4045,6 +4045,64 @@ int PSL_plotsegment (struct PSL_CTRL *PSL, double x0, double y0, double x1, doub
return (PSL_NO_ERROR);
}

int PSL_plotline_clipped_by_textbox(struct PSL_CTRL *PSL, double x0, double y0, double x1, double y1,
double fontsize, char *text, double angle, int justify, double offset[2]) {
/* Draw a line from (x0,y0) to the text-reference point (x1,y1), clipping out the part
* that falls inside the text bounding box (plus optional clearance offset) around (x1,y1).
* The box is sized for the given text/fontsize/justify and rotated by angle. Used for
* leader lines from a data point to an offset text label (pstext -D...+v<pen>).
*/
const char *jx[3] = {"0", "PSL_dim_w 2 div neg", "PSL_dim_w neg"};
const char *jy[3] = {"0", "PSL_dim_h 2 div neg", "PSL_dim_h neg"};
int x_just = 0, y_just = 0, ixl, iyl;
double a_rad, ca, sa, dx_u, dy_u, xl_u, yl_u, saved_fontsize;

if (text == NULL || text[0] == '\0') /* No text -- just draw the line */
return (PSL_plotsegment(PSL, x0, y0, x1, y1));

if (justify > 1) {
x_just = (justify + 3) % 4; /* 0=left, 1=center, 2=right */
y_just = justify / 4; /* 0=bottom, 1=middle, 2=top */
}

/* Compute line-start position in the local (rotated) coord system whose origin is at (x1,y1) */
a_rad = angle * D2R;
ca = cos(a_rad); sa = sin(a_rad);
dx_u = x0 - x1; dy_u = y0 - y1;
xl_u = dx_u * ca + dy_u * sa;
yl_u = -dx_u * sa + dy_u * ca;
ixl = (int)lrint(xl_u * PSL->internal.x2ix);
iyl = (int)lrint(yl_u * PSL->internal.y2iy);

saved_fontsize = PSL->current.fontsize; /* PSL_deftextdim will update the cache; restore after grestore */

PSL_comment(PSL, "PSL_plotline_clipped_by_textbox begin\n");
PSL_command(PSL, "V "); /* gsave */
PSL_command(PSL, "%d %d T ", psl_ix(PSL, x1), psl_iy(PSL, y1));
if (angle != 0.0) PSL_command(PSL, "%.12g R ", angle);
PSL_deftextdim(PSL, "PSL_dim", fontsize, text); /* Defines PSL_dim_w, _h, _d, _x0, _x1 in PS */
PSL_defunits(PSL, "PSL_dx", offset[0]);
PSL_defunits(PSL, "PSL_dy", offset[1]);

/* Build even-odd clip path: huge outer rectangle + textbox rectangle (the hole) */
PSL_command(PSL, "N -10000000 -10000000 M 20000000 0 D 0 20000000 D -20000000 0 D P\n");
PSL_command(PSL, "%s PSL_dim_x0 add PSL_dx sub %s PSL_dim_d add PSL_dy sub M ",
jx[x_just], jy[y_just]);
PSL_command(PSL, "PSL_dim_x1 PSL_dim_x0 sub PSL_dx 2 mul add 0 D ");
PSL_command(PSL, "0 PSL_dim_h PSL_dim_d sub PSL_dy 2 mul add D ");
PSL_command(PSL, "PSL_dim_x1 PSL_dim_x0 sub PSL_dx 2 mul add neg 0 D P\n");
PSL_command(PSL, "eoclip N\n");

/* Draw the (now clipped) line from (xl, yl) to (0, 0) in local coords */
PSL_command(PSL, "N %d %d M %d %d D S\n", ixl, iyl, -ixl, -iyl);

PSL_command(PSL, "U\n"); /* grestore -- pops clip and CTM */
PSL_comment(PSL, "PSL_plotline_clipped_by_textbox end\n");

PSL->current.fontsize = saved_fontsize;
return (PSL_NO_ERROR);
}

int PSL_setcurrentpoint (struct PSL_CTRL *PSL, double x, double y) {
/* Set the current point only */
PSL->internal.ix = psl_ix (PSL, x);
Expand Down
1 change: 1 addition & 0 deletions src/postscriptlight.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ EXTERN_MSC int PSL_plotpolygon (struct PSL_CTRL *PSL, double *x, double *y, int
EXTERN_MSC int PSL_plotgradienttriangle (struct PSL_CTRL *PSL, double *x, double *y, double *rgb, int steps);
EXTERN_MSC int PSL_plotgradienttriangle_gouraud (struct PSL_CTRL *PSL, double *x, double *y, double *rgb);
EXTERN_MSC int PSL_plotsegment (struct PSL_CTRL *PSL, double x0, double y0, double x1, double y1);
EXTERN_MSC int PSL_plotline_clipped_by_textbox (struct PSL_CTRL *PSL, double x0, double y0, double x1, double y1, double fontsize, char *text, double angle, int justify, double offset[2]);
EXTERN_MSC int PSL_plotsymbol (struct PSL_CTRL *PSL, double x, double y, double param[], int symbol);
EXTERN_MSC int PSL_plottext (struct PSL_CTRL *PSL, double x, double y, double fontsize, char *text, double angle, int justify, int mode);
EXTERN_MSC int PSL_plottextbox (struct PSL_CTRL *PSL, double x, double y, double fontsize, char *text, double angle, int justify, double offset[], int mode);
Expand Down
42 changes: 21 additions & 21 deletions src/pstext.c
Original file line number Diff line number Diff line change
Expand Up @@ -998,19 +998,19 @@ EXTERN_MSC int GMT_pstext (void *V_API, int mode, void *args) {

PSL_setfont (PSL, T.font.id);
gmt_plane_perspective (GMT, GMT->current.proj.z_project.view_plane, 0.0);
if (T.boxflag & 32) { /* Draw line from original point to shifted location */
gmt_setpen (GMT, &T.vecpen);
PSL_plotsegment (PSL, xx[0], yy[0], xx[1], yy[1]);
if (T.space_flag) { /* Meant % of fontsize */
offset[0] = 0.01 * T.x_space * T.font.size / PSL_POINTS_PER_INCH;
offset[1] = 0.01 * T.y_space * T.font.size / PSL_POINTS_PER_INCH;
}
else {
offset[0] = T.x_space;
offset[1] = T.y_space;
}
if (T.boxflag & 32) { /* Draw line from original point to shifted location, clipped at textbox edge */
gmt_setpen(GMT, &T.vecpen);
PSL_plotline_clipped_by_textbox(PSL, xx[0], yy[0], xx[1], yy[1], T.font.size, use_text, T.paragraph_angle, T.block_justify, offset);
}
if (!Ctrl->G.mode && T.boxflag & 3) { /* Plot the box beneath the text */
if (T.space_flag) { /* Meant % of fontsize */
offset[0] = 0.01 * T.x_space * T.font.size / PSL_POINTS_PER_INCH;
offset[1] = 0.01 * T.y_space * T.font.size / PSL_POINTS_PER_INCH;
}
else {
offset[0] = T.x_space;
offset[1] = T.y_space;
}
if (Ctrl->S.active) { /* Lay down shaded box first */
PSL_setfill (PSL, Ctrl->S.fill.rgb, 0); /* shade color */
PSL_plottextbox (PSL, plot_x + Ctrl->S.off[GMT_X], plot_y + Ctrl->S.off[GMT_Y], T.font.size, use_text, T.paragraph_angle, T.block_justify, offset, T.boxflag & 4);
Expand Down Expand Up @@ -1477,19 +1477,19 @@ EXTERN_MSC int GMT_pstext (void *V_API, int mode, void *args) {
}
PSL_setfont (PSL, T.font.id);
gmt_plane_perspective (GMT, GMT->current.proj.z_project.view_plane, in[GMT_Z]);
if (T.boxflag & 32) { /* Draw line from original point to shifted location */
if (T.space_flag) { /* Meant % of fontsize */
offset[0] = 0.01 * T.x_space * T.font.size / PSL_POINTS_PER_INCH;
offset[1] = 0.01 * T.y_space * T.font.size / PSL_POINTS_PER_INCH;
}
else {
offset[0] = T.x_space;
offset[1] = T.y_space;
}
if (T.boxflag & 32) { /* Draw line from original point to shifted location, clipped at textbox edge */
gmt_setpen (GMT, &T.vecpen);
PSL_plotsegment (PSL, xx[0], yy[0], xx[1], yy[1]);
PSL_plotline_clipped_by_textbox(PSL, xx[0], yy[0], xx[1], yy[1], T.font.size, use_text, T.paragraph_angle, T.block_justify, offset);
}
if (!Ctrl->G.mode && T.boxflag & 3) { /* Plot the box beneath the text */
if (T.space_flag) { /* Meant % of fontsize */
offset[0] = 0.01 * T.x_space * T.font.size / PSL_POINTS_PER_INCH;
offset[1] = 0.01 * T.y_space * T.font.size / PSL_POINTS_PER_INCH;
}
else {
offset[0] = T.x_space;
offset[1] = T.y_space;
}
if (Ctrl->S.active) { /* Lay down shaded box first */
PSL_setfill (PSL, Ctrl->S.fill.rgb, 0); /* shade color */
PSL_plottextbox (PSL, plot_x + Ctrl->S.off[GMT_X], plot_y + Ctrl->S.off[GMT_Y], T.font.size, use_text, T.paragraph_angle, T.block_justify, offset, T.boxflag & 4);
Expand Down
Loading