]> Pileus Git - grits/blob - src/objects/grits-poly.c
da35b36c792333b7d043a174253f8be137997c3a
[grits] / src / objects / grits-poly.c
1 /*
2  * Copyright (C) 2010 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /**
19  * SECTION:grits-poly
20  * @short_description: Single point polys
21  *
22  * Each #GritsPoly represents a 3 dimentional polygon.
23  */
24
25 #include <config.h>
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28 #include "grits-poly.h"
29
30 /* Drawing */
31 static void grits_poly_tess(gdouble (**points)[3])
32 {
33         //g_debug("GritsPoly: tess");
34         GLUtesselator *tess = gluNewTess();
35         gluTessCallback(tess, GLU_TESS_BEGIN,  (_GLUfuncptr)glBegin);
36         gluTessCallback(tess, GLU_TESS_VERTEX, (_GLUfuncptr)glVertex3dv);
37         gluTessCallback(tess, GLU_TESS_END,    (_GLUfuncptr)glEnd);
38         gluTessBeginPolygon(tess, NULL);
39         for (int pi = 0; points[pi]; pi++) {
40                 gluTessBeginContour(tess);
41                 for (int ci = 0; points[pi][ci][0]; ci++) {
42                         gluTessVertex(tess,
43                                 points[pi][ci],
44                                 points[pi][ci]);
45                 }
46                 gluTessEndContour(tess);
47         }
48         gluTessEndPolygon(tess);
49         gluDeleteTess(tess);
50 }
51
52 static void grits_poly_outline(gdouble (**points)[3])
53 {
54         //g_debug("GritsPoly: outline");
55         for (int pi = 0; points[pi]; pi++) {
56                 glBegin(GL_LINE_LOOP);
57                 for (int ci = 0; points[pi][ci][0] &&
58                                  points[pi][ci][1] &&
59                                  points[pi][ci][2]; ci++)
60                         glVertex3dv(points[pi][ci]);
61                 glEnd();
62                 glBegin(GL_POINTS);
63                 for (int ci = 0; points[pi][ci][0] &&
64                                  points[pi][ci][1] &&
65                                  points[pi][ci][2]; ci++)
66                         glVertex3dv(points[pi][ci]);
67                 glEnd();
68         }
69 }
70 static gboolean grits_poly_genlist(gpointer _poly)
71 {
72         //g_debug("GritsPoly: genlist");
73         GritsPoly *poly = GRITS_POLY(_poly);
74         guint list = glGenLists(2);
75         glNewList(list+0, GL_COMPILE);
76         grits_poly_tess(poly->points);
77         glEndList();
78         glNewList(list+1, GL_COMPILE);
79         grits_poly_outline(poly->points);
80         glEndList();
81         poly->list = list;
82         return FALSE;
83 }
84
85 static void grits_poly_draw(GritsObject *_poly, GritsOpenGL *opengl)
86 {
87         //g_debug("GritsPoly: draw");
88         GritsPoly *poly = GRITS_POLY(_poly);
89
90         if (!poly->list)
91                 return;
92
93         glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_CURRENT_BIT);
94         glDisable(GL_TEXTURE_2D);
95         glDisable(GL_ALPHA_TEST);
96         glDisable(GL_CULL_FACE);
97         glDisable(GL_LIGHTING);
98         glEnable(GL_POLYGON_OFFSET_FILL);
99         glPolygonOffset(1, 1);
100         if (poly->color[3]) {
101                 glColor4dv(poly->color);
102                 glCallList(poly->list+0);
103         }
104         if (poly->border[3]) {
105                 glPointSize(poly->width);
106                 glLineWidth(poly->width);
107                 glColor4dv(poly->border);
108                 glCallList(poly->list+1);
109         }
110         glPopAttrib();
111 }
112
113 static void grits_poly_pick(GritsObject *_poly, GritsOpenGL *opengl)
114 {
115         //g_debug("GritsPoly: pick");
116         GritsPoly *poly = GRITS_POLY(_poly);
117         if (!poly->list)
118                 return;
119         glPushAttrib(GL_ENABLE_BIT);
120         glDisable(GL_CULL_FACE);
121         glCallList(poly->list+0);
122         glPopAttrib();
123 }
124
125 /**
126  * grits_poly_new:
127  * @points:  TODO
128  * @npoints: TODO
129  *
130  * Create a new GritsPoly which TODO.
131  *
132  * Returns: the new #GritsPoly.
133  */
134 GritsPoly *grits_poly_new(gdouble (**points)[3])
135 {
136         //g_debug("GritsPoly: new - %p", points);
137         GritsPoly *poly = g_object_new(GRITS_TYPE_POLY, NULL);
138         poly->points    = points;
139         g_idle_add(grits_poly_genlist, poly);
140         return poly;
141 }
142
143 GritsPoly *grits_poly_parse(const gchar *str,
144                 const gchar *poly_sep, const gchar *point_sep, const gchar *coord_sep)
145 {
146         /* Split and count polygons */
147         gchar **spolys = g_strsplit(str, poly_sep, -1);
148         int     npolys = g_strv_length(spolys);
149
150         GritsBounds bounds = {-90, 90, -180, 180};
151         gdouble (**polys)[3] = (gpointer)g_new0(double*, npolys+1);
152         for (int pi = 0; pi < npolys; pi++) {
153                 /* Split and count coordinates */
154                 gchar **scoords = g_strsplit(spolys[pi], point_sep, -1);
155                 int     ncoords = g_strv_length(scoords);
156
157                 /* Create binary coords */
158                 gdouble (*coords)[3] = (gpointer)g_new0(gdouble, 3*(ncoords+1));
159                 for (int ci = 0; ci < ncoords; ci++) {
160                         gdouble lat, lon;
161                         sscanf(scoords[ci], "%lf,%lf", &lat, &lon);
162                         if (lat > bounds.n) bounds.n = lat;
163                         if (lat < bounds.s) bounds.s = lat;
164                         if (lon > bounds.e) bounds.e = lon;
165                         if (lon < bounds.w) bounds.w = lon;
166                         lle2xyz(lat, lon, 0,
167                                         &coords[ci][0],
168                                         &coords[ci][1],
169                                         &coords[ci][2]);
170                 }
171
172                 /* Insert coords into poly array */
173                 polys[pi] = coords;
174                 g_strfreev(scoords);
175         }
176
177         /* Create GritsPoly */
178         GritsPoly *poly = grits_poly_new(polys);
179         GRITS_OBJECT(poly)->center.lat  = (bounds.n + bounds.s)/2;
180         GRITS_OBJECT(poly)->center.lon  = lon_avg(bounds.e, bounds.w);
181         GRITS_OBJECT(poly)->center.elev = 0;
182         GRITS_OBJECT(poly)->skip        = GRITS_SKIP_CENTER;
183         return poly;
184 }
185
186 /* GObject code */
187 G_DEFINE_TYPE(GritsPoly, grits_poly, GRITS_TYPE_OBJECT);
188 static void grits_poly_init(GritsPoly *poly)
189 {
190         poly->border[0] = 1;
191         poly->border[1] = 1;
192         poly->border[2] = 1;
193         poly->border[3] = 0.2;
194         poly->width     = 1;
195 }
196
197 static void grits_poly_finalize(GObject *_poly)
198 {
199         g_debug("GritsPoly: finalize");
200         GritsPoly *poly = GRITS_POLY(_poly);
201         (void)poly;
202         // TODO: free points
203 }
204
205 static void grits_poly_class_init(GritsPolyClass *klass)
206 {
207         g_debug("GritsPoly: class_init");
208         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
209         gobject_class->finalize = grits_poly_finalize;
210
211         GritsObjectClass *object_class = GRITS_OBJECT_CLASS(klass);
212         object_class->draw = grits_poly_draw;
213         object_class->pick = grits_poly_pick;
214 }