GRASS GIS 7 Programmer's Manual  7.5.svn(2018)-r72090
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gs3.c
Go to the documentation of this file.
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  */
84 double Gs_distance(double *from, double *to)
85 {
86  static int first = 1;
87 
88  if (first) {
89  first = 0;
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
896 
897  GS_v3eq(v.from_to[FROM], gv->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];
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  */
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 
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)
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  */
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 }
float scale
Definition: ogsf.h:487
#define CELL_TYPE
Definition: raster.h:11
int colorgrid
Definition: gis.h:464
float min_nz
Definition: ogsf.h:253
float zmin
Definition: ogsf.h:268
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
#define ATTY_CHAR
Definition: ogsf.h:168
float from_to[2][3]
Definition: gis.h:455
void Rast_get_f_row(int fd, FCELL *buf, int row)
Get raster row (FCELL type)
float ambient[3]
Definition: ogsf.h:465
int FILEDESC
Definition: gs3.c:70
#define DM_WIRE_POLY
Definition: ogsf.h:62
int Rast_is_f_null_value(const FCELL *fcellVal)
To check if a FCELL raster value is set to NULL.
Definition: null_val.c:242
int Rast_read_cats(const char *name, const char *mapset, struct Categories *pcats)
Read raster category file.
Definition: raster/cats.c:104
float twist
Definition: gis.h:457
void Rast_lookup_f_colors(const FCELL *fcell, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors)
Lookup an array of colors (FCELL)
Definition: color_look.c:113
float max_nz
Definition: ogsf.h:253
short * sb
Definition: ogsf.h:208
float zrange_nz
Definition: ogsf.h:270
int Gs_loadmap_as_char(struct Cell_head *wind, const char *map_name, unsigned char *buff, struct BM *nullmap, int *has_null)
Load raster map as integer map.
Definition: gs3.c:417
2D/3D raster map header (used also for region)
Definition: gis.h:390
void GS_moveto_real(float *pt)
Move position to (real)
Definition: gs2.c:2648
void Rast_close(int fd)
Close a raster map.
Definition: raster/close.c:72
int G_begin_distance_calculations(void)
Begin distance calculations.
Definition: gis/distance.c:42
CELL * Rast_allocate_c_buf(void)
Allocate memory for a CELL type raster map.
Definition: alloc_cell.c:82
float lightcol[3]
Definition: gis.h:473
#define min(x, y)
Definition: draw2.c:31
int GS_get_zrange(float *min, float *max, int doexag)
Get z-extent for all loaded surfaces.
Definition: gs2.c:2690
int Gs_update_attrange(geosurf *gs, int desc)
Update no_zero ranges for attribute (actually no_null now)
Definition: gs3.c:1087
double west
Extent coordinates (west)
Definition: gis.h:442
int rows
Definition: ogsf.h:260
double DCELL
Definition: gis.h:581
int poly_freq
Definition: gis.h:460
float zmax_nz
Definition: ogsf.h:270
#define ATT_TOPO
Definition: ogsf.h:73
#define NO_DATA_COL
Definition: gs3.c:72
int Gs_build_256lookup(const char *filename, int *buff)
Build color table (256)
Definition: gs3.c:576
int fringe
Definition: gis.h:466
float range_nz
Definition: ogsf.h:253
int * ib
Definition: ogsf.h:207
void Rast_get_c_row(int fd, CELL *buf, int row)
Get raster row (CELL type)
int Rast_read_colors(const char *name, const char *mapset, struct Colors *colors)
Read color table of raster map.
Definition: bitmap.h:17
#define INIT_MINMAX(p, nm, size, min, max, found)
Used in the function Gs_update_attrange()
Definition: gs3.c:35
char * Rast_get_c_cat(CELL *rast, struct Categories *pcats)
Get a raster category label (CELL)
Definition: raster/cats.c:323
int G_get_3dview_defaults(struct G_3dview *v, struct Cell_head *w)
Sets default for v based on w.
Definition: view.c:62
char * Rast_get_d_cat(DCELL *rast, struct Categories *pcats)
Get a raster category label (DCELL)
Definition: raster/cats.c:371
#define DM_COL_WIRE
Definition: ogsf.h:60
int Rast_is_c_null_value(const CELL *cellVal)
To check if a CELL raster value is set to NULL.
Definition: null_val.c:209
void GS_set_global_exag(float exag)
Set global z-exag value.
Definition: gs2.c:1978
typbuff * gsds_get_typbuff(int id, IFLAG change_flag)
Get data buffer.
Definition: gsds.c:281
#define NULL
Definition: ccmath.h:32
char pgm_id[40]
Definition: gis.h:454
int display_type
Definition: gis.h:461
float ambient
Definition: gis.h:474
float shine
Definition: gis.h:475
#define max(x, y)
Definition: draw2.c:32
int G_put_3dview(const char *fname, const char *mapset, const struct G_3dview *View, const struct Cell_head *Win)
Saves info to a 3d.view file.
Definition: view.c:170
void Gs_pack_colors(const char *filename, int *buff, int rows, int cols)
Pack color table.
Definition: gs3.c:636
void GS_set_focus(float *realto)
Set focus.
Definition: gs2.c:2521
int Rast_read_range(const char *name, const char *mapset, struct Range *range)
Read raster range (CELL)
Definition: range.c:154
float lightpos[4]
Definition: gis.h:472
int GS_setall_drawmode(int mode)
Set all draw-modes.
Definition: gs2.c:2062
fd
Definition: d/range.c:69
#define W
Definition: ogsf.h:140
int shading
Definition: gis.h:465
float zrange
Definition: ogsf.h:269
#define ATTY_SHORT
Definition: ogsf.h:167
int dozero
Definition: gis.h:463
int cols
Definition: ogsf.h:260
double Gs_distance(double *from, double *to)
Calculates distance in METERS between two points in current projection (2D)
Definition: gs3.c:84
IFLAG draw_mode
Definition: ogsf.h:262
#define ATTY_FLOAT
Definition: ogsf.h:165
int x_mod
Definition: ogsf.h:271
int Gs_loadmap_as_bitmap(struct Cell_head *wind, const char *map_name, struct BM *buff)
Load raster map as integer map.
Definition: gs3.c:517
void GS_set_twist(int t)
Set viewpoint twist value.
Definition: gs2.c:2878
double b
Definition: r_raster.c:39
#define ATTY_INT
Definition: ogsf.h:166
void GS_v3mult(float *v1, float k)
Multiple vectors.
Definition: gs_util.c:229
float zminmasked
Definition: ogsf.h:268
int GS_setall_drawres(int xres, int yres, int xwire, int ywire)
Set all draw resolutions.
Definition: gs2.c:2199
double south
Extent coordinates (south)
Definition: gis.h:438
int fov
Definition: ogsf.h:485
void Rast_get_d_row(int fd, DCELL *buf, int row)
Get raster row (DCELL type)
#define DM_POLY
Definition: ogsf.h:61
int mesh_freq
Definition: gis.h:459
int gsds_get_changed(int id)
ADD.
Definition: gsds.c:615
Definition: ogsf.h:478
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
float zmin_nz
Definition: ogsf.h:270
int nz_topo
Definition: ogsf.h:272
void Rast_get_c_color_range(CELL *min, CELL *max, const struct Colors *colors)
Get color range values (CELL)
Definition: color_range.c:64
struct Cell_head vwin
Definition: gis.h:476
#define DM_GOURAUD
Definition: ogsf.h:54
int hdata
Definition: ogsf.h:249
void Rast_free_colors(struct Colors *colors)
Free color structure memory.
Definition: color_free.c:30
float fov
Definition: gis.h:456
float g
Definition: named_colr.c:8
int lightson
Definition: gis.h:462
void Gs_pack_colors_float(const char *filename, float *fbuf, int *ibuf, int rows, int cols)
Pack color table (floating-point map)
Definition: gs3.c:705
float vert_exag
Definition: ogsf.h:486
#define FROM
Definition: ogsf.h:141
int Gs_loadmap_as_int(struct Cell_head *wind, const char *map_name, int *buff, struct BM *nullmap, int *has_null)
Load raster map as integer map.
Definition: gs3.c:178
#define Z
Definition: ogsf.h:139
int G_get_3dview(const char *fname, const char *mapset, struct G_3dview *View)
Gets a 3D View.
Definition: view.c:251
void gsd_model2real(Point3 point)
Convert model to real coordinates.
Definition: gsd_views.c:393
void G_percent(long n, long d, int s)
Print percent complete messages.
Definition: percent.c:62
gsurf_att att[MAX_ATTS]
Definition: ogsf.h:261
Definition: raster.h:225
float shine
Definition: ogsf.h:467
float FCELL
Definition: gis.h:582
int Gs_get_cat_label(const char *filename, int drow, int dcol, char *catstr)
Get categories/labels.
Definition: gs3.c:776
#define DM_WIRE
Definition: ogsf.h:59
Definition: gis.h:626
int Gs_loadmap_as_float(struct Cell_head *wind, const char *map_name, float *buff, struct BM *nullmap, int *has_null)
Load raster map as floating point map.
Definition: gs3.c:114
#define Y
Definition: ogsf.h:138
Definition: gis.h:452
DCELL * Rast_allocate_d_buf(void)
Allocates memory for a raster map of type DCELL.
Definition: alloc_cell.c:108
RASTER_MAP_TYPE Rast_get_map_type(int fd)
Determine raster type from descriptor.
Definition: raster/open.c:907
#define CF_COLOR_PACKED
Definition: ogsf.h:180
int cols
Number of columns for 2D data.
Definition: gis.h:409
int Gs_loadmap_as_short(struct Cell_head *wind, const char *map_name, short *buff, struct BM *nullmap, int *has_null)
Load raster map as integer map.
Definition: gs3.c:312
int infocus
Definition: ogsf.h:482
double ns_res
Resolution - north to south cell size for 2D data.
Definition: gis.h:430
Definition: ogsf.h:204
void GS_v3eq(float *v1, float *v2)
Copy vector values.
Definition: gs_util.c:178
int CELL
Definition: gis.h:580
int gs_get_att_src(geosurf *gs, int desc)
Get attribute source.
Definition: gs.c:656
float real_to[4]
Definition: ogsf.h:486
void GS_alldraw_wire(void)
Draw all wires.
Definition: gs2.c:1920
int Gs_load_3dview(const char *vname, geoview *gv, geodisplay *gd, struct Cell_head *w, geosurf *defsurf)
Load 3dview.
Definition: gs3.c:951
void GS_set_fov(int fov)
Set field of view.
Definition: gs2.c:2844
float color[3]
Definition: ogsf.h:464
double G_distance(double e1, double n1, double e2, double n2)
Returns distance in meters.
Definition: gis/distance.c:75
#define TO
Definition: ogsf.h:142
float position[4]
Definition: ogsf.h:463
#define _(str)
Definition: glocale.h:13
void G_message(const char *msg,...)
Print a message to stderr.
Definition: gis/error.c:89
int RASTER_MAP_TYPE
Definition: raster.h:25
void Rast_lookup_c_colors(const CELL *cell, unsigned char *red, unsigned char *grn, unsigned char *blu, unsigned char *set, int n, struct Colors *colors)
Lookup an array of colors.
Definition: color_look.c:45
int BM_set(struct BM *map, int x, int y, int val)
Sets bitmap value to &#39;val&#39; at location &#39;x&#39; &#39;y&#39;.
Definition: bitmap.c:187
char * G_fully_qualified_name(const char *name, const char *mapset)
Get fully qualified element name.
Definition: nme_in_mps.c:101
const char * G_find_raster2(const char *name, const char *mapset)
Find a raster map (look but don&#39;t touch)
Definition: find_rast.c:76
#define X
Definition: ogsf.h:137
int Rast_map_is_fp(const char *name, const char *mapset)
Check if raster map is floating-point.
Definition: raster/open.c:836
float zmax
Definition: ogsf.h:268
int Gs_numtype(const char *filename, int *negflag)
Get map data type.
Definition: gs3.c:230
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
float exag
Definition: gis.h:458
char buff[1024]
Definition: raster3d/cats.c:81
int
Reads the categories file for map name in mapset and stores the categories in the pcats structure...
#define SET_MINMAX(p, nm, size, min, max)
Used in the function Gs_update_attrange()
Definition: gs3.c:52
void G_zero(void *buf, int i)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
int Rast_open_old(const char *name, const char *mapset)
Open an existing integer raster map (cell)
Definition: raster/open.c:112
int Gs_save_3dview(const char *vname, geoview *gv, geodisplay *gd, struct Cell_head *w, geosurf *defsurf)
Save 3dview.
Definition: gs3.c:853
double ew_res
Resolution - east to west cell size for 2D data.
Definition: gis.h:426
int x_modw
Definition: ogsf.h:271
struct BM * nm
Definition: ogsf.h:211
#define CONST_ATT
Definition: ogsf.h:84
int surfonly
Definition: gis.h:467
int rows
Number of rows for 2D data.
Definition: gis.h:405
float * fb
Definition: ogsf.h:206
int twist
Definition: ogsf.h:485
Definition: ogsf.h:257
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:203
const char * G_find_file2(const char *element, const char *name, const char *mapset)
Searches for a file from the mapset search list or in a specified mapset. (look but don&#39;t touch) ...
Definition: find_file.c:247
float constant
Definition: ogsf.h:251
double r
Definition: r_raster.c:39
unsigned char * cb
Definition: ogsf.h:209
float from_to[2][4]
Definition: ogsf.h:483
void Rast_get_range_min_max(const struct Range *range, CELL *min, CELL *max)
Get range min and max.
Definition: range.c:699
int Rast_is_d_null_value(const DCELL *dcellVal)
To check if a DCELL raster value is set to NULL.
Definition: null_val.c:261
struct lightdefs lights[MAX_LIGHTS]
Definition: ogsf.h:488
void Rast_free_cats(struct Categories *pcats)
Free category structure memory.
Definition: raster/cats.c:1213