Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let grdimage share -T with grdview #7315

Merged
merged 4 commits into from
Mar 9, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 14 additions & 2 deletions doc/rst/source/grdimage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Synopsis
[ |-N| ]
[ |-Q|\ [*color*][**+z**\ *value*] ]
[ |SYN_OPT-Rz| ]
[ |-T|\ [**+o**\ [*pen*]][**+s**] ]
[ |SYN_OPT-U| ]
[ |SYN_OPT-V| ]
[ |SYN_OPT-X| ]
Expand Down Expand Up @@ -184,6 +185,17 @@ Optional Arguments
subset of the grid [Default is the region given by the grid file].
.. include:: explain_-Rz.rst_

.. _-t:

**-T**\ [**+o**\ [*pen*]][**+s**]
Plot a data grid without any interpolation. This involves converting each
node-centered bin into a polygon which is then painted separately.
Append **+s** to skip nodes with z = NaN. This option is suitable for
categorical data where interpolating between values is meaningless
and a categorical CPT has been provided via |-C|.
Optionally, append **+o** to draw the tile outlines, and specify a
custom pen if the default pen is not to your liking.

.. |Add_-U| replace:: |Add_-U_links|
.. include:: explain_-U.rst_
:start-after: **Syntax**
Expand Down Expand Up @@ -226,7 +238,7 @@ place with most map projections. Because **grdimage** uses the
PostScript colorimage operator, for most non-linear projections we
must resample your grid onto an equidistant rectangular lattice. If you
find that the NaN areas are not treated adequately, consider (a) use a
linear projection, or (b) use :doc:`grdview` **-Ts** instead.
linear projection, or (b) use **-T+s** instead to plot graticule polygons.

.. include:: explain_grdresample.rst_

Expand All @@ -240,7 +252,7 @@ requires a resampling onto an equidistant Cartesian lattice that usually
will result in such blending. We do not know if a grid is categorical but
if the CPT provided via |-C| is categorical we will override any **-n** setting you
have chosen (perhaps implicitly) with **-nn+a** that turns *on* nearest neighbor
gridding and turns *off* anti-aliasing. Alternatively, use :doc:`grdview` |-T|
gridding and turns *off* anti-aliasing. Alternatively, use |-T|
instead to plot individual polygons centered on each node.

Image formats recognized
Expand Down
43 changes: 43 additions & 0 deletions src/gmt_plot.c
Original file line number Diff line number Diff line change
Expand Up @@ -10794,3 +10794,46 @@ struct GMT_POSTSCRIPT * gmt_get_postscript (struct GMT_CTRL *GMT) {
P->hidden = gmt_M_memory (GMT, NULL, 1, struct GMT_POSTSCRIPT_HIDDEN);
return (P);
}

void gmt_plot_image_graticules (struct GMT_CTRL *GMT, struct GMT_GRID *G, struct GMT_GRID *I, struct GMT_PALETTE *P, struct GMT_PEN *pen, bool skip, double *intensity) {
/* Lay down an image using polygons of the graticules. This is recoded from grdview
* so it can also be used in grdimage.
* G is the data grid
* I is an optional intensity grid. If NULL then either intensity points to a
* constant intensity or it is also NULL, meaning no intensity adjustment for colors.
* P is the CPT in use
* pen is an optional pen for drawing the graticules, or NULL
* skip determines if we paint NaN polygons or not
* intensity is pointer to a constant intensity or NULL
*/
openmp_int row, col;
uint64_t ij, n;
double *xx = NULL, *yy = NULL, inc2[2] = {0.0, 0.0};
struct GMT_FILL fill;
struct GMT_DATASEGMENT *S = gmt_get_segment (GMT, 2);
gmt_init_fill (GMT, &fill, -1.0, -1.0, -1.0); /* Initialize fill structure */

GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Tiling grid without interpolation\n");

inc2[GMT_X] = 0.5 * G->header->inc[GMT_X]; inc2[GMT_Y] = 0.5 * G->header->inc[GMT_Y];
if (pen) gmt_setpen (GMT, pen);
S->data = gmt_M_memory (GMT, NULL, 2, double *);
S->n_columns = 2;
gmt_M_grd_loop (GMT, G, row, col, ij) { /* Compute rgb for each pixel */
if (gmt_M_is_fnan (G->data[ij]) && skip) continue;
if (I && skip && gmt_M_is_fnan (I->data[ij])) continue;
gmt_get_fill_from_z (GMT, P, G->data[ij], &fill);
if (I)
gmt_illuminate (GMT, I->data[ij], fill.rgb);
else if (intensity)
gmt_illuminate (GMT, *intensity, fill.rgb);
n = gmt_graticule_path (GMT, &xx, &yy, 1, true, G->x[col] - inc2[GMT_X], G->x[col] + inc2[GMT_X], G->y[row] - inc2[GMT_Y], G->y[row] + inc2[GMT_Y]);
gmt_setfill (GMT, &fill, pen != NULL);
S->data[GMT_X] = xx; S->data[GMT_Y] = yy; S->n_rows = n;
gmt_geo_polygons (GMT, S);
gmt_M_free (GMT, xx);
gmt_M_free (GMT, yy);
}
S->data[GMT_X] = S->data[GMT_Y] = NULL; /* Since xx and yy was set to NULL but not data... */
gmt_free_segment (GMT, &S);
}
1 change: 1 addition & 0 deletions src/gmt_prototypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ EXTERN_MSC struct GMT_GRID * gmt_duplicate_grid (struct GMT_CTRL *GMT, struct GM
#ifdef _POSTSCRIPTLIGHT_H
/* gmt_plot.c prototypes only included if postscriptlight has been included */

EXTERN_MSC void gmt_plot_image_graticules (struct GMT_CTRL *GMT, struct GMT_GRID *G, struct GMT_GRID *I, struct GMT_PALETTE *P, struct GMT_PEN *pen, bool skip, double *intensity);
EXTERN_MSC double gmt_inch_to_degree_scale (struct GMT_CTRL *GMT, double lon0, double lat0, double azimuth);
EXTERN_MSC bool gmt_text_is_latex (struct GMT_CTRL *GMT, const char *string);
EXTERN_MSC void gmt_map_text (struct GMT_CTRL *GMT, double x, double y, struct GMT_FONT *font, char *label, double angle, int just, unsigned int form);
Expand Down
34 changes: 33 additions & 1 deletion src/grdimage.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ struct GRDIMAGE_CTRL {
double rgb[4]; /* Pixel value for transparency in images */
double value; /* If +z is used this z-value will give us the r/g/b via CPT */
} Q;
struct GRDIMAGE_T { /* -T[s][o[<pen>]] */
bool active;
bool skip;
bool outline;
struct GMT_PEN pen;
} T;
struct GRDIMAGE_W { /* -W */
bool active;
} W;
Expand Down Expand Up @@ -154,7 +160,7 @@ static int usage (struct GMTAPI_CTRL *API, int level) {
if (level == GMT_MODULE_PURPOSE) return (GMT_NOERROR);
GMT_Usage (API, 0, "usage: %s %s %s%s [%s] [-C<cpt>] [-D[r]] [-Ei|<dpi>] "
"[-G<rgb>[+b|f]] [-I[<intensgrid>|<value>|<modifiers>]] %s[-M] [-N] %s%s[-Q[<color>][+z<value>]] "
"[%s] [%s] [%s] [%s] [%s] %s[%s] [%s] [%s] [%s]%s[%s]\n",
"[%s] [-T[+o[<pen>]][+s]] [%s] [%s] [%s] [%s] %s[%s] [%s] [%s] [%s]%s[%s]\n",
name, GMT_INGRID, GMT_J_OPT, extra[API->external], GMT_B_OPT, API->K_OPT, API->O_OPT, API->P_OPT, GMT_Rgeo_OPT, GMT_U_OPT,
GMT_V_OPT, GMT_X_OPT, GMT_Y_OPT, API->c_OPT, GMT_f_OPT, GMT_n_OPT, GMT_p_OPT, GMT_t_OPT, GMT_x_OPT, GMT_PAR_OPT);

Expand Down Expand Up @@ -217,6 +223,9 @@ static int usage (struct GMTAPI_CTRL *API, int level) {
"Append an alternate <color> to change the transparent pixel for images [black], or alternatively");
GMT_Usage (API, 3, "+z Specify <value> to set transparent pixel color via CPT lookup.");
GMT_Option (API, "R");
gmt_pen_syntax (API->GMT, 'T', NULL, "Image the data without interpolation by painting polygonal tiles in the form [+o[<pen>]][+s].", NULL, 0);
GMT_Usage (API, 3, "+s Skip tiles for nodes with z = NaN [Default paints all tiles].");
GMT_Usage (API, 3, "+o to draw tile outline; optionally append <pen> [Default uses no outline].");
GMT_Option (API, "U,V,X,c,f,n,p,t,x,.");

return (GMT_MODULE_USAGE);
Expand Down Expand Up @@ -425,6 +434,21 @@ static int parse (struct GMT_CTRL *GMT, struct GRDIMAGE_CTRL *Ctrl, struct GMT_O
}
if (c) c[0] = '+'; /* Restore the modifier */
break;
case 'T': /* Tile plot -T[+s][+o<pen>] */
n_errors += gmt_M_repeated_module_option (API, Ctrl->T.active);
if (opt->arg[0]) { /* Also got arguments */
if (strstr (opt->arg, "+s"))
Ctrl->T.skip = true;
if ((c = strstr (opt->arg, "+o"))) {
if (gmt_getpen (GMT, &c[2], &Ctrl->T.pen)) {
gmt_pen_syntax (GMT, 'T', NULL, " ", NULL, 0);
n_errors++;
}
else
Ctrl->T.outline = true;
}
}
break;
case 'W': /* Warn if no image, usually when called from grd2kml */
n_errors += gmt_M_repeated_module_option (API, Ctrl->W.active);
n_errors += gmt_get_no_argument (GMT, opt->arg, opt->option, 0);
Expand Down Expand Up @@ -1625,6 +1649,12 @@ EXTERN_MSC int GMT_grdimage (void *V_API, int mode, void *args) {
}
}

if (Ctrl->T.active) { /* Plot colored graticules instead */
need_to_project = false; /* Since we are not doing reprojection of the grid */
gmt_plot_image_graticules (GMT, Grid_orig, Intens_orig, P, (Ctrl->T.outline) ? &Ctrl->T.pen : NULL, Ctrl->T.skip, Ctrl->I.constant ? &Ctrl->I.value : NULL);
goto basemap_and_free; /* Skip all the image projection and just overlay basemap and free memory */
}

if (need_to_project) { /* Need to resample the grid or image [and intensity grid] using the specified map projection */
int nx_proj = 0, ny_proj = 0;
double inc[2] = {0.0, 0.0};
Expand Down Expand Up @@ -1989,6 +2019,8 @@ EXTERN_MSC int GMT_grdimage (void *V_API, int mode, void *args) {
}
}

basemap_and_free:

if (!Ctrl->A.active) { /* Finalize PostScript plot, possibly including basemap */
if (!Ctrl->N.active) gmt_map_clip_off (GMT);

Expand Down
32 changes: 2 additions & 30 deletions src/grdview.c
Original file line number Diff line number Diff line change
Expand Up @@ -1299,36 +1299,8 @@ EXTERN_MSC int GMT_grdview (void *V_API, int mode, void *args) {
}
}

if (Ctrl->T.active) { /* Plot image as polygonal pieces. Here, -JZ is not set */
double *xx = NULL, *yy = NULL;
struct GMT_FILL fill;
struct GMT_DATASEGMENT *S = gmt_get_segment (GMT, 2);
gmt_init_fill (GMT, &fill, -1.0, -1.0, -1.0); /* Initialize fill structure */

GMT_Report (API, GMT_MSG_INFORMATION, "Tiling without interpolation\n");

if (Ctrl->T.outline) gmt_setpen (GMT, &Ctrl->T.pen);
S->data = gmt_M_memory (GMT, NULL, 2, double *);
S->n_columns = 2;
gmt_M_grd_loop (GMT, Z, row, col, ij) { /* Compute rgb for each pixel */
if (gmt_M_is_fnan (Topo->data[ij]) && Ctrl->T.skip) continue;
if (use_intensity_grid && Ctrl->T.skip && gmt_M_is_fnan (Intens->data[ij])) continue;
gmt_get_fill_from_z (GMT, P, Topo->data[ij], &fill);
if (use_intensity_grid)
gmt_illuminate (GMT, Intens->data[ij], fill.rgb);
else
gmt_illuminate (GMT, Ctrl->I.value, fill.rgb);
n = gmt_graticule_path (GMT, &xx, &yy, 1, true, xval[col] - inc2[GMT_X], xval[col] + inc2[GMT_X], yval[row] - inc2[GMT_Y], yval[row] + inc2[GMT_Y]);
gmt_setfill (GMT, &fill, Ctrl->T.outline);
S->data[GMT_X] = xx; S->data[GMT_Y] = yy; S->n_rows = n;
gmt_geo_polygons (GMT, S);
gmt_M_free (GMT, xx);
gmt_M_free (GMT, yy);
}
S->data[GMT_X] = S->data[GMT_Y] = NULL; /* Since xx and yy was set to NULL but not data... */
gmt_free_segment (GMT, &S);
}

if (Ctrl->T.active) /* Plot colored graticules instead */
gmt_plot_image_graticules (GMT, Topo, Intens, P, (Ctrl->T.outline) ? &Ctrl->T.pen : NULL, Ctrl->T.skip, Ctrl->I.constant ? &Ctrl->I.value : NULL);
else if (Ctrl->Q.mode == GRDVIEW_IMAGE) { /* Plot image */
int nx_i, ny_i, ip, jp, min_i, max_i, min_j, max_j, dist;
int done, layers, last_i, last_j;
Expand Down