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