1 /*!
2    \file lib/ogsf/gs3.c
3 
4    \brief OGSF library - loading surfaces (lower level functions)
5 
6    GRASS OpenGL gsurf OGSF Library
7 
8    (C) 1999-2008 by the GRASS Development Team
9 
10    This program is free software under the
11    GNU General Public License (>=v2).
12    Read the file COPYING that comes with GRASS
13    for details.
14 
15    \author Bill Brown USACERL, GMSL/University of Illinois (January 1993)
16    \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
17  */
18 
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include <grass/gis.h>
23 #include <grass/raster.h>
24 #include <grass/glocale.h>
25 #include <grass/bitmap.h>
26 
27 #include <grass/ogsf.h>
28 /* for geoview & geodisplay in 3dview stuff */
29 #include "gsget.h"
30 /* for update_attrange - might be able to move this func now */
31 
32 /*!
33    \brief Used in the function Gs_update_attrange()
34  */
35 #define INIT_MINMAX(p, nm, size, min, max, found) \
36 	found = 0; \
37 	p+=(size-1); \
38 	while (size--) \
39 	{ \
40 	    if (!BM_GET_BYOFFSET(nm, size)) \
41 	    { \
42 		min = max = *p; \
43 		found = 1; \
44 		break; \
45 	    } \
46 	    p--; \
47 	}
48 
49 /*!
50    \brief Used in the function Gs_update_attrange()
51  */
52 #define SET_MINMAX(p, nm, size, min, max) \
53 	p+=(size-1); \
54 	while(size--) \
55 	{ \
56 	    if (!BM_GET_BYOFFSET(nm, size)) \
57 	    { \
58 		if (*p < min) \
59 		{ \
60 		    min = *p; \
61 		} \
62 		else if (*p > max) \
63 		{ \
64 		    max = *p; \
65 		}  \
66 	    } \
67 	    p--; \
68 	}
69 
70 typedef int FILEDESC;
71 
72 #define NO_DATA_COL 0xffffff
73 
74 /*!
75    \brief Calculates distance in METERS between two points in current projection (2D)
76 
77    Uses G_distance().
78 
79    \param from 'from' point (X, Y)
80    \param to 'to' point (X, Y)
81 
82    \return distance
83  */
Gs_distance(double * from,double * to)84 double Gs_distance(double *from, double *to)
85 {
86     static int first = 1;
87 
88     if (first) {
89 	first = 0;
90 	G_begin_distance_calculations();
91     }
92 
93     return G_distance(from[0], from[1], to[0], to[1]);
94 }
95 
96 /*!
97    \brief Load raster map as floating point map
98 
99    Calling function must have already allocated space in buff for
100    wind->rows * wind->cols floats.
101 
102    This routine simply loads the map into a 2d array by repetitve calls
103    to get_f_raster_row.
104 
105    \param wind current window
106    \param map_name raster map name
107    \param[out] buff data buffer
108    \param[out] nullmap null map buffer
109    \param[out] has_null indicates if raster map contains null-data
110 
111    \return 1 on success
112    \return 0 on failure
113  */
Gs_loadmap_as_float(struct Cell_head * wind,const char * map_name,float * buff,struct BM * nullmap,int * has_null)114 int Gs_loadmap_as_float(struct Cell_head *wind, const char *map_name,
115 			float *buff, struct BM *nullmap, int *has_null)
116 {
117     FILEDESC cellfile;
118     const char *map_set;
119     int offset, row, col;
120 
121     G_debug(3, "Gs_loadmap_as_float(): name=%s", map_name);
122 
123     map_set = G_find_raster2(map_name, "");
124     if (!map_set) {
125 	G_warning(_("Raster map <%s> not found"), map_name);
126 	return 0;
127     }
128     *has_null = 0;
129 
130     cellfile = Rast_open_old(map_name, map_set);
131 
132     G_message(_("Loading raster map <%s>..."),
133 	      G_fully_qualified_name(map_name, map_set));
134 
135     for (row = 0; row < wind->rows; row++) {
136 	offset = row * wind->cols;
137 	Rast_get_f_row(cellfile, &(buff[offset]), row);
138 
139 	G_percent(row, wind->rows, 2);
140 
141 	for (col = 0; col < wind->cols; col++) {
142 	    if (Rast_is_f_null_value(buff + offset + col)) {
143 		*has_null = 1;
144 		BM_set(nullmap, col, row, 1);
145 	    }
146 	    /* set nm */
147 	}
148     }
149     G_percent(1, 1, 1);
150 
151     G_debug(4, "  has_null=%d", *has_null);
152 
153     Rast_close(cellfile);
154 
155     return (1);
156 }
157 
158 /*!
159    \brief Load raster map as integer map
160 
161    Calling function must have already allocated space in buff for
162    wind->rows * wind->cols floats.
163 
164    This routine simply loads the map into a 2d array by repetitve calls
165    to get_f_raster_row.
166 
167    \todo fn body of Gs_loadmap_as_float()
168 
169    \param wind current window
170    \param map_name raster map name
171    \param[out] buff data buffer
172    \param[out] nullmap null map buffer
173    \param[out] has_null indicates if raster map contains null-data
174 
175    \return 1 on success
176    \return 0 on failure
177  */
Gs_loadmap_as_int(struct Cell_head * wind,const char * map_name,int * buff,struct BM * nullmap,int * has_null)178 int Gs_loadmap_as_int(struct Cell_head *wind, const char *map_name, int *buff,
179 		      struct BM *nullmap, int *has_null)
180 {
181     FILEDESC cellfile;
182     const char *map_set;
183     int offset, row, col;
184 
185     G_debug(3, "Gs_loadmap_as_int");
186 
187     map_set = G_find_raster2(map_name, "");
188     if (!map_set) {
189 	G_warning(_("Raster map <%s> not found"), map_name);
190 	return 0;
191     }
192     *has_null = 0;
193 
194     cellfile = Rast_open_old(map_name, map_set);
195 
196     G_message(_("Loading raster map <%s>..."),
197 	      G_fully_qualified_name(map_name, map_set));
198 
199     for (row = 0; row < wind->rows; row++) {
200 	offset = row * wind->cols;
201 	Rast_get_c_row(cellfile, &(buff[offset]), row);
202 
203 	G_percent(row, wind->rows, 2);
204 
205 	for (col = 0; col < wind->cols; col++) {
206 	    if (Rast_is_f_null_value(buff + offset + col)) {
207 		*has_null = 1;
208 		BM_set(nullmap, col, row, 1);
209 	    }
210 
211 	    /* set nm */
212 	}
213     }
214     G_percent(1, 1, 1);
215 
216     Rast_close(cellfile);
217 
218     return (1);
219 }
220 
221 /*!
222    \brief Get map data type
223 
224    \param filename raster map name
225    \param negflag
226 
227    \return -1 if map is integer and Rast_read_range() fails
228    \return data type (ARRY_*)
229  */
Gs_numtype(const char * filename,int * negflag)230 int Gs_numtype(const char *filename, int *negflag)
231 {
232     CELL max = 0, min = 0;
233     struct Range range;
234     const char *mapset;
235     int shortbits, charbits, bitplace;
236     static int max_short, max_char;
237     static int first = 1;
238 
239     if (first) {
240 	max_short = max_char = 1;
241 	shortbits = 8 * sizeof(short);
242 
243 	for (bitplace = 1; bitplace < shortbits; ++bitplace) {
244 	    /*1 bit for sign */
245 	    max_short *= 2;
246 	}
247 
248 	max_short -= 1;
249 
250 	/* NO bits for sign, using unsigned char */
251 	charbits = 8 * sizeof(unsigned char);
252 
253 	for (bitplace = 0; bitplace < charbits; ++bitplace) {
254 	    max_char *= 2;
255 	}
256 
257 	max_char -= 1;
258 
259 	first = 0;
260     }
261 
262     mapset = G_find_raster2(filename, "");
263     if (!mapset) {
264 	G_warning(_("Raster map <%s> not found"), filename);
265 	return -1;
266     }
267 
268     if (Rast_map_is_fp(filename, mapset)) {
269 	G_debug(3, "Gs_numtype(): fp map detected");
270 
271 	return (ATTY_FLOAT);
272     }
273 
274     if (-1 == Rast_read_range(filename, mapset, &range)) {
275 	return (-1);
276     }
277 
278     Rast_get_range_min_max(&range, &min, &max);
279     *negflag = (min < 0);
280 
281     if (max < max_char && min > 0) {
282 	return (ATTY_CHAR);
283     }
284 
285     if (max < max_short && min > -max_short) {
286 	return (ATTY_SHORT);
287     }
288 
289     return (ATTY_INT);
290 }
291 
292 /*!
293    \brief Load raster map as integer map
294 
295    Calling function must have already allocated space in buff for
296    wind->rows * wind->cols shorts.
297 
298    This routine simply loads the map into a 2d array by repetitve calls
299    to get_map_row.
300 
301    \param wind current window
302    \param map_name raster map name
303    \param[out] buff data buffer
304    \param[out] nullmap null map buffer
305    \param[out] has_null indicates if raster map contains null-data
306 
307    \return 1 on success
308    \return -1 on failure,
309    \return -2 if read ok, but 1 or more values were too large (small)
310    to fit into a short (in which case the max (min) short is used)
311  */
Gs_loadmap_as_short(struct Cell_head * wind,const char * map_name,short * buff,struct BM * nullmap,int * has_null)312 int Gs_loadmap_as_short(struct Cell_head *wind, const char *map_name,
313 			short *buff, struct BM *nullmap, int *has_null)
314 {
315     FILEDESC cellfile;
316     const char *map_set;
317     int *ti, *tmp_buf;
318     int offset, row, col, val, max_short, overflow, shortsize, bitplace;
319     short *ts;
320 
321     G_debug(3, "Gs_loadmap_as_short");
322 
323     overflow = 0;
324     shortsize = 8 * sizeof(short);
325 
326     /* 1 bit for sign */
327     /* same as 2 << (shortsize-1) */
328     for (max_short = bitplace = 1; bitplace < shortsize; ++bitplace) {
329 	max_short *= 2;
330     }
331 
332     max_short -= 1;
333 
334     map_set = G_find_raster2(map_name, "");
335     if (!map_set) {
336 	G_warning(_("Raster map <%s> not found"), map_name);
337 	return -1;
338     }
339     *has_null = 0;
340 
341     cellfile = Rast_open_old(map_name, map_set);
342 
343     tmp_buf = (int *)G_malloc(wind->cols * sizeof(int));	/* G_fatal_error */
344     if (!tmp_buf) {
345 	return -1;
346     }
347 
348     G_message(_("Loading raster map <%s>..."),
349 	      G_fully_qualified_name(map_name, map_set));
350 
351     for (row = 0; row < wind->rows; row++) {
352 	offset = row * wind->cols;
353 	Rast_get_c_row(cellfile, tmp_buf, row);
354 
355 	G_percent(row, wind->rows, 2);
356 
357 	ts = &(buff[offset]);
358 	ti = tmp_buf;
359 
360 	for (col = 0; col < wind->cols; col++) {
361 	    if (Rast_is_c_null_value(&tmp_buf[col])) {
362 		*has_null = 1;
363 		BM_set(nullmap, col, row, 1);
364 	    }
365 	    else {
366 		val = *ti;
367 		if (abs(val) > max_short) {
368 		    overflow = 1;
369 		    /* assign floor/ceiling value?
370 		     */
371 		    *ts = (short)(max_short * val / abs(val));
372 		}
373 		else {
374 		    *ts = (short)val;
375 		}
376 	    }
377 
378 	    ti++;
379 	    ts++;
380 	}
381     }
382     G_percent(1, 1, 1);
383 
384     Rast_close(cellfile);
385 
386     G_free(tmp_buf);
387 
388     return (overflow ? -2 : 1);
389 }
390 
391 /*!
392    \brief Load raster map as integer map
393 
394    Calling function must have already allocated space in buff for
395    wind->rows * wind->cols unsigned chars.
396 
397    This routine simply loads the map into a 2d array by repetitve calls
398    to get_map_row.
399 
400    Since signs of chars can be tricky, we only load positive chars
401    between 0-255.
402 
403    \todo fn body Gs_loadmap_as_float()
404 
405    \param wind current window
406    \param map_name raster map name
407    \param[out] buff data buffer
408    \param[out] nullmap null map buffer
409    \param[out] has_null indicates if raster map contains null-data
410 
411    \return 1 on success
412    \return -1 on failure
413    \return -2 if read ok, but 1 or more values
414    were too large (small) to fit into an unsigned char.
415    (in which case the max (min) char is used)
416  */
Gs_loadmap_as_char(struct Cell_head * wind,const char * map_name,unsigned char * buff,struct BM * nullmap,int * has_null)417 int Gs_loadmap_as_char(struct Cell_head *wind, const char *map_name,
418 		       unsigned char *buff, struct BM *nullmap, int *has_null)
419 {
420     FILEDESC cellfile;
421     const char *map_set;
422     int *ti, *tmp_buf;
423     int offset, row, col, val, max_char, overflow, charsize, bitplace;
424     unsigned char *tc;
425 
426     G_debug(3, "Gs_loadmap_as_char");
427 
428     overflow = 0;
429     charsize = 8 * sizeof(unsigned char);
430 
431     /* 0 bits for sign! */
432     max_char = 1;
433 
434     for (bitplace = 0; bitplace < charsize; ++bitplace) {
435 	max_char *= 2;
436     }
437 
438     max_char -= 1;
439 
440     map_set = G_find_raster2(map_name, "");
441     if (!map_set) {
442 	G_warning(_("Raster map <%s> not found"), map_name);
443 	return -1;
444     }
445     *has_null = 0;
446 
447     cellfile = Rast_open_old(map_name, map_set);
448 
449     tmp_buf = (int *)G_malloc(wind->cols * sizeof(int));	/* G_fatal_error */
450     if (!tmp_buf) {
451 	return -1;
452     }
453 
454     G_message(_("Loading raster map <%s>..."),
455 	      G_fully_qualified_name(map_name, map_set));
456 
457     for (row = 0; row < wind->rows; row++) {
458 	offset = row * wind->cols;
459 	Rast_get_c_row(cellfile, tmp_buf, row);
460 	tc = (unsigned char *)&(buff[offset]);
461 	ti = tmp_buf;
462 
463 	G_percent(row, wind->rows, 2);
464 
465 	for (col = 0; col < wind->cols; col++) {
466 	    if (Rast_is_c_null_value(&tmp_buf[col])) {
467 		*has_null = 1;
468 		BM_set(nullmap, col, row, 1);
469 	    }
470 	    else {
471 		val = *ti;
472 		if (val > max_char) {
473 		    overflow = 1;
474 		    *tc = (unsigned char)max_char;
475 		}
476 		else if (val < 0) {
477 		    overflow = 1;
478 		    *tc = 0;
479 		}
480 		else {
481 		    *tc = (unsigned char)val;
482 		}
483 	    }
484 
485 	    ti++;
486 	    tc++;
487 	}
488     }
489     G_percent(1, 1, 1);
490 
491     Rast_close(cellfile);
492 
493     G_free(tmp_buf);
494 
495     return (overflow ? -2 : 1);
496 }
497 
498 /*!
499    \brief Load raster map as integer map
500 
501    Calling function must have already allocated space in buff for
502    struct BM of wind->rows & wind->cols.
503 
504    This routine simply loads the map into the bitmap by repetitve calls
505    to get_map_row.  Any value other than 0 in the map will set the bitmap.
506    (may want to change later to allow specific value to set)
507 
508    Changed to use null.
509 
510    \param wind current window
511    \param map_name raster map name
512    \param[out] buff data buffer
513 
514    \returns 1 on success
515    \return -1 on failure
516  */
Gs_loadmap_as_bitmap(struct Cell_head * wind,const char * map_name,struct BM * buff)517 int Gs_loadmap_as_bitmap(struct Cell_head *wind, const char *map_name,
518 			 struct BM *buff)
519 {
520     FILEDESC cellfile;
521     const char *map_set;
522     int *tmp_buf;
523     int row, col;
524 
525     G_debug(3, "Gs_loadmap_as_bitmap");
526 
527     map_set = G_find_raster2(map_name, "");
528     if (!map_set) {
529 	G_warning(_("Raster map <%s> not found"), map_name);
530 	return -1;
531     }
532 
533     cellfile = Rast_open_old(map_name, map_set);
534 
535     tmp_buf = (int *)G_malloc(wind->cols * sizeof(int));	/* G_fatal_error */
536     if (!tmp_buf) {
537 	return -1;
538     }
539 
540     G_message(_("Loading raster map <%s>..."),
541 	      G_fully_qualified_name(map_name, map_set));
542 
543     for (row = 0; row < wind->rows; row++) {
544 	Rast_get_c_row(cellfile, tmp_buf, row);
545 
546 	for (col = 0; col < wind->cols; col++) {
547 	    if (Rast_is_c_null_value(&tmp_buf[col])) {
548 		/* no data */
549 		BM_set(buff, col, row, 1);
550 	    }
551 	    else {
552 		BM_set(buff, col, row, 0);
553 	    }
554 	}
555     }
556 
557     Rast_close(cellfile);
558 
559     G_free(tmp_buf);
560 
561     return (1);
562 }
563 
564 /*!
565    \brief Build color table (256)
566 
567    Calling function must have already allocated space in buff for range of
568    data (256 for now) - simply calls get_color for each cat in color range
569 
570    \param filename raster map name
571    \param[out] buff data buffer
572 
573    \return 1 on success
574    \return 0 on failure
575  */
Gs_build_256lookup(const char * filename,int * buff)576 int Gs_build_256lookup(const char *filename, int *buff)
577 {
578     const char *mapset;
579     struct Colors colrules;
580     CELL min, max, cats[256];
581     int i;
582     unsigned char r[256], g[256], b[256], set[256];
583 
584     G_debug(3, "building color table");
585 
586     mapset = G_find_raster2(filename, "");
587     if (!mapset) {
588 	G_warning(_("Raster map <%s> not found"), filename);
589 	return 0;
590     }
591 
592     Rast_read_colors(filename, mapset, &colrules);
593     Rast_get_c_color_range(&min, &max, &colrules);
594 
595     if (min < 0 || max > 255) {
596 	G_warning(_("Color table range doesn't match data (mincol=%d, maxcol=%d"),
597 		  min, max);
598 
599 	min = min < 0 ? 0 : min;
600 	max = max > 255 ? 255 : max;
601     }
602 
603     G_zero(cats, 256 * sizeof(CELL));
604 
605     for (i = min; i <= max; i++) {
606 	cats[i] = i;
607     }
608 
609     Rast_lookup_c_colors(cats, r, g, b, set, 256, &colrules);
610 
611     for (i = 0; i < 256; i++) {
612 
613 	if (set[i]) {
614 	    buff[i] =
615 		(r[i] & 0xff) | ((g[i] & 0xff) << 8) | ((b[i] & 0xff) << 16);
616 	}
617 	else {
618 	    buff[i] = NO_DATA_COL;
619 	}
620     }
621 
622     return (1);
623 }
624 
625 /*!
626    \brief Pack color table
627 
628    Passed an array of 32 bit ints that is converted from cell values
629    to packed colors (0xbbggrr)
630 
631    \param filename raster map name
632    \param buff
633    \param rows number of rows
634    \param cols number of cols
635  */
Gs_pack_colors(const char * filename,int * buff,int rows,int cols)636 void Gs_pack_colors(const char *filename, int *buff, int rows, int cols)
637 {
638     const char *mapset;
639     struct Colors colrules;
640     unsigned char *r, *g, *b, *set;
641     int *cur, i, j;
642 
643     mapset = G_find_raster2(filename, "");
644     if (!mapset) {
645 	G_warning(_("Raster map <%s> not found"), filename);
646 	return;
647     }
648 
649     r = (unsigned char *)G_malloc(cols);
650     g = (unsigned char *)G_malloc(cols);
651     b = (unsigned char *)G_malloc(cols);
652     set = (unsigned char *)G_malloc(cols);
653 
654     Rast_read_colors(filename, mapset, &colrules);
655 
656     cur = buff;
657 
658     G_message(_("Translating colors from raster map <%s>..."),
659 	      G_fully_qualified_name(filename, mapset));
660 
661     for (i = 0; i < rows; i++) {
662 	Rast_lookup_c_colors(cur, r, g, b, set, cols, &colrules);
663 	G_percent(i, rows, 2);
664 
665 	for (j = 0; j < cols; j++) {
666 	    if (set[j]) {
667 		cur[j] =
668 		    (r[j] & 0xff) | ((g[j] & 0xff) << 8) | ((b[j] & 0xff) <<
669 							    16);
670 	    }
671 	    else {
672 		cur[j] = NO_DATA_COL;
673 	    }
674 	}
675 
676 	cur = &(cur[cols]);
677     }
678     G_percent(1, 1, 1);
679 
680     Rast_free_colors(&colrules);
681 
682     G_free(r);
683     G_free(g);
684     G_free(b);
685 
686     G_free(set);
687 
688     return;
689 }
690 
691 /*!
692    \brief Pack color table (floating-point map)
693 
694    Passed a array of floats that will be converted from cell values
695    to packed colors (0xbbggrr) and float to int
696    Floating point data not freed here, use:
697    gsds_free_data_buff(id, ATTY_FLOAT)
698 
699    \param filename raster map name
700    \param fbuf
701    \param ibuf
702    \param rows number of rows
703    \param cols number of cols
704  */
Gs_pack_colors_float(const char * filename,float * fbuf,int * ibuf,int rows,int cols)705 void Gs_pack_colors_float(const char *filename, float *fbuf, int *ibuf,
706 			  int rows, int cols)
707 {
708     const char *mapset;
709     struct Colors colrules;
710     unsigned char *r, *g, *b, *set;
711     int i, j, *icur;
712     FCELL *fcur;
713 
714     mapset = G_find_raster2(filename, "");
715     if (!mapset) {
716 	G_warning(_("Raster map <%s> not found"), filename);
717 	return;
718     }
719 
720     r = (unsigned char *)G_malloc(cols);
721     g = (unsigned char *)G_malloc(cols);
722     b = (unsigned char *)G_malloc(cols);
723     set = (unsigned char *)G_malloc(cols);
724 
725     Rast_read_colors(filename, mapset, &colrules);
726 
727     fcur = fbuf;
728     icur = ibuf;
729 
730     G_message(_("Translating colors from raster map <%s>..."),
731 	      G_fully_qualified_name(filename, mapset));
732 
733     for (i = 0; i < rows; i++) {
734 	Rast_lookup_f_colors(fcur, r, g, b, set, cols, &colrules);
735 	G_percent(i, rows, 2);
736 
737 	for (j = 0; j < cols; j++) {
738 	    if (set[j]) {
739 		icur[j] =
740 		    (r[j] & 0xff) | ((g[j] & 0xff) << 8) | ((b[j] & 0xff) <<
741 							    16);
742 	    }
743 	    else {
744 		icur[j] = NO_DATA_COL;
745 	    }
746 	}
747 
748 	icur = &(icur[cols]);
749 	fcur = &(fcur[cols]);
750     }
751     G_percent(1, 1, 1);
752 
753     Rast_free_colors(&colrules);
754 
755     G_free(r);
756     G_free(g);
757     G_free(b);
758     G_free(set);
759 
760     return;
761 }
762 
763 /*!
764    \brief Get categories/labels
765 
766    Formats label as in d.what.rast -> (catval) catlabel
767 
768    \param filename raster map name
769    \param drow
770    \param dcol
771    \param catstr category string
772 
773    \return 1 on success
774    \return 0 on failure
775  */
Gs_get_cat_label(const char * filename,int drow,int dcol,char * catstr)776 int Gs_get_cat_label(const char *filename, int drow, int dcol, char *catstr)
777 {
778     struct Categories cats;
779     const char *mapset;
780     CELL *buf;
781     DCELL *dbuf;
782     RASTER_MAP_TYPE map_type;
783     int fd = -1;
784 
785     if ((mapset = G_find_raster2(filename, "")) == NULL) {
786 	G_warning(_("Raster map <%s> not found"), filename);
787 	return 0;
788     }
789 
790     if (-1 != Rast_read_cats(filename, mapset, &cats)) {
791 	fd = Rast_open_old(filename, mapset);
792 	map_type = Rast_get_map_type(fd);
793 
794 	if (map_type == CELL_TYPE) {
795 	    buf = Rast_allocate_c_buf();
796 
797 	    Rast_get_c_row(fd, buf, drow);
798 	    if (Rast_is_c_null_value(&buf[dcol])) {
799 		sprintf(catstr, "(NULL) %s",
800 			Rast_get_c_cat(&buf[dcol], &cats));
801 	    }
802 	    else {
803 		sprintf(catstr, "(%d) %s", buf[dcol],
804 			Rast_get_c_cat(&buf[dcol], &cats));
805 	    }
806 
807 	    G_free(buf);
808 	}
809 
810 	else {
811 	    /* fp map */
812 	    dbuf = Rast_allocate_d_buf();
813 
814 	    Rast_get_d_row(fd, dbuf, drow);
815 	    if (Rast_is_d_null_value(&dbuf[dcol])) {
816 		sprintf(catstr, "(NULL) %s",
817 			Rast_get_d_cat(&dbuf[dcol], &cats));
818 	    }
819 	    else {
820 		sprintf(catstr, "(%g) %s", dbuf[dcol],
821 			Rast_get_d_cat(&dbuf[dcol], &cats));
822 	    }
823 
824 	    G_free(dbuf);
825 	}
826     }
827     else {
828 	strcpy(catstr, "no category label");
829 	return 0;
830     }
831 
832     /* TODO: may want to keep these around for multiple queries */
833     Rast_free_cats(&cats);
834 
835     if (fd >= 0)
836 	Rast_close(fd);
837 
838     return (1);
839 }
840 
841 /*!
842    \brief Save 3dview
843 
844    \param vname view name
845    \param gv pointer to geoview struct
846    \param gd pointer to geodisplay struct
847    \param w current window
848    \param defsurf default geosurf struct
849 
850    \return -1 on error
851    \return ?
852  */
Gs_save_3dview(const char * vname,geoview * gv,geodisplay * gd,struct Cell_head * w,geosurf * defsurf)853 int Gs_save_3dview(const char *vname, geoview * gv, geodisplay * gd,
854 		   struct Cell_head *w, geosurf * defsurf)
855 {
856     const char *mapset;
857     struct G_3dview v;
858     float zmax, zmin;
859 
860     GS_get_zrange(&zmin, &zmax, 0);
861 
862     G_get_3dview_defaults(&v, w);
863     mapset = G_mapset();
864 
865     if (mapset != NULL) {
866 	if (defsurf) {
867 	    if (defsurf->draw_mode & DM_WIRE_POLY) {
868 		v.display_type = 3;
869 	    }
870 	    else if (defsurf->draw_mode & DM_WIRE ||
871 		     defsurf->draw_mode & DM_COL_WIRE) {
872 		v.display_type = 1;
873 	    }
874 	    else if (defsurf->draw_mode & DM_POLY) {
875 		v.display_type = 2;
876 	    }
877 
878 	    v.mesh_freq = defsurf->x_modw;	/* mesh resolution */
879 	    v.poly_freq = defsurf->x_mod;	/* poly resolution */
880 	    v.dozero = !(defsurf->nz_topo);
881 	    v.colorgrid = (defsurf->draw_mode & DM_COL_WIRE) ? 1 : 0;
882 	    v.shading = (defsurf->draw_mode & DM_GOURAUD) ? 1 : 0;
883 	}
884 
885 	if (gv->infocus) {
886 	    GS_v3eq(v.from_to[TO], gv->real_to);
887 	    v.from_to[TO][Z] -= zmin;
888 	    GS_v3mult(v.from_to[TO], gv->scale);
889 	    v.from_to[TO][Z] *= gv->vert_exag;
890 	}
891 	else {
892 	    GS_v3eq(v.from_to[TO], gv->from_to[TO]);
893 	}
894 
895 	gsd_model2real(v.from_to[TO]);
896 
897 	GS_v3eq(v.from_to[FROM], gv->from_to[FROM]);
898 	gsd_model2real(v.from_to[FROM]);
899 
900 	v.exag = gv->vert_exag;
901 	v.fov = gv->fov / 10.;
902 	v.twist = gv->twist;
903 	v.fringe = 0;		/* not implemented here */
904 
905 	v.lightson = 1;		/* always true, curently */
906 
907 	if (gv->lights[0].position[W] == 1) {
908 	    /* local */
909 	    v.lightpos[X] = gv->lights[0].position[X];
910 	    v.lightpos[Y] = gv->lights[0].position[Y];
911 	    v.lightpos[Z] = gv->lights[0].position[Z];
912 	    gsd_model2real(v.lightpos);
913 	    v.lightpos[W] = 1.0;	/* local */
914 	}
915 	else {
916 	    v.lightpos[X] = gv->lights[0].position[X];
917 	    v.lightpos[Y] = gv->lights[0].position[Y];
918 	    v.lightpos[Z] = gv->lights[0].position[Z];
919 	    v.lightpos[W] = 0.0;	/* inf */
920 	}
921 
922 	v.lightcol[0] = gv->lights[0].color[0];
923 	v.lightcol[1] = gv->lights[0].color[1];
924 	v.lightcol[2] = gv->lights[0].color[2];
925 
926 	v.ambient = (gv->lights[0].ambient[0] + gv->lights[0].ambient[1] +
927 		     gv->lights[0].ambient[2]) / 3.;
928 	v.shine = gv->lights[0].shine;
929 
930 	v.surfonly = 0;		/* N/A - now uses constant color */
931 	strcpy((v.pgm_id), "Nvision-ALPHA!");
932 
933 	return (G_put_3dview(vname, mapset, &v, w));
934     }
935     else {
936 	return (-1);
937     }
938 }
939 
940 /*!
941    \brief Load 3dview
942 
943    \param vname view name
944    \param gv pointer to geoview struct
945    \param gd pointer to geodisplay struct
946    \param w current window
947    \param defsurf default geosurf struct
948 
949    \return 1
950  */
Gs_load_3dview(const char * vname,geoview * gv,geodisplay * gd,struct Cell_head * w,geosurf * defsurf)951 int Gs_load_3dview(const char *vname, geoview * gv, geodisplay * gd,
952 		   struct Cell_head *w, geosurf * defsurf)
953 {
954     const char *mapset;
955     struct G_3dview v;
956     int ret = -1;
957     float pt[3];
958 
959     mapset = G_find_file2("3d.view", vname, "");
960 
961     if (mapset != NULL) {
962 	ret = G_get_3dview(vname, mapset, &v);
963     }
964 
965     if (ret >= 0) {
966 	if (strcmp((v.pgm_id), "Nvision-ALPHA!")) {
967 	    G_warning(_("View not saved by this program,"
968 			"there may be some inconsistancies"));
969 	}
970 
971 	/* set poly and mesh resolutions */
972 	v.mesh_freq = (int)(v.mesh_freq * v.vwin.ns_res / w->ns_res);
973 	v.poly_freq = (int)(v.poly_freq * v.vwin.ns_res / w->ns_res);
974 
975 	/* Set To and FROM positions */
976 	/* TO */
977 	pt[0] = (v.from_to[TO][X] - w->west) - w->ew_res / 2.;
978 	pt[1] = (v.from_to[TO][Y] - w->south) - w->ns_res / 2.;
979 	pt[2] = v.from_to[TO][Z];
980 	GS_set_focus(pt);
981 
982 	/* FROM */
983 	pt[0] = (float)v.from_to[FROM][X];
984 	pt[1] = (float)v.from_to[FROM][Y];
985 	pt[2] = (float)v.from_to[FROM][Z];
986 	GS_moveto_real(pt);
987 
988 	if (defsurf) {
989 	    int dmode = 0;
990 
991 	    GS_setall_drawres(v.poly_freq, v.poly_freq,
992 			      v.mesh_freq, v.mesh_freq);
993 
994 	    while (v.display_type >= 10) {
995 		/* globe stuff not used */
996 		v.display_type -= 10;
997 	    }
998 
999 	    /* set drawing modes */
1000 	    if (v.colorgrid) {
1001 		dmode |= DM_COL_WIRE;
1002 	    }
1003 
1004 	    if (v.shading) {
1005 		dmode |= DM_GOURAUD;
1006 	    }
1007 
1008 	    switch (v.display_type) {
1009 	    case 1:
1010 		dmode |= DM_WIRE;
1011 
1012 		break;
1013 	    case 2:
1014 		dmode |= DM_POLY;
1015 
1016 		break;
1017 	    case 3:
1018 		dmode |= DM_WIRE_POLY;
1019 
1020 		break;
1021 	    }
1022 	    GS_setall_drawmode(dmode);
1023 
1024 	    /* should also set nozeros here */
1025 	}
1026 
1027 	/* set exaggeration */
1028 	if (v.exag)
1029 	    GS_set_global_exag(v.exag);
1030 
1031 	/* Set FOV */
1032 	if (v.fov) {
1033 	    GS_set_fov((int)
1034 		       (v.fov > 0 ? v.fov * 10. + 0.5 : v.fov * 10. - 0.5));
1035 	}
1036 	else {
1037 	    /* TODO: do ortho */
1038 	}
1039 
1040 	/* Set twist */
1041 	if (v.twist)
1042 	    GS_set_twist((int)(v.twist > 0 ? v.twist + 0.5 : v.twist - 0.5));
1043 
1044 
1045 	/* TODO:  OK to here - need to unravel/reverse lights stuff*** */
1046 
1047 	if (v.lightson) {
1048 	    /* Lights are on */
1049 
1050 	    /* Light Position */
1051 	    gv->lights[0].position[X] = v.lightpos[X];
1052 	    gv->lights[0].position[Y] = v.lightpos[Y];
1053 	    gv->lights[0].position[Z] = v.lightpos[Z];
1054 
1055 	    /* Light Color */
1056 	    gv->lights[0].color[0] = v.lightcol[0];
1057 	    gv->lights[0].color[1] = v.lightcol[1];
1058 	    gv->lights[0].color[2] = v.lightcol[2];
1059 
1060 	    /* Light Shininess */
1061 	    gv->lights[0].shine = v.shine;
1062 
1063 	    /* Light Ambient */
1064 	    gv->lights[0].ambient[0] = gv->lights[0].ambient[1] =
1065 		gv->lights[0].ambient[2] = v.ambient * 3.;
1066 
1067 
1068 	}			/* Done with lights */
1069 
1070 
1071 	GS_alldraw_wire();
1072 
1073     }				/* Done with file */
1074     return (1);
1075 
1076 }
1077 
1078 /*!
1079    \brief Update no_zero ranges for attribute (actually no_null now)
1080 
1081    \param gs pointer to geosurf struct
1082    \param desc attribute id (descriptor)
1083 
1084    \return -1 on error
1085    \return 1 on success
1086  */
Gs_update_attrange(geosurf * gs,int desc)1087 int Gs_update_attrange(geosurf * gs, int desc)
1088 {
1089     long size;
1090     float min, max;
1091     typbuff *tb;
1092     struct BM *nm;
1093     int found;
1094 
1095     gs->att[desc].max_nz = gs->att[desc].min_nz = gs->att[desc].range_nz =
1096 	0.0;
1097 
1098     if (CONST_ATT == gs_get_att_src(gs, desc)) {
1099 	gs->att[desc].max_nz = gs->att[desc].min_nz = gs->att[desc].constant;
1100 	min = max = gs->att[desc].constant;
1101 	gs->att[desc].range_nz = 0.0;
1102     }
1103     else if (CF_COLOR_PACKED & gsds_get_changed(gs->att[desc].hdata)) {
1104 	gs->att[desc].max_nz = 0xFFFFFF;
1105 	gs->att[desc].min_nz = 0x010101;
1106 	gs->att[desc].range_nz = 0xFFFFFF;
1107     }
1108     else {
1109 	if (NULL == (tb = gsds_get_typbuff(gs->att[desc].hdata, 0))) {
1110 	    return (-1);
1111 	}
1112 
1113 	nm = tb->nm;
1114 
1115 	if (tb->ib) {
1116 	    int *p;
1117 
1118 	    size = gs->rows * gs->cols;
1119 	    p = tb->ib;
1120 	    INIT_MINMAX(p, nm, size, min, max, found);
1121 
1122 	    if (!found) {
1123 		/* all nulls! */
1124 		return (-1);
1125 	    }
1126 
1127 	    size = gs->rows * gs->cols;
1128 	    p = tb->ib;
1129 	    SET_MINMAX(p, nm, size, min, max);
1130 	}
1131 	else if (tb->sb) {
1132 	    short *p;
1133 
1134 	    size = gs->rows * gs->cols;
1135 	    p = tb->sb;
1136 	    INIT_MINMAX(p, nm, size, min, max, found);
1137 
1138 	    if (!found) {
1139 		/* all nulls! */
1140 		return (-1);
1141 	    }
1142 
1143 	    size = gs->rows * gs->cols;
1144 	    p = tb->sb;
1145 	    SET_MINMAX(p, nm, size, min, max);
1146 	}
1147 	else if (tb->cb) {
1148 	    char *p;
1149 
1150 	    size = gs->rows * gs->cols;
1151 	    p = (char *)tb->cb;
1152 	    INIT_MINMAX(p, nm, size, min, max, found);
1153 
1154 	    if (!found) {
1155 		/* all nulls! */
1156 		return (-1);
1157 	    }
1158 
1159 	    size = gs->rows * gs->cols;
1160 	    p = (char *)tb->cb;
1161 	    SET_MINMAX(p, nm, size, min, max);
1162 	}
1163 	else if (tb->fb) {
1164 	    float *p;
1165 
1166 	    size = gs->rows * gs->cols;
1167 	    p = tb->fb;
1168 	    INIT_MINMAX(p, nm, size, min, max, found);
1169 
1170 	    if (!found) {
1171 		/* all nulls! */
1172 		return (-1);
1173 	    }
1174 
1175 	    size = gs->rows * gs->cols;
1176 	    p = tb->fb;
1177 	    SET_MINMAX(p, nm, size, min, max);
1178 	}
1179 
1180 	gs->att[desc].max_nz = max;
1181 	gs->att[desc].min_nz = min;
1182 	gs->att[desc].range_nz = gs->att[desc].max_nz - gs->att[desc].min_nz;
1183     }
1184 
1185     if (ATT_TOPO == desc) {
1186 	gs->zmin = min;
1187 	gs->zmax = max;
1188 	gs->zrange = gs->zmax - gs->zmin;
1189 	gs->zminmasked = gs->zmin;
1190 	gs->zmax_nz = gs->zmax;
1191 	gs->zmin_nz = gs->zmin;
1192 	gs->zrange_nz = gs->zmax_nz - gs->zmin_nz;
1193     }
1194 
1195     G_debug(3, "Gs_update_attrange(): min=%f max=%f", gs->zmin, gs->zmax);
1196 
1197     return (1);
1198 }
1199