diff --git a/src/gmt_api.c b/src/gmt_api.c index 99a2a739253..8b317b3e391 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -1332,7 +1332,7 @@ GMT_LOCAL double gmtapi_get_record_value (struct GMT_CTRL *GMT, double *record, double val; unsigned int col_pos; col_pos = gmtapi_pick_in_col_number (GMT, (unsigned int)col); - val = (col_pos >= n_colums) ? GMT->session.d_NaN : record[col_pos]; /* If we request a column beyond length of array, return NaN */ + val = (col_pos >= n_colums) ? GMT->session.d_NaN : gmt_M_convert_col (GMT->current.io.col[GMT_IN][col_pos], record[col_pos]); /* If we request a column beyond length of array, return NaN */ if (GMT->common.d.active[GMT_IN] && gmt_M_is_dnan (val)) val = GMT->common.d.nan_proxy[GMT_IN]; /* Write this value instead of NaNs */ if (gmt_M_is_type (GMT, GMT_IN, col_pos, GMT_IS_LON)) gmt_lon_range_adjust (GMT->current.io.geo.range, &val); /* Set longitude range */ return (val); @@ -3488,6 +3488,14 @@ GMT_LOCAL void gmtapi_switch_cols (struct GMT_CTRL *GMT, struct GMT_DATASET *D, } } +GMT_LOCAL bool gmtapi_vector_data_must_be_duplicated (struct GMTAPI_CTRL *API, struct GMT_VECTOR *V) { + /* Check if referenced vector data arrays must be scaled/offset and hence must be duplicated instead */ + for (unsigned int col = 0; col < V->n_columns; col++) { + if (API->GMT->common.i.select && API->GMT->current.io.col[GMT_IN][col].convert) return (true); /* Cannot pass as read-only if it must be converted */ + } + return false; /* Seems OK */ +} + /*! . */ GMT_LOCAL struct GMT_DATASET * gmtapi_import_dataset (struct GMTAPI_CTRL *API, int object_ID, unsigned int mode) { /* Does the actual work of loading in the entire virtual data set (possibly via many sources) @@ -3562,6 +3570,12 @@ GMT_LOCAL struct GMT_DATASET * gmtapi_import_dataset (struct GMTAPI_CTRL *API, i via = false; geometry = (GMT->common.a.output) ? GMT->common.a.geometry : S_obj->geometry; /* When reading GMT and writing OGR/GMT we must make sure we set this first */ method = gmtapi_set_method (S_obj); /* Get the actual method to use */ + /* At the time an external vector was created via GMT_Open_VirtualFile there is not yet any knowledge if this data + * will be passed to a module with options -i that could require scaling, offseting, or taking the log of the data. + * If that is the case then we cannot pass via reference but must switch method to duplicate. */ + if (method == (GMT_IS_REFERENCE|GMT_VIA_VECTOR) && gmtapi_vector_data_must_be_duplicated (API, S_obj->resource)) + method = GMT_IS_DUPLICATE|GMT_VIA_VECTOR; /* We need to adjust at least one vector due to -i+s+o+l so must duplicate input rather than reference */ + switch (method) { /* File, array, stream, reference, etc ? */ case GMT_IS_FILE: /* Import all the segments, then count total number of records */ #ifdef SET_IO_MODE @@ -8639,7 +8653,7 @@ GMT_LOCAL bool gmtapi_matrix_data_conforms_to_dataset (struct GMT_MATRIX *M) { return (M->type == GMT_DOUBLE); /* Having double means we can use as is */ } -GMT_LOCAL bool gmtapi_vector_data_conforms_to_dataset (struct GMT_VECTOR *V, enum GMT_enum_type type) { +GMT_LOCAL bool gmtapi_vector_data_conforms_to_dataset (struct GMTAPI_CTRL *API, struct GMT_VECTOR *V, enum GMT_enum_type type) { /* Check if the vector data arrays matches the form of a GMT dataset (columns of doubles) */ if (type != GMT_DOUBLE) { /* Only doubles can be passed or memcpy directly */ if (V->n_columns == 0) return (false); /* Having nothing yet means we must duplicate */ @@ -8685,7 +8699,7 @@ GMT_LOCAL void gmtapi_maybe_change_method_to_duplicate (struct GMTAPI_CTRL *API, S_obj->method = GMT_IS_DUPLICATE; /* Must duplicate this resource */ GMT_Report (API, GMT_MSG_INFORMATION, "GMT_Open_VirtualFile: Switch method to GMT_IS_DUPLICATE as vectors are not compatible with a GMT grid\n"); } - else if (S_obj->actual_family == GMT_IS_VECTOR && S_obj->family == GMT_IS_DATASET && !gmtapi_vector_data_conforms_to_dataset (S_obj->resource, S_obj->type)) { + else if (S_obj->actual_family == GMT_IS_VECTOR && S_obj->family == GMT_IS_DATASET && !gmtapi_vector_data_conforms_to_dataset (API, S_obj->resource, S_obj->type)) { S_obj->method = GMT_IS_DUPLICATE; /* Must duplicate this resource */ GMT_Report (API, GMT_MSG_INFORMATION, "GMT_Open_VirtualFile: Switch method to GMT_IS_DUPLICATE as input vectors are not compatible with a GMT dataset\n"); } @@ -9637,11 +9651,13 @@ struct GMT_RECORD *api_get_record_vector (struct GMTAPI_CTRL *API, unsigned int while (col < API->current_get_n_columns) { col_pos = gmtapi_pick_in_col_number (GMT, (unsigned int)col); API->current_get_V_val[col_pos] (&(V->data[col_pos]), S->rec, &(GMT->current.io.curr_rec[col])); - col++; + GMT->current.io.curr_rec[col] = gmt_M_convert_col (GMT->current.io.col[GMT_IN][col_pos], GMT->current.io.curr_rec[col]); + col++; while (GMT->common.i.select && col < GMT->common.i.n_cols && GMT->current.io.col[GMT_IN][col].col == GMT->current.io.col[GMT_IN][col-1].col) { /* This input column is requested more than once */ col_pos = GMT->current.io.col[GMT_IN][col].order; /* The data column that will receive this value */ - API->current_get_V_val[col_pos] (&(V->data[col_pos]), S->rec, &(GMT->current.io.curr_rec[col])); + API->current_get_V_val[col_pos] (&(V->data[col_pos]), S->rec, &(GMT->current.io.curr_rec[col])); + GMT->current.io.curr_rec[col] = gmt_M_convert_col (GMT->current.io.col[GMT_IN][col_pos], GMT->current.io.curr_rec[col]); col++; } } diff --git a/src/gmt_macros.h b/src/gmt_macros.h index e98bca7aa4b..b3ca3e0d6eb 100644 --- a/src/gmt_macros.h +++ b/src/gmt_macros.h @@ -59,6 +59,9 @@ #define gmt_nc_put_varm_grdfloat nc_put_varm_float #endif +/*! Macro to apply columns log/scale/offset conversion on the fly */ +#define gmt_M_convert_col(S,x) ((S.convert) ? ((S.convert & 2) ? log10 (x) : x) * S.scale + S.offset : x) + /* This macro is called via each modules "Return" macro so API and options are available */ #define gmt_M_free_options(mode) {if (GMT_Destroy_Options (API, &options) != GMT_OK) return (GMT_MEMORY_ERROR);}