1 /*!
2    \file lib/ogsf/gvl.c
3 
4    \brief OGSF library - loading and manipulating volumes (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, UI-GMSL (May 1997)
16    \author Tomas Paudits (February 2004)
17    \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
18  */
19 
20 #include <stdlib.h>
21 
22 #include <grass/gis.h>
23 #include <grass/ogsf.h>
24 
25 #include "gsget.h"
26 
27 #define FIRST_VOL_ID 81721
28 
29 static geovol *Vol_top = NULL;
30 
31 /*!
32    \brief Get volume set structure
33 
34    \param id volume set id
35 
36    \return pointer to geovol struct
37    \return NULL on failure
38  */
gvl_get_vol(int id)39 geovol *gvl_get_vol(int id)
40 {
41     geovol *gvl;
42 
43     G_debug(5, "gvl_get_vol():");
44 
45     for (gvl = Vol_top; gvl; gvl = gvl->next) {
46 	if (gvl->gvol_id == id) {
47 	    G_debug(5, "    id=%d", id);
48 	    return (gvl);
49 	}
50     }
51 
52     return (NULL);
53 }
54 
55 /*!
56    \brief Get previous volume
57 
58    \param id current volume set id
59 
60    \return pointer to geovol struct
61    \return NULL on failure
62  */
gvl_get_prev_vol(int id)63 geovol *gvl_get_prev_vol(int id)
64 {
65     geovol *pv;
66 
67     G_debug(5, "gvl_get_prev_vol");
68 
69     for (pv = Vol_top; pv; pv = pv->next) {
70 	if (pv->gvol_id == id - 1) {
71 	    return (pv);
72 	}
73     }
74 
75     return (NULL);
76 }
77 
78 /*!
79    \brief Get all volumes
80 
81    \param[out] list of geovol structs
82 
83    \return number of available volume sets
84  */
gvl_getall_vols(geovol ** gvols)85 int gvl_getall_vols(geovol ** gvols)
86 {
87     geovol *gvl;
88     int i;
89 
90     G_debug(5, "gvl_getall_vols");
91 
92     for (i = 0, gvl = Vol_top; gvl; gvl = gvl->next, i++) {
93 	gvols[i] = gvl;
94     }
95 
96     return (i);
97 }
98 
99 /*!
100    \brief Get number of loaded volume sets
101 
102    \return number of volumes
103  */
gvl_num_vols(void)104 int gvl_num_vols(void)
105 {
106     geovol *gvl;
107     int i;
108 
109     for (i = 0, gvl = Vol_top; gvl; gvl = gvl->next, i++) ;
110 
111     G_debug(5, "gvl_num_vols(): num=%d", i);
112 
113     return (i);
114 }
115 
116 /*!
117    \brief Get last volume set from the list
118 
119    \return pointer to geovol struct
120    \return NULL on failure
121  */
gvl_get_last_vol(void)122 geovol *gvl_get_last_vol(void)
123 {
124     geovol *lvl;
125 
126     G_debug(5, "gvl_get_last_vol");
127 
128     if (!Vol_top) {
129 	return (NULL);
130     }
131 
132     for (lvl = Vol_top; lvl->next; lvl = lvl->next) ;
133 
134     G_debug(5, "  last vol id: %d", lvl->gvol_id);
135 
136     return (lvl);
137 }
138 
139 /*!
140    \brief Allocate new volume set and add it to the list
141 
142    \return pointer to geovol struct
143    \return NULL on failure
144  */
gvl_get_new_vol(void)145 geovol *gvl_get_new_vol(void)
146 {
147     geovol *nvl, *lvl;
148 
149     G_debug(5, "gvl_get_new_vol()");
150 
151     nvl = (geovol *) G_malloc(sizeof(geovol));	/* G_fatal_error */
152     if (!nvl) {
153 	return (NULL);
154     }
155 
156     if ((lvl = gvl_get_last_vol())) {
157 	lvl->next = nvl;
158 	nvl->gvol_id = lvl->gvol_id + 1;
159     }
160     else {
161 	Vol_top = nvl;
162 	nvl->gvol_id = FIRST_VOL_ID;
163     }
164 
165     nvl->next = NULL;
166 
167     G_debug(5, "    id=%d", nvl->gvol_id);
168 
169     return (nvl);
170 }
171 
172 /*!
173    \brief Initialize geovol structure
174 
175    \param gvl pointer to geovol struct
176    \param ox,oy,oz
177    \param rows number of rows
178    \param cols number of cols
179    \param xres,yres,zres x/y/z resolution value
180 
181    \return -1 on failure
182    \return 1 on success
183  */
gvl_init_vol(geovol * gvl,double ox,double oy,double oz,int rows,int cols,int depths,double xres,double yres,double zres)184 int gvl_init_vol(geovol * gvl, double ox, double oy, double oz,
185 		 int rows, int cols, int depths, double xres, double yres,
186 		 double zres)
187 {
188     G_debug(5, "gvl_init_vol() id=%d", gvl->gvol_id);
189 
190     if (!gvl) {
191 	return (-1);
192     }
193 
194     gvl->ox = ox;
195     gvl->oy = oy;
196     gvl->oz = oz;
197     gvl->rows = rows;
198     gvl->cols = cols;
199     gvl->depths = depths;
200     gvl->xres = xres;
201     gvl->yres = yres;
202     gvl->zres = zres;
203 
204     gvl->xmin = ox;
205     gvl->xmax = ox + (cols - 1) * xres;
206     gvl->xrange = gvl->xmax - gvl->xmin;
207     gvl->ymin = oy;
208     gvl->ymax = oy + (rows - 1) * yres;
209     gvl->yrange = gvl->ymax - gvl->ymin;
210     gvl->zmin = oz;
211     gvl->zmax = oz + (depths - 1) * zres;
212     gvl->zrange = gvl->zmax - gvl->zmin;
213 
214     gvl->x_trans = gvl->y_trans = gvl->z_trans = 0.0;
215     gvl->draw_wire = 0;
216 
217     gvl->n_isosurfs = 0;
218     G_zero(gvl->isosurf, sizeof(geovol_isosurf *) * MAX_ISOSURFS);
219     gvl->isosurf_x_mod = 1;
220     gvl->isosurf_y_mod = 1;
221     gvl->isosurf_z_mod = 1;
222     gvl->isosurf_draw_mode = DM_GOURAUD;
223 
224     gvl->n_slices = 0;
225     G_zero(gvl->slice, sizeof(geovol_slice *) * MAX_SLICES);
226     gvl->slice_x_mod = 1;
227     gvl->slice_y_mod = 1;
228     gvl->slice_z_mod = 1;
229     gvl->slice_draw_mode = DM_GOURAUD;
230 
231     gvl->hfile = -1;
232     gvl->clientdata = NULL;
233 
234     return (1);
235 }
236 
237 /*!
238    \brief Remove volume set from list
239 
240    \param id volume set id
241  */
gvl_delete_vol(int id)242 void gvl_delete_vol(int id)
243 {
244     geovol *fvl;
245 
246     G_debug(5, "gvl_delete_vol");
247 
248     fvl = gvl_get_vol(id);
249 
250     if (fvl) {
251 	gvl_free_vol(fvl);
252     }
253 
254     return;
255 }
256 
257 /*!
258    \brief Free geovol struct
259 
260    \param fvl pointer to geovol struct
261 
262    \return -1 on failure
263    \return 1 on success
264  */
gvl_free_vol(geovol * fvl)265 int gvl_free_vol(geovol * fvl)
266 {
267     geovol *gvl;
268     int found = 0;
269 
270     G_debug(5, "gvl_free_vol");
271 
272     if (Vol_top) {
273 	if (fvl == Vol_top) {
274 	    if (Vol_top->next) {
275 		/* can't free top if last */
276 		found = 1;
277 		Vol_top = fvl->next;
278 	    }
279 	    else {
280 		gvl_free_volmem(fvl);
281 		G_free(fvl);
282 		Vol_top = NULL;
283 	    }
284 	}
285 	else {
286 	    for (gvl = Vol_top; gvl && !found; gvl = gvl->next) {
287 		/* can't free top */
288 		if (gvl->next) {
289 		    if (gvl->next == fvl) {
290 			found = 1;
291 			gvl->next = fvl->next;
292 		    }
293 		}
294 	    }
295 	}
296 
297 	if (found) {
298 	    gvl_free_volmem(fvl);
299 	    G_free(fvl);
300 	    fvl = NULL;
301 	}
302 
303 	return (1);
304     }
305 
306     return (-1);
307 }
308 
309 /*!
310    \brief Free geovol struct memory
311 
312    \param fvl pointer to geovol struct
313  */
gvl_free_volmem(geovol * fvl)314 void gvl_free_volmem(geovol * fvl)
315 {
316     if (0 < fvl->hfile)
317 	gvl_file_free_datah(fvl->hfile);
318 
319     return;
320 }
321 
322 /*!
323    \brief Debug volume fields
324 
325    \param gvl pointer to geovol struct
326  */
print_vol_fields(geovol * gvl)327 void print_vol_fields(geovol * gvl)
328 {
329     G_debug(5, "ID: %d", gvl->gvol_id);
330     G_debug(5, "cols: %d rows: %d depths: %d", gvl->cols, gvl->rows,
331 	    gvl->depths);
332     G_debug(5, "ox: %lf oy: %lf oz: %lf", gvl->ox, gvl->oy, gvl->oz);
333     G_debug(5, "xres: %lf yres: %lf zres: %lf", gvl->xres, gvl->yres,
334 	    gvl->zres);
335     G_debug(5, "xmin: %f ymin: %f zmin: %f", gvl->xmin, gvl->ymin, gvl->zmin);
336     G_debug(5, "xmax: %f ymax: %f zmax: %f", gvl->xmax, gvl->ymax, gvl->zmax);
337     G_debug(5, "x_trans: %f y_trans: %f z_trans: %f", gvl->x_trans,
338 	    gvl->y_trans, gvl->z_trans);
339 
340     return;
341 }
342 
343 /*!
344    \brief Get volume x-extent value
345 
346    \param gvl pointer to geovol struct
347    \param[out] min x-min value
348    \param[out] max y-max value
349 
350    \return 1
351  */
gvl_get_xextents(geovol * gvl,float * min,float * max)352 int gvl_get_xextents(geovol * gvl, float *min, float *max)
353 {
354     *min = gvl->xmin + gvl->x_trans;
355     *max = gvl->xmax + gvl->x_trans;
356 
357     return (1);
358 }
359 
360 /*!
361    \brief Get volume y-extent value
362 
363    \param gvl pointer to geovol struct
364    \param[out] min y-min value
365    \param[out] max y-max value
366 
367    \return 1
368  */
gvl_get_yextents(geovol * gvl,float * min,float * max)369 int gvl_get_yextents(geovol * gvl, float *min, float *max)
370 {
371     *min = gvl->ymin + gvl->y_trans;
372     *max = gvl->ymax + gvl->y_trans;
373 
374     return (1);
375 }
376 
377 /*!
378    \brief Get volume z-extent value
379 
380    \param gvl pointer to geovol struct
381    \param[out] min z-min value
382    \param[out] max z-max value
383 
384    \return 1
385  */
gvl_get_zextents(geovol * gvl,float * min,float * max)386 int gvl_get_zextents(geovol * gvl, float *min, float *max)
387 {
388     *min = gvl->zmin + gvl->z_trans;
389     *max = gvl->zmax + gvl->z_trans;
390 
391     return (1);
392 }
393 
394 /*!
395    \brief Get volume x-range value
396 
397    \param[out] min x-min value
398    \param[out] max x-max value
399 
400    \return 1
401  */
gvl_get_xrange(float * min,float * max)402 int gvl_get_xrange(float *min, float *max)
403 {
404     geovol *gvl;
405     float tmin, tmax;
406 
407     if (Vol_top) {
408 	gvl_get_xextents(Vol_top, &tmin, &tmax);
409 	*min = tmin;
410 	*max = tmax;
411     }
412     else {
413 	return (-1);
414     }
415 
416     for (gvl = Vol_top->next; gvl; gvl = gvl->next) {
417 	gvl_get_xextents(gvl, &tmin, &tmax);
418 
419 	if (tmin < *min) {
420 	    *min = tmin;
421 	}
422 
423 	if (tmax > *max) {
424 	    *max = tmax;
425 	}
426     }
427 
428     return (1);
429 }
430 
431 /*!
432    \brief Get volume y-range value
433 
434    \param[out] min y-min value
435    \param[out] max y-max value
436 
437    \return 1
438  */
gvl_get_yrange(float * min,float * max)439 int gvl_get_yrange(float *min, float *max)
440 {
441     geovol *gvl;
442     float tmin, tmax;
443 
444     if (Vol_top) {
445 	gvl_get_yextents(Vol_top, &tmin, &tmax);
446 	*min = tmin;
447 	*max = tmax;
448     }
449     else {
450 	return (-1);
451     }
452 
453     for (gvl = Vol_top->next; gvl; gvl = gvl->next) {
454 	gvl_get_yextents(gvl, &tmin, &tmax);
455 
456 	if (tmin < *min) {
457 	    *min = tmin;
458 	}
459 
460 	if (tmax > *max) {
461 	    *max = tmax;
462 	}
463     }
464 
465     return (1);
466 }
467 
468 /*!
469    \brief Get volume z-range value
470 
471    \param[out] min z-min value
472    \param[out] max z-max value
473 
474    \return 1
475  */
gvl_get_zrange(float * min,float * max)476 int gvl_get_zrange(float *min, float *max)
477 {
478     geovol *gvl;
479     float tmin, tmax;
480 
481     if (Vol_top) {
482 	gvl_get_zextents(Vol_top, &tmin, &tmax);
483 	*min = tmin;
484 	*max = tmax;
485     }
486     else {
487 	return (-1);
488     }
489 
490     for (gvl = Vol_top->next; gvl; gvl = gvl->next) {
491 	gvl_get_zextents(gvl, &tmin, &tmax);
492 
493 	if (tmin < *min) {
494 	    *min = tmin;
495 	}
496 
497 	if (tmax > *max) {
498 	    *max = tmax;
499 	}
500     }
501 
502     return (1);
503 }
504 
505 /************************************************************************/
506 /* ISOSURFACES */
507 
508 /************************************************************************/
509 
510 /*!
511    \brief Initialize geovol_isosurf struct
512 
513    \param isosurf pointer to geovol_isosurf struct
514 
515    \return -1 on failure
516    \return 1 on success
517  */
gvl_isosurf_init(geovol_isosurf * isosurf)518 int gvl_isosurf_init(geovol_isosurf * isosurf)
519 {
520     int i;
521 
522     G_debug(5, "gvl_isosurf_init");
523 
524     if (!isosurf)
525 	return (-1);
526 
527     for (i = 0; i < MAX_ATTS; i++) {
528 	isosurf->att[i].att_src = NOTSET_ATT;
529 	isosurf->att[i].constant = 0.;
530 	isosurf->att[i].hfile = -1;
531 	isosurf->att[i].user_func = NULL;
532 	isosurf->att[i].att_data = NULL;
533 	isosurf->att[i].changed = 0;
534     }
535 
536     isosurf->data = NULL;
537     isosurf->data_desc = 0;
538     isosurf->inout_mode = 0;
539 
540     return (1);
541 }
542 
543 /*!
544    \brief Free geovol_isosurf struct
545 
546    \param isosurf pointer to geovol_isosurf struct
547 
548    \return -1 on failure
549    \return 1 on success
550  */
gvl_isosurf_freemem(geovol_isosurf * isosurf)551 int gvl_isosurf_freemem(geovol_isosurf * isosurf)
552 {
553     int i;
554 
555     G_debug(5, "gvl_isosurf_freemem");
556 
557     if (!isosurf)
558 	return (-1);
559 
560     for (i = 0; i < MAX_ATTS; i++) {
561 	gvl_isosurf_set_att_src(isosurf, i, NOTSET_ATT);
562     }
563 
564     G_free(isosurf->data);
565 
566     return (1);
567 }
568 
569 /*!
570    \brief Get isosurface of given volume set
571 
572    \param id volume set id
573    \param isosurf_id isosurface id (0 - MAX_ISOSURFS)
574 
575    \return pointer to geovol_isosurf struct
576    \return NULL on failure
577  */
gvl_isosurf_get_isosurf(int id,int isosurf_id)578 geovol_isosurf *gvl_isosurf_get_isosurf(int id, int isosurf_id)
579 {
580     geovol *gvl;
581 
582     G_debug(5, "gvl_isosurf_get_isosurf(): id=%d isosurf=%d", id, isosurf_id);
583 
584     gvl = gvl_get_vol(id);
585 
586     if (gvl) {
587 	if ((isosurf_id < 0) || (isosurf_id > (gvl->n_isosurfs - 1)))
588 	    return (NULL);
589 
590 	return gvl->isosurf[isosurf_id];
591     }
592 
593     return (NULL);
594 }
595 
596 /*!
597    \brief Get attribute source
598 
599    \param isosurf pointer to geovol_isosurf struct
600    \param desc attribute id
601 
602    \return -1 on failure
603    \return attribute value
604  */
gvl_isosurf_get_att_src(geovol_isosurf * isosurf,int desc)605 int gvl_isosurf_get_att_src(geovol_isosurf * isosurf, int desc)
606 {
607     G_debug(5, "isosurf_get_att_src");
608 
609     if (!LEGAL_ATT(desc)) {
610 	return (-1);
611     }
612 
613     if (isosurf) {
614 	return (isosurf->att[desc].att_src);
615     }
616 
617     return (-1);
618 }
619 
620 /*!
621    \brief Set attribute source
622 
623    \param isosurf pointer to geovol_isosurf struct
624    \param desc attribute id
625    \param src attribute value
626 
627    \return -1 on failure
628    \return 1 on success
629  */
gvl_isosurf_set_att_src(geovol_isosurf * isosurf,int desc,int src)630 int gvl_isosurf_set_att_src(geovol_isosurf * isosurf, int desc, int src)
631 {
632     G_debug(5, "gvl_isosurf_set_att_src");
633 
634     /* check if old source was MAP_ATT, deattach volfile */
635     if (MAP_ATT == gvl_isosurf_get_att_src(isosurf, desc)) {
636 	gvl_file_free_datah(isosurf->att[desc].hfile);
637 
638 	if (desc == ATT_COLOR) {
639 	    Gvl_unload_colors_data(isosurf->att[desc].att_data);
640 	}
641     }
642 
643     if (isosurf && LEGAL_SRC(src)) {
644 	isosurf->att[desc].att_src = src;
645 	gvl_isosurf_set_att_changed(isosurf, desc);
646 
647 	return (1);
648     }
649 
650     return (-1);
651 }
652 
653 /*!
654    \brief Set isosurface attribute constant
655 
656    \param isosurf pointer to geovol_isosurf struct
657    \param desc attribute descriptor
658    \param constant attribute value
659 
660    \return -1 on failure
661    \return 1 on success
662  */
gvl_isosurf_set_att_const(geovol_isosurf * isosurf,int desc,float constant)663 int gvl_isosurf_set_att_const(geovol_isosurf * isosurf, int desc,
664 			      float constant)
665 {
666     G_debug(5, "gvl_isosurf_set_att_const(): att=%d, const=%f",
667 	    desc, constant);
668 
669     if (isosurf) {
670 	isosurf->att[desc].constant = constant;
671 
672 	gvl_isosurf_set_att_src(isosurf, desc, CONST_ATT);
673 
674 	return (1);
675     }
676 
677     return (-1);
678 }
679 
680 /*!
681    \brief Set attribute map
682 
683    \param isosurf pointer to geovol_isosurf struct
684    \param desc attribute id
685    \param filename filename
686 
687    \return -1 on failure
688    \return 1 on success
689  */
gvl_isosurf_set_att_map(geovol_isosurf * isosurf,int desc,const char * filename)690 int gvl_isosurf_set_att_map(geovol_isosurf * isosurf, int desc,
691 			    const char *filename)
692 {
693     int hfile;
694 
695     G_debug(5, "gvl_isosurf_set_att_map(): att=%d map=%s", desc, filename);
696 
697     if (isosurf) {
698 	if (0 > (hfile = gvl_file_newh(filename, VOL_FTYPE_RASTER3D)))
699 	    return (-1);
700 
701 	gvl_isosurf_set_att_src(isosurf, desc, MAP_ATT);
702 
703 	isosurf->att[desc].hfile = hfile;
704 
705 	if (ATT_COLOR == desc) {
706 	    Gvl_load_colors_data(&(isosurf->att[desc].att_data), filename);
707 	}
708 	return (1);
709     }
710 
711     return (-1);
712 }
713 
714 /*!
715    \brief Set attribute changed
716 
717    \param isosurf pointer to geovol_isosurf struct
718    \param desc attribute id
719 
720    \return -1 on failure
721    \return 1 on success
722  */
gvl_isosurf_set_att_changed(geovol_isosurf * isosurf,int desc)723 int gvl_isosurf_set_att_changed(geovol_isosurf * isosurf, int desc)
724 {
725     int i;
726 
727     G_debug(5, "gvl_isosurf_set_att_changed");
728 
729     if (isosurf && LEGAL_ATT(desc)) {
730 	isosurf->att[desc].changed = 1;
731 
732 	if ((desc == ATT_TOPO) || (desc == ATT_MASK)) {
733 	    for (i = 1; i < MAX_ATTS; i++)
734 		isosurf->att[i].changed = 1;
735 	}
736 
737 	return (1);
738     }
739 
740     return (-1);
741 }
742 
743 /************************************************************************/
744 /* SLICES */
745 
746 /************************************************************************/
747 
748 /*!
749    \brief Initialize geovol_slice struct
750 
751    \param slice pointer to geovol_slice struct
752 
753    \return -1 on failure
754    \return 1 on success
755  */
gvl_slice_init(geovol_slice * slice)756 int gvl_slice_init(geovol_slice * slice)
757 {
758     G_debug(5, "gvl_slice_init");
759 
760     if (!slice)
761 	return (-1);
762 
763     slice->data = NULL;
764     slice->changed = 0;
765     slice->mode = 1;
766     slice->transp = 0;
767 
768     slice->z1 = 0;
769     slice->z2 = 99;
770 
771     return (1);
772 }
773 
774 /*!
775    \brief Free geovol_slice struct
776 
777    \param slice pointer to geovol_slice struct
778 
779    \return -1 on failure
780    \return 1 on success
781  */
gvl_slice_freemem(geovol_slice * slice)782 int gvl_slice_freemem(geovol_slice * slice)
783 {
784     G_debug(5, "gvl_slice_freemem");
785 
786     if (!slice)
787 	return (-1);
788 
789     G_free(slice->data);
790 
791     return (1);
792 }
793 
794 /*!
795    \brief Get geovol_slice struct
796 
797    \param id volume set id
798    \param slice_id slice id
799 
800    \return pointer to geovol_slice struct
801    \return NULL on failure
802  */
gvl_slice_get_slice(int id,int slice_id)803 geovol_slice *gvl_slice_get_slice(int id, int slice_id)
804 {
805     geovol *gvl;
806 
807     gvl = gvl_get_vol(id);
808 
809     if (gvl) {
810 	if ((slice_id < 0) || (slice_id > (gvl->n_slices - 1)))
811 	    return (NULL);
812 
813 	return gvl->slice[slice_id];
814     }
815 
816     return (NULL);
817 }
818