source: subversion/utils/osm2pgsql/osm2pgsql.c @ 2153

Last change on this file since 2153 was 2153, checked in by jonb, 13 years ago

Make mapnik & osm2pgsql use NULL instead of empty strings in db

File size: 18.8 KB
Line 
1/*
2#-----------------------------------------------------------------------------
3# osm2pgsql - converts planet.osm file into PostgreSQL
4# compatible output suitable to be rendered by mapnik
5# Use: osm2pgsql planet.osm > planet.sql
6#-----------------------------------------------------------------------------
7# Original Python implementation by Artem Pavlenko
8# Re-implementation by Jon Burgess, Copyright 2006
9#
10# This program is free software; you can redistribute it and/or
11# modify it under the terms of the GNU General Public License
12# as published by the Free Software Foundation; either version 2
13# of the License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23#-----------------------------------------------------------------------------
24*/
25
26#define _GNU_SOURCE
27
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33
34#include <libxml/xmlstring.h>
35#include <libxml/xmlreader.h>
36
37#include "bst.h"
38#include "avl.h"
39
40#define WKT_MAX 128000
41#define SQL_MAX 140000
42
43#if 0
44#define DEBUG printf
45#else
46#define DEBUG(x, ...)
47#endif
48
49struct tagDesc {
50        const char *name;
51        const char *type;
52        const int polygon;
53}; 
54
55static struct tagDesc exportTags[] = {
56        {"name",    "text", 0},
57        {"place",   "text", 0},
58        {"landuse", "text", 1},
59        {"leisure", "text", 1},
60        {"natural", "text", 1},
61        {"man_made","text", 0},
62        {"waterway","text", 0},
63        {"highway", "text", 0},
64        {"railway", "text", 0},
65        {"amenity", "text", 1},
66        {"tourism", "text", 0},
67        {"learning","text", 0}
68};
69
70static const char *table_name = "planet_osm";
71
72#define MAX_ID_NODE (35000000)
73#define MAX_ID_SEGMENT (35000000)
74
75struct osmNode {
76        unsigned int id;
77        double lon;
78        double lat;
79};
80
81struct osmSegment {
82        unsigned int id;
83        unsigned int from;
84        unsigned int to;
85};
86
87struct osmWay {
88        unsigned int id;
89        char *values;
90        char *wkt;     
91};
92
93static struct osmNode    nodes[MAX_ID_NODE+1];
94static struct osmSegment segments[MAX_ID_SEGMENT+1];
95
96struct bst_table *node_positions;
97struct avl_table *segment_unique;
98struct avl_table *way_tree;
99
100static int count_node, count_all_node, count_dupe_node;
101static int count_segment, count_all_segment, count_dupe_segment;
102static int count_way, count_all_way, count_dupe_way;
103static int count_way_seg;
104
105// Enable this to suppress duplicate ways in the output
106// This is useful on the planet-061128.osm dump and earlier
107// to remove lots of redundant data in the US Tiger import.
108// Note: This approximately doubles the RAM usage!
109static int suppress_dupes=0;
110
111struct keyval;
112
113struct keyval {
114        char *key;
115        char *value;
116        struct keyval *next;
117        struct keyval *prev;
118};
119
120static struct keyval keys, tags, segs;
121
122void usage(const char *arg0)
123{
124        fprintf(stderr, "Usage error:\n\t%s planet.osm  > planet.sql\n", arg0);
125        fprintf(stderr, "or\n\tgzip -dc planet.osm.gz | %s - | gzip -c > planet.sql.gz\n", arg0);
126}
127
128void initList(struct keyval *head)
129{
130        head->next = head;
131        head->prev = head;
132        head->key = NULL;
133        head->value = NULL;
134}
135
136void freeItem(struct keyval *p)
137{
138        free(p->key);
139        free(p->value);
140        free(p);
141}
142
143
144unsigned int countList(struct keyval *head) 
145{
146        struct keyval *p = head->next;
147        unsigned int count = 0; 
148
149        while(p != head) {
150                count++;
151                p = p->next;
152        }
153        return count;
154}
155
156int listHasData(struct keyval *head) 
157{
158        return (head->next != head);
159}
160
161
162char *getItem(struct keyval *head, const char *name)
163{
164        struct keyval *p = head->next;
165        while(p != head) {
166                if (!strcmp(p->key, name))
167                        return p->value;
168                p = p->next;
169        }
170        return NULL;
171}       
172
173
174struct keyval *popItem(struct keyval *head)
175{
176        struct keyval *p = head->next;
177        if (p == head)
178                return NULL;
179
180        head->next = p->next;
181        p->next->prev = head;
182
183        p->next = NULL;
184        p->prev = NULL;
185
186        return p;
187}       
188
189
190void pushItem(struct keyval *head, struct keyval *item)
191{
192        item->next = head;
193        item->prev = head->prev;
194        head->prev->next = item;
195        head->prev = item;
196}       
197
198int addItem(struct keyval *head, const char *name, const char *value, int noDupe)
199{
200        struct keyval *item;
201       
202        if (noDupe) {
203                item = head->next;
204                while (item != head) {
205                        if (!strcmp(item->value, value) && !strcmp(item->key, name)) {
206                                //fprintf(stderr, "Discarded %s=%s\n", name, value);
207                                return 1;
208                        }
209                        item = item->next;
210                }
211        }
212       
213        item = malloc(sizeof(struct keyval));
214               
215        if (!item) {
216                fprintf(stderr, "Error allocating keyval\n");
217                return 2;
218        }
219
220        item->key   = strdup(name);
221        item->value = strdup(value);
222
223        item->next = head->next;
224        item->prev = head;
225        head->next->prev = item;
226        head->next = item;
227
228        return 0;
229}
230
231void resetList(struct keyval *head) 
232{
233        struct keyval *item;
234       
235        while((item = popItem(head))) 
236                freeItem(item);
237}
238
239void WKT(char *wkt, int polygon)
240{
241        double start_x=0, start_y=0, end_x=0, end_y=0;
242        int first = 1;
243        char tmpwkt[WKT_MAX];
244        unsigned int i = countList(&segs); 
245        unsigned int max = i * i;
246        wkt[0] = '\0';
247        static struct keyval triedSegs, *q;
248
249        initList(&triedSegs);   
250        i = 0;
251
252        while (listHasData(&segs) && i++ < max) {
253                struct keyval *p;
254                unsigned int id, to, from;
255                double x0, y0, x1, y1;
256
257                p = popItem(&segs);
258                id = strtoul(p->value, NULL, 10);
259
260                from = segments[id].from;
261                to   = segments[id].to; 
262
263                x0 = nodes[from].lon;
264                y0 = nodes[from].lat;
265                x1 = nodes[to].lon;
266                y1 = nodes[to].lat;
267
268                if (first) {
269                        first = 0;
270                        start_x = x0;
271                        start_y = y0;
272                        end_x = x1;
273                        end_y = y1;
274                        snprintf(wkt, WKT_MAX-1, "%.15g %.15g,%.15g %.15g", x0, y0, x1, y1);
275                } else {
276                        if (start_x == x0 && start_y == y0)  {
277                                start_x = x1;
278                                start_y = y1;
279                                snprintf(tmpwkt, WKT_MAX-1, "%.15g %.15g,%s", x1, y1, wkt);
280                        } else if (start_x == x1 && start_y == y1)  {
281                                start_x = x0;
282                                start_y = y0;
283                                snprintf(tmpwkt, WKT_MAX-1, "%.15g %.15g,%s", x0, y0, wkt);
284                        } else if (end_x == x0 && end_y == y0)  {
285                                end_x = x1;
286                                end_y = y1;
287                                snprintf(tmpwkt, WKT_MAX-1, "%s,%.15g %.15g", wkt, x1, y1);
288                        } else if (end_x == x1 && end_y == y1)  {
289                                end_x = x0;
290                                end_y = y0;
291                                snprintf(tmpwkt, WKT_MAX-1, "%s,%.15g %.15g", wkt, x0, y0);
292                        } else {
293                                pushItem(&triedSegs, p);
294                                continue;
295                        }
296                        strcpy(wkt, tmpwkt);
297                }
298                freeItem(p);
299                // Need to reconsider all previously tried segments again
300                while ((q = popItem(&triedSegs))) 
301                        pushItem(&segs, q);
302        }
303
304        if (strlen(wkt)) {
305                strcpy(tmpwkt, wkt);
306                // Only generate a polygon for a closed area
307                if (polygon && (start_x == end_x) && (start_y == end_y))
308                        snprintf(wkt, WKT_MAX-1, "POLYGON((%s,%.15g %.15g))", tmpwkt, start_x, start_y);
309                else
310                        snprintf(wkt, WKT_MAX-1, "LINESTRING(%s)", tmpwkt);
311        }
312
313        // Push any unattached segments back in the list for next time
314        while ((q = popItem(&triedSegs))) 
315                pushItem(&segs, q);
316}
317
318void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
319{
320        xmlChar *xid, *xlat, *xlon, *xfrom, *xto, *xk, *xv;
321        unsigned int id, to, from;
322        double lon, lat;
323        char *k;
324
325        if (xmlStrEqual(name, BAD_CAST "node")) {
326                struct osmNode *node, *dupe;
327                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
328                xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
329                xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
330                assert(xid); assert(xlon); assert(xlat);
331                id  = strtoul((char *)xid, NULL, 10);
332                lon = strtod((char *)xlon, NULL);
333                lat = strtod((char *)xlat, NULL);
334
335                assert(id > 0 && id < MAX_ID_NODE);
336                count_all_node++;
337                if (count_all_node%10000 == 0) 
338                        fprintf(stderr, "\rProcessing: Node(%dk)", count_all_node/1000);
339
340                node = &nodes[id];
341                node->id  = id;
342                node->lon = lon;
343                node->lat = lat;
344
345                dupe = suppress_dupes ? bst_insert(node_positions, (void *)node) : NULL;
346               
347                if (!dupe) {
348                        DEBUG("NODE(%d) %f %f\n", id, lon, lat);
349                } else {
350                        node->id = dupe->id;
351                        count_dupe_node++;
352                        DEBUG("NODE(%d) %f %f - dupe %d\n", id, lon, lat, dupe->id);
353                }
354                addItem(&keys, "id", (char *)xid, 0);
355
356                xmlFree(xid);
357                xmlFree(xlon);
358                xmlFree(xlat);
359        } else if (xmlStrEqual(name, BAD_CAST "segment")) {
360                xid   = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
361                xfrom = xmlTextReaderGetAttribute(reader, BAD_CAST "from");
362                xto   = xmlTextReaderGetAttribute(reader, BAD_CAST "to");
363                assert(xid); assert(xfrom); assert(xto);
364                id   = strtoul((char *)xid, NULL, 10);
365                from = strtoul((char *)xfrom, NULL, 10);
366                to   = strtoul((char *)xto, NULL, 10);
367
368                assert(id > 0 && id < MAX_ID_SEGMENT);
369                if (count_all_segment == 0) {
370                        //fprintf(stderr, "\nBalancing node tree\n");
371                        bst_balance(node_positions);
372                        fprintf(stderr, "\n");
373                }
374
375                count_all_segment++;
376                if (count_all_segment%10000 == 0) 
377                        fprintf(stderr, "\rProcessing: Segment(%dk)", count_all_segment/1000);
378
379                if (!nodes[to].id) {
380                        DEBUG("SEGMENT(%d), NODE(%d) is missing\n", id, to);
381                } else if (!nodes[from].id) {
382                        DEBUG("SEGMENT(%d), NODE(%d) is missing\n", id, from);
383                } else {
384                        from = nodes[from].id;
385                        to   = nodes[to].id;
386                        if (from != to) {
387                                struct osmSegment *segment, *dupe;
388                                segment = &segments[id];
389                                segment->id   = id;
390                                segment->to   = to;
391                                segment->from = from;
392
393                                dupe = suppress_dupes ? avl_insert(segment_unique, (void *)segment) : NULL;
394
395                                if (!dupe) {
396                                        count_segment++;
397                                        DEBUG("SEGMENT(%d) %d, %d\n", id, from, to);
398                                } else {
399                                        count_dupe_segment++;
400                                        segment->id = dupe->id;
401                                        DEBUG("SEGMENT(%d) %d, %d - dupe %d\n", id, from, to, dupe->id);
402                                }
403                        }
404                }
405
406                xmlFree(xid);
407                xmlFree(xfrom);
408                xmlFree(xto);
409        } else if (xmlStrEqual(name, BAD_CAST "tag")) {
410                char *p;
411                xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
412                xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
413                assert(xk); assert(xv);
414                k  = (char *)xmlStrdup(xk);
415                /* FIXME: This does not look safe on UTF-8 data */
416                while ((p = strchr(k, ':')))
417                        *p = '_';
418                while ((p = strchr(k, ' ')))
419                        *p = '_';
420                addItem(&tags, k, (char *)xv, 0);
421                DEBUG("\t%s = %s\n", xk, xv);
422                xmlFree(k);
423                xmlFree(xk);
424                xmlFree(xv);
425        } else if (xmlStrEqual(name, BAD_CAST "way")) {
426                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
427                assert(xid);
428                addItem(&keys, "id", (char *)xid, 0);
429                DEBUG("WAY(%s)\n", xid);
430
431                if (count_all_way == 0)
432                        fprintf(stderr, "\n");
433               
434                count_all_way++;
435                if (count_all_way%1000 == 0) 
436                        fprintf(stderr, "\rProcessing: Way(%dk)", count_all_way/1000);
437
438                xmlFree(xid);
439        } else if (xmlStrEqual(name, BAD_CAST "seg")) {
440                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
441                assert(xid);
442                id   = strtoul((char *)xid, NULL, 10);
443                if (!id || (id > MAX_ID_SEGMENT))
444                        DEBUG("\tSEG(%s) - invalid segment ID\n", xid);
445                else if (!segments[id].id)
446                        DEBUG("\tSEG(%s) - missing segment\n", xid);
447                else {
448                        char *tmp;
449                        // Find unique segment
450                        id = segments[id].id;
451                        asprintf(&tmp, "%d", id);
452                        if (addItem(&segs, "id", tmp, 1)) {
453                                const char *way_id = getItem(&keys, "id");
454                                if (!way_id) way_id = "???";
455                                //fprintf(stderr, "Way %s with duplicate segment id %d\n", way_id, id);
456                                count_way_seg++;
457                        }
458                        DEBUG("\tSEG(%s)\n", xid);
459                        free(tmp);
460                }
461                xmlFree(xid);
462        } else if (xmlStrEqual(name, BAD_CAST "osm")) {
463                /* ignore */
464        } else {
465                fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
466        }
467}
468
469void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
470{
471        unsigned int id;
472
473        DEBUG("%s: %s\n", __FUNCTION__, name);
474
475        if (xmlStrEqual(name, BAD_CAST "node")) {
476                int i;
477                char *values = NULL, *names = NULL;
478                char *osm_id = getItem(&keys, "id");
479                if (!osm_id) {
480                        fprintf(stderr, "%s: Node ID not in keys\n", __FUNCTION__);
481                        resetList(&keys);
482                        resetList(&tags);
483                        return;
484                }
485                id  = strtoul(osm_id, NULL, 10);
486                assert(nodes[id].id);
487#if 0
488                if (id != nodes[id].id) {
489                        // TODO: Consider dropping all duplicate nodes or compare tags?
490                        // Don't really want to store all node attributes for comparison.
491                        resetList(&keys);
492                        resetList(&tags);
493                        return;
494                }
495#endif
496                for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
497                        char *v;
498                        if ((v = getItem(&tags, exportTags[i].name))) {
499                                if (values) {
500                                        char *oldval = values, *oldnam = names;
501                                        asprintf(&names,  "%s,\"%s\"", oldnam, exportTags[i].name);
502                                        asprintf(&values, "%s,$$%s$$", oldval, v);
503                                        free(oldnam);
504                                        free(oldval);
505                                } else {
506                                        asprintf(&names,  "\"%s\"", exportTags[i].name);
507                                        asprintf(&values, "$$%s$$", v);
508                                }
509                        }
510                }
511                if (values) {
512                        char wkt[WKT_MAX];
513                        count_node++;
514                        snprintf(wkt, sizeof(wkt)-1, 
515                                "POINT(%.15g %.15g)", nodes[id].lon, nodes[id].lat);
516                        wkt[sizeof(wkt)-1] = '\0';
517                        printf("insert into %s (osm_id,%s,way) values (%s,%s,GeomFromText('%s',4326));\n", table_name,names,osm_id,values,wkt);
518                }
519                resetList(&keys);
520                resetList(&tags);
521                free(values);
522                free(names);
523        } else if (xmlStrEqual(name, BAD_CAST "segment")) {
524                resetList(&tags);
525        } else if (xmlStrEqual(name, BAD_CAST "tag")) {
526                /* Separate tag list so tag stack unused */
527        } else if (xmlStrEqual(name, BAD_CAST "way")) {
528                int i, polygon = 0; 
529                char *values = NULL, *names = NULL;
530                char wkt[WKT_MAX];
531                char *osm_id = getItem(&keys, "id");
532
533                if (!osm_id) {
534                        fprintf(stderr, "%s: WAY ID not in keys\n", __FUNCTION__);
535                        resetList(&keys);
536                        resetList(&tags);
537                        resetList(&segs);
538                        return;
539                }
540
541                if (!listHasData(&segs)) {
542                        DEBUG("%s: WAY(%s) has no segments\n", __FUNCTION__, osm_id);
543                        resetList(&keys);
544                        resetList(&tags);
545                        resetList(&segs);
546                        return;
547                }
548                id  = strtoul(osm_id, NULL, 10);
549
550                for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
551                        char *v;
552                        if ((v = getItem(&tags, exportTags[i].name))) {
553                                if (values) {
554                                        char *oldval = values, *oldnam = names;
555                                        asprintf(&names,  "%s,\"%s\"", oldnam, exportTags[i].name);
556                                        asprintf(&values, "%s,$$%s$$", oldval, v);
557                                        free(oldnam);
558                                        free(oldval);
559                                } else {
560                                        asprintf(&names,  "\"%s\"", exportTags[i].name);
561                                        asprintf(&values, "$$%s$$", v);
562                                }
563                                polygon |= exportTags[i].polygon;
564                        }
565                }
566
567                if (values) {
568                        do {
569                                WKT(wkt, polygon); 
570                                if (strlen(wkt)) {
571                                        struct osmWay *dupe = NULL;
572       
573                                        if (suppress_dupes) {
574                                                struct osmWay *way = malloc(sizeof(struct osmWay));
575                                                assert(way);
576                                                way->id = id;
577                                                way->values = strdup(values);
578                                                way->wkt    = strdup(wkt);
579                                                assert(way->values);
580                                                assert(way->wkt);
581                                                dupe = avl_insert(way_tree, (void *)way);
582                                                if (dupe) {
583                                                        DEBUG("WAY(%d) - duplicate of %d\n", id, dupe->id);
584                                                        count_dupe_way++;
585                                                        free(way->values);
586                                                        free(way->wkt);
587                                                        free(way);
588                                                }
589                                        } 
590                                        if (!dupe) {
591                                                printf("insert into %s (osm_id,%s,way) values (%s,%s,GeomFromText('%s',4326));\n", table_name,names,osm_id,values,wkt);
592                                                count_way++;   
593                                        }
594                                }
595                        } while (listHasData(&segs));
596                }
597                resetList(&keys);
598                resetList(&tags);
599                resetList(&segs);
600                free(values);
601                free(names);
602        } else if (xmlStrEqual(name, BAD_CAST "seg")) {
603                /* ignore */
604        } else if (xmlStrEqual(name, BAD_CAST "osm")) {
605                /* ignore */
606        } else {
607                fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
608        }
609}
610
611static void processNode(xmlTextReaderPtr reader) {
612        xmlChar *name;
613        name = xmlTextReaderName(reader);
614        if (name == NULL)
615                name = xmlStrdup(BAD_CAST "--");
616       
617        switch(xmlTextReaderNodeType(reader)) {
618                case XML_READER_TYPE_ELEMENT:
619                        StartElement(reader, name);     
620                        if (xmlTextReaderIsEmptyElement(reader))
621                                EndElement(reader, name); /* No end_element for self closing tags! */
622                        break;
623                case XML_READER_TYPE_END_ELEMENT:
624                        EndElement(reader, name);
625                        break;
626                case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
627                        /* Ignore */
628                        break;
629                default:
630                        fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
631                        break;
632        }
633       
634        xmlFree(name);
635}
636
637void streamFile(char *filename) {
638        xmlTextReaderPtr reader;
639        int ret;
640       
641        reader = xmlNewTextReaderFilename(filename);
642        if (reader != NULL) {
643                ret = xmlTextReaderRead(reader);
644                while (ret == 1) {
645                        processNode(reader);
646                        ret = xmlTextReaderRead(reader);
647                }
648       
649                if (ret != 0) {
650                        fprintf(stderr, "%s : failed to parse\n", filename);
651                        return;
652                }
653       
654                xmlFreeTextReader(reader);
655        } else {
656                fprintf(stderr, "Unable to open %s\n", filename);
657        }
658}
659
660int compare_node(const void *bst_a, const void *bst_b, void *bst_param)
661{
662        const struct osmNode *nA = bst_a;
663        const struct osmNode *nB = bst_b;
664
665        if (nA == nB) return 0;
666        if (nA->id == nB->id) return 0;
667
668        if (nA->lon < nB->lon)
669                return -1;
670        else if (nA->lon > nB->lon)
671                return +1;
672       
673        if (nA->lat < nB->lat)
674                return -1;
675        else if (nA->lat > nB->lat)
676                return +1;
677
678        return 0; 
679}
680
681int compare_segment(const void *avl_a, const void *avl_b, void *avl_param)
682{
683        const struct osmSegment *sA = avl_a;
684        const struct osmSegment *sB = avl_b;
685
686        if (sA == sB) return 0;
687        if (sA->id == sB->id) return 0;
688
689        if (sA->from < sB->from)
690                return -1;
691        else if (sA->from > sB->from)
692                return +1;
693
694        if (sA->to < sB->to)
695                return -1;
696        else if (sA->to > sB->to)
697                return +1;
698        return 0;
699}
700
701int compare_way(const void *avl_a, const void *avl_b, void *avl_param)
702{
703        const struct osmWay *wA = avl_a;
704        const struct osmWay *wB = avl_b;
705        int c;
706
707        if (wA == wB) return 0;
708        if (wA->id == wB->id) return 0;
709
710        // TODO: Maybe keeping a hash of WKT would be better?
711        c = strcmp(wA->wkt, wB->wkt);
712        if (c) return c;
713
714        return strcmp(wA->values, wB->values);
715}
716
717
718int main(int argc, char *argv[])
719{
720        int i;
721
722        if (argc != 2) {
723                usage(argv[0]);
724                exit(1);
725        }
726 
727        node_positions = bst_create(compare_node, NULL, NULL);
728        assert(node_positions);
729        segment_unique = avl_create(compare_segment, NULL, NULL);
730        assert(segment_unique);
731        way_tree = avl_create(compare_way, NULL, NULL);
732        assert(way_tree);
733
734        initList(&keys);
735        initList(&tags);
736        initList(&segs);
737
738        LIBXML_TEST_VERSION
739       
740        printf("drop table %s ;\n", table_name);
741        printf("create table %s ( osm_id int4",table_name);
742        for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++)
743                printf(",\"%s\" %s", exportTags[i].name, exportTags[i].type);
744        printf(" );\n");
745        printf("select AddGeometryColumn('%s', 'way', 4326, 'GEOMETRY', 2 );\n", table_name);
746        printf("begin;\n");
747       
748        streamFile(argv[1]);
749       
750        printf("commit;\n");
751        printf("vacuum analyze %s;\n", table_name);
752        printf("CREATE INDEX way_index ON %s USING GIST (way GIST_GEOMETRY_OPS);\n", table_name);
753        printf("vacuum analyze %s;\n", table_name);
754       
755        xmlCleanupParser();
756        xmlMemoryDump();
757       
758        fprintf(stderr, "\n");
759       
760        if (count_all_node) {
761        fprintf(stderr, "Node stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
762                count_node, count_dupe_node, 100.0 * count_dupe_node / count_all_node, count_all_node);
763        }
764        if (count_all_segment) {
765        fprintf(stderr, "Segment stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
766                count_segment, count_dupe_segment, 100.0 * count_dupe_segment / count_all_segment, count_all_segment);
767        }
768        if (count_all_way) {
769        fprintf(stderr, "Way stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
770                count_way, count_dupe_way, 100.0 * count_dupe_way / count_all_way, count_all_way);
771        }
772        fprintf(stderr, "Way stats: duplicate segments in ways %d\n", count_way_seg);
773
774        return 0;
775}
Note: See TracBrowser for help on using the repository browser.