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

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

osm2pgql filter duplicate segments in ways

File size: 18.6 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 unnkown author
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}; 
53
54static struct tagDesc exportTags[] = {
55        {"name","text"},
56        {"place","text"},
57        {"landuse","text"},
58        {"leisure","text"},
59        {"natural","text"},
60        {"man_made","text"},
61        {"waterway","text"},
62        {"highway","text"},
63        {"railway","text"},
64        {"amenity","text"},
65        {"tourism","text"},
66        {"learning","text"}
67};
68
69static const char *table_name = "planet_osm";
70char fieldNames[128];
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                if (polygon) 
307                        snprintf(wkt, WKT_MAX-1, "POLYGON((%s,%.15g %.15g))", tmpwkt, start_x, start_y);
308                else 
309                        snprintf(wkt, WKT_MAX-1, "LINESTRING(%s)", tmpwkt);
310        }
311
312        // Push any unattached segments back in the list for next time
313        while ((q = popItem(&triedSegs))) 
314                pushItem(&segs, q);
315}
316
317void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
318{
319        xmlChar *xid, *xlat, *xlon, *xfrom, *xto, *xk, *xv;
320        unsigned int id, to, from;
321        double lon, lat;
322        char *k;
323
324        if (xmlStrEqual(name, BAD_CAST "node")) {
325                struct osmNode *node, *dupe;
326                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
327                xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
328                xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
329                assert(xid); assert(xlon); assert(xlat);
330                id  = strtoul((char *)xid, NULL, 10);
331                lon = strtod((char *)xlon, NULL);
332                lat = strtod((char *)xlat, NULL);
333
334                assert(id > 0 && id < MAX_ID_NODE);
335                count_all_node++;
336                if (count_all_node%10000 == 0) 
337                        fprintf(stderr, "\rProcessing: Node(%dk)", count_all_node/1000);
338
339                node = &nodes[id];
340                node->id  = id;
341                node->lon = lon;
342                node->lat = lat;
343
344                dupe = suppress_dupes ? bst_insert(node_positions, (void *)node) : NULL;
345               
346                if (!dupe) {
347                        DEBUG("NODE(%d) %f %f\n", id, lon, lat);
348                } else {
349                        node->id = dupe->id;
350                        count_dupe_node++;
351                        DEBUG("NODE(%d) %f %f - dupe %d\n", id, lon, lat, dupe->id);
352                }
353                addItem(&keys, "id", (char *)xid, 0);
354
355                xmlFree(xid);
356                xmlFree(xlon);
357                xmlFree(xlat);
358        } else if (xmlStrEqual(name, BAD_CAST "segment")) {
359                xid   = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
360                xfrom = xmlTextReaderGetAttribute(reader, BAD_CAST "from");
361                xto   = xmlTextReaderGetAttribute(reader, BAD_CAST "to");
362                assert(xid); assert(xfrom); assert(xto);
363                id   = strtoul((char *)xid, NULL, 10);
364                from = strtoul((char *)xfrom, NULL, 10);
365                to   = strtoul((char *)xto, NULL, 10);
366
367                assert(id > 0 && id < MAX_ID_SEGMENT);
368                if (count_all_segment == 0) {
369                        //fprintf(stderr, "\nBalancing node tree\n");
370                        bst_balance(node_positions);
371                        fprintf(stderr, "\n");
372                }
373
374                count_all_segment++;
375                if (count_all_segment%10000 == 0) 
376                        fprintf(stderr, "\rProcessing: Segment(%dk)", count_all_segment/1000);
377
378                if (!nodes[to].id) {
379                        DEBUG("SEGMENT(%d), NODE(%d) is missing\n", id, to);
380                } else if (!nodes[from].id) {
381                        DEBUG("SEGMENT(%d), NODE(%d) is missing\n", id, from);
382                } else {
383                        from = nodes[from].id;
384                        to   = nodes[to].id;
385                        if (from != to) {
386                                struct osmSegment *segment, *dupe;
387                                segment = &segments[id];
388                                segment->id   = id;
389                                segment->to   = to;
390                                segment->from = from;
391
392                                dupe = suppress_dupes ? avl_insert(segment_unique, (void *)segment) : NULL;
393
394                                if (!dupe) {
395                                        count_segment++;
396                                        DEBUG("SEGMENT(%d) %d, %d\n", id, from, to);
397                                } else {
398                                        count_dupe_segment++;
399                                        segment->id = dupe->id;
400                                        DEBUG("SEGMENT(%d) %d, %d - dupe %d\n", id, from, to, dupe->id);
401                                }
402                        }
403                }
404
405                xmlFree(xid);
406                xmlFree(xfrom);
407                xmlFree(xto);
408        } else if (xmlStrEqual(name, BAD_CAST "tag")) {
409                char *p;
410                xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
411                xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
412                assert(xk); assert(xv);
413                k  = (char *)xmlStrdup(xk);
414                /* FIXME: This does not look safe on UTF-8 data */
415                while ((p = strchr(k, ':')))
416                        *p = '_';
417                while ((p = strchr(k, ' ')))
418                        *p = '_';
419                addItem(&tags, k, (char *)xv, 0);
420                DEBUG("\t%s = %s\n", xk, xv);
421                xmlFree(k);
422                xmlFree(xk);
423                xmlFree(xv);
424        } else if (xmlStrEqual(name, BAD_CAST "way")) {
425                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
426                assert(xid);
427                addItem(&keys, "id", (char *)xid, 0);
428                DEBUG("WAY(%s)\n", xid);
429
430                if (count_all_way == 0)
431                        fprintf(stderr, "\n");
432               
433                count_all_way++;
434                if (count_all_way%1000 == 0) 
435                        fprintf(stderr, "\rProcessing: Way(%dk)", count_all_way/1000);
436
437                xmlFree(xid);
438        } else if (xmlStrEqual(name, BAD_CAST "seg")) {
439                xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
440                assert(xid);
441                id   = strtoul((char *)xid, NULL, 10);
442                if (!id || (id > MAX_ID_SEGMENT))
443                        DEBUG("\tSEG(%s) - invalid segment ID\n", xid);
444                else if (!segments[id].id)
445                        DEBUG("\tSEG(%s) - missing segment\n", xid);
446                else {
447                        char *tmp;
448                        // Find unique segment
449                        id = segments[id].id;
450                        asprintf(&tmp, "%d", id);
451                        if (addItem(&segs, "id", tmp, 1)) {
452                                const char *way_id = getItem(&keys, "id");
453                                if (!way_id) way_id = "???";
454                                //fprintf(stderr, "Way %s with duplicate segment id %d\n", way_id, id);
455                                count_way_seg++;
456                        }
457                        DEBUG("\tSEG(%s)\n", xid);
458                        free(tmp);
459                }
460                xmlFree(xid);
461        } else if (xmlStrEqual(name, BAD_CAST "osm")) {
462                /* ignore */
463        } else {
464                fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
465        }
466}
467
468void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
469{
470        unsigned int id;
471        char *v;
472
473        DEBUG("%s: %s\n", __FUNCTION__, name);
474
475        if (xmlStrEqual(name, BAD_CAST "node")) {
476                int i, count = 0; 
477                char *values = 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 *oldval = values;
498                        int width = strcmp(exportTags[i].name, "name")?32:64;
499                        if ((v = getItem(&tags, exportTags[i].name)))
500                                count++;
501                        else
502                                v = "";
503
504                        if (oldval)                             
505                                asprintf(&values, "%s,$$%.*s$$", oldval, width, v);
506                        else
507                                asprintf(&values, "$$%.*s$$", width, v);
508
509                        free(oldval);
510                }
511                if (count) {
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,fieldNames,osm_id,values,wkt);
518                }
519                resetList(&keys);
520                resetList(&tags);
521                free(values);
522        } else if (xmlStrEqual(name, BAD_CAST "segment")) {
523                resetList(&tags);
524        } else if (xmlStrEqual(name, BAD_CAST "tag")) {
525                /* Separate tag list so tag stack unused */
526        } else if (xmlStrEqual(name, BAD_CAST "way")) {
527                int i, polygon = 0; 
528                char *values = NULL;
529                char wkt[WKT_MAX];
530                char *osm_id = getItem(&keys, "id");
531
532                if (!osm_id) {
533                        fprintf(stderr, "%s: WAY ID not in keys\n", __FUNCTION__);
534                        resetList(&keys);
535                        resetList(&tags);
536                        resetList(&segs);
537                        return;
538                }
539
540                if (!listHasData(&segs)) {
541                        DEBUG("%s: WAY(%s) has no segments\n", __FUNCTION__, osm_id);
542                        resetList(&keys);
543                        resetList(&tags);
544                        resetList(&segs);
545                        return;
546                }
547                id  = strtoul(osm_id, NULL, 10);
548
549                for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
550                        char *oldval = values;
551                        const char *name = exportTags[i].name;
552                        if ((v = getItem(&tags, name))) {
553                                if (!strcmp(name, "landuse") || !strcmp(name, "leisure")
554                                   || !strcmp(name, "amenity") || !strcmp(name, "natural"))
555                                        polygon = 1;
556                        } else
557                                v = "";                 
558
559                        if (oldval)                             
560                                asprintf(&values, "%s,$$%s$$", oldval, v);
561                        else
562                                asprintf(&values, "$$%s$$", v);
563
564                        free(oldval);
565                }
566
567                do {
568                        WKT(wkt, polygon); 
569                        if (strlen(wkt)) {
570                                struct osmWay *dupe = NULL;
571
572                                if (suppress_dupes) {
573                                        struct osmWay *way = malloc(sizeof(struct osmWay));
574                                        assert(way);
575                                        way->id = id;
576                                        way->values = strdup(values);
577                                        way->wkt    = strdup(wkt);
578                                        assert(way->values);
579                                        assert(way->wkt);
580                                        dupe = avl_insert(way_tree, (void *)way);
581                                        if (dupe) {
582                                                DEBUG("WAY(%d) - duplicate of %d\n", id, dupe->id);
583                                                count_dupe_way++;
584                                                free(way->values);
585                                                free(way->wkt);
586                                                free(way);
587                                        }
588                                } 
589                                if (!dupe) {
590                                        printf("insert into %s (osm_id,%s,way) values (%s,%s,GeomFromText('%s',4326));\n", table_name,fieldNames,osm_id,values,wkt);
591                                        count_way++;   
592                                }
593                        }
594                } while (listHasData(&segs));
595                resetList(&keys);
596                resetList(&tags);
597                resetList(&segs);
598                free(values);
599        } else if (xmlStrEqual(name, BAD_CAST "seg")) {
600                /* ignore */
601        } else if (xmlStrEqual(name, BAD_CAST "osm")) {
602                /* ignore */
603        } else {
604                fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
605        }
606}
607
608static void processNode(xmlTextReaderPtr reader) {
609        xmlChar *name;
610        name = xmlTextReaderName(reader);
611        if (name == NULL)
612                name = xmlStrdup(BAD_CAST "--");
613       
614        switch(xmlTextReaderNodeType(reader)) {
615                case XML_READER_TYPE_ELEMENT:
616                        StartElement(reader, name);     
617                        if (xmlTextReaderIsEmptyElement(reader))
618                                EndElement(reader, name); /* No end_element for self closing tags! */
619                        break;
620                case XML_READER_TYPE_END_ELEMENT:
621                        EndElement(reader, name);
622                        break;
623                case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
624                        /* Ignore */
625                        break;
626                default:
627                        fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
628                        break;
629        }
630       
631        xmlFree(name);
632}
633
634void streamFile(char *filename) {
635        xmlTextReaderPtr reader;
636        int ret;
637       
638        reader = xmlNewTextReaderFilename(filename);
639        if (reader != NULL) {
640                ret = xmlTextReaderRead(reader);
641                while (ret == 1) {
642                        processNode(reader);
643                        ret = xmlTextReaderRead(reader);
644                }
645       
646                if (ret != 0) {
647                        fprintf(stderr, "%s : failed to parse\n", filename);
648                        return;
649                }
650       
651                xmlFreeTextReader(reader);
652        } else {
653                fprintf(stderr, "Unable to open %s\n", filename);
654        }
655}
656
657int compare_node(const void *bst_a, const void *bst_b, void *bst_param)
658{
659        const struct osmNode *nA = bst_a;
660        const struct osmNode *nB = bst_b;
661
662        if (nA == nB) return 0;
663        if (nA->id == nB->id) return 0;
664
665        if (nA->lon < nB->lon)
666                return -1;
667        else if (nA->lon > nB->lon)
668                return +1;
669       
670        if (nA->lat < nB->lat)
671                return -1;
672        else if (nA->lat > nB->lat)
673                return +1;
674
675        return 0; 
676}
677
678int compare_segment(const void *avl_a, const void *avl_b, void *avl_param)
679{
680        const struct osmSegment *sA = avl_a;
681        const struct osmSegment *sB = avl_b;
682
683        if (sA == sB) return 0;
684        if (sA->id == sB->id) return 0;
685
686        if (sA->from < sB->from)
687                return -1;
688        else if (sA->from > sB->from)
689                return +1;
690
691        if (sA->to < sB->to)
692                return -1;
693        else if (sA->to > sB->to)
694                return +1;
695        return 0;
696}
697
698int compare_way(const void *avl_a, const void *avl_b, void *avl_param)
699{
700        const struct osmWay *wA = avl_a;
701        const struct osmWay *wB = avl_b;
702        int c;
703
704        if (wA == wB) return 0;
705        if (wA->id == wB->id) return 0;
706
707        // TODO: Maybe keeping a hash of WKT would be better?
708        c = strcmp(wA->wkt, wB->wkt);
709        if (c) return c;
710
711        return strcmp(wA->values, wB->values);
712}
713
714
715int main(int argc, char *argv[])
716{
717        int i;
718
719        if (argc != 2) {
720                usage(argv[0]);
721                exit(1);
722        }
723 
724        node_positions = bst_create(compare_node, NULL, NULL);
725        assert(node_positions);
726        segment_unique = avl_create(compare_segment, NULL, NULL);
727        assert(segment_unique);
728        way_tree = avl_create(compare_way, NULL, NULL);
729        assert(way_tree);
730
731        initList(&keys);
732        initList(&tags);
733        initList(&segs);
734
735        LIBXML_TEST_VERSION
736       
737        printf("drop table %s ;\n", table_name);
738        printf("create table %s ( osm_id int4",table_name);
739        fieldNames[0] = '\0';
740        for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
741                char tmp[32];
742                sprintf(tmp, i?",\"%s\"":"\"%s\"", exportTags[i].name);
743                strcat(fieldNames, tmp);
744                printf(",\"%s\" %s", exportTags[i].name, exportTags[i].type);
745        }       
746        printf(" );\n");
747        printf("select AddGeometryColumn('%s', 'way', 4326, 'GEOMETRY', 2 );\n", table_name);
748        printf("begin;\n");
749       
750        streamFile(argv[1]);
751       
752        printf("commit;\n");
753        printf("vacuum analyze %s;\n", table_name);
754        printf("CREATE INDEX way_index ON %s USING GIST (way GIST_GEOMETRY_OPS);\n", table_name);
755        printf("vacuum analyze %s;\n", table_name);
756       
757        xmlCleanupParser();
758        xmlMemoryDump();
759       
760        fprintf(stderr, "\n");
761       
762        if (count_all_node) {
763        fprintf(stderr, "Node stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
764                count_node, count_dupe_node, 100.0 * count_dupe_node / count_all_node, count_all_node);
765        }
766        if (count_all_segment) {
767        fprintf(stderr, "Segment stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
768                count_segment, count_dupe_segment, 100.0 * count_dupe_segment / count_all_segment, count_all_segment);
769        }
770        if (count_all_way) {
771        fprintf(stderr, "Way stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
772                count_way, count_dupe_way, 100.0 * count_dupe_way / count_all_way, count_all_way);
773        }
774        fprintf(stderr, "Way stats: duplicate segments in ways %d\n", count_way_seg);
775
776        return 0;
777}
Note: See TracBrowser for help on using the repository browser.