source: subversion/applications/utils/coastcheck/osm2coast.c @ 9744

Last change on this file since 9744 was 7969, checked in by martinvoosterhout, 12 years ago

No new features, just plenty of error checking, growing the nodes array and
plugging some memory leaks.

File size: 9.1 KB
Line 
1/*
2#-----------------------------------------------------------------------------
3# osm2coast - extracts coastline data from planet.
4# Use: osm2coast planet.osm.gz >coastline.osm
5#-----------------------------------------------------------------------------
6# by Martijn van Oosterhout 2007
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License
10# as published by the Free Software Foundation; either version 2
11# of the License, or (at your option) any later version.
12#
13# This program 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
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21#-----------------------------------------------------------------------------
22*/
23
24#define _GNU_SOURCE
25#include <stdio.h>
26#include <unistd.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
30#include <getopt.h>
31#include <errno.h>
32#include <math.h>
33#include <stdint.h>
34
35#include <libxml/xmlstring.h>
36#include <libxml/xmlreader.h>
37
38#include "input.h"
39
40#define MAX_NODE_ID (300*1024*1024)
41#define MAX_NODES_PER_WAY 10000
42
43static int count_node,    max_node;
44static int count_way,     max_way;
45static int count_rel,     max_rel;
46
47/* Since {node,way} elements are not nested we can guarantee the
48   values in an end tag must match those of the corresponding
49   start tag and can therefore be cached.
50*/
51static double node_lon, node_lat;
52static int32_t *nds;
53static int nd_count;
54static unsigned char *bitmap;
55int pass, wanted;
56static int osm_id;
57
58static void printStatus(void)
59{
60  if( isatty(STDERR_FILENO) )
61    fprintf(stderr, "\rProcessing: Node(%dk) Way(%dk) Relation(%dk)",
62            count_node/1000, count_way/1000, count_rel/1000);
63}
64
65
66void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
67{
68    xmlChar *xid, *xlat, *xlon, *xk, *xv /*, *xrole, *xtype*/;
69
70    if (xmlStrEqual(name, BAD_CAST "node")) {
71        if( pass == 1 )
72        {
73            xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
74            xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
75            xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
76            assert(xid); assert(xlon); assert(xlat);
77
78            osm_id  = strtol((char *)xid, NULL, 10);
79            node_lon = strtod((char *)xlon, NULL);
80            node_lat = strtod((char *)xlat, NULL);
81
82            if (osm_id > max_node)
83                max_node = osm_id;
84
85            xmlFree(xid);
86            xmlFree(xlon);
87            xmlFree(xlat);
88        }
89        count_node++;
90        if (count_node%10000 == 0)
91            printStatus();
92    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
93        if( pass == 0 )
94        {
95            xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
96            xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
97            assert(xk);
98
99            /* 'created_by' and 'source' are common and not interesting to mapnik renderer */
100            if (strcmp((char *)xk, "natural")==0 && strcmp((char *)xv, "coastline")==0)
101                wanted = 1;
102            xmlFree(xv);
103            xmlFree(xk);
104        }
105    } else if (xmlStrEqual(name, BAD_CAST "way")) {
106        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
107        assert(xid);
108        osm_id = strtol((char *)xid, NULL, 10);
109
110        if (osm_id > max_way)
111            max_way = osm_id;
112
113        count_way++;
114        if (count_way%1000 == 0)
115            printStatus();
116
117        wanted = 0;
118        nd_count = 0;
119        xmlFree(xid);
120    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
121        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
122        assert(xid);
123
124        int id = strtol((char *)xid, NULL, 10);
125        if( id > 0 && nd_count < MAX_NODES_PER_WAY)
126            nds[nd_count++] = id;
127        xmlFree(xid);
128    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
129        count_rel++;
130        if (count_rel%1000 == 0)
131            printStatus();
132
133    } else if (xmlStrEqual(name, BAD_CAST "member")) {
134        /* ignore */
135    } else if (xmlStrEqual(name, BAD_CAST "osm")) {
136        /* ignore */
137    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
138        /* ignore */
139    } else {
140        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
141    }
142}
143
144void EndElement(const xmlChar *name)
145{
146    if (xmlStrEqual(name, BAD_CAST "node")) {
147        if( pass == 1 )
148        {
149            if( osm_id > MAX_NODE_ID )
150            {
151              fprintf( stderr, "Exceeded maximum node ID: %d\n", MAX_NODE_ID );
152              exit(1);
153            }
154            if( bitmap[ osm_id >> 3 ] & (1<<(osm_id&7)) )
155                printf( "<node id=\"%d\" lat=\"%f\" lon=\"%f\" />\n", osm_id, node_lat, node_lon );
156        }
157    } else if (xmlStrEqual(name, BAD_CAST "way")) {
158        if( nd_count >= MAX_NODES_PER_WAY )
159        {
160            fprintf(stderr, "Exceeded maximum node count (%d >= %d) way=%d\n", nd_count, MAX_NODES_PER_WAY, osm_id );
161        }
162
163        if( pass == 0 && wanted )
164        {
165            int i;
166            printf( "<way id=\"%d\">\n", osm_id );
167            for( i=0; i<nd_count; i++ )
168            {
169                if( nds[i] > MAX_NODE_ID )
170                {
171                  fprintf( stderr, "Exceeded maximum node ID: %d\n", MAX_NODE_ID );
172                  exit(1);
173                }
174                bitmap[ nds[i] >> 3 ] |= (1<<(nds[i]&7));
175                printf( "<nd ref=\"%d\" />\n", nds[i] );
176            }
177            printf( "</way>\n" );
178        }
179    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
180        /* ignore */
181    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
182        /* ignore */
183    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
184        /* ignore */
185    } else if (xmlStrEqual(name, BAD_CAST "member")) {
186        /* ignore */
187    } else if (xmlStrEqual(name, BAD_CAST "osm")) {
188        printStatus();
189    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
190        /* ignore */
191    } else {
192        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
193    }
194}
195
196static void processNode(xmlTextReaderPtr reader) {
197    xmlChar *name;
198    name = xmlTextReaderName(reader);
199    if (name == NULL)
200        name = xmlStrdup(BAD_CAST "--");
201       
202    switch(xmlTextReaderNodeType(reader)) {
203        case XML_READER_TYPE_ELEMENT:
204            StartElement(reader, name);
205            if (xmlTextReaderIsEmptyElement(reader))
206                EndElement(name); /* No end_element for self closing tags! */
207            break;
208        case XML_READER_TYPE_END_ELEMENT:
209            EndElement(name);
210            break;
211        case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
212            /* Ignore */
213            break;
214        default:
215            fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
216            break;
217    }
218
219    xmlFree(name);
220}
221
222static int streamFile(char *filename) {
223    xmlTextReaderPtr reader;
224    int ret = 0;
225
226    reader = inputUTF8(filename);
227
228    if (reader != NULL) {
229        ret = xmlTextReaderRead(reader);
230        while (ret == 1) {
231            processNode(reader);
232            ret = xmlTextReaderRead(reader);
233        }
234
235        if (ret != 0) {
236            fprintf(stderr, "%s : failed to parse\n", filename);
237            return ret;
238        }
239
240        xmlFreeTextReader(reader);
241    } else {
242        fprintf(stderr, "Unable to open %s\n", filename);
243        return 1;
244    }
245    return 0;
246}
247
248void exit_nicely(void)
249{
250    fprintf(stderr, "Error occurred, cleaning up\n");
251    exit(1);
252}
253 
254static void usage(const char *arg0)
255{
256    const char *name = basename(arg0);
257
258    fprintf(stderr, "Usage:\n");
259    fprintf(stderr, "\t%s planet.osm.gz >coastline.osm\n", name);
260    fprintf(stderr, "\n");
261}
262
263int main(int argc, char *argv[])
264{
265    fprintf(stderr, "osm2coast SVN version %s $Rev: 4895 $ \n", VERSION);
266
267    if (argc != 2) {
268        usage(argv[0]);
269        exit(EXIT_FAILURE);
270    }
271   
272    nice(10);
273
274    LIBXML_TEST_VERSION
275
276    nds = malloc( sizeof(nds[0]) * MAX_NODES_PER_WAY );
277    bitmap = calloc( MAX_NODE_ID /8 + 1, 1 );
278   
279    count_node = max_node = 0;
280    count_way = max_way = 0;
281    count_rel = max_rel = 0;
282
283    printf("<osm version=\"0.5\">\n");
284    fprintf(stderr, "\nReading in file: %s\n", argv[1]);
285    if (streamFile(argv[1]) != 0)
286        exit_nicely();
287
288    pass = 1;
289   
290    count_node = max_node = 0;
291    count_way = max_way = 0;
292    count_rel = max_rel = 0;
293
294    fprintf(stderr, "\nReading in file: %s\n", argv[1]);
295    if (streamFile(argv[1]) != 0)
296        exit_nicely();
297
298    /* Try to detect output error */
299    if( printf("</osm>\n") < 0 )
300      exit(1);
301    xmlCleanupParser();
302    xmlMemoryDump();
303
304    if (count_node || count_way || count_rel) {
305        fprintf(stderr, "\n");
306        fprintf(stderr, "Node stats: total(%d), max(%d)\n", count_node, max_node);
307        fprintf(stderr, "Way stats: total(%d), max(%d)\n", count_way, max_way);
308        fprintf(stderr, "Relation stats: total(%d), max(%d)\n", count_rel, max_rel);
309    }
310
311    return 0;
312}
313
Note: See TracBrowser for help on using the repository browser.