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  * gmt_macros.h contains definitions of macros used through GMT.
19  *
20  * Author:	Paul Wessel
21  * Date:	01-OCT-2009
22  * Version:	6 API
23  */
24 
25 /*!
26  * \file gmt_macros.h
27  * \brief Definitions of macros used through GMT.
28  */
29 
30 #ifndef GMT_MACROS_H
31 #define GMT_MACROS_H
32 
33 /*--------------------------------------------------------------------
34  *			GMT MACROS DEFINITIONS
35  *--------------------------------------------------------------------*/
36 
37 #define gmt_M_compat_check(C,version) (C->current.setting.compatibility <= version)	/* true if this section should be processed with backwards compatibility to given version */
38 
39 #ifndef MIN
40 #define MIN(x, y) (((x) < (y)) ? (x) : (y))	/* min and max value macros */
41 #endif
42 #ifndef MAX
43 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
44 #endif
45 #ifndef MOD	/* Knuth-style modulo function (remainder after floored division) */
46 #define MOD(x, y) (x - y * floor((double)(x)/(double)(y)))
47 #endif
48 
49 #ifdef DOUBLE_PRECISION_GRID
50 #define GMT_GRDFLOAT GMT_DOUBLE
51 #define gmt_nc_get_vara_grdfloat nc_get_vara_double
52 #define gmt_nc_put_vara_grdfloat nc_put_vara_double
53 #define gmt_nc_get_varm_grdfloat nc_get_varm_double
54 #define gmt_nc_put_varm_grdfloat nc_put_varm_double
55 #else
56 #define gmt_nc_get_vara_grdfloat nc_get_vara_float
57 #define gmt_nc_put_vara_grdfloat nc_put_vara_float
58 #define gmt_nc_get_varm_grdfloat nc_get_varm_float
59 #define gmt_nc_put_varm_grdfloat nc_put_varm_float
60 #endif
61 
62 /*! Macro to apply columns log/scale/offset conversion on the fly */
63 #define gmt_M_convert_col(S,x) ((S.convert) ? ((S.convert & 2) ? log10 (x) : x) * S.scale + S.offset : x)
64 
65 /* This macro is called via each modules "Return" macro so API and options are available */
66 #define gmt_M_free_options(mode) {if (GMT_Destroy_Options (API, &options) != GMT_OK) return (GMT_MEMORY_ERROR);}
67 
68 /*! Safe math macros that check arguments */
69 
70 #define d_log2(C,x) ((x) <= 0.0f ? C->session.f_NaN : log2 (x))
71 #define d_log10(C,x) ((x) <= 0.0 ? C->session.d_NaN : log10 (x))
72 #define d_log10f(C,x) ((x) <= 0.0f ? C->session.f_NaN : log10f (x))
73 #define d_log101p(C,x) ((x) <= -1.0 ? C->session.d_NaN : log10 (1.0+(x)))
74 #define d_log101pf(C,x) ((x) <= -1.0f ? C->session.f_NaN : log10f (1.0f+(x)))
75 #define d_sqrt(x) ((x) < 0.0 ? 0.0 : sqrt (x))
76 #define d_acos(x) (fabs(x) >= 1.0 ? ((x) < 0.0 ? M_PI : 0.0) : acos(x))
77 #define d_acosf(x) (fabsf(x) >= 1.0 ? ((x) < 0.0f ? (float)M_PI : 0.0f) : acosf(x))
78 #define d_asin(x) (fabs(x) >= 1.0 ? copysign (M_PI_2, x) : asin(x))
79 #define d_asinf(x) (fabsf(x) >= 1.0 ? copysignf ((float)M_PI_2, x) : asinf(x))
80 #define d_atan2(y,x) ((x) == 0.0 && (y) == 0.0 ? 0.0 : atan2(y, x))
81 #define d_atan2f(y,x) ((x) == 0.0f && (y) == 0.0f ? 0.0f : atan2f(y, x))
82 #define d_log(C,x) ((x) <= 0.0 ? C->session.d_NaN : log (x))
83 #define d_logf(C,x) ((x) <= 0.0f ? C->session.f_NaN : logf (x))
84 #define d_log1p(C,x) ((x) <= -1.0 ? C->session.d_NaN : log1p (x))
85 #define d_log1pf(C,x) ((x) <= -1.0f ? C->session.f_NaN : log1pf (x))
86 
87 /*! Macros for degree-based trig */
88 
89 #define sind(x) sin((x) * D2R)
90 #define sindf(x) sinf((x) * D2R)
91 #define cosd(x) cos((x) * D2R)
92 #define cosdf(x) cosf((x) * D2R)
93 #define tand(x) tan((x) * D2R)
94 #define tandf(x) tanf((x) * D2R)
95 #define sincosd(x,s,c) sincos((x) * D2R,s,c)
96 #define asind(x) (asin(x) * R2D)
97 #define acosd(x) (acos(x) * R2D)
98 #define atand(x) (atan(x) * R2D)
99 #define atan2d(y,x) (atan2(y,x) * R2D)
100 #define atan2df(y,x) (atan2f(y,x) * R2D)
101 
102 /*! Safe versions of the degree-based trig */
103 
104 #define d_acosd(x) (fabs(x) >= 1.0 ? ((x) < 0.0 ? 180.0 : 0.0) : acosd(x))
105 #define d_asind(x) (fabs(x) >= 1.0 ? copysign (90.0, (x)) : asind(x))
106 #define d_atan2d(y,x) ((x) == 0.0 && (y) == 0.0 ? 0.0 : atan2d(y,x))
107 
108 /* Extract column type for given direction and column number */
109 #define gmt_M_type(C,dir,col) (C->current.io.col_type[dir][col])
110 /* Compare column type to given type -- true if the same */
111 #define gmt_M_is_type(C,dir,col,type) (gmt_M_type(C,dir,col) == type)
112 
113 /*! Macros for swapping misc data types */
114 
115 #define gmt_M_bool_swap(x, y) {bool bool_tmp; bool_tmp = x, x = y, y = bool_tmp;}
116 #define gmt_M_char_swap(x, y) {char char_tmp; char_tmp = x, x = y, y = char_tmp;}
117 #define gmt_M_charp_swap(x, y) {char *char_tmp; char_tmp = x, x = y, y = char_tmp;}
118 #define gmt_M_uint64_swap(x, y) {uint64_t uint64_t_tmp; uint64_t_tmp = x, x = y, y = uint64_t_tmp;}
119 #define gmt_M_int_swap(x, y) {int int_tmp; int_tmp = x, x = y, y = int_tmp;}
120 #define gmt_M_uint_swap(x, y) {unsigned int uint_tmp; uint_tmp = x, x = y, y = uint_tmp;}
121 #define gmt_M_double_swap(x, y) {double double_tmp; double_tmp = x, x = y, y = double_tmp;}
122 #define gmt_M_doublep_swap(x, y) {double *double_tmp; double_tmp = x, x = y, y = double_tmp;}
123 #define gmt_M_float_swap(x, y) {float float_tmp; float_tmp = x, x = y, y = float_tmp;}
124 
125 /*! Macro to ensure proper value and sign of a change in longitude from lon1 to lon2 */
126 #define gmt_M_set_delta_lon(lon1,lon2,delta) {delta = fmod ((lon2) - (lon1), 360.0); if (fabs (delta) > 180.0) delta = copysign (360.0 - fabs (delta), -delta);}
127 
128 /*! Macro to simplify call to memcpy when duplicating values and memset when zeroing out */
129 #define gmt_M_memcpy(to,from,n,type) memcpy(to, from, (n)*sizeof(type))
130 #define gmt_M_memset(array,n,type) memset(array, 0, (n)*sizeof(type))
131 /*! Macro to set all items in an array to the given value */
132 #define gmt_M_setnval(array,n,value) {uint64_t k; for (k = 0; k < (uint64_t)n; k++) array[k] = value;}
133 /*! Macro to simplify assignment of one 3-vector to another */
134 #define gmt_M_cpy3v(to,from) memcpy(to, from, 3*sizeof(double))
135 
136 /*! Macros for printing a tic/toc elapsed time message*/
137 #define gmt_M_tic(C) {if (C->current.setting.verbose == GMT_MSG_TICTOC) GMT_Message(C->parent,GMT_TIME_RESET,"");}
138 #define gmt_M_toc(C,...) {if (C->current.setting.verbose == GMT_MSG_TICTOC) GMT_Message(C->parent,GMT_TIME_ELAPSED, \
139 		"(%s) | %s\n", C->init.module_name, __VA_ARGS__);}
140 
141 /*! Cleaner check to see if a line is associated with the extended syntax or not */
142 #define gmt_M_showusage(API) (!API->GMT->common.synopsis.extended)
143 
144 /* COLOR MACROS */
145 
146 /* Determine if fill is in fact a pattern */
147 /* Old: always starts with integer dpi.
148  * New: Either start with pattern 1-88 or a file which should have an extension */
149 #define gmt_M_is_pattern(txt) ((txt[0] == 'p' || txt[0] == 'P') && (isdigit((int)txt[1]) || strchr(txt,'.')))
150 
151 /* Determine if this CPT slice requires a pattern */
152 #define gmt_M_cptslice_is_pattern(P,index) ((index >= 0 && P->data[index].fill != NULL) || (index < 0 && P->bfn[index+3].fill != NULL))
153 
154 /* Determine if this CPT slice requires a pattern */
155 #define gmt_M_get_cptslice_pattern(P,index) ((index >= 0) ? P->data[index].fill : P->bfn[index+3].fill)
156 
157 /* Determine if we should skip this CPT slice */
158 #define gmt_M_skip_cptslice(P,index) ((index >= 0 && P->data[index].skip) || (index < 0 && P->bfn[index+3].skip))
159 
160 /* See if CPT modifiers was given (+h|i|u|U) */
161 #define gmt_M_cpt_mod(arg) ((arg) && ((arg)[0] =='+' && strchr (GMT_CPTFILE_MODIFIERS, (arg)[1])))
162 
163 /* See if no CPT name was given (+u|U modifier may be present but not filename) */
164 #define gmt_M_no_cpt_given(arg) (arg == NULL || arg[0] == '\0' || gmt_M_cpt_mod(arg))
165 
166 /*! Copy two RGB[T] arrays (a = b) including transparency */
167 #define gmt_M_rgb_copy(a,b) memcpy (a, b, 4 * sizeof(double))
168 
169 /*! Copy two RGB[T] arrays (a = b) excluding transparency */
170 #define gmt_M_rgb_only_copy(a,b) memcpy (a, b, 3 * sizeof(double))
171 
172 /*! To compare is two colors are ~ the same */
173 #define gmt_M_eq(a,b) (fabs((a)-(b)) < GMT_CONV4_LIMIT)
174 #define gmt_M_same_rgb(a,b) (gmt_M_eq(a[0],b[0]) && gmt_M_eq(a[1],b[1]) && gmt_M_eq(a[2],b[2]) && gmt_M_eq(a[3],b[3]))
175 
176 /*! To compare is two pens are ~ the same */
177 #define gmt_M_same_pen(a,b) (gmt_M_eq(a.width,b.width) && gmt_M_eq(a.offset,b.offset) && gmt_M_same_rgb(a.rgb,b.rgb) && !strcmp (a.style, b.style))
178 
179 /*! Macros for conversion of RGB in 0-1 range to 0-255 range */
180 #define gmt_M_s255(s) ((s) * 255.0)
181 #define gmt_M_t255(t,k) gmt_M_q(gmt_M_s255(t[k]))
182 
183 #define gmt_M_u255(s) ((unsigned char)rint(gmt_M_s255(s)))
184 
185 /*! Macros for conversion of RGB in 0-255 range to 0-1 range */
186 #define gmt_M_is255(s) ((s) / 255.0)
187 
188 /*! Macro to avoid small numbers in color codes */
189 #define gmt_M_q(s) ((s) < 1e-5 ? 0.0 : (s))
190 
191 /*! How B/W TV's convert RGB to Gray */
192 #define gmt_M_yiq(rgb) (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2])
193 
194 /*! Determine if a RGB combination is grayshade */
195 #define gmt_M_is_gray(rgb) (gmt_M_eq(rgb[0],rgb[1]) && gmt_M_eq(rgb[1],rgb[2]))
196 
197 /*! Determine if a RGB combination is in fact B/W */
198 #define gmt_M_is_bw(rgb) (gmt_M_is_gray(rgb) && (gmt_M_eq(rgb[0],0.0) || gmt_M_eq(rgb[0],1.0)))
199 
200 /*! Get a color component from a n*4 column-oriented colormap */
201 #define gmt_M_get_rgba(map,index,color,n) map[index + (color)*(n)]
202 
203 /*! Set a color component in a n*4 column-oriented colormap */
204 #define gmt_M_set_rgba(map,index,color,n,value) map[index + (color)*(n)] = (value)
205 
206 /*! Macros to do conversion to inches with PROJ_LENGTH_UNIT as default */
207 
208 #define gmt_M_to_inch(GMT,value) gmt_convert_units (GMT, value, GMT->current.setting.proj_length_unit, GMT_INCH)
209 #define gmt_M_to_points(GMT,value) gmt_convert_units (GMT, value, GMT->current.setting.proj_length_unit, GMT_PT)
210 
211 /*! Determine default justification for box item */
212 #define gmt_M_just_default(GMT,refpoint,just) (refpoint->mode == GMT_REFPOINT_JUST_FLIP ? gmt_flip_justify(GMT,refpoint->justify) : refpoint->mode == GMT_REFPOINT_JUST ? refpoint->justify : just)
213 
214 /*! Determine if we have a remote file, special URL files or queries, or special netCDF files */
215 #define gmt_M_file_is_remote(file) (file != NULL && !gmt_M_file_is_memory(file) && file[0] == '@')
216 #define gmt_M_file_is_url(file) (file != NULL && (!strncmp (file, "http:", 5U) || !strncmp (file, "https:", 6U) || !strncmp (file, "ftp:", 4U)))
217 #define gmt_M_file_is_query(file) (gmt_M_file_is_url(file) && strchr (file, '?') && strchr (file, '='))
218 #define gmt_M_file_is_netcdf(file) (!gmt_M_file_is_url(file) && strchr (file, '?'))
219 #define gmt_M_file_is_netcdf_layer(file) (gmt_M_file_is_netcdf(file) && (strchr (file, '(') || strchr (file, '[')))
220 
221 /*! Determine if file is an image GDAL can read */
222 #define gmt_M_file_is_image(file) (file != NULL && (strstr (file, "=gd") || strstr (file, ".jpg") || strstr (file, ".png") || strstr (file, ".ppm") || strstr (file, ".tif") || strstr (file, ".bmp") || strstr (file, ".gif")))
223 
224 /*! Set the correct column mode (trailing vs no trailing text) based on the given string is NULL or not */
225 #define gmt_M_colmode(text) ((text == NULL) ? GMT_COL_FIX_NO_TEXT : GMT_COL_FIX)
226 
227 #endif  /* GMT_MACROS_H */
228