GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
GS2.c
Go to the documentation of this file.
1 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 
35 #include <grass/config.h>
36 
37 #if defined(OPENGL_X11) || defined(OPENGL_WINDOWS)
38 #include <GL/gl.h>
39 #include <GL/glu.h>
40 #elif defined(OPENGL_AQUA)
41 #include <OpenGL/gl.h>
42 #include <OpenGL/glu.h>
43 #endif
44 
45 #include <grass/gis.h>
46 #include <grass/gstypes.h>
47 #include <grass/glocale.h>
48 
49 #include "gsget.h"
50 #include "rowcol.h"
51 #include "rgbpack.h"
52 
53 /* Hack to make NVIZ2.2 query functions.("What's Here" and "Look at")
54  * to work.
55  * Uses gs_los_intersect1() instead of gs_los_intersect().
56  * Pierre de Mouveaux - 31 oct. 1999. p_de_mouveaux@hotmail.com.
57  */
58 #define NVIZ_HACK 1
59 
60 int gsd_getViewport(GLint *, GLint *);
61 
62 /* array of surface ids */
63 static int Surf_ID[MAX_SURFS];
64 static int Next_surf = 0;
65 static int SDref_surf = 0;
66 
67 /* attributes array */
68 static float Default_const[MAX_ATTS];
69 static float Default_nulls[MAX_ATTS];
70 
71 /* largest dimension */
72 static float Longdim;
73 
74 /* N, S, W, E */
75 static float Region[4];
76 static geoview Gv;
77 static geodisplay Gd;
78 static struct Cell_head wind;
79 static int Buffermode;
80 static int Numlights = 0;
81 static int Modelshowing = 0;
82 
83 void void_func(void)
84 {
85  return;
86 }
87 
95 void GS_libinit(void)
96 {
97  static int first = 1;
98 
99  G_get_set_window(&wind);
100 
101  Region[0] = wind.north;
102  Region[1] = wind.south;
103  Region[2] = wind.west;
104  Region[3] = wind.east;
105 
106  /* scale largest dimension to GS_UNIT_SIZE */
107  if ((wind.east - wind.west) > (wind.north - wind.south)) {
108  Longdim = (wind.east - wind.west);
109  }
110  else {
111  Longdim = (wind.north - wind.south);
112  }
113 
114  Gv.scale = GS_UNIT_SIZE / Longdim;
115 
118 
119  if (first) {
120  gs_init();
121  }
122 
123  first = 0;
124 
125  return;
126 }
127 
135 int GS_get_longdim(float *dim)
136 {
137  *dim = Longdim;
138 
139  G_debug(3, "GS_get_longdim(): dim=%g", *dim);
140 
141  return (1);
142 }
143 
151 int GS_get_region(float *n, float *s, float *w, float *e)
152 {
153  *n = Region[0];
154  *s = Region[1];
155  *w = Region[2];
156  *e = Region[3];
157 
158  return (1);
159 }
160 
167 void GS_set_att_defaults(float *defs, float *null_defs)
168 {
169  int i;
170 
171  G_debug(3, "GS_set_att_defaults");
172 
173  for (i = 0; i < MAX_ATTS; i++) {
174  Default_const[i] = defs[i];
175  Default_nulls[i] = null_defs[i];
176  }
177 
178  return;
179 }
180 
189 int GS_surf_exists(int id)
190 {
191  int i, found = 0;
192 
193  G_debug(3, "GS_surf_exists(): id=%d", id);
194 
195 
196  if (NULL == gs_get_surf(id)) {
197  return (0);
198  }
199 
200  for (i = 0; i < Next_surf && !found; i++) {
201  if (Surf_ID[i] == id) {
202  found = 1;
203  }
204  }
205 
206  return (found);
207 }
208 
219 int GS_new_surface(void)
220 {
221  geosurf *ns;
222 
223  G_debug(3, "GS_new_surface():");
224 
225  if (Next_surf < MAX_SURFS) {
226  ns = gs_get_new_surface();
227  gs_init_surf(ns, wind.west + wind.ew_res / 2.,
228  wind.south + wind.ns_res / 2., wind.rows, wind.cols,
229  wind.ew_res, wind.ns_res);
230  gs_set_defaults(ns, Default_const, Default_nulls);
231 
232  /* make default shine current */
233  gs_set_att_src(ns, ATT_SHINE, CONST_ATT);
234 
235  Surf_ID[Next_surf] = ns->gsurf_id;
236  ++Next_surf;
237 
238  G_debug(3, " id=%d", ns->gsurf_id);
239 
240  return (ns->gsurf_id);
241  }
242 
243 
244 
245  return (-1);
246 }
247 
254 int GS_new_light(void)
255 {
256  static int first = 1;
257  int i;
258 
259  if (first) {
260  first = 0;
261 
262  for (i = 0; i < MAX_LIGHTS; i++) {
263  Gv.lights[i].position[X] = Gv.lights[i].position[Y] = 0.0;
264  Gv.lights[i].position[Z] = 1.0;
265  Gv.lights[i].position[W] = 0.0; /* infinite */
266  Gv.lights[i].color[0] = Gv.lights[i].color[1] =
267  Gv.lights[i].color[2] = 1.0;
268  Gv.lights[i].ambient[0] = Gv.lights[i].ambient[1] =
269  Gv.lights[i].ambient[2] = 0.2;
270  Gv.lights[i].shine = 32.0;
271  }
272 
274  }
275 
276  if (Numlights < MAX_LIGHTS) {
277  gsd_deflight(Numlights + 1, &(Gv.lights[Numlights]));
278  gsd_switchlight(Numlights + 1, 1);
279 
280  return (++Numlights);
281  }
282 
283  return (-1);
284 }
285 
295 void GS_setlight_position(int num, float xpos, float ypos, float zpos,
296  int local)
297 {
298  if (num) {
299  num -= 1;
300  if (num < Numlights) {
301  Gv.lights[num].position[X] = xpos;
302  Gv.lights[num].position[Y] = ypos;
303  Gv.lights[num].position[Z] = zpos;
304  Gv.lights[num].position[W] = (float)local;
305 
306  gsd_deflight(num + 1, &(Gv.lights[num]));
307  }
308  }
309 
310  return;
311 }
312 
313 
321 void GS_getlight_position(int num, float *xpos, float *ypos, float *zpos,
322  int *local)
323 {
324  if (num) {
325  num -= 1;
326  if (num < Numlights) {
327  *xpos = Gv.lights[num].position[X];
328  *ypos = Gv.lights[num].position[Y];
329  *zpos = Gv.lights[num].position[Z];
330  *local = (int)Gv.lights[num].position[W];
331 
332  }
333  }
334 
335  return;
336 }
337 
344 void GS_setlight_color(int num, float red, float green, float blue)
345 {
346  if (num) {
347  num -= 1;
348  if (num < Numlights) {
349  Gv.lights[num].color[0] = red;
350  Gv.lights[num].color[1] = green;
351  Gv.lights[num].color[2] = blue;
352 
353  gsd_deflight(num + 1, &(Gv.lights[num]));
354  }
355  }
356 
357  return;
358 }
359 
366 void GS_getlight_color(int num, float *red, float *green, float *blue)
367 {
368  if (num) {
369  num -= 1;
370  if (num < Numlights) {
371  *red = Gv.lights[num].color[0];
372  *green = Gv.lights[num].color[1];
373  *blue = Gv.lights[num].color[2];
374  }
375  }
376 
377  return;
378 }
379 
388 void GS_setlight_ambient(int num, float red, float green, float blue)
389 {
390  if (num) {
391  num -= 1;
392  if (num < Numlights) {
393  Gv.lights[num].ambient[0] = red;
394  Gv.lights[num].ambient[1] = green;
395  Gv.lights[num].ambient[2] = blue;
396 
397  gsd_deflight(num + 1, &(Gv.lights[num]));
398  }
399  }
400 
401  return;
402 }
403 
410 void GS_getlight_ambient(int num, float *red, float *green, float *blue)
411 {
412  if (num) {
413  num -= 1;
414  if (num < Numlights) {
415  *red = Gv.lights[num].ambient[0];
416  *green = Gv.lights[num].ambient[1];
417  *blue = Gv.lights[num].ambient[2];
418  }
419  }
420 
421  return;
422 }
423 
424 
428 void GS_lights_off(void)
429 {
430  int i;
431 
432  for (i = 0; i < Numlights; i++) {
433  gsd_switchlight(i + 1, 0);
434  }
435 
436  return;
437 }
438 
442 void GS_lights_on(void)
443 {
444  int i;
445 
446  for (i = 0; i < Numlights; i++) {
447  gsd_switchlight(i + 1, 1);
448  }
449 
450  return;
451 }
452 
459 void GS_switchlight(int num, int on)
460 {
461  if (num) {
462  num -= 1;
463 
464  if (num < Numlights) {
465  gsd_switchlight(num + 1, on);
466  }
467  }
468 
469  return;
470 }
471 
479 {
480  return (gs_att_is_set(NULL, ATT_TRANSP) || (FC_GREY == gsd_getfc()));
481 }
482 
488 void GS_get_modelposition1(float pos[])
489 {
490  /* TODO: Still needs work to handle other cases */
491  /* this is a quick hack to get lighting adjustments debugged */
492  /*
493  GS_v3dir(Gv.from_to[FROM], Gv.from_to[TO], center);
494  GS_v3mult(center, 1000);
495  GS_v3add(center, Gv.from_to[FROM]);
496  */
497 
498  gs_get_datacenter(pos);
499  gs_get_data_avg_zmax(&(pos[Z]));
500 
501  G_debug(1, "GS_get_modelposition1(): model position: %f %f %f",
502  pos[X], pos[Y], pos[Z]);
503 
504  return;
505 }
506 
517 void GS_get_modelposition(float *siz, float *pos)
518 {
519  float dist, near_h, dir[3];
520 
521  dist = 2. * Gd.nearclip;
522 
523  near_h = 2.0 * tan(4.0 * atan(1.) * Gv.fov / 3600.) * dist;
524  *siz = near_h / 8.0;
525 
526  /* prevent clipping - would only happen if fov > ~127 degrees, at
527  fov = 2.0 * atan(2.0) */
528 
529  if (*siz > Gd.nearclip) {
530  *siz = Gd.nearclip;
531  }
532 
533  GS_v3dir(Gv.from_to[FROM], Gv.from_to[TO], dir);
534 
535  pos[X] = Gv.from_to[FROM][X] + dir[X] * dist;
536  pos[Y] = Gv.from_to[FROM][Y] + dir[Y] * dist;
537  pos[Z] = Gv.from_to[FROM][Z] + dir[Z] * dist;
538 
539  return;
540 }
541 
542 
554 void GS_set_Narrow(int *pt, int id, float *pos2)
555 {
556  geosurf *gs;
557  float x, y, z;
558  GLdouble modelMatrix[16], projMatrix[16];
559  GLint viewport[4];
560 
561  if (GS_get_selected_point_on_surface(pt[X], pt[Y], &id, &x, &y, &z)) {
562  gs = gs_get_surf(id);
563  if (gs) {
564  z = gs->zmax;
565  pos2[X] = (float)x - gs->ox + gs->x_trans;
566  pos2[Y] = (float)y - gs->oy + gs->y_trans;
567  pos2[Z] = (float)z + gs->z_trans;
568 
569  return;
570  }
571  }
572  else {
573  gs = gs_get_surf(id);
574 
575  /* Need to get model matrix, etc
576  * to run gluUnProject
577  */
578  gsd_pushmatrix();
579  gsd_do_scale(1);
580  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
581  glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
582  glGetIntegerv(GL_VIEWPORT, viewport);
583 
584  if (gs) {
585  GLdouble out_near[3], out_far[3];
586  GLdouble factor;
587  GLdouble out[3];
588 
589  z = (float)gs->zmax + gs->z_trans;
590 
591  gluUnProject((GLdouble) pt[X], (GLdouble) pt[Y], (GLdouble) 0.,
592  modelMatrix, projMatrix, viewport,
593  &out_near[X], &out_near[Y], &out_near[Z]);
594  gluUnProject((GLdouble) pt[X], (GLdouble) pt[Y], (GLdouble) 1.,
595  modelMatrix, projMatrix, viewport,
596  &out_far[X], &out_far[Y], &out_far[Z]);
597 
598  glPopMatrix();
599 
600  factor = (out_near[Z] - z) / (out_near[Z] - out_far[Z]);
601 
602  out[X] = out_near[X] - ((out_near[X] - out_far[X]) * factor);
603  out[Y] = out_near[Y] - ((out_near[Y] - out_far[Y]) * factor);
604  out[Z] = z;
605 
606  pos2[X] = (float)out[X];
607  pos2[Y] = (float)out[Y];
608  pos2[Z] = (float)out[Z];
609 
610  return;
611 
612  }
613  }
614  return;
615 }
616 
623 void GS_draw_X(int id, float *pt)
624 {
625  geosurf *gs;
626  Point3 pos;
627  float siz;
628 
629  if ((gs = gs_get_surf(id))) {
630  GS_get_longdim(&siz);
631  siz /= 200.;
632  pos[X] = pt[X] - gs->ox;
633  pos[Y] = pt[Y] - gs->oy;
634  _viewcell_tri_interp(gs, pos);
635 
636  gsd_pushmatrix();
637 
638  gsd_do_scale(1);
639  gsd_translate(gs->x_trans, gs->y_trans, gs->z_trans);
640  gsd_linewidth(1);
641 
642  if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) {
643  pos[Z] = gs->att[ATT_TOPO].constant;
644  gs = NULL; /* tells gpd_obj to use given Z val */
645  }
646 
647  gpd_obj(gs, Gd.bgcol, siz, ST_GYRO, pos);
648  gsd_flush();
649 
650  gsd_popmatrix();
651  }
652 
653  return;
654 }
655 
662 void GS_draw_line_onsurf(int id, float x1, float y1, float x2, float y2)
663 {
664  float p1[2], p2[2];
665  geosurf *gs;
666 
667  if ((gs = gs_get_surf(id))) {
668  p1[X] = x1 - gs->ox;
669  p1[Y] = y1 - gs->oy;
670  p2[X] = x2 - gs->ox;
671  p2[Y] = y2 - gs->oy;
672 
673  gsd_pushmatrix();
674 
675  gsd_do_scale(1);
676  gsd_translate(gs->x_trans, gs->y_trans, gs->z_trans);
677  gsd_linewidth(1);
678 
680  gsd_line_onsurf(gs, p1, p2);
681 
682  gsd_popmatrix();
683  gsd_flush();
684  }
685 
686  return;
687 }
688 
701 int GS_draw_nline_onsurf(int id, float x1, float y1, float x2, float y2,
702  float *lasp, int n)
703 {
704  float p1[2], p2[2];
705  geosurf *gs;
706  int ret = 0;
707 
708  if ((gs = gs_get_surf(id))) {
709  p1[X] = x1 - gs->ox;
710  p1[Y] = y1 - gs->oy;
711  p2[X] = x2 - gs->ox;
712  p2[Y] = y2 - gs->oy;
713 
714  gsd_pushmatrix();
715 
716  gsd_do_scale(1);
717  gsd_translate(gs->x_trans, gs->y_trans, gs->z_trans);
718  gsd_linewidth(1);
720  ret = gsd_nline_onsurf(gs, p1, p2, lasp, n);
721  gsd_surf2real(gs, lasp);
722 
723  gsd_popmatrix();
724  gsd_flush();
725  }
726 
727  return (ret);
728 }
729 
739 void GS_draw_flowline_at_xy(int id, float x, float y)
740 {
741  geosurf *gs;
742  float nv[3], pdir[2], mult;
743  float p1[2], p2[2], next[2];
744  int i = 0;
745 
746  if ((gs = gs_get_surf(id))) {
747  p1[X] = x;
748  p1[Y] = y;
749  /* multiply by 1.5 resolutions to ensure a crossing ? */
750  mult = .1 * (VXRES(gs) > VYRES(gs) ? VXRES(gs) : VYRES(gs));
751 
752  GS_coordpair_repeats(p1, p1, 50);
753 
754  while (1 == GS_get_norm_at_xy(id, p1[X], p1[Y], nv)) {
755  if (nv[Z] == 1.0) {
756  if (pdir[X] == 0.0 && pdir[Y] == 0.0) {
757  break;
758  }
759 
760  p2[X] = p1[X] + (pdir[X] * mult);
761  p2[Y] = p1[Y] + (pdir[Y] * mult);
762  }
763  else {
764  /* use previous direction */
765  GS_v2norm(nv);
766  p2[X] = p1[X] + (nv[X] * mult);
767  p2[Y] = p1[Y] + (nv[Y] * mult);
768  pdir[X] = nv[X];
769  pdir[Y] = nv[Y];
770  }
771 
772  if (i > 2000) {
773  break;
774  }
775 
776  if (GS_coordpair_repeats(p1, p2, 0)) {
777  break;
778  }
779 
780  /* Think about this: */
781  /* degenerate line means edge or level edge ? */
782  /* next is filled with last point drawn */
783  if (2 > GS_draw_nline_onsurf(id, p1[X], p1[Y],
784  p2[X], p2[Y], next, 3)) {
785  break;
786  }
787 
788  p1[X] = next[X];
789  p1[Y] = next[Y];
790  }
791 
792  G_debug(3, "GS_draw_flowline_at_xy(): dir: %f %f", nv[X], nv[Y]);
793  }
794 
795  return;
796 }
797 
806 void GS_draw_fringe(int id, unsigned long clr, float elev, int *where)
807 {
808  geosurf *gs;
809 
810  G_debug(3, "GS_draw_fringe(): id: %d clr: %ld elev %f edges: %d %d %d %d",
811  id, clr, elev, where[0], where[1], where[2], where[3]);
812  if ((gs = gs_get_surf(id)))
813  gsd_display_fringe(gs, clr, elev, where);
814 
815 }
816 
817 
831 int GS_draw_legend(const char *name, GLuint fontbase, int size, int *flags,
832  float *range, int *pt)
833 {
834  int list_no;
835 
836  list_no = gsd_put_legend(name, fontbase, size, flags, range, pt);
837 
838  return (list_no);
839 }
840 
849 void GS_draw_list(GLuint list_id)
850 {
851  gsd_calllist(list_id);
852  glFlush();
853  return;
854 }
855 
863 {
864  gsd_calllists(0); /* not sure if 0 is right - MN */
865  glFlush();
866  return;
867 }
868 
874 void GS_delete_list(GLuint list_id)
875 {
876  gsd_deletelist(list_id, 1);
877 
878  return;
879 }
880 
885 {
886  static float center[3];
887  float tcenter[3];
888 
889  if (!Modelshowing) {
890  GS_get_modelposition1(center);
891  }
892 
893  GS_v3eq(tcenter, center);
894 
895  gsd_zwritemask(0x0);
896  gsd_backface(1);
897 
898  gsd_colormode(CM_AD);
899  gsd_shademodel(DM_GOURAUD);
900  gsd_pushmatrix();
901  gsd_do_scale(1);
902 
903  if (Gv.vert_exag) {
904  tcenter[Z] *= Gv.vert_exag;
905  gsd_scale(1.0, 1.0, 1. / Gv.vert_exag);
906  }
907 
908  gsd_drawsphere(tcenter, 0xDDDDDD, (float)(Longdim / 10.));
909  gsd_popmatrix();
910  Modelshowing = 1;
911 
912  gsd_backface(0);
913  gsd_zwritemask(0xffffffff);
914 
915  return;
916 }
917 
925 {
926  static float center[3], size;
927  float tcenter[3], tsize;
928  int i, wason[MAX_CPLANES];
929 
930  gsd_get_cplanes_state(wason);
931 
932  for (i = 0; i < MAX_CPLANES; i++) {
933  if (wason[i]) {
934  gsd_cplane_off(i);
935  }
936  }
937 
938 
939  if (!Modelshowing) {
940  GS_get_modelposition(&size, center);
941  }
942 
943  GS_v3eq(tcenter, center);
944  tsize = size;
945 
946  gsd_zwritemask(0x0);
947  gsd_backface(1);
948 
949  gsd_colormode(CM_DIFFUSE);
950  gsd_shademodel(DM_GOURAUD);
951  gsd_pushmatrix();
952  gsd_drawsphere(tcenter, 0xDDDDDD, tsize);
953  gsd_popmatrix();
954  Modelshowing = 1;
955 
956  gsd_backface(0);
957  gsd_zwritemask(0xffffffff);
958 
959  for (i = 0; i < MAX_CPLANES; i++) {
960  if (wason[i]) {
961  gsd_cplane_on(i);
962  }
963  }
964 
965  gsd_flush();
966 
967  return;
968 }
969 
980 int GS_update_curmask(int id)
981 {
982  geosurf *gs;
983 
984  gs = gs_get_surf(id);
985  return (gs_update_curmask(gs));
986 }
987 
998 int GS_is_masked(int id, float *pt)
999 {
1000  geosurf *gs;
1001  Point3 tmp;
1002 
1003  if ((gs = gs_get_surf(id))) {
1004  tmp[X] = pt[X] - gs->ox;
1005  tmp[Y] = pt[Y] - gs->oy;
1006 
1007  return (gs_point_is_masked(gs, tmp));
1008  }
1009 
1010  return (-1);
1011 }
1012 
1017 {
1019  SDref_surf = 0;
1020 
1021  return;
1022 }
1023 
1032 int GS_set_SDsurf(int id)
1033 {
1034  geosurf *gs;
1035 
1036  if ((gs = gs_get_surf(id))) {
1037  gsdiff_set_SDref(gs);
1038  SDref_surf = id;
1039 
1040  return (1);
1041  }
1042 
1043  return (0);
1044 }
1045 
1053 int GS_set_SDscale(float scale)
1054 {
1055  gsdiff_set_SDscale(scale);
1056 
1057  return (1);
1058 }
1059 
1068 int GS_get_SDsurf(int *id)
1069 {
1070  geosurf *gs;
1071 
1072  if ((gs = gsdiff_get_SDref())) {
1073  *id = SDref_surf;
1074 
1075  return (1);
1076  }
1077 
1078  return (0);
1079 }
1080 
1088 int GS_get_SDscale(float *scale)
1089 {
1090  *scale = gsdiff_get_SDscale();
1091 
1092  return (1);
1093 }
1094 
1103 {
1104  geosurf *gs;
1105 
1106  gs = gs_get_surf(id);
1107 
1108  return (gs_calc_normals(gs));
1109 }
1110 
1123 int GS_get_att(int id, int att, int *set, float *constant, char *mapname)
1124 {
1125  int src;
1126  geosurf *gs;
1127 
1128  gs = gs_get_surf(id);
1129  if (gs) {
1130  if (-1 != (src = gs_get_att_src(gs, att))) {
1131  *set = src;
1132 
1133  if (src == CONST_ATT) {
1134  *constant = gs->att[att].constant;
1135  }
1136  else if (src == MAP_ATT) {
1137  strcpy(mapname, gsds_get_name(gs->att[att].hdata));
1138  }
1139 
1140  return (1);
1141  }
1142 
1143  return (-1);
1144  }
1145 
1146  return (-1);
1147 }
1148 
1166 int GS_get_cat_at_xy(int id, int att, char *catstr, float x, float y)
1167 {
1168  int offset, drow, dcol, vrow, vcol;
1169  float ftmp, pt[3];
1170  typbuff *buff;
1171  geosurf *gs;
1172 
1173  *catstr = '\0';
1174  gs = gs_get_surf(id);
1175 
1176  if (NULL == gs) {
1177  return -1;
1178  }
1179 
1180  pt[X] = x;
1181  pt[Y] = y;
1182 
1183  gsd_real2surf(gs, pt);
1184  if (gs_point_is_masked(gs, pt)) {
1185  return -1;
1186  }
1187 
1188  if (!in_vregion(gs, pt)) {
1189  return -1;
1190  }
1191 
1192  if (MAP_ATT != gs_get_att_src(gs, att)) {
1193  sprintf(catstr, _("no category info"));
1194  return -1;
1195  }
1196 
1197  buff = gs_get_att_typbuff(gs, att, 0);
1198 
1199  vrow = Y2VROW(gs, pt[Y]);
1200  vcol = X2VCOL(gs, pt[X]);
1201  drow = VROW2DROW(gs, vrow);
1202  dcol = VCOL2DCOL(gs, vcol);
1203 
1204  offset = DRC2OFF(gs, drow, dcol);
1205 
1206  if (GET_MAPATT(buff, offset, ftmp)) {
1207  return
1208  (Gs_get_cat_label(gsds_get_name(gs->att[att].hdata),
1209  drow, dcol, catstr));
1210  }
1211 
1212  sprintf(catstr, _("no data"));
1213 
1214  return 1;
1215 }
1216 
1229 int GS_get_norm_at_xy(int id, float x, float y, float *nv)
1230 {
1231  int offset, drow, dcol, vrow, vcol;
1232  float pt[3];
1233  geosurf *gs;
1234 
1235  gs = gs_get_surf(id);
1236 
1237  if (NULL == gs) {
1238  return (-1);
1239  }
1240 
1241  if (gs->norm_needupdate) {
1242  gs_calc_normals(gs);
1243  }
1244 
1245  pt[X] = x;
1246  pt[Y] = y;
1247 
1248  gsd_real2surf(gs, pt);
1249  if (gs_point_is_masked(gs, pt)) {
1250  return (-1);
1251  }
1252 
1253  if (!in_vregion(gs, pt)) {
1254  return (-1);
1255  }
1256 
1257  vrow = Y2VROW(gs, pt[Y]);
1258  vcol = X2VCOL(gs, pt[X]);
1259  drow = VROW2DROW(gs, vrow);
1260  dcol = VCOL2DCOL(gs, vcol);
1261 
1262  offset = DRC2OFF(gs, drow, dcol);
1263 
1264  if (gs->norms) {
1265  FNORM(gs->norms[offset], nv);
1266  }
1267  else {
1268  /* otherwise must be a constant */
1269  nv[0] = 0.0;
1270  nv[1] = 0.0;
1271  nv[2] = 1.0;
1272  }
1273 
1274  return (1);
1275 }
1276 
1293 int GS_get_val_at_xy(int id, int att, char *valstr, float x, float y)
1294 {
1295  int offset, drow, dcol, vrow, vcol;
1296  float ftmp, pt[3];
1297  typbuff *buff;
1298  geosurf *gs;
1299 
1300  *valstr = '\0';
1301  gs = gs_get_surf(id);
1302 
1303  if (NULL == gs) {
1304  return -1;
1305  }
1306 
1307  pt[X] = x;
1308  pt[Y] = y;
1309 
1310  gsd_real2surf(gs, pt);
1311 
1312  if (gs_point_is_masked(gs, pt)) {
1313  return -1;
1314  }
1315 
1316  if (!in_vregion(gs, pt)) {
1317  return (-1);
1318  }
1319 
1320  if (CONST_ATT == gs_get_att_src(gs, att)) {
1321  if (att == ATT_COLOR) {
1322  int r, g, b, i;
1323 
1324  i = gs->att[att].constant;
1325  sprintf(valstr, "R%d G%d B%d",
1326  INT_TO_RED(i, r), INT_TO_GRN(i, g), INT_TO_BLU(i, b));
1327  }
1328  else {
1329  sprintf(valstr, "%f", gs->att[att].constant);
1330  }
1331 
1332  return 1;
1333  }
1334  else if (MAP_ATT != gs_get_att_src(gs, att)) {
1335  return -1;
1336  }
1337 
1338  buff = gs_get_att_typbuff(gs, att, 0);
1339 
1340  vrow = Y2VROW(gs, pt[Y]);
1341  vcol = X2VCOL(gs, pt[X]);
1342  drow = VROW2DROW(gs, vrow);
1343  dcol = VCOL2DCOL(gs, vcol);
1344 
1345  offset = DRC2OFF(gs, drow, dcol);
1346 
1347  if (GET_MAPATT(buff, offset, ftmp)) {
1348  if (att == ATT_COLOR) {
1349  int r, g, b, i;
1350 
1351  i = gs_mapcolor(gs_get_att_typbuff(gs, ATT_COLOR, 0),
1352  &(gs->att[ATT_COLOR]), offset);
1353  sprintf(valstr, "R%d G%d B%d",
1354  INT_TO_RED(i, r), INT_TO_GRN(i, g), INT_TO_BLU(i, b));
1355  }
1356  else {
1357  sprintf(valstr, "%f", ftmp);
1358  }
1359 
1360  return (1);
1361  }
1362 
1363  sprintf(valstr, "NULL");
1364 
1365  return (1);
1366 }
1367 
1376 int GS_unset_att(int id, int att)
1377 {
1378  geosurf *gs;
1379 
1380  gs = gs_get_surf(id);
1381  gs->mask_needupdate = 1;
1382 
1383  return (gs_set_att_src(gs, att, NOTSET_ATT));
1384 }
1385 
1395 int GS_set_att_const(int id, int att, float constant)
1396 {
1397  geosurf *gs;
1398  int ret;
1399 
1400  gs = gs_get_surf(id);
1401  ret = (gs_set_att_const(gs, att, constant));
1402 
1403  Gs_update_attrange(gs, att);
1404 
1405  return (ret);
1406 }
1407 
1419 int GS_set_maskmode(int id, int mode)
1420 {
1421  geosurf *gs;
1422 
1423  gs = gs_get_surf(id);
1424 
1425  if (gs) {
1426  gs->att[ATT_MASK].constant = mode;
1427  gs->mask_needupdate = 1;
1428 
1429  return (mode);
1430  }
1431 
1432  return (-1);
1433 }
1434 
1444 int GS_get_maskmode(int id, int *mode)
1445 {
1446  geosurf *gs;
1447 
1448  gs = gs_get_surf(id);
1449 
1450  if (gs) {
1451  *mode = gs->att[ATT_MASK].constant;
1452 
1453  return (1);
1454  }
1455 
1456  return (-1);
1457 }
1458 
1468 int GS_Set_ClientData(int id, void *clientd)
1469 {
1470  geosurf *gs;
1471 
1472  gs = gs_get_surf(id);
1473  if (gs) {
1474  gs->clientdata = clientd;
1475 
1476  return (1);
1477  }
1478 
1479  return (-1);
1480 }
1481 
1490 void *GS_Get_ClientData(int id)
1491 {
1492  geosurf *gs;
1493 
1494  gs = gs_get_surf(id);
1495  if (gs) {
1496  return (gs->clientdata);
1497  }
1498 
1499  return (NULL);
1500 }
1501 
1507 int GS_num_surfs(void)
1508 {
1509  return (gs_num_surfaces());
1510 }
1511 
1522 int *GS_get_surf_list(int *numsurfs)
1523 {
1524  int i, *ret;
1525 
1526  *numsurfs = Next_surf;
1527 
1528  if (Next_surf) {
1529  ret = (int *)G_malloc(Next_surf * sizeof(int));
1530 
1531  for (i = 0; i < Next_surf; i++) {
1532  ret[i] = Surf_ID[i];
1533  }
1534 
1535  return (ret);
1536  }
1537 
1538  return (NULL);
1539 }
1540 
1550 {
1551  int i, j, found = 0;
1552 
1553  G_debug(3, "GS_delete_surface");
1554 
1555  if (GS_surf_exists(id)) {
1556  gs_delete_surf(id);
1557 
1558  for (i = 0; i < Next_surf && !found; i++) {
1559  if (Surf_ID[i] == id) {
1560  found = 1;
1561 
1562  for (j = i; j < Next_surf; j++) {
1563  Surf_ID[j] = Surf_ID[j + 1];
1564  }
1565  }
1566  }
1567 
1569 
1570  if (found) {
1571  --Next_surf;
1572  return (1);
1573  }
1574  }
1575 
1576  return (-1);
1577 }
1578 
1579 
1590 int GS_load_att_map(int id, const char *filename, int att)
1591 {
1592  geosurf *gs;
1593  unsigned int changed;
1594  unsigned int atty;
1595  const char *mapset;
1596  struct Cell_head rast_head;
1597  int reuse, begin, hdata, ret, neg, has_null;
1598  typbuff *tbuff;
1599 
1600  G_debug(3, "GS_load_att_map(): map=%s", filename);
1601 
1602  reuse = ret = neg = has_null = 0;
1603  gs = gs_get_surf(id);
1604 
1605  if (NULL == gs) {
1606  return -1;
1607  }
1608 
1609  gs->mask_needupdate = (ATT_MASK == att || ATT_TOPO == att ||
1610  (gs->nz_topo && ATT_TOPO == att) ||
1611  (gs->nz_color && ATT_COLOR == att));
1612 
1613  gs_set_att_src(gs, att, MAP_ATT);
1614 
1615  /* Check against maps already loaded in memory */
1616  /* if to be color attribute:
1617  - if packed color for another surface, OK to reuse
1618  - if unchanged, ok to reuse IF it's of type char (will have lookup)
1619  */
1620  begin = hdata = 1;
1621 
1622  /* Get MAPSET to ensure names are fully qualified */
1623  mapset = G_find_cell2(filename, "");
1624  if (mapset == NULL) {
1625  /* Check for valid filename */
1626  G_warning("Raster map <%s> not found", filename);
1627  return -1;
1628  }
1629 
1630  /* Check to see if map is in Region */
1631  G_get_cellhd(filename, mapset, &rast_head);
1632  if (rast_head.north <= wind.south ||
1633  rast_head.south >= wind.north ||
1634  rast_head.east <= wind.west || rast_head.west >= wind.east) {
1635 
1636  G_warning(_("Raster map <%s> is outside of current region. Load failed."),
1637  G_fully_qualified_name(filename, mapset));
1638  }
1639 
1640  while (!reuse && (0 < hdata)) {
1641  changed = CF_COLOR_PACKED;
1642  atty = ATTY_FLOAT | ATTY_CHAR | ATTY_INT | ATTY_SHORT | ATTY_MASK;
1643 
1644  if (0 < (hdata = gsds_findh(filename, &changed, &atty, begin))) {
1645 
1646  G_debug(3, "GS_load_att_map(): %s already has data handle %d.CF=%x",
1647  filename, hdata, changed);
1648 
1649  /* handle found */
1650  if (ATT_COLOR == att) {
1651  if ((changed == CF_COLOR_PACKED) ||
1652  (!changed && atty == ATTY_CHAR)) {
1653  reuse = 1;
1654  }
1655  }
1656  else if (atty == ATTY_MASK && att != ATT_MASK) {
1657  reuse = 0;
1658  /* should also free mask data & share new - but need backward
1659  reference? */
1660  }
1661  else if (!changed) {
1662  reuse = 1;
1663  }
1664  }
1665 
1666  begin = 0;
1667  }
1668 
1669  if (reuse) {
1670  gs->att[att].hdata = hdata;
1671  gs_set_att_type(gs, att, atty); /* ?? */
1672 
1673  /* free lookup & set to NULL! */
1674  if (atty == ATTY_INT) {
1675  if (gs->att[att].lookup) {
1676  free(gs->att[att].lookup);
1677  gs->att[att].lookup = NULL;
1678  }
1679  }
1680  /* TODO: FIX THIS stuff with lookup sharing! */
1681 
1682  G_debug(3, "GS_load_att_map(): %s is being reused. hdata=%d",
1683  filename, hdata);
1684  }
1685  else {
1686  G_debug(3, "GS_load_att_map(): %s not loaded in correct form - loading now",
1687  filename);
1688 
1689  /* not loaded - need to get new dataset handle */
1690  gs->att[att].hdata = gsds_newh(filename);
1691 
1692  tbuff = gs_get_att_typbuff(gs, att, 1);
1693 
1694  /* TODO: Provide mechanism for loading certain attributes at
1695  specified sizes, allow to scale or cap, or scale non-zero */
1696  if (ATT_MASK == att) {
1697  atty = ATTY_MASK;
1698  }
1699  else {
1700  atty = Gs_numtype(filename, &neg);
1701  }
1702 
1703 #ifdef MAYBE_LATER
1704  if (att == ATT_COLOR && atty == ATTY_SHORT) {
1705  atty = (neg ? ATTY_INT : ATTY_SHORT);
1706  }
1707 #endif
1708 
1709  if (att == ATT_COLOR && atty == ATTY_SHORT) {
1710  atty = ATTY_INT;
1711  }
1712 
1713  if (0 > gs_malloc_att_buff(gs, att, ATTY_NULL)) {
1714  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1715  }
1716 
1717  switch (atty) {
1718  case ATTY_MASK:
1719  if (0 > gs_malloc_att_buff(gs, att, ATTY_MASK)) {
1720  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1721  }
1722 
1723  ret = Gs_loadmap_as_bitmap(&wind, filename, tbuff->bm);
1724 
1725  break;
1726  case ATTY_CHAR:
1727  if (0 > gs_malloc_att_buff(gs, att, ATTY_CHAR)) {
1728  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1729  }
1730 
1731  ret = Gs_loadmap_as_char(&wind, filename, tbuff->cb,
1732  tbuff->nm, &has_null);
1733 
1734  break;
1735  case ATTY_SHORT:
1736  if (0 > gs_malloc_att_buff(gs, att, ATTY_SHORT)) {
1737  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1738  }
1739 
1740  ret = Gs_loadmap_as_short(&wind, filename, tbuff->sb,
1741  tbuff->nm, &has_null);
1742  break;
1743  case ATTY_FLOAT:
1744  if (0 > gs_malloc_att_buff(gs, att, ATTY_FLOAT)) {
1745  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1746  }
1747 
1748  ret = Gs_loadmap_as_float(&wind, filename, tbuff->fb,
1749  tbuff->nm, &has_null);
1750 
1751  break;
1752  case ATTY_INT:
1753  default:
1754  if (0 > gs_malloc_att_buff(gs, att, ATTY_INT)) {
1755  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1756  }
1757 
1758  ret = Gs_loadmap_as_int(&wind, filename, tbuff->ib,
1759  tbuff->nm, &has_null);
1760  break;
1761 
1762  } /* Done with switch */
1763 
1764  if (ret == -1) {
1765  gsds_free_data_buff(gs->att[att].hdata, ATTY_NULL);
1766  return -1;
1767  }
1768 
1769  G_debug(4, " has_null=%d", has_null);
1770 
1771  if (!has_null) {
1772  gsds_free_data_buff(gs->att[att].hdata, ATTY_NULL);
1773  }
1774  else {
1775  gs_update_curmask(gs);
1776  }
1777 
1778  } /* end if not reuse */
1779 
1780  if (ATT_COLOR == att) {
1781 #ifdef MAYBE_LATER
1782  if (ATTY_INT == atty) {
1783  Gs_pack_colors(filename, tbuff->ib, gs->rows, gs->cols);
1784  gsds_set_changed(gs->att[att].hdata, CF_COLOR_PACKED);
1785  gs->att[att].lookup = NULL;
1786  }
1787  else {
1788  gs_malloc_lookup(gs, att);
1789  Gs_build_lookup(filename, gs->att[att].lookup);
1790  }
1791 #else
1792 
1793  if (ATTY_CHAR == atty) {
1794  if (!gs->att[att].lookup) {
1795  /* might already exist if reusing */
1796  gs_malloc_lookup(gs, att);
1797  Gs_build_256lookup(filename, gs->att[att].lookup);
1798  }
1799  }
1800  else if (ATTY_FLOAT == atty) {
1801  if (!reuse) {
1802  if (0 > gs_malloc_att_buff(gs, att, ATTY_INT)) {
1803  G_fatal_error(_("GS_load_att_map(): Out of memory. Unable to load map"));
1804  }
1805 
1806  Gs_pack_colors_float(filename, tbuff->fb, tbuff->ib,
1807  gs->rows, gs->cols);
1808  gsds_set_changed(gs->att[att].hdata, CF_COLOR_PACKED);
1809  gsds_free_data_buff(gs->att[att].hdata, ATTY_FLOAT);
1810  gs->att[att].lookup = NULL;
1811  }
1812  }
1813  else {
1814  if (!reuse) {
1815  Gs_pack_colors(filename, tbuff->ib, gs->rows, gs->cols);
1816  gsds_set_changed(gs->att[att].hdata, CF_COLOR_PACKED);
1817  gs->att[att].lookup = NULL;
1818  }
1819  }
1820 #endif
1821  }
1822 
1823  if (ATT_TOPO == att) {
1824  gs_init_normbuff(gs);
1825  /* S_DIFF: should also check here to see if this surface is a
1826  reference surface for scaled differences, if so update references
1827  to it */
1828  }
1829 
1830  if (ret < 0) {
1831  G_warning(_("Loading failed"));
1832  }
1833 
1834  if (-1 == Gs_update_attrange(gs, att)) {
1835  G_warning(_("Error finding range"));
1836  }
1837 
1838  return ret;
1839 }
1840 
1846 void GS_draw_surf(int id)
1847 {
1848  geosurf *gs;
1849 
1850  G_debug(3, "GS_draw_surf(): id=%d", id);
1851 
1852  gs = gs_get_surf(id);
1853  if (gs) {
1854  gsd_shademodel(gs->draw_mode & DM_GOURAUD);
1855 
1856  if (gs->draw_mode & DM_POLY) {
1857  gsd_surf(gs);
1858  }
1859 
1860  if (gs->draw_mode & DM_WIRE) {
1861  gsd_wire_surf(gs);
1862  }
1863 
1864  /* TODO: write wire/poly draw routines */
1865  if (gs->draw_mode & DM_WIRE_POLY) {
1866  gsd_surf(gs);
1867  gsd_wire_surf(gs);
1868  }
1869  }
1870 
1871  return;
1872 }
1873 
1881 void GS_draw_wire(int id)
1882 {
1883  geosurf *gs;
1884 
1885  G_debug(3, "GS_draw_wire(): id=%d", id);
1886 
1887  gs = gs_get_surf(id);
1888 
1889  if (gs) {
1890  gsd_wire_surf(gs);
1891  }
1892 
1893  return;
1894 }
1895 
1902 {
1903  geosurf *gs;
1904  int i;
1905 
1906  for (i = 0; i < Next_surf; i++) {
1907  if ((gs = gs_get_surf(Surf_ID[i]))) {
1908  gsd_wire_surf(gs);
1909  }
1910  }
1911 
1912  return;
1913 }
1914 
1919 {
1920  int i;
1921 
1922  for (i = 0; i < Next_surf; i++) {
1923  GS_draw_surf(Surf_ID[i]);
1924  }
1925 
1926  return;
1927 }
1928 
1935 void GS_set_exag(int id, float exag)
1936 {
1937  geosurf *gs;
1938 
1939  G_debug(3, "GS_set_exag");
1940 
1941  gs = gs_get_surf(id);
1942 
1943  if (gs) {
1944  if (gs->z_exag != exag) {
1945  gs->norm_needupdate = 1;
1946  }
1947 
1948  gs->z_exag = exag;
1949  }
1950 
1951  return;
1952 }
1953 
1959 void GS_set_global_exag(float exag)
1960 {
1961 
1962  G_debug(3, "GS_set_global_exag");
1963 
1964  Gv.vert_exag = exag;
1965  /* GL_NORMALIZE */
1966  /* Only need to update norms gs_norms.c
1967  * if exag is used in norm equation which
1968  * it is not! If GL_NORMALIZE is disabled
1969  * will need to include.
1970  gs_setall_norm_needupdate();
1971  */
1972 
1973  return;
1974 }
1975 
1981 float GS_global_exag(void)
1982 {
1983  G_debug(3, "GS_global_exag(): %g", Gv.vert_exag);
1984 
1985  return (Gv.vert_exag);
1986 }
1987 
1996 void GS_set_wire_color(int id, int colr)
1997 {
1998  geosurf *gs;
1999 
2000  G_debug(3, "GS_set_wire_color");
2001 
2002  gs = gs_get_surf(id);
2003 
2004  if (gs) {
2005  gs->wire_color = colr;
2006  }
2007 
2008  return;
2009 }
2010 
2020 int GS_get_wire_color(int id, int *colr)
2021 {
2022  geosurf *gs;
2023 
2024  gs = gs_get_surf(id);
2025 
2026  if (gs) {
2027  *colr = gs->wire_color;
2028 
2029  return (1);
2030  }
2031 
2032  return (-1);
2033 }
2034 
2043 int GS_setall_drawmode(int mode)
2044 {
2045  int i;
2046 
2047  for (i = 0; i < Next_surf; i++) {
2048  if (0 != GS_set_drawmode(Surf_ID[i], mode)) {
2049  return (-1);
2050  }
2051  }
2052 
2053  return (0);
2054 }
2055 
2065 int GS_set_drawmode(int id, int mode)
2066 {
2067  geosurf *gs;
2068 
2069  G_debug(3, "GS_set_drawmode(): id=%d mode=%d", id, mode);
2070 
2071  gs = gs_get_surf(id);
2072 
2073  if (gs) {
2074  gs->draw_mode = mode;
2075 
2076  return (0);
2077  }
2078 
2079  return (-1);
2080 }
2081 
2091 int GS_get_drawmode(int id, int *mode)
2092 {
2093  geosurf *gs;
2094 
2095  gs = gs_get_surf(id);
2096 
2097  if (gs) {
2098  *mode = gs->draw_mode;
2099 
2100  return (1);
2101  }
2102 
2103  return (-1);
2104 }
2105 
2113 void GS_set_nozero(int id, int att, int mode)
2114 {
2115  geosurf *gs;
2116 
2117  G_debug(3, "GS_set_nozero");
2118 
2119  gs = gs_get_surf(id);
2120 
2121  if (gs) {
2122  if (att == ATT_TOPO) {
2123  gs->nz_topo = mode;
2124  gs->mask_needupdate = 1;
2125  }
2126 
2127  if (att == ATT_COLOR) {
2128  gs->nz_color = mode;
2129  gs->mask_needupdate = 1;
2130  }
2131  }
2132 
2133  return;
2134 }
2135 
2146 int GS_get_nozero(int id, int att, int *mode)
2147 {
2148  geosurf *gs;
2149 
2150  G_debug(3, "GS_set_nozero");
2151 
2152  gs = gs_get_surf(id);
2153 
2154  if (gs) {
2155  if (att == ATT_TOPO) {
2156  *mode = gs->nz_topo;
2157  }
2158  else if (att == ATT_COLOR) {
2159  *mode = gs->nz_color;
2160  }
2161  else {
2162  return (-1);
2163  }
2164 
2165  return (1);
2166  }
2167 
2168  return (-1);
2169 }
2170 
2180 int GS_setall_drawres(int xres, int yres, int xwire, int ywire)
2181 {
2182  int i;
2183 
2184  for (i = 0; i < Next_surf; i++) {
2185  if (0 != GS_set_drawres(Surf_ID[i], xres, yres, xwire, ywire)) {
2186  return (-1);
2187  }
2188  }
2189 
2190  return (0);
2191 }
2192 
2203 int GS_set_drawres(int id, int xres, int yres, int xwire, int ywire)
2204 {
2205  geosurf *gs;
2206 
2207  G_debug(3, "GS_set_drawres() id=%d xyres=%d/%d xywire=%d/%d",
2208  id, xres, yres, xwire, ywire);
2209 
2210  if (xres < 1 || yres < 1 || xwire < 1 || ywire < 1) {
2211  return (-1);
2212  }
2213 
2214  gs = gs_get_surf(id);
2215 
2216  if (gs) {
2217  if (gs->x_mod != xres || gs->y_mod != yres) {
2218  gs->norm_needupdate = 1;
2219  }
2220 
2221  gs->x_mod = xres;
2222  gs->y_mod = yres;
2223  gs->x_modw = xwire;
2224  gs->y_modw = ywire;
2225  }
2226 
2227  return (0);
2228 }
2229 
2237 void GS_get_drawres(int id, int *xres, int *yres, int *xwire, int *ywire)
2238 {
2239  geosurf *gs;
2240 
2241  G_debug(3, "GS_get_drawres");
2242 
2243  gs = gs_get_surf(id);
2244 
2245  if (gs) {
2246  *xres = gs->x_mod;
2247  *yres = gs->y_mod;
2248  *xwire = gs->x_modw;
2249  *ywire = gs->y_modw;
2250  }
2251 
2252  return;
2253 }
2254 
2261 void GS_get_dims(int id, int *rows, int *cols)
2262 {
2263  geosurf *gs;
2264 
2265  gs = gs_get_surf(id);
2266 
2267  if (gs) {
2268  *rows = gs->rows;
2269  *cols = gs->cols;
2270  }
2271 
2272  return;
2273 }
2274 
2288 int GS_get_exag_guess(int id, float *exag)
2289 {
2290  geosurf *gs;
2291  float guess;
2292 
2293  gs = gs_get_surf(id);
2294  guess = 1.0;
2295 
2296  /* if gs is type const return guess = 1.0 */
2297  if (CONST_ATT == gs_get_att_src(gs, ATT_TOPO)) {
2298  return (1);
2299  }
2300 
2301  if (gs) {
2302  if (gs->zrange_nz == 0.0) {
2303  *exag = 0.0;
2304 
2305  return (1);
2306  }
2307 
2308  G_debug(3, "GS_get_exag_guess(): %f %f", gs->zrange_nz, Longdim);
2309 
2310  while (gs->zrange_nz * guess / Longdim >= .25) {
2311  guess *= .1;
2312 
2313  G_debug(3, "GS_get_exag_guess(): %f", guess);
2314  }
2315 
2316  while (gs->zrange_nz * guess / Longdim < .025) {
2317  guess *= 10.;
2318 
2319  G_debug(3, "GS_get_exag_guess(): %f", guess);
2320  }
2321 
2322  *exag = guess;
2323 
2324  return (1);
2325  }
2326 
2327  return (-1);
2328 }
2329 
2338 void GS_get_zrange_nz(float *min, float *max)
2339 {
2340  int i, first = 1;
2341  geosurf *gs;
2342 
2343  for (i = 0; i < Next_surf; i++) {
2344  if ((gs = gs_get_surf(Surf_ID[i]))) {
2345  if (first) {
2346  first = 0;
2347  *min = gs->zmin_nz;
2348  *max = gs->zmax_nz;
2349  }
2350 
2351  if (gs->zmin_nz < *min) {
2352  *min = gs->zmin_nz;
2353  }
2354 
2355  if (gs->zmax_nz > *max) {
2356  *max = gs->zmax_nz;
2357  }
2358  }
2359  }
2360 
2361  G_debug(3, "GS_get_zrange_nz(): min=%g max=%g", *min, *max);
2362 
2363  return;
2364 }
2365 
2372 void GS_set_trans(int id, float xtrans, float ytrans, float ztrans)
2373 {
2374  geosurf *gs;
2375 
2376  G_debug(3, "GS_set_trans");
2377 
2378  gs = gs_get_surf(id);
2379 
2380  if (gs) {
2381  gs->x_trans = xtrans;
2382  gs->y_trans = ytrans;
2383  gs->z_trans = ztrans;
2384  }
2385 
2386  return;
2387 }
2388 
2395 void GS_get_trans(int id, float *xtrans, float *ytrans, float *ztrans)
2396 {
2397  geosurf *gs;
2398 
2399  G_debug(3, "GS_get_trans");
2400 
2401  gs = gs_get_surf(id);
2402 
2403  if (gs) {
2404  *xtrans = gs->x_trans;
2405  *ytrans = gs->y_trans;
2406  *ztrans = gs->z_trans;
2407  }
2408 
2409  return;
2410 }
2411 
2412 
2418 unsigned int GS_default_draw_color(void)
2419 {
2420 
2421  G_debug(3, "GS_default_draw_color");
2422 
2423  return ((unsigned int)Gd.bgcol);
2424 }
2425 
2431 unsigned int GS_background_color(void)
2432 {
2433  return ((unsigned int)Gd.bgcol);
2434 }
2435 
2441 void GS_set_draw(int where)
2442 {
2443  Buffermode = where;
2444 
2445  switch (where) {
2446  case GSD_BOTH:
2447  gsd_frontbuffer(1);
2448  gsd_backbuffer(1);
2449 
2450  break;
2451  case GSD_FRONT:
2452  gsd_frontbuffer(1);
2453  gsd_backbuffer(0);
2454 
2455  break;
2456  case GSD_BACK:
2457  default:
2458  gsd_frontbuffer(0);
2459  gsd_backbuffer(1);
2460 
2461  break;
2462  }
2463 
2464  return;
2465 }
2466 
2467 /*
2468  \brief Ready to draw
2469  */
2470 void GS_ready_draw(void)
2471 {
2472 
2473  G_debug(3, "GS_ready_draw");
2474 
2475  gsd_set_view(&Gv, &Gd);
2476 
2477  return;
2478 }
2479 
2483 void GS_done_draw(void)
2484 {
2485 
2486  G_debug(3, "GS_done_draw");
2487 
2488  if (GSD_BACK == Buffermode) {
2489  gsd_swapbuffers();
2490  }
2491 
2492  gsd_flush();
2493 
2494  return;
2495 }
2496 
2502 void GS_set_focus(float *realto)
2503 {
2504 
2505  G_debug(3, "GS_set_focus(): %f,%f,%f", realto[0], realto[1], realto[2]);
2506 
2507  Gv.infocus = 1;
2508  GS_v3eq(Gv.real_to, realto);
2509 
2510  gsd_set_view(&Gv, &Gd);
2511 
2512  return;
2513 }
2514 
2520 void GS_set_focus_real(float *realto)
2521 {
2522 
2523  G_get_set_window(&wind);
2524  realto[X] = realto[X] - wind.west - (wind.ew_res / 2.);
2525  realto[Y] = realto[Y] - wind.south - (wind.ns_res / 2.);
2526 
2527  Gv.infocus = 1;
2528  GS_v3eq(Gv.real_to, realto);
2529 
2530  gsd_set_view(&Gv, &Gd);
2531 
2532  return;
2533 }
2534 
2535 
2545 int GS_get_focus(float *realto)
2546 {
2547 
2548  G_debug(3, "GS_get_focus");
2549 
2550  if (Gv.infocus) {
2551  if (realto) {
2552  GS_v3eq(realto, Gv.real_to);
2553  }
2554  }
2555 
2556  return (Gv.infocus);
2557 }
2558 
2565 {
2566  float center[3];
2567  geosurf *gs;
2568 
2569  G_debug(3, "GS_set_focus_center_map");
2570 
2571  gs = gs_get_surf(id);
2572 
2573  if (gs) {
2574  center[X] = (gs->xmax - gs->xmin) / 2.;
2575  center[Y] = (gs->ymax - gs->ymin) / 2.;
2576  center[Z] = (gs->zmax_nz + gs->zmin_nz) / 2.;
2577 
2578  /* not yet working
2579  buff = gs_get_att_typbuff(gs, ATT_TOPO, 0);
2580  offset = gs->rows*gs->cols/2 + gs->cols/2;
2581  if (buff)
2582  {
2583  if (GET_MAPATT(buff, offset, tmp))
2584  {
2585  center[Z] = tmp;
2586  }
2587  }
2588  */
2589 
2590  GS_set_focus(center);
2591  }
2592 }
2593 
2599 void GS_moveto(float *pt)
2600 {
2601  float ft[3];
2602 
2603  G_debug(3, "GS_moveto(): %f,%f,%f", pt[0], pt[1], pt[2]);
2604 
2605  if (Gv.infocus) {
2606  GS_v3eq(Gv.from_to[FROM], pt);
2607  /*
2608  GS_v3eq(Gv.from_to[TO], Gv.real_to);
2609  */
2610  GS_v3normalize(Gv.from_to[FROM], Gv.from_to[TO]);
2611  /* update inclination, look_dir if we're keeping these */
2612  }
2613  else {
2614  GS_v3eq(ft, Gv.from_to[TO]);
2615  GS_v3sub(ft, Gv.from_to[FROM]);
2616  GS_v3eq(Gv.from_to[FROM], pt);
2617  GS_v3eq(Gv.from_to[TO], pt);
2618  GS_v3add(Gv.from_to[TO], ft);
2619  }
2620 
2621  return;
2622 }
2623 
2629 void GS_moveto_real(float *pt)
2630 {
2631  gsd_real2model(pt);
2632  GS_moveto(pt);
2633 
2634  return;
2635 }
2636 
2648 int GS_get_zextents(int id, float *min, float *max, float *mid)
2649 {
2650  geosurf *gs;
2651 
2652  if (NULL == (gs = gs_get_surf(id))) {
2653  return (-1);
2654  }
2655 
2656  G_debug(3, "GS_get_zextents(): id=%d", id);
2657 
2658  return (gs_get_zextents(gs, min, max, mid));
2659 }
2660 
2671 int GS_get_zrange(float *min, float *max, int doexag)
2672 {
2673  int ret_surf, ret_vol;
2674  float surf_min, surf_max;
2675  float vol_min, vol_max;
2676 
2677  ret_surf = gs_get_zrange(&surf_min, &surf_max);
2678  ret_vol = gvl_get_zrange(&vol_min, &vol_max);
2679 
2680  if (ret_surf > 0 && ret_vol > 0) {
2681  *min = (surf_min < vol_min) ? surf_min : vol_min;
2682  *max = (surf_max < vol_max) ? surf_max : vol_max;
2683  }
2684  else if (ret_surf > 0) {
2685  *min = surf_min;
2686  *max = surf_max;
2687  }
2688  else if (ret_vol > 0) {
2689  *min = vol_min;
2690  *max = vol_max;
2691  }
2692 
2693  if (doexag) {
2694  *min *= Gv.vert_exag;
2695  *max *= Gv.vert_exag;
2696  }
2697 
2698  G_debug(3, "GS_get_zrange(): min=%g max=%g", *min, *max);
2699  return ((ret_surf > 0 || ret_vol > 0) ? (1) : (-1));
2700 }
2701 
2707 void GS_get_from(float *fr)
2708 {
2709  GS_v3eq(fr, Gv.from_to[FROM]);
2710 
2711  G_debug(3, "GS_get_from(): %f,%f,%f", fr[0], fr[1], fr[2]);
2712 
2713  return;
2714 }
2715 
2721 void GS_get_from_real(float *fr)
2722 {
2723  GS_v3eq(fr, Gv.from_to[FROM]);
2724  gsd_model2real(fr);
2725 
2726  return;
2727 }
2728 
2734 void GS_get_to_real(float *to)
2735 {
2736  float realto[3];
2737 
2738  G_get_set_window(&wind);
2739  GS_get_focus(realto);
2740  to[X] = realto[X] + wind.west + (wind.ew_res / 2.);
2741  to[Y] = realto[Y] + wind.south + (wind.ns_res / 2.);
2742  to[Z] = realto[Z];
2743 
2744  return;
2745 }
2746 
2747 
2754 void GS_zoom_setup(int *a, int *b, int *c, int *d, int *maxx, int *maxy)
2755 {
2756  GLint tmp[4];
2757  GLint num[2];
2758 
2759  gsd_getViewport(tmp, num);
2760  *a = tmp[0];
2761  *b = tmp[1];
2762  *c = tmp[2];
2763  *d = tmp[3];
2764  *maxx = num[0];
2765  *maxy = num[1];
2766 
2767  return;
2768 }
2769 
2777 void GS_get_to(float *to)
2778 {
2779  G_debug(3, "GS_get_to");
2780 
2781  GS_v3eq(to, Gv.from_to[TO]);
2782 
2783  return;
2784 }
2785 
2791 void GS_get_viewdir(float *dir)
2792 {
2793  GS_v3dir(Gv.from_to[FROM], Gv.from_to[TO], dir);
2794 
2795  return;
2796 }
2797 
2805 void GS_set_viewdir(float *dir)
2806 {
2807  float tmp[3];
2808 
2809  GS_v3eq(tmp, dir);
2810  GS_v3norm(tmp);
2811  GS_v3eq(Gv.from_to[TO], Gv.from_to[FROM]);
2812  GS_v3add(Gv.from_to[TO], tmp);
2813 
2814  GS_set_nofocus();
2815  gsd_set_view(&Gv, &Gd);
2816 
2817  return;
2818 }
2819 
2825 void GS_set_fov(int fov)
2826 {
2827  Gv.fov = fov;
2828 
2829  return;
2830 }
2831 
2837 int GS_get_fov(void)
2838 {
2839  return (Gv.fov);
2840 }
2841 
2847 int GS_get_twist(void)
2848 {
2849  return (Gv.twist);
2850 }
2851 
2859 void GS_set_twist(int t)
2860 {
2861  Gv.twist = t;
2862 
2863  return;
2864 }
2865 
2869 void GS_set_nofocus(void)
2870 {
2871  G_debug(3, "GS_set_nofocus");
2872 
2873  Gv.infocus = 0;
2874 
2875  return;
2876 }
2877 
2883 void GS_set_infocus(void)
2884 {
2885  G_debug(3, "GS_set_infocus");
2886 
2887  Gv.infocus = 1;
2888 
2889  return;
2890 }
2891 
2897 void GS_set_viewport(int left, int right, int bottom, int top)
2898 {
2899  G_debug(3, "GS_set_viewport(): left=%d, right=%d, "
2900  "bottom=%d, top=%d", left, right, bottom, top);
2901 
2902  gsd_viewport(left, right, bottom, top);
2903 
2904  return;
2905 }
2906 
2921 int GS_look_here(int sx, int sy)
2922 {
2923  float x, y, z, len, los[2][3];
2924  Point3 realto, dir;
2925  int id;
2926  geosurf *gs;
2927 
2928  if (GS_get_selected_point_on_surface(sx, sy, &id, &x, &y, &z)) {
2929  gs = gs_get_surf(id);
2930  if (gs) {
2931  realto[X] = x - gs->ox + gs->x_trans;
2932  realto[Y] = y - gs->oy + gs->y_trans;
2933  realto[Z] = z + gs->z_trans;
2934  GS_set_focus(realto);
2935 
2936  return (1);
2937  }
2938  }
2939  else {
2940  if (gsd_get_los(los, (short)sx, (short)sy)) {
2941  len = GS_distance(Gv.from_to[FROM], Gv.real_to);
2942  GS_v3dir(los[FROM], los[TO], dir);
2943  GS_v3mult(dir, len);
2944  realto[X] = Gv.from_to[FROM][X] + dir[X];
2945  realto[Y] = Gv.from_to[FROM][Y] + dir[Y];
2946  realto[Z] = Gv.from_to[FROM][Z] + dir[Z];
2947  GS_set_focus(realto);
2948 
2949  return (1);
2950  }
2951  }
2952 
2953  return (0);
2954 }
2955 
2970 int GS_get_selected_point_on_surface(int sx, int sy, int *id, float *x,
2971  float *y, float *z)
2972 {
2973  float los[2][3], find_dist[MAX_SURFS], closest;
2974  Point3 point, tmp, finds[MAX_SURFS];
2975  int surfs[MAX_SURFS], i, iclose, numhits = 0;
2976  geosurf *gs;
2977 
2978  /* returns surface-world coords */
2979  gsd_get_los(los, (short)sx, (short)sy);
2980 
2981  if (!gs_setlos_enterdata(los)) {
2982  G_debug(3, "gs_setlos_enterdata(los): returns false");
2983  return (0);
2984  }
2985 
2986  for (i = 0; i < Next_surf; i++) {
2987  G_debug(3, "id=%d", i);
2988 
2989  gs = gs_get_surf(Surf_ID[i]);
2990 
2991  /* los_intersect expects surf-world coords (xy transl, no scaling) */
2992 
2993 #if NVIZ_HACK
2994  if (gs_los_intersect1(Surf_ID[i], los, point)) {
2995 #else
2996  if (gs_los_intersect(Surf_ID[i], los, point)) {
2997 #endif
2998  if (!gs_point_is_masked(gs, point)) {
2999  GS_v3eq(tmp, point);
3000  tmp[X] += gs->x_trans;
3001  tmp[Y] += gs->y_trans;
3002  tmp[Z] += gs->z_trans;
3003  find_dist[numhits] = GS_distance(los[FROM], tmp);
3004  gsd_surf2real(gs, point);
3005  GS_v3eq(finds[numhits], point);
3006  surfs[numhits] = Surf_ID[i];
3007  numhits++;
3008  }
3009  }
3010  }
3011 
3012  for (i = iclose = 0; i < numhits; i++) {
3013  closest = find_dist[iclose];
3014 
3015  if (find_dist[i] < closest) {
3016  iclose = i;
3017  }
3018  }
3019 
3020  if (numhits) {
3021  *x = finds[iclose][X];
3022  *y = finds[iclose][Y];
3023  *z = finds[iclose][Z];
3024  *id = surfs[iclose];
3025  }
3026 
3027  G_debug(3, "NumHits %d, next %d", numhits, Next_surf);
3028 
3029  return (numhits);
3030 }
3031 
3038 void GS_set_cplane_rot(int num, float dx, float dy, float dz)
3039 {
3040  gsd_cplane_setrot(num, dx, dy, dz);
3041 
3042  return;
3043 }
3044 
3051 void GS_set_cplane_trans(int num, float dx, float dy, float dz)
3052 {
3053  gsd_cplane_settrans(num, dx, dy, dz);
3054 
3055  return;
3056 }
3057 
3058 
3064 void GS_draw_cplane(int num)
3065 {
3066  geosurf *gsurfs[MAX_SURFS];
3067  int nsurfs;
3068 
3069  nsurfs = gs_num_surfaces();
3070  if (2 == nsurfs) {
3071  /* testing */
3072  gs_getall_surfaces(gsurfs);
3073  gsd_draw_cplane_fence(gsurfs[0], gsurfs[1], num);
3074  }
3075  else {
3076  gsd_draw_cplane(num);
3077  }
3078 
3079  return;
3080 }
3081 
3091 int GS_draw_cplane_fence(int hs1, int hs2, int num)
3092 {
3093  geosurf *gs1, *gs2;
3094 
3095  if (NULL == (gs1 = gs_get_surf(hs1))) {
3096  return (0);
3097  }
3098 
3099  if (NULL == (gs2 = gs_get_surf(hs2))) {
3100  return (0);
3101  }
3102 
3103  gsd_draw_cplane_fence(gs1, gs2, num);
3104 
3105  return (1);
3106 }
3107 
3112 {
3113  int onstate[MAX_CPLANES], i;
3114 
3115  gsd_get_cplanes_state(onstate);
3116 
3117  for (i = 0; i < MAX_CPLANES; i++) {
3118  if (onstate[i]) {
3119  GS_draw_cplane_fence(Surf_ID[0], Surf_ID[1], i);
3120  }
3121  }
3122 
3123  return;
3124 }
3125 
3131 void GS_set_cplane(int num)
3132 {
3133  gsd_cplane_on(num);
3134 
3135  return;
3136 }
3137 
3143 void GS_unset_cplane(int num)
3144 {
3145  gsd_cplane_off(num);
3146 
3147  return;
3148 }
3149 
3156 void GS_get_scale(float *sx, float *sy, float *sz, int doexag)
3157 {
3158  float zexag;
3159 
3160  zexag = doexag ? Gv.vert_exag : 1.;
3161  *sx = *sy = Gv.scale;
3162  *sz = Gv.scale * zexag;
3163 
3164  return;
3165 }
3166 
3172 void GS_set_fencecolor(int mode)
3173 {
3174  gsd_setfc(mode);
3175 
3176  return;
3177 }
3178 
3185 {
3186  return gsd_getfc();
3187 }
3188 
3201 int GS_get_distance_alongsurf(int hs, float x1, float y1, float x2, float y2,
3202  float *dist, int use_exag)
3203 {
3204  geosurf *gs;
3205  float p1[2], p2[2];
3206 
3207  gs = gs_get_surf(hs);
3208  if (gs == NULL) {
3209  return 0;
3210  }
3211 
3212  p1[X] = x1;
3213  p1[Y] = y1;
3214  p2[X] = x2;
3215  p2[Y] = y2;
3216  gsd_real2surf(gs, p1);
3217  gsd_real2surf(gs, p2);
3218 
3219  G_debug(3, "GS_get_distance_alongsurf(): hs=%d p1=%f,%f p2=%f,%f",
3220  hs, x1, y1, x2, y2);
3221  return gs_distance_onsurf(gs, p1, p2, dist, use_exag);
3222 }
3223 
3232 int GS_save_3dview(const char *vname, int surfid)
3233 {
3234  return (Gs_save_3dview(vname, &Gv, &Gd, &wind, gs_get_surf(surfid)));
3235 }
3236 
3245 int GS_load_3dview(const char *vname, int surfid)
3246 {
3247 
3248  return (Gs_load_3dview(vname, &Gv, &Gd, &wind, gs_get_surf(surfid)));
3249 
3250  /* what to do about lights - I guess, delete all &
3251  create any that exist in 3dview file */
3252 }
3253 
3254 /************************************************************************
3255 * Following routines use Graphics Library
3256 ************************************************************************/
3257 
3263 void GS_init_view(void)
3264 {
3265  static int first = 1;
3266 
3267  G_debug(3, "GS_init_view");
3268 
3269  if (first) {
3270  first = 0;
3271  glMatrixMode(GL_MODELVIEW);
3272 
3273  /* OGLXXX doublebuffer: use GLX_DOUBLEBUFFER in attriblist */
3274  /* glxChooseVisual(*dpy, screen, *attriblist); */
3275  /* OGLXXX
3276  * ZMIN not needed -- always 0.
3277  * ZMAX not needed -- always 1.
3278  * getgdesc other posiblilties:
3279  * glxGetConfig();
3280  * glxGetCurrentContext();
3281  * glxGetCurrentDrawable();
3282  * GLint gdtmp;
3283  * getgdesc other posiblilties:
3284  * glxGetConfig();
3285  * glxGetCurrentContext();
3286  * glxGetCurrentDrawable();
3287  * GLint gdtmp;
3288  * glDepthRange params must be scaled to [0, 1]
3289  */
3290  glDepthRange(0.0, 1.0);
3291  glEnable(GL_DEPTH_TEST);
3292  glDepthFunc(GL_LEQUAL);
3293  /* } */
3294 
3295  /* replace these with something meaningful */
3296  Gv.fov = 450;
3297  Gv.twist = 0;
3298  Gv.from_to[FROM][X] = Gv.from_to[FROM][Y] =
3299  Gv.from_to[FROM][Z] = GS_UNIT_SIZE / 2.;
3300 
3301  Gv.from_to[TO][X] = GS_UNIT_SIZE / 2.;
3302  Gv.from_to[TO][Y] = GS_UNIT_SIZE / 2.;
3303  Gv.from_to[TO][Z] = 0.;
3304  Gv.from_to[TO][W] = Gv.from_to[FROM][W] = 1.;
3305 
3306  Gv.real_to[W] = 1.;
3307  Gv.vert_exag = 1.;
3308 
3309  GS_v3eq(Gv.real_to, Gv.from_to[TO]);
3310  GS_v3normalize(Gv.from_to[FROM], Gv.from_to[TO]);
3311 
3312  /*
3313  Gd.nearclip = 50;
3314  Gd.farclip = 10000.;
3315  */
3316  Gd.nearclip = 10.;
3317  Gd.farclip = 10000.;
3318  Gd.aspect = (float)GS_get_aspect();
3319 
3320  GS_set_focus(Gv.real_to);
3321  }
3322 
3323  return;
3324 }
3325 
3331 void GS_clear(int col)
3332 {
3333  G_debug(3, "GS_clear");
3334 
3335  col = col | 0xFF000000;
3336 
3337  /* OGLXXX
3338  * change glClearDepth parameter to be in [0, 1]
3339  * ZMAX not needed -- always 1.
3340  * getgdesc other posiblilties:
3341  * glxGetConfig();
3342  * glxGetCurrentContext();
3343  * glxGetCurrentDrawable();
3344  * GLint gdtmp;
3345  */
3346  glClearDepth(1.0);
3347  glClearColor(((float)((col) & 0xff)) / 255.,
3348  (float)((col) >> 8 & 0xff) / 255.,
3349  (float)((col) >> 16 & 0xff) / 255.,
3350  (float)((col) >> 24 & 0xff) / 255.);
3351  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
3352 
3353  Gd.bgcol = col;
3354  Modelshowing = 0;
3355  gsd_flush();
3356 
3357  return;
3358 }
3359 
3365 double GS_get_aspect(void)
3366 {
3367  int left, right, bottom, top;
3368  GLint tmp[4];
3369 
3370  /* OGLXXX
3371  * get GL_VIEWPORT:
3372  * You can probably do better than this.
3373  */
3374  glGetIntegerv(GL_VIEWPORT, tmp);
3375  left = tmp[0];
3376  right = tmp[0] + tmp[2] - 1;
3377  bottom = tmp[1];
3378  top = tmp[1] + tmp[3] - 1;
3379 
3380  G_debug(3, "GS_get_aspect(): left=%d, right=%d, top=%d, bottom=%d",
3381  left, right, top, bottom);
3382 
3383  return ((double)(right - left) / (top - bottom));
3384 }
3385 
3394 {
3395  /* OGLXXX
3396  * getgdesc other posiblilties:
3397  * glxGetConfig();
3398  * glxGetCurrentContext();
3399  * glxGetCurrentDrawable();
3400  * GLint gdtmp;
3401  * blending is ALWAYS supported.
3402  * This function returns whether it is enabled.
3403  * return((glGetIntegerv(GL_BLEND, &gdtmp), gdtmp));
3404  */
3405 
3406  return (1);
3407 }