1 /*!
2  * \file lib/raster/null_val.c
3  *
4  * \brief Raster Library - NULL value management
5  *
6  * To provide functionality to handle NULL values for data types CELL,
7  * FCELL, and DCELL. May need more...
8  *
9  * (C) 2001-2009 GRASS Development Team
10  *
11  * This program is free software under the GNU General Public License
12  * (>=v2). Read the file COPYING that comes with GRASS for details.
13  *
14  * \author Original author unknown - probably CERL
15  * \author Justin Hickey - Thailand - jhickey@hpcc.nectec.or.th
16  */
17 
18 /* System include files */
19 #include <string.h>
20 
21 /* Grass and local include files */
22 #include <grass/gis.h>
23 #include <grass/raster.h>
24 #include <grass/glocale.h>
25 
26 static void EmbedGivenNulls(void *, char *, RASTER_MAP_TYPE, int);
27 
28 /*!
29    \brief To insert null values into a map. Needs more.....
30 
31    \param cell raster values
32    \param nulls raster null values
33    \param map_type type of raster - CELL, FCELL, DCELL
34    \param ncols number of columns
35  */
EmbedGivenNulls(void * cell,char * nulls,RASTER_MAP_TYPE map_type,int ncols)36 void EmbedGivenNulls(void *cell, char *nulls, RASTER_MAP_TYPE map_type,
37 		     int ncols)
38 {
39     CELL *c;
40     FCELL *f;
41     DCELL *d;
42     int i;
43 
44     c = (CELL *) cell;
45     f = (FCELL *) cell;
46     d = (DCELL *) cell;
47 
48     for (i = 0; i < ncols; i++) {
49 	if (nulls[i]) {
50 	    switch (map_type) {
51 	    case CELL_TYPE:
52 		Rast_set_c_null_value((CELL *) (c + i), 1);
53 		break;
54 
55 	    case FCELL_TYPE:
56 		Rast_set_f_null_value((FCELL *) (f + i), 1);
57 		break;
58 
59 	    case DCELL_TYPE:
60 		Rast_set_d_null_value((DCELL *) (d + i), 1);
61 		break;
62 
63 	    default:
64 		G_warning(_("EmbedGivenNulls: wrong data type"));
65 	    }
66 	}
67     }
68 }
69 
70 /*!
71    \brief To set one or more raster values to null.
72 
73    It also sets null to zero if null_is_zero is TRUE.
74 
75    \param rast pointer to values to set to null
76    \param numVals number of values to set to null
77    \param null_is_zero flag to indicate if NULL = 0
78    \param data_type type of raster - CELL, FCELL, DCELL
79  */
Rast__set_null_value(void * rast,int numVals,int null_is_zero,RASTER_MAP_TYPE data_type)80 void Rast__set_null_value(void *rast, int numVals, int null_is_zero,
81 			  RASTER_MAP_TYPE data_type)
82 {
83     if (null_is_zero) {
84 	G_zero((char *)rast, numVals * Rast_cell_size(data_type));
85 	return;
86     }
87 
88     Rast_set_null_value(rast, numVals, data_type);
89 }
90 
91 /*!
92    \brief To set one or more raster values to null.
93 
94    \param buf pointer to values to set to null
95    \param numVals number of values to set to null
96    \param data_type type of raster - CELL, FCELL, DCELL
97  */
Rast_set_null_value(void * buf,int numVals,RASTER_MAP_TYPE data_type)98 void Rast_set_null_value(void *buf, int numVals, RASTER_MAP_TYPE data_type)
99 {
100     switch (data_type) {
101     case CELL_TYPE:
102 	Rast_set_c_null_value((CELL *) buf, numVals);
103 	break;
104 
105     case FCELL_TYPE:
106 	Rast_set_f_null_value((FCELL *) buf, numVals);
107 	break;
108 
109     case DCELL_TYPE:
110 	Rast_set_d_null_value((DCELL *) buf, numVals);
111 	break;
112 
113     default:
114 	G_warning(_("Rast_set_null_value: wrong data type!"));
115     }
116 }
117 
118 /*!
119    \brief To set a number of CELL raster values to NULL.
120 
121    \param cellVals pointer to CELL values to set to null
122    \param numVals  number of values to set to null
123  */
Rast_set_c_null_value(CELL * cellVals,int numVals)124 void Rast_set_c_null_value(CELL * cellVals, int numVals)
125 {
126     int i;			/* counter */
127 
128     for (i = 0; i < numVals; i++)
129 	cellVals[i] = (int)0x80000000;
130 }
131 
132 /*!
133    \brief To set a number of FCELL raster values to NULL.
134 
135    \param fcellVals pointer to FCELL values to set to null
136    \param numVals number of values to set to null
137  */
Rast_set_f_null_value(FCELL * fcellVals,int numVals)138 void Rast_set_f_null_value(FCELL * fcellVals, int numVals)
139 {
140     static const unsigned char null_bits[4] = {
141 	0xFF, 0xFF, 0xFF, 0xFF
142     };
143     int i;
144 
145     for (i = 0; i < numVals; i++)
146 	memcpy(&fcellVals[i], null_bits, sizeof(null_bits));
147 }
148 
149 /*!
150    \brief To set a number of DCELL raster values to NULL.
151 
152    \param dcellVals pointer to DCELL values to set to null
153    \param numVals number of values to set to null
154  */
Rast_set_d_null_value(DCELL * dcellVals,int numVals)155 void Rast_set_d_null_value(DCELL * dcellVals, int numVals)
156 {
157     static const unsigned char null_bits[8] = {
158 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
159     };
160     int i;
161 
162     for (i = 0; i < numVals; i++)
163 	memcpy(&dcellVals[i], null_bits, sizeof(null_bits));
164 }
165 
166 /*!
167    \brief To check if a raster value is set to NULL
168 
169    - If the <em>data_type</em> is CELL_TYPE, calls Rast_is_c_null_value()
170    - If the <em>data_type</em> is FCELL_TYPE, calls Rast_is_f_null_value()
171    - If the <em>data_type</em> is DCELL_TYPE, calls Rast_is_d_null_value()
172 
173    \param rast raster value to check
174    \param data_type type of raster - CELL, FCELL, DCELL
175 
176    \return TRUE if raster value is NULL
177    \return FALSE otherwise
178  */
Rast_is_null_value(const void * rast,RASTER_MAP_TYPE data_type)179 int Rast_is_null_value(const void *rast, RASTER_MAP_TYPE data_type)
180 {
181     switch (data_type) {
182     case CELL_TYPE:
183 	return (Rast_is_c_null_value((CELL *) rast));
184 
185     case FCELL_TYPE:
186 	return (Rast_is_f_null_value((FCELL *) rast));
187 
188     case DCELL_TYPE:
189 	return (Rast_is_d_null_value((DCELL *) rast));
190 
191     default:
192 	G_warning("Rast_is_null_value: wrong data type!");
193 	return FALSE;
194     }
195 }
196 
197 /*!
198    \brief To check if a CELL raster value is set to NULL
199 
200    Returns 1 if <em>cell</em> is NULL, 0 otherwise. This will test if the
201    value <em>cell</em> is the largest <tt>int</tt>.
202 
203    \param cellVal CELL raster value to check
204 
205    \return TRUE if CELL raster value is NULL
206    \return FALSE otherwise
207  */
208 #ifndef Rast_is_c_null_value
Rast_is_c_null_value(const CELL * cellVal)209 int Rast_is_c_null_value(const CELL * cellVal)
210 {
211     /* Check if the CELL value matches the null pattern */
212     return *cellVal == (CELL) 0x80000000;
213 }
214 #endif
215 
216 /*!
217    \brief To check if a FCELL raster value is set to NULL
218 
219    Returns 1 if <em>fcell</em> is NULL, 0 otherwise. This will test if
220    the value <em>fcell</em> is a NaN. It isn't good enough to test for
221    a particular NaN bit pattern since the machine code may change this
222    bit pattern to a different NaN. The test will be
223 
224    \code
225    if(fcell==0.0) return 0;
226    if(fcell>0.0) return 0;
227    if(fcell<0.0) return 0;
228    return 1;
229    \endcode
230 
231    or (as suggested by Mark Line)
232    \code
233    return (fcell != fcell);
234    \endcode
235 
236    \param fcellVal FCELL raster value to check
237 
238    \return TRUE if FCELL raster value is NULL
239    \return FALSE otherwise
240  */
241 #ifndef Rast_is_f_null_value
Rast_is_f_null_value(const FCELL * fcellVal)242 int Rast_is_f_null_value(const FCELL * fcellVal)
243 {
244     return *fcellVal != *fcellVal;
245 }
246 #endif
247 
248 /*!
249    \brief To check if a DCELL raster value is set to NULL
250 
251    Returns 1 if <em>dcell</em> is NULL, 0 otherwise. This will test if
252    the value <em>dcell</em> is a NaN. Same test as in
253    Rast_is_f_null_value().
254 
255    \param dcellVal DCELL raster value to check
256 
257    \return TRUE if DCELL raster value is NULL
258    \return FALSE otherwise
259  */
260 #ifndef Rast_is_d_null_value
Rast_is_d_null_value(const DCELL * dcellVal)261 int Rast_is_d_null_value(const DCELL * dcellVal)
262 {
263     return *dcellVal != *dcellVal;
264 }
265 #endif
266 
267 /*!
268    \brief To insert null values into a map.
269 
270    - If the <em>data_type</em> is CELL_TYPE, calls Rast_insert_c_null_values()
271    - If the <em>data_type</em> is FCELL_TYPE, calls Rast_insert_f_null_values()
272    - If the <em>data_type</em> is DCELL_TYPE, calls Rast_insert_d_null_values()
273 
274    \param rast pointer raster values
275    \param null_row null row
276    \param ncols number of columns
277    \param data_type type of raster - CELL, FCELL, DCELL
278  */
Rast_insert_null_values(void * rast,char * null_row,int ncols,RASTER_MAP_TYPE data_type)279 void Rast_insert_null_values(void *rast, char *null_row, int ncols,
280 			     RASTER_MAP_TYPE data_type)
281 {
282     EmbedGivenNulls(rast, null_row, data_type, ncols);
283 }
284 
285 /*!
286    \brief To insert null values into an integer raster map (CELL)
287 
288    For each of the <em>count</em> <em>flags</em> which is true(!=0),
289    set the corresponding <em>cell</em> to the NULL value.
290 
291    \param rast pointer raster values
292    \param null_row null row
293    \param ncols number of columns
294  */
Rast_insert_c_null_values(CELL * cellVal,char * null_row,int ncols)295 void Rast_insert_c_null_values(CELL * cellVal, char *null_row, int ncols)
296 {
297     EmbedGivenNulls((void *)cellVal, null_row, CELL_TYPE, ncols);
298 }
299 
300 /*!
301    \brief To insert null values into an floating-point raster map (FCELL)
302 
303    \param fcellVal pointer raster values
304    \param null_row null row
305    \param ncols number of columns
306  */
Rast_insert_f_null_values(FCELL * fcellVal,char * null_row,int ncols)307 void Rast_insert_f_null_values(FCELL * fcellVal, char *null_row, int ncols)
308 {
309     EmbedGivenNulls((void *)fcellVal, null_row, FCELL_TYPE, ncols);
310 }
311 
312 /*!
313    \brief To insert null values into an floating-point raster map (FCELL)
314 
315    For each for the <em>count</em> <em>flag</em> which is true(!=0), set
316    the corresponding <em>dcell</em> to the NULL value.
317 
318    \param dcellVal pointer raster values
319    \param null_row null row
320    \param ncols number of columns
321  */
Rast_insert_d_null_values(DCELL * dcellVal,char * null_row,int ncols)322 void Rast_insert_d_null_values(DCELL * dcellVal, char *null_row, int ncols)
323 {
324     EmbedGivenNulls((void *)dcellVal, null_row, DCELL_TYPE, ncols);
325 }
326 
327 /*!
328    \brief Check NULL
329 
330    Note: Only for internal use.
331 
332    \param flags null bitmap
333    \param bit_num index of bit to check
334    \param n size of null bitmap (in bits)
335 
336    \return 1 if set, 0 if unset
337  */
Rast__check_null_bit(const unsigned char * flags,int bit_num,int n)338 int Rast__check_null_bit(const unsigned char *flags, int bit_num, int n)
339 {
340     int ind;
341     int offset;
342 
343     /* check that bit_num is in range */
344     if (bit_num < 0 || bit_num >= n)
345 	G_fatal_error("Rast__check_null_bit: index %d out of range (size = %d).",
346 		      bit_num, n);
347 
348 
349     /* find the index of the unsigned char in which this bit appears */
350     ind = bit_num / 8;
351 
352     offset = bit_num & 7;
353 
354     return ((flags[ind] & ((unsigned char)0x80 >> offset)) != 0);
355 }
356 
357 /*!
358    \brief Given array of 0/1 of length n starting from column.
359 
360    Note: Only for internal use.
361 
362    Given array of 0/1 of length n starting from column set the
363    corresponding bits of flags; total number of bits in flags is ncols.
364 
365    \param zero_ones
366    \param flags
367    \param col
368    \param n
369    \param ncols
370 
371    \return 0
372    \return 1
373  */
G__set_flags_from_01_random(const char * zero_ones,unsigned char * flags,int col,int n,int ncols)374 int G__set_flags_from_01_random(const char *zero_ones, unsigned char *flags,
375 				int col, int n, int ncols)
376 {
377     unsigned char v;
378     int count;
379     int size;
380     int i, k;
381 
382     if (col == 0 && n == ncols) {
383 	Rast__convert_01_flags(zero_ones, flags, n);
384 	return 0;
385     }
386 
387     count = 0;
388     size = Rast__null_bitstream_size(ncols);
389 
390     for (i = 0; i < size; i++) {
391 	v = 0;
392 	k = 8;
393 
394 	while (k-- > 0) {
395 	    if (count >= col && count < (col + n)) {
396 		v = v | ((unsigned char)zero_ones[count - col] << k);
397 	    }
398 	    else if (count < ncols) {
399 		v = v |
400 		    ((unsigned char)Rast__check_null_bit(flags, count, ncols)
401 		     << k);
402 	    }
403 
404 	    /* otherwise  keep this bit the same as it was */
405 	    count++;
406 	}
407 
408 	flags[i] = v;
409     }
410 
411     return 1;
412 }
413 
414 /*!
415    \brief ?
416 
417    Note: Only for internal use.
418 
419    \param zero_ones
420    \param flags
421    \param n
422  */
Rast__convert_01_flags(const char * zero_ones,unsigned char * flags,int n)423 void Rast__convert_01_flags(const char *zero_ones, unsigned char *flags,
424 			    int n)
425 {
426     unsigned char *v;
427     int count;
428     int size;
429     int i, k;
430 
431     /* pad the flags with 0's to make size multiple of 8 */
432     v = flags;
433     size = Rast__null_bitstream_size(n);
434     count = 0;
435 
436     for (i = 0; i < size; i++) {
437 	*v = 0;
438 	k = 8;
439 
440 	while (k-- > 0) {
441 	    if (count < n) {
442 		*v = *v | ((unsigned char)zero_ones[count] << k);
443 	    }
444 
445 	    count++;
446 	}
447 
448 	v++;
449     }
450 }
451 
452 /*!
453    \brief ?
454 
455    Note: Only for internal use.
456 
457    \param zero_ones
458    \param flags
459    \param n
460  */
Rast__convert_flags_01(char * zero_ones,const unsigned char * flags,int n)461 void Rast__convert_flags_01(char *zero_ones, const unsigned char *flags,
462 			    int n)
463 {
464     const unsigned char *v;
465     int count;
466     int size;
467     int i, k;
468 
469     count = 0;
470     v = flags;
471     size = Rast__null_bitstream_size(n);
472 
473     for (i = 0; i < size; i++) {
474 	k = 8;
475 
476 	while (k-- > 0) {
477 	    if (count < n) {
478 		zero_ones[count] = ((*v & ((unsigned char)1 << k)) != 0);
479 		count++;
480 	    }
481 	}
482 
483 	v++;
484     }
485 }
486 
487 /*!
488    \brief ?
489 
490    Note: Only for internal use.
491 
492    \param flags
493    \param cols
494  */
Rast__init_null_bits(unsigned char * flags,int cols)495 void Rast__init_null_bits(unsigned char *flags, int cols)
496 {
497     unsigned char *v;
498     int size;
499     int i;
500 
501     /* pad the flags with 0's to make size multiple of 8 */
502     v = flags;
503     size = Rast__null_bitstream_size(cols);
504 
505     for (i = 0; i < size; i++) {
506 	if ((i + 1) * 8 <= cols) {
507 	    *v = (unsigned char)255;
508 	}
509 	else {
510 	    *v = (unsigned char)255 << ((i + 1) * 8 - cols);
511 	}
512 
513 	v++;
514     }
515 }
516