1 /*--------------------------------------------------------------------
2  *
3  * Copyright (c) 1991-2021 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
4  * See LICENSE.TXT file for copying and redistribution conditions.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; version 3 or any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * Contact info: www.generic-mapping-tools.org
16  *--------------------------------------------------------------------*/
17 /*
18  *
19  * G M T _ G R D I O . C   R O U T I N E S
20  *
21  * Generic routines that take care of all low-level gridfile input/output.
22  *
23  * Author:  Paul Wessel
24  * Date:    1-JAN-2010
25  * Version: 5
26  * 64-bit Compliant: Yes
27  *
28  * NOTE: We do not support grids that have more rows or columns that can fit
29  * in a 32-bit integer, hence all linear dimensions (row, col, etc.) are addressed
30  * with 32-bit ints.  However, 1-D array indices (e.g., ij = row*n_columns + col) are
31  * addressed with 64-bit integers.
32  *
33  * Public functions (42 [+2]):
34  *
35  *  gmt_grd_get_format      : Get format id, scale, offset and missing value for grdfile
36  *  gmtlib_read_grd_info       : Read header from file
37  *  gmtlib_read_grd            : Read data set from file (must be preceded by gmtlib_read_grd_info)
38  *  gmt_update_grd_info     : Update header in existing file (must be preceded by gmtlib_read_grd_info)
39  *  gmtlib_write_grd_info      : Write header to new file
40  *  gmtlib_write_grd           : Write header and data set to new file
41  *  gmt_set_R_from_grd
42  *  gmt_grd_coord           :
43  *  gmtlib_grd_real_interleave :
44  *  gmt_grd_mux_demux       :
45  *  gmtlib_grd_set_units       :
46  *  gmt_grd_pad_status      :
47  *  gmt_grd_info_syntax
48  *  gmtlib_get_grdtype         :
49  *  gmtlib_grd_data_size       :
50  *  gmt_grd_set_ij_inc      :
51  *  gmt_grd_format_decoder  :
52  *  gmt_grd_prep_io         :
53  *  gmt_set_grdinc          :
54  *  gmt_set_grddim          :
55  *  gmt_grd_pad_off         :
56  *  gmt_grd_pad_on          :
57  *  gmt_grd_pad_zero        :
58  *  gmt_create_grid         :
59  *  gmt_duplicate_grid      :
60  *  gmt_free_grid           :
61  *  gmt_set_outgrid         :
62  *  gmt_change_grdreg       :
63  *  gmt_grd_zminmax         :
64  *  gmt_grd_minmax          :
65  *  gmt_grd_detrend         :
66  *  gmtlib_init_complex        :
67  *  gmtlib_found_url_for_gdal      :
68  *  gmt_read_img            : Read [subset from] a Sandwell/Smith *.img file
69  *  gmt_grd_init            : Initialize grd header structure
70  *  gmt_grd_shift           : Rotates grdfiles in x-direction
71  *  gmt_grd_setregion       : Determines subset coordinates for grdfiles
72  *  gmt_grd_is_global       : Determine whether grid is "global", i.e. longitudes are periodic
73  *  gmt_adjust_loose_wesn   : Ensures region, increments, and n_columns/n_rows are compatible
74  *  gmt_decode_grd_h_info   : Decodes a -Dstring into header text components
75  *  gmt_grd_RI_verify       : Test to see if region and incs are compatible
76  *  gmt_scale_and_offset_f  : Routine that scales and offsets the data in a vector
77  *  gmt_grd_flip_vertical  : Flips the grid in vertical direction
78  *  gmtgrdio_pack_grid         : Packs or unpacks a grid by calling gmt_scale_and_offset_f()
79  *
80  *  Reading images via GDAL (if enabled):
81  *  gmtlib_read_image          : Read [subset of] an image via GDAL
82  *  gmtlib_read_image_info     : Get information for an image via GDAL
83  *
84  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
85 
86 #include "gmt_dev.h"
87 #include "gmt_internals.h"
88 #include "gmt_common_byteswap.h"
89 
90 struct GRD_PAD {	/* Local structure */
91 	double wesn[4];
92 	unsigned int pad[4];
93 };
94 
95 /* Local functions */
96 
97 /*! gmt_M_grd_get_size computes grid size including the padding, and doubles it if complex values */
gmtgrdio_grd_get_size(struct GMT_GRID_HEADER * h)98 GMT_LOCAL size_t gmtgrdio_grd_get_size (struct GMT_GRID_HEADER *h) {
99 	return ((((h->complex_mode & GMT_GRID_IS_COMPLEX_MASK) > 0) + 1ULL) * h->mx * h->my);
100 }
101 
gmtgrdio_grd_layout(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,unsigned int complex_mode,unsigned int direction)102 GMT_LOCAL int gmtgrdio_grd_layout (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, unsigned int complex_mode, unsigned int direction) {
103 	/* Checks or sets the array arrangement for a complex array */
104 	size_t needed_size;	/* Space required to hold both components of a complex grid */
105 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
106 	if ((complex_mode & GMT_GRID_IS_COMPLEX_MASK) == 0) return GMT_OK;	/* Regular, non-complex grid, nothing special to do */
107 
108 	needed_size = 2ULL * ((size_t)header->mx) * ((size_t)header->my);	/* For the complex array */
109 	if (header->size < needed_size) {
110 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Complex grid not large enough to hold both components!.\n");
111 		return GMT_DIM_TOO_SMALL;
112 	}
113 	if (direction == GMT_IN) {	/* About to read in a complex component; another one might have been read in earlier */
114 		if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
115 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Demultiplexing complex grid before reading can take place.\n");
116 			gmt_grd_mux_demux (GMT, header, grid, GMT_GRID_IS_SERIAL);
117 		}
118 		if ((header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) == GMT_GRID_IS_COMPLEX_MASK) {	/* Already have both component; this will overwrite one of them */
119 			unsigned int type = (complex_mode & GMT_GRID_IS_COMPLEX_REAL) ? 0 : 1;
120 			char *kind[2] = {"read", "imaginary"};
121 			GMT_Report (GMT->parent, GMT_MSG_WARNING, "Overwriting previously stored %s component in complex grid.\n", kind[type]);
122 		}
123 		header->complex_mode |= complex_mode;	/* Update the grids complex mode */
124 	}
125 	else {	/* About to write out a complex component */
126 		if ((header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) == 0) {	/* Not a complex grid */
127 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Asking to write out complex components from a non-complex grid.\n");
128 			return GMT_WRONG_MATRIX_SHAPE;
129 		}
130 		if ((header->complex_mode & GMT_GRID_IS_COMPLEX_REAL) && (header->complex_mode & GMT_GRID_IS_COMPLEX_REAL) == 0) {
131 			/* Programming error: Requesting to write real components when there are none */
132 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Complex grid has no real components that can be written to file.\n");
133 			return GMT_WRONG_MATRIX_SHAPE;
134 		}
135 		else if ((header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG) && (header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG) == 0) {
136 			/* Programming error: Requesting to write imag components when there are none */
137 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Complex grid has no imaginary components that can be written to file.\n");
138 			return GMT_WRONG_MATRIX_SHAPE;
139 		}
140 		if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {	/* Must first demultiplex the grid */
141 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Demultiplexing complex grid before writing can take place.\n");
142 			gmt_grd_mux_demux (GMT, header, grid, GMT_GRID_IS_SERIAL);
143 		}
144 	}
145 	/* header->arrangement might now have been changed accordingly */
146 	return GMT_OK;
147 }
148 
gmtgrdio_grd_parse_xy_units(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,char * file,unsigned int direction)149 GMT_LOCAL void gmtgrdio_grd_parse_xy_units (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, char *file, unsigned int direction) {
150 	/* Decode the optional +u|U<unit> and determine scales */
151 	enum gmt_enum_units u_number;
152 	unsigned int mode = 0;
153 	char *c = NULL, *name = NULL, *f = NULL;
154 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
155 
156 	if (gmt_M_is_geographic (GMT, direction)) return;	/* Does not apply to geographic data */
157 	name = (file) ? file : HH->name;
158 	if ((f = gmt_strrstr (name, ".grd")) || (f = gmt_strrstr (file, ".nc")))
159 		c = gmtlib_last_valid_file_modifier (GMT->parent, f, "Uu");
160 	else
161 		c = gmtlib_last_valid_file_modifier (GMT->parent, name, "Uu");
162 	if (c == NULL) return;	/* Did not find any modifier */
163 	mode = (c[1] == 'u') ? 0 : 1;
164 	u_number = gmtlib_get_unit_number (GMT, c[2]);		/* Convert char unit to enumeration constant for this unit */
165 	if (u_number == GMT_IS_NOUNIT) {
166 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Grid file x/y unit specification %s was unrecognized (part of file name?) and is ignored.\n", c);
167 		return;
168 	}
169 	/* Got a valid unit */
170 	HH->xy_unit_to_meter[direction] = GMT->current.proj.m_per_unit[u_number];	/* Converts unit to meters */
171 	if (mode) HH->xy_unit_to_meter[direction] = 1.0 / HH->xy_unit_to_meter[direction];	/* Wanted the inverse */
172 	HH->xy_unit[direction] = u_number;	/* Unit ID */
173 	HH->xy_adjust[direction] |= 1;		/* Says we have successfully parsed and readied the x/y scaling */
174 	HH->xy_mode[direction] = mode;
175 	c[0] = '\0';	/* Chop off the unit specification from the file name */
176 }
177 
gmtgrdio_grd_xy_scale(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,unsigned int direction)178 GMT_LOCAL void gmtgrdio_grd_xy_scale (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, unsigned int direction) {
179 	unsigned int k;
180 	/* Apply the scaling of wesn,inc as given by the header's xy_* settings.
181 	 * After reading a grid it will have wesn/inc in meters.
182 	 * Before writing a grid, it may have units changed back to original units
183 	 * or scaled to another set of units */
184 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
185 
186 	if (direction == GMT_IN) {
187 		if (HH->xy_adjust[direction] == 0) return;	/* Nothing to do */
188 		if (HH->xy_adjust[GMT_IN] & 2) return;		/* Already scaled them */
189 		for (k = 0; k < 4; k++) h->wesn[k] *= HH->xy_unit_to_meter[GMT_IN];
190 		for (k = 0; k < 2; k++) h->inc[k]  *= HH->xy_unit_to_meter[GMT_IN];
191 		HH->xy_adjust[GMT_IN] = 2;	/* Now the grid is ready for use and in meters */
192 		if (HH->xy_mode[direction])
193 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Input grid file x/y unit was converted from meters to %s after reading.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_IN]]);
194 		else
195 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Input grid file x/y unit was converted from %s to meters after reading.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_IN]]);
196 	}
197 	else if (direction == GMT_OUT) {	/* grid x/y are assumed to be in meters */
198 		if (HH->xy_adjust[GMT_OUT] & 1) {	/* Was given a new unit for output */
199 			for (k = 0; k < 4; k++) h->wesn[k] /= HH->xy_unit_to_meter[GMT_OUT];
200 			for (k = 0; k < 2; k++) h->inc[k]  /= HH->xy_unit_to_meter[GMT_OUT];
201 			HH->xy_adjust[GMT_OUT] = 2;	/* Now we are ready for writing */
202 			if (HH->xy_mode[GMT_OUT])
203 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Output grid file x/y unit was converted from %s to meters before writing.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_OUT]]);
204 			else
205 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Output grid file x/y unit was converted from meters to %s before writing.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_OUT]]);
206 		}
207 		else if (HH->xy_adjust[GMT_IN] & 2) {	/* Just undo old scaling */
208 			for (k = 0; k < 4; k++) h->wesn[k] /= HH->xy_unit_to_meter[GMT_IN];
209 			for (k = 0; k < 2; k++) h->inc[k]  /= HH->xy_unit_to_meter[GMT_IN];
210 			HH->xy_adjust[GMT_IN] -= 2;	/* Now it is back to where we started */
211 			if (HH->xy_mode[GMT_OUT])
212 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Output grid file x/y unit was reverted back to %s from meters before writing.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_IN]]);
213 			else
214 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Output grid file x/y unit was reverted back from meters to %s before writing.\n", GMT->current.proj.unit_name[HH->xy_unit[GMT_IN]]);
215 		}
216 	}
217 }
218 
219 /* Routines to see if a particular grd file format is specified as part of filename. */
220 
gmtgrdio_expand_filename(struct GMT_CTRL * GMT,const char * file,char * fname)221 GMT_LOCAL void gmtgrdio_expand_filename (struct GMT_CTRL *GMT, const char *file, char *fname) {
222 	bool found;
223 	unsigned int i;
224 	size_t f_length, length;
225 
226 	if (GMT->current.setting.io_gridfile_shorthand) {	/* Look for matches */
227 		f_length = strlen (file);
228 		for (i = 0, found = false; !found && i < GMT->session.n_shorthands; ++i) {
229 			length = strlen (GMT->session.shorthand[i].suffix);
230 			found = (length > f_length) ? false : !strncmp (&file[f_length - length], GMT->session.shorthand[i].suffix, length);
231 		}
232 		if (found) {	/* file ended in a recognized shorthand extension */
233 			--i;
234 			sprintf (fname, "%s=%s", file, GMT->session.shorthand[i].format);
235 		}
236 		else
237 			strcpy (fname, file);
238 	}
239 	else	/* Simply copy the full name */
240 		strcpy (fname, file);
241 }
242 
243 enum Grid_packing_mode {
244 	k_grd_pack = 0, /* scale and offset before writing to disk */
245 	k_grd_unpack    /* remove scale and offset after reading packed data */
246 };
247 
gmtgrdio_pack_grid(struct GMT_CTRL * Ctrl,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,unsigned pack_mode)248 GMT_LOCAL void gmtgrdio_pack_grid (struct GMT_CTRL *Ctrl, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, unsigned pack_mode) {
249 	size_t n_representations = 0; /* number of distinct values >= 0 that a signed integral type can represent */
250 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
251 
252 	if (pack_mode == k_grd_pack && (HH->z_scale_autoadjust || HH->z_offset_autoadjust)) {
253 		switch (Ctrl->session.grdformat[header->type][1]) {
254 			case 'b':
255 				n_representations = 128;         /* exp2 (8 * sizeof (int8_t)) / 2 */
256 				break;
257 			case 's':
258 				n_representations = 32768;       /* exp2 (8 * sizeof (int16_t)) / 2 */
259 				break;
260 			case 'i':
261 				/* A single precision float's significand has a precision of 24 bits.
262 				 * In order to avoid round-off errors, we must not use all 2^32
263 				 * n_representations of an int32_t. */
264 				n_representations = 0x1000000;   /* exp2 (24) */
265 				break;
266 			/* default: do not auto-scale floating point */
267 		}
268 	}
269 
270 	if (n_representations != 0) {
271 		/* Calculate auto-scale and offset */
272 		gmt_grd_zminmax (Ctrl, header, grid); /* Calculate z_min/z_max */
273 		if (HH->z_offset_autoadjust) {
274 			/* shift to center values around 0 but shift only by integral value */
275 			double z_range = header->z_max - header->z_min;
276 			if (isfinite (z_range))
277 				header->z_add_offset = rint(z_range / 2.0 + header->z_min);
278 		}
279 		if (HH->z_scale_autoadjust) {
280 			/* scale z-range to use all n_representations */
281 			double z_max = header->z_max - header->z_add_offset;
282 			double z_min = fabs(header->z_min - header->z_add_offset);
283 			double z_0_n_range = MAX (z_max, z_min); /* use [0,n] range because of signed int */
284 			--n_representations;                     /* subtract 1 for NaN value */
285 			if (isnormal (z_0_n_range))
286 				header->z_scale_factor = z_0_n_range / n_representations;
287 		}
288 	}
289 
290 	/* Do actual packing/unpacking: */
291 	switch (pack_mode) {
292 		case k_grd_unpack:
293 			gmt_scale_and_offset_f (Ctrl, grid, header->size, header->z_scale_factor, header->z_add_offset);
294 			/* Adjust z-range in header: */
295 			header->z_min = header->z_min * header->z_scale_factor + header->z_add_offset;
296 			header->z_max = header->z_max * header->z_scale_factor + header->z_add_offset;
297 			if (header->z_scale_factor < 0.0) gmt_M_double_swap (header->z_min, header->z_max);
298 			break;
299 		case k_grd_pack:
300 			gmt_scale_and_offset_f (Ctrl, grid, header->size, 1.0/header->z_scale_factor, -header->z_add_offset/header->z_scale_factor);
301 			break;
302 		default:
303 			assert (false); /* gmtgrdio_pack_grid() called with illegal pack_mode */
304 	}
305 }
306 
gmtgrdio_parse_grd_format_scale_old(struct GMT_CTRL * Ctrl,struct GMT_GRID_HEADER * header,char * format)307 GMT_LOCAL int gmtgrdio_parse_grd_format_scale_old (struct GMT_CTRL *Ctrl, struct GMT_GRID_HEADER *header, char *format) {
308 	/* parses format string after =-suffix: ff/scale/offset/invalid
309 	 * ff:      can be one of [abcegnrs][bsifd]
310 	 * scale:   can be any non-zero normalized number or 'a' for scale and
311 	 *          offset auto-adjust, defaults to 1.0 if omitted
312 	 * offset:  can be any finite number or 'a' for offset auto-adjust, defaults to 0 if omitted
313 	 * invalid: can be any finite number, defaults to NaN if omitted
314 	 * scale and offset may be left empty (e.g., ns//a will auto-adjust the offset only)
315 	 */
316 
317 	char type_code[3];
318 	char *p;
319 	int err; /* gmt_M_err_trap */
320 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
321 
322 	/* decode grid type */
323 	strncpy (type_code, format, 2);
324 	type_code[2] = '\0';
325 	if (type_code[0] == '/')		/* user passed a scale with no id code  =/scale[...]. Assume "nf" */
326 		header->type = GMT_GRID_IS_NF;
327 	else {
328 		err = gmt_grd_format_decoder (Ctrl, type_code, &header->type); /* update header type id */
329 		if (err != GMT_NOERROR)
330 			return err;
331 	}
332 
333 	/* parse scale/offset/invalid if any */
334 	p = strchr (format, '/');
335 	if (p != NULL && *p) {
336 		++p;
337 		/* parse scale */
338 		if (*p == 'a')
339 			HH->z_scale_autoadjust = HH->z_offset_autoadjust = true;
340 		else
341 			sscanf (p, "%lf", &header->z_scale_factor);
342 	}
343 	else
344 		return GMT_NOERROR;
345 
346 	p = strchr (p, '/');
347 	if (p != NULL && *p) {
348 		++p;
349 		/* parse offset */
350 		if (*p != 'a') {
351 			HH->z_offset_autoadjust = false;
352 			sscanf (p, "%lf", &header->z_add_offset);
353 		}
354 		else
355 			HH->z_offset_autoadjust = true;
356 	}
357 	else
358 		return GMT_NOERROR;
359 
360 	p = strchr (p, '/');
361 	if (p != NULL && *p) {
362 		++p;
363 		/* parse invalid value */
364 #ifdef DOUBLE_PRECISION_GRID
365 		sscanf (p, "%lf", &header->nan_value);
366 #else
367 		sscanf (p, "%f", &header->nan_value);
368 #endif
369 
370 		/* header->nan_value should be of same type as (float)*grid to avoid
371 		 * round-off errors. For example, =gd///-3.4028234e+38:gtiff, would fail
372 		 * otherwise because the GTiff'd NoData values are of type double but the
373 		 * grid is truncated to float.
374 		 * Don't allow infitiy: */
375 		if (!isfinite (header->nan_value))
376 			header->nan_value = (gmt_grdfloat)NAN;
377 	}
378 
379 	return GMT_NOERROR;
380 }
381 
gmtgrdio_parse_grd_format_scale_new(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,char * format)382 GMT_LOCAL int gmtgrdio_parse_grd_format_scale_new (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, char *format) {
383 	/* parses format string after = suffix: ff[+d<divisor>][+s<scale>][+o<offset>/][+n<invalid>]
384 	 * ff:      can be one of [abcegnrs][bsifd]
385 	 * scale:   can be any non-zero normalized number or 'a' for scale and
386 	 *          offset auto-adjust, defaults to 1.0 if omitted
387 	 * offset:  can be any finite number or 'a' for offset auto-adjust, defaults to 0 if omitted
388 	 * invalid: can be any finite number, defaults to NaN if omitted
389 	 * E.g., ns+oa will auto-adjust the offset only.
390 	 */
391 
392 	char type_code[3];
393 	char p[GMT_BUFSIZ] = {""};
394 	unsigned int pos = 0, uerr = 0;
395 	int err; /* gmt_M_err_trap */
396 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
397 
398 	/* decode grid type */
399 	strncpy (type_code, format, 2);
400 	type_code[2] = '\0';
401 	if (type_code[0] == '+')		/* User passed a scale, offset, or nan-modifier with no id code, e.g.,  =+s<scale>[...]. Assume "nf" format */
402 		header->type = GMT_GRID_IS_NF;
403 	else {	/* Match given code with known codes */
404 		err = gmt_grd_format_decoder (GMT, type_code, &header->type); /* update header type id */
405 		if (err != GMT_NOERROR)
406 			return err;
407 	}
408 
409 	while (gmt_getmodopt (GMT, 0, format, "bdnos", &pos, p, &uerr) && uerr == 0) {	/* Looking for +b, +d, +n, +o, +s */
410 		switch (p[0]) {
411 			case 'b':	/* bands - not parsed here */
412 				break;
413 			case 'd':	/* parse divisor */
414 				GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_parse_grd_format_scale_new: Setting divisor as %s\n", &p[1]);
415 				header->z_scale_factor = 1.0 / atof (&p[1]);	/* Just convert to a scale */
416 				HH->z_scale_given = true;
417 				break;
418 			case 'n':	/* Nan value */
419 				GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_parse_grd_format_scale_new: Using %s to represent missing value (NaN)\n", &p[1]);
420 				header->nan_value = (gmt_grdfloat)atof (&p[1]);
421 				/* header->nan_value should be of same type as (gmt_grdfloat)*grid to avoid
422 				 * round-off errors. For example, =gd+n-3.4028234e+38:gtiff, would fail
423 				 * otherwise because the GTiff'd NoData values are of type double but the
424 				 * grid is truncated to gmt_grdfloat.  Don't allow infinity: */
425 				if (!isfinite (header->nan_value))
426 					header->nan_value = (gmt_grdfloat)NAN;
427 				break;
428 			case 'o':	/* parse offset */
429 				GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_parse_grd_format_scale_new: Setting offset as %s\n", &p[1]);
430 				if (p[1] != 'a') {
431 					HH->z_offset_autoadjust = false;
432 					HH->z_offset_given = true;
433 					header->z_add_offset = atof (&p[1]);
434 				}
435 				else
436 					HH->z_offset_autoadjust = true;
437 				break;
438 			case 's':	/* parse scale */
439 				GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_parse_grd_format_scale_new: Setting scale as %s\n", &p[1]);
440 				if (p[1] == 'a') /* This sets both scale and offset to auto */
441 					HH->z_scale_autoadjust = HH->z_offset_autoadjust = true;
442 				else {
443 					header->z_scale_factor = atof (&p[1]);
444 					HH->z_scale_given = true;
445 				}
446 				break;
447 			default:	/* These are caught in gmt_getmodopt so break is just for Coverity */
448 				break;
449 		}
450 	}
451 	return (uerr) ? GMT_NOT_A_VALID_MODIFIER : GMT_NOERROR;
452 }
453 
gmtgrdio_parse_grd_format_scale(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,char * format)454 GMT_LOCAL int gmtgrdio_parse_grd_format_scale (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, char *format) {
455 	int code;
456 	if (gmt_found_modifier (GMT, format, "bdnos"))
457 		code = gmtgrdio_parse_grd_format_scale_new (GMT, header, format);
458 	else
459 		code = gmtgrdio_parse_grd_format_scale_old (GMT, header, format);
460 	return (code);
461 }
462 
gmtgrdio_eq(double this,double that,double inc)463 GMT_LOCAL bool gmtgrdio_eq (double this, double that, double inc) {
464 	/* this and that are the same value if less than 10e-4 * inc apart */
465 	return ((fabs (this - that) / inc) < GMT_CONV4_LIMIT);
466 }
467 
gmtgrdio_padspace(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,double * wesn,bool image,unsigned int * pad,struct GRD_PAD * P)468 GMT_LOCAL int gmtgrdio_padspace (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, double *wesn, bool image, unsigned int *pad, struct GRD_PAD *P) {
469 	/* When padding is requested it is usually used to set boundary conditions based on
470 	 * two extra rows/columns around the domain of interest.  BCs like natural or periodic
471 	 * can then be used to fill in the pad.  However, if the domain is taken from a grid
472 	 * whose full domain exceeds the region of interest we are better off using the extra
473 	 * data to fill those pad rows/columns.  Thus, this function tries to determine if the
474 	 * input grid has the extra data we need to fill the BC pad with observations
475 	 * P returns the correct region and pad to use regardless if function returns true or false */
476 	bool wrap;
477 	unsigned int side, n_sides = 0;
478 	double wesn2[4];
479 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
480 	gmt_M_unused(GMT);
481 
482 	/* First copy over original settings to the Pad structure */
483 	gmt_M_memset (P, 1, struct GRD_PAD);				/* Initialize to zero */
484 	gmt_M_memcpy (P->pad, pad, 4, int);					/* Duplicate the pad */
485 	gmt_M_memcpy (P->wesn, header->wesn, 4, double);	/* Copy the header boundaries */
486 	if (!wesn) return (false);							/* No subset requested */
487 	if (wesn[XLO] == wesn[XHI] && wesn[YLO] == wesn[YHI]) return (false);	/* Subset not set */
488 	if (gmtgrdio_eq (wesn[XLO], header->wesn[XLO], header->inc[GMT_X]) && gmtgrdio_eq (wesn[XHI], header->wesn[XHI], header->inc[GMT_X])
489 		&& gmtgrdio_eq (wesn[YLO], header->wesn[YLO], header->inc[GMT_Y]) && gmtgrdio_eq (wesn[YHI], header->wesn[YHI], header->inc[GMT_Y]))
490 		return (false);	/* Subset equals whole area */
491 	gmt_M_memcpy (P->wesn, wesn, 4, double);			/* Copy the subset boundaries */
492 	if (pad[XLO] == 0 && pad[XHI] == 0 && pad[YLO] == 0 && pad[YHI] == 0) return (false);	/* No padding requested */
493 	if (!GMT->current.io.grid_padding) return (false);	/* Not requested */
494 
495 	/* Determine if data exist for a pad on all four sides.  If not we give up */
496 	wrap = !image && gmt_grd_is_global (GMT, header);	/* If global grid wrap then we cannot be outside */
497 	if ((wesn2[XLO] = wesn[XLO] - pad[XLO] * header->inc[GMT_X]) < header->wesn[XLO] && !wrap)	/* Cannot extend west/xmin */
498 		{ n_sides++; wesn2[XLO] = wesn[XLO]; }
499 	else	/* OK to load left pad with data */
500 		P->pad[XLO] = 0;
501 	if ((wesn2[XHI] = wesn[XHI] + pad[XHI] * header->inc[GMT_X]) > header->wesn[XHI] && !wrap)	/* Cannot extend east/xmax */
502 		{ n_sides++; wesn2[XHI] = wesn[XHI]; }
503 	else	/* OK to load right pad with data */
504 		P->pad[XHI] = 0;
505 	if ((wesn2[YLO] = wesn[YLO] - pad[YLO] * header->inc[GMT_Y]) < header->wesn[YLO])	/* Cannot extend south/ymin */
506 		{ n_sides++; wesn2[YLO] = wesn[YLO]; }
507 	else	/* OK to load bottom pad with data */
508 		P->pad[YLO] = 0;
509 	if ((wesn2[YHI] = wesn[YHI] + pad[YHI] * header->inc[GMT_Y]) > header->wesn[YHI])	/* Cannot extend north/ymax */
510 		{ n_sides++; wesn2[YHI] = wesn[YHI]; }
511 	else	/* OK to load top pad with data */
512 		P->pad[YHI] = 0;
513 	if (n_sides == 4) return (false);	/* No can do */
514 
515 	/* Here we know that there is enough input data to fill some or all of the BC pad with actual data values */
516 	/* We have temporarily set padding to zero (since the pad is now part of the region) for those sides we can extend */
517 
518 	/* Temporarily enlarge the region so it now includes the padding we need */
519 	gmt_M_memcpy (P->wesn, wesn2, 4, double);
520 
521 	/* Set BC */
522 	for (side = 0; side < 4; side++) {
523 		if (P->pad[side] == 0)
524 			HH->BC[side] = GMT_BC_IS_DATA;
525 	}
526 
527 	return (true);	/* Return true so the calling function can take appropriate action */
528 }
529 
gmt_grd_set_datapadding(struct GMT_CTRL * GMT,bool set)530 void gmt_grd_set_datapadding (struct GMT_CTRL *GMT, bool set) {
531 	/* Changes the value of GMT->current.io.grid_padding.
532 	 * If set = true we turn padding on, else off. */
533 	GMT->current.io.grid_padding = set;
534 }
535 
gmtgrdio_handle_pole_averaging(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,gmt_grdfloat f_value,int pole)536 GMT_LOCAL void gmtgrdio_handle_pole_averaging (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, gmt_grdfloat f_value, int pole) {
537 	uint64_t node;
538 	unsigned int col = 0;
539 	char *name[3] = {"south", "", "north"};
540 	gmt_M_unused(GMT);
541 
542 	if (pole == -1)
543 		node = gmt_M_ijp (header, header->n_rows-1, 0);	/* First node at S pole */
544 	else
545 		node = gmt_M_ijp (header, 0, 0);		/* First node at N pole */
546 	if (gmt_M_type (GMT, GMT_OUT, GMT_Z) == GMT_IS_AZIMUTH || gmt_M_type (GMT, GMT_OUT, GMT_Z) == GMT_IS_ANGLE) {	/* Must average azimuths */
547 		uint64_t orig = node;
548 		double s, c, sum_s = 0.0, sum_c = 0.0;
549 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Average %d angles at the %s pole\n", header->n_columns, name[pole+1]);
550 		for (col = 0; col < header->n_columns; col++, node++) {
551 			sincosd ((double)grid[node], &s, &c);
552 			sum_s += s;	sum_c += c;
553 		}
554 		f_value = (gmt_grdfloat)atan2d (sum_s, sum_c);
555 		node = orig;
556 	}
557 	for (col = 0; col < header->n_columns; col++, node++) grid[node] = f_value;
558 }
559 
gmtgrdio_grd_check_consistency(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid)560 GMT_LOCAL void gmtgrdio_grd_check_consistency (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid) {
561 	/* Enforce before writing a grid that periodic grids with repeating columns
562 	 * agree on the node values in those columns; if different replace with average.
563 	 * This only affects geographic grids of 360-degree extent with gridline registration.
564 	 * Also, if geographic grid with gridline registration, if the N or S pole row is present
565 	 * we ensure that they all have identical values, otherwise replace by mean value */
566 	unsigned int row = 0, col = 0;
567 	unsigned int we_conflicts = 0, p_conflicts = 0;
568 	uint64_t left = 0, right = 0, node = 0;
569 
570 	if (header->registration == GMT_GRID_PIXEL_REG) return;	/* Not gridline registered */
571 	if (gmt_M_is_cartesian (GMT, GMT_OUT)) return;		/* Not geographic */
572 	if (header->wesn[YLO] == -90.0) {	/* Check consistency of S pole duplicates */
573 		double sum;
574 		node = gmt_M_ijp (header, header->n_rows-1, 0);	/* First node at S pole */
575 		sum = grid[node++];
576 		p_conflicts = 0;
577 		for (col = 1; col < header->n_columns; col++, node++) {
578 			if (grid[node] != grid[node-1]) p_conflicts++;
579 			sum += grid[node];
580 		}
581 		if (p_conflicts) {
582 			gmt_grdfloat f_value = (gmt_grdfloat)(sum / header->n_columns);
583 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Detected %u inconsistent values at south pole. Values fixed by setting all to average row value.\n", p_conflicts);
584 			gmtgrdio_handle_pole_averaging (GMT, header, grid, f_value, -1);
585 		}
586 	}
587 	if (header->wesn[YHI] == +90.0) {	/* Check consistency of N pole duplicates */
588 		double sum;
589 		node = gmt_M_ijp (header, 0, 0);	/* First node at N pole */
590 		sum = grid[node++];
591 		p_conflicts = 0;
592 		for (col = 1; col < header->n_columns; col++, node++) {
593 			if (grid[node] != grid[node-1]) p_conflicts++;
594 			sum += grid[node];
595 		}
596 		if (p_conflicts) {
597 			gmt_grdfloat f_value = (gmt_grdfloat)(sum / header->n_columns);
598 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Detected %u inconsistent values at north pole. Values fixed by setting all to average row value.\n", p_conflicts);
599 			gmtgrdio_handle_pole_averaging (GMT, header, grid, f_value, +1);
600 		}
601 	}
602 	if (!gmt_M_360_range (header->wesn[XLO], header->wesn[XHI])) return;	/* Not 360-degree range */
603 
604 	for (row = 0; row < header->n_rows; row++) {
605 		left = gmt_M_ijp (header, row, 0);	/* Left node */
606 		right = left + header->n_columns - 1;		/* Right node */
607 		if (grid[right] != grid[left]) {
608 			grid[right] = grid[left];
609 			we_conflicts++;
610 		}
611 	}
612 	if (we_conflicts)
613 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Detected %u inconsistent values along periodic east boundary of grid. Values fixed by duplicating west boundary.\n", we_conflicts);
614 }
615 
gmtgrdio_grd_wipe_pad(struct GMT_CTRL * GMT,struct GMT_GRID * G)616 GMT_LOCAL void gmtgrdio_grd_wipe_pad (struct GMT_CTRL *GMT, struct GMT_GRID *G) {
617 	/* Reset padded areas to 0. */
618 	unsigned int row;
619 	size_t ij0;
620 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (G->header);
621 
622 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
623 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Calling gmtgrdio_grd_wipe_pad on interleaved complex grid! Programming error?\n");
624 		return;
625 	}
626 	if (G->header->pad[YHI]) gmt_M_memset (G->data, G->header->mx * G->header->pad[YHI], gmt_grdfloat);	/* Wipe top pad */
627 	if (G->header->pad[YLO]) {	/* Wipe bottom pad */
628 		ij0 = gmt_M_ij (G->header, G->header->my - G->header->pad[YLO], 0);	/* Index of start of bottom pad */
629 		gmt_M_memset (&(G->data[ij0]), G->header->mx * G->header->pad[YLO], gmt_grdfloat);
630 	}
631 	if (G->header->pad[XLO] == 0 && G->header->pad[XHI] == 0) return;	/* Nothing to do */
632 	for (row = G->header->pad[YHI]; row < G->header->my - G->header->pad[YLO]; row++) {	/* Wipe left and right pad which is trickier */
633 		ij0 = gmt_M_ij (G->header, row, 0);	/* Index of this row's left column (1st entry in west pad) */
634 		if (G->header->pad[XLO]) gmt_M_memset (&(G->data[ij0]), G->header->pad[XLO], gmt_grdfloat);
635 		ij0 += (G->header->mx - G->header->pad[XHI]);	/* Start of this rows east pad's 1st column */
636 		if (G->header->pad[XHI]) gmt_M_memset (&(G->data[ij0]), G->header->pad[XHI], gmt_grdfloat);
637 	}
638 }
639 
gmtgrdio_pad_grd_off_sub(struct GMT_GRID * G,gmt_grdfloat * data)640 GMT_LOCAL void gmtgrdio_pad_grd_off_sub (struct GMT_GRID *G, gmt_grdfloat *data) {
641 	/* Remove the current grid pad and shuffle all rows to the left */
642 	uint64_t ijp, ij0;
643 	unsigned int row;
644 	for (row = 0; row < G->header->n_rows; row++) {
645 		ijp = gmt_M_ijp (G->header, row, 0);	/* Index of start of this row's first column in padded grid  */
646 		ij0 = gmt_M_ij0 (G->header, row, 0);	/* Index of start of this row's first column in unpadded grid */
647 		gmt_M_memcpy (&(data[ij0]), &(data[ijp]), G->header->n_columns, gmt_grdfloat);	/* Only copy the n_columns data values */
648 	}
649 }
650 
gmtgrdio_pad_grd_on_sub(struct GMT_CTRL * GMT,struct GMT_GRID * G,struct GMT_GRID_HEADER * h_old,gmt_grdfloat * data)651 GMT_LOCAL void gmtgrdio_pad_grd_on_sub (struct GMT_CTRL *GMT, struct GMT_GRID *G, struct GMT_GRID_HEADER *h_old, gmt_grdfloat *data) {
652 	/* Use G for dimensions but operate on data array which points to either the real or imaginary section */
653 	uint64_t ij_new, ij_old, row, col, start_last_new_row, end_last_old_row;
654 
655 	/* See if the index of start of last new row exceeds index of last node in old grid */
656 	start_last_new_row = gmt_M_get_nm (GMT, G->header->pad[YHI] + G->header->n_rows - 1, G->header->pad[XLO] + G->header->n_columns + G->header->pad[XHI]) + G->header->pad[XLO];
657 	end_last_old_row   = gmt_M_get_nm (GMT, h_old->pad[YHI] + h_old->n_rows - 1, h_old->pad[XLO] + h_old->n_columns + h_old->pad[XHI]) + h_old->pad[XLO] + h_old->n_columns - 1;
658 	if (start_last_new_row > end_last_old_row && (start_last_new_row - end_last_old_row) > G->header->n_columns) {        /* May copy whole rows from bottom to top */
659 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_pad_grd_on_sub can copy row-by-row\n");
660 		for (row = G->header->n_rows; row > 0; row--) {
661 			ij_new = gmt_M_ijp (G->header, row-1, 0);   /* Index of this row's first column in new padded grid  */
662 			ij_old = gmt_M_ijp (h_old, row-1, 0);       /* Index of this row's first column in old padded grid */
663 			gmt_M_memcpy (&(data[ij_new]), &(data[ij_old]), G->header->n_columns, gmt_grdfloat);
664 		}
665 	}
666 	else {	/* Must do it from bottom to top on a per node basis */
667 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_pad_grd_on_sub must copy node-by-node\n");
668 		ij_new = gmt_M_ijp (G->header, G->header->n_rows-1, G->header->n_columns-1); /* Index of this row's last column in new padded grid  */
669 		ij_old = gmt_M_ijp (h_old, h_old->n_rows-1, h_old->n_columns-1);     /* Index of this row's last column in old padded grid */
670 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_pad_grd_on_sub: last ij_new = %d, last ij_old = %d\n", (int)ij_new, (int)ij_old);
671 
672 		if (ij_new > ij_old) {	/* Can go back to front */
673 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_pad_grd_on_sub: Must loop from end to front\n");
674 			for (row = G->header->n_rows; row > 0; row--) {
675 				ij_new = gmt_M_ijp (G->header, row-1, G->header->n_columns-1); /* Index of this row's last column in new padded grid  */
676 				ij_old = gmt_M_ijp (h_old, row-1, h_old->n_columns-1);     /* Index of this row's last column in old padded grid */
677 				for (col = 0; col < G->header->n_columns; col++)
678 					data[ij_new--] = data[ij_old--];
679 			}
680 		}
681 		else {
682 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "gmtgrdio_pad_grd_on_sub: Must loop from front to end\n");
683 			for (row = 0; row < G->header->n_rows; row++) {
684 				ij_new = gmt_M_ijp (G->header, row, 0); /* Index of this row's last column in new padded grid  */
685 				ij_old = gmt_M_ijp (h_old, row, 0);     /* Index of this row's last column in old padded grid */
686 				for (col = 0; col < G->header->n_columns; col++)
687 					data[ij_new++] = data[ij_old++];
688 			}
689 		}
690 	}
691 	gmtgrdio_grd_wipe_pad (GMT, G);	/* Set pad areas to 0 */
692 }
693 
gmtgrdio_pad_grd_zero_sub(struct GMT_GRID * G,gmt_grdfloat * data)694 GMT_LOCAL void gmtgrdio_pad_grd_zero_sub (struct GMT_GRID *G, gmt_grdfloat *data) {
695 	unsigned int row, col, nx1;
696 	uint64_t ij_f, ij_l;
697 
698 	if (G->header->pad[YHI]) gmt_M_memset (data, G->header->pad[YHI] * G->header->mx, gmt_grdfloat);		/* Zero the top pad */
699 	nx1 = G->header->n_columns - 1;	/* Last column */
700 	gmt_M_row_loop (NULL, G, row) {
701 		ij_f = gmt_M_ijp (G->header, row,   0);				/* Index of first column this row  */
702 		ij_l = gmt_M_ijp (G->header, row, nx1);				/* Index of last column this row */
703 		for (col = 1; col <= G->header->pad[XLO]; col++) data[ij_f-col] = 0.0f;	/* Zero the left pad at this row */
704 		for (col = 1; col <= G->header->pad[XHI]; col++) data[ij_l+col] = 0.0f;	/* Zero the left pad at this row */
705 	}
706 	if (G->header->pad[YLO]) {
707 		int pad = G->header->pad[XLO];
708 		ij_f = gmt_M_ijp (G->header, G->header->n_rows, -pad);				/* Index of first column of bottom pad  */
709 		gmt_M_memset (&(data[ij_f]), G->header->pad[YLO] * G->header->mx, gmt_grdfloat);	/* Zero the bottom pad */
710 	}
711 }
712 
gmtgrdio_duplicate_gridheader(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)713 GMT_LOCAL struct GMT_GRID_HEADER *gmtgrdio_duplicate_gridheader (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
714 	/* Duplicates a grid header. */
715 	struct GMT_GRID_HEADER *hnew = gmt_get_header (GMT);
716 	gmt_copy_gridheader (GMT, hnew, h);
717 	return (hnew);
718 }
719 
720 /*----------------------------------------------------------|
721  * Public functions that are part of the GMT Devel library  |
722  *----------------------------------------------------------|
723  */
724 
725 #ifdef DEBUG
726 /* Uncomment this to have gmt_grd_dump be called and do something */
727 /* #define GMT_DUMPING */
728 #ifdef GMT_DUMPING
gmt_grd_dump(struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,bool is_complex,char * txt)729 void gmt_grd_dump (struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, bool is_complex, char *txt) {
730 	unsigned int row, col;
731 	uint64_t k = 0U;
732 	fprintf (stderr, "Dump [%s]:\n---------------------------------------------\n", txt);
733 	for (row = 0; row < header->my; row++) {
734 		if (is_complex)
735 			for (col = 0; col < header->mx; col++, k+= 2) fprintf (stderr, "(%g,%g)\t", grid[k], grid[k+1]);
736 		else
737 			for (col = 0; col < header->mx; col++, k++) fprintf (stderr, "%g\t", grid[k]);
738 		fprintf (stderr, "\n");
739 	}
740 	fprintf (stderr, "---------------------------------------------\n");
741 }
742 #else	/* Just a dummy */
gmt_grd_dump(struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,bool is_complex,char * txt)743 void gmt_grd_dump (struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, bool is_complex, char *txt) {
744 	gmt_M_unused(header); gmt_M_unused(grid); gmt_M_unused(is_complex); gmt_M_unused(txt);
745 	/* Nothing */
746 }
747 #endif
748 #endif
749 
gmt_copy_gridheader(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * to,struct GMT_GRID_HEADER * from)750 void gmt_copy_gridheader (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *to, struct GMT_GRID_HEADER *from) {
751 	/* Destination must exist */
752 	struct GMT_GRID_HEADER_HIDDEN *Hfrom = gmt_get_H_hidden (from), *Hto = gmt_get_H_hidden (to);
753 	gmt_M_unused(GMT);
754 	if (to->ProjRefWKT) gmt_M_str_free (to->ProjRefWKT);		/* Since we will duplicate via from */
755 	if (to->ProjRefPROJ4) gmt_M_str_free (to->ProjRefPROJ4);	/* Since we will duplicate via from */
756 	if (Hto->pocket) gmt_M_str_free (Hto->pocket);			/* Since we will duplicate via from */
757 	gmt_M_memcpy (to, from, 1, struct GMT_GRID_HEADER);		/* Copies full contents but also duplicates the hidden address */
758 	to->hidden = Hto;	/* Restore the original hidden address in to */
759 	gmt_M_memcpy (to->hidden, from->hidden, 1, struct GMT_GRID_HEADER_HIDDEN);	/* Copies full contents of hidden area */
760 	/* Must deal with three pointers individually */
761 	if (from->ProjRefWKT) to->ProjRefWKT = strdup (from->ProjRefWKT);
762 	if (from->ProjRefPROJ4) to->ProjRefPROJ4 = strdup (from->ProjRefPROJ4);
763 	if (Hfrom->pocket) Hto->pocket = strdup (Hfrom->pocket);
764 }
765 
766 /*! gmt_grd_is_global returns true for a geographic grid with exactly 360-degree range (with or without repeating column) */
gmt_grd_is_global(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)767 bool gmt_grd_is_global (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
768 	bool global;
769 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
770 	gmt_M_unused(GMT);
771 	global = (HH->grdtype == GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT || HH->grdtype == GMT_GRID_GEOGRAPHIC_EXACT360_REPEAT);
772 	return (global);
773 }
774 
775 /*! gmt_grd_is_polar returns true for a geographic grid with exactly 180-degree range in latitude (with or without repeating column) */
gmt_grd_is_polar(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)776 bool gmt_grd_is_polar (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
777 	if (!gmt_M_y_is_lat (GMT, GMT_IN))
778 		return false;
779 	if (gmt_M_180_range (h->wesn[YHI], h->wesn[YLO]))
780 		return true;
781 	if (fabs (h->n_rows * h->inc[GMT_Y] - 180.0) < GMT_CONV4_LIMIT)
782 		return true;
783 	return false;
784 }
785 
gmt_set_R_from_grd(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header)786 void gmt_set_R_from_grd (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header) {
787 	/* When no -R was given we will inherit the region from the grid.  However,
788 	 * many grids are hobbled by not clearly specifying they are truly global grids.
789 	 * What frequently happens is that gridnode-registered grids omit the repeating
790 	 * column in the east, leading to regions such as -R0/359/-90/90 for a 1-degree grid.
791 	 * Since these are clearly global we do now want to pass 0/359 to the projection
792 	 * machinery but 0/360.  Hence we test if the grid is truly global and make this decision. */
793 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
794 
795 	gmt_M_memcpy (GMT->common.R.wesn, header->wesn, 4, double);	/* Initially we set -R as is from grid header */
796 	if (HH->grdtype != GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT) return;	/* Nothing to do */
797 	if (!gmt_M_360_range (GMT->common.R.wesn[XLO], GMT->common.R.wesn[XHI]) && fabs (header->n_columns * header->inc[GMT_X] - 360.0) < GMT_CONV4_LIMIT) {
798 		/* The w/e need to state the complete 360 range: Let east = 360 + west */
799 		GMT->common.R.wesn[XHI] = GMT->common.R.wesn[XLO] + 360.0;
800 	}
801 	if (!gmt_M_180_range (GMT->common.R.wesn[YLO], GMT->common.R.wesn[YHI]) && fabs (header->n_rows * header->inc[GMT_Y] - 180.0) < GMT_CONV4_LIMIT) {
802 		/* The s/n need to state the complete 180 range */
803 		GMT->common.R.wesn[YLO] = -90.0;
804 		GMT->common.R.wesn[YHI] = +90.0;
805 	}
806 }
807 
gmtlib_grd_get_units(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header)808 void gmtlib_grd_get_units (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header) {
809 	/* Set input data types for columns 0, 1 and 2 based on unit strings for
810 	   grid coordinates x, y and z.
811 	   When "Time": transform the data scale and offset to match the current time system.
812 	*/
813 	unsigned int i;
814 	char string[3][GMT_LEN256], *units = NULL;
815 	double scale = 1.0, offset = 0.0;
816 	struct GMT_TIME_SYSTEM time_system;
817 
818 	/* Copy unit strings */
819 	strncpy (string[0], header->x_units, GMT_GRID_UNIT_LEN80);
820 	strncpy (string[1], header->y_units, GMT_GRID_UNIT_LEN80);
821 	strncpy (string[2], header->z_units, GMT_GRID_UNIT_LEN80);
822 
823 	/* Parse the unit strings one by one */
824 	for (i = 0; i < 3; i++) {
825 		/* Skip parsing when input data type is already set */
826 		if (GMT->current.io.col_type[GMT_IN][i] & GMT_IS_GEO) continue;
827 		if (GMT->current.io.col_type[GMT_IN][i] & GMT_IS_RATIME) {
828 			GMT->current.proj.xyz_projection[i] = GMT_TIME;
829 			continue;
830 		}
831 
832 		/* Change name of variable and unit to lower case for comparison */
833 		gmt_str_tolower (string[i]);
834 
835 		/* PW: This test was <= 360 but if you have grids from 340-375 and it says longitude then we should not make it Cartesian */
836 		if ((!strncmp (string[i], "longitude", 9U) || strstr (string[i], "degrees_e")) && (header->wesn[XLO] > -360.0 && header->wesn[XHI] < 720.0)) {
837 			/* Input data type is longitude */
838 			gmt_set_column_type (GMT, GMT_IN, i, GMT_IS_LON);
839 		}
840 		else if ((!strncmp (string[i], "latitude", 8U) || strstr (string[i], "degrees_n")) && (header->wesn[YLO] >= -90.0 && header->wesn[YHI] <= 90.0)) {
841 			/* Input data type is latitude */
842 			gmt_set_column_type (GMT, GMT_IN, i, GMT_IS_LAT);
843 		}
844 		else if (!strcmp (string[i], "time") || !strncmp (string[i], "time [", 6U)) {
845 			/* Input data type is time */
846 			gmt_set_column_type (GMT, GMT_IN, i, GMT_IS_RELTIME);
847 			GMT->current.proj.xyz_projection[i] = GMT_TIME;
848 
849 			/* Determine coordinates epoch and units (default is internal system) */
850 			gmt_M_memcpy (&time_system, &GMT->current.setting.time_system, 1, struct GMT_TIME_SYSTEM);
851 			units = strchr (string[i], '[');
852 			if (!units || gmt_get_time_system (GMT, ++units, &time_system) || gmt_init_time_system_structure (GMT, &time_system))
853 				GMT_Report (GMT->parent, GMT_MSG_WARNING, "Time units [%s] in grid not recognized, defaulting to %s settings.\n", units, GMT_SETTINGS_FILE);
854 
855 			/* Determine scale between grid and internal time system, as well as the offset (in internal units) */
856 			scale = time_system.scale * GMT->current.setting.time_system.i_scale;
857 			offset = (time_system.rata_die - GMT->current.setting.time_system.rata_die) + (time_system.epoch_t0 - GMT->current.setting.time_system.epoch_t0);
858 			offset *= GMT_DAY2SEC_F * GMT->current.setting.time_system.i_scale;
859 
860 			/* Scale data scale and extremes based on scale and offset */
861 			if (i == 0) {
862 				header->wesn[XLO] = header->wesn[XLO] * scale + offset;
863 				header->wesn[XHI] = header->wesn[XHI] * scale + offset;
864 				header->inc[GMT_X] *= scale;
865 			}
866 			else if (i == 1) {
867 				header->wesn[YLO] = header->wesn[YLO] * scale + offset;
868 				header->wesn[YHI] = header->wesn[YHI] * scale + offset;
869 				header->inc[GMT_Y] *= scale;
870 			}
871 			else {
872 				header->z_add_offset = header->z_add_offset * scale + offset;
873 				header->z_scale_factor *= scale;
874 			}
875 		}
876 	}
877 }
878 
gmt_grd_coord(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,int dir)879 double * gmt_grd_coord (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, int dir) {
880 	/* Allocate, compute, and return the x- or y-coordinates for a grid */
881 	unsigned int k;
882 	double *coord = NULL;
883 	assert (dir == GMT_X || dir == GMT_Y);
884 	if (dir == GMT_X) {
885 		coord = gmt_M_memory (GMT, NULL, header->n_columns, double);
886 		for (k = 0; k < header->n_columns; k++) coord[k] = gmt_M_grd_col_to_x (GMT, k, header);
887 	}
888 	else if (dir == GMT_Y) {
889 		coord = gmt_M_memory (GMT, NULL, header->n_rows, double);
890 		for (k = 0; k < header->n_rows; k++) coord[k] = gmt_M_grd_row_to_y (GMT, k, header);
891 	}
892 
893 	return (coord);
894 }
895 
gmtlib_grd_real_interleave(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,gmt_grdfloat * data)896 void gmtlib_grd_real_interleave (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_grdfloat *data) {
897 	/* Sub-function since this step is also needed in the specific case when a module
898 	 * calls GMT_Read_Data with GMT_GRID_IS_COMPLEX_REAL but input comes via an
899 	 * external interface (MATLAB, Python) and thus has not been multiplexed yet.
900 	 * We assume the data array is already large enough to hold the double-sized grid.
901 	 */
902 	uint64_t row, col, col_1, col_2, left_node_1, left_node_2;
903 	gmt_M_unused(GMT);
904 	/* Here we have a grid with RRRRRR..._________ and want R_R_R_R_... */
905 	for (row = header->my; row > 0; row--) {	/* Going from last to first row */
906 		left_node_1 = gmt_M_ij (header, row-1, 0);	/* Start of row in RRRRR layout */
907 		left_node_2 = 2 * left_node_1;			/* Start of same row in R_R_R_ layout */
908 		for (col = header->mx, col_1 = col - 1, col_2 = 2*col - 1; col > 0; col--, col_1--) { /* Go from right to left */
909 			data[left_node_2+col_2] = 0.0f;	col_2--;	/* Set the Imag component to zero */
910 			data[left_node_2+col_2] = data[left_node_1+col_1];	col_2--;
911 		}
912 	}
913 }
914 
gmt_grd_mux_demux(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,gmt_grdfloat * data,unsigned int desired_mode)915 void gmt_grd_mux_demux (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, gmt_grdfloat *data, unsigned int desired_mode) {
916 	/* Multiplex and demultiplex complex grids.
917  	 * Complex grids are read/written by dealing with just one component: real or imag.
918 	 * Thus, at read|write the developer must specify which component (GMT_CMPLX_REAL|IMAG).
919 	 * For fast disk i/o we read complex data in serial.  I.e., if we ask for GMT_CMPLX_REAL
920 	 * then the array will contain RRRRR....________, where ______ is unused space for the
921 	 * imaginary components.  Likewise, if we requested GMT_CMPLX_IMAG then the array will
922 	 * be returned as _______...IIIIIII....
923 	 * Operations like FFTs typically required the data to be interleaved, i.e., in the
924 	 * form RIRIRIRI.... Then, when the FFT work is done and we wish to write out the
925 	 * result we will need to demultiplex the array back to its serial RRRRR....IIIII
926 	 * format before writing takes place.
927 	 * gmt_grd_mux_demux performs either multiplex or demultiplex, depending on desired_mode.
928 	 * If grid is not complex then we just return doing nothing.
929 	 * Note: At this point the grid is mx * my and we visit all the nodes, including the pads.
930 	 * hence we use header->mx/my and gmt_M_ij below.
931 	 */
932 	uint64_t row, col, col_1, col_2, left_node_1, left_node_2, offset, ij, ij2;
933 	gmt_grdfloat *array = NULL;
934 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
935 
936 	if (! (desired_mode == GMT_GRID_IS_INTERLEAVED || desired_mode == GMT_GRID_IS_SERIAL)) {
937 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "gmt_grd_mux_demux called with inappropriate mode - skipped.\n");
938 		return;
939 	}
940 	if ((header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) == 0) return;	/* Nuthin' to do */
941 	if (HH->arrangement == desired_mode) return;				/* Already has the right layout */
942 
943 	/* In most cases we will actually have RRRRR...______ or _____...IIIII..
944 	 * which means half the array is empty and it is easy to shuffle. However,
945 	 * in the case with actual RRRR...IIII there is no simple way to do this inplace;
946 	 * see http://stackoverflow.com/questions/1777901/array-interleaving-problem */
947 
948 	if (desired_mode == GMT_GRID_IS_INTERLEAVED) {	/* Must multiplex the grid */
949 		if ((header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) == GMT_GRID_IS_COMPLEX_MASK) {
950 			/* Transform from RRRRR...IIIII to RIRIRIRIRI... */
951 			/* Implement properly later; for now waste memory by duplicating [memory is cheap and plentiful] */
952 			/* One advantage is that the padding is all zero by virtue of the allocation */
953 			array = gmt_M_memory_aligned (GMT, NULL, header->size, gmt_grdfloat);
954 			offset = header->size / 2;	/* Position of 1st row in imag portion of RRRR...IIII... */
955 			for (row = 0; row < header->my; row++) {	/* Going from first to last row */
956 				for (col = 0; col < header->mx; col++) {
957 					ij = gmt_M_ij (header, row, col);	/* Position of an 'R' in the RRRRR portion */
958 					ij2 = 2 * ij;
959 					array[ij2++] = data[ij];
960 					array[ij2] = data[ij+offset];
961 				}
962 			}
963 			gmt_M_memcpy (data, array, header->size, gmt_grdfloat);	/* Overwrite serial array with interleaved array */
964 			gmt_M_free (GMT, array);
965 		}
966 		else if (header->complex_mode & GMT_GRID_IS_COMPLEX_REAL) {
967 			/* Here we have RRRRRR..._________ and want R_R_R_R_... */
968 			gmtlib_grd_real_interleave (GMT, header, data);
969 		}
970 		else {
971 			/* Here we have _____...IIIII and want _I_I_I_I */
972 			offset = header->size / 2;	/* Position of 1st row in imag portion of ____...IIII... */
973 			for (row = 0; row < header->my; row++) {	/* Going from first to last row */
974 				left_node_1 = gmt_M_ij (header, row, 0);		/* Start of row in _____IIII layout not counting ____*/
975 				left_node_2 = 2 * left_node_1;			/* Start of same row in _I_I_I... layout */
976 				left_node_1 += offset;				/* Move past length of all ____... */
977 				for (col_1 = 0, col_2 = 1; col_1 < header->mx; col_1++, col_2 += 2) {
978 					data[left_node_2+col_2] = data[left_node_1+col_1];
979 					data[left_node_1+col_1] = 0.0f;	/* Set the Real component to zero */
980 				}
981 			}
982 		}
983 	}
984 	else if (desired_mode == GMT_GRID_IS_SERIAL) {	/* Must demultiplex the grid */
985 		if ((header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) == GMT_GRID_IS_COMPLEX_MASK) {
986 			/* Transform from RIRIRIRIRI... to RRRRR...IIIII  */
987 			/* Implement properly later; for now waste memory by duplicating [memory is cheap and plentiful] */
988 			/* One advantage is that the padding is all zero by virtue of the allocation */
989 			array = gmt_M_memory_aligned (GMT, NULL, header->size, gmt_grdfloat);
990 			offset = header->size / 2;	/* Position of 1st row in imag portion of RRRR...IIII... */
991 			for (row = 0; row < header->my; row++) {	/* Going from first to last row */
992 				for (col = 0; col < header->mx; col++) {
993 					ij = gmt_M_ij (header, row, col);	/* Position of an 'R' in the RRRRR portion */
994 					ij2 = 2 * ij;
995 					array[ij] = data[ij2++];
996 					array[ij+offset] = data[ij2];
997 				}
998 			}
999 			gmt_M_memcpy (data, array, header->size, gmt_grdfloat);	/* Overwrite interleaved array with serial array */
1000 			gmt_M_free (GMT, array);
1001 		}
1002 		else if (header->complex_mode & GMT_GRID_IS_COMPLEX_REAL) {
1003 			/* Here we have R_R_R_R_... and want RRRRRR..._______  */
1004 			for (row = 0; row < header->my; row++) {	/* Doing from first to last row */
1005 				left_node_1 = gmt_M_ij (header, row, 0);	/* Start of row in RRRRR... */
1006 				left_node_2 = 2 * left_node_1;		/* Start of same row in R_R_R_R... layout */
1007 				for (col_1 = col_2 = 0; col_1 < header->mx; col_1++, col_2 += 2) {
1008 					data[left_node_1+col_1] = data[left_node_2+col_2];
1009 				}
1010 			}
1011 			offset = header->size / 2;			/* Position of 1st _ in RRRR...____ */
1012 			gmt_M_memset (&data[offset], offset, gmt_grdfloat);	/* Wipe _____ portion clean */
1013 		}
1014 		else {	/* Here we have _I_I_I_I and want _____...IIIII */
1015 			offset = header->size / 2;	/* Position of 1st row in imag portion of ____...IIII... */
1016 			for (row = header->my; row > 0; row--) {	/* Going from last to first row */
1017 				left_node_1 = gmt_M_ij (header, row, 0);	/* Start of row in _____IIII layout not counting ____*/
1018 				left_node_2 = 2 * left_node_1;		/* Start of same row in _I_I_I... layout */
1019 				left_node_1 += offset;			/* Move past length of all ____... */
1020 				for (col = header->mx, col_1 = col - 1, col_2 = 2*col - 1; col > 0; col--, col_1--, col_2 -= 2) { /* Go from right to left */
1021 					data[left_node_1+col_1] = data[left_node_2+col_2];
1022 				}
1023 			}
1024 			gmt_M_memset (data, offset, gmt_grdfloat);	/* Wipe leading _____ portion clean */
1025 		}
1026 	}
1027 	HH->arrangement = desired_mode;
1028 }
1029 
gmt_grd_get_format(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header,bool magic)1030 int gmt_grd_get_format (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header, bool magic) {
1031 	/* This functions does a couple of things:
1032 	 * 1. It tries to determine what kind of grid file this is. If a file is openeed for
1033 	 *    reading we see if (a) a particular format has been specified with
1034 	 *    the =<code> suffix, or (b) we are able to guess the format based on known
1035 	 *    characteristics of various formats, or (c) assume the default grid format.
1036 	 *    If a file is opened for writing, only option (a) and (c) apply.
1037 	 *    If we cannot obtain the format we return an error.
1038 	 * 2. We strip the suffix off. The relevant info is stored in the header struct.
1039 	 * 3. In case of netCDF grids, the optional ?<varname> is stripped off as well.
1040 	 *    The info is stored in header->varname.
1041 	 * 4. If a file is open for reading, we set header->name to the full path of the file
1042 	 *    by searching in current dir and the various GMT_*DIR paths.
1043 	 */
1044 
1045 	size_t i = 0, j;
1046 	int val;
1047 	unsigned int direction = (magic) ? GMT_IN : GMT_OUT, pos = 0;
1048 	char tmp[GMT_LEN512] = {""};	/* But it's copied at most 256 chars into header->name so 256 should do */
1049 	char *c = NULL, *f = NULL, *ext = NULL;	/* Various char pointers used to deal with file modifiers */
1050 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
1051 
1052 	if (file[0] == '@') pos = 1;	/* At this point we will already have downloaded any remote file so skip the @ */
1053 	gmtgrdio_grd_parse_xy_units (GMT, header, &file[pos], direction);	/* Parse and strip xy scaling via +u<unit> modifier */
1054 
1055 	gmtgrdio_expand_filename (GMT, &file[pos], HH->name);	/* May append a suffix to header->name */
1056 
1057 	/* Must reset scale and invalid value because sometimes headers from input grids are
1058 	 * 'recycled' and used for output grids that may have a different type and z-range: */
1059 	header->z_scale_factor = 1.0;
1060 	header->z_add_offset   = 0.0;
1061 	header->nan_value      = (gmt_grdfloat)NAN;
1062 
1063 	i = strcspn (HH->name, "=");	/* get number of chars until first '=' or '\0' */
1064 
1065 	if ((f = gmt_strrstr (HH->name, ".grd")) || (f = gmt_strrstr (HH->name, ".nc")))
1066 		c = gmtlib_last_valid_file_modifier (GMT->parent, f, GMT_GRIDFILE_MODIFIERS);
1067 	else
1068 		c = gmtlib_last_valid_file_modifier (GMT->parent, HH->name, GMT_GRIDFILE_MODIFIERS);
1069 
1070 	if (HH->name[i] == '\0' && c) {	/* No grid type but gave valid modifiers */
1071 		/* parse grid format string: */
1072 		if ((val = gmtgrdio_parse_grd_format_scale (GMT, header, c)) != GMT_NOERROR)
1073 			return val;
1074 		c[0] = '\0';	/* Chop off since we did got the scalings */
1075 	}
1076 	if (HH->name[i]) {	/* Reading or writing when =suffix is present: get format type, scale, offset and missing value */
1077 		i++;
1078 		/* parse grid format string: */
1079 		if (c && (val = gmtgrdio_parse_grd_format_scale (GMT, header, c)) != GMT_NOERROR)
1080 			return val;
1081 		else if ((val = gmtgrdio_parse_grd_format_scale (GMT, header, &HH->name[i])) != GMT_NOERROR)
1082 			return val;
1083 		if (header->type == GMT_GRID_IS_GD && HH->name[i+2] && HH->name[i+2] == '?') {	/* A SUBDATASET request for GDAL */
1084 			char *pch = strstr(&HH->name[i+3], "::");
1085 			if (pch) {		/* The file name was omitted within the SUBDATASET. Must put it there for GDAL */
1086 				strncpy (tmp, &HH->name[i+3], pch - &HH->name[i+3] + 1);
1087 				strcat (tmp, "\"");	strncat(tmp, HH->name, i-1);	strcat(tmp, "\"");
1088 				if (strlen(&pch[1]) < (GMT_LEN512-strlen(tmp)-1)) strncat (tmp, &pch[1], GMT_LEN512-1);
1089 				strncpy (HH->name, tmp, GMT_LEN256-1);
1090 			}
1091 			else
1092 				memmove (HH->name, &HH->name[i+3], strlen(&HH->name[i+3])+1);
1093 			magic = 0;	/* We don't want it to try to prepend any path */
1094 		} /* if (header->type == GMT_GRID_IS_GD && HH->name[i+2] && HH->name[i+2] == '?') */
1095 		else if (header->type == GMT_GRID_IS_GD && HH->name[i+2] && HH->name[i+2] == '+' && HH->name[i+3] == 'b') { /* A Band request for GDAL */
1096 			HH->pocket = strdup(&HH->name[i+4]);
1097 			HH->name[i-1] = '\0';
1098 		}
1099 		else if (header->type == GMT_GRID_IS_GD && HH->name[i+2] && strchr(&HH->name[i+2], ':')) {
1100 			char *pch;
1101 			size_t nc_limit = 2147483647U;	/* 2^31 - 1 is the max length of a 1-D array in netCDF */
1102 			pch = strchr(&HH->name[i+2], ':');
1103 			HH->pocket = strdup(++pch);
1104 			HH->name[i-1] = '\0';			/* Done, rip the driver/outtype info from file name */
1105 			if (!strncmp (HH->pocket, "GMT", 3U) && header->nm > nc_limit) {
1106 				GMT_Report (GMT->parent, GMT_MSG_ERROR, "Your grid contains more than 2^31 - 1 nodes (%" PRIu64 ") and cannot be stored with the deprecated GMT netCDF format via GDAL.\n", header->nm);
1107 				GMT_Report (GMT->parent, GMT_MSG_ERROR, "Please choose another grid format such as the default netCDF 4 COARDS-compliant grid format.\n");
1108 				return (GMT_GRDIO_BAD_DIM);	/* Grid is too large */
1109 			}
1110 		}
1111 		else {
1112 			j = (i == 1) ? i : i - 1;
1113 			HH->name[j] = 0;
1114 		}
1115 		sscanf (HH->name, "%[^?]?%s", tmp, HH->varname);    /* Strip off variable name */
1116 		if (magic) {	/* Reading: possibly prepend a path from GMT_[GRID|DATA|IMG]DIR */
1117 			if (header->type != GMT_GRID_IS_GD || !gmtlib_found_url_for_gdal(tmp))	/* Do not try path stuff with Web files (accessed via GDAL) */
1118 				if (!gmt_getdatapath (GMT, tmp, HH->name, R_OK))
1119 					return (GMT_GRDIO_FILE_NOT_FOUND);
1120 		}
1121 		else		/* Writing: store truncated pathname */
1122 			strncpy (HH->name, tmp, GMT_LEN256-1);
1123 	} /* if (header->name[i]) */
1124 	else if (magic) {	/* Reading: determine file format automatically based on grid content */
1125 		int choice = 0;
1126 		sscanf (HH->name, "%[^?]?%s", tmp, HH->varname);    /* Strip off variable name */
1127 #ifdef HAVE_GDAL
1128 		/* Check if file is an URL */
1129 		if (gmtlib_found_url_for_gdal(HH->name)) {
1130 			/* Then check for GDAL grid */
1131 			if (gmtlib_is_gdal_grid (GMT, header) == GMT_NOERROR)
1132 				return (GMT_NOERROR);
1133 		}
1134 #endif
1135 		if (!gmt_getdatapath (GMT, tmp, HH->name, R_OK))
1136 			return (GMT_GRDIO_FILE_NOT_FOUND);	/* Possibly prepended a path from GMT_[GRID|DATA|IMG]DIR */
1137 		/* First check if we have a netCDF grid. This MUST be first, because ?var needs to be stripped off. */
1138 		if ((val = gmtlib_is_nc_grid (GMT, header)) == GMT_NOERROR)
1139 			return (GMT_NOERROR);
1140 		/* Continue only when file was not a pipe or when gmt_nc_open didn't like the file or when the grid was COARDS-compliant. */
1141 		if (val != GMT_GRDIO_NC_NO_PIPE && val != GMT_GRDIO_OPEN_FAILED && val != GMT_GRDIO_NC_NOT_COARDS)
1142 			return (val);
1143 		/* Then check for native binary GMT grid */
1144 		if ((choice = gmtlib_is_native_grid (GMT, header)) == GMT_NOERROR)
1145 			return (GMT_NOERROR);
1146 		else if (choice == GMT_GRDIO_NONUNIQUE_FORMAT)
1147 			return (GMT_GRDIO_NONUNIQUE_FORMAT);
1148 		/* Next check for Sun raster grid */
1149 		if (gmtlib_is_ras_grid (GMT, header) == GMT_NOERROR)
1150 			return (GMT_NOERROR);
1151 		/* Then check for Golden Software surfer grid */
1152 		if (gmtlib_is_srf_grid (GMT, header) == GMT_NOERROR)
1153 			return (GMT_NOERROR);
1154 		/* Then check for NGDC GRD98 grid */
1155 		if (gmtlib_is_mgg2_grid (GMT, header) == GMT_NOERROR)
1156 			return (GMT_NOERROR);
1157 		/* Then check for AGC grid */
1158 		if (gmtlib_is_agc_grid (GMT, header) == GMT_NOERROR)
1159 			return (GMT_NOERROR);
1160 		/* Then check for ESRI grid */
1161 		if (gmtlib_is_esri_grid (GMT, header) == GMT_NOERROR)
1162 			return (GMT_NOERROR);
1163 		/* Rule out dumb *.txt and *.lis files before GDAL checks to avoid dumb error message */
1164 		ext = gmt_get_ext (file);
1165 		if (ext && (!strcmp (ext, "txt") || !strcmp (ext, "lis")))
1166 			return (GMT_GRDIO_UNKNOWN_FORMAT);
1167 #ifdef HAVE_GDAL
1168 		/* Then check for GDAL grid */
1169 		if (gmtlib_is_gdal_grid (GMT, header) == GMT_NOERROR)
1170 			return (GMT_NOERROR);
1171 #endif
1172 		return (GMT_GRDIO_UNKNOWN_FORMAT);	/* No supported format found */
1173 	}
1174 	else {			/* Writing: get format type, scale, offset and missing value from GMT->current.setting.io_gridfile_format */
1175 		if (sscanf (HH->name, "%[^?]?%s", tmp, HH->varname) > 1)
1176 			strncpy (HH->name, tmp, GMT_LEN256-1);    /* Strip off variable name */
1177 		/* parse grid format string: */
1178 		if ((val = gmtgrdio_parse_grd_format_scale (GMT, header, GMT->current.setting.io_gridfile_format)) != GMT_NOERROR)
1179 			return val;
1180 	}
1181 	if (header->type == GMT_GRID_IS_AF)
1182 		header->nan_value = 0.0f; /* NaN value for AGC format */
1183 	return (GMT_NOERROR);
1184 }
1185 
gmtlib_grd_set_units(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header)1186 void gmtlib_grd_set_units (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header) {
1187 	/* Set unit strings for grid coordinates x, y and z based on
1188 	   output data types for columns 0, 1, and 2.
1189 	*/
1190 	unsigned int i;
1191 	char *string[3] = {NULL, NULL, NULL}, unit[GMT_GRID_UNIT_LEN80] = {""};
1192 	char date[GMT_LEN16] = {""}, clock[GMT_LEN16] = {""};
1193 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
1194 
1195 	/* Copy pointers to unit strings */
1196 	string[0] = header->x_units;
1197 	string[1] = header->y_units;
1198 	string[2] = header->z_units;
1199 
1200 	/* Use input data type as backup for output data type */
1201 	for (i = 0; i < 3; i++)
1202 		if (gmt_M_type (GMT, GMT_OUT, i) == GMT_IS_UNKNOWN) GMT->current.io.col_type[GMT_OUT][i] = GMT->current.io.col_type[GMT_IN][i];
1203 
1204 	/* Catch some anomalies */
1205 	if (gmt_M_type (GMT, GMT_OUT, GMT_X) == GMT_IS_LAT && gmt_M_type (GMT, GMT_OUT, GMT_Y) == GMT_IS_LAT) {
1206 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Output type for X-coordinate of grid %s is LAT. Replaced by LON.\n", HH->name);
1207 		gmt_set_column_type (GMT, GMT_OUT, GMT_X, GMT_IS_LON);
1208 
1209 	}
1210 	if (gmt_M_type (GMT, GMT_OUT, GMT_Y) == GMT_IS_LON && gmt_M_type (GMT, GMT_OUT, GMT_X) == GMT_IS_LON) {
1211 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Output type for Y-coordinate of grid %s is LON. Replaced by LAT.\n", HH->name);
1212 		gmt_set_column_type (GMT, GMT_OUT, GMT_Y, GMT_IS_LAT);
1213 	}
1214 
1215 	/* Set unit strings one by one based on output type */
1216 	for (i = 0; i < 3; i++) {
1217 		switch (gmt_M_type (GMT, GMT_OUT, i)) {
1218 			case GMT_IS_LON:
1219 				strcpy (string[i], "longitude [degrees_east]"); break;
1220 			case GMT_IS_LAT:
1221 				strcpy (string[i], "latitude [degrees_north]"); break;
1222 			case GMT_IS_ABSTIME:
1223 			case GMT_IS_RELTIME:
1224 			case GMT_IS_RATIME:
1225 				/* Determine time unit */
1226 				switch (GMT->current.setting.time_system.unit) {
1227 					case 'y':
1228 						strcpy (unit, "years"); break;
1229 					case 'o':
1230 						strcpy (unit, "months"); break;
1231 					case 'd':
1232 						strcpy (unit, "days"); break;
1233 					case 'h':
1234 						strcpy (unit, "hours"); break;
1235 					case 'm':
1236 						strcpy (unit, "minutes"); break;
1237 					default:
1238 						strcpy (unit, "seconds"); break;
1239 				}
1240 				gmt_format_calendar (GMT, date, clock, &GMT->current.io.date_output, &GMT->current.io.clock_output, false, 1, 0.0);
1241 				snprintf (string[i], GMT_GRID_UNIT_LEN80, "time [%s since %s %s]", unit, date, clock);
1242 				/* Warning for non-double grids */
1243 				if (i == 2 && header->n_bands == 1 && GMT->session.grdformat[header->type][1] != 'd')
1244 					GMT_Report (GMT->parent, GMT_MSG_WARNING, "Use double precision output grid to avoid loss of significance of time coordinate.\n");
1245 				break;
1246 		}
1247 	}
1248 }
1249 
gmtgrdio_pad_status(struct GMT_CTRL * GMT,unsigned int * pad)1250 bool gmtgrdio_pad_status (struct GMT_CTRL *GMT, unsigned int *pad) {
1251 	unsigned int side;
1252 	gmt_M_unused(GMT);
1253 	for (side = 0; side < 4; side++) if (pad[side]) return (true);	/* Grid has a pad */
1254 	return (false);	/* Grid has no pad */
1255 }
1256 
gmt_grd_pad_status(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,unsigned int * pad)1257 bool gmt_grd_pad_status (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, unsigned int *pad) {
1258 	/* Determines if this grid has padding at all (pad = NULL) OR
1259 	 * if pad is given, determines if the pads are different.
1260 	 * Return codes are:
1261 	 * 1) If pad == NULL:
1262 	 *    false: Grid has zero padding.
1263 	 *    true:  Grid has non-zero padding.
1264 	 * 2) If pad contains the desired pad:
1265 	 *    true:  Grid padding matches pad exactly.
1266 	 *    false: Grid padding failed to match pad exactly.
1267 	 */
1268 	unsigned int side;
1269 	gmt_M_unused(GMT);
1270 
1271 	if (pad) {	/* Determine if the grid's pad differ from given pad (false) or not (true) */
1272 		for (side = 0; side < 4; side++) if (header->pad[side] != pad[side]) return (false);	/* Pads differ */
1273 		return (true);	/* Pads match */
1274 	}
1275 	else	/* We just want to determine if the grid has padding already (true) or not (false) */
1276 		return (gmtgrdio_pad_status (GMT, header->pad));
1277 }
1278 
gmtlib_get_matrixtype(struct GMT_CTRL * GMT,unsigned int direction,struct GMT_MATRIX * M)1279 int gmtlib_get_matrixtype (struct GMT_CTRL *GMT, unsigned int direction, struct GMT_MATRIX *M) {
1280 	/* Determine if input or output matrix is Cartesian or geographic, and if so if longitude range is <360, ==360, or >360 */
1281 	char *dir[2] = {"input", "output"};
1282 	if (gmt_M_x_is_lon (GMT, direction)) {	/* Data set is geographic with x = longitudes */
1283 		if (fabs (M->range[XHI] - M->range[XLO] - 360.0) < GMT_CONV4_LIMIT) {
1284 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s matrix, longitudes span exactly 360\n", dir[direction]);
1285 			/* If w/e is 360 and gridline reg then we have a repeat entry for 360.  For pixel there are never repeat pixels */
1286 			return ((M->registration == GMT_GRID_NODE_REG) ? GMT_GRID_GEOGRAPHIC_EXACT360_REPEAT : GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT);
1287 		}
1288 		else if (fabs (M->n_columns * M->inc[GMT_X] - 360.0) < GMT_CONV4_LIMIT) {
1289 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s matrix, longitude cells span exactly 360\n", dir[direction]);
1290 			/* If n*xinc = 360 and previous test failed then we do not have a repeat node */
1291 			return (GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT);
1292 		}
1293 		else if ((M->range[XHI] - M->range[XLO]) > 360.0) {
1294 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s matrix, longitudes span more than 360\n", dir[direction]);
1295 			return (GMT_GRID_GEOGRAPHIC_MORE360);
1296 		}
1297 		else {
1298 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s matrix, longitudes span less than 360\n", dir[direction]);
1299 			return (GMT_GRID_GEOGRAPHIC_LESS360);
1300 		}
1301 	}
1302 	else if (M->range[YLO] >= -90.0 && M->range[YHI] <= 90.0) {	/* Here we simply advice the user if matrix looks like geographic but is not set as such */
1303 		if (fabs (M->range[XHI] - M->range[XLO] - 360.0) < GMT_CONV4_LIMIT) {
1304 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s matrix, yet x spans exactly 360 and -90 <= y <= 90.\n", dir[direction]);
1305 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "     To make sure the matrix is recognized as geographical and global, use the -fg option\n");
1306 			return (GMT_GRID_CARTESIAN);
1307 		}
1308 		else if (fabs (M->n_columns * M->inc[GMT_X] - 360.0) < GMT_CONV4_LIMIT) {
1309 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s matrix, yet x cells span exactly 360 and -90 <= y <= 90.\n", dir[direction]);
1310 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "     To make sure the matrix is recognized as geographical and global, use the -fg option\n");
1311 			return (GMT_GRID_CARTESIAN);
1312 		}
1313 	}
1314 	GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s matrix\n", dir[direction]);
1315 	return (GMT_GRID_CARTESIAN);
1316 }
1317 
gmtlib_get_grdtype(struct GMT_CTRL * GMT,unsigned int direction,struct GMT_GRID_HEADER * h)1318 int gmtlib_get_grdtype (struct GMT_CTRL *GMT, unsigned int direction, struct GMT_GRID_HEADER *h) {
1319 	/* Determine if input or output grid is Cartesian or geographic, and if so if longitude range is <360, ==360, or >360 */
1320 	char *dir[2] = {"input", "output"};
1321 	if (gmt_M_x_is_lon (GMT, direction)) {	/* Data set is geographic with x = longitudes */
1322 		if (fabs (h->wesn[XHI] - h->wesn[XLO] - 360.0) < GMT_CONV4_LIMIT) {
1323 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s grid, longitudes span exactly 360\n", dir[direction]);
1324 			/* If w/e is 360 and gridline reg then we have a repeat entry for 360.  For pixel there are never repeat pixels */
1325 			return ((h->registration == GMT_GRID_NODE_REG) ? GMT_GRID_GEOGRAPHIC_EXACT360_REPEAT : GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT);
1326 		}
1327 		else if (fabs (h->n_columns * h->inc[GMT_X] - 360.0) < GMT_CONV4_LIMIT) {
1328 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s grid, longitude cells span exactly 360\n", dir[direction]);
1329 			/* If n*xinc = 360 and previous test failed then we do not have a repeat node */
1330 			return (GMT_GRID_GEOGRAPHIC_EXACT360_NOREPEAT);
1331 		}
1332 		else if ((h->wesn[XHI] - h->wesn[XLO]) > 360.0) {
1333 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s grid, longitudes span more than 360\n", dir[direction]);
1334 			return (GMT_GRID_GEOGRAPHIC_MORE360);
1335 		}
1336 		else {
1337 			GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Geographic %s grid, longitudes span less than 360\n", dir[direction]);
1338 			return (GMT_GRID_GEOGRAPHIC_LESS360);
1339 		}
1340 	}
1341 	else if (h->wesn[YLO] >= -90.0 && h->wesn[YHI] <= 90.0) {	/* Here we simply advice the user if grid looks like geographic but is not set as such */
1342 		if (fabs (h->wesn[XHI] - h->wesn[XLO] - 360.0) < GMT_CONV4_LIMIT) {
1343 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s grid, yet x spans exactly 360 and -90 <= y <= 90.\n", dir[direction]);
1344 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "     To make sure the grid is recognized as geographical and global, use the -fg option\n");
1345 			return (GMT_GRID_CARTESIAN);
1346 		}
1347 		else if (fabs (h->n_columns * h->inc[GMT_X] - 360.0) < GMT_CONV4_LIMIT) {
1348 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s grid, yet x cells span exactly 360 and -90 <= y <= 90.\n", dir[direction]);
1349 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "     To make sure the grid is recognized as geographical and global, use the -fg option\n");
1350 			return (GMT_GRID_CARTESIAN);
1351 		}
1352 	}
1353 	GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Cartesian %s grid\n", dir[direction]);
1354 	return (GMT_GRID_CARTESIAN);
1355 }
1356 
gmtgrdio_doctor_geo_increments(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header)1357 GMT_LOCAL void gmtgrdio_doctor_geo_increments (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header) {
1358 	/* Check for sloppy arc min/sec increments due to divisions by 60 or 3600 */
1359 	double round_inc[2], scale[2], inc, slop;
1360 	unsigned int side, n_fix = 0;
1361 	static char *type[2] = {"longitude", "latitude"};
1362 
1363 	GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Call gmtgrdio_doctor_geo_increments on a geographic grid\n");
1364 	for (side = GMT_X; side <= GMT_Y; side++) {	/* Check both increments */
1365 		scale[side] = (header->inc[side] < GMT_MIN2DEG) ? 3600.0 : 60.0;	/* Check for clean multiples of minutes or seconds */
1366 		inc = header->inc[side] * scale[side];
1367 		round_inc[side] = rint (inc);
1368 		slop = fabs (inc - round_inc[side]);
1369 		if (slop > 0 && slop < GMT_CONV4_LIMIT) n_fix++;
1370 	}
1371 	if (n_fix == 2) {
1372 		for (side = GMT_X; side <= GMT_Y; side++) {	/* Check both increments */
1373 			inc = header->inc[side];
1374 			header->inc[side] = round_inc[side] / scale[side];
1375 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Round-off patrol changed geographic grid increment for %s from %.18g to %.18g\n",
1376 				type[side], inc, header->inc[side]);
1377 		}
1378 	}
1379 }
1380 
gmtgrdio_round_off_patrol(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header)1381 GMT_LOCAL void gmtgrdio_round_off_patrol (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header) {
1382 	/* This function is called after the read info functions return.  We use it to make
1383 	 * sure there are no tiny inconsistencies between grid increments and limits, and
1384 	 * also check that geographic latitudes are within bounds. For geographic data we
1385 	 * also examine if the increment * 60 or 3600 is very close (< 1e-4) to an integer,
1386 	 * in which case we reset it to the exact reciprocal value. */
1387 	unsigned int k;
1388 	double norm_v, round_v, d, slop;
1389 	static char *type[4] = {"xmin", "xmax", "ymin", "ymax"};
1390 
1391 	if (gmt_M_x_is_lon (GMT, GMT_IN) && (header->wesn[XHI] - header->wesn[XLO] - header->inc[GMT_X]) <= 360.0) {	/* Correct any slop in geographic increments */
1392 		gmtgrdio_doctor_geo_increments (GMT, header);
1393 		if (gmt_M_y_is_lat (GMT, GMT_IN)) {
1394 			if ((header->wesn[YLO]+90.0) < (-GMT_CONV4_LIMIT*header->inc[GMT_Y]))
1395 				GMT_Report (GMT->parent, GMT_MSG_WARNING, "Round-off patrol found south latitude outside valid range (%.16g)!\n", header->wesn[YLO]);
1396 			if ((header->wesn[YHI]-90.0) > (GMT_CONV4_LIMIT*header->inc[GMT_Y]))
1397 				GMT_Report (GMT->parent, GMT_MSG_WARNING, "Round-off patrol found north latitude outside valid range (%.16g)!\n", header->wesn[YHI]);
1398 		}
1399 	}
1400 
1401 	/* If boundaries are close to multiple of inc/2 fix them */
1402 	for (k = XLO; k <= YHI; k++) {	/* Check all limits for closeness to 0.5*increments */
1403 		d = 0.5 * ((k < YLO) ? header->inc[GMT_X] : header->inc[GMT_Y]);
1404 		norm_v = header->wesn[k] / d;
1405 		round_v = rint (norm_v);
1406 		slop = fabs (norm_v - round_v);
1407 		if (slop > GMT_CONV12_LIMIT && slop < GMT_CONV4_LIMIT) {	/* Ignore super tiny-slop and larger mismatches */
1408 			header->wesn[k] = round_v * d;
1409 			norm_v = header->wesn[k];
1410 			GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Round-off patrol changed grid limit for %s from %.16g to %.16g\n",
1411 				type[k], norm_v, header->wesn[k]);
1412 		}
1413 	}
1414 }
1415 
gmtlib_read_grd_info(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header)1416 int gmtlib_read_grd_info (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header) {
1417 	/* file:	File name
1418 	 * header:	grid structure header
1419 	 * Note: The header reflects what is actually in the file, and all the dimensions
1420 	 * reflect the number of rows, cols, size, pads etc.  However, if gmtlib_read_grd is
1421 	 * called requesting a subset then these will be reset accordingly.
1422 	 */
1423 
1424 	int err;	/* Implied by gmt_M_err_trap */
1425 	unsigned int n_columns, n_rows;
1426 	double scale, offset;
1427 	gmt_grdfloat invalid;
1428 	struct GMT_GRID_HEADER_HIDDEN *HH = NULL;
1429 
1430 	gmt_M_err_trap (gmt_grd_get_format (GMT, file, header, true));	/* Get format and also parse any +s<scl> +o<offset> +n<nan> modifiers */
1431 	HH = gmt_get_H_hidden (header);
1432 
1433 	/* remember scale, offset, and invalid: */
1434 	scale = header->z_scale_factor;
1435 	offset = header->z_add_offset;
1436 	invalid = header->nan_value;
1437 
1438 	gmt_M_err_trap ((*GMT->session.readinfo[header->type]) (GMT, header));
1439 	GMT_Set_Index (GMT->parent, header, GMT_GRID_LAYOUT);
1440 
1441 	gmtgrdio_grd_xy_scale (GMT, header, GMT_IN);	/* Possibly scale wesn,inc */
1442 
1443 	/* restore non-default scale, offset, and invalid: */
1444 	if (HH->z_scale_given)	/* User used +s<scl> */
1445 		header->z_scale_factor = scale;
1446 	if (HH->z_offset_given)	/* User used +s<off> */
1447 		header->z_add_offset = offset;
1448 	if (isfinite(invalid))	/* Means user used +n<invalid> */
1449 		header->nan_value = invalid;
1450 
1451 	gmtlib_grd_get_units (GMT, header);
1452 	if (strncmp (GMT->init.module_name, "grdedit", 7U))
1453 		gmtgrdio_round_off_patrol (GMT, header);	/* Ensure limit/inc consistency */
1454 	//gmtlib_clean_global_headers (GMT, header);
1455 
1456 	if (header->ProjRefPROJ4 && strstr (header->ProjRefPROJ4, "longlat"))	/* A geographic image perhaps */
1457 		gmt_set_geographic (GMT, GMT_IN);
1458 
1459 	HH->grdtype = gmtlib_get_grdtype (GMT, GMT_IN, header);
1460 
1461 	gmt_M_err_pass (GMT, gmt_grd_RI_verify (GMT, header, 0), file);
1462 	n_columns = header->n_columns;	n_rows = header->n_rows;	/* Save copy */
1463 	gmt_set_grddim (GMT, header);	/* Set all integer dimensions and xy_off */
1464 
1465 	/* Sanity check for grid that may have been created oddly.  Inspired by
1466 	 * Geomapapp output where -R was set to outside of pixel boundaries instead
1467 	 * of standard -R settings, yet with node_offset = gridline... */
1468 
1469 	if (abs((int)(header->n_columns - n_columns)) == 1 && abs((int)(header->n_rows - n_rows)) == 1) {
1470        		header->n_columns = n_columns;    header->n_rows = n_rows;
1471  		if (header->registration == GMT_GRID_PIXEL_REG) {
1472  			header->registration = GMT_GRID_NODE_REG;
1473 			GMT_Report (GMT->parent, GMT_MSG_WARNING, "Grid has wrong registration type. Switching from pixel to gridline registration\n");
1474 		}
1475 		else {
1476  			header->registration = GMT_GRID_PIXEL_REG;
1477 			GMT_Report (GMT->parent, GMT_MSG_WARNING, "Grid has wrong registration type. Switching from gridline to pixel registration\n");
1478 		}
1479 	}
1480 
1481 	/* unpack z-range: */
1482 	header->z_min = header->z_min * header->z_scale_factor + header->z_add_offset;
1483 	header->z_max = header->z_max * header->z_scale_factor + header->z_add_offset;
1484 
1485 	return (GMT_NOERROR);
1486 }
1487 
gmtlib_write_grd_info(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header)1488 int gmtlib_write_grd_info (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header) {
1489 	/* file:	File name
1490 	 * header:	grid structure header
1491 	 */
1492 
1493 	int err;	/* Implied by gmt_M_err_trap */
1494 
1495 	gmt_M_err_trap (gmt_grd_get_format (GMT, file, header, false));
1496 
1497 	gmtgrdio_grd_xy_scale (GMT, header, GMT_OUT);	/* Possibly scale wesn,inc */
1498 	/* pack z-range: */
1499 	header->z_min = (header->z_min - header->z_add_offset) / header->z_scale_factor;
1500 	header->z_max = (header->z_max - header->z_add_offset) / header->z_scale_factor;
1501 	return ((*GMT->session.writeinfo[header->type]) (GMT, header));
1502 }
1503 
gmt_update_grd_info(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header)1504 int gmt_update_grd_info (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header) {
1505 	/* file:	- IGNORED -
1506 	 * header:	grid structure header
1507 	 */
1508 
1509 	/* pack z-range: */
1510 	gmt_M_unused(file);
1511 	header->z_min = (header->z_min - header->z_add_offset) / header->z_scale_factor;
1512 	header->z_max = (header->z_max - header->z_add_offset) / header->z_scale_factor;
1513 	return ((*GMT->session.updateinfo[header->type]) (GMT, header));
1514 }
1515 
gmtlib_read_grd(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,double * wesn,unsigned int * pad,int complex_mode)1516 int gmtlib_read_grd (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, double *wesn, unsigned int *pad, int complex_mode) {
1517 	/* file:	- IGNORED -
1518 	 * header:	grid structure header
1519 	 * grid:	array with final grid
1520 	 * wesn:	Sub-region to extract  [Use entire file if NULL or contains 0,0,0,0]
1521 	 * padding:	# of empty rows/columns to add on w, e, s, n of grid, respectively
1522 	 * complex_mode:	&1 | &2 if complex array is to hold real (1) and imaginary (2) parts (otherwise read as real only)
1523 	 *		Note: The file has only real values, we simply allow space in the array
1524 	 *		for imaginary parts when processed by grdfft etc.
1525 	 */
1526 
1527 	bool expand;		/* true or false */
1528 	int err = GMT_OK;		/* Implied by gmt_M_err_trap */
1529 	struct GRD_PAD P;
1530 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
1531 
1532 	complex_mode &= GMT_GRID_IS_COMPLEX_MASK;	/* Remove any non-complex flags */
1533 	/* If we are reading a 2nd grid (e.g., real, then imag) we must update info about the file since it will be a different file */
1534 	if (header->complex_mode && (header->complex_mode & complex_mode) == 0) gmt_M_err_trap (gmt_grd_get_format (GMT, file, header, true));
1535 
1536 	expand = gmtgrdio_padspace (GMT, header, wesn, false, pad, &P);	/* true if we can extend the region by the pad-size to obtain real data for BC */
1537 
1538 	if ((err = gmtgrdio_grd_layout (GMT, header, grid, complex_mode & GMT_GRID_IS_COMPLEX_MASK, GMT_IN)))	/* Deal with complex layout */
1539 		return err;
1540 
1541 	gmt_M_err_trap ((*GMT->session.readgrd[header->type]) (GMT, header, grid, P.wesn, P.pad, complex_mode));
1542 
1543 	if (header->z_min == DBL_MAX && header->z_max == -DBL_MAX) /* No valid data values in the grid */
1544 		header->z_min = header->z_max = NAN;
1545 	if (expand) /* Must undo the region extension and reset n_columns, n_rows using original pad  */
1546 		gmt_M_memcpy (header->wesn, wesn, 4, double);
1547 	gmt_M_grd_setpad (GMT, header, pad);	/* Copy the pad to the header */
1548 	gmt_set_grddim (GMT, header);		/* Update all dimensions */
1549 	HH->grdtype = gmtlib_get_grdtype (GMT, GMT_IN, header);	/* Since may change if a subset */
1550 	if (expand) gmt_grd_zminmax (GMT, header, grid);	/* Reset min/max since current extrema includes the padded region */
1551 	gmtgrdio_pack_grid (GMT, header, grid, k_grd_unpack); /* revert scale and offset */
1552 	gmt_BC_init (GMT, header);	/* Initialize grid interpolation and boundary condition parameters */
1553 
1554 	return (GMT_NOERROR);
1555 }
1556 
gmtlib_write_grd(struct GMT_CTRL * GMT,char * file,struct GMT_GRID_HEADER * header,gmt_grdfloat * grid,double * wesn,unsigned int * pad,int complex_mode)1557 int gmtlib_write_grd (struct GMT_CTRL *GMT, char *file, struct GMT_GRID_HEADER *header, gmt_grdfloat *grid, double *wesn, unsigned int *pad, int complex_mode) {
1558 	/* file:	File name
1559 	 * header:	grid structure header
1560 	 * grid:	array with final grid
1561 	 * wesn:	Sub-region to write out  [Use entire file if NULL or contains 0,0,0,0]
1562 	 * padding:	# of empty rows/columns to add on w, e, s, n of grid, respectively
1563 	 * complex_mode:	&1 | &2 if complex array is to hold real (1) and imaginary (2) parts (otherwise read as real only)
1564 	 *		Note: The file has only real values, we simply allow space in the array
1565 	 *		for imaginary parts when processed by grdfft etc.
1566 	 */
1567 
1568 	int err = GMT_OK;	/* Implied by gmt_M_err_trap */
1569 
1570 	gmt_M_err_trap (gmt_grd_get_format (GMT, file, header, false));
1571 	gmtgrdio_pack_grid (GMT, header, grid, k_grd_pack); /* scale and offset */
1572 	gmtgrdio_grd_xy_scale (GMT, header, GMT_OUT);	/* Possibly scale wesn,inc */
1573 
1574 	if ((err = gmtgrdio_grd_layout (GMT, header, grid, complex_mode, GMT_OUT)))	/* Deal with complex layout */
1575 		return (err);
1576 	gmtgrdio_grd_check_consistency (GMT, header, grid);			/* Fix east repeating columns and polar values */
1577 	err = (*GMT->session.writegrd[header->type]) (GMT, header, grid, wesn, pad, complex_mode);
1578 	if (GMT->parent->leave_grid_scaled == 0) gmtgrdio_pack_grid (GMT, header, grid, k_grd_unpack); /* revert scale and offset to leave grid as it was before writing unless session originated from gm*/
1579 	return (err);
1580 }
1581 
gmtlib_grd_data_size(struct GMT_CTRL * GMT,unsigned int format,gmt_grdfloat * nan_value)1582 size_t gmtlib_grd_data_size (struct GMT_CTRL *GMT, unsigned int format, gmt_grdfloat *nan_value) {
1583 	/* Determine size of data type and set NaN value, if not yet done so (integers only) */
1584 
1585 	switch (GMT->session.grdformat[format][1]) {
1586 		case 'b':
1587 			if (isnan (*nan_value)) *nan_value = CHAR_MIN;
1588 			return (sizeof (char));
1589 			break;
1590 		case 's':
1591 			if (isnan (*nan_value)) *nan_value = SHRT_MIN;
1592 			return (sizeof (int16_t));
1593 			break;
1594 		case 'i':
1595 			if (isnan (*nan_value)) *nan_value = INT_MIN;
1596 			/* Intentionally fall through */
1597 		case 'm':
1598 			return (sizeof (int32_t));
1599 			break;
1600 		case 'f':
1601 			return (sizeof (float));
1602 			break;
1603 		case 'd':
1604 			return (sizeof (double));
1605 			break;
1606 		default:
1607 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Unknown grid data type: %c\n", GMT->session.grdformat[format][1]);
1608 			return (GMT_GRDIO_UNKNOWN_TYPE);
1609 	}
1610 }
1611 
gmt_grd_set_ij_inc(struct GMT_CTRL * GMT,unsigned int n_columns,int * ij_inc)1612 void gmt_grd_set_ij_inc (struct GMT_CTRL *GMT, unsigned int n_columns, int *ij_inc) {
1613 	/* Set increments to the 4 nodes with ij as lower-left node, from a node at (i,j).
1614 	 * n_columns may be header->n_columns or header->mx depending on pad */
1615 	int s_nx = n_columns;	/* A signed version */
1616 	gmt_M_unused(GMT);
1617 	ij_inc[0] = 0;		/* No offset relative to itself */
1618 	ij_inc[1] = 1;		/* The node one column to the right relative to ij */
1619 	ij_inc[2] = 1 - s_nx;	/* The node one column to the right and one row up relative to ij */
1620 	ij_inc[3] = -s_nx;	/* The node one row up relative to ij */
1621 }
1622 
gmt_grd_format_decoder(struct GMT_CTRL * GMT,const char * code,unsigned int * type_id)1623 int gmt_grd_format_decoder (struct GMT_CTRL *GMT, const char *code, unsigned int *type_id) {
1624 	/* Returns the integer grid format ID that goes with the specified 2-character code */
1625 	if (isdigit ((int)code[0])) {
1626 		/* File format number given, look for old code */
1627 		unsigned id_candidate = (unsigned) abs (atoi (code));
1628 		if (id_candidate > 0 && id_candidate < GMT_N_GRD_FORMATS) {
1629 			*type_id = id_candidate;
1630 			return GMT_NOERROR;
1631 		}
1632 	}
1633 	else {
1634 		/* Character code given */
1635 		unsigned i;
1636 		for (i = 1; i < GMT_N_GRD_FORMATS; i++) {
1637 			if (strncmp (GMT->session.grdformat[i], code, 2) == 0) {
1638 				*type_id = i;
1639 				return GMT_NOERROR;
1640 			}
1641 		}
1642 	}
1643 
1644 	return GMT_GRDIO_UNKNOWN_ID;
1645 }
1646 
gmt_grd_RI_verify(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,unsigned int mode)1647 int gmt_grd_RI_verify (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, unsigned int mode) {
1648 	/* mode - 0 means we are checking an existing grid, mode = 1 means we test a new -R -I combination */
1649 	/* gmt_grd_RI_verify -- routine to check grd R and I compatibility
1650 	 *
1651 	 * Author:	W H F Smith
1652 	 * Date:	20 April 1998
1653 	 */
1654 
1655 	unsigned int error = 0, level = (mode == 0) ? GMT_MSG_ERROR : GMT_MSG_WARNING;
1656 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
1657 
1658 	if (!strcmp (GMT->init.module_name, "grdedit")) return (GMT_NOERROR);	/* Separate handling in grdedit to allow grdedit -A */
1659 
1660 	switch (gmt_minmaxinc_verify (GMT, h->wesn[XLO], h->wesn[XHI], h->inc[GMT_X], GMT_CONV4_LIMIT)) {
1661 		case 3:
1662 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Grid x increment <= 0.0\n");
1663 			error++;
1664 			break;
1665 		case 2:
1666 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Grid x range <= 0.0\n");
1667 			if (gmt_M_is_geographic (GMT, GMT_IN)) GMT_Report (GMT->parent, GMT_MSG_ERROR,
1668 			                         "Make sure west < east for geographic coordinates\n");
1669 			error++;
1670 			break;
1671 		case 1:
1672 			if (HH->var_spacing[GMT_X] == 0) {
1673 				GMT_Report (GMT->parent, level,
1674 			            "(x_max-x_min) must equal (NX + eps) * x_inc), where NX is an integer and |eps| <= %g.\n", GMT_CONV4_LIMIT);
1675 				error++;
1676 			}
1677 		default:
1678 			/* Everything is OK */
1679 			break;
1680 	}
1681 
1682 	switch (gmt_minmaxinc_verify (GMT, h->wesn[YLO], h->wesn[YHI], h->inc[GMT_Y], GMT_CONV4_LIMIT)) {
1683 		case 3:
1684 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Grid y increment <= 0.0\n");
1685 			error++;
1686 			break;
1687 		case 2:
1688 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Grid y range <= 0.0\n");
1689 			error++;
1690 			break;
1691 		case 1:
1692 			if (HH->var_spacing[GMT_Y] == 0) {
1693 				GMT_Report (GMT->parent, level,
1694 			            "(y_max-y_min) must equal (NY + eps) * y_inc), where NY is an integer and |eps| <= %g.\n", GMT_CONV4_LIMIT);
1695 				error++;
1696 			}
1697 		default:
1698 			/* Everything is OK */
1699 			break;
1700 	}
1701 	if (error) return ((mode == 0) ? GMT_GRDIO_RI_OLDBAD : GMT_GRDIO_RI_NEWBAD);
1702 
1703 	/* Final polish for geo grids that are global to ensure clean -R settings for the cases -Rg and -Rd */
1704 
1705 	if (gmt_M_x_is_lon (GMT, GMT_IN)) {
1706 		if (fabs (h->wesn[XLO]) < GMT_CONV12_LIMIT) h->wesn[XLO] = 0.0;
1707 		else if (fabs (180.0+h->wesn[XLO]) < GMT_CONV12_LIMIT) h->wesn[XLO] = -180.0;
1708 		else if (fabs (h->wesn[XLO]-180.0) < GMT_CONV12_LIMIT) h->wesn[XLO] = +180.0;
1709 		else if (fabs (h->wesn[XLO]-360.0) < GMT_CONV12_LIMIT) h->wesn[XLO] = +360.0;
1710 		if (fabs (h->wesn[XHI]) < GMT_CONV12_LIMIT) h->wesn[XHI] = 0.0;
1711 		else if (fabs (180.0+h->wesn[XHI]) < GMT_CONV12_LIMIT) h->wesn[XHI] = -180.0;
1712 		else if (fabs (h->wesn[XHI]-180.0) < GMT_CONV12_LIMIT) h->wesn[XHI] = +180.0;
1713 		else if (fabs (h->wesn[XHI]-360.0) < GMT_CONV12_LIMIT) h->wesn[XHI] = +360.0;
1714 	}
1715 	if (gmt_M_y_is_lat (GMT, GMT_IN)) {
1716 		if (fabs (90.0+h->wesn[YLO]) < GMT_CONV12_LIMIT) h->wesn[YLO] = -90.0;
1717 		if (fabs (h->wesn[YLO]-90.0) < GMT_CONV12_LIMIT) h->wesn[YLO] = +90.0;
1718 	}
1719 	return (GMT_NOERROR);
1720 }
1721 
gmt_grd_prep_io(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,double wesn[],unsigned int * width,unsigned int * height,int * first_col,int * last_col,int * first_row,int * last_row,unsigned int ** index)1722 int gmt_grd_prep_io (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, double wesn[], unsigned int *width, unsigned int *height, int *first_col, int *last_col, int *first_row, int *last_row, unsigned int **index) {
1723 	/* Determines which rows and columns to extract to extract from a grid, based on w,e,s,n.
1724 	 * This routine first rounds the w,e,s,n boundaries to the nearest gridlines or pixels,
1725 	 * then determines the first and last columns and rows, and the width and height of the subset (in cells).
1726 	 * The routine also returns and array of the x-indices in the source grid to be used in the target (subset) grid.
1727 	 * All integers represented positive definite items hence unsigned variables.
1728 	 */
1729 
1730 	bool geo = false;
1731 	unsigned int one_or_zero, col, *actual_col = NULL;	/* Column numbers */
1732 	double small = 0.1, half_or_zero, x;
1733 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
1734 
1735 	GMT_Report (GMT->parent, GMT_MSG_DEBUG, "region: %g %g, grid: %g %g\n", wesn[XLO], wesn[XHI], header->wesn[XLO], header->wesn[XHI]);
1736 
1737 	half_or_zero = (header->registration == GMT_GRID_PIXEL_REG) ? 0.5 : 0.0;
1738 
1739 	if (!gmt_M_is_subset (GMT, header, wesn)) {	/* Get entire file */
1740 		*width  = header->n_columns;
1741 		*height = header->n_rows;
1742 		*first_col = *first_row = 0;
1743 		*last_col  = header->n_columns - 1;
1744 		*last_row  = header->n_rows - 1;
1745 		gmt_M_memcpy (wesn, header->wesn, 4, double);
1746 	}
1747 	else {				/* Must deal with a subregion */
1748 		if (gmt_M_x_is_lon (GMT, GMT_IN))
1749 			geo = true;	/* Geographic data for sure */
1750 		else if (wesn[XLO] < header->wesn[XLO] || wesn[XHI] > header->wesn[XHI])
1751 			geo = true;	/* Probably dealing with periodic grid */
1752 
1753 		x = fabs (header->wesn[YLO] - wesn[YLO]);	/* if |x| < GMT_CONV4_LIMIT * header->inc[GMT_Y] we set wesn to the grid limit */
1754 		if (x > 0.0 && x < GMT_CONV4_LIMIT * header->inc[GMT_Y]) wesn[YLO] = header->wesn[YLO];	/* Avoid snafu */
1755 		x = fabs (header->wesn[YHI] - wesn[YHI]);	/* if |x| < GMT_CONV4_LIMIT * header->inc[GMT_Y] we set wesn to the grid limit */
1756 		if (x > 0.0 && x < GMT_CONV4_LIMIT * header->inc[GMT_Y]) wesn[YHI] = header->wesn[YHI];	/* Avoid snafu */
1757 
1758 		if (wesn[YLO] < header->wesn[YLO] || wesn[YHI] > header->wesn[YHI]) return (GMT_GRDIO_DOMAIN_VIOLATION);	/* Calling program goofed... */
1759 
1760 		one_or_zero = (header->registration == GMT_GRID_PIXEL_REG) ? 0 : 1;
1761 
1762 		/* Make sure w,e,s,n are proper multiples of x_inc,y_inc away from x_min,y_min */
1763 
1764 		gmt_M_err_pass (GMT, gmt_adjust_loose_wesn (GMT, wesn, header), HH->name);
1765 
1766 		/* Get dimension of subregion */
1767 
1768 		*width  = urint ((wesn[XHI] - wesn[XLO]) * HH->r_inc[GMT_X]) + one_or_zero;
1769 		*height = urint ((wesn[YHI] - wesn[YLO]) * HH->r_inc[GMT_Y]) + one_or_zero;
1770 
1771 		/* Get first and last row and column numbers */
1772 
1773 		*first_col = irint (floor ((wesn[XLO] - header->wesn[XLO]) * HH->r_inc[GMT_X] + small));
1774 		*last_col  = irint (ceil  ((wesn[XHI] - header->wesn[XLO]) * HH->r_inc[GMT_X] - small)) - 1 + one_or_zero;
1775 		*first_row = irint (floor ((header->wesn[YHI] - wesn[YHI]) * HH->r_inc[GMT_Y] + small));
1776 		*last_row  = irint (ceil  ((header->wesn[YHI] - wesn[YLO]) * HH->r_inc[GMT_Y] - small)) - 1 + one_or_zero;
1777 	}
1778 
1779 	actual_col = gmt_M_memory (GMT, NULL, *width, unsigned int);
1780 	if (geo) {
1781 		small = 0.1 * header->inc[GMT_X];
1782 		for (col = 0; col < (*width); col++) {
1783 			x = gmt_M_col_to_x (GMT, col, wesn[XLO], wesn[XHI], header->inc[GMT_X], half_or_zero, *width);
1784 			if (header->wesn[XLO] - x > small)
1785 				x += 360.0;
1786 			else if (x - header->wesn[XHI] > small)
1787 				x -= 360.0;
1788 			actual_col[col] = (unsigned int)gmt_M_grd_x_to_col (GMT, x, header);
1789 		}
1790 	}
1791 	else {	/* Normal ordering */
1792 		for (col = 0; col < (*width); col++) actual_col[col] = (*first_col) + col;
1793 	}
1794 
1795 	*index = actual_col;
1796 	GMT_Report (GMT->parent, GMT_MSG_DEBUG, "-> region: %g %g, grid: %g %g\n", wesn[XLO], wesn[XHI], header->wesn[XLO], header->wesn[XHI]);
1797 	GMT_Report (GMT->parent, GMT_MSG_DEBUG, "row: %d %d, col: %d %d\n", *first_row, *last_row, *first_col, *last_col);
1798 
1799 	return (GMT_NOERROR);
1800 }
1801 
gmtgrdio_decode_grd_h_info_old(struct GMT_CTRL * GMT,char * input,struct GMT_GRID_HEADER * h)1802 GMT_LOCAL void gmtgrdio_decode_grd_h_info_old (struct GMT_CTRL *GMT, char *input, struct GMT_GRID_HEADER *h) {
1803 	/* Given input string, copy elements into string portions of h.
1804 		 By default use "/" as the field separator. However, if the first and
1805 		 last character of the input string is the same AND that character
1806 		 is non-alpha-numeric, use the first character as a separator. This
1807 		 is to allow "/" as part of the fields.
1808 		 If a field is blank [or has an equals sign - backwards compatibility], skip it.
1809 		 This routine is usually called if -D<input> was given by user,
1810 		 and after gmt_grd_init() has been called. */
1811 
1812 	char *ptr, *stringp = input, sep[] = "/";
1813 	bool copy;
1814 	unsigned int entry = 0;
1815 	size_t len = 0;
1816 	double d;
1817 
1818 	if (input[0] != input[strlen(input)-1]) {}
1819 	else if (input[0] == '=') {}
1820 	else if (input[0] >= 'A' && input[0] <= 'Z') {}
1821 	else if (input[0] >= 'a' && input[0] <= 'z') {}
1822 	else if (input[0] >= '0' && input[0] <= '9') {}
1823 	else {
1824 		sep[0] = input[0];
1825 		++stringp; /* advance past first field separator */
1826 	}
1827 
1828 	while ((ptr = strsep (&stringp, sep)) != NULL) { /* using strsep because of possible empty fields */
1829 		if (*ptr != '\0' || strcmp (ptr, "=") == 0 || strcmp (ptr, " ") == 0) { /* entry is not blank or "=" or " " */
1830 			len = strlen (ptr);
1831 			copy = (len > 1 || ptr[0] != '-');	/* Copy unless a "-" was given */
1832 			switch (entry) {
1833 				case 0:
1834 					gmt_M_memset (h->x_units, GMT_GRID_UNIT_LEN80, char);
1835 					if (len >= GMT_GRID_UNIT_LEN80)
1836 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1837 								"X unit string exceeds upper length of %d characters (truncated)\n",
1838 								GMT_GRID_UNIT_LEN80);
1839 					if (copy) strncpy (h->x_units, ptr, GMT_GRID_UNIT_LEN80-1);
1840 					break;
1841 				case 1:
1842 					gmt_M_memset (h->y_units, GMT_GRID_UNIT_LEN80, char);
1843 					if (len >= GMT_GRID_UNIT_LEN80)
1844 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1845 								"Y unit string exceeds upper length of %d characters (truncated)\n",
1846 								GMT_GRID_UNIT_LEN80);
1847 					if (copy) strncpy (h->y_units, ptr, GMT_GRID_UNIT_LEN80-1);
1848 					break;
1849 				case 2:
1850 					gmt_M_memset (h->z_units, GMT_GRID_UNIT_LEN80, char);
1851 					if (len >= GMT_GRID_UNIT_LEN80)
1852 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1853 								"Z unit string exceeds upper length of %d characters (truncated)\n",
1854 								GMT_GRID_UNIT_LEN80);
1855 					if (copy) strncpy (h->z_units, ptr, GMT_GRID_UNIT_LEN80-1);
1856 					break;
1857 				case 3:
1858 				 	d = strtod (ptr, NULL);
1859 					if (d != 0.0) h->z_scale_factor = d;	/* Don't want scale factor to become zero */
1860 					break;
1861 				case 4:
1862 					h->z_add_offset = strtod (ptr, NULL);
1863 					break;
1864 				case 5:
1865 					h->nan_value = strtof (ptr, NULL);
1866 					break;
1867 				case 6:
1868 					gmt_M_memset (h->title, GMT_GRID_TITLE_LEN80, char);
1869 					if (len >= GMT_GRID_TITLE_LEN80)
1870 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1871 								"Title string exceeds upper length of %d characters (truncated)\n",
1872 								GMT_GRID_TITLE_LEN80);
1873 					if (copy) strncpy (h->title, ptr, GMT_GRID_TITLE_LEN80-1);
1874 					break;
1875 				case 7:
1876 					gmt_M_memset (h->remark, GMT_GRID_REMARK_LEN160, char);
1877 					if (len >= GMT_GRID_REMARK_LEN160)
1878 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1879 								"Remark string exceeds upper length of %d characters (truncated)\n",
1880 								GMT_GRID_REMARK_LEN160);
1881 					if (copy) strncpy (h->remark, ptr, GMT_GRID_REMARK_LEN160-1);
1882 					break;
1883 				default:
1884 					break;
1885 			}
1886 		}
1887 		entry++;
1888 	}
1889 }
1890 
gmtgrdio_decode_grdcube_info(struct GMT_CTRL * GMT,char * input,unsigned int dim,struct GMT_GRID_HEADER * h,struct GMT_CUBE * C)1891 GMT_LOCAL int gmtgrdio_decode_grdcube_info (struct GMT_CTRL *GMT, char *input, unsigned int dim, struct GMT_GRID_HEADER *h, struct GMT_CUBE *C) {
1892 	size_t k, n_slash = 0;
1893 	unsigned int uerr = 0;
1894 	bool old = false;
1895 	char *modifiers = "xyzdsontrv", code;
1896 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
1897 
1898 	for (k = 0; k < strlen (input); k++) if (input[k] == '/') n_slash++;
1899 	if (!(input[0] == '+' && gmt_found_modifier (GMT, input, "norstxyz"))) {	/* Cannot be new syntax */
1900 		old = (n_slash > 4);	/* Pretty sure this is the old syntax of that many slashes */
1901 	}
1902 	if (dim == 3 && old) return GMT_PARSE_ERROR;	/* Old syntax does not exist for cubes */
1903 	if (dim < 2 || dim > 3) return GMT_PARSE_ERROR;	/* Not a valid dimension */
1904 	if (old)	/* Old grid syntax: -D<xname>/<yname>/<zname>/<scale>/<offset>/<invalid>/<title>/<remark> */
1905 		gmtgrdio_decode_grd_h_info_old (GMT, input, h);
1906 	else {	/* New syntax: -D[+x<xname>][+yyname>][+z<zname>][+d<dname>][+s<scale>][+o<offset>][+n<invalid>][+t<title>][+r<remark>] plus [+v<name>] for 3D */
1907 		char word[GMT_LEN256] = {""};
1908 		unsigned int pos = 0;
1909 		double d;
1910 		while (gmt_getmodopt (GMT, 'D', input, modifiers, &pos, word, &uerr) && uerr == 0) {
1911 			code = word[0];	/* This is the modifier. Check if 2D and 'z' and change to 'v' */
1912 			if (code == 'z' && dim == 2) code = 'd';	/* Backwards compatibility for using +z with grids */
1913 			switch (code) {
1914 				case 'x':	/* Revise x-unit name */
1915 					gmt_M_memset (h->x_units, GMT_GRID_UNIT_LEN80, char);
1916 					if (strlen(word) > GMT_GRID_UNIT_LEN80)
1917 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1918 							"x_unit string exceeds upper length of %d characters (truncated)\n",
1919 							GMT_GRID_UNIT_LEN80);
1920 					if (word[1]) strncpy (h->x_units, &word[1], GMT_GRID_UNIT_LEN80-1);
1921 					break;
1922 				case 'y':	/* Revise y-unit name */
1923 					gmt_M_memset (h->y_units, GMT_GRID_UNIT_LEN80, char);
1924 					if (strlen(word) > GMT_GRID_UNIT_LEN80)
1925 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1926 							"y_unit string exceeds upper length of %d characters (truncated)\n",
1927 							GMT_GRID_UNIT_LEN80);
1928 					if (word[1]) strncpy (h->y_units, &word[1], GMT_GRID_UNIT_LEN80-1);
1929 					break;
1930 				case 'z':	/* Revise 3rd dim z-unit name for 3-D cubes  */
1931 					gmt_M_memset (C->units, GMT_GRID_UNIT_LEN80, char);
1932 					if (strlen(word) > GMT_GRID_UNIT_LEN80)
1933 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1934 							"z_unit string exceeds upper length of %d characters (truncated)\n",
1935 							GMT_GRID_UNIT_LEN80);
1936 					if (word[1]) strncpy (C->units, &word[1], GMT_GRID_UNIT_LEN80-1);
1937 					break;
1938 				case 'd':	/* Revise 2-D or 3-D data-unit name */
1939 					gmt_M_memset (h->z_units, GMT_GRID_UNIT_LEN80, char);
1940 					if (strlen(word) > GMT_GRID_UNIT_LEN80)
1941 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1942 							"z_unit string exceeds upper length of %d characters (truncated)\n",
1943 							GMT_GRID_UNIT_LEN80);
1944 					if (word[1]) strncpy (h->z_units, &word[1], GMT_GRID_UNIT_LEN80-1);
1945 					break;
1946 				case 's':	/* Revise the scale */
1947 				 	d = strtod (&word[1], NULL);
1948 					if (d != 0.0) h->z_scale_factor = d;	/* Don't want scale factor to become zero */
1949 					break;
1950 				case 'o':	/* Revise the offset */
1951 					h->z_add_offset = strtod (&word[1], NULL);
1952 					break;
1953 				case 'n':	/* Revise the nan-value */
1954 					h->nan_value = strtof (&word[1], NULL);
1955 					break;
1956 				case 't':	/* Revise the title */
1957 					gmt_M_memset (h->title, GMT_GRID_TITLE_LEN80, char);
1958 					if (strlen(word) > GMT_GRID_TITLE_LEN80)
1959 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1960 							"WTitle string exceeds upper length of %d characters (truncated)\n",
1961 							GMT_GRID_TITLE_LEN80);
1962 					if (word[1]) strncpy (h->title, &word[1], GMT_GRID_TITLE_LEN80-1);
1963 					break;
1964 				case 'r':	/* Revise the title */
1965 					gmt_M_memset (h->remark, GMT_GRID_REMARK_LEN160, char);
1966 					if (strlen(word) > GMT_GRID_REMARK_LEN160)
1967 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1968 							"Remark string exceeds upper length of %d characters (truncated)\n",
1969 							GMT_GRID_REMARK_LEN160);
1970 					if (word[1]) strncpy (h->remark, &word[1], GMT_GRID_REMARK_LEN160-1);
1971 					break;
1972 				case 'v':	/* Set the data netCDF variable name */
1973 					gmt_M_memset (HH->varname, GMT_GRID_VARNAME_LEN80, char);
1974 					if (strlen(word) > GMT_GRID_VARNAME_LEN80)
1975 						GMT_Report (GMT->parent, GMT_MSG_WARNING,
1976 							"data variable name exceeds upper length of %d characters (truncated)\n",
1977 							GMT_GRID_VARNAME_LEN80);
1978 					if (word[1]) strncpy (HH->varname, &word[1], GMT_GRID_VARNAME_LEN80-1);
1979 					break;
1980 				default:	/* These are caught in gmt_getmodopt so break is just for Coverity */
1981 					break;
1982 			}
1983 		}
1984 	}
1985 	return (int)uerr;
1986 }
1987 
gmt_decode_grd_h_info(struct GMT_CTRL * GMT,char * input,struct GMT_GRID_HEADER * h)1988 int gmt_decode_grd_h_info (struct GMT_CTRL *GMT, char *input, struct GMT_GRID_HEADER *h) {
1989 	/* Backwards compatible when just dealing with grids */
1990 	return gmtgrdio_decode_grdcube_info (GMT, input, 2U, h, NULL);
1991 }
1992 
gmt_decode_cube_h_info(struct GMT_CTRL * GMT,char * input,struct GMT_CUBE * C)1993 int gmt_decode_cube_h_info (struct GMT_CTRL *GMT, char *input, struct GMT_CUBE *C) {
1994 	/* Backwards compatible when just dealing with grids */
1995 	return gmtgrdio_decode_grdcube_info (GMT, input, 3U, C->header, C);
1996 }
1997 
gmt_grd_set_cartesian(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,unsigned int direction)1998 void gmt_grd_set_cartesian (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, unsigned int direction) {
1999 	/* When we need to turn a geographic grid into a Cartesian grid type.
2000 	 * direction is 0 for input, 1 for output, and 2 for both */
2001 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
2002 	if (direction == GMT_IO) {	/* Set Cartesian for both directions */
2003 		gmt_set_cartesian (GMT, GMT_IN);
2004 		gmt_set_cartesian (GMT, GMT_OUT);
2005 	}
2006 	else
2007 		gmt_set_cartesian (GMT, direction);
2008 	/* Reset the units from degree_longitude/latitude to plain x/y */
2009 	strcpy (h->x_units, "x");
2010 	strcpy (h->y_units, "y");
2011 	HH->grdtype = GMT_GRID_CARTESIAN;	/* Set hidden type to Cartesian */
2012 }
2013 
gmtgrdio_grdcube_info_syntax(struct GMT_CTRL * GMT,char option,unsigned int dim)2014 GMT_LOCAL void gmtgrdio_grdcube_info_syntax (struct GMT_CTRL *GMT, char option, unsigned int dim) {
2015 	/* Display the option for setting grid, cube, or both metadata in grdedit etc. */
2016 	static char *type[3] = {"grid", "cube", "grid or cube"};
2017 	static char *vname[3] = {"z", "cube", "z or cube"};
2018 	unsigned int k = dim - 2;
2019 	struct GMTAPI_CTRL *API = GMT->parent;
2020 	GMT_Usage (API, 1, "\n-%c<information>", option);
2021 	GMT_Usage (API, -2, "Append %s header information as one string composed of one or "
2022 		"more modifiers; items not listed will remain unchanged:", type[k]);
2023 	GMT_Usage (API, 3, "+x Append x-dimension unit <name>, or leave blank to reset.");
2024 	GMT_Usage (API, 3, "+y Append y-dimension unit <name>, or leave blank to reset.");
2025 	if (dim > 2) GMT_Usage (API, 3, "+z Append z-dimension unit <name>, or leave blank to reset.");
2026 	GMT_Usage (API, 3, "+d Append %s data unit <name>, or leave blank to reset.", type[k]);
2027 	GMT_Usage (API, 3, "+n Append a value to represent missing data.", type[k]);
2028 	GMT_Usage (API, 3, "+t Append %s <title>, or leave blank to reset.", type[k]);
2029 	GMT_Usage (API, 3, "+r Append %s <remark>, or leave blank to reset.", type[k]);
2030 	GMT_Usage (API, 3, "+s Append data <scale>.");
2031 	GMT_Usage (API, 3, "+o Append data <offset>.");
2032 	GMT_Usage (API, 3, "+v Append netCDF data variable <name> (if netCDF format) [%s].", vname[k]);
2033 }
2034 
gmt_grd_info_syntax(struct GMT_CTRL * GMT,char option)2035 void gmt_grd_info_syntax (struct GMT_CTRL *GMT, char option) {
2036 	gmtgrdio_grdcube_info_syntax (GMT, option, 2U);
2037 }
2038 
gmt_cube_info_syntax(struct GMT_CTRL * GMT,char option)2039 void gmt_cube_info_syntax (struct GMT_CTRL *GMT, char option) {
2040 	gmtgrdio_grdcube_info_syntax (GMT, option, 3U);
2041 }
gmt_grdcube_info_syntax(struct GMT_CTRL * GMT,char option)2042 void gmt_grdcube_info_syntax (struct GMT_CTRL *GMT, char option) {
2043 	gmtgrdio_grdcube_info_syntax (GMT, option, 4U);
2044 }
2045 
gmt_set_grdinc(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)2046 void gmt_set_grdinc (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
2047 	/* Update grid increments based on w/e/s/n, n_columns/n_rows, and registration */
2048 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
2049 	gmt_M_unused(GMT);
2050 	h->inc[GMT_X] = gmt_M_get_inc (GMT, h->wesn[XLO], h->wesn[XHI], h->n_columns, h->registration);
2051 	h->inc[GMT_Y] = gmt_M_get_inc (GMT, h->wesn[YLO], h->wesn[YHI], h->n_rows, h->registration);
2052 	HH->r_inc[GMT_X] = 1.0 / h->inc[GMT_X];	/* Get inverse increments to avoid divisions later */
2053 	HH->r_inc[GMT_Y] = 1.0 / h->inc[GMT_Y];
2054 }
2055 
gmt_set_grddim(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)2056 void gmt_set_grddim (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
2057 	/* Assumes pad is set and then computes n_columns, n_rows, mx, my, nm, size, xy_off based on w/e/s/n.  */
2058 	h->n_columns = gmt_M_grd_get_nx (GMT, h);		/* Set n_columns, n_rows based on w/e/s/n and offset */
2059 	h->n_rows = gmt_M_grd_get_ny (GMT, h);
2060 	h->mx = gmt_M_grd_get_nxpad (h, h->pad);	/* Set mx, my based on h->{n_columns,n_rows} and the current pad */
2061 	h->my = gmt_M_grd_get_nypad (h, h->pad);
2062 	h->nm = gmt_M_grd_get_nm (h);		/* Sets the number of actual data items */
2063 	h->size = gmtgrdio_grd_get_size (h);	/* Sets the number of items (not bytes!) needed to hold this array, which includes the padding (size >= nm) */
2064 	h->xy_off = 0.5 * h->registration;
2065 	gmt_set_grdinc (GMT, h);
2066 }
2067 
gmt_grd_init(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,struct GMT_OPTION * options,bool update)2068 void gmt_grd_init (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, struct GMT_OPTION *options, bool update) {
2069 	/* gmt_grd_init initializes a grd header to default values and copies the
2070 	 * options to the header variable command.
2071 	 * update = true if we only want to update command line */
2072 
2073 	int i;
2074 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
2075 
2076 	if (update)	/* Only clean the command history */
2077 		gmt_M_memset (header->command, GMT_GRID_COMMAND_LEN320, char);
2078 	else {		/* Wipe the slate clean */
2079 		void *ptr = HH->index_function;	/* Keep these two */
2080 		char mem[4];
2081 		gmt_M_memcpy (mem, header->mem_layout, 4, char);
2082 		gmt_M_memset (header, 1, struct GMT_GRID_HEADER);
2083 		HH->index_function = ptr;
2084 		header->hidden = HH;
2085 		gmt_M_memcpy (header->mem_layout, mem, 4, char);
2086 
2087 		/* Set the variables that are not initialized to 0/false/NULL */
2088 		header->z_scale_factor = 1.0;
2089 		HH->row_order   	   = k_nc_start_south; /* S->N */
2090 		HH->z_id         	   = GMT_NOTSET;
2091 		header->n_bands        = 1; /* Grids have at least one band but images may have 3 (RGB) or 4 (RGBA) */
2092 		header->z_min          = GMT->session.d_NaN;
2093 		header->z_max          = GMT->session.d_NaN;
2094 		header->nan_value      = GMT->session.f_NaN;
2095 		if (gmt_M_is_geographic (GMT, GMT_OUT)) {
2096 			strcpy (header->x_units, "longitude [degrees_east]");
2097 			strcpy (header->y_units, "latitude [degrees_north]");
2098 		}
2099 		else {
2100 			strcpy (header->x_units, "x");
2101 			strcpy (header->y_units, "y");
2102 		}
2103 		strcpy (header->z_units, "z");
2104 		gmt_M_grd_setpad (GMT, header, GMT->current.io.pad); /* Assign default pad */
2105 	}
2106 
2107 	/* Always update command line history, if given */
2108 
2109 	if (options) {
2110 		size_t len;
2111 		struct GMTAPI_CTRL *API = GMT->parent;
2112 		int argc = 0, k_data;
2113 		char **argv = NULL, *c = NULL;
2114 		char file[GMT_LEN64] = {""}, *txt = NULL;
2115 
2116 		if ((argv = GMT_Create_Args (API, &argc, options)) == NULL) {
2117 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Could not create argc, argv from linked structure options!\n");
2118 			return;
2119 		}
2120 		strncpy (header->command, GMT->init.module_name, GMT_GRID_COMMAND_LEN320-1);
2121 		len = strlen (header->command);
2122 		for (i = 0; len < GMT_GRID_COMMAND_LEN320 && i < argc; i++) {
2123 			if (gmt_file_is_tiled_list (API, argv[i], &k_data, NULL, NULL)) {	/* Want to replace the tiled list with the original @earth_relief_xxx name instead */
2124 				snprintf (file, GMT_LEN64, "@%s", API->remote_info[k_data].file);
2125 				txt = file;
2126 			}
2127 			else if ((k_data = gmt_remote_dataset_id (API, argv[i])) != GMT_NOTSET && API->remote_info[k_data].ext[0] && (c = strstr (argv[i], API->remote_info[k_data].ext))) {
2128 				c[0] = '\0';
2129 				snprintf (file, GMT_LEN64, "%s", argv[i]);
2130 				c[0] = '.';
2131 				txt = file;
2132 			}
2133 			else
2134 				txt = argv[i];
2135 			len += strlen (txt) + 1;
2136 			if (len >= GMT_GRID_COMMAND_LEN320) continue;
2137 			strcat (header->command, " ");
2138 			strcat (header->command, txt);
2139 		}
2140 		if (len < GMT_GRID_COMMAND_LEN320)
2141 			header->command[len] = 0;
2142 		else /* Must truncate */
2143 			header->command[GMT_GRID_COMMAND_LEN320-1] = 0;
2144 		snprintf (header->title, GMT_GRID_TITLE_LEN80, "Produced by %s", GMT->init.module_name);
2145 		GMT_Destroy_Args (API, argc, &argv);
2146 	}
2147 }
2148 
gmt_grd_shift(struct GMT_CTRL * GMT,struct GMT_GRID * G,double shift)2149 void gmt_grd_shift (struct GMT_CTRL *GMT, struct GMT_GRID *G, double shift) {
2150 	/* Rotate geographical, global grid in e-w direction
2151 	 * This function will shift a grid by shift degrees.
2152 	 * It is only called when we know the grid is geographic. */
2153 
2154 	unsigned int row, n_warn = 0;
2155 	int col, n_shift, width, actual_col;
2156 	bool gridline;
2157 	uint64_t ij;
2158 	gmt_grdfloat *tmp = NULL;
2159 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (G->header);
2160 
2161 	n_shift = irint (shift * HH->r_inc[GMT_X]);
2162 	width = irint (360.0 * HH->r_inc[GMT_X]);
2163 	if (width > (int)G->header->n_columns) {
2164 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Cannot rotate grid, width is too small\n");
2165 		return;
2166 	}
2167 
2168 	/* Shift boundaries */
2169 
2170 	tmp = gmt_M_memory (GMT, NULL, G->header->n_columns, gmt_grdfloat);
2171 
2172 	G->header->wesn[XLO] += shift;
2173 	G->header->wesn[XHI] += shift;
2174 	if (G->header->wesn[XHI] < 0.0) {
2175 		G->header->wesn[XLO] += 360.0;
2176 		G->header->wesn[XHI] += 360.0;
2177 	}
2178 	else if (G->header->wesn[XHI] > 360.0) {
2179 		G->header->wesn[XLO] -= 360.0;
2180 		G->header->wesn[XHI] -= 360.0;
2181 	}
2182 
2183 	gridline = (width < (int)G->header->n_columns);	/* Gridline-registrered grids will have width = n_columns-1, pixel grids have width = n_columns */
2184 
2185 	if (gridline) GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Repeating column now at %g/%g\n", G->header->wesn[XLO], G->header->wesn[XHI]);
2186 
2187 
2188 	for (row = 0; row < G->header->n_rows; row++) {
2189 		ij = gmt_M_ijp (G->header, row, 0);
2190 		if (gridline && G->data[ij] != G->data[ij+width]) n_warn++;
2191 		for (col = 0; col < (int)G->header->n_columns; col++) {
2192 			actual_col = (col - n_shift) % width;
2193 			if (actual_col < 0) actual_col += width;
2194 			tmp[actual_col] = G->data[ij+col];
2195 		}
2196 		if (gridline) tmp[width] = tmp[0];	/* Set new repeating column */
2197 		gmt_M_memcpy (&G->data[ij], tmp, G->header->n_columns, gmt_grdfloat);
2198 	}
2199 	gmt_M_free (GMT, tmp);
2200 
2201 	if (n_warn)
2202 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Inconsistent values at repeated longitude nodes (%g and %g) for %d rows\n",
2203 			G->header->wesn[XLO], G->header->wesn[XHI], n_warn);
2204 }
2205 
gmt_grd_setregion(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,double * wesn,unsigned int interpolant)2206 int gmt_grd_setregion (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, double *wesn, unsigned int interpolant) {
2207 	/* gmt_grd_setregion determines what w,e,s,n should be passed to gmtlib_read_grd.
2208 	 * It does so by using GMT->common.R.wesn which have been set correctly by map_setup.
2209 	 * Use interpolant to indicate if (and how) the grid is interpolated after this call.
2210 	 * This determines possible extension of the grid to allow interpolation (without padding).
2211 	 *
2212 	 * Here are some considerations about the boundary we need to match, assuming the grid is gridline oriented:
2213 	 * - When the output is to become pixels, the outermost point has to be beyond 0.5 cells inside the region
2214 	 * - When linear interpolation is needed afterwards, the outermost point needs to be on the region edge or beyond
2215 	 * - When the grid is pixel oriented, the limits need to go outward by another 0.5 cells
2216 	 * - When the region is global, do not extend the longitudes outward (otherwise you create wrap-around issues)
2217 	 * So to determine the boundary, we go inward from there.
2218 	 *
2219 	 * Return values are as follows:
2220 	 * 0 = Grid is entirely outside Region
2221 	 * 1 = Region is equal to or entirely inside Grid
2222 	 * 2 = All other
2223 	 */
2224 
2225 	bool grid_global;
2226 	double shift_x, x_range, off;
2227 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (h);
2228 
2229 	/* First make an educated guess whether the grid and region are geographical and global */
2230 	grid_global = gmt_grd_is_global (GMT, h);
2231 
2232 	switch (interpolant) {
2233 		case BCR_BILINEAR:
2234 			off = 0.0;
2235 			break;
2236 		case BCR_BSPLINE:
2237 		case BCR_BICUBIC:
2238 			off = 1.5;
2239 			break;
2240 		default:
2241 			off = -0.5;
2242 			break;
2243 	}
2244 	if (h->registration == GMT_GRID_PIXEL_REG) off += 0.5;
2245 
2246 	/* Initial assignment of wesn */
2247 	wesn[YLO] = GMT->common.R.wesn[YLO] - off * h->inc[GMT_Y], wesn[YHI] = GMT->common.R.wesn[YHI] + off * h->inc[GMT_Y];
2248 	if (gmt_M_360_range (GMT->common.R.wesn[XLO], GMT->common.R.wesn[XHI]) && gmt_M_x_is_lon (GMT, GMT_IN)) off = 0.0;
2249 	wesn[XLO] = GMT->common.R.wesn[XLO] - off * h->inc[GMT_X], wesn[XHI] = GMT->common.R.wesn[XHI] + off * h->inc[GMT_X];
2250 
2251 	if (GMT->common.R.oblique && !gmt_M_is_rect_graticule (GMT)) {	/* Used -R... with oblique boundaries - return entire grid */
2252 		if (wesn[XHI] < h->wesn[XLO])	/* Make adjustments so GMT->current.proj.[w,e] jives with h->wesn */
2253 			shift_x = 360.0;
2254 		else if (wesn[XLO] > h->wesn[XHI])
2255 			shift_x = -360.0;
2256 		else
2257 			shift_x = 0.0;
2258 
2259 		wesn[XLO] = h->wesn[XLO] + lrint ((wesn[XLO] - h->wesn[XLO] + shift_x) * HH->r_inc[GMT_X]) * h->inc[GMT_X];
2260 		wesn[XHI] = h->wesn[XHI] + lrint ((wesn[XHI] - h->wesn[XHI] + shift_x) * HH->r_inc[GMT_X]) * h->inc[GMT_X];
2261 		wesn[YLO] = h->wesn[YLO] + lrint ((wesn[YLO] - h->wesn[YLO]) * HH->r_inc[GMT_Y]) * h->inc[GMT_Y];
2262 		wesn[YHI] = h->wesn[YHI] + lrint ((wesn[YHI] - h->wesn[YHI]) * HH->r_inc[GMT_Y]) * h->inc[GMT_Y];
2263 
2264 		/* Make sure we do not exceed grid domain (which can happen if GMT->common.R.wesn exceeds the grid limits) */
2265 		if (wesn[XLO] < h->wesn[XLO] && !grid_global) wesn[XLO] = h->wesn[XLO];
2266 		if (wesn[XHI] > h->wesn[XHI] && !grid_global) wesn[XHI] = h->wesn[XHI];
2267 		if (wesn[YLO] < h->wesn[YLO]) wesn[YLO] = h->wesn[YLO];
2268 		if (wesn[YHI] > h->wesn[YHI]) wesn[YHI] = h->wesn[YHI];
2269 
2270 		/* If North or South pole are within the map boundary, we need all longitudes but restrict latitudes */
2271 		if (!GMT->current.map.outside (GMT, 0.0, +90.0)) wesn[XLO] = h->wesn[XLO], wesn[XHI] = h->wesn[XHI], wesn[YHI] = h->wesn[YHI];
2272 		if (!GMT->current.map.outside (GMT, 0.0, -90.0)) wesn[XLO] = h->wesn[XLO], wesn[XHI] = h->wesn[XHI], wesn[YLO] = h->wesn[YLO];
2273 		return (grid_global ? 1 : 2);
2274 	}
2275 
2276 	/* First set and check latitudes since they have no complications */
2277 	wesn[YLO] = MAX (h->wesn[YLO], h->wesn[YLO] + floor ((wesn[YLO] - h->wesn[YLO]) * HH->r_inc[GMT_Y] + GMT_CONV4_LIMIT) * h->inc[GMT_Y]);
2278 	wesn[YHI] = MIN (h->wesn[YHI], h->wesn[YLO] + ceil  ((wesn[YHI] - h->wesn[YLO]) * HH->r_inc[GMT_Y] - GMT_CONV4_LIMIT) * h->inc[GMT_Y]);
2279 
2280 	if (wesn[YHI] <= wesn[YLO]) {	/* Grid must be outside chosen -R */
2281 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Your grid y's or latitudes appear to be outside the map region and will be skipped.\n");
2282 		return (0);
2283 	}
2284 
2285 	/* Periodic grid with 360 degree range is easy */
2286 
2287 	if (grid_global) {
2288 		bool true_global_region = (gmt_M_360_range (h->wesn[XLO], h->wesn[XHI]) && gmt_M_360_range (GMT->common.R.wesn[XLO], GMT->common.R.wesn[XHI]));
2289 		double x_noise = GMT_CONV4_LIMIT * h->inc[GMT_X];
2290 		wesn[XLO] = h->wesn[XLO] + floor ((wesn[XLO] - h->wesn[XLO]) * HH->r_inc[GMT_X] + GMT_CONV4_LIMIT) * h->inc[GMT_X];
2291 		wesn[XHI] = h->wesn[XLO] + ceil  ((wesn[XHI] - h->wesn[XLO]) * HH->r_inc[GMT_X] - GMT_CONV4_LIMIT) * h->inc[GMT_X];
2292 		/* For the odd chance that xmin or xmax are outside the region: bring them in */
2293 		if ((wesn[XHI] - wesn[XLO]) >= 360.0) {
2294 			while ((wesn[XLO] + x_noise) < GMT->common.R.wesn[XLO]) wesn[XLO] += h->inc[GMT_X];
2295 			while ((wesn[XHI]- x_noise) > GMT->common.R.wesn[XHI]) wesn[XHI] -= h->inc[GMT_X];
2296 		}
2297 		if (true_global_region && (wesn[XHI] - wesn[XLO]) < 360.0)	/* Need to enforce 360 range since that is what it should be */
2298 			wesn[XHI] = wesn[XLO] + 360.0;
2299 		return (1);
2300 	}
2301 	if (GMT->current.map.is_world) {
2302 		wesn[XLO] = h->wesn[XLO], wesn[XHI] = h->wesn[XHI];
2303 		return (1);
2304 	}
2305 
2306 	/* Shift a geographic grid 360 degrees up or down to maximize the amount of longitude range */
2307 
2308 	if (gmt_M_x_is_lon (GMT, GMT_IN)) {
2309 		if (gmt_M_360_range (GMT->common.R.wesn[XLO], GMT->common.R.wesn[XHI])) {
2310 			wesn[XLO] = h->wesn[XLO], wesn[XHI] = h->wesn[XHI];
2311 			return (1);
2312 		}
2313 		x_range = MIN (wesn[XLO], h->wesn[XHI]) - MAX (wesn[XHI], h->wesn[XLO]);
2314 		if (MIN (wesn[XLO], h->wesn[XHI] + 360.0) - MAX (wesn[XHI], h->wesn[XLO] + 360.0) > x_range)
2315 			shift_x = 360.0;
2316 		else if (MIN (wesn[XLO], h->wesn[XHI] - 360.0) - MAX (wesn[XHI], h->wesn[XLO] - 360.0) > x_range)
2317 			shift_x = -360.0;
2318 		else
2319 			shift_x = 0.0;
2320 		h->wesn[XLO] += shift_x;
2321 		h->wesn[XHI] += shift_x;
2322 	}
2323 
2324 	wesn[XLO] = MAX (h->wesn[XLO], h->wesn[XLO] + floor ((wesn[XLO] - h->wesn[XLO]) * HH->r_inc[GMT_X] + GMT_CONV4_LIMIT) * h->inc[GMT_X]);
2325 	wesn[XHI] = MIN (h->wesn[XHI], h->wesn[XLO] + ceil  ((wesn[XHI] - h->wesn[XLO]) * HH->r_inc[GMT_X] - GMT_CONV4_LIMIT) * h->inc[GMT_X]);
2326 
2327 	if (wesn[XHI] <= wesn[XLO]) {	/* Grid may is outside chosen -R in longitude */
2328 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Your grid x's or longitudes appear to be outside the map region and will be skipped.\n");
2329 		return (0);
2330 	}
2331 	return (2);
2332 }
2333 
gmtlib_adjust_loose_wesn(struct GMT_CTRL * GMT,double wesn[],struct GMT_GRID_HEADER * header,unsigned int verbose_level)2334 GMT_LOCAL int gmtlib_adjust_loose_wesn (struct GMT_CTRL *GMT, double wesn[], struct GMT_GRID_HEADER *header, unsigned int verbose_level) {
2335 	/* Used to ensure that sloppy w,e,s,n values are rounded to the gridlines or pixels in the referenced grid.
2336 	 * Upon entry, the boundaries w,e,s,n are given as a rough approximation of the actual subset needed.
2337 	 * The routine will limit the boundaries to the grids region and round w,e,s,n to the nearest gridline or
2338 	 * pixel boundaries (depending on the grid orientation).
2339 	 * Warnings are produced when the w,e,s,n boundaries are adjusted, so this routine is currently not
2340 	 * intended to throw just any values at it (although one could).
2341 	 */
2342 
2343 	bool global, error = false;
2344 	double val, dx, small, was;
2345 	char format[GMT_LEN256] = {""};
2346 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (header);
2347 
2348 	switch (gmt_minmaxinc_verify (GMT, wesn[XLO], wesn[XHI], header->inc[GMT_X], GMT_CONV4_LIMIT)) {	/* Check if range is compatible with x_inc */
2349 		case 3:
2350 			return (GMT_GRDIO_BAD_XINC);
2351 			break;
2352 		case 2:
2353 			return (GMT_GRDIO_BAD_XRANGE);
2354 			break;
2355 		default:
2356 			/* Everything is seemingly OK */
2357 			break;
2358 	}
2359 	switch (gmt_minmaxinc_verify (GMT, wesn[YLO], wesn[YHI], header->inc[GMT_Y], GMT_CONV4_LIMIT)) {	/* Check if range is compatible with y_inc */
2360 		case 3:
2361 			return (GMT_GRDIO_BAD_YINC);
2362 			break;
2363 		case 2:
2364 			return (GMT_GRDIO_BAD_YRANGE);
2365 			break;
2366 		default:
2367 			/* Everything is OK */
2368 			break;
2369 	}
2370 	global = gmt_grd_is_global (GMT, header);
2371 
2372 	if (!global) {
2373 		if (gmt_M_x_is_lon (GMT, GMT_IN)) {
2374 			/* If longitudes are all west of range or all east of range, try moving them by 360 degrees east or west */
2375 			if (wesn[XHI] < header->wesn[XLO])
2376 				wesn[XLO] += 360.0, wesn[XHI] += 360.0;
2377 			else if (wesn[XLO] > header->wesn[XHI])
2378 				wesn[XLO] -= 360.0, wesn[XHI] -= 360.0;
2379 		}
2380 		if (header->wesn[XLO] - wesn[XLO] > GMT_CONV4_LIMIT) wesn[XLO] = header->wesn[XLO], error = true;
2381 		if (wesn[XHI] - header->wesn[XHI] > GMT_CONV4_LIMIT) wesn[XHI] = header->wesn[XHI], error = true;
2382 	}
2383 	if (header->wesn[YLO] - wesn[YLO] > GMT_CONV4_LIMIT) wesn[YLO] = header->wesn[YLO], error = true;
2384 	if (wesn[YHI] - header->wesn[YHI] > GMT_CONV4_LIMIT) wesn[YHI] = header->wesn[YHI], error = true;
2385 	if (error)
2386 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Region exceeds grid domain. Region reduced to grid domain.\n");
2387 
2388 	/* If new region is not an exact match with grid increment we ensure we extend the region outwards to cover the desired
2389 	 * region.  However, if that takes us outside the grid's region then we backtrack back in */
2390 
2391 	if (!(gmt_M_x_is_lon (GMT, GMT_IN) && gmt_M_360_range (wesn[XLO], wesn[XHI]) && global)) {    /* Do this unless a 360 longitude wrap */
2392 		small = GMT_CONV4_LIMIT * header->inc[GMT_X];
2393 
2394 		val = header->wesn[XLO] + lrint ((wesn[XLO] - header->wesn[XLO]) * HH->r_inc[GMT_X]) * header->inc[GMT_X];
2395 		dx = fabs (wesn[XLO] - val);
2396 		if (gmt_M_x_is_lon (GMT, GMT_IN)) dx = fmod (dx, 360.0);
2397 		if (dx > small) {
2398 			was = wesn[XLO];
2399 			GMT_Report (GMT->parent, verbose_level,
2400 			            "(w - x_min) must equal (NX + eps) * x_inc), where NX is an integer and |eps| <= %g.\n", GMT_CONV4_LIMIT);
2401 			snprintf (format, GMT_LEN256, "w reset from %s to %s\n",
2402 			          GMT->current.setting.format_float_out, GMT->current.setting.format_float_out);
2403 			wesn[XLO] = val - header->inc[GMT_X];
2404 			if (wesn[XLO] < header->wesn[XLO]) val += header->inc[GMT_X];
2405 			GMT_Report (GMT->parent, verbose_level, format, was, wesn[XLO]);
2406 		}
2407 
2408 		val = header->wesn[XLO] + lrint ((wesn[XHI] - header->wesn[XLO]) * HH->r_inc[GMT_X]) * header->inc[GMT_X];
2409 		dx = fabs (wesn[XHI] - val);
2410 		if (gmt_M_x_is_lon (GMT, GMT_IN)) dx = fmod (dx, 360.0);
2411 		if (dx > small) {
2412 			was = wesn[XHI];
2413 			GMT_Report (GMT->parent, verbose_level,
2414 			            "(e - x_min) must equal (NX + eps) * x_inc), where NX is an integer and |eps| <= %g.\n", GMT_CONV4_LIMIT);
2415 			snprintf (format, GMT_LEN256, "e reset from %s to %s\n",
2416 			          GMT->current.setting.format_float_out, GMT->current.setting.format_float_out);
2417 			wesn[XHI] = val + header->inc[GMT_X];
2418 			if (wesn[XHI] > header->wesn[XHI]) val -= header->inc[GMT_X];
2419 			GMT_Report (GMT->parent, verbose_level, format, was, wesn[XHI]);
2420 		}
2421 	}
2422 
2423 	/* Check if s,n are a multiple of y_inc offset from y_min - if not adjust s, n */
2424 	small = GMT_CONV4_LIMIT * header->inc[GMT_Y];
2425 
2426 	val = header->wesn[YLO] + lrint ((wesn[YLO] - header->wesn[YLO]) * HH->r_inc[GMT_Y]) * header->inc[GMT_Y];
2427 	if (fabs (wesn[YLO] - val) > small) {
2428 		was = wesn[YLO];
2429 		GMT_Report (GMT->parent, verbose_level, "(s - y_min) must equal (NY + eps) * y_inc), where NY is an integer and |eps| <= %g.\n",
2430 		            GMT_CONV4_LIMIT);
2431 		snprintf (format, GMT_LEN256, "s reset from %s to %s\n",
2432 		          GMT->current.setting.format_float_out, GMT->current.setting.format_float_out);
2433 		wesn[YLO] = val - header->inc[GMT_Y];
2434 		if (wesn[YLO] < header->wesn[YLO]) val += header->inc[GMT_Y];
2435 		GMT_Report (GMT->parent, verbose_level, format, was, wesn[YLO]);
2436 	}
2437 
2438 	val = header->wesn[YLO] + lrint ((wesn[YHI] - header->wesn[YLO]) * HH->r_inc[GMT_Y]) * header->inc[GMT_Y];
2439 	if (fabs (wesn[YHI] - val) > small) {
2440 		was = wesn[YHI];
2441 		GMT_Report (GMT->parent, verbose_level, "(n - y_min) must equal (NY + eps) * y_inc), where NY is an integer and |eps| <= %g.\n",
2442 		            GMT_CONV4_LIMIT);
2443 		snprintf (format, GMT_LEN256, "n reset from %s to %s\n",
2444 		          GMT->current.setting.format_float_out, GMT->current.setting.format_float_out);
2445 		wesn[YHI] = val + header->inc[GMT_Y];
2446 		if (wesn[YHI] > header->wesn[YHI]) val -= header->inc[GMT_Y];
2447 		GMT_Report (GMT->parent, verbose_level, format, was, wesn[YHI]);
2448 	}
2449 	return (GMT_NOERROR);
2450 }
2451 
gmt_adjust_loose_wesn(struct GMT_CTRL * GMT,double wesn[],struct GMT_GRID_HEADER * header)2452 int gmt_adjust_loose_wesn (struct GMT_CTRL *GMT, double wesn[], struct GMT_GRID_HEADER *header) {
2453 	/* Most places we wish to warn if w/e/s/n is sloppy except when via DCW that must be rounded */
2454 	return gmtlib_adjust_loose_wesn (GMT, wesn, header, GMT->common.R.via_polygon ? GMT_MSG_INFORMATION : GMT_MSG_WARNING);
2455 }
2456 
gmt_scale_and_offset_f(struct GMT_CTRL * GMT,gmt_grdfloat * data,size_t length,double scale,double offset)2457 void gmt_scale_and_offset_f (struct GMT_CTRL *GMT, gmt_grdfloat *data, size_t length, double scale, double offset) {
2458 	/* Routine that does the data conversion and sanity checking before
2459 	 * calling scale_and_offset_f() to scale and offset the data in a grid */
2460 	gmt_grdfloat scale_f  = (gmt_grdfloat)scale;
2461 	gmt_grdfloat offset_f = (gmt_grdfloat)offset;
2462 
2463 	if (scale_f == 1.0 && offset_f == 0.0)
2464 		return; /* No work needed */
2465 
2466 	/* Sanity checks */
2467 	if (!isnormal (scale)) {
2468 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Scale must be a non-zero normalized number (%g).\n", scale);
2469 		scale_f = 1.0f;
2470 	}
2471 	if (!isfinite (offset)) {
2472 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Offset must be a finite number (%g).\n", offset);
2473 		offset_f = 0.0f;
2474 	}
2475 
2476 	/* Call workhorse */
2477 	scale_and_offset_f (data, length, scale_f, offset_f);
2478 }
2479 
gmt_read_img(struct GMT_CTRL * GMT,char * imgfile,struct GMT_GRID * Grid,double * in_wesn,double scale,unsigned int mode,double lat,bool init)2480 int gmt_read_img (struct GMT_CTRL *GMT, char *imgfile, struct GMT_GRID *Grid, double *in_wesn, double scale, unsigned int mode, double lat, bool init) {
2481 	/* Function that reads an entire Sandwell/Smith Mercator grid and stores it like a regular
2482 	 * GMT grid.  If init is true we also initialize the Mercator projection.  Lat should be 0.0
2483 	 * if we are dealing with standard 72 or 80 img latitude; else it must be specified.
2484 	 */
2485 
2486 	int status, first_i;
2487 	unsigned int min, actual_col, n_cols, row, col, first;
2488 	uint64_t ij;
2489 	off_t n_skip;
2490 	int16_t *i2 = NULL;
2491 	uint16_t *u2 = NULL;
2492 	char file[PATH_MAX];
2493 	struct stat buf;
2494 	FILE *fp = NULL;
2495 	double wesn[4], wesn_all[4];
2496 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (Grid->header);
2497 
2498 	first = gmt_download_file_if_not_found (GMT, imgfile, GMT_CACHE_DIR);
2499 	if (!gmt_getdatapath (GMT, &imgfile[first], file, R_OK)) return (GMT_GRDIO_FILE_NOT_FOUND);
2500 	if (stat (file, &buf)) return (GMT_GRDIO_STAT_FAILED);	/* Inquiry about file failed somehow */
2501 
2502 	switch (buf.st_size) {	/* Known sizes are 1 or 2 min at lat_max = ~72, ~80, or ~85.  Set exact latitude */
2503 		case GMT_IMG_NLON_1M*GMT_IMG_NLAT_1M_85*GMT_IMG_ITEMSIZE:
2504 			lat = GMT_IMG_MAXLAT_85;
2505 			min = 1;
2506 			break;
2507 		case GMT_IMG_NLON_1M*GMT_IMG_NLAT_1M_80*GMT_IMG_ITEMSIZE:
2508 			lat = GMT_IMG_MAXLAT_80;
2509 			min = 1;
2510 			break;
2511 		case GMT_IMG_NLON_1M*GMT_IMG_NLAT_1M_72*GMT_IMG_ITEMSIZE:
2512 			lat = GMT_IMG_MAXLAT_72;
2513 			min = 1;
2514 			break;
2515 		case GMT_IMG_NLON_2M*GMT_IMG_NLAT_2M_85*GMT_IMG_ITEMSIZE:
2516 			lat = GMT_IMG_MAXLAT_85;
2517 			min = 2;
2518 			break;
2519 		case GMT_IMG_NLON_2M*GMT_IMG_NLAT_2M_80*GMT_IMG_ITEMSIZE:
2520 			lat = GMT_IMG_MAXLAT_80;
2521 			min = 2;
2522 			break;
2523 		case GMT_IMG_NLON_2M*GMT_IMG_NLAT_2M_72*GMT_IMG_ITEMSIZE:
2524 			lat = GMT_IMG_MAXLAT_72;
2525 			min = 2;
2526 			break;
2527 		case GMT_IMG_NLON_4M*GMT_IMG_NLAT_4M_72*GMT_IMG_ITEMSIZE:	/* Test grids only */
2528 			lat = GMT_IMG_MAXLAT_72;
2529 			min = 4;
2530 			break;
2531 		default:
2532 			if (lat == 0.0) return (GMT_GRDIO_BAD_IMG_LAT);
2533 			min = (buf.st_size > GMT_IMG_NLON_2M*GMT_IMG_NLAT_2M_80*GMT_IMG_ITEMSIZE) ? 1 : 2;
2534 			GMT_Report (GMT->parent, GMT_MSG_WARNING, "img file %s has unusual size - grid increment defaults to %d min\n", file, min);
2535 			break;
2536 	}
2537 
2538 	wesn_all[XLO] = GMT_IMG_MINLON;	wesn_all[XHI] = GMT_IMG_MAXLON;
2539 	wesn_all[YLO] = -lat;		wesn_all[YHI] = lat;
2540 	if (!in_wesn || (in_wesn[XLO] == in_wesn[XHI] && in_wesn[YLO] == in_wesn[YHI])) {	/* Default is entire grid */
2541 		gmt_M_memcpy (wesn, wesn_all, 4, double);
2542 	}
2543 	else	/* Use specified subset */
2544 		gmt_M_memcpy (wesn, in_wesn, 4, double);
2545 
2546 	if ((fp = gmt_fopen (GMT, file, "rb")) == NULL) return (GMT_GRDIO_OPEN_FAILED);
2547 
2548 	GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Reading img grid from file %s (scale = %g mode = %d lat = %g)\n",
2549 	            &imgfile[first], scale, mode, lat);
2550 	Grid->header->inc[GMT_X] = Grid->header->inc[GMT_Y] = min / 60.0;
2551 
2552 	if (init) {
2553 		/* Select plain Mercator on a sphere with -Jm1 -R0/360/-lat/+lat */
2554 		GMT->current.setting.proj_ellipsoid = gmt_get_ellipsoid (GMT, "Sphere");
2555 		GMT->current.proj.units_pr_degree = true;
2556 		GMT->current.proj.pars[0] = 180.0;
2557 		GMT->current.proj.pars[1] = 0.0;
2558 		GMT->current.proj.pars[2] = 1.0;
2559 		GMT->current.proj.projection = GMT->current.proj.projection_GMT = GMT_MERCATOR;
2560 		gmt_set_geographic (GMT, GMT_IN);
2561 		GMT->common.J.active = true;
2562 
2563 		gmt_M_err_pass (GMT, gmt_proj_setup (GMT, wesn_all), file);
2564 	}
2565 
2566 	if (wesn[XLO] < 0.0 && wesn[XHI] < 0.0) wesn[XLO] += 360.0, wesn[XHI] += 360.0;
2567 
2568 	/* Project lon/lat boundaries to Mercator units */
2569 	gmt_geo_to_xy (GMT, wesn[XLO], wesn[YLO], &Grid->header->wesn[XLO], &Grid->header->wesn[YLO]);
2570 	gmt_geo_to_xy (GMT, wesn[XHI], wesn[YHI], &Grid->header->wesn[XHI], &Grid->header->wesn[YHI]);
2571 
2572 	/* Adjust boundaries to multiples of increments, making sure we are inside bounds */
2573 	Grid->header->wesn[XLO] = MAX (GMT_IMG_MINLON, floor (Grid->header->wesn[XLO] / Grid->header->inc[GMT_X]) * Grid->header->inc[GMT_X]);
2574 	Grid->header->wesn[XHI] = MIN (GMT_IMG_MAXLON, ceil (Grid->header->wesn[XHI] / Grid->header->inc[GMT_X]) * Grid->header->inc[GMT_X]);
2575 	if (Grid->header->wesn[XLO] > Grid->header->wesn[XHI]) Grid->header->wesn[XLO] -= 360.0;
2576 	Grid->header->wesn[YLO] = MAX (0.0, floor (Grid->header->wesn[YLO] / Grid->header->inc[GMT_Y]) * Grid->header->inc[GMT_Y]);
2577 	Grid->header->wesn[YHI] = MIN (GMT->current.proj.rect[YHI], ceil (Grid->header->wesn[YHI] / Grid->header->inc[GMT_Y]) * Grid->header->inc[GMT_Y]);
2578 	/* Allocate grid memory */
2579 
2580 	Grid->header->registration = GMT_GRID_PIXEL_REG;	/* These are always pixel grids */
2581 	if ((status = gmt_grd_RI_verify (GMT, Grid->header, 1))) {	/* Final verification of -R -I; return error if we must */
2582 		gmt_fclose (GMT, fp);
2583 		return (status);
2584 	}
2585 	gmt_M_grd_setpad (GMT, Grid->header, GMT->current.io.pad);			/* Assign default pad */
2586 	gmt_set_grddim (GMT, Grid->header);					/* Set all dimensions before returning */
2587 	Grid->data = gmt_M_memory_aligned (GMT, NULL, Grid->header->size, gmt_grdfloat);
2588 
2589 	n_cols = (min == 1) ? GMT_IMG_NLON_1M : GMT_IMG_NLON_2M;		/* Number of columns (10800 or 21600) */
2590 	first_i = irint (floor (Grid->header->wesn[XLO] * HH->r_inc[GMT_X]));				/* first tile partly or fully inside region */
2591 	if (first_i < 0) first_i += n_cols;
2592 	n_skip = lrint (floor ((GMT->current.proj.rect[YHI] - Grid->header->wesn[YHI]) * HH->r_inc[GMT_Y]));	/* Number of rows clearly above y_max */
2593 	if (fseek (fp, n_skip * n_cols * GMT_IMG_ITEMSIZE, SEEK_SET)) {
2594 		gmt_fclose (GMT, fp);
2595 		return (GMT_GRDIO_SEEK_FAILED);
2596 	}
2597 
2598 	i2 = gmt_M_memory (GMT, NULL, n_cols, int16_t);
2599 	for (row = 0; row < Grid->header->n_rows; row++) {	/* Read all the rows, offset by 2 boundary rows and cols */
2600 		if (gmt_M_fread (i2, sizeof (int16_t), n_cols, fp) != n_cols) {
2601 			gmt_M_free (GMT, i2);
2602 			gmt_fclose (GMT, fp);
2603 			return (GMT_GRDIO_READ_FAILED);	/* Failed to get one row */
2604 		}
2605 #ifndef WORDS_BIGENDIAN
2606 		u2 = (uint16_t *)i2;
2607 		for (col = 0; col < n_cols; col++)
2608 			u2[col] = bswap16 (u2[col]);
2609 #endif
2610 #ifdef DEBUG
2611 		if (row == 0) {
2612 			uint16_t step, max_step = 0;
2613 			for (col = 1; col < n_cols; col++) {
2614 				step = abs (i2[col] - i2[col-1]);
2615 				if (step > max_step) max_step = step;
2616 			}
2617 			if (max_step > 32768)
2618 				GMT_Report (GMT->parent, GMT_MSG_WARNING, "File %s probably needs to byteswapped (max change = %u)\n", file, max_step);
2619 		}
2620 #endif
2621 		ij = gmt_M_ijp (Grid->header, row, 0);
2622 		for (col = 0, actual_col = first_i; col < Grid->header->n_columns; col++) {	/* Process this row's values */
2623 			switch (mode) {
2624 				case 0:	/* No encoded track flags, do nothing */
2625 					break;
2626 				case 1:	/* Remove the track flag on odd (constrained) points */
2627 					if (i2[actual_col]%2) i2[actual_col]--;
2628 					break;
2629 				case 2:	/* Remove the track flag on odd (constrained) points and set unconstrained to NaN */
2630 					i2[actual_col] = (i2[actual_col]%2) ? i2[actual_col] - 1 : SHRT_MIN;
2631 					break;
2632 				case 3:	/* Set odd (constrained) points to 1 and set unconstrained to 0 */
2633 					i2[actual_col] %= 2;
2634 					break;
2635 			}
2636 			Grid->data[ij+col] = (gmt_grdfloat)((mode == 3) ? i2[actual_col] : (i2[actual_col] * scale));
2637 			if (++actual_col == n_cols) actual_col = 0;	/* Wrapped around 360 */
2638 		}
2639 	}
2640 	gmt_M_free (GMT, i2);
2641 	gmt_fclose (GMT, fp);
2642 	if (init) {
2643 		gmt_M_memcpy (GMT->common.R.wesn, wesn, 4, double);
2644 		GMT->common.J.active = false;
2645 	}
2646 	gmt_BC_init (GMT, Grid->header);	/* Initialize grid interpolation and boundary condition parameters */
2647 	gmt_grd_BC_set (GMT, Grid, GMT_IN);	/* Set boundary conditions */
2648 	HH->has_NaNs = GMT_GRID_NO_NANS;	/* No nans in img grids */
2649 	return (GMT_NOERROR);
2650 }
2651 
gmt_cube_pad_off(struct GMT_CTRL * GMT,struct GMT_CUBE * U)2652 void gmt_cube_pad_off (struct GMT_CTRL *GMT, struct GMT_CUBE *U) {
2653 	/* Shifts the cube contents so there is no pad.  The remainder of
2654 	 * the array is not reset and should not be addressed, but
2655 	 * we set it to zero just in case.
2656 	 * If pad is zero then we do nothing.
2657 	 */
2658 	uint64_t k, ijp, ij0, nm, here_p = 0, here_0 = 0;
2659 	unsigned int row;
2660 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (U->header);
2661 
2662 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
2663 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Calling gmt_cube_pad_off on interleaved complex grid! Programming error?\n");
2664 		return;
2665 	}
2666 	if (!gmt_grd_pad_status (GMT, U->header, NULL)) return;	/* No pad so nothing to do */
2667 
2668 	/* Here, U has a pad which we need to eliminate */
2669 	nm = U->header->nm;	/* Number of nodes in one component */
2670 	for (k = 0; k < U->header->n_bands; k++) {
2671 		for (row = 0; row < U->header->n_rows; row++) {
2672 			ijp = gmt_M_ijp (U->header, row, 0) + here_p;	/* Index of start of this row's first column in padded cube  */
2673 			ij0 = gmt_M_ij0 (U->header, row, 0) + here_0;	/* Index of start of this row's first column in unpadded cube */
2674 			gmt_M_memcpy (&(U->data[ij0]), &(U->data[ijp]), U->header->n_columns, gmt_grdfloat);	/* Only copy the n_columns data values */
2675 		}
2676 		here_p += U->header->size;
2677 		here_0 += nm;
2678 	}
2679 	if (here_p > here_0) {	/* Just wipe the remainder of the array to be sure */
2680 		size_t n_to_cleen = here_p - here_0;
2681 		gmt_M_memset (&(U->data[nm*U->header->n_bands]), n_to_cleen, gmt_grdfloat);	/* nm*U->header->n_bands is 1st position after last row in cube */
2682 	}
2683 	gmt_M_memset (U->header->pad, 4, int);	/* Pad is no longer active */
2684 	gmt_set_grddim (GMT, U->header);		/* Update all dimensions to reflect the padding */
2685 }
2686 
gmt_grd_pad_off(struct GMT_CTRL * GMT,struct GMT_GRID * G)2687 void gmt_grd_pad_off (struct GMT_CTRL *GMT, struct GMT_GRID *G) {
2688 	/* Shifts the grid contents so there is no pad.  The remainder of
2689 	 * the array is not reset and should not be addressed, but
2690 	 * we set it to zero just in case.
2691 	 * If pad is zero then we do nothing.
2692 	 */
2693 	bool is_complex;
2694 	uint64_t nm;
2695 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (G->header);
2696 
2697 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
2698 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Calling gmt_grd_pad_off on interleaved complex grid! Programming error?\n");
2699 		return;
2700 	}
2701 	if (!gmt_grd_pad_status (GMT, G->header, NULL)) return;	/* No pad so nothing to do */
2702 
2703 	/* Here, G has a pad which we need to eliminate */
2704 	is_complex = (G->header->complex_mode & GMT_GRID_IS_COMPLEX_MASK);
2705 	if (!is_complex || (G->header->complex_mode & GMT_GRID_IS_COMPLEX_REAL))
2706 		gmtgrdio_pad_grd_off_sub (G, G->data);	/* Remove pad around real component only or entire normal grid */
2707 	if (is_complex && (G->header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG))
2708 		gmtgrdio_pad_grd_off_sub (G, &G->data[G->header->size/2]);	/* Remove pad around imaginary component */
2709 	nm = G->header->nm;	/* Number of nodes in one component */
2710 	if (is_complex) nm *= 2;	/* But there might be two */
2711 	if (G->header->size > nm) {	/* Just wipe the remaineder of the array to be sure */
2712 		size_t n_to_cleen = G->header->size - nm;
2713 		gmt_M_memset (&(G->data[nm]), n_to_cleen, gmt_grdfloat);	/* nm is 1st position after last row */
2714 	}
2715 	gmt_M_memset (G->header->pad, 4, int);	/* Pad is no longer active */
2716 	gmt_set_grddim (GMT, G->header);		/* Update all dimensions to reflect the padding */
2717 }
2718 
gmt_grd_pad_on(struct GMT_CTRL * GMT,struct GMT_GRID * G,unsigned int * pad)2719 void gmt_grd_pad_on (struct GMT_CTRL *GMT, struct GMT_GRID *G, unsigned int *pad) {
2720  	/* Shift grid content from a non-padded (or differently padded) to a padded organization.
2721 	 * We check that the grid size can handle this and allocate more space if needed.
2722 	 * If pad matches the grid's pad then we do nothing.
2723 	 */
2724 	bool is_complex;
2725 	size_t size;
2726 	struct GMT_GRID_HEADER *h = NULL;
2727 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (G->header);
2728 
2729 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
2730 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Calling gmt_grd_pad_off on interleaved complex grid! Programming error?\n");
2731 		return;
2732 	}
2733 	if (gmt_grd_pad_status (GMT, G->header, pad)) return;	/* Already padded as requested so nothing to do */
2734 	if (pad[XLO] == 0 && pad[XHI] == 0 && pad[YLO] == 0 && pad[YHI] == 0) {	/* Just remove the existing pad entirely */
2735 		gmt_grd_pad_off (GMT, G);
2736 		return;
2737 	}
2738 	/* Here the pads differ (or G has no pad at all) */
2739 	is_complex = (G->header->complex_mode & GMT_GRID_IS_COMPLEX_MASK);
2740 	size = ((size_t)gmt_M_grd_get_nxpad (G->header, pad)) * ((size_t)gmt_M_grd_get_nypad (G->header, pad));	/* New array size after pad is added */
2741 	if (is_complex) size *= 2;	/* Twice the space for complex grids */
2742 	if (size > G->header->size) {	/* Must allocate more space, but since no realloc for aligned memory we must do it the hard way */
2743 		gmt_grdfloat *f = NULL;
2744 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Extend grid via copy onto larger memory-aligned grid\n");
2745 		f = gmt_M_memory_aligned (GMT, NULL, size, gmt_grdfloat);	/* New, larger grid size */
2746 		gmt_M_memcpy (f, G->data, G->header->size, gmt_grdfloat);	/* Copy over previous grid values */
2747 		gmt_M_free_aligned (GMT, G->data);			/* Free previous aligned grid memory */
2748 		G->data = f;						/* Attach the new, larger aligned memory */
2749 		G->header->size = size;					/* Update the size */
2750 	}
2751 	/* Because G may have a pad that is nonzero (but different from pad) we need a different header structure in the macros below */
2752 	h = gmtgrdio_duplicate_gridheader (GMT, G->header);
2753 
2754 	gmt_M_grd_setpad (GMT, G->header, pad);	/* G->header->pad is now set to specified dimensions in pad */
2755 	gmt_set_grddim (GMT, G->header);	/* Update all dimensions to reflect the new padding */
2756 	if (is_complex && (G->header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG))
2757 		gmtgrdio_pad_grd_on_sub (GMT, G, h, &G->data[size/2]);	/* Add pad around imaginary component first */
2758 	if (!is_complex || (G->header->complex_mode & GMT_GRID_IS_COMPLEX_REAL))
2759 		gmtgrdio_pad_grd_on_sub (GMT, G, h, G->data);	/* Add pad around real component */
2760 	gmt_M_free (GMT, h->hidden);	/* Done with this header hidden struct */
2761 	gmt_M_free (GMT, h);	/* Done with this header */
2762 }
2763 
gmt_grd_pad_zero(struct GMT_CTRL * GMT,struct GMT_GRID * G)2764 void gmt_grd_pad_zero (struct GMT_CTRL *GMT, struct GMT_GRID *G) {
2765 	/* Sets all boundary row/col nodes to zero and sets
2766 	 * the header->BC to GMT_IS_NOTSET.
2767 	 */
2768 	bool is_complex;
2769 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (G->header);
2770 
2771 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
2772 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "Calling gmt_grd_pad_off on interleaved complex grid! Programming error?\n");
2773 		return;
2774 	}
2775 	if (!gmt_grd_pad_status (GMT, G->header, NULL)) return;	/* No pad so nothing to do */
2776 	if (HH->BC[XLO] == GMT_BC_IS_NOTSET && HH->BC[XHI] == GMT_BC_IS_NOTSET && HH->BC[YLO] ==
2777 		GMT_BC_IS_NOTSET && HH->BC[YHI] == GMT_BC_IS_NOTSET)
2778 		return;	/* No BCs set so nothing to do */			/* No pad so nothing to do */
2779 	/* Here, G has a pad with BCs which we need to reset */
2780 	is_complex = (G->header->complex_mode & GMT_GRID_IS_COMPLEX_MASK);
2781 	if (!is_complex || (G->header->complex_mode & GMT_GRID_IS_COMPLEX_REAL))
2782 		gmtgrdio_pad_grd_zero_sub (G, G->data);
2783 	if (is_complex && (G->header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG))
2784 		gmtgrdio_pad_grd_zero_sub (G, &G->data[G->header->size/2]);
2785 	gmt_M_memset (HH->BC, 4U, int);	/* BCs no longer set for this grid */
2786 }
2787 
gmt_get_grid(struct GMT_CTRL * GMT)2788 struct GMT_GRID *gmt_get_grid (struct GMT_CTRL *GMT) {
2789 	struct GMT_GRID *G = NULL;
2790 	G = gmt_M_memory (GMT, NULL, 1, struct GMT_GRID);
2791 	G->hidden = gmt_M_memory (GMT, NULL, 1, struct GMT_GRID_HIDDEN);
2792 	return (G);
2793 }
2794 
gmt_create_grid(struct GMT_CTRL * GMT)2795 struct GMT_GRID *gmt_create_grid (struct GMT_CTRL *GMT) {
2796 	/* Allocates space for a new grid container.  No space allocated for the gmt_grdfloat grid itself */
2797 	struct GMT_GRID *G = NULL;
2798 	struct GMT_GRID_HIDDEN *GH = NULL;
2799 
2800 	G = gmt_get_grid (GMT);
2801 	GH = gmt_get_G_hidden (G);
2802 	G->header = gmt_get_header (GMT);
2803 	gmt_grd_init (GMT, G->header, NULL, false); /* Set default values */
2804 	GMT_Set_Index (GMT->parent, G->header, GMT_GRID_LAYOUT);
2805 #ifdef DOUBLE_PRECISION_GRID
2806 	G->header->type = GMT_GRID_IS_ND;
2807 #else
2808 	G->header->type = GMT_GRID_IS_NF;
2809 #endif
2810 	GH->alloc_mode = GMT_ALLOC_INTERNALLY;		/* Memory can be freed by GMT. */
2811 	GH->alloc_level = GMT->hidden.func_level;	/* Must be freed at this level. */
2812 	GH->id = GMT->parent->unique_var_ID++;		/* Give unique identifier */
2813 	return (G);
2814 }
2815 
gmt_duplicate_grid(struct GMT_CTRL * GMT,struct GMT_GRID * G,unsigned int mode)2816 struct GMT_GRID *gmt_duplicate_grid (struct GMT_CTRL *GMT, struct GMT_GRID *G, unsigned int mode) {
2817 	/* Duplicates an entire grid, including data if requested. */
2818 	struct GMT_GRID *Gnew = NULL;
2819 
2820 	Gnew = gmt_create_grid (GMT);
2821 	gmt_copy_gridheader (GMT, Gnew->header, G->header);
2822 
2823 	if ((mode & GMT_DUPLICATE_DATA) || (mode & GMT_DUPLICATE_ALLOC)) {	/* Also allocate and possibly duplicate data array */
2824 		struct GMT_GRID_HIDDEN *GH = gmt_get_G_hidden (Gnew);
2825 		if ((mode & GMT_DUPLICATE_RESET) && !gmt_grd_pad_status (GMT, G->header, GMT->current.io.pad)) {
2826 			/* Pads differ and we requested resetting the pad */
2827 			gmt_M_grd_setpad (GMT, Gnew->header, GMT->current.io.pad);	/* Set default pad size */
2828 			gmt_set_grddim (GMT, Gnew->header);	/* Update size dimensions given the change of pad */
2829 			if (mode & GMT_DUPLICATE_DATA) {	/* Per row since grid sizes will not the same */
2830 				uint64_t node_in, node_out;
2831 				unsigned int row;
2832 				Gnew->data = gmt_M_memory_aligned (GMT, NULL, Gnew->header->size, gmt_grdfloat);
2833 				gmt_M_row_loop (GMT, G, row) {
2834 					node_in  = gmt_M_ijp (G->header, row, 0);
2835 					node_out = gmt_M_ijp (Gnew->header, row, 0);
2836 					gmt_M_memcpy (&Gnew->data[node_out], &G->data[node_in], G->header->n_columns, gmt_grdfloat);
2837 				}
2838 			}
2839 		}
2840 		else {	/* Can do fast copy */
2841 			Gnew->data = gmt_M_memory_aligned (GMT, NULL, G->header->size, gmt_grdfloat);
2842 			if (mode & GMT_DUPLICATE_DATA) gmt_M_memcpy (Gnew->data, G->data, G->header->size, gmt_grdfloat);
2843 		}
2844 
2845 		Gnew->x = gmt_grd_coord (GMT, Gnew->header, GMT_X);	/* Get array of x coordinates */
2846 		Gnew->y = gmt_grd_coord (GMT, Gnew->header, GMT_Y);	/* Get array of y coordinates */
2847 		GH->xy_alloc_mode[GMT_X] = GH->xy_alloc_mode[GMT_Y] = GMT_ALLOC_INTERNALLY;
2848 	}
2849 	return (Gnew);
2850 }
2851 
gmt_free_header(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER ** header)2852 void gmt_free_header (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER **header) {
2853 	struct GMT_GRID_HEADER_HIDDEN *HH = NULL;
2854 	struct GMT_GRID_HEADER *h = *header;
2855 	if (h == NULL) return;	/* Nothing to deallocate */
2856 	/* Free the header structure and anything allocated by it */
2857 	HH = gmt_get_H_hidden (h);
2858 	if (!GMT->parent->external) {
2859 		gmt_M_str_free (h->ProjRefWKT);
2860 		gmt_M_str_free (h->ProjRefPROJ4);
2861 	}
2862 	gmt_M_str_free (HH->pocket);
2863 	gmt_M_free (GMT, h->hidden);
2864 	gmt_M_free (GMT, *header);
2865 }
2866 
gmtlib_free_grid_ptr(struct GMT_CTRL * GMT,struct GMT_GRID * G,bool free_grid)2867 unsigned int gmtlib_free_grid_ptr (struct GMT_CTRL *GMT, struct GMT_GRID *G, bool free_grid) {
2868 	/* By taking a reference to the grid pointer we can set it to NULL when done */
2869 	struct GMT_GRID_HIDDEN *GH = NULL;
2870 	enum GMT_enum_alloc alloc_mode;
2871 	if (!G) return 0;	/* Nothing to deallocate */
2872 	/* Only free G->data if allocated by GMT AND free_grid is true */
2873 	GH = gmt_get_G_hidden (G);
2874 	if (G->data && free_grid) {
2875 		if (GH->alloc_mode == GMT_ALLOC_INTERNALLY) gmt_M_free_aligned (GMT, G->data);
2876 		G->data = NULL;	/* This will remove reference to external memory since gmt_M_free_aligned would not have been called */
2877 	}
2878 	if (G->x && GH->xy_alloc_mode[GMT_X] == GMT_ALLOC_INTERNALLY)
2879 		gmt_M_free (GMT, G->x);
2880 	if (G->y && GH->xy_alloc_mode[GMT_Y] == GMT_ALLOC_INTERNALLY)
2881 		gmt_M_free (GMT, G->y);
2882 	G->x = G->y = NULL;	/* This will remove reference to external memory since gmt_M_free would not have been called */
2883 	if (GH->extra) gmtlib_close_grd (GMT, G);	/* Close input file used for row-by-row i/o */
2884 	alloc_mode = GH->alloc_mode;
2885 	gmt_M_free (GMT, G->hidden);
2886 	gmt_free_header (GMT, &(G->header));	/* Free the header structure and anything allocated by it */
2887 	return (alloc_mode);
2888 }
2889 
gmt_free_grid(struct GMT_CTRL * GMT,struct GMT_GRID ** G,bool free_grid)2890 void gmt_free_grid (struct GMT_CTRL *GMT, struct GMT_GRID **G, bool free_grid) {
2891 	/* By taking a reference to the grid pointer we can set it to NULL when done */
2892 	(void)gmtlib_free_grid_ptr (GMT, *G, free_grid);
2893 	gmt_M_free (GMT, *G);
2894 }
2895 
gmt_set_outgrid(struct GMT_CTRL * GMT,char * file,bool separate,unsigned int min_pad,struct GMT_GRID * G,struct GMT_GRID ** Out)2896 int gmt_set_outgrid (struct GMT_CTRL *GMT, char *file, bool separate, unsigned int min_pad, struct GMT_GRID *G, struct GMT_GRID **Out) {
2897 	/* In most situations we can recycle the input grid to be the output grid as well.  However, there
2898 	 * are a few situations when we must override this situation:
2899 	 *   1) When OpenMP is enabled and calculations depend on nearby nodes.
2900 	 *   2) The input grid is a read-only memory location
2901 	 *   3) The intended output file is a memory location.
2902 	 * To avoid wasting memory we try to reuse the input array when
2903 	 * it is possible. We return true when new memory had to be allocated.
2904 	 * Note we duplicate the grid if we must so that Out always has the input
2905 	 * data in it (directly or via the pointer).
2906 	 * If the selected grid has a smaller pad than min_pad then we extend it to min_pad  */
2907 	bool add_pad = false;
2908 	unsigned int k, pad[4] = {min_pad, min_pad, min_pad, min_pad};
2909 	struct GMT_GRID_HIDDEN *GH = gmt_get_G_hidden (G);
2910 
2911 	for (k = 0; !add_pad && k < 4; k++)
2912 		if (G->header->pad[k] < min_pad) add_pad = true;
2913 	if (separate || gmt_M_file_is_memory (file) || GH->alloc_mode == GMT_ALLOC_EXTERNALLY) {	/* Cannot store results in a non-GMT read-only input array */
2914 		if ((*Out = GMT_Duplicate_Data (GMT->parent, GMT_IS_GRID, GMT_DUPLICATE_DATA, G)) == NULL) {
2915 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Unable to duplicate grid! - this is not a good thing and may crash this module\n");
2916 			(*Out) = G;
2917 		}
2918 		else {
2919 			struct GMT_GRID_HIDDEN *GH = gmt_get_G_hidden (*Out);
2920 			GH->alloc_mode = GMT_ALLOC_INTERNALLY;
2921 			if (add_pad) {
2922 				gmt_grd_pad_on (GMT, *Out, pad);	/* Add pad */
2923 				gmt_BC_init (GMT, (*Out)->header);	/* Initialize grid interpolation and boundary condition parameters */
2924 				gmt_grd_BC_set (GMT, *Out, GMT_IN);	/* Set boundary conditions */
2925 			}
2926 		}
2927 		return (true);
2928 	}
2929 	/* Here we may overwrite the input grid and just pass the pointer back */
2930 	(*Out) = G;
2931 	if (add_pad) {
2932 		gmt_grd_pad_on (GMT, *Out, pad);	/* Add pad */
2933 		gmt_BC_init (GMT, (*Out)->header);	/* Initialize grid interpolation and boundary condition parameters */
2934 		gmt_grd_BC_set (GMT, *Out, GMT_IN);	/* Set boundary conditions */
2935 	}
2936 	return (false);
2937 }
2938 
gmt_change_grdreg(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * header,unsigned int registration)2939 int gmt_change_grdreg (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *header, unsigned int registration) {
2940 	unsigned int old_registration;
2941 	double F;
2942 	gmt_M_unused(GMT);
2943 	/* Adjust the grid header to the selected registration, if different.
2944 	 * In all cases we return the original registration. */
2945 
2946 	old_registration = header->registration;
2947 	if (old_registration == registration) return (old_registration);	/* Noting to do */
2948 
2949 	F = (header->registration == GMT_GRID_PIXEL_REG) ? 0.5 : -0.5;	/* Pixel will shrink w/e/s/n, gridline will extend */
2950 	header->wesn[XLO] += F * header->inc[GMT_X];
2951 	header->wesn[XHI] -= F * header->inc[GMT_X];
2952 	header->wesn[YLO] += F * header->inc[GMT_Y];
2953 	header->wesn[YHI] -= F * header->inc[GMT_Y];
2954 
2955 	header->registration = registration;
2956 	header->xy_off = 0.5 * header->registration;
2957 	return (old_registration);
2958 }
2959 
gmt_cube_vminmax(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,gmt_grdfloat * z)2960 void gmt_cube_vminmax (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, gmt_grdfloat *z) {
2961 	/* Reset the vmin/vmax values in the header based on the non-NaN values in the cube */
2962 	unsigned int row, col, layer;
2963 	uint64_t node, offset = 0, n = 0;
2964 
2965 	h->z_min = DBL_MAX;	h->z_max = -DBL_MAX;
2966 	for (layer = 0; layer < h->n_bands; layer++) {
2967 		for (row = 0; row < h->n_rows; row++) {
2968 			for (col = 0, node = gmt_M_ijp (h, row, 0) + offset; col < h->n_columns; col++, node++) {
2969 				if (isnan (z[node]))
2970 					continue;
2971 				/* Update v_min, v_max (called z_min/max in header) */
2972 				h->z_min = MIN (h->z_min, (double)z[node]);
2973 				h->z_max = MAX (h->z_max, (double)z[node]);
2974 				n++;
2975 			}
2976 		}
2977 		offset += h->size;	/* Go to next layer */
2978 	}
2979 	if (n == 0) h->z_min = h->z_max = GMT->session.d_NaN;	/* No non-NaNs in the entire grid */
2980 }
2981 
gmt_grd_zminmax(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h,gmt_grdfloat * z)2982 void gmt_grd_zminmax (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h, gmt_grdfloat *z) {
2983 	/* Reset the zmin/zmax values in the header based on the non-NaN values in the grid */
2984 	unsigned int row, col;
2985 	uint64_t node, n = 0;
2986 
2987 	h->z_min = DBL_MAX;	h->z_max = -DBL_MAX;
2988 	for (row = 0; row < h->n_rows; row++) {
2989 		for (col = 0, node = gmt_M_ijp (h, row, 0); col < h->n_columns; col++, node++) {
2990 			if (isnan (z[node]))
2991 				continue;
2992 			/* Update z_min, z_max */
2993 			h->z_min = MIN (h->z_min, (double)z[node]);
2994 			h->z_max = MAX (h->z_max, (double)z[node]);
2995 			n++;
2996 		}
2997 	}
2998 	if (n == 0) h->z_min = h->z_max = GMT->session.d_NaN;	/* No non-NaNs in the entire grid */
2999 }
3000 
gmt_grd_minmax(struct GMT_CTRL * GMT,struct GMT_GRID * Grid,double xyz[2][3])3001 void gmt_grd_minmax (struct GMT_CTRL *GMT, struct GMT_GRID *Grid, double xyz[2][3]) {
3002 	/* Determine a grid's global min and max locations and z values; return via xyz */
3003 	unsigned int row, col, i;
3004 	uint64_t ij, i_minmax[2] = {0, 0};
3005 	gmt_grdfloat z_extreme[2] = {FLT_MAX, -FLT_MAX};
3006 	gmt_M_unused(GMT);
3007 
3008 	gmt_M_grd_loop (GMT, Grid, row, col, ij) {
3009 		if (gmt_M_is_fnan (Grid->data[ij])) continue;
3010 		if (Grid->data[ij] < z_extreme[0]) {
3011 			z_extreme[0] = Grid->data[ij];
3012 			i_minmax[0]  = ij;
3013 		}
3014 		if (Grid->data[ij] > z_extreme[1]) {
3015 			z_extreme[1] = Grid->data[ij];
3016 			i_minmax[1]  = ij;
3017 		}
3018 	}
3019 	for (i = 0; i < 2; i++) {	/* 0 is min, 1 is max */
3020 		xyz[i][GMT_X] = gmt_M_grd_col_to_x (GMT, gmt_M_col (Grid->header, i_minmax[i]), Grid->header);
3021 		xyz[i][GMT_Y] = gmt_M_grd_row_to_y (GMT, gmt_M_row (Grid->header, i_minmax[i]), Grid->header);
3022 		xyz[i][GMT_Z] = z_extreme[i];
3023 	}
3024 }
3025 
gmt_grd_detrend(struct GMT_CTRL * GMT,struct GMT_GRID * Grid,unsigned mode,double * coeff)3026 void gmt_grd_detrend (struct GMT_CTRL *GMT, struct GMT_GRID *Grid, unsigned mode, double *coeff) {
3027 	/* mode = 0 (GMT_FFT_REMOVE_NOTHING):  Do nothing.
3028 	 * mode = 1 (GMT_FFT_REMOVE_MEAN):  Remove the mean value (returned via a[0])
3029 	 * mode = 2 (GMT_FFT_REMOVE_MID):   Remove the mid value value (returned via a[0])
3030 	 * mode = 3 (GMT_FFT_REMOVE_TREND): Remove the best-fitting plane by least squares (returned via a[0-2])
3031 	 *
3032 	 * Note: The grid may be complex and contain real, imag, or both components.  The data should
3033 	 * be in serial layout so we may loop over the components and do our thing.  Only the real
3034 	 * components coefficients are returned.
3035 	 */
3036 
3037 	unsigned int col, row, one_or_zero, start_component = 0, stop_component = 0, component;
3038 	uint64_t ij, offset;
3039 	bool is_complex = false;
3040 	double x_half_length, one_on_xhl, y_half_length, one_on_yhl;
3041 	double sumx2, sumy2, data_var_orig = 0.0, data_var = 0.0, var_redux, x, y, z, a[3];
3042 	char *comp[2] = {"real", "imaginary"};
3043 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (Grid->header);
3044 
3045 	gmt_M_memset (coeff, 3, double);
3046 
3047 	if (HH->trendmode != GMT_FFT_REMOVE_NOTHING) {	/* Already removed the trend */
3048 		GMT_Report (GMT->parent, GMT_MSG_WARNING, "Grid has already been detrending - no action taken\n");
3049 		return;
3050 	}
3051 	if (mode == GMT_FFT_REMOVE_NOTHING) {	/* Do nothing */
3052 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "No detrending selected\n");
3053 		return;
3054 	}
3055 	HH->trendmode = mode;	/* Update grid header */
3056 	if (HH->arrangement == GMT_GRID_IS_INTERLEAVED) {
3057 		GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Demultiplexing complex grid before detrending can take place.\n");
3058 		gmt_grd_mux_demux (GMT, Grid->header, Grid->data, GMT_GRID_IS_SERIAL);
3059 	}
3060 
3061 	if (Grid->header->complex_mode & GMT_GRID_IS_COMPLEX_MASK) {	/* Complex grid */
3062 		is_complex = true;
3063 		start_component = (Grid->header->complex_mode & GMT_GRID_IS_COMPLEX_REAL) ? 0 : 1;
3064 		stop_component  = (Grid->header->complex_mode & GMT_GRID_IS_COMPLEX_IMAG) ? 1 : 0;
3065 	}
3066 
3067 	for (component = start_component; component <= stop_component; component++) {	/* Loop over 1 or 2 components */
3068 		offset = component * Grid->header->size / 2;	/* offset to start of this component in grid */
3069 		gmt_M_memset (a, 3, double);
3070 		if (mode == GMT_FFT_REMOVE_MEAN) {	/* Remove mean */
3071 			for (row = 0; row < Grid->header->n_rows; row++) for (col = 0; col < Grid->header->n_columns; col++) {
3072 				ij = gmt_M_ijp (Grid->header,row,col) + offset;
3073 				z = Grid->data[ij];
3074 				a[0] += z;
3075 				data_var_orig += z * z;
3076 			}
3077 			a[0] /= Grid->header->nm;
3078 			for (row = 0; row < Grid->header->n_rows; row++) for (col = 0; col < Grid->header->n_columns; col++) {
3079 				ij = gmt_M_ijp (Grid->header,row,col) + offset;
3080 				Grid->data[ij] -= (gmt_grdfloat)a[0];
3081 				z = Grid->data[ij];
3082 				data_var += z * z;
3083 			}
3084 			var_redux = 100.0 * (data_var_orig - data_var) / data_var_orig;
3085 			if (is_complex)
3086 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Mean value removed from %s component: %.8g Variance reduction: %.2f\n",
3087 				            comp[component], a[0], var_redux);
3088 			else
3089 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Mean value removed: %.8g Variance reduction: %.2f\n", a[0], var_redux);
3090 		}
3091 		else if (mode == GMT_FFT_REMOVE_MID) {	/* Remove mid value */
3092 			double zmin = DBL_MAX, zmax = -DBL_MAX;
3093 			for (row = 0; row < Grid->header->n_rows; row++) for (col = 0; col < Grid->header->n_columns; col++) {
3094 				ij = gmt_M_ijp (Grid->header,row,col) + offset;
3095 				z = Grid->data[ij];
3096 				data_var_orig += z * z;
3097 				if (z < zmin) zmin = z;
3098 				if (z > zmax) zmax = z;
3099 			}
3100 			a[0] = 0.5 * (zmin + zmax);	/* Mid value */
3101 			for (row = 0; row < Grid->header->n_rows; row++) for (col = 0; col < Grid->header->n_columns; col++) {
3102 				ij = gmt_M_ijp (Grid->header,row,col) + offset;
3103 				Grid->data[ij] -= (gmt_grdfloat)a[0];
3104 				z = Grid->data[ij];
3105 				data_var += z * z;
3106 			}
3107 			var_redux = 100.0 * (data_var_orig - data_var) / data_var_orig;
3108 			if (is_complex)
3109 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Mid value removed from %s component: %.8g Variance reduction: %.2f\n",
3110 				            comp[component], a[0], var_redux);
3111 			else
3112 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Mid value removed: %.8g Variance reduction: %.2f\n", a[0], var_redux);
3113 		}
3114 		else {	/* Here we wish to remove a LS plane */
3115 
3116 			/* Let plane be z = a0 + a1 * x + a2 * y.  Choose the
3117 			   center of x,y coordinate system at the center of
3118 			   the array.  This will make the Normal equations
3119 			   matrix G'G diagonal, so solution is trivial.  Also,
3120 			   spend some multiplications on normalizing the
3121 			   range of x,y into [-1,1], to avoid roundoff error.
3122 			 */
3123 
3124 			one_or_zero = (Grid->header->registration == GMT_GRID_PIXEL_REG) ? 0 : 1;
3125 			x_half_length = 0.5 * (Grid->header->n_columns - one_or_zero);
3126 			one_on_xhl = 1.0 / x_half_length;
3127 			y_half_length = 0.5 * (Grid->header->n_rows - one_or_zero);
3128 			one_on_yhl = 1.0 / y_half_length;
3129 
3130 			sumx2 = sumy2 = data_var = 0.0;
3131 
3132 			for (row = 0; row < Grid->header->n_rows; row++) {
3133 				y = one_on_yhl * (row - y_half_length);
3134 				for (col = 0; col < Grid->header->n_columns; col++) {
3135 					x = one_on_xhl * (col - x_half_length);
3136 					ij = gmt_M_ijp (Grid->header,row,col) + offset;
3137 					z = Grid->data[ij];
3138 					data_var_orig += z * z;
3139 					a[0] += z;
3140 					a[1] += z*x;
3141 					a[2] += z*y;
3142 					sumx2 += x*x;
3143 					sumy2 += y*y;
3144 				}
3145 			}
3146 			a[0] /= Grid->header->nm;
3147 			a[1] /= sumx2;
3148 			a[2] /= sumy2;
3149 			for (row = 0; row < Grid->header->n_rows; row++) {
3150 				y = one_on_yhl * (row - y_half_length);
3151 				for (col = 0; col < Grid->header->n_columns; col++) {
3152 					ij = gmt_M_ijp (Grid->header,row,col) + offset;
3153 					x = one_on_xhl * (col - x_half_length);
3154 					Grid->data[ij] -= (gmt_grdfloat)(a[0] + a[1]*x + a[2]*y);
3155 					data_var += (Grid->data[ij] * Grid->data[ij]);
3156 				}
3157 			}
3158 			var_redux = 100.0 * (data_var_orig - data_var) / data_var_orig;
3159 			data_var = sqrt (data_var / (Grid->header->nm - 1));
3160 			/* Rescale a1,a2 into user's units, in case useful later */
3161 			a[1] *= (2.0 / (Grid->header->wesn[XHI] - Grid->header->wesn[XLO]));
3162 			a[2] *= (2.0 / (Grid->header->wesn[YHI] - Grid->header->wesn[YLO]));
3163 			if (is_complex)
3164 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Plane removed from %s component. Mean, S.D., Dx, Dy: %.8g\t%.8g\t%.8g\t%.8g Variance reduction: %.2f\n",
3165 				            comp[component], a[0], data_var, a[1], a[2], var_redux);
3166 			else
3167 				GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "Plane removed.  Mean, S.D., Dx, Dy: %.8g\t%.8g\t%.8g\t%.8g Variance reduction: %.2f\n",
3168 				            a[0], data_var, a[1], a[2], var_redux);
3169 		}
3170 		if (component == 0) gmt_M_memcpy (coeff, a, 3, double);	/* Return the real component results */
3171 	}
3172 }
3173 
gmtlib_init_complex(struct GMT_GRID_HEADER * header,unsigned int complex_mode,uint64_t * imag_offset)3174 bool gmtlib_init_complex (struct GMT_GRID_HEADER *header, unsigned int complex_mode, uint64_t *imag_offset) {
3175 	/* Sets complex-related parameters based on the input complex_mode variable:
3176 	 * If complex_mode & GMT_GRID_NO_HEADER then we do NOT want to write a header [output only; only some formats]
3177 	 * If grid is the imaginary components of a complex grid then we compute the offset
3178 	 * from the start of the complex array where the first imaginary value goes, using the serial arrangement.
3179 	 */
3180 	bool do_header = !(complex_mode & GMT_GRID_NO_HEADER);	/* Want no header if this bit is set */
3181 	/* Imaginary components are stored after the real components if complex */
3182 	*imag_offset = (complex_mode & GMT_GRID_IS_COMPLEX_IMAG) ? header->size / 2ULL : 0ULL;
3183 
3184 	return (do_header);
3185 }
3186 
3187 /* Reverses the grid vertically, that is, from north up to south up or vice versa. */
gmt_grd_flip_vertical(void * gridp,const unsigned n_cols32,const unsigned n_rows32,const unsigned n_stride32,size_t cell_size)3188 void gmt_grd_flip_vertical (void *gridp, const unsigned n_cols32, const unsigned n_rows32, const unsigned n_stride32, size_t cell_size) {
3189 	/* Note: when grid is complex, pass 2x n_rows */
3190 	size_t row, n_cols = n_cols32, n_rows = n_rows32;
3191 	size_t rows_over_2 = (size_t) floor (n_rows / 2.0);
3192 	size_t stride = n_cols;	/* stride is the distance between rows. defaults to n_cols */
3193 	char *grid = (char*)gridp;
3194 	char *tmp = calloc (n_cols, cell_size);
3195 	char *top, *bottom;
3196 
3197 	if (n_stride32 != 0)
3198 		stride = (size_t)n_stride32;
3199 
3200 	for (row = 0; row < rows_over_2; ++row) {
3201 		/* pointer to top row: */
3202 		top = grid + row * stride * cell_size;
3203 		/* pointer to bottom row: */
3204 		bottom = grid + ( (n_rows - row) * stride - stride ) * cell_size;
3205 		memcpy (tmp, top, n_cols * cell_size);    /* save top row */
3206 		memcpy (top, bottom, n_cols * cell_size); /* copy bottom to top */
3207 		memcpy (bottom, tmp, n_cols * cell_size); /* copy tmp to bottom */
3208 	}
3209 	gmt_M_str_free (tmp);
3210 }
3211 
gmtlib_found_url_for_gdal(char * fname)3212 bool gmtlib_found_url_for_gdal (char *fname) {
3213 	/* File names starting as below should not be tested for existence or reading permissions as they
3214 	   are either meant to be read via GDAL.  Regular URLs (e.g., htthp://, ftp:// are read via libcurl. */
3215 	if (!strncmp(fname,"WCS:", 4)  ||
3216 		!strncmp(fname,"WMS:", 4)  ||
3217 		!strncmp(fname,"MVT:", 4)  ||
3218 		!strncmp(fname,"/vsi", 4)) {
3219 #ifdef WIN32
3220 		/* On Windows libcurl does not care about the certificates file (see https://github.com/curl/curl/issues/1538)
3221 		   and would fail, so no choice but prevent certificates verification.
3222 		   However, a CURL_CA_BUNDLE=/path/to/curl-ca-bundle.crt will overcome this and will consult the crt file. */
3223 		if (!getenv ("GDAL_HTTP_UNSAFESSL") && !getenv("CURL_CA_BUNDLE"))
3224 			putenv ("GDAL_HTTP_UNSAFESSL=YES");
3225 #endif
3226 		return true;
3227 	}
3228 	else
3229 		return false;
3230 }
3231 
gmtgrdio_get_extension_period(char * file)3232 GMT_LOCAL int gmtgrdio_get_extension_period (char *file) {
3233 	int i, pos_ext = 0;
3234 	for (i = (int)strlen(file) - 1; i > 0; i--) {
3235 		if (file[i] == '.') { 	/* Beginning of file extension */
3236 			pos_ext = i;
3237 			break;
3238 		}
3239 	}
3240 	return (pos_ext);
3241 }
3242 
3243 #define GMT_VF_TYPE_POS	13	/* Character in the virtual file name that indicates data family */
3244 
gmt_raster_type(struct GMT_CTRL * GMT,char * file,bool extra)3245 int gmt_raster_type (struct GMT_CTRL *GMT, char *file, bool extra) {
3246 	/* Returns the type of the file (either grid or image).
3247 	 * We use the file extension to make these decisions:
3248 	 * GMT_IS_IMAGE: In this context, this means a plain image
3249 	 *	that does not have any georeference information in it.
3250 	 *	The image types that fall into this category are
3251 	 *	GIF, JPG, RAS, PNG, BMP, WEBP, PBM, RGB.
3252 	 *	These are all detected by looking for magic bytes.
3253 	 * GMT_IS_GRID: In this context, this means file has an extension
3254 	 *	that could be used by images or images with geospatial
3255 	 *	data and even floating point values, such as geotiff.
3256 	 *	THus the list of types in this category are
3257 	 *	TIF, JP2, IMG (ERDAS).  These are detected via magic bytes.
3258 	 * GMT_NOTSET: This covers anything that fails to land in the
3259 	 *	other two categories.
3260 	 * extra will try to open the image to count bands.
3261 	 */
3262 	FILE *fp = NULL;
3263 	unsigned char data[16] = {""};
3264 	char *F = NULL, *p = NULL, path[PATH_MAX] = {""};
3265 	int j, code, pos_ext;
3266 
3267 	if (!file) return (GMT_ARG_IS_NULL);	/* Gave nothing */
3268 	if (gmt_M_file_is_memory (file)) {
3269 		return (file[GMT_VF_TYPE_POS] == 'G') ? GMT_NOTSET : GMT_IS_IMAGE;
3270 	}
3271 	if (gmt_M_file_is_remote (file) || gmt_M_file_is_url (file)) {	/* Must download, then modify the name */
3272 		j = gmt_download_file_if_not_found (GMT, file, 0);
3273 		F = strdup (&file[j]);
3274 	}
3275 	else
3276 		F = strdup (file);
3277 
3278 	if ((p = strstr(F, "=gd")) != NULL) *p = '\0';	/* Chop off any =gd<stuff> so that the opening test doesn't fail */
3279 	if (!gmt_getdatapath (GMT, F, path, R_OK)) {
3280 		gmt_M_str_free (F);
3281 		return GMT_GRDIO_FILE_NOT_FOUND;
3282 	}
3283 	pos_ext = gmtgrdio_get_extension_period (path) + 1;	/* Start of extension */
3284 	if ((fp = fopen (path, "rb")) == NULL) {
3285 		gmt_M_str_free (F);
3286 		return (GMT_ERROR_ON_FOPEN);
3287 	}
3288 	gmt_M_str_free (F);
3289 	if (gmt_M_fread (data, sizeof (unsigned char), 16, fp) < 16) {
3290 		fclose (fp);
3291 		return (GMT_GRDIO_READ_FAILED);	/* Failed to get one row */
3292 	}
3293 	fclose (fp);
3294 
3295 	/* Different magic chars for different image formats:
3296 	   .jpg:  FF D8 FF
3297 	   .png:  89 50 4E 47 0D 0A 1A 0A
3298 	   .gif:  GIF87a
3299 	          GIF89a
3300 	   .bmp:  BM
3301 	   .webp: RIFF ???? WEBP
3302 	   .ras   59 A6 6A 95
3303 	   .pbm   P 1-6
3304 	   .rgb   01 da
3305 	   .tif   49 49 2A 00 or 4D 4D 00 2A
3306 	   .jp2   00 00 00 0C 6A 50 20 20 0D 0A 87 0A
3307 	   .img   EHFA_HEADER_TAG
3308 	   .ige   ERDAS_IMG_EXTERNAL_RASTER
3309 	   .fits  53 49 4d 50 4c 45
3310 	   .ewc   06 02 01 02
3311  	*/
3312 
3313 	switch (data[0]) {
3314 		case 0x00:	/* JP2 */
3315 			code = ( !strncmp( (const char *)data, "\x00\x00\x00\x0C\x6A\x50\x20\x20\x0d\x0a\x87\x0a", 12 )) ? GMT_IS_GRID : GMT_NOTSET;	break;
3316 
3317 		case 0x01:	/* SGI Iris */
3318 			code = (( data[1] == 0xda )) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3319 
3320 		case 0x06:	/* EWC */
3321 			code = ( !strncmp( (const char *)data, "\x06\x02\x01\x02", 4 )) ? GMT_IS_GRID : GMT_NOTSET;	break;
3322 
3323 		case 0x53:	/* FITS */
3324 			code = ( !strncmp( (const char *)data, "\x53\x49\x4d\x50\x4c\x45", 6 )) ? GMT_IS_GRID : GMT_NOTSET;	break;
3325 
3326 		case 0x59:	/* Sun raster */
3327 			code =  ( !strncmp( (const char *)data, "\x59\xA6\x6A\x95", 4 )) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3328 
3329 		case 0x77:	/* OZI */
3330 			if (data[1] == 0x80 && gmt_strlcmp (&path[pos_ext], "ozfx3"))
3331 				code = GMT_IS_GRID;
3332 			else if (data[1] == 0x78 && gmt_strlcmp (&path[pos_ext], "ozf2"))
3333 				code = GMT_IS_GRID;
3334 			else
3335 				code = GMT_NOTSET;
3336 			break;
3337 		case 0x89:	/* PNG */
3338 			code = ( !strncmp( (const char *)data, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8 )) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3339 
3340 		case 0xFF:	/* JPG */
3341 			code = ( !strncmp( (const char *)data, "\xFF\xD8\xFF", 3 )) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3342 
3343 		case 'B':	/* BMP */
3344 			code = (( data[1] == 'M' && gmt_strlcmp (&path[pos_ext], "bmp"))) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3345 
3346 		case 'E':	/* IMG or IGE */
3347 			code = ( !strncmp( (const char *)data, "EHFA_HEADER_TAG", 15 ) || !strncmp( (const char *)data, "ERDAS_IMG_EXTER", 15 ) ) ? GMT_IS_GRID : GMT_NOTSET;	break;
3348 
3349 		case 'G':	/* GIF */
3350 			code = ( !strncmp( (const char *)data, "GIF87a", 6 ) || !strncmp( (const char *)data, "GIF89a", 6 ) ) ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3351 
3352 		case 'I':	/* TIF */
3353 			if (strstr (file, "earth_day") || strstr (file, "earth_night"))	/* We know these are images, not data */
3354 				code = GMT_IS_IMAGE;
3355 			else
3356 				code = ( !strncmp( (const char*)data, "\x49\x49\x2A\x00", 4 )) ? GMT_IS_GRID : GMT_NOTSET;
3357 			break;
3358 		case 'M':	/* TIF */
3359 			if (strstr (file, "earth_day") || strstr (file, "earth_night"))	/* We know these are images, not data */
3360 				code = GMT_IS_IMAGE;
3361 			else
3362 				code = ( !strncmp( (const char*)data, "\x4D\x4D\x00\x2A", 4 )) ? GMT_IS_GRID : GMT_NOTSET;
3363 			break;
3364 		case 'P':	/* PPM (also check that extension starts with p since the magic bytes are a bit weak ) */
3365 			code = (data[1] >= '1' && data[1] <= '6' && tolower (path[pos_ext]) == 'p') ? GMT_IS_IMAGE : GMT_NOTSET;	break;
3366 
3367 		case 'R':	/* Google WEBP */
3368 			if ( !strncmp ((const char *)data, "RIFF", 4) || !strncmp ((const char *)(data+8), "WEBP", 4))
3369 				code = GMT_IS_IMAGE;
3370 			else
3371 				code = GMT_NOTSET;
3372 			break;
3373 
3374 		default:	/* Just consider file extensions at this point */
3375 			/* .sid (MrSID), .ecw (ECW), .kap (BSB), .gen (ADRG), .map (OZI) */
3376 			if (gmt_strlcmp (&path[pos_ext], "sid") || gmt_strlcmp (&path[pos_ext], "ecw") ||
3377 			    gmt_strlcmp (&path[pos_ext], "kap") || gmt_strlcmp (&path[pos_ext], "gen") ||
3378 				gmt_strlcmp (&path[pos_ext], "map"))
3379 				code = GMT_IS_GRID;
3380 			else
3381 				code =  GMT_NOTSET;
3382 			break;
3383 	}
3384 
3385 	if (extra && code != GMT_IS_IMAGE && (data[0] == 'I' || data[0] == 'M')) {	/* Need to check more to determine if TIFF is grid or image */
3386 		/* See if input could be an image of a kind that could also be a grid and we don't yet know what it is.  Pass GMT_GRID_IS_IMAGE mode */
3387 		struct GMT_IMAGE *I = NULL;
3388 		if ((I = GMT_Read_Data (GMT->parent, GMT_IS_IMAGE, GMT_IS_FILE, GMT_IS_SURFACE, GMT_CONTAINER_ONLY | GMT_GRID_IS_IMAGE, NULL, file, NULL)) != NULL) {
3389 			struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (I->header);	/* Get pointer to hidden structure */
3390 			if (HH->pocket && strchr (HH->pocket, ',') == NULL)	/* Got a single band request which we return as a grid */
3391 				code = GMT_IS_GRID;
3392 			else if (HH->orig_datatype == GMT_UCHAR || HH->orig_datatype == GMT_CHAR)	/* Got a gray or RGB image with or without transparency */
3393 				code = GMT_IS_IMAGE;
3394 			else if (I->header->n_bands > 1)	/* Whatever it is we must return multiband as an image */
3395 				code = GMT_IS_IMAGE;
3396 			else	/* Here we only have one band so it is a grid */
3397 				code = GMT_IS_GRID;
3398 			GMT_Destroy_Data (GMT->parent, &I);
3399 		}
3400 	}
3401 	if (code == GMT_IS_IMAGE)
3402 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "%s considered a valid image instead of grid. Open via GDAL\n", file);
3403 	else if (code == GMT_IS_GRID)
3404 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "%s may be image or grid.  Open via GDAL for checking\n", file);
3405 	else
3406 		GMT_Report (GMT->parent, GMT_MSG_DEBUG, "%s is most likely a grid. Open in GMT as grid\n", file);
3407 
3408 	return code;
3409 }
3410 
gmt_img_sanitycheck(struct GMT_CTRL * GMT,struct GMT_GRID_HEADER * h)3411 int gmt_img_sanitycheck (struct GMT_CTRL *GMT, struct GMT_GRID_HEADER *h) {
3412 	/* Make sure that IMG Mercator grids are not used with map projections for plotting */
3413 
3414 	if (strncmp (h->remark, GMT_IMG_REMARK, strlen(GMT_IMG_REMARK))) return GMT_NOERROR;	/* Not a Mercator img grid since missing the critical remark format */
3415 	if (h->registration == GMT_GRID_NODE_REG) return GMT_NOERROR;		/* Cannot be a Mercator img grid since they are all pixel registered */
3416 	if (GMT->current.proj.projection == GMT_LINEAR) return GMT_NOERROR;	/* Only linear projection is allowed with this projected grid */
3417 	GMT_Report (GMT->parent, GMT_MSG_ERROR, "Cannot use a map projection with an already projected grid (spherical Mercator img grid).  Use -Jx or -JX.\n");
3418 	return GMT_PROJECTION_ERROR;
3419 }
3420 
3421 /* 3-D GMT_CUBE handling is here */
3422 
gmtgrdio_get_cube(struct GMT_CTRL * GMT)3423 GMT_LOCAL struct GMT_CUBE *gmtgrdio_get_cube (struct GMT_CTRL *GMT) {
3424 	struct GMT_CUBE *C = NULL;
3425 	C = gmt_M_memory (GMT, NULL, 1, struct GMT_CUBE);
3426 	C->hidden = gmt_M_memory (GMT, NULL, 1, struct GMT_CUBE_HIDDEN);
3427 	return (C);
3428 }
3429 
gmtlib_create_cube(struct GMT_CTRL * GMT)3430 struct GMT_CUBE *gmtlib_create_cube (struct GMT_CTRL *GMT) {
3431 	/* Allocates space for a new cube container.  No space allocated for the gmt_grdfloat cube itself */
3432 	struct GMT_CUBE *C = NULL;
3433 	struct GMT_CUBE_HIDDEN *GU = NULL;
3434 
3435 	C = gmtgrdio_get_cube (GMT);
3436 	GU = gmt_get_U_hidden (C);
3437 	C->header = gmt_get_header (GMT);
3438 	gmt_grd_init (GMT, C->header, NULL, false); /* Set default values */
3439 #ifdef DOUBLE_PRECISION_GRID
3440 	C->header->type = GMT_GRID_IS_ND;
3441 #else
3442 	C->header->type = GMT_GRID_IS_NF;
3443 #endif
3444 	GMT_Set_Index (GMT->parent, C->header, GMT_GRID_LAYOUT);
3445 	GU->alloc_mode = GMT_ALLOC_INTERNALLY;		/* Memory can be freed by GMT. */
3446 	GU->alloc_level = GMT->hidden.func_level;	/* Must be freed at this level. */
3447 	GU->id = GMT->parent->unique_var_ID++;		/* Give unique identifier */
3448 	return (C);
3449 }
3450 
gmtlib_duplicate_cube(struct GMT_CTRL * GMT,struct GMT_CUBE * U,unsigned int mode)3451 struct GMT_CUBE *gmtlib_duplicate_cube (struct GMT_CTRL *GMT, struct GMT_CUBE *U, unsigned int mode) {
3452 	/* Duplicates an entire grid, including data if requested. */
3453 	struct GMT_CUBE *Unew = NULL;
3454 
3455 	Unew = gmtlib_create_cube (GMT);
3456 	gmt_copy_gridheader (GMT, Unew->header, U->header);
3457 	gmt_M_memcpy (Unew->z_range, U->z_range, 2U, double);
3458 	Unew->z_inc = U->z_inc;
3459 	Unew->mode = U->mode;
3460 	strncpy (Unew->name, U->name, GMT_GRID_UNIT_LEN80-1);
3461 	strncpy (Unew->units, U->units, GMT_GRID_UNIT_LEN80-1);
3462 
3463 	if ((mode & GMT_DUPLICATE_DATA) || (mode & GMT_DUPLICATE_ALLOC)) {	/* Also allocate and possibly duplicate data array */
3464 		struct GMT_CUBE_HIDDEN *UH = gmt_get_U_hidden (Unew);
3465 		if ((mode & GMT_DUPLICATE_RESET) && !gmt_grd_pad_status (GMT, U->header, GMT->current.io.pad)) {
3466 			/* Pads differ and we requested resetting the pad */
3467 			gmt_M_grd_setpad (GMT, Unew->header, GMT->current.io.pad);	/* Set default pad size */
3468 			gmt_set_grddim (GMT, Unew->header);	/* Update size dimensions given the change of pad */
3469 			if (mode & GMT_DUPLICATE_DATA) {	/* Per row since grid sizes will not the same */
3470 				uint64_t node_in, node_out, k, off_in = 0, off_out = 0;
3471 				unsigned int row;
3472 				Unew->data = gmt_M_memory_aligned (GMT, NULL, Unew->header->size * Unew->header->n_bands, gmt_grdfloat);
3473 				for (k = 0; k < U->header->n_bands; k++, off_in += U->header->size, off_out += Unew->header->size) {
3474 					for (row = 0; row < U->header->n_rows; row++) {
3475 						node_in  = gmt_M_ijp (U->header, row, 0)    + off_in;
3476 						node_out = gmt_M_ijp (Unew->header, row, 0) + off_out;
3477 						gmt_M_memcpy (&Unew->data[node_out], &U->data[node_in], U->header->n_columns, gmt_grdfloat);
3478 					}
3479 				}
3480 			}
3481 		}
3482 		else {	/* Can do fast copy of the whole cube */
3483 			Unew->data = gmt_M_memory_aligned (GMT, NULL, U->header->size * U->header->n_bands, gmt_grdfloat);
3484 			if (mode & GMT_DUPLICATE_DATA) gmt_M_memcpy (Unew->data, U->data, U->header->size * U->header->n_bands, gmt_grdfloat);
3485 		}
3486 
3487 		Unew->x = gmt_grd_coord (GMT, Unew->header, GMT_X);	/* Get array of x coordinates */
3488 		Unew->y = gmt_grd_coord (GMT, Unew->header, GMT_Y);	/* Get array of y coordinates */
3489 		UH->xyz_alloc_mode[GMT_X] = UH->xyz_alloc_mode[GMT_Y] = GMT_ALLOC_INTERNALLY;
3490 		if (U->z) {
3491 			Unew->z = gmt_duplicate_array (GMT, U->z, U->header->n_bands);
3492 			UH->xyz_alloc_mode[GMT_Z] = GMT_ALLOC_INTERNALLY;
3493 		}
3494 	}
3495 	return (Unew);
3496 }
3497 
gmtlib_free_cube_ptr(struct GMT_CTRL * GMT,struct GMT_CUBE * U,bool free_cube)3498 unsigned int gmtlib_free_cube_ptr (struct GMT_CTRL *GMT, struct GMT_CUBE *U, bool free_cube) {
3499 	/* By taking a reference to the grid pointer we can set it to NULL when done */
3500 	struct GMT_CUBE_HIDDEN *UH = NULL;
3501 	enum GMT_enum_alloc alloc_mode;
3502 	if (!U) return 0;	/* Nothing to deallocate */
3503 	/* Only free G->data if allocated by GMT AND free_grid is true */
3504 	UH = gmt_get_U_hidden (U);
3505 	if (U->data && free_cube) {
3506 		if (UH->alloc_mode == GMT_ALLOC_INTERNALLY) gmt_M_free_aligned (GMT, U->data);
3507 		U->data = NULL;	/* This will remove reference to external memory since gmt_M_free_aligned would not have been called */
3508 	}
3509 	if (U->x && UH->xyz_alloc_mode[GMT_X] == GMT_ALLOC_INTERNALLY)
3510 		gmt_M_free (GMT, U->x);
3511 	if (U->y && UH->xyz_alloc_mode[GMT_Y] == GMT_ALLOC_INTERNALLY)
3512 		gmt_M_free (GMT, U->y);
3513 	if (U->z && UH->xyz_alloc_mode[GMT_Z] == GMT_ALLOC_INTERNALLY)
3514 		gmt_M_free (GMT, U->z);
3515 	U->x = U->y = U->z = NULL;	/* This will remove reference to external memory since gmt_M_free would not have been called */
3516 	alloc_mode = UH->alloc_mode;
3517 	gmt_M_free (GMT, U->hidden);
3518 	gmt_free_header (GMT, &(U->header));	/* Free the header structure and anything allocated by it */
3519 	return (alloc_mode);
3520 }
3521 
gmtlib_free_cube(struct GMT_CTRL * GMT,struct GMT_CUBE ** U,bool free_cube)3522 void gmtlib_free_cube (struct GMT_CTRL *GMT, struct GMT_CUBE **U, bool free_cube) {
3523 	/* By taking a reference to the grid pointer we can set it to NULL when done */
3524 	(void)gmtlib_free_cube_ptr (GMT, *U, free_cube);
3525 	gmt_M_free (GMT, *U);
3526 }
3527 
gmt_get_active_layers(struct GMT_CTRL * GMT,struct GMT_CUBE * U,double * range,uint64_t * start_k,uint64_t * stop_k)3528 uint64_t gmt_get_active_layers (struct GMT_CTRL *GMT, struct GMT_CUBE *U, double *range, uint64_t *start_k, uint64_t *stop_k) {
3529 	/* Return via start_k, stop_k the first and last index of the selected layers */
3530 	uint64_t n_layers = U->header->n_bands, n_layers_used;
3531 	if (range[0] > U->z[n_layers-1] || range[1] < U->z[0]) {
3532 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "gmt_get_active_layers: Requested range is outside the valid cube range.\n");
3533 		return 0;
3534 	}
3535 	*start_k = 0; *stop_k = n_layers - 1;	/* We first assume all layers are needed */
3536 	while (*start_k < n_layers && range[0] > U->z[*start_k])	/* Find the first layer that is inside the selected range */
3537 		(*start_k)++;
3538 	if (*start_k && range[0] < U->z[*start_k]) (*start_k)--;		/* Go back one if start is less than first layer */
3539 	while (*stop_k && range[1] < U->z[*stop_k])	/* Find the last layer that is inside the output time range */
3540 		(*stop_k)--;
3541 	if (*stop_k < (n_layers - 1) && range[1] > U->z[*stop_k]) (*stop_k)++;	/* Go forward one if stop is larger than last layer */
3542 	n_layers_used = *stop_k - *start_k + 1;	/* Total number of input layers needed */
3543 	return (n_layers_used);
3544 }
3545 
3546 #ifdef HAVE_GDAL
gmtgrdio_gdal_free_from(struct GMT_CTRL * GMT,struct GMT_GDALREAD_OUT_CTRL * from_gdalread)3547 GMT_LOCAL void gmtgrdio_gdal_free_from (struct GMT_CTRL *GMT, struct GMT_GDALREAD_OUT_CTRL *from_gdalread) {
3548 	int i;
3549 	if (from_gdalread->band_field_names) {
3550 		for (i = 0; i < from_gdalread->RasterCount; i++ )
3551 			if (from_gdalread->band_field_names[i].DataType)
3552 				gmt_M_str_free (from_gdalread->band_field_names[i].DataType);	/* Those were allocated with strdup */
3553 		gmt_M_free (GMT, from_gdalread->band_field_names);
3554 	}
3555 	if (from_gdalread->ColorMap) gmt_M_free (GMT, from_gdalread->ColorMap);	/* Maybe we will have a use for this in future, but not yet */
3556 }
3557 
gmtlib_read_image_info(struct GMT_CTRL * GMT,char * file,bool must_be_image,struct GMT_IMAGE * I)3558 int gmtlib_read_image_info (struct GMT_CTRL *GMT, char *file, bool must_be_image, struct GMT_IMAGE *I) {
3559 	size_t k;
3560 	char *p;
3561 	double dumb;
3562 	struct GMT_GDALREAD_IN_CTRL *to_gdalread = NULL;
3563 	struct GMT_GDALREAD_OUT_CTRL *from_gdalread = NULL;
3564 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (I->header);
3565 
3566 	/* Allocate new control structures */
3567 	to_gdalread   = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_IN_CTRL);
3568 	from_gdalread = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_OUT_CTRL);
3569 
3570 	to_gdalread->M.active = true;	/* Get metadata only */
3571 
3572 	k = strlen (file) - 1;
3573 	while (k && file[k] && file[k] != '+') k--;	/* See if we have a band request */
3574 	if (k && file[k+1] == 'b') {
3575 		/* Yes we do. Put the band string into the 'pocket' where gmtlib_read_image will look and finish the request */
3576 		HH->pocket = strdup (&file[k+2]);
3577 		file[k] = '\0';
3578 	}
3579 	if ((p = strstr (file, "=gd")) != NULL) *p = '\0';	/* Chop off any =<stuff> */
3580 
3581 	if (gmt_gdalread (GMT, file, to_gdalread, from_gdalread)) {
3582 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "ERROR reading image with gdalread.\n");
3583 		gmt_M_free (GMT, to_gdalread);
3584 		gmtgrdio_gdal_free_from (GMT, from_gdalread);
3585 		gmt_M_free (GMT, from_gdalread);
3586 		return (GMT_GRDIO_READ_FAILED);
3587 	}
3588 	if (from_gdalread->band_field_names != NULL) {	/* Know the data type */
3589 		if (!strcmp(from_gdalread->band_field_names[0].DataType, "Byte"))
3590 			I->type = GMT_UCHAR;
3591 		else if (!strcmp(from_gdalread->band_field_names[0].DataType, "Int16"))
3592 			I->type = GMT_SHORT;
3593 		else if (!strcmp(from_gdalread->band_field_names[0].DataType, "UInt16"))
3594 			I->type = GMT_USHORT;
3595 		else if (!strcmp(from_gdalread->band_field_names[0].DataType, "Int32"))
3596 			I->type = GMT_INT;
3597 		else if (!strcmp(from_gdalread->band_field_names[0].DataType, "UInt32"))
3598 			I->type = GMT_UINT;
3599 		else if (!must_be_image && !strcmp(from_gdalread->band_field_names[0].DataType, "Float32"))
3600 			I->type = GMT_FLOAT;
3601 		else if (!must_be_image && !strcmp(from_gdalread->band_field_names[0].DataType, "Float64"))
3602 			I->type = GMT_FLOAT;	/* No doubles for grids or images */
3603 		else  {
3604 			GMT_Report (GMT->parent, GMT_MSG_ERROR, "Using this data type (%s) is not implemented\n",
3605 			            from_gdalread->band_field_names[0].DataType);
3606 			gmt_M_free (GMT, to_gdalread);
3607 			gmtgrdio_gdal_free_from (GMT, from_gdalread);
3608 			gmt_M_free (GMT, from_gdalread);
3609 			return (GMT_NOT_A_VALID_TYPE);
3610 		}
3611 	}
3612 
3613 	I->color_interp    = from_gdalread->color_interp;     /* Must find out how to release this mem */
3614 	I->n_indexed_colors = from_gdalread->nIndexedColors;
3615 	gmt_M_str_free (I->header->ProjRefPROJ4);		/* Make sure we don't leak due to a previous copy */
3616 	gmt_M_str_free (I->header->ProjRefWKT);
3617 	I->header->ProjRefPROJ4 = from_gdalread->ProjRefPROJ4;
3618 	I->header->ProjRefWKT   = from_gdalread->ProjRefWKT;
3619 	I->header->ProjRefEPSG  = from_gdalread->ProjRefEPSG;
3620 	I->header->inc[GMT_X] = from_gdalread->hdr[7];
3621 	I->header->inc[GMT_Y] = from_gdalread->hdr[8];
3622 	I->header->n_columns = from_gdalread->RasterXsize;
3623 	I->header->n_rows = from_gdalread->RasterYsize;
3624 	I->header->n_bands = from_gdalread->RasterCount;
3625 	I->header->registration = (int)from_gdalread->hdr[6];
3626 	I->header->z_min = from_gdalread->hdr[4];	/* Whatever that means for an image */
3627 	I->header->z_max = from_gdalread->hdr[5];
3628 	/* These are always pixel-reg, so they would be wrong when we are returning grid-reg
3629 	I->header->wesn[XLO] = from_gdalread->Corners.LL[0];
3630 	I->header->wesn[XHI] = from_gdalread->Corners.UR[0];
3631 	I->header->wesn[YLO] = from_gdalread->Corners.LL[1];
3632 	I->header->wesn[YHI] = from_gdalread->Corners.UR[1];
3633 	*/
3634 	I->header->wesn[XLO] = from_gdalread->hdr[0];
3635 	I->header->wesn[XHI] = from_gdalread->hdr[1];
3636 	I->header->wesn[YLO] = from_gdalread->hdr[2];
3637 	I->header->wesn[YHI] = from_gdalread->hdr[3];
3638 	if (I->header->wesn[YHI] < I->header->wesn[YLO]) {	/* Simple images have that annoying origin at UL and y positive down */
3639 		dumb = I->header->wesn[YHI];
3640 		I->header->wesn[YHI] = I->header->wesn[YLO];
3641 		I->header->wesn[YLO] = dumb;
3642 	}
3643 	if (I->header->ProjRefPROJ4 && (strstr (I->header->ProjRefPROJ4, "longlat") || strstr (I->header->ProjRefPROJ4, "latlong")))
3644 		gmt_set_geographic (GMT, GMT_IN);	/* A geographic image */
3645 
3646 	HH->grdtype = gmtlib_get_grdtype (GMT, GMT_IN, I->header);
3647 	gmt_set_grddim (GMT, I->header);		/* This recomputes n_columns|n_rows. Dangerous if -R is not compatible with inc */
3648 	GMT_Set_Index (GMT->parent, I->header, GMT_IMAGE_LAYOUT);
3649 
3650 	gmt_M_free (GMT, to_gdalread);
3651 	gmtgrdio_gdal_free_from (GMT, from_gdalread);
3652 	gmt_M_free (GMT, from_gdalread);
3653 
3654 	return (GMT_NOERROR);
3655 }
3656 
gmtlib_read_image(struct GMT_CTRL * GMT,char * file,struct GMT_IMAGE * I,double * wesn,unsigned int * pad,unsigned int complex_mode)3657 int gmtlib_read_image (struct GMT_CTRL *GMT, char *file, struct GMT_IMAGE *I, double *wesn, unsigned int *pad, unsigned int complex_mode) {
3658 	/* file:	- IGNORED -
3659 	 * image:	array with final image
3660 	 * wesn:	Sub-region to extract  [Use entire file if NULL or contains 0,0,0,0]
3661 	 * padding:	# of empty rows/columns to add on w, e, s, n of image, respectively
3662 	 * complex_mode:	&1 | &2 if complex array is to hold real (1) and imaginary (2) parts (otherwise read as real only)
3663 	 *		Note: The file has only real values, we simply allow space in the array
3664 	 *		for imaginary parts when processed by grdfft etc.
3665 	 */
3666 
3667 	int    i;
3668 	bool   expand;
3669 	char   strR[GMT_LEN128];
3670 	struct GRD_PAD P;
3671 	struct GMT_GDALREAD_IN_CTRL  *to_gdalread = NULL;
3672 	struct GMT_GDALREAD_OUT_CTRL *from_gdalread = NULL;
3673 	struct GMT_GRID_HEADER_HIDDEN *HH = gmt_get_H_hidden (I->header);
3674 	gmt_M_unused(complex_mode);
3675 
3676 	expand = gmtgrdio_padspace (GMT, I->header, wesn, true, pad, &P);	/* true if we can extend the region by the pad-size to obtain real data for BC */
3677 
3678 	/* Allocate new control structures */
3679 	to_gdalread   = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_IN_CTRL);
3680 	from_gdalread = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_OUT_CTRL);
3681 
3682 	if (GMT->common.R.active[RSET]) {
3683 		if (gmt_M_360_range (I->header->wesn[XLO], I->header->wesn[XHI])) {	/* Ensure we handle -180/180 and 0/360 right */
3684 			if (P.wesn[XLO] > I->header->wesn[XHI]) P.wesn[XLO] -= 360.0, P.wesn[XHI] -= 360.0;
3685 			else if (P.wesn[XHI] < I->header->wesn[XLO]) P.wesn[XLO] += 360.0, P.wesn[XHI] += 360.0;
3686 		}
3687 		snprintf (strR, GMT_LEN128, "%.10f/%.10f/%.10f/%.10f", P.wesn[XLO], P.wesn[XHI], P.wesn[YLO], P.wesn[YHI]);
3688 		to_gdalread->R.region = strR;
3689 		to_gdalread->registration.val = I->header->registration;	/* Due to pix-reg only by GDAL we need to inform it about our reg type */
3690  		to_gdalread->registration.x_inc = I->header->inc[GMT_X];
3691  		to_gdalread->registration.y_inc = I->header->inc[GMT_Y];
3692 		to_gdalread->R.active = true;	/* Wait until we really know how to use it */
3693 	}
3694 
3695 	if (HH->pocket) {				/* See if we have a band request */
3696 		to_gdalread->B.active = true;
3697 		to_gdalread->B.bands = HH->pocket;	/* Band parsing and error testing is done in gmt_gdalread */
3698 	}
3699 
3700 	if (pad) {
3701 		gmt_M_memcpy (to_gdalread->p.pad, P.pad, 4U, unsigned int);
3702 		to_gdalread->p.active = gmtgrdio_pad_status (GMT, P.pad);
3703 	}
3704 	to_gdalread->I.active = true;		/* Means that image in I->data will be BIP interleaved */
3705 
3706 	/* Tell gmt_gdalread that we already have the memory allocated and send in the *data pointer */
3707 	if (I->data) {		/* Otherwise (subregion) memory is allocated in gdalread */
3708 		if (I->type == GMT_FLOAT || I->type == GMT_DOUBLE) {
3709 			to_gdalread->f_ptr.active = true;
3710 			to_gdalread->f_ptr.grd = (gmt_grdfloat *)I->data;
3711 		}
3712 		else {
3713 			to_gdalread->c_ptr.active = true;
3714 			to_gdalread->c_ptr.grd = I->data;
3715 		}
3716 	}
3717 	if (HH->grdtype > GMT_GRID_GEOGRAPHIC_LESS360) to_gdalread->R.periodic = true;	/* Let gmt_gdalread know we have a periodic image */
3718 	if (gmt_gdalread (GMT, file, to_gdalread, from_gdalread)) {
3719 		GMT_Report (GMT->parent, GMT_MSG_ERROR, "ERROR reading image with gdalread.\n");
3720 		gmt_M_free (GMT, to_gdalread);
3721 		for (i = 0; i < from_gdalread->RasterCount; i++)
3722 			gmt_M_str_free (from_gdalread->band_field_names[i].DataType);	/* Those were allocated with strdup */
3723 		gmt_M_free (GMT, from_gdalread->band_field_names);
3724 		gmt_M_free (GMT, from_gdalread);
3725 		return (GMT_GRDIO_READ_FAILED);
3726 	}
3727 
3728 	if (to_gdalread->O.mem_layout[0]) 	/* If a different mem_layout request was applied in gmt_gdalread than we must update */
3729 		gmt_strncpy(I->header->mem_layout, to_gdalread->O.mem_layout, 4);
3730 
3731 	if (to_gdalread->B.active) gmt_M_str_free (HH->pocket);		/* It was allocated by strdup. Free it for an eventual reuse. */
3732 
3733 	I->colormap = from_gdalread->ColorMap;
3734 	I->n_indexed_colors  = from_gdalread->nIndexedColors;
3735 	I->header->n_bands = from_gdalread->nActualBands;	/* What matters here on is the number of bands actually read */
3736 
3737 	gmt_M_memcpy (I->header->wesn, from_gdalread->hdr, 4, double);	/* Set the actual w/e/s/n bounds */
3738 
3739 	if (expand)	/* Must undo the region extension and reset n_columns, n_rows */
3740 		gmt_M_memcpy (I->header->wesn, wesn, 4, double);
3741 	gmt_M_grd_setpad (GMT, I->header, pad);	/* Copy the pad to the header */
3742 	gmt_set_grddim (GMT, I->header);	/* Update header items */
3743 	HH->grdtype = gmtlib_get_grdtype (GMT, GMT_IN, I->header);
3744 
3745 	gmt_M_free (GMT, to_gdalread);
3746 	for (i = 0; i < from_gdalread->RasterCount; i++)
3747 		gmt_M_str_free (from_gdalread->band_field_names[i].DataType);	/* Those were allocated with strdup */
3748 	gmt_M_free (GMT, from_gdalread->band_field_names);
3749 	gmt_M_free (GMT, from_gdalread);
3750 	gmt_BC_init (GMT, I->header);	/* Initialize image interpolation and boundary condition parameters */
3751 
3752 	return (GMT_NOERROR);
3753 }
3754 #endif
3755