diff options
Diffstat (limited to '')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/plugins/import/imp_osm/imp_osm.c | 334 |
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 | |||
38 | typedef struct { | ||
39 | guint32 length; | ||
40 | guint32 *ids; | ||
41 | } OSMNodeTransList; | ||
42 | |||
43 | typedef struct { | ||
44 | const gchar *name; | ||
45 | gdouble r, g, b, a; | ||
46 | } OSMMaterial; | ||
47 | |||
48 | static 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 | |||
59 | static int osm_input_read_cb(gpointer ctx, gchar *buffer, gint len); | ||
60 | static void osm_add_node(G3DObject *object, OSMNodeTransList *translist, | ||
61 | xmlNodePtr node); | ||
62 | static void osm_add_way(G3DObject *object, OSMNodeTransList *translist, | ||
63 | xmlNodePtr node, GHashTable *materials); | ||
64 | |||
65 | EAPI | ||
66 | gboolean 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 | |||
140 | EAPI | ||
141 | char *plugin_description(void) | ||
142 | { | ||
143 | return g_strdup("OpenStreetMap maps."); | ||
144 | } | ||
145 | |||
146 | EAPI | ||
147 | char **plugin_extensions(void) | ||
148 | { | ||
149 | return g_strsplit("osm", ":", 0); | ||
150 | } | ||
151 | |||
152 | /*****************************************************************************/ | ||
153 | /* helper functions | ||
154 | *****************************************************************************/ | ||
155 | |||
156 | static 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 | |||
164 | static 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 | |||
181 | static 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 | |||
195 | static 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 | |||
205 | static 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 | |||
229 | static 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 | |||
294 | static 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 | } | ||