aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c')
-rw-r--r--src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c
new file mode 100644
index 0000000..f541925
--- /dev/null
+++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c
@@ -0,0 +1,334 @@
1/* $Id$ */
2
3/*
4 libg3d - 3D object loading library
5
6 Copyright (C) 2005-2009 Markus Dahms <mad@automagically.de>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
23#include <string.h>
24#include <locale.h>
25#include <math.h>
26
27#include <libxml/parser.h>
28#include <libxml/tree.h>
29
30#include <g3d/types.h>
31#include <g3d/stream.h>
32#include <g3d/material.h>
33#include <g3d/object.h>
34#include <g3d/vector.h>
35#include <g3d/matrix.h>
36#include <g3d/primitive.h>
37
38typedef struct {
39 guint32 length;
40 guint32 *ids;
41} OSMNodeTransList;
42
43typedef struct {
44 const gchar *name;
45 gdouble r, g, b, a;
46} OSMMaterial;
47
48static OSMMaterial osm_materials[] = {
49 { "default", 0.7, 0.7, 0.7, 0.7 },
50 { "highway:primary", 1.0, 0.8, 0.1, 1.0 },
51 { "highway:secondary", 1.0, 0.2, 0.2, 1.0 },
52 { "highway:footway", 0.2, 1.0, 0.2, 1.0 },
53 { "waterway:canal", 0.0, 0.1, 1.0, 0.7 },
54 { "waterway:river", 0.0, 0.4, 1.0, 0.7 },
55 { "waterway:riverbank", 0.0, 0.4, 1.0, 0.7 },
56 { NULL, 0.0, 0.0, 0.0, 0.0 }
57};
58
59static int osm_input_read_cb(gpointer ctx, gchar *buffer, gint len);
60static void osm_add_node(G3DObject *object, OSMNodeTransList *translist,
61 xmlNodePtr node);
62static void osm_add_way(G3DObject *object, OSMNodeTransList *translist,
63 xmlNodePtr node, GHashTable *materials);
64
65EAPI
66gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream,
67 G3DModel *model)
68{
69 xmlDocPtr xmldoc;
70 xmlNodePtr rootnode, node;
71 OSMNodeTransList *translist;
72 G3DObject *object;
73 GHashTable *materials;
74 G3DMaterial *material;
75 OSMMaterial *mentry;
76
77 setlocale(LC_NUMERIC, "C");
78
79 xmlInitParser();
80
81 xmldoc = xmlReadIO(osm_input_read_cb, NULL, stream, stream->uri, NULL, 0);
82 if(xmldoc == NULL) {
83 g_warning("OSM: failed to parse XML file '%s'", stream->uri);
84 xmlCleanupParser();
85 return FALSE;
86 }
87
88 /* create material table */
89 materials = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
90 for(mentry = osm_materials; mentry->name != NULL; mentry ++) {
91 material = g3d_material_new();
92 material->name = g_strdup(mentry->name);
93 material->r = mentry->r;
94 material->g = mentry->g;
95 material->b = mentry->b;
96 material->a = mentry->a;
97 model->materials = g_slist_append(model->materials, material);
98 g_hash_table_insert(materials, g_strdup(material->name), material);
99 }
100
101 translist = g_new0(OSMNodeTransList, 1);
102 object = g_new0(G3DObject, 1);
103 object->name = g_strdup("OpenStreetMap object");
104 model->objects = g_slist_append(model->objects, object);
105
106 rootnode = xmlDocGetRootElement(xmldoc);
107 for(node = rootnode->children; node != NULL; node = node->next) {
108 /* skip non-element nodes */
109 if(node->type != XML_ELEMENT_NODE)
110 continue;
111
112 if(xmlStrcmp((xmlChar *)"node", node->name) == 0) {
113 /* "node" nodes */
114 osm_add_node(object, translist, node);
115 } else if(xmlStrcmp((xmlChar *)"way", node->name) == 0) {
116 /* "way" nodes */
117 osm_add_way(object, translist, node, materials);
118 } else if(xmlStrcmp((xmlChar *)"relation", node->name) == 0) {
119 /* "relation" nodes */
120 }
121 }
122
123 /* clean up */
124 if(object->vertex_data) {
125 /* reference points not needed anymore */
126 g_free(object->vertex_data);
127 object->vertex_data = NULL;
128 object->vertex_count = 0;
129 }
130 g_hash_table_destroy(materials);
131 if(translist->ids)
132 g_free(translist->ids);
133 g_free(translist);
134 xmlFreeDoc(xmldoc);
135 xmlCleanupParser();
136
137 return TRUE;
138}
139
140EAPI
141char *plugin_description(void)
142{
143 return g_strdup("OpenStreetMap maps.");
144}
145
146EAPI
147char **plugin_extensions(void)
148{
149 return g_strsplit("osm", ":", 0);
150}
151
152/*****************************************************************************/
153/* helper functions
154 *****************************************************************************/
155
156static int osm_input_read_cb(gpointer ctx, gchar *buffer, gint len)
157{
158 return g3d_stream_read((G3DStream *)ctx, buffer, len);
159}
160
161#if 0
162#define G(i) (gdouble)(i)
163
164static gdouble misc_angle(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
165{
166 gdouble at;
167
168 if(x1 == x2) {
169 if(y1 > y2)
170 return G_PI * 1.5;
171 else
172 return G_PI / 2.0;
173 }
174 at = atan((G(y2) - G(y1)) / (G(x2) - G(x1)));
175 if(x2 < x1)
176 return G_PI + at;
177 else
178 return at;
179}
180
181static gdouble misc_delta(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
182{
183 gdouble a, b;
184
185 a = ABS(G(x2) - G(x1));
186 b = ABS(G(y2) - G(y1));
187 return sqrt(a * a + b * b);
188}
189#endif
190
191/*****************************************************************************/
192/* OSM specific functions
193 *****************************************************************************/
194
195static gint32 osm_translist_lookup(OSMNodeTransList *translist, guint32 id)
196{
197 gint32 i;
198
199 for(i = 0; i < translist->length; i ++)
200 if(translist->ids[i] == id)
201 return i;
202 return -1;
203}
204
205static void osm_add_node(G3DObject *object, OSMNodeTransList *translist,
206 xmlNodePtr node)
207{
208 gdouble lat, lon;
209
210 lat = strtod((char *)xmlGetProp(node, (xmlChar *)"lat"), NULL);
211 lon = strtod((char *)xmlGetProp(node, (xmlChar *)"lon"), NULL);
212
213 translist->length ++;
214 translist->ids = g_realloc(translist->ids,
215 translist->length * sizeof(guint32));
216 translist->ids[translist->length - 1] = strtoul(
217 (char *)xmlGetProp(node, (xmlChar *)"id"), NULL, 10);
218
219 object->vertex_count ++;
220 object->vertex_data = g_realloc(object->vertex_data,
221 object->vertex_count * sizeof(gdouble) * 3);
222 object->vertex_data[(object->vertex_count - 1) * 3 + 0] =
223 (lat * G_PI / 180) * cos(lon * G_PI / 180) * 180 / G_PI;
224 object->vertex_data[(object->vertex_count - 1) * 3 + 1] = 0.0;
225 object->vertex_data[(object->vertex_count - 1) * 3 + 2] =
226 (lat * G_PI / 180) * sin(lon * G_PI / 180) * 180 / G_PI;
227}
228
229static void osm_add_street(G3DObject *object, OSMNodeTransList *translist,
230 guint32 refcount, guint32 *refdata,
231 GHashTable *tags, GHashTable *materials)
232{
233 gint32 i, n;
234 gdouble *vdata;
235 G3DFloat matrix[16];
236 G3DObject *ostreet = NULL;
237 gchar *name, *mname;
238 G3DMaterial *material = NULL;
239
240 /* lookup material */
241 name = g_hash_table_lookup(tags, "highway");
242 if(name != NULL) {
243 mname = g_strdup_printf("highway:%s", name);
244 material = g_hash_table_lookup(materials, mname);
245 g_free(mname);
246 } else {
247 name = g_hash_table_lookup(tags, "waterway");
248 if(name != NULL) {
249 mname = g_strdup_printf("waterway:%s", name);
250 material = g_hash_table_lookup(materials, mname);
251 g_free(mname);
252 }
253 }
254 if(material == NULL) {
255 material = g_hash_table_lookup(materials, "default");
256 g_return_if_fail(material != NULL);
257 }
258
259 /* create strip */
260 vdata = g_new0(gdouble, refcount * 2);
261 for(i = 0; i < refcount; i ++) {
262 n = osm_translist_lookup(translist, refdata[i]);
263 if(n == -1) {
264 g_warning("OSM: looking up reference %d failed", refdata[i]);
265 continue;
266 }
267 vdata[i * 2 + 0] = object->vertex_data[n * 3 + 0];
268 vdata[i * 2 + 1] = object->vertex_data[n * 3 + 2];
269 }
270 ostreet = g3d_primitive_box_strip_2d(refcount, vdata, 0.00003, 0.0003,
271 material);
272 g_free(vdata);
273
274 if(ostreet == NULL)
275 return;
276
277 /* bridge? */
278 name = g_hash_table_lookup(tags, "bridge");
279 if(name && (strcmp(name, "true") == 0)) {
280 g3d_matrix_identity(matrix);
281 g3d_matrix_translate(0.0, 0.00005, 0.0, matrix);
282 g3d_object_transform(ostreet, matrix);
283 }
284
285 /* name? */
286 name = g_hash_table_lookup(tags, "name");
287 if(name == NULL)
288 ostreet->name = g_strdup("unnamed street");
289 else
290 ostreet->name = g_strdup(name);
291 object->objects = g_slist_append(object->objects, ostreet);
292}
293
294static void osm_add_way(G3DObject *object, OSMNodeTransList *translist,
295 xmlNodePtr node, GHashTable *materials)
296{
297 guint32 refcount = 0;
298 guint32 *refdata = NULL;
299 GHashTable *tags;
300 xmlNodePtr subnode;
301
302 tags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
303
304 /* parse subnodes */
305 for(subnode = node->children; subnode != NULL; subnode = subnode->next) {
306 if(subnode->type != XML_ELEMENT_NODE)
307 continue;
308
309 if(xmlStrcmp((xmlChar *)"nd", subnode->name) == 0) {
310 refcount ++;
311 refdata = g_realloc(refdata, refcount * sizeof(guint32));
312 refdata[refcount - 1] = strtoul(
313 (char *)xmlGetProp(subnode, (xmlChar *)"ref"), NULL, 10);
314 } else if(xmlStrcmp((xmlChar *)"tag", subnode->name) == 0) {
315 g_hash_table_insert(tags,
316 g_strdup((char *)xmlGetProp(subnode, (xmlChar *)"k")),
317 g_strdup((char *)xmlGetProp(subnode, (xmlChar *)"v")));
318 } else {
319 /* unknown "way" subnode */
320 g_debug("OSM: 'way': unknown subnode '%s'",
321 (gchar *)subnode->name);
322 }
323 }
324
325 /* do something with the collected data */
326 if((g_hash_table_lookup(tags, "highway") != NULL) ||
327 (g_hash_table_lookup(tags, "waterway") != NULL))
328 osm_add_street(object, translist, refcount, refdata, tags, materials);
329
330 /* clean up */
331 g_hash_table_destroy(tags);
332 if(refdata)
333 g_free(refdata);
334}