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