1 /*!
2    \file lib/ogsf/gs.c
3 
4    \brief OGSF library - loading and manipulating 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 <stdio.h>
21 
22 #include <grass/ogsf.h>
23 #include <grass/glocale.h>
24 
25 #include "gsget.h"
26 #include "rowcol.h"
27 
28 #define FIRST_SURF_ID 110658
29 
30 static geosurf *Surf_top;
31 static int Invertmask;
32 
33 /***********************************************************************/
gs_err(const char * msg)34 void gs_err(const char *msg)
35 {
36     G_warning("%s", msg);
37 
38     return;
39 }
40 
41 /*!
42    \brief Initialize library
43 
44    Still need to take care of library initialization,
45    probably want to define a Surf_top of constant value (i.e., 0)
46  */
gs_init(void)47 void gs_init(void)
48 {
49     Surf_top = NULL;
50 
51     return;
52 }
53 
54 /*!
55    \brief Get geosurf struct
56 
57    \param id surface id
58 
59    \return pointer to geosurf struct
60    \return NULL if not found
61  */
gs_get_surf(int id)62 geosurf *gs_get_surf(int id)
63 {
64     geosurf *gs;
65 
66     G_debug(5, "gs_get_surf():");
67 
68     for (gs = Surf_top; gs; gs = gs->next) {
69 	if (gs->gsurf_id == id) {
70 	    G_debug(5, "  id=%d", id);
71 	    return (gs);
72 	}
73     }
74 
75     return (NULL);
76 }
77 
78 /*!
79    \brief Get previous geosurf struct
80 
81    \param id current surface id
82 
83    \return pointer to geosurf struct
84    \return NULL if not found
85  */
gs_get_prev_surface(int id)86 geosurf *gs_get_prev_surface(int id)
87 {
88     geosurf *ps;
89 
90     G_debug(5, "gs_get_prev_surface");
91 
92     for (ps = Surf_top; ps; ps = ps->next) {
93 	if (ps->gsurf_id == id - 1) {
94 	    return (ps);
95 	}
96     }
97 
98     return (NULL);
99 }
100 
101 /*!
102    \brief Get array of geosurf structs
103 
104    \param gsurfs pointer to array
105 
106    \return number of geosurfs
107  */
gs_getall_surfaces(geosurf ** gsurfs)108 int gs_getall_surfaces(geosurf ** gsurfs)
109 {
110     geosurf *gs;
111     int i;
112 
113     for (i = 0, gs = Surf_top; gs; gs = gs->next, i++) {
114 	gsurfs[i] = gs;
115     }
116 
117     G_debug(5, "gs_num_surfaces(): num=%d", i);
118 
119     return (i);
120 }
121 
122 /*!
123    \brief Get number of surfaces
124 
125    \return number of surfaces
126  */
gs_num_surfaces(void)127 int gs_num_surfaces(void)
128 {
129     geosurf *gs;
130     int i;
131 
132     for (i = 0, gs = Surf_top; gs; gs = gs->next, i++) ;
133 
134     G_debug(5, "gs_num_surfaces(): num=%d", i);
135 
136     return (i);
137 }
138 
139 
140 /*!
141    \brief Check if attribute is set
142 
143    \param surf pointer to gsurf or NULL to look at all geosurfs
144    \param att attribute id
145 
146    \return 1 attribute is set up
147    \return 0 attribute is not set up
148  */
gs_att_is_set(geosurf * surf,IFLAG att)149 int gs_att_is_set(geosurf * surf, IFLAG att)
150 {
151     geosurf *gs;
152 
153     if (surf) {
154 	return (NOTSET_ATT != surf->att[att].att_src);
155     }
156 
157     /* if surf == NULL, look at all surfs */
158     for (gs = Surf_top; gs; gs = gs->next) {
159 	if (NOTSET_ATT != gs->att[att].att_src) {
160 	    return (1);
161 	}
162     }
163 
164     return (0);
165 }
166 
167 /*!
168    \brief Get last allocated geosurf struct from list
169 
170    \return pointer to geosurf struct
171  */
gs_get_last_surface(void)172 geosurf *gs_get_last_surface(void)
173 {
174     geosurf *ls;
175 
176     if (!Surf_top) {
177 	return (NULL);
178     }
179 
180     for (ls = Surf_top; ls->next; ls = ls->next) ;
181 
182     G_debug(5, "gs_get_last_surface(): last surface id=%d", ls->gsurf_id);
183 
184     return (ls);
185 }
186 
187 
188 /*!
189    \brief Allocate new geosurf struct
190 
191    \return pointer to geosurf struct
192  */
gs_get_new_surface(void)193 geosurf *gs_get_new_surface(void)
194 {
195     geosurf *ns, *ls;
196 
197     ns = (geosurf *) G_malloc(sizeof(geosurf));	/* G_fatal_error */
198     if (!ns) {
199 	return (NULL);
200     }
201 
202     if ((ls = gs_get_last_surface())) {
203 	ls->next = ns;
204 	ns->gsurf_id = ls->gsurf_id + 1;
205     }
206     else {
207 	Surf_top = ns;
208 	ns->gsurf_id = FIRST_SURF_ID;
209     }
210 
211     ns->next = NULL;
212 
213     G_debug(5, "gs_get_new_surface(): id=%d", ns->gsurf_id);
214 
215     return (ns);
216 }
217 
218 /*!
219    \brief Initialize allocated geosurf struct
220 
221    \todo Now xmin & ox are the same, right? - get rid of ox, oy in geosurf struct?
222 
223    \param gs pointer to geosurf struct
224    \param ox,oy x/y origin coordinates
225    \param rows number of rows
226    \param cols number of cols
227    \param xres,yres x/y resolution value
228 
229    \return -1 on error
230    \return 0 on success
231  */
gs_init_surf(geosurf * gs,double ox,double oy,int rows,int cols,double xres,double yres)232 int gs_init_surf(geosurf * gs, double ox, double oy, int rows, int cols,
233 		 double xres, double yres)
234 {
235     geosurf *ps;
236     int i;
237 
238     if (!gs) {
239 	return (-1);
240     }
241 
242     G_debug(5, "gs_init_surf() id=%d", gs->gsurf_id);
243 
244     /* default attributes */
245     for (i = 0; i < MAX_ATTS; i++) {
246 	gs->att[i].att_src = NOTSET_ATT;
247 	gs->att[i].att_type = ATTY_INT;
248 	gs->att[i].hdata = -1;
249 	gs->att[i].user_func = NULL;
250 	gs->att[i].constant = 0.;
251 	gs->att[i].lookup = NULL;
252 	gs->att[i].min_nz = gs->att[i].max_nz = gs->att[i].range_nz = 0;
253 	gs->att[i].default_null = 0.;
254     }
255 
256     /* default values */
257     gs->ox = ox;
258     gs->oy = oy;
259     gs->rows = rows;
260     gs->cols = cols;
261     gs->xres = xres;
262     gs->yres = yres;
263     gs->x_mod = 2;
264     gs->y_mod = 2;
265     gs->x_modw = rows / 30;
266     gs->y_modw = rows / 30;
267     gs->xmin = ox;
268     gs->xmax = ox + (cols - 1) * xres;
269     gs->xrange = gs->xmax - gs->xmin;
270     gs->ymin = oy;
271     gs->ymax = oy + (rows - 1) * yres;
272     gs->yrange = gs->ymax - gs->ymin;
273     gs->zmin = gs->zmin_nz = gs->zminmasked = 0;
274     gs->zmax = gs->zmax_nz = 0;
275     gs->zrange = gs->zrange_nz = 0;
276     gs->wire_color = 0x00888888;
277     gs->x_trans = gs->y_trans = gs->z_trans = 0.0;
278     gs->nz_topo = gs->nz_color = 0;
279     gs->norm_needupdate = 1;
280     gs->mask_needupdate = 1;
281     gs->curmask = NULL;
282     gs->norms = NULL;
283 
284     gs->draw_mode = DM_GOURAUD;
285 
286     /* default z_exag value */
287     if (gs->gsurf_id == FIRST_SURF_ID) {
288 	gs->z_exag = 1.0;
289     }
290     else {
291 	ps = gs_get_prev_surface(gs->gsurf_id);
292 	gs->z_exag = ps->z_exag;
293     }
294 
295     return (0);
296 }
297 
298 /*!
299    \brief Init geosurf normbuff
300 
301    \param gs pointer to geosurf struct
302 
303    \return 0 on error
304    \return 1 on success
305  */
gs_init_normbuff(geosurf * gs)306 int gs_init_normbuff(geosurf * gs)
307 {
308     long size;
309 
310     if (!gs) {
311 	return (0);
312     }
313 
314     if (gs->norms) {
315 	G_free(gs->norms);
316     }
317 
318     size = gs->rows * gs->cols * sizeof(unsigned long);
319 
320     gs->norms = (unsigned long *)G_malloc(size);	/* G_fatal_error */
321     if (!gs->norms) {
322 	return (-1);
323     }
324 
325     gs->norm_needupdate = 1;
326 
327     return (1);
328 }
329 
330 /*!
331    \brief Debugging, print 'from/to' model coordinates to stderr
332 
333    \todo G_debug ?
334 
335    \param ft pointer to coordinates
336  */
print_frto(float (* ft)[4])337 void print_frto(float (*ft)[4])
338 {
339     fprintf(stderr, "FROM: %f, %f, %f\n", ft[FROM][X], ft[FROM][Y],
340 	    ft[FROM][Z]);
341     fprintf(stderr, "TO: %f, %f, %f\n", ft[TO][X], ft[TO][Y], ft[TO][Z]);
342 
343     return;
344 }
345 
346 /*!
347    \brief Debugging, print 'to' real coordinates to stderr
348 
349    \todo G_debug ?
350 
351    \param ft pointer to coordinates
352  */
print_realto(float * rt)353 void print_realto(float *rt)
354 {
355     fprintf(stderr, "REAL TO: %f, %f, %f\n", rt[X], rt[Y], rt[Z]);
356 
357     return;
358 }
359 
360 /*!
361    \brief Debugging, 256 integer values from buffer
362 
363    \todo G_debug ?
364 
365    \param ft pointer to buffer
366  */
print_256lookup(int * buff)367 void print_256lookup(int *buff)
368 {
369     int i;
370 
371     for (i = 0; i < 256; i++) {
372 	if (!(i % 8)) {
373 	    fprintf(stderr, "\n");
374 	}
375 
376 	fprintf(stderr, "%x ", buff[i]);
377     }
378 
379     fprintf(stderr, "\n");
380 
381     return;
382 }
383 
384 /*!
385    \brief Debugging, print geosurf fields to stderr
386 
387    \todo G_debug ?
388 
389    \param s pointer to geosurf struct
390  */
print_surf_fields(geosurf * s)391 void print_surf_fields(geosurf * s)
392 {
393     fprintf(stderr, "ID: %d\n", s->gsurf_id);
394     fprintf(stderr, "rows: %d cols: %d\n", s->rows, s->cols);
395     fprintf(stderr, "draw_mode: %x\n", s->draw_mode);
396     fprintf(stderr, "wire_color: %lx\n", s->wire_color);
397     fprintf(stderr, "ox: %lf oy: %lf\n", s->ox, s->oy);
398     fprintf(stderr, "xres: %lf yres: %lf\n", s->xres, s->yres);
399     fprintf(stderr, "z_exag: %f \n", s->z_exag);
400     fprintf(stderr, "x_trans: %f y_trans: %f z_trans: %f\n",
401 	    s->x_trans, s->y_trans, s->z_trans);
402     fprintf(stderr, "xmin: %f ymin: %f zmin: %f\n",
403 	    s->xmin, s->ymin, s->zmin);
404     fprintf(stderr, "xmax: %f ymax: %f zmax: %f\n",
405 	    s->xmax, s->ymax, s->zmax);
406     fprintf(stderr, "x_mod: %d y_mod: %d x_modw: %d y_modw: %d\n",
407 	    s->x_mod, s->y_mod, s->x_modw, s->y_modw);
408 
409     return;
410 }
411 
412 /*!
413    \brief Debugging, print geoview fields to stderr
414 
415    \todo G_debug ?
416 
417    \param gv pointer to geoview struct
418  */
print_view_fields(geoview * gv)419 void print_view_fields(geoview * gv)
420 {
421     fprintf(stderr, "coord_sys: %d\n", gv->coord_sys);
422     fprintf(stderr, "view_proj: %d\n", gv->view_proj);
423     fprintf(stderr, "infocus: %d\n", gv->infocus);
424     print_frto(gv->from_to);
425     fprintf(stderr, "twist: %d fov: %d\n", gv->twist, gv->fov);
426     fprintf(stderr, "incl: %d look: %d\n", gv->incl, gv->look);
427     fprintf(stderr, "real_to: %f %f %f\n",
428 	    gv->real_to[X], gv->real_to[Y], gv->real_to[Z]);
429     fprintf(stderr, "vert_exag: %f scale: %f \n", gv->vert_exag, gv->scale);
430 
431     return;
432 }
433 
434 /*!
435    \brief Set default attribute values
436 
437    \param gs pointer to geosurf struct
438    \param defs array of default values (dim MAX_ATTRS)
439    \param null_defs array of null default values (dim MAX_ATTRS)
440  */
gs_set_defaults(geosurf * gs,float * defs,float * null_defs)441 void gs_set_defaults(geosurf * gs, float *defs, float *null_defs)
442 {
443     int i;
444 
445     G_debug(5, "gs_set_defaults(): id=%d", gs->gsurf_id);
446 
447     for (i = 0; i < MAX_ATTS; i++) {
448 	gs->att[i].constant = defs[i];
449 	gs->att[i].default_null = null_defs[i];
450 	gs->att[i].lookup = NULL;
451 	gs->att[i].hdata = -1;
452 	gs->att[i].att_src = NOTSET_ATT;
453     }
454 
455     return;
456 }
457 
458 /*!
459    \brief Remove geosurf struct from list
460 
461    \param id surface id
462  */
gs_delete_surf(int id)463 void gs_delete_surf(int id)
464 {
465     geosurf *fs;
466 
467     G_debug(5, "gs_delete_surf");
468 
469     fs = gs_get_surf(id);
470 
471     if (fs) {
472 	gs_free_surf(fs);
473     }
474 
475     return;
476 }
477 
478 /*!
479    \brief Free geosurf struct
480 
481    \param fs pointer to geosurf struct
482 
483    \return 1 found
484    \return 0 not found
485    \return -1 on error
486  */
gs_free_surf(geosurf * fs)487 int gs_free_surf(geosurf * fs)
488 {
489     geosurf *gs;
490     int found = 0;
491 
492     G_debug(5, "gs_free_surf");
493 
494     if (Surf_top) {
495 	if (fs == Surf_top) {
496 	    if (Surf_top->next) {
497 		/* can't free top if last */
498 		found = 1;
499 		Surf_top = fs->next;
500 	    }
501 	    else {
502 		gs_free_unshared_buffs(fs);
503 
504 		if (fs->curmask) {
505 		    G_free(fs->curmask);
506 		}
507 
508 		if (fs->norms) {
509 		    G_free(fs->norms);
510 		}
511 
512 		G_free(fs);
513 		Surf_top = NULL;
514 	    }
515 	}
516 	else {
517 	    for (gs = Surf_top; gs && !found; gs = gs->next) {
518 		if (gs->next) {
519 		    if (gs->next == fs) {
520 			found = 1;
521 			gs->next = fs->next;
522 		    }
523 		}
524 	    }
525 	}
526 
527 	if (found) {
528 	    gs_free_unshared_buffs(fs);
529 
530 	    if (fs->curmask) {
531 		G_free(fs->curmask);
532 	    }
533 
534 	    if (fs->norms) {
535 		G_free(fs->norms);
536 	    }
537 
538 	    G_free(fs);
539 	    fs = NULL;
540 	}
541 
542 	return (found);
543     }
544 
545     return (-1);
546 }
547 
548 /*!
549    \brief Free unshared buffers of geosurf struct
550 
551    <i>fs</i> has already been taken out of the list
552 
553    This function is fairly revealing about how shared datsets work
554 
555    \param fs pointer to geosurf struct
556  */
gs_free_unshared_buffs(geosurf * fs)557 void gs_free_unshared_buffs(geosurf * fs)
558 {
559     geosurf *gs;
560     int i, j, same;
561     int old_datah;
562 
563     G_debug(5, "gs_free_unshared_buffs");
564 
565     /* for each attribute
566        if !same, free buff
567      */
568     for (i = 0; i < MAX_ATTS; i++) {
569 	same = 0;
570 
571 	if (0 < (old_datah = fs->att[i].hdata)) {
572 	    /* for ea att of all other surfs */
573 	    for (gs = Surf_top; gs; gs = gs->next) {
574 		for (j = 0; j < MAX_ATTS; j++) {
575 		    if ((old_datah == gs->att[j].hdata) && (fs != gs)) {
576 			same = 1;
577 		    }
578 		}
579 	    }
580 
581 	    if (!same) {
582 		gsds_free_datah(old_datah);
583 	    }
584 	}
585     }
586 
587     return;
588 }
589 
590 /*!
591    \brief Get number of reused values
592 
593    \param dh value
594 
595    \return number of reused values
596  */
gs_num_datah_reused(int dh)597 int gs_num_datah_reused(int dh)
598 {
599     geosurf *gs;
600     int ref, j;
601 
602     G_debug(5, "gs_num_datah_reused");
603 
604     /* for each attribute
605        if same, ++reference
606      */
607     /* for ea att of all surfs */
608     ref = 0;
609 
610     for (gs = Surf_top; gs; gs = gs->next) {
611 	for (j = 0; j < MAX_ATTS; j++) {
612 	    if (dh == gs->att[j].hdata) {
613 		ref++;
614 	    }
615 	}
616     }
617 
618     return (ref);
619 }
620 
621 /*!
622    \brief Get attribute type
623 
624    \param gs pointer to geosurf struct
625    \param desc attribute id
626 
627    \return -1 on error
628    \return attribute type
629  */
gs_get_att_type(geosurf * gs,int desc)630 int gs_get_att_type(geosurf * gs, int desc)
631 {
632     G_debug(5, "gs_get_att_type");
633 
634     if (!LEGAL_ATT(desc)) {
635 	return (-1);
636     }
637 
638     if (gs) {
639 	if (gs->att[desc].att_src != NOTSET_ATT) {
640 	    return (gs->att[desc].att_type);
641 	}
642     }
643 
644     return (-1);
645 }
646 
647 /*!
648    \brief Get attribute source
649 
650    \param gs pointer to geosurf struct
651    \param desc attribute id (descriptor)
652 
653    \return -1 on error
654    \return attribute source id
655  */
gs_get_att_src(geosurf * gs,int desc)656 int gs_get_att_src(geosurf * gs, int desc)
657 {
658     if (gs)
659 	G_debug(5, "gs_get_att_src(): id=%d, desc=%d", gs->gsurf_id, desc);
660     if (!LEGAL_ATT(desc)) {
661 	return (-1);
662     }
663 
664     if (gs) {
665 	return (gs->att[desc].att_src);
666     }
667 
668     return (-1);
669 }
670 
671 /*!
672    \brief Get attribute data buffer
673 
674    \param gs pointer to geosurf struct
675    \param desc attribute id (descriptor)
676    \param to_write non-zero value for 'write'
677 
678    \return NULL on error
679    \return pointer to typbuff
680  */
gs_get_att_typbuff(geosurf * gs,int desc,int to_write)681 typbuff *gs_get_att_typbuff(geosurf * gs, int desc, int to_write)
682 {
683     typbuff *tb;
684     geosurf *gsref;
685 
686     if (gs) {
687 	G_debug(5, "gs_get_att_typbuff(): id=%d desc=%d to_write=%d",
688 		gs->gsurf_id, desc, to_write);
689 	if ((tb = gsds_get_typbuff(gs->att[desc].hdata, to_write))) {
690 	    tb->tfunc = NULL;
691 
692 	    if (desc == ATT_TOPO) {
693 		gsref = gsdiff_get_SDref();
694 
695 		if (gsref && gsref != gs) {
696 		    tb->tfunc = gsdiff_do_SD;
697 		}
698 	    }
699 
700 	    return (tb);
701 	}
702     }
703 
704     return (NULL);
705 }
706 
707 /*!
708    \brief Allocate attribute buffer
709 
710    \param gs pointer to geosurf struct
711    \param desc attribute id (descriptor)
712    \param type buffer type (based on raster map type)
713 
714    \return -1 on error
715    \return amount of allocated memory
716  */
gs_malloc_att_buff(geosurf * gs,int desc,int type)717 size_t gs_malloc_att_buff(geosurf * gs, int desc, int type)
718 {
719     int hdata, dims[2], ndims;
720 
721     G_debug(5, "gs_malloc_att_buff");
722 
723     if (gs) {
724 	if (0 < (hdata = gs->att[desc].hdata)) {
725 	    dims[0] = gs->rows;
726 	    dims[1] = gs->cols;
727 	    ndims = 2;
728 	    gs_set_att_type(gs, desc, type);
729 
730 	    return (gsds_alloc_typbuff(hdata, dims, ndims, type));
731 	}
732     }
733 
734     return 0;
735 }
736 
737 /*!
738    \brief Allocate attribute lookup
739 
740    \param gs pointer to geosurf struct
741    \param desc attribute id
742 
743    \return -1 on error
744    \return pointer to typbuff (casted)
745  */
gs_malloc_lookup(geosurf * gs,int desc)746 int gs_malloc_lookup(geosurf * gs, int desc)
747 {
748     int size;
749 
750     G_debug(5, "gs_malloc_lookup");
751 
752     if (gs) {
753 	if (gs->att[desc].lookup) {
754 	    G_free(gs->att[desc].lookup);
755 	    gs->att[desc].lookup = NULL;
756 	}
757 
758 	switch (gs->att[desc].att_type) {
759 	case (ATTY_SHORT):
760 	    size = 32768 * sizeof(int);
761 
762 	    /* positive integers only, because use as array index */
763 	    gs->att[desc].lookup = (int *)G_malloc(size);	/* G_fatal_error */
764 	    if (!gs->att[desc].lookup) {
765 		return (-1);
766 	    }
767 
768 	    break;
769 	case (ATTY_CHAR):
770 	    size = 256 * sizeof(int);
771 
772 	    /* unsigned char */
773 	    gs->att[desc].lookup = (int *)G_malloc(size);
774 	    if (!gs->att[desc].lookup) {
775 		return (-1);
776 	    }
777 
778 	    break;
779 	default:
780 	    G_warning("bad type: gs_malloc_lookup");
781 	    return (-1);
782 	}
783 
784 	if (gs->att[desc].lookup) {
785 	    return (0);
786 	}
787 
788     }
789 
790     return (-1);
791 }
792 
793 /*!
794    \brief Set attribute type
795 
796    \param gs pointer to geosurf struct
797    \param desc attribute id
798    \param type attribute type
799 
800    \return -1 on error
801    \return 0 on success
802  */
gs_set_att_type(geosurf * gs,int desc,int type)803 int gs_set_att_type(geosurf * gs, int desc, int type)
804 {
805 
806     G_debug(5, "gs_set_att_type(): desc=%d, type=%d", desc, type);
807 
808     if (gs && LEGAL_TYPE(type)) {
809 	gs->att[desc].att_type = type;
810 
811 	return (0);
812     }
813 
814     return (-1);
815 }
816 
817 /*!
818    \brief Set attribute source
819 
820    \param gs pointer to geosurf struct
821    \param desc attribute id (descriptor)
822    \param src source id
823 
824    \return -1 on error
825    \return 0 on success
826  */
gs_set_att_src(geosurf * gs,int desc,int src)827 int gs_set_att_src(geosurf * gs, int desc, int src)
828 {
829     if (gs)
830 	G_debug(5, "gs_set_att_src(): id=%d desc=%d src=%d",
831 		gs->gsurf_id, desc, src);
832 
833     /* check if old source was MAP_ATT, free buff */
834     if (MAP_ATT == gs_get_att_src(gs, desc)) {
835 	if (1 == gs_num_datah_reused(gs->att[desc].hdata)) {
836 	    /* only reference */
837 	    G_debug(5, "gs_set_att_src(): replacing existing map");
838 	    gsds_free_datah(gs->att[desc].hdata);
839 	}
840 
841 	if (ATT_TOPO == desc) {
842 	    if (gs->norms) {
843 		G_free(gs->norms);
844 	    }
845 
846 	    gs->norms = NULL;
847 	    gs->norm_needupdate = 0;
848 	}
849     }
850 
851     if (gs && LEGAL_SRC(src)) {
852 	gs->att[desc].att_src = src;
853 
854 	return (0);
855     }
856 
857     return (-1);
858 }
859 
860 /*!
861    \brief Set attribute constant value
862 
863    \todo set typbuf constant
864 
865    \param gs pointer to geosurf struct
866    \param desc attribute id
867    \param constant constant value
868 
869    \return 0 on success
870    \return -1 on error
871  */
gs_set_att_const(geosurf * gs,int desc,float constant)872 int gs_set_att_const(geosurf * gs, int desc, float constant)
873 {
874 
875     if (gs) {
876 	G_debug(5, "gs_set_att_const(): id=%d, desc=%d, const=%f",
877 		gs->gsurf_id, desc, constant);
878 	gs->att[desc].constant = constant;
879 
880 	if (ATT_MASK == desc) {
881 	    gs->mask_needupdate = 1;
882 	}
883 	else {
884 	    gs_set_att_src(gs, desc, CONST_ATT);
885 	}
886 
887 	Gs_update_attrange(gs, desc);
888 
889 	return (0);
890     }
891 
892     return (-1);
893 }
894 
895 /*!
896    \brief Set geosurf mask mode
897 
898    \param invert invert mask
899  */
gs_set_maskmode(int invert)900 void gs_set_maskmode(int invert)
901 {
902     Invertmask = invert;
903 
904     return;
905 }
906 
907 /*!
908    \brief Check if mask is defined
909 
910    \param gs pointer to geosurf struct
911 
912    \return 1 if defined
913    \return 0 not defined
914  */
gs_mask_defined(geosurf * gs)915 int gs_mask_defined(geosurf * gs)
916 {
917     return (gs->att[ATT_MASK].att_src != NOTSET_ATT);
918 }
919 
920 /*!
921    \brief
922 
923    Should only be called when setting up the current mask (gs_bm.c)
924 
925    \param tb pointer to typbuff
926    \param col number of cols
927    \param row number of rows
928    \param offset offset value
929 
930    \return 1
931    \return 0
932  */
gs_masked(typbuff * tb,int col,int row,int offset)933 int gs_masked(typbuff * tb, int col, int row, int offset)
934 {
935     int ret;
936 
937     ret = 1;
938 
939     if (tb->bm) {
940 	ret = BM_get(tb->bm, col, row);
941     }
942     else if (tb->cb) {
943 	ret = tb->cb[offset];
944     }
945     else if (tb->sb) {
946 	ret = tb->sb[offset];
947     }
948     else if (tb->ib) {
949 	ret = tb->ib[offset];
950     }
951     else if (tb->fb) {
952 	ret = tb->fb[offset];
953     }
954 
955     return (Invertmask ? ret : !ret);
956 }
957 
958 /*!
959    \brief
960 
961    Call this one when you already know att_src is MAP_ATT
962 
963    \param cobuff
964    \param coloratt color attribute
965    \param offset offset value
966 
967    \return packed color for category at offset
968  */
gs_mapcolor(typbuff * cobuff,gsurf_att * coloratt,int offset)969 int gs_mapcolor(typbuff * cobuff, gsurf_att * coloratt, int offset)
970 {
971     if (coloratt->lookup) {
972 	/* for now, but may add larger color lookup capabilities later,
973 	   so would have to use GET_MAPATT */
974 	return (coloratt->lookup[cobuff->cb[offset]]);
975     }
976 
977     return (cobuff->ib[offset]);
978 }
979 
980 /*
981    In the following functions, "extents" refers to translated extents for
982    a single surface, while "range" refers to accumulated extents of all
983    loaded surfaces
984  */
985 
986 /*!
987    \brief Get z-extent values
988 
989    \todo pass flag to use zminmasked instead of zmin
990 
991    \param gs pointer to geosurf struct
992    \param[out] min z-min value
993    \param[out] max z-max value
994    \param[out] mid z-middle value
995 
996    \return 1
997  */
gs_get_zextents(geosurf * gs,float * min,float * max,float * mid)998 int gs_get_zextents(geosurf * gs, float *min, float *max, float *mid)
999 {
1000     *min = gs->zmin + gs->z_trans;
1001     *max = gs->zmax + gs->z_trans;
1002     *mid = (*max + *min) / 2.;
1003 
1004     return (1);
1005 }
1006 
1007 /*!
1008    \brief Get x-extent values
1009 
1010    \param gs pointer to geosurf struct
1011    \param[out] min x-min value
1012    \param[out] max x-max value
1013 
1014    \return 1
1015  */
gs_get_xextents(geosurf * gs,float * min,float * max)1016 int gs_get_xextents(geosurf * gs, float *min, float *max)
1017 {
1018     *min = gs->xmin + gs->x_trans;
1019     *max = gs->xmax + gs->x_trans;
1020 
1021     return (1);
1022 }
1023 
1024 /*!
1025    \brief Get y-extent values
1026 
1027    \param gs pointer to geosurf struct
1028    \param[out] min y-min value
1029    \param[out] max y-max value
1030 
1031    \return 1
1032  */
gs_get_yextents(geosurf * gs,float * min,float * max)1033 int gs_get_yextents(geosurf * gs, float *min, float *max)
1034 {
1035     *min = gs->ymin + gs->y_trans;
1036     *max = gs->ymax + gs->y_trans;
1037 
1038     return (1);
1039 }
1040 
1041 
1042 /*!
1043    \brief Get z-range
1044 
1045    \todo pass flag to use zminmasked instead of zmin
1046    could also have this return a weighted average for vertical "centroid"
1047 
1048    \param[out] min z-min value
1049    \param[out] max z-max value
1050 
1051    \return -1 on error (no surface)
1052    \return 1 on success
1053  */
gs_get_zrange0(float * min,float * max)1054 int gs_get_zrange0(float *min, float *max)
1055 {
1056     geosurf *gs;
1057 
1058     if (Surf_top) {
1059 	*min = Surf_top->zmin;
1060 	*max = Surf_top->zmax;
1061     }
1062     else {
1063 	return (-1);
1064     }
1065 
1066     for (gs = Surf_top->next; gs; gs = gs->next) {
1067 	if (gs->zmin < *min) {
1068 	    *min = gs->zmin;
1069 	}
1070 
1071 	if (gs->zmax > *max) {
1072 	    *max = gs->zmax;
1073 	}
1074     }
1075 
1076     return (1);
1077 }
1078 
1079 /*!
1080    \brief Get z-range
1081 
1082    \param[out] min z-min value
1083    \param[out] max z-max value
1084 
1085    \return -1 on error (no surface)
1086    \return 1 on success
1087  */
gs_get_zrange(float * min,float * max)1088 int gs_get_zrange(float *min, float *max)
1089 {
1090     geosurf *gs;
1091     float tmin, tmax, tmid;
1092 
1093     if (Surf_top) {
1094 	gs_get_zextents(Surf_top, &tmin, &tmax, &tmid);
1095 	*min = tmin;
1096 	*max = tmax;
1097     }
1098     else {
1099 	return (-1);
1100     }
1101 
1102     for (gs = Surf_top->next; gs; gs = gs->next) {
1103 	gs_get_zextents(gs, &tmin, &tmax, &tmid);
1104 
1105 	if (tmin < *min) {
1106 	    *min = tmin;
1107 	}
1108 
1109 	if (tmax > *max) {
1110 	    *max = tmax;
1111 	}
1112     }
1113 
1114     return (1);
1115 }
1116 
1117 /*!
1118    \brief Get x-range
1119 
1120    \param[out] min x-min value
1121    \param[out] max x-max value
1122 
1123    \return -1 on error (no surface)
1124    \return 1 on success
1125  */
gs_get_xrange(float * min,float * max)1126 int gs_get_xrange(float *min, float *max)
1127 {
1128     geosurf *gs;
1129     float tmin, tmax;
1130 
1131     if (Surf_top) {
1132 	gs_get_xextents(Surf_top, &tmin, &tmax);
1133 	*min = tmin;
1134 	*max = tmax;
1135     }
1136     else {
1137 	return (-1);
1138     }
1139 
1140     for (gs = Surf_top->next; gs; gs = gs->next) {
1141 	gs_get_xextents(gs, &tmin, &tmax);
1142 
1143 	if (tmin < *min) {
1144 	    *min = tmin;
1145 	}
1146 
1147 	if (tmax > *max) {
1148 	    *max = tmax;
1149 	}
1150     }
1151 
1152     return (1);
1153 }
1154 
1155 /*!
1156    \brief Get y-range
1157 
1158    \param[out] min y-min value
1159    \param[out] max y-max value
1160 
1161    \return -1 on error (no surface)
1162    \return 1 on success
1163  */
gs_get_yrange(float * min,float * max)1164 int gs_get_yrange(float *min, float *max)
1165 {
1166     geosurf *gs;
1167     float tmin, tmax;
1168 
1169     if (Surf_top) {
1170 	gs_get_yextents(Surf_top, &tmin, &tmax);
1171 	*min = tmin;
1172 	*max = tmax;
1173     }
1174     else {
1175 	return (-1);
1176     }
1177 
1178     for (gs = Surf_top->next; gs; gs = gs->next) {
1179 	gs_get_yextents(gs, &tmin, &tmax);
1180 
1181 	if (tmin < *min) {
1182 	    *min = tmin;
1183 	}
1184 
1185 	if (tmax > *max) {
1186 	    *max = tmax;
1187 	}
1188     }
1189 
1190     return (1);
1191 }
1192 
1193 /*!
1194    \brief Get average z-max value
1195 
1196    Useful for setting position of cplane, lighting ball, etc.
1197 
1198    \param[out] azmax average z-max value
1199 
1200    \return -1 on error
1201    \return 1 on success
1202  */
gs_get_data_avg_zmax(float * azmax)1203 int gs_get_data_avg_zmax(float *azmax)
1204 {
1205     float zmax;
1206     int i;
1207     geosurf *gs;
1208 
1209     zmax = *azmax = 0.0;
1210 
1211     if (Surf_top) {
1212 	for (i = 0, gs = Surf_top; gs; i++, gs = gs->next) {
1213 	    zmax += (gs->zmax + gs->z_trans);
1214 	}
1215 
1216 	*azmax = zmax / i;
1217 
1218 	return (1);
1219     }
1220 
1221     return (-1);
1222 }
1223 
1224 /*!
1225    \brief Get data center point
1226 
1227    \param[out] center (array X,Y,Z)
1228 
1229    \return -1 on error
1230    \return 1 on success
1231  */
gs_get_datacenter(float * cen)1232 int gs_get_datacenter(float *cen)
1233 {
1234     float zmin, zmax, ymin, ymax, xmin, xmax;
1235     geosurf *gs;
1236 
1237     if (Surf_top) {
1238 	zmin = Surf_top->zmin;
1239 	zmax = Surf_top->zmax;
1240 	ymin = Surf_top->ymin;
1241 	ymax = Surf_top->ymax;
1242 	xmin = Surf_top->xmin;
1243 	xmax = Surf_top->xmax;
1244 
1245 	for (gs = Surf_top->next; gs; gs = gs->next) {
1246 	    if (gs->zmin < zmin) {
1247 		zmin = gs->zmin;
1248 	    }
1249 
1250 	    if (gs->zmax > zmax) {
1251 		zmax = gs->zmax;
1252 	    }
1253 
1254 	    if (gs->ymin < ymin) {
1255 		ymin = gs->ymin;
1256 	    }
1257 
1258 	    if (gs->ymax > ymax) {
1259 		ymax = gs->ymax;
1260 	    }
1261 
1262 	    if (gs->xmin < xmin) {
1263 		xmin = gs->xmin;
1264 	    }
1265 
1266 	    if (gs->xmax > xmax) {
1267 		xmax = gs->xmax;
1268 	    }
1269 	}
1270 
1271 	cen[X] = (xmin + xmax) / 2. - xmin;
1272 	cen[Y] = (ymin + ymax) / 2. - ymin;
1273 	cen[Z] = (zmin + zmax) / 2.;
1274 
1275 	return (1);
1276     }
1277 
1278     cen[X] = cen[Y] = cen[Z] = 0.0;
1279 
1280     return (-1);
1281 }
1282 
1283 
1284 /*!
1285    \brief Set for geosurf need-to-update mark
1286 
1287    \return -1 no surface available
1288    \return 1 on success
1289  */
gs_setall_norm_needupdate(void)1290 int gs_setall_norm_needupdate(void)
1291 {
1292     geosurf *gs;
1293 
1294     if (Surf_top) {
1295 	Surf_top->norm_needupdate = 1;
1296     }
1297     else {
1298 	return (-1);
1299     }
1300 
1301     for (gs = Surf_top->next; gs; gs = gs->next) {
1302 	gs->norm_needupdate = 1;
1303     }
1304 
1305     return (1);
1306 }
1307 
1308 /*!
1309    \brief Check if point is masked
1310 
1311    \param gs pointer to geosurf struct
1312    \param pt point coordinates (X,Y,Z)
1313 
1314    \return 1 masked
1315    \return 0 not masked
1316  */
gs_point_is_masked(geosurf * gs,float * pt)1317 int gs_point_is_masked(geosurf * gs, float *pt)
1318 {
1319     int vrow, vcol, drow, dcol;
1320     int retmask = 0, npts = 0;
1321     float p2[2];
1322 
1323     if (!gs->curmask) {
1324 	return (0);
1325     }
1326 
1327     vrow = Y2VROW(gs, pt[Y]);
1328     vcol = X2VCOL(gs, pt[X]);
1329 
1330     /* check right & bottom edges */
1331     if (pt[X] == VCOL2X(gs, VCOLS(gs))) {
1332 	/* right edge */
1333 	vcol -= 1;
1334     }
1335 
1336     if (pt[Y] == VROW2Y(gs, VROWS(gs))) {
1337 	/* bottom edge */
1338 	vrow -= 1;
1339     }
1340 
1341     drow = VROW2DROW(gs, vrow);
1342     dcol = VCOL2DCOL(gs, vcol);
1343 
1344     if (BM_get(gs->curmask, dcol, drow)) {
1345 	retmask |= MASK_TL;
1346 	npts++;
1347     }
1348 
1349     dcol = VCOL2DCOL(gs, vcol + 1);
1350 
1351     if (BM_get(gs->curmask, dcol, drow)) {
1352 	retmask |= MASK_TR;
1353 	npts++;
1354     }
1355 
1356     drow = VROW2DROW(gs, vrow + 1);
1357 
1358     if (BM_get(gs->curmask, dcol, drow)) {
1359 	retmask |= MASK_BR;
1360 	npts++;
1361     }
1362 
1363     dcol = VCOL2DCOL(gs, vcol);
1364 
1365     if (BM_get(gs->curmask, dcol, drow)) {
1366 	retmask |= MASK_BL;
1367 	npts++;
1368     }
1369 
1370     if (npts != 1) {
1371 	/* zero or masked */
1372 	return (retmask | npts);
1373     }
1374 
1375     p2[X] = VCOL2X(gs, vcol);
1376     p2[Y] = VROW2Y(gs, vrow + 1);
1377 
1378     switch (retmask) {
1379     case MASK_TL:
1380 	if ((pt[X] - p2[X]) / VXRES(gs) > (pt[Y] - p2[Y]) / VYRES(gs)) {
1381 	    /* lower triangle */
1382 	    return (0);
1383 	}
1384 
1385 	return (retmask | npts);
1386     case MASK_TR:
1387 
1388 	return (retmask | npts);
1389     case MASK_BR:
1390 	if ((pt[X] - p2[X]) / VXRES(gs) <= (pt[Y] - p2[Y]) / VYRES(gs)) {
1391 	    /* upper triangle */
1392 	    return (0);
1393 	}
1394 
1395 	return (retmask | npts);
1396     case MASK_BL:
1397 
1398 	return (retmask | npts);
1399     }
1400 
1401     /* Assume that if we get here it is an error */
1402     return (0);
1403 }
1404 
1405 /*!
1406    \brief Calculate distance on surface
1407 
1408    \param gs pointer to geosurf struct
1409    \param p1 from point
1410    \param p2 to point
1411    \param[out] dist distnace
1412    \param use_exag use exag for calculation
1413 
1414    \return 0 on error (points not in region)
1415    \return 1 on success
1416  */
gs_distance_onsurf(geosurf * gs,float * p1,float * p2,float * dist,int use_exag)1417 int gs_distance_onsurf(geosurf * gs, float *p1, float *p2, float *dist,
1418 		       int use_exag)
1419 {
1420     Point3 *tmp;
1421     int np, i;
1422     float exag, length;
1423 
1424     if (in_vregion(gs, p1) && in_vregion(gs, p2)) {
1425 	if (NULL == (tmp = gsdrape_get_segments(gs, p1, p2, &np))) {
1426 	    return (0);
1427 	}
1428 
1429 	length = 0.;
1430 
1431 	if (use_exag) {
1432 	    exag = GS_global_exag();
1433 	    tmp[0][Z] *= exag;
1434 
1435 	    for (i = 0; i < (np - 1); i++) {
1436 		tmp[i + 1][Z] *= exag;
1437 		length += GS_distance(tmp[i], tmp[i + 1]);
1438 	    }
1439 	}
1440 	else {
1441 	    for (i = 0; i < (np - 1); i++) {
1442 		length += GS_distance(tmp[i], tmp[i + 1]);
1443 	    }
1444 	}
1445 
1446 	*dist = length;
1447 
1448 	return (1);
1449     }
1450 
1451     return (0);
1452 }
1453