| 6167 | } |
| 6168 | |
| 6169 | void gmt_plot_line (struct GMT_CTRL *GMT, double *x, double *y, unsigned int *pen, uint64_t n, unsigned int mode) { |
| 6170 | /* Mode = PSL_LINEAR [0] or PSL_BEZIER [1] */ |
| 6171 | /* Drawing lines of finite thickness that cross map boundaries is tricky because the exit or entry point |
| 6172 | * refers to the center line of a finite thickness line but the wider part of the line do not share those |
| 6173 | * coordinates. To avoid ugly line gaps we must extend such lines a bit beyond the border and clip so that |
| 6174 | * things look pretty. For now we only do this for a few situations: |
| 6175 | * 1) The map border must be rectangular |
| 6176 | * 2) The line must be a linear spline and not the Bezier spline |
| 6177 | * Hopefully we can work to avoid the first case soon */ |
| 6178 | |
| 6179 | uint64_t i, j, im1, ip1, k; |
| 6180 | int way; |
| 6181 | bool close, stop; |
| 6182 | double x_cross[2], y_cross[2]; |
| 6183 | double x_ext, y_ext; /* Coordinates of the external helper point */ |
| 6184 | unsigned int start_pen = PSL_MOVE, end_pen = PSL_STROKE; /* Default pen code of given line endings */ |
| 6185 | struct PSL_CTRL *PSL= GMT->PSL; |
| 6186 | |
| 6187 | if (n < 2) return; |
| 6188 | |
| 6189 | gmtplot_NaN_pen_up (x, y, pen, n); /* Ensure we don't have NaNs in the coordinates */ |
| 6190 | |
| 6191 | /* First skip any repeating PSL_MOVE in the beginning since only the last one will matter */ |
| 6192 | i = 0; |
| 6193 | while (i < (n-1) && (pen[i+1] & PSL_MOVE)) i++; /* Skip repeating pen & PSL_MOVE in beginning */ |
| 6194 | if ((n-i) < 2) return; /* Less than 2 points is not a line */ |
| 6195 | j = i; /* j is now the first valid point with a PSL_MOVE */ |
| 6196 | /* Then we want to prevent duplicate points since the first point may have a different pen (e.g., include PSL_CLIP) */ |
| 6197 | while (i < (n-1) && gmtplot_these_are_duplicates (x[j], y[j], x[i+1], y[i+1])) i++; /* Skip duplicate points in beginning */ |
| 6198 | if ((n-i) < 2) return; /* Less than 2 points is not a line */ |
| 6199 | if (i > j) pen[i] = pen[j]; /* Skipped initial duplicates but must maintain the initial pen code */ |
| 6200 | /* Likewise, skip any repeating PSL_MOVE at the end */ |
| 6201 | while (n > 1 && (pen[n-1] & PSL_MOVE)) n--; /* Cut off repeating pen & PSL_MOVE at end */ |
| 6202 | if ((n-i) < 2) return; /* Less than 2 points is not a line */ |
| 6203 | /* Then we want to prevent duplicate points at end since the last valid point may have a different pen (e.g., include PSL_CLIP) */ |
| 6204 | j = n - 1; /* j is now last point after initial skip test */ |
| 6205 | while (n > 1 && gmtplot_these_are_duplicates (x[j], y[j], x[n-2], y[n-2])) n--; /* Skip duplicate points at end */ |
| 6206 | if ((n-i) < 2) return; /* Less than 2 points is not a line */ |
| 6207 | if (n <= j) { /* Got a duplicate at the end */ |
| 6208 | if ((pen[n-1] & PSL_CLIP) == 0) pen[n-1] = pen[j]; /* Skipped trailing duplicates but must maintain initial pen code of last valid point unless has clip information */ |
| 6209 | while (n > 1 && (pen[n-1] & PSL_MOVE)) n--; /* Cut off repeating pen & PSL_MOVE at end that might result after removing that duplicate */ |
| 6210 | } |
| 6211 | for (j = i + 1; j < n && !(pen[j] & PSL_MOVE); j++); /* j == n means no PSL_MOVEs present */ |
| 6212 | close = (j == n) ? (hypot (x[n-1] - x[i], y[n-1] - y[i]) < GMT_CONV4_LIMIT) : false; |
| 6213 | |
| 6214 | /* First see if we can use the PSL_plotline call directly to save points */ |
| 6215 | |
| 6216 | for (j = i + 1, stop = false; !stop && j < n; j++) stop = (pen[j] & PSL_MOVE || (*GMT->current.map.jump) (GMT, x[j-1], y[j-1], x[j], y[j])); |
| 6217 | if (!stop) { /* Safe to draw single line directly since no jumping around */ |
| 6218 | if (mode == PSL_BEZIER) |
| 6219 | PSL_plotcurve (PSL, &x[i], &y[i], (int)(n - i), PSL_MOVE + PSL_STROKE + close * PSL_CLOSE); |
| 6220 | else { /* Pay more attention here since exiting lines of finite thickness may need some corrections */ |
| 6221 | //bool rect = gmt_M_is_rect_graticule (GMT) || GMT->common.R.oblique; /* We have a rectangular map boundary */ |
| 6222 | bool rect = !(gmt_M_is_azimuthal (GMT) && !GMT->current.proj.polar); |
| 6223 | for (j = i + 1, stop = false; !stop && j < n; j++) stop = (pen[j] & PSL_CLIP); /* Look for clipped end points */ |
| 6224 | if (!rect || !stop) /* No troubled clip points or it is not a rectangular border */ |
| 6225 | //if (!stop) /* No troubled clip points or it is not a rectangular border */ |
| 6226 | PSL_plotline (PSL, &x[i], &y[i], (int)(n - i), PSL_MOVE + PSL_STROKE + close * PSL_CLOSE); |
no test coverage detected