GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
gsd_objs.c
Go to the documentation of this file.
1/*!
2 \file lib/ogsf/gsd_label.c
3
4 \brief OGSF library - objects management (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 (October 1993)
16 \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
17 */
18
19#include <stdlib.h>
20#include <string.h>
21
22#include <grass/gis.h>
23#include <grass/ogsf.h>
24
25#include "gsget.h"
26#include "math.h"
27#include "rowcol.h"
28
29static void init_stuff(void);
30
31/*!
32 \brief vertices for octahedron
33 */
34float Octo[6][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0},
35 {-1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, -1.0}};
36
37#define ONORM .57445626
38
39/*!
40 \brief normals for flat-shaded octahedron
41 */
42float OctoN[8][3] = {
44 {-ONORM, -ONORM, ONORM}, {ONORM, ONORM, -ONORM}, {-ONORM, ONORM, -ONORM},
45 {ONORM, -ONORM, -ONORM}, {-ONORM, -ONORM, -ONORM},
46};
47
48/*!
49 ???? not sure if any of these are needed for correct lighting.
50 float CubeNormals[6][3] = {
51 {ONORM, 0, 0},
52 {-ONORM, 0, 0},
53 {0, ONORM, 0},
54 {0, -ONORM, 0},
55 {0, 0, ONORM},
56 {0, 0, -ONORM}
57 };
58 */
59
60float CubeNormals[3][3] = {{0, -ONORM, 0}, {0, 0, ONORM}, {ONORM, 0, 0}};
61
62float CubeVertices[8][3] = {
63 {-1.0, -1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, 1.0, -1.0}, {-1.0, 1.0, -1.0},
64 {-1.0, -1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}};
65
66float origin[3] = {0.0, 0.0, 0.0};
67
68#define UP_NORM Octo[2]
69#define DOWN_NORM Octo[5]
70#define ORIGIN origin
71
72/*!
73 \brief vertices & normals for octagon in xy plane
74 */
75float ogverts[8][3];
76
77/*!
78 \brief vertices for octagon in xy plane, z=1
79 */
80float ogvertsplus[8][3];
81
82float Pi;
83
84static void init_stuff(void)
85{
86 float cos45;
87 int i;
88 static int first = 1;
89
90 if (first) {
91 first = 0;
92
93 cos45 = cos(atan(1.0));
94
95 for (i = 0; i < 8; i++) {
96 ogverts[i][Z] = 0.0;
97 ogvertsplus[i][Z] = 1.0;
98 }
99
100 ogverts[0][X] = ogvertsplus[0][X] = 1.0;
101 ogverts[0][Y] = ogvertsplus[0][Y] = 0.0;
102 ogverts[1][X] = ogvertsplus[1][X] = cos45;
103 ogverts[1][Y] = ogvertsplus[1][Y] = cos45;
104 ogverts[2][X] = ogvertsplus[2][X] = 0.0;
105 ogverts[2][Y] = ogvertsplus[2][Y] = 1.0;
106 ogverts[3][X] = ogvertsplus[3][X] = -cos45;
107 ogverts[3][Y] = ogvertsplus[3][Y] = cos45;
108 ogverts[4][X] = ogvertsplus[4][X] = -1.0;
109 ogverts[4][Y] = ogvertsplus[4][Y] = 0.0;
110 ogverts[5][X] = ogvertsplus[5][X] = -cos45;
111 ogverts[5][Y] = ogvertsplus[5][Y] = -cos45;
112 ogverts[6][X] = ogvertsplus[6][X] = 0.0;
113 ogverts[6][Y] = ogvertsplus[6][Y] = -1.0;
114 ogverts[7][X] = ogvertsplus[7][X] = cos45;
115 ogverts[7][Y] = ogvertsplus[7][Y] = -cos45;
116
117 Pi = 4.0 * atan(1.0);
118 }
119
120 return;
121}
122
123/*!
124 \brief ADD
125
126 \param center center point
127 \param colr color value
128 \param siz size value
129 */
130void gsd_plus(float *center, int colr, float siz)
131{
132 float v1[3], v2[3];
133
134 gsd_color_func(colr);
135 siz *= .5;
136
137 v1[Z] = v2[Z] = center[Z];
138
139 v1[X] = v2[X] = center[X];
140 v1[Y] = center[Y] - siz;
141 v2[Y] = center[Y] + siz;
142 gsd_bgnline();
143 gsd_vert_func(v1);
144 gsd_vert_func(v2);
145 gsd_endline();
146
147 v1[Y] = v2[Y] = center[Y];
148 v1[X] = center[X] - siz;
149 v2[X] = center[X] + siz;
150 gsd_bgnline();
151 gsd_vert_func(v1);
152 gsd_vert_func(v2);
153 gsd_endline();
154
155 return;
156}
157
158/*!
159 \brief Line on surface, fix z-values
160
161 \todo remove fudge, instead fudge the Z buffer
162
163 \param gs surface (geosurf)
164 \param v1 first point
165 \param v2 second point
166 */
167void gsd_line_onsurf(geosurf *gs, float *v1, float *v2)
168{
169 int i, np;
170 Point3 *pts;
171 float fudge;
172
173 pts = gsdrape_get_segments(gs, v1, v2, &np);
174 if (pts) {
175 fudge = FUDGE(gs);
176 gsd_bgnline();
177
178 for (i = 0; i < np; i++) {
179 /* ACS */
180 /* reverting back, as it broke displaying X symbol and query line */
181 pts[i][Z] += fudge;
182 /*pts[i][Z] *= fudge; */
183 gsd_vert_func(pts[i]);
184 }
185
186 gsd_endline();
187
188 /* fix Z values? */
189 v1[Z] = pts[0][Z];
190 v2[Z] = pts[np - 1][Z];
191 }
192
193 return;
194}
195
196/*!
197 \brief Multiline on surface, fix z-values
198
199 \todo remove fudge, instead fudge the Z buffer
200
201 Like above, except only draws first n points of line, or np,
202 whichever is less. Returns number of points used. Fills
203 pt with last pt drawn.
204
205 \param gs surface (geosurf)
206 \param v1 first point
207 \param v2 second point
208 \param pt
209 \param n number of segments
210
211 \param number of vertices
212 */
213int gsd_nline_onsurf(geosurf *gs, float *v1, float *v2, float *pt, int n)
214{
215 int i, np, pdraw;
216 Point3 *pts;
217 float fudge;
218
219 pts = gsdrape_get_segments(gs, v1, v2, &np);
220
221 if (pts) {
222 pdraw = n < np ? n : np;
223 fudge = FUDGE(gs);
224 gsd_bgnline();
225
226 for (i = 0; i < pdraw; i++) {
227 pts[i][Z] += fudge;
228 gsd_vert_func(pts[i]);
229 }
230
231 gsd_endline();
232
233 pt[X] = pts[i - 1][X];
234 pt[Y] = pts[i - 1][Y];
235
236 /* fix Z values? */
237 v1[Z] = pts[0][Z];
238 v2[Z] = pts[np - 1][Z];
239
240 return (i);
241 }
242
243 return (0);
244}
245
246/*!
247 \brief Draw X symbol
248
249 Note gs: NULL if flat
250
251 \param gs surface (geosurf)
252 \param center
253 \param colr color value
254 \param siz size value
255 */
256void gsd_x(geosurf *gs, float *center, int colr, float siz)
257{
258 float v1[3], v2[3];
259
260 gsd_color_func(colr);
261 siz *= .5;
262
263 v1[Z] = v2[Z] = center[Z];
264
265 v1[X] = center[X] - siz;
266 v2[X] = center[X] + siz;
267 v1[Y] = center[Y] - siz;
268 v2[Y] = center[Y] + siz;
269
270 if (gs) {
271 gsd_line_onsurf(gs, v1, v2);
272 }
273 else {
274 gsd_bgnline();
275 gsd_vert_func(v1);
276 gsd_vert_func(v2);
277 gsd_endline();
278 }
279
280 v1[X] = center[X] - siz;
281 v2[X] = center[X] + siz;
282 v1[Y] = center[Y] + siz;
283 v2[Y] = center[Y] - siz;
284
285 if (gs) {
286 gsd_line_onsurf(gs, v1, v2);
287 }
288 else {
289 gsd_bgnline();
290 gsd_vert_func(v1);
291 gsd_vert_func(v2);
292 gsd_endline();
293 }
294
295 return;
296}
297
298/*!
299 \brief Draw diamond symbol
300
301 \param center center point
302 \param colr color value
303 \param size size value
304 */
305void gsd_diamond(float *center, unsigned long colr, float siz)
306{
307 int preshade;
308
309 /* seems right, but isn't
310 siz *= .5;
311 */
312
314 gsd_translate(center[X], center[Y], center[Z]);
315 gsd_scale(siz, siz, siz);
316 preshade = gsd_getshademodel();
317 gsd_shademodel(0); /* want flat shading */
318
320 gsd_litvert_func(OctoN[0], colr, Octo[0]);
321 gsd_litvert_func(OctoN[0], colr, Octo[1]);
322 gsd_litvert_func(OctoN[0], colr, Octo[2]);
324
326 gsd_litvert_func(OctoN[1], colr, Octo[2]);
327 gsd_litvert_func(OctoN[1], colr, Octo[1]);
328 gsd_litvert_func(OctoN[1], colr, Octo[3]);
330
332 gsd_litvert_func(OctoN[2], colr, Octo[2]);
333 gsd_litvert_func(OctoN[2], colr, Octo[4]);
334 gsd_litvert_func(OctoN[2], colr, Octo[0]);
336
338 gsd_litvert_func(OctoN[3], colr, Octo[2]);
339 gsd_litvert_func(OctoN[3], colr, Octo[3]);
340 gsd_litvert_func(OctoN[3], colr, Octo[4]);
342
344 gsd_litvert_func(OctoN[4], colr, Octo[0]);
345 gsd_litvert_func(OctoN[4], colr, Octo[5]);
346 gsd_litvert_func(OctoN[4], colr, Octo[1]);
348
350 gsd_litvert_func(OctoN[5], colr, Octo[1]);
351 gsd_litvert_func(OctoN[5], colr, Octo[5]);
352 gsd_litvert_func(OctoN[5], colr, Octo[3]);
354
356 gsd_litvert_func(OctoN[6], colr, Octo[5]);
357 gsd_litvert_func(OctoN[6], colr, Octo[0]);
358 gsd_litvert_func(OctoN[6], colr, Octo[4]);
360
362 gsd_litvert_func(OctoN[7], colr, Octo[5]);
363 gsd_litvert_func(OctoN[7], colr, Octo[4]);
364 gsd_litvert_func(OctoN[7], colr, Octo[3]);
366
367#ifdef OCT_SHADED
368 {
369 gsd_bgntmesh();
370 gsd_litvert_func(Octo[0], colr, Octo[0]);
371 gsd_litvert_func(Octo[1], colr, Octo[1]);
373 gsd_litvert_func(Octo[2], colr, Octo[2]);
375 gsd_litvert_func(Octo[4], colr, Octo[4]);
377 gsd_litvert_func(Octo[5], colr, Octo[5]);
379 gsd_litvert_func(Octo[1], colr, Octo[1]);
380 gsd_litvert_func(Octo[3], colr, Octo[3]);
381 gsd_litvert_func(Octo[2], colr, Octo[2]);
383 gsd_litvert_func(Octo[4], colr, Octo[4]);
385 gsd_litvert_func(Octo[5], colr, Octo[5]);
387 gsd_litvert_func(Octo[1], colr, Octo[1]);
388 gsd_endtmesh();
389 }
390#endif
391
393 gsd_shademodel(preshade);
394
395 return;
396}
397
398/*!
399 \brief Draw cube
400
401 Added by Hamish Bowman Nov 2005
402
403 \param center center point
404 \param colr color value
405 \param siz size value
406 */
407void gsd_cube(float *center, unsigned long colr, float siz)
408{
409 int preshade;
410
411 /* see gsd_diamond() "seems right, but isn't" */
412 siz *= .5;
413
415 gsd_translate(center[X], center[Y], center[Z]);
416 gsd_scale(siz, siz, siz);
417 preshade = gsd_getshademodel();
418 gsd_shademodel(0); /* want flat shading */
419
420 /* N wall: */
427
428 /* S wall: */
435
436 /* E wall: */
443
444 /* W wall: */
451
452 /* lower wall: */
459
460 /* top wall: */
467
469 gsd_shademodel(preshade);
470
471 return;
472}
473
474/*!
475 \brief Draw box
476
477 Added by Hamish Bowman Nov 2005
478
479 \param center center point
480 \param colr color value
481 \param siz size value
482 */
483void gsd_draw_box(float *center, unsigned long colr, float siz)
484{
485
486 /* see gsd_diamond() "seems right, but isn't" */
487 siz *= .5;
488
490 gsd_translate(center[X], center[Y], center[Z]);
491 gsd_scale(siz, siz, siz);
492 gsd_color_func(colr);
493
494 gsd_bgnline(); /* N wall */
500 gsd_endline();
501
502 gsd_bgnline(); /* S wall */
508 gsd_endline();
509
510 gsd_bgnline();
513 gsd_endline();
514
515 gsd_bgnline();
518 gsd_endline();
519
520 gsd_bgnline();
523 gsd_endline();
524
525 gsd_bgnline();
528 gsd_endline();
529
531
532 return;
533}
534
535/*!
536 \brief Draw sphere
537
538 \param center center point
539 \param colr color value
540 \param size size value
541 */
542void gsd_drawsphere(float *center, unsigned long colr, float siz)
543{
544 siz *= .5; /* siz is diameter, gsd_sphere uses radius */
545 gsd_color_func(colr);
546 gsd_sphere(center, siz);
547
548 return;
549}
550
551/*!
552 \brief Draw diamond lines
553 */
555{
556 gsd_bgnline();
559 gsd_endline();
560
561 gsd_bgnline();
564 gsd_endline();
565
566 gsd_bgnline();
569 gsd_endline();
570
571 return;
572}
573
574/*!
575 \brief Draw asterisk
576
577 \param center center point
578 \param colr color value
579 \param siz size value
580 */
581void gsd_draw_asterisk(float *center, unsigned long colr, float siz)
582{
583 float angle;
584
585 angle = 45.; /* degrees */
586
588 gsd_translate(center[X], center[Y], center[Z]);
589 gsd_scale(siz, siz, siz);
590 gsd_color_func(colr);
591
593
595 gsd_rot(angle, 'x');
598
600 gsd_rot(-angle, 'x');
603
605 gsd_rot(angle, 'y');
608
610 gsd_rot(-angle, 'y');
613
615 gsd_rot(angle, 'z');
618
620 gsd_rot(-angle, 'z');
623
625
626 return;
627}
628
629/*!
630 \brief Draw gyro
631
632 \param center center point
633 \param colr color value
634 \param siz size value
635 */
636void gsd_draw_gyro(float *center, unsigned long colr, float siz)
637{
638 int i;
639
641 gsd_translate(center[X], center[Y], center[Z]);
642 gsd_scale(siz, siz, siz);
643 gsd_color_func(colr);
644
645 /* vert axis */
646 gsd_bgnline();
649 gsd_endline();
650
651 /* spokes */
653
654 for (i = 0; i < 6; i++) {
655 gsd_rot(30., 'z');
656 gsd_bgnline();
659 gsd_endline();
660 }
661
663
664 gsd_color_func(colr);
665
666 gsd_circ(0., 0., 1.);
667
669 gsd_rot(90., 'x');
670 gsd_circ(0., 0., 1.);
672
674 gsd_rot(90., 'y');
675 gsd_circ(0., 0., 1.);
677
679
680 return;
681}
682
683/*!
684 \brief Draw 3d cursor
685
686 \param pt point
687 */
688void gsd_3dcursor(float *pt)
689{
690 float big, vert[3];
691
692 big = 10000.;
693
694 gsd_bgnline();
695 vert[X] = pt[X];
696 vert[Y] = pt[Y];
697 vert[Z] = big;
698 gsd_vert_func(vert);
699 vert[Z] = -big;
700 gsd_vert_func(vert);
701 gsd_endline();
702
703 gsd_bgnline();
704 vert[X] = pt[X];
705 vert[Z] = pt[Z];
706 vert[Y] = big;
707 gsd_vert_func(vert);
708 vert[Y] = -big;
709 gsd_vert_func(vert);
710 gsd_endline();
711
712 gsd_bgnline();
713 vert[Y] = pt[Y];
714 vert[Z] = pt[Z];
715 vert[X] = big;
716 gsd_vert_func(vert);
717 vert[X] = -big;
718 gsd_vert_func(vert);
719 gsd_endline();
720
721 return;
722}
723
724/*!
725 \brief ADD
726
727 \param dir
728 \param slope
729 \param ascpect
730 \param degrees
731 */
732void dir_to_slope_aspect(float *dir, float *slope, float *aspect, int degrees)
733{
734 float dx, dy, dz;
735 float costheta, theta, adjacent;
736
737 dx = dir[X];
738 dy = dir[Y];
739 dz = dir[Z];
740
741 /* project vector <dx,dy,dz> onto plane of constant z containing
742 * final value should be 0.0 to 3600.0 */
743 if (dx == 0 && dy == 0) {
744 *aspect = 0.;
745 }
746 else {
747 if (dx == 0) {
748 theta = 90.0;
749 }
750 else {
751 costheta = dx / sqrt(dx * dx + dy * dy);
752 theta = acos(costheta);
753 }
754
755 if (dy < 0) {
756 theta = (2 * Pi) - theta;
757 }
758
759 *aspect = theta;
760 }
761
762 /* project vector <dx,dy,dz> onto plane of constant y containing
763 * final value should be -900.0 (looking up) to 900.0 (looking down) */
764 if (dz == 0) {
765 theta = 0.0;
766 }
767 else if (dx == 0 && dy == 0) {
768 theta = Pi / 2.;
769 }
770 else {
771 adjacent = sqrt(dx * dx + dy * dy);
772 costheta = adjacent / sqrt(adjacent * adjacent + dz * dz);
773 theta = acos(costheta);
774 }
775
776 if (dz > 0) {
777 theta = -theta;
778 }
779
780 *slope = theta;
781
782 if (degrees) {
783 *aspect = *aspect * (180. / Pi);
784 *slope = *slope * (180. / Pi);
785 }
786
787 return;
788}
789
790/*!
791 \brief Draw North Arrow takes OpenGL coords and size
792
793 \param pos2
794 \param len
795 \param fontbase
796 \param arw_clr north arrow color
797 \param text_clr text color
798
799 \return 1
800 */
801/*TODO: Store arrow somewhere to enable it's removal/change.
802 Add option to specify north text and font. */
803int gsd_north_arrow(float *pos2, float len, GLuint fontbase,
804 unsigned long arw_clr, unsigned long text_clr)
805{
806 const char *txt;
807 float v[4][3];
808 float base[3][3];
809 float Ntop[] = {0.0, 0.0, 1.0};
810
811 base[0][Z] = base[1][Z] = base[2][Z] = pos2[Z];
812 v[0][Z] = v[1][Z] = v[2][Z] = v[3][Z] = pos2[Z];
813
814 base[0][X] = pos2[X] - len / 16.;
815 base[1][X] = pos2[X] + len / 16.;
816 base[0][Y] = base[1][Y] = pos2[Y] - len / 2.;
817 base[2][X] = pos2[X];
818 base[2][Y] = pos2[Y] + .45 * len;
819
820 v[0][X] = v[2][X] = pos2[X];
821 v[1][X] = pos2[X] + len / 8.;
822 v[3][X] = pos2[X] - len / 8.;
823 v[0][Y] = pos2[Y] + .2 * len;
824 v[1][Y] = v[3][Y] = pos2[Y] + .1 * len;
825 v[2][Y] = pos2[Y] + .5 * len;
826
827 /* make sure we are drawing in front buffer */
828 GS_set_draw(GSD_FRONT);
829
831 gsd_do_scale(1);
832
833 glNormal3fv(Ntop);
834 gsd_color_func(arw_clr);
835
837 glVertex3fv(base[0]);
838 glVertex3fv(base[1]);
839 glVertex3fv(base[2]);
841
843 glVertex3fv(v[0]);
844 glVertex3fv(v[1]);
845 glVertex3fv(v[2]);
846 glVertex3fv(v[0]);
848
850 glVertex3fv(v[0]);
851 glVertex3fv(v[2]);
852 glVertex3fv(v[3]);
853 glVertex3fv(v[0]);
855
856 /* draw N for North */
857 /* Need to pick a nice generic font */
858 /* TODO -- project text position off arrow
859 * bottom along azimuth
860 */
861
862 gsd_color_func(text_clr);
863 txt = "North";
864 /* adjust position of N text */
865 base[0][X] -= gsd_get_txtwidth(txt, 18) - 20.;
866 base[0][Y] -= gsd_get_txtheight(18) - 20.;
867
868 glRasterPos3fv(base[0]);
869 glListBase(fontbase);
870 glCallLists(strlen(txt), GL_UNSIGNED_BYTE, (const GLvoid *)txt);
871 GS_done_draw();
872
874 gsd_flush();
875
876 return (1);
877}
878
879/*!
880 \brief ADD
881
882 siz is height, sz is global exag to correct for.
883
884 If onsurf in non-null, z component of dir is dropped and
885 line-on-suf is used, resulting in length of arrow being proportional
886 to slope
887
888 \param center center point
889 \param colr color value
890 \param siz size value
891 \param dir
892 \param sz
893 \param onsurf surface (geosurf)
894
895 \return 1 no surface given
896 \return 0 on surface
897 */
898int gsd_arrow(float *center, unsigned long colr, float siz, float *dir,
899 float sz, geosurf *onsurf)
900{
901 float slope, aspect;
902 float tmp[3];
903 static int first = 1;
904
905 if (first) {
906 init_stuff();
907 first = 0;
908 }
909
910 dir[Z] /= sz;
911
912 GS_v3norm(dir);
913
914 if (NULL != onsurf) {
915 float base[3], tip[3], len;
916
917 base[X] = center[X];
918 base[Y] = center[Y];
919
920 /* project dir to surface, after zexag */
921 len = GS_P2distance(ORIGIN, dir); /* in case dir isn't normalized */
922 tip[X] = center[X] + dir[X] * len * siz;
923 tip[Y] = center[Y] + dir[Y] * len * siz;
924
925 return gsd_arrow_onsurf(base, tip, colr, 2, onsurf);
926 }
927
928 dir_to_slope_aspect(dir, &slope, &aspect, 1);
929
931 gsd_translate(center[X], center[Y], center[Z]);
932 gsd_scale(1.0, 1.0, 1.0 / sz);
933 gsd_rot(aspect + 90, 'z');
934 gsd_rot(slope + 90., 'x');
935 gsd_scale(siz, siz, siz);
936 gsd_color_func(colr);
937
938 tmp[X] = 0.2;
939 tmp[Y] = 0.0;
940 tmp[Z] = 0.65;
941
942 gsd_bgnline();
945 gsd_endline();
946
947 gsd_bgnline();
948 gsd_vert_func(tmp);
950 tmp[X] = -0.2;
951 gsd_vert_func(tmp);
952 gsd_endline();
953
955
956 return (1);
957}
958
959/*!
960 \brief Draw north arrow on surface
961
962 \param base
963 \param tip
964 \param colr
965 \param wid
966 \param gs surface (geosurf)
967
968 \return 0
969 */
970int gsd_arrow_onsurf(float *base, float *tip, unsigned long colr, int wid,
971 geosurf *gs)
972{
973 static int first = 1;
974
975 if (first) {
976 init_stuff();
977 first = 0;
978 }
979
980 gsd_linewidth(wid);
981 gsd_color_func(colr);
982
983 G_debug(3, "gsd_arrow_onsurf");
984 G_debug(3, " %f %f -> %f %f", base[X], base[Y], tip[X], tip[Y]);
985
986 gsd_line_onsurf(gs, base, tip);
987
988#ifdef DO_SPHERE_BASE
989 {
990 GS_v3dir(tip, base, dir0);
991 GS_v3mag(dir0, &len);
992 gsd_disc(base[X], base[Y], len / 10.);
993 }
994#endif
995
996#ifdef ARROW_READY
997 {
998 base[Z] = tip[Z] = 0.0;
999 GS_v3dir(tip, base, dir0);
1000
1001 G_debug(3, " dir0: %f %f %f", dir0[X], dir0[Y], dir0[Z]);
1002
1003 /* rotate this direction 90 degrees */
1004 GS_v3cross(dir0, UP_NORM, dir2);
1005 GS_v3mag(dir0, &len);
1006 GS_v3eq(dir1, dir0);
1007
1008 G_debug(3, " len: %f", len);
1009 G_debug(3, " a-dir1: %f %f %f", dir1[X], dir1[Y], dir1[Z]);
1010 G_debug(3, " a-dir2: %f %f %f", dir2[X], dir2[Y], dir2[Z]);
1011
1012 dim1 = len * .7;
1013 dim2 = len * .2;
1014 GS_v3mult(dir1, dim1);
1015 GS_v3mult(dir2, dim2);
1016
1017 G_debug(3, " b-dir1: %f %f %f", dir1[X], dir1[Y], dir1[Z]);
1018 G_debug(3, " b-dir2: %f %f %f", dir2[X], dir2[Y], dir2[Z]);
1019
1020 GS_v3eq(tmp, base);
1021 GS_v3add(tmp, dir1);
1022 GS_v3add(tmp, dir2);
1023
1024 G_debug(3, " %f %f -> ", tmp[X], tmp[Y]);
1025
1026 gsd_line_onsurf(gs, tmp, tip);
1027
1028 GS_v3cross(dir0, DOWN_NORM, dir2);
1029 GS_v3mult(dir2, dim2);
1030 GS_v3eq(tmp, base);
1031
1032 G_debug(3, " dir1: %f %f %f", dir1[X], dir1[Y], dir1[Z]);
1033 G_debug(3, " dir2: %f %f %f", dir2[X], dir2[Y], dir2[Z]);
1034
1035 GS_v3add(tmp, dir1);
1036 GS_v3add(tmp, dir2);
1037
1038 G_debug(3, " %f %f", tmp[X], tmp[Y]);
1039
1040 gsd_line_onsurf(gs, tip, tmp);
1041 }
1042#endif
1043
1044 return (0);
1045}
1046
1047/*!
1048 \brief Draw 3d north arrow
1049
1050 \param center center point
1051 \param colr color value
1052 \param siz1 height
1053 \param siz2 is diameter
1054 \param dir
1055 \param sz
1056 */
1057void gsd_3darrow(float *center, unsigned long colr, float siz1, float siz2,
1058 float *dir, float sz)
1059{
1060 float slope, aspect;
1061 int preshade;
1062 static int first = 1;
1063 static int list;
1064 static int debugint = 1;
1065
1066 dir[Z] /= sz;
1067
1068 GS_v3norm(dir);
1069 dir_to_slope_aspect(dir, &slope, &aspect, 1);
1070
1071 if (debugint > 100) {
1072 G_debug(3, "gsd_3darrow()");
1073 G_debug(3, " pt: %f,%f,%f dir: %f,%f,%f slope: %f aspect: %f",
1074 center[X], center[Y], center[Z], dir[X], dir[Y], dir[Z], slope,
1075 aspect);
1076 debugint = 1;
1077 }
1078 debugint++;
1079
1080 preshade = gsd_getshademodel();
1081
1082 /*
1083 gsd_shademodel(0);
1084 want flat shading? */
1086 gsd_translate(center[X], center[Y], center[Z]);
1087 gsd_scale(1.0, 1.0, 1.0 / sz);
1088 gsd_rot(aspect + 90, 'z');
1089 gsd_rot(slope + 90., 'x');
1090 gsd_scale(siz2, siz2, siz1);
1091 gsd_color_func(colr);
1092
1093 if (first) {
1094 /* combine these into an object */
1095 first = 0;
1096 list = gsd_makelist();
1097 gsd_bgnlist(list, 1);
1098 gsd_backface(1);
1099
1101 gsd_scale(.10, .10, .75); /* narrow cyl */
1102 primitive_cylinder(colr, 0);
1103 gsd_popmatrix();
1104
1106 gsd_translate(0.0, 0.0, .60);
1107 gsd_scale(0.3, 0.3, 0.4); /* cone */
1108 primitive_cone(colr);
1109 gsd_popmatrix();
1110
1111 gsd_backface(0);
1112 gsd_endlist();
1113 }
1114 else {
1116 }
1117
1118 gsd_popmatrix();
1119 gsd_shademodel(preshade);
1120
1121 return;
1122}
1123
1124/*!
1125 \brief Draw Scalebar takes OpenGL coords and size
1126
1127 Adapted from gsd_north_arrow Hamish Bowman Dec 2006
1128
1129 \param pos2
1130 \param fontbase font-base
1131 \param bar_clr barscale color
1132 \param text_clr text color
1133
1134 \return 1
1135 */
1136int gsd_scalebar(float *pos2, float len, GLuint fontbase, unsigned long bar_clr,
1137 unsigned long text_clr)
1138{
1139 char txt[100];
1140 float base[4][3];
1141 float Ntop[] = {0.0, 0.0, 1.0};
1142
1143 base[0][Z] = base[1][Z] = base[2][Z] = base[3][Z] = pos2[Z];
1144
1145 /* simple 1:8 rectangle */ /* bump to X/20. for a 1:10 narrower bar? */
1146 base[0][X] = base[1][X] = pos2[X] - len / 2.;
1147 base[2][X] = base[3][X] = pos2[X] + len / 2.;
1148
1149 base[0][Y] = base[3][Y] = pos2[Y] - len / 16.;
1150 base[1][Y] = base[2][Y] = pos2[Y] + len / 16.;
1151
1152 /* make sure we are drawing in front buffer */
1153 GS_set_draw(GSD_FRONT);
1154
1156 gsd_do_scale(1); /* get map scale factor */
1157
1158 glNormal3fv(Ntop);
1159
1160 gsd_color_func(bar_clr);
1161
1163 glVertex3fv(base[0]);
1164 glVertex3fv(base[1]);
1165 glVertex3fv(base[2]);
1166 glVertex3fv(base[3]);
1167 glVertex3fv(base[0]);
1169
1170 /* draw units */
1171 /* Need to pick a nice generic font */
1172 /* TODO -- project text position off bar bottom along azimuth */
1173
1174 gsd_color_func(text_clr);
1175
1176 /* format text in a nice way */
1177 if (strcmp("meters", G_database_unit_name(TRUE)) == 0) {
1178 if (len > 2500)
1179 sprintf(txt, "%g km", len / 1000);
1180 else
1181 sprintf(txt, "%g meters", len);
1182 }
1183 else if (strcmp("feet", G_database_unit_name(TRUE)) == 0) {
1184 if (len > 5280)
1185 sprintf(txt, "%g miles", len / 5280);
1186 else if (len == 5280)
1187 sprintf(txt, "1 mile");
1188 else
1189 sprintf(txt, "%g feet", len);
1190 }
1191 else {
1192 sprintf(txt, "%g %s", len, G_database_unit_name(TRUE));
1193 }
1194
1195 /* adjust position of text (In map units?!) */
1196 base[0][X] -= gsd_get_txtwidth(txt, 18) - 20.;
1197 base[0][Y] -= gsd_get_txtheight(18) - 20.;
1198
1199 glRasterPos3fv(base[0]);
1200 glListBase(fontbase);
1201 glCallLists(strlen(txt), GL_BYTE, (GLubyte *)txt);
1202 GS_done_draw();
1203
1204 gsd_popmatrix();
1205 gsd_flush();
1206
1207 return (1);
1208}
1209
1210/*!
1211 \brief Draw Scalebar (as lines)
1212
1213 Adapted from gsd_scalebar A.Kratochvilova 2011
1214
1215 \param pos2 scalebar position
1216 \param fontbase font-base (unused)
1217 \param bar_clr barscale color
1218 \param text_clr text color (unused)
1219
1220 \return 1
1221 */
1222int gsd_scalebar_v2(float *pos, float len, GLuint fontbase UNUSED,
1223 unsigned long bar_clr, unsigned long text_clr UNUSED)
1224{
1225 float base[6][3];
1226 float Ntop[] = {0.0, 0.0, 1.0};
1227
1228 base[0][Z] = base[1][Z] = base[2][Z] = pos[Z];
1229 base[3][Z] = base[4][Z] = base[5][Z] = pos[Z];
1230
1231 /* simple scalebar: |------| */
1232 base[0][X] = base[2][X] = base[3][X] = pos[X] - len / 2.;
1233 base[1][X] = base[4][X] = base[5][X] = pos[X] + len / 2.;
1234 base[0][Y] = base[1][Y] = pos[Y];
1235 base[2][Y] = base[4][Y] = pos[Y] - len / 12;
1236 base[3][Y] = base[5][Y] = pos[Y] + len / 12;
1237
1238 /* make sure we are drawing in front buffer */
1239 GS_set_draw(GSD_FRONT);
1240
1242 gsd_do_scale(1); /* get map scale factor */
1243
1244 glNormal3fv(Ntop);
1245
1246 gsd_color_func(bar_clr);
1247
1248 gsd_linewidth(3); /* could be optional */
1249
1250 /* ------- */
1251 gsd_bgnline();
1252 gsd_vert_func(base[0]);
1253 gsd_vert_func(base[1]);
1254 gsd_endline();
1255
1256 /* |------- */
1257 gsd_bgnline();
1258 gsd_vert_func(base[2]);
1259 gsd_vert_func(base[3]);
1260 gsd_endline();
1261
1262 /* |-------| */
1263 gsd_bgnline();
1264 gsd_vert_func(base[4]);
1265 gsd_vert_func(base[5]);
1266 gsd_endline();
1267
1268 /* TODO -- draw units */
1269
1270 GS_done_draw();
1271
1272 gsd_popmatrix();
1273 gsd_flush();
1274
1275 return 1;
1276}
1277
1278/*!
1279 \brief Primitives only called after transforms
1280
1281 Center is actually center at base of 8 sided cone
1282
1283 \param col color value
1284 */
1285void primitive_cone(unsigned long col)
1286{
1287 float tip[3];
1288 static int first = 1;
1289
1290 if (first) {
1291 init_stuff();
1292 first = 0;
1293 }
1294
1295 tip[X] = tip[Y] = 0.0;
1296 tip[Z] = 1.0;
1297
1298 gsd_bgntfan();
1299 gsd_litvert_func2(UP_NORM, col, tip);
1300 gsd_litvert_func2(ogverts[0], col, ogverts[0]);
1301 gsd_litvert_func2(ogverts[1], col, ogverts[1]);
1302 gsd_litvert_func2(ogverts[2], col, ogverts[2]);
1303 gsd_litvert_func2(ogverts[3], col, ogverts[3]);
1304 gsd_litvert_func2(ogverts[4], col, ogverts[4]);
1305 gsd_litvert_func2(ogverts[5], col, ogverts[5]);
1306 gsd_litvert_func2(ogverts[6], col, ogverts[6]);
1307 gsd_litvert_func2(ogverts[7], col, ogverts[7]);
1308 gsd_litvert_func2(ogverts[0], col, ogverts[0]);
1309 gsd_endtfan();
1310
1311 return;
1312}
1313
1314/*!
1315 \brief Primitives only called after transforms
1316
1317 Center is actually center at base of 8 sided cylinder
1318
1319 \param col color value
1320 \param caps
1321 */
1322void primitive_cylinder(unsigned long col, int caps)
1323{
1324 static int first = 1;
1325
1326 if (first) {
1327 init_stuff();
1328 first = 0;
1329 }
1330
1331 gsd_bgnqstrip();
1333 gsd_litvert_func2(ogverts[0], col, ogverts[0]);
1335 gsd_litvert_func2(ogverts[1], col, ogverts[1]);
1337 gsd_litvert_func2(ogverts[2], col, ogverts[2]);
1339 gsd_litvert_func2(ogverts[3], col, ogverts[3]);
1341 gsd_litvert_func2(ogverts[4], col, ogverts[4]);
1343 gsd_litvert_func2(ogverts[5], col, ogverts[5]);
1345 gsd_litvert_func2(ogverts[6], col, ogverts[6]);
1347 gsd_litvert_func2(ogverts[7], col, ogverts[7]);
1349 gsd_litvert_func2(ogverts[0], col, ogverts[0]);
1350 gsd_endqstrip();
1351
1352 if (caps) {
1353 /* draw top */
1354 gsd_bgntfan();
1365 gsd_endtfan();
1366
1367 /* draw bottom */
1368 gsd_bgntfan();
1379 gsd_endtfan();
1380 }
1381
1382 return;
1383}
1384
1385/*** ACS_MODIFY_BEGIN - sites_attribute management
1386 * ********************************/
1387/*
1388 Draws boxes that are used for histograms by gpd_obj function in gpd.c
1389 for site_attribute management
1390 */
1391
1392/*!
1393 \brief Vertices for box
1394 */
1395float Box[8][3] = {{1.0, 1.0, -1.0}, {-1.0, 1.0, -1.0}, {-1.0, 1.0, 1.0},
1396 {1.0, 1.0, 1.0}, {1.0, -1.0, -1.0}, {-1.0, -1.0, -1.0},
1397 {-1.0, -1.0, 1.0}, {1.0, -1.0, 1.0}};
1398
1399float BoxN[6][3] = {{0, 0, -ONORM}, {0, 0, ONORM}, {0, ONORM, 0},
1400 {0, -ONORM, 0}, {ONORM, 0, 0}, {-ONORM, 0, 0}};
1401
1402/*!
1403 \brief Draw box
1404
1405 Warning siz is an array (we need it for scale only Z in histograms)
1406
1407 \param center center point
1408 \param colr color value
1409 \param siz size value
1410 */
1411void gsd_box(float *center, int colr, float *siz)
1412{
1413 int preshade;
1414
1416 gsd_translate(center[X], center[Y], center[Z] + siz[2]);
1417 gsd_scale(siz[0], siz[1], siz[2]);
1418 preshade = gsd_getshademodel();
1419 gsd_shademodel(0); /* want flat shading */
1420
1421 /* Top */
1423 gsd_litvert_func(BoxN[2], colr, Box[0]);
1424 gsd_litvert_func(BoxN[2], colr, Box[1]);
1425 gsd_litvert_func(BoxN[2], colr, Box[2]);
1426 gsd_litvert_func(BoxN[2], colr, Box[3]);
1428
1429 /* Bottom */
1431 gsd_litvert_func(BoxN[3], colr, Box[7]);
1432 gsd_litvert_func(BoxN[3], colr, Box[6]);
1433 gsd_litvert_func(BoxN[3], colr, Box[5]);
1434 gsd_litvert_func(BoxN[3], colr, Box[4]);
1436
1437 /* Right */
1439 gsd_litvert_func(BoxN[4], colr, Box[0]);
1440 gsd_litvert_func(BoxN[4], colr, Box[3]);
1441 gsd_litvert_func(BoxN[4], colr, Box[7]);
1442 gsd_litvert_func(BoxN[4], colr, Box[4]);
1444
1445 /* Left */
1447 gsd_litvert_func(BoxN[5], colr, Box[1]);
1448 gsd_litvert_func(BoxN[5], colr, Box[5]);
1449 gsd_litvert_func(BoxN[5], colr, Box[6]);
1450 gsd_litvert_func(BoxN[5], colr, Box[2]);
1452
1453 /* Front */
1455 gsd_litvert_func(BoxN[0], colr, Box[0]);
1456 gsd_litvert_func(BoxN[0], colr, Box[4]);
1457 gsd_litvert_func(BoxN[0], colr, Box[5]);
1458 gsd_litvert_func(BoxN[0], colr, Box[1]);
1460
1461 /* Back */
1463 gsd_litvert_func(BoxN[1], colr, Box[3]);
1464 gsd_litvert_func(BoxN[1], colr, Box[2]);
1465 gsd_litvert_func(BoxN[1], colr, Box[6]);
1466 gsd_litvert_func(BoxN[1], colr, Box[7]);
1468
1469 gsd_popmatrix();
1470 gsd_shademodel(preshade);
1471 return;
1472}
1473
1474/*** ACS_MODIFY_END - sites_attribute management
1475 * ********************************/
#define NULL
Definition ccmath.h:32
#define TRUE
Definition dbfopen.c:75
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
void GS_set_draw(int where)
Sets which buffer to draw to.
Definition gs2.c:2459
void GS_done_draw(void)
Draw done, swap buffers.
Definition gs2.c:2498
void GS_v3mult(float *v1, float k)
Multiple vectors.
Definition gs_util.c:229
void GS_v3mag(float *v1, float *mag)
Magnitude of vector.
Definition gs_util.c:418
void GS_v3add(float *v1, float *v2)
Sum vectors.
Definition gs_util.c:195
int GS_v3norm(float *v1)
Change v1 so that it is a unit vector (2D)
Definition gs_util.c:246
void GS_v3eq(float *v1, float *v2)
Copy vector values.
Definition gs_util.c:178
float GS_P2distance(float *from, float *to)
Calculate distance in plane.
Definition gs_util.c:160
int GS_v3dir(float *v1, float *v2, float *v3)
Get a normalized direction from v1 to v2, store in v3.
Definition gs_util.c:351
void GS_v3cross(float *v1, float *v2, float *v3)
Get the cross product v3 = v1 cross v2.
Definition gs_util.c:403
int gsd_get_txtwidth(const char *s, int size)
Get text width.
Definition gsd_fonts.c:36
int gsd_get_txtheight(int size)
Get text height.
Definition gsd_fonts.c:53
float Ntop[]
Definition gsd_fringe.c:36
void gsd_3dcursor(float *pt)
Draw 3d cursor.
Definition gsd_objs.c:688
void gsd_diamond(float *center, unsigned long colr, float siz)
Draw diamond symbol.
Definition gsd_objs.c:305
void primitive_cylinder(unsigned long col, int caps)
Primitives only called after transforms.
Definition gsd_objs.c:1322
float Box[8][3]
Vertices for box.
Definition gsd_objs.c:1395
void gsd_draw_box(float *center, unsigned long colr, float siz)
Draw box.
Definition gsd_objs.c:483
#define UP_NORM
Definition gsd_objs.c:68
float CubeNormals[3][3]
Definition gsd_objs.c:60
void gsd_3darrow(float *center, unsigned long colr, float siz1, float siz2, float *dir, float sz)
Draw 3d north arrow.
Definition gsd_objs.c:1057
float CubeVertices[8][3]
Definition gsd_objs.c:62
#define DOWN_NORM
Definition gsd_objs.c:69
void gsd_line_onsurf(geosurf *gs, float *v1, float *v2)
Line on surface, fix z-values.
Definition gsd_objs.c:167
int gsd_arrow(float *center, unsigned long colr, float siz, float *dir, float sz, geosurf *onsurf)
ADD.
Definition gsd_objs.c:898
void gsd_x(geosurf *gs, float *center, int colr, float siz)
Draw X symbol.
Definition gsd_objs.c:256
float Pi
Definition gsd_objs.c:82
#define ORIGIN
Definition gsd_objs.c:70
void gsd_drawsphere(float *center, unsigned long colr, float siz)
Draw sphere.
Definition gsd_objs.c:542
int gsd_north_arrow(float *pos2, float len, GLuint fontbase, unsigned long arw_clr, unsigned long text_clr)
Draw North Arrow takes OpenGL coords and size.
Definition gsd_objs.c:803
int gsd_scalebar_v2(float *pos, float len, GLuint fontbase UNUSED, unsigned long bar_clr, unsigned long text_clr UNUSED)
Draw Scalebar (as lines)
Definition gsd_objs.c:1222
float BoxN[6][3]
Definition gsd_objs.c:1399
float ogverts[8][3]
vertices & normals for octagon in xy plane
Definition gsd_objs.c:75
void gsd_cube(float *center, unsigned long colr, float siz)
Draw cube.
Definition gsd_objs.c:407
int gsd_nline_onsurf(geosurf *gs, float *v1, float *v2, float *pt, int n)
Multiline on surface, fix z-values.
Definition gsd_objs.c:213
void gsd_diamond_lines(void)
Draw diamond lines.
Definition gsd_objs.c:554
int gsd_arrow_onsurf(float *base, float *tip, unsigned long colr, int wid, geosurf *gs)
Draw north arrow on surface.
Definition gsd_objs.c:970
int gsd_scalebar(float *pos2, float len, GLuint fontbase, unsigned long bar_clr, unsigned long text_clr)
Draw Scalebar takes OpenGL coords and size.
Definition gsd_objs.c:1136
float OctoN[8][3]
normals for flat-shaded octahedron
Definition gsd_objs.c:42
float ogvertsplus[8][3]
vertices for octagon in xy plane, z=1
Definition gsd_objs.c:80
void primitive_cone(unsigned long col)
Primitives only called after transforms.
Definition gsd_objs.c:1285
void dir_to_slope_aspect(float *dir, float *slope, float *aspect, int degrees)
ADD.
Definition gsd_objs.c:732
float Octo[6][3]
vertices for octahedron
Definition gsd_objs.c:34
void gsd_draw_asterisk(float *center, unsigned long colr, float siz)
Draw asterisk.
Definition gsd_objs.c:581
#define ONORM
Definition gsd_objs.c:37
void gsd_box(float *center, int colr, float *siz)
Draw box.
Definition gsd_objs.c:1411
void gsd_draw_gyro(float *center, unsigned long colr, float siz)
Draw gyro.
Definition gsd_objs.c:636
void gsd_plus(float *center, int colr, float siz)
ADD.
Definition gsd_objs.c:130
float origin[3]
Definition gsd_objs.c:66
void gsd_endlist(void)
End list.
Definition gsd_prim.c:1140
void gsd_endtfan(void)
ADD.
Definition gsd_prim.c:347
void gsd_endtmesh(void)
ADD.
Definition gsd_prim.c:307
void gsd_swaptmesh(void)
ADD.
Definition gsd_prim.c:357
void gsd_backface(int n)
ADD.
Definition gsd_prim.c:254
void gsd_pushmatrix(void)
Push the current matrix stack.
Definition gsd_prim.c:511
void gsd_litvert_func2(float *norm, unsigned long col UNUSED, float *pt)
ADD.
Definition gsd_prim.c:673
void gsd_calllist(int listno)
ADD.
Definition gsd_prim.c:1173
void gsd_vert_func(float *pt)
ADD.
Definition gsd_prim.c:686
void gsd_bgnqstrip(void)
ADD.
Definition gsd_prim.c:277
void gsd_litvert_func(float *norm, unsigned long col, float *pt)
Set the current normal vector & specify vertex.
Definition gsd_prim.c:657
void gsd_bgnpolygon(void)
Delimit the vertices of a primitive or a group of like primitives.
Definition gsd_prim.c:372
int gsd_getshademodel(void)
Get shaded model.
Definition gsd_prim.c:438
void gsd_bgnlist(int listno, int do_draw)
ADD.
Definition gsd_prim.c:1125
int gsd_makelist(void)
ADD.
Definition gsd_prim.c:1094
void gsd_endqstrip(void)
ADD.
Definition gsd_prim.c:287
void gsd_sphere(float *center, float siz)
ADD.
Definition gsd_prim.c:207
void gsd_popmatrix(void)
Pop the current matrix stack.
Definition gsd_prim.c:501
void gsd_flush(void)
Mostly for flushing drawing commands across a network.
Definition gsd_prim.c:84
void gsd_endline(void)
End line.
Definition gsd_prim.c:407
void gsd_circ(float x, float y, float rad)
ADD.
Definition gsd_prim.c:167
void gsd_bgntfan(void)
ADD.
Definition gsd_prim.c:337
void gsd_rot(float angle, char axis)
ADD.
Definition gsd_prim.c:605
void gsd_bgnline(void)
Begin line.
Definition gsd_prim.c:397
void gsd_scale(float xs, float ys, float zs)
Multiply the current matrix by a general scaling matrix.
Definition gsd_prim.c:525
void gsd_translate(float dx, float dy, float dz)
Multiply the current matrix by a translation matrix.
Definition gsd_prim.c:539
void gsd_bgntmesh(void)
ADD.
Definition gsd_prim.c:297
void gsd_disc(float x, float y, float z, float rad)
ADD.
Definition gsd_prim.c:187
void gsd_color_func(unsigned int col)
Set current color.
Definition gsd_prim.c:698
void gsd_shademodel(int shade)
Set shaded model.
Definition gsd_prim.c:419
void gsd_endpolygon(void)
Delimit the vertices of a primitive or a group of like primitives.
Definition gsd_prim.c:387
void gsd_linewidth(short n)
Set width of rasterized lines.
Definition gsd_prim.c:267
void gsd_do_scale(int doexag)
Set current scale.
Definition gsd_views.c:355
Point3 * gsdrape_get_segments(geosurf *gs, float *bgn, float *end, int *num)
ADD.
Definition gsdrape.c:349
const char * G_database_unit_name(int plural)
Get units (localized) name for the current location.
Definition proj3.c:53
struct list * list
Definition read_list.c:24
#define X(j)
#define Y(j)