diff --git a/src/psxy.c b/src/psxy.c index 54741fa73f8..80263b65bca 100644 --- a/src/psxy.c +++ b/src/psxy.c @@ -1935,6 +1935,10 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) { SH = gmt_get_DS_hidden (L); + duplicate = (DH->alloc_mode == GMT_ALLOC_EXTERNALLY && (polygon || gmt_trim_requested (GMT, ¤t_pen) || GMT->current.map.path_mode == GMT_RESAMPLE_PATH)); + if (duplicate) /* Must duplicate externally allocated segment since it needs to be resampled below */ + L = gmt_duplicate_segment (GMT, D->table[tbl]->segment[seg]); + resampled = false; if (!polygon && gmt_trim_requested (GMT, ¤t_pen)) { /* Needs a haircut */ if (L->n_rows == 2) { /* Given endpoints we need to resample in order to trim */ @@ -1950,7 +1954,11 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) { gmt_set_seg_minmax (GMT, D->geometry, 2, L); /* Update min/max of x/y only */ resampled = true; /* To avoid doing it twice */ } - if (gmt_trim_line (GMT, &L->data[GMT_X], &L->data[GMT_Y], &L->n_rows, ¤t_pen)) continue; /* Trimmed away completely */ + if (gmt_trim_line (GMT, &L->data[GMT_X], &L->data[GMT_Y], &L->n_rows, ¤t_pen)) { + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); + continue; /* Trimmed away completely */ + } } if (D->n_tables > 1) @@ -1978,11 +1986,11 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) { change = gmt_parse_segment_header (GMT, L->header, P, &fill_active, ¤t_fill, &default_fill, &outline_active, ¤t_pen, &default_pen, default_outline, SH->ogr); outline_setting = outline_active ? 1 : 0; } - if (P && PH->skip) continue; /* Chosen CPT indicates skip for this z */ - - duplicate = (DH->alloc_mode == GMT_ALLOC_EXTERNALLY && ((polygon && gmt_polygon_is_open (GMT, L->data[GMT_X], L->data[GMT_Y], L->n_rows)) || GMT->current.map.path_mode == GMT_RESAMPLE_PATH)); - if (duplicate) /* Must duplicate externally allocated segment since it needs to be resampled below */ - L = gmt_duplicate_segment (GMT, D->table[tbl]->segment[seg]); + if (P && PH->skip) { + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); + continue; /* Chosen CPT indicates skip for this z */ + } if (L->header && L->header[0]) { PSL_comment (PSL, "Segment header: %s\n", L->header); @@ -2024,6 +2032,8 @@ EXTERN_MSC int GMT_psxy (void *V_API, int mode, void *args) { GMT_Report (API, GMT_MSG_ERROR, "Segment header did not supply enough parameters for -S~; skipping this segment\n"); else GMT_Report (API, GMT_MSG_ERROR, "Segment header did not supply enough parameters for -Sq; skipping this segment\n"); + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); continue; } if (Ctrl->I.active) { diff --git a/src/psxyz.c b/src/psxyz.c index 792cc3f588d..88e1c332c4d 100644 --- a/src/psxyz.c +++ b/src/psxyz.c @@ -1622,10 +1622,12 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { gmt_reset_meminc (GMT); } else { /* Line/polygon part */ + bool duplicate = false; int outline_setting; uint64_t seg; struct GMT_DATASET *D = NULL; /* Pointer to GMT segment table(s) */ struct GMT_DATASEGMENT_HIDDEN *SH = NULL; + struct GMT_DATASET_HIDDEN *DH = NULL; if (GMT_Init_IO (API, GMT_IS_DATASET, geometry, GMT_IN, GMT_ADD_DEFAULT, 0, options) != GMT_NOERROR) { /* Establishes data input */ Return (API->error); @@ -1637,6 +1639,7 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { GMT_Report (API, GMT_MSG_ERROR, "Input data have %d column(s) but at least 3 are needed\n", (int)D->n_columns); Return (GMT_DIM_TOO_SMALL); } + DH = gmt_get_DD_hidden (D); if (Zin) { /* Check that the Z file matches our polygon file */ if (Zin->n_records < D->n_segments) { @@ -1684,6 +1687,10 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { else GMT_Report (API, GMT_MSG_INFORMATION, "Plotting segment %" PRIu64 "\n", seg); + duplicate = (DH->alloc_mode == GMT_ALLOC_EXTERNALLY && GMT->current.map.path_mode == GMT_RESAMPLE_PATH && psxyz_no_z_variation (GMT, L)); + if (duplicate) /* Must duplicate externally allocated segment since it needs to be resampled below */ + L = gmt_duplicate_segment (GMT, D->table[tbl]->segment[seg]); + /* We had here things like: x = D->table[tbl]->segment[seg]->data[GMT_X]; * but reallocating x below lead to disasters. */ @@ -1706,7 +1713,11 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { outline_setting = outline_active ? 1 : 0; } - if (P && PH->skip) continue; /* Chosen CPT indicates skip for this z */ + if (P && PH->skip) { + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); + continue; /* Chosen CPT indicates skip for this z */ + } if (L->header && L->header[0]) { PSL_comment (PSL, "Segment header: %s\n", L->header); @@ -1732,6 +1743,8 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { GMT_Report (API, GMT_MSG_ERROR, "Segment header did not supply enough parameters for -Sf; skipping this segment\n"); else GMT_Report (API, GMT_MSG_ERROR, "Segment header did not supply enough parameters for -Sq; skipping this segment\n"); + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); continue; } @@ -1765,7 +1778,6 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { gmt_set_seg_minmax (GMT, D->geometry, 2, L); /* Update min/max of x/y only */ } - n = (int)L->n_rows; /* Number of points in this segment */ xp = gmt_M_memory (GMT, NULL, n, double); yp = gmt_M_memory (GMT, NULL, n, double); @@ -1895,6 +1907,8 @@ EXTERN_MSC int GMT_psxyz (void *V_API, int mode, void *args) { gmt_draw_front (GMT, GMT->current.plot.x, GMT->current.plot.y, GMT->current.plot.n, &S.f); if (S.f.f_pen == 0) gmt_setpen (GMT, ¤t_pen); /* Reinstate current pen */ } + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &L); gmt_M_free (GMT, xp); gmt_M_free (GMT, yp); diff --git a/src/sphdistance.c b/src/sphdistance.c index 6c7d8c7bd6a..b3d5bc162db 100644 --- a/src/sphdistance.c +++ b/src/sphdistance.c @@ -251,7 +251,7 @@ static int parse (struct GMT_CTRL *GMT, struct SPHDISTANCE_CTRL *Ctrl, struct GM #define Return(code) {Free_Ctrl (GMT, Ctrl); gmt_end_module (GMT, GMT_cpy); bailout (code);} EXTERN_MSC int GMT_sphdistance (void *V_API, int mode, void *args) { - bool first = false, periodic, duplicate_col; + bool first = false, periodic, duplicate_col, duplicate = false; int error = 0, s_row, south_row, north_row, w_col, e_col; unsigned int row, col, p_col, west_col, east_col, nx1, n_in = 0; @@ -479,15 +479,21 @@ EXTERN_MSC int GMT_sphdistance (void *V_API, int mode, void *args) { duplicate_col = (periodic && Grid->header->registration == GMT_GRID_NODE_REG); /* E.g., lon = 0 column should match lon = 360 column */ gmt_set_inside_mode (GMT, NULL, GMT_IOO_SPHERICAL); - if (Ctrl->Q.active) /* Pre-chewed, just get number of nodes */ + if (Ctrl->Q.active) { /* Pre-chewed, just get number of nodes */ + struct GMT_DATASET_HIDDEN *QH = gmt_get_DD_hidden (Qin); n = Table->n_segments; + duplicate = (QH->alloc_mode == GMT_ALLOC_EXTERNALLY); + } else V = &T.V; for (node = 0; node < n; node++) { GMT_Report (API, GMT_MSG_INFORMATION, "Processing polygon %7ld\r", node); if (Ctrl->Q.active) { /* Just point to next polygon */ - P = Table->segment[node]; + if (duplicate) /* Must duplicate externally allocated segment since it needs to be resampled below */ + P = gmt_duplicate_segment (GMT, Table->segment[node]); + else + P = Table->segment[node]; } else { /* Obtain current polygon from Voronoi listings */ if (P == NULL) { /* Need a single polygon structure that we reuse for each polygon */ @@ -529,7 +535,6 @@ EXTERN_MSC int GMT_sphdistance (void *V_API, int mode, void *args) { case SPHD_VALUES: f_val = z_val[node]; break; default: break; /* Must compute distances below */ } - } /* Here we have the polygon in P */ @@ -576,6 +581,8 @@ EXTERN_MSC int GMT_sphdistance (void *V_API, int mode, void *args) { } } } + if (duplicate) /* Free duplicate segment */ + gmt_free_segment (GMT, &P); } GMT_Report (API, GMT_MSG_INFORMATION, "Processing polygon %7ld\n", node); diff --git a/src/testapi_vector_plot.c b/src/testapi_vector_plot.c new file mode 100644 index 00000000000..10e2e410190 --- /dev/null +++ b/src/testapi_vector_plot.c @@ -0,0 +1,29 @@ +#include "gmt.h" +int main () { + void *API = NULL; /* The API control structure */ + struct GMT_VECTOR *V = NULL; /* Structure to hold input dataset as vectors */ + char input[GMT_VF_LEN] = {""}; /* String to hold virtual input filename */ + char args[128] = {""}; /* String to hold module command arguments */ + + uint64_t dim[4] = {2, 2, 1, 0}; + double x[2] = {5.0, 5.0}; + double y[2] = {3.0, 8.0}; + + /* Initialize the GMT session */ + API = GMT_Create_Session ("test", 2U, GMT_SESSION_EXTERNAL, NULL); + /* Create a dataset */ + if ((V = GMT_Create_Data (API, GMT_IS_DATASET|GMT_VIA_VECTOR, GMT_IS_POINT, GMT_CONTAINER_ONLY, dim, NULL, NULL, 0, 0, NULL)) == NULL) return (EXIT_FAILURE); + /**/ + GMT_Put_Vector(API, V, 0, GMT_DOUBLE, x); + GMT_Put_Vector(API, V, 1, GMT_DOUBLE, y); + /* Associate our data table with a virtual file */ + //GMT_Open_VirtualFile (API, GMT_IS_DATASET|GMT_VIA_VECTOR, GMT_IS_POINT, GMT_IN|GMT_IS_REFERENCE, V, input); + GMT_Open_VirtualFile (API, GMT_IS_DATASET|GMT_VIA_VECTOR, GMT_IS_POINT, GMT_IN|GMT_IS_REFERENCE, V, input); + /* Prepare the module arguments */ + sprintf (args, "%s -JX10c -R0/10/0/10 -Baf -W1p,black+ve0.2c -P", input); + /* Call the psxy module */ + GMT_Call_Module (API, "psxy", GMT_MODULE_CMD, args); + GMT_Close_VirtualFile (API, input); + /* Destroy the GMT session */ + if (GMT_Destroy_Session (API)) return EXIT_FAILURE; +}; diff --git a/test/api/apivectorplot.ps b/test/api/apivectorplot.ps new file mode 100644 index 00000000000..821a969e943 Binary files /dev/null and b/test/api/apivectorplot.ps differ diff --git a/test/api/apivectorplot.sh b/test/api/apivectorplot.sh new file mode 100755 index 00000000000..7a65aae8683 --- /dev/null +++ b/test/api/apivectorplot.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# +# Test the C API for plotting lines with arrows +# See https://github.com/GenericMappingTools/gmt/pull/3528 +ps=apivectorplot.ps +testapi_vector_plot > $ps diff --git a/test/gmtest.in b/test/gmtest.in index fe6098b3bde..37ea817d618 100755 --- a/test/gmtest.in +++ b/test/gmtest.in @@ -85,7 +85,8 @@ for apiprog in \ testgrdio \ testapi_imageshading \ testapi_matrix_as_grid \ - testapi_vector_strings + testapi_vector_strings \ + testapi_vector_plot do eval "${apiprog}() { valgrind_wrapper \"@GMT_BINARY_DIR@/src/${apiprog}\" \"\$@\"; }" done