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

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

osm2pgsql polygons for closed ways only

File size: 18.7 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                // 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        char *v;
473
474        DEBUG("%s: %s\n", __FUNCTION__, name);
475
476        if (xmlStrEqual(name, BAD_CAST "node")) {
477                int i, count = 0; 
478                char *values = NULL;
479                char *osm_id = getItem(&keys, "id");
480                if (!osm_id) {
481                        fprintf(stderr, "%s: Node ID not in keys\n", __FUNCTION__);
482                        resetList(&keys);
483                        resetList(&tags);
484                        return;
485                }
486                id  = strtoul(osm_id, NULL, 10);
487                assert(nodes[id].id);
488#if 0
489                if (id != nodes[id].id) {
490                        // TODO: Consider dropping all duplicate nodes or compare tags?
491                        // Don't really want to store all node attributes for comparison.
492                        resetList(&keys);
493                        resetList(&tags);
494                        return;
495                }
496#endif
497                for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
498                        char *oldval = values;
499                        int width = strcmp(exportTags[i].name, "name")?32:64;
500                        if ((v = getItem(&tags, exportTags[i].name)))
501                                count++;
502                        else
503                                v = "";
504
505                        if (oldval)                             
506                                asprintf(&values, "%s,$$%.*s$$", oldval, width, v);
507                        else
508                                asprintf(&values, "$$%.*s$$", width, v);
509
510                        free(oldval);
511                }
512                if (count) {
513                        char wkt[WKT_MAX];
514                        count_node++;
515                        snprintf(wkt, sizeof(wkt)-1, 
516                                "POINT(%.15g %.15g)", nodes[id].lon, nodes[id].lat);
517                        wkt[sizeof(wkt)-1] = '\0';
518                        printf("insert into %s (osm_id,%s,way) values (%s,%s,GeomFromText('%s',4326));\n", table_name,fieldNames,osm_id,values,wkt);
519                }
520                resetList(&keys);
521                resetList(&tags);
522                free(values);
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;
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 *oldval = values;
552                        const char *name = exportTags[i].name;
553                        if ((v = getItem(&tags, name))) {
554                                if (!strcmp(name, "landuse") || !strcmp(name, "leisure")
555                                   || !strcmp(name, "amenity") || !strcmp(name, "natural"))
556                                        polygon = 1;
557                        } else
558                                v = "";                 
559
560                        if (oldval)                             
561                                asprintf(&values, "%s,$$%s$$", oldval, v);
562                        else
563                                asprintf(&values, "$$%s$$", v);
564
565                        free(oldval);
566                }
567
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,fieldNames,osm_id,values,wkt);
592                                        count_way++;   
593                                }
594                        }
595                } while (listHasData(&segs));
596                resetList(&keys);
597                resetList(&tags);
598                resetList(&segs);
599                free(values);
600        } else if (xmlStrEqual(name, BAD_CAST "seg")) {
601                /* ignore */
602        } else if (xmlStrEqual(name, BAD_CAST "osm")) {
603                /* ignore */
604        } else {
605                fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
606        }
607}
608
609static void processNode(xmlTextReaderPtr reader) {
610        xmlChar *name;
611        name = xmlTextReaderName(reader);
612        if (name == NULL)
613                name = xmlStrdup(BAD_CAST "--");
614       
615        switch(xmlTextReaderNodeType(reader)) {
616                case XML_READER_TYPE_ELEMENT:
617                        StartElement(reader, name);     
618                        if (xmlTextReaderIsEmptyElement(reader))
619                                EndElement(reader, name); /* No end_element for self closing tags! */
620                        break;
621                case XML_READER_TYPE_END_ELEMENT:
622                        EndElement(reader, name);
623                        break;
624                case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
625                        /* Ignore */
626                        break;
627                default:
628                        fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
629                        break;
630        }
631       
632        xmlFree(name);
633}
634
635void streamFile(char *filename) {
636        xmlTextReaderPtr reader;
637        int ret;
638       
639        reader = xmlNewTextReaderFilename(filename);
640        if (reader != NULL) {
641                ret = xmlTextReaderRead(reader);
642                while (ret == 1) {
643                        processNode(reader);
644                        ret = xmlTextReaderRead(reader);
645                }
646       
647                if (ret != 0) {
648                        fprintf(stderr, "%s : failed to parse\n", filename);
649                        return;
650                }
651       
652                xmlFreeTextReader(reader);
653        } else {
654                fprintf(stderr, "Unable to open %s\n", filename);
655        }
656}
657
658int compare_node(const void *bst_a, const void *bst_b, void *bst_param)
659{
660        const struct osmNode *nA = bst_a;
661        const struct osmNode *nB = bst_b;
662
663        if (nA == nB) return 0;
664        if (nA->id == nB->id) return 0;
665
666        if (nA->lon < nB->lon)
667                return -1;
668        else if (nA->lon > nB->lon)
669                return +1;
670       
671        if (nA->lat < nB->lat)
672                return -1;
673        else if (nA->lat > nB->lat)
674                return +1;
675
676        return 0; 
677}
678
679int compare_segment(const void *avl_a, const void *avl_b, void *avl_param)
680{
681        const struct osmSegment *sA = avl_a;
682        const struct osmSegment *sB = avl_b;
683
684        if (sA == sB) return 0;
685        if (sA->id == sB->id) return 0;
686
687        if (sA->from < sB->from)
688                return -1;
689        else if (sA->from > sB->from)
690                return +1;
691
692        if (sA->to < sB->to)
693                return -1;
694        else if (sA->to > sB->to)
695                return +1;
696        return 0;
697}
698
699int compare_way(const void *avl_a, const void *avl_b, void *avl_param)
700{
701        const struct osmWay *wA = avl_a;
702        const struct osmWay *wB = avl_b;
703        int c;
704
705        if (wA == wB) return 0;
706        if (wA->id == wB->id) return 0;
707
708        // TODO: Maybe keeping a hash of WKT would be better?
709        c = strcmp(wA->wkt, wB->wkt);
710        if (c) return c;
711
712        return strcmp(wA->values, wB->values);
713}
714
715
716int main(int argc, char *argv[])
717{
718        int i;
719
720        if (argc != 2) {
721                usage(argv[0]);
722                exit(1);
723        }
724 
725        node_positions = bst_create(compare_node, NULL, NULL);
726        assert(node_positions);
727        segment_unique = avl_create(compare_segment, NULL, NULL);
728        assert(segment_unique);
729        way_tree = avl_create(compare_way, NULL, NULL);
730        assert(way_tree);
731
732        initList(&keys);
733        initList(&tags);
734        initList(&segs);
735
736        LIBXML_TEST_VERSION
737       
738        printf("drop table %s ;\n", table_name);
739        printf("create table %s ( osm_id int4",table_name);
740        fieldNames[0] = '\0';
741        for (i=0; i < sizeof(exportTags) / sizeof(exportTags[0]); i++) {
742                char tmp[32];
743                sprintf(tmp, i?",\"%s\"":"\"%s\"", exportTags[i].name);
744                strcat(fieldNames, tmp);
745                printf(",\"%s\" %s", exportTags[i].name, exportTags[i].type);
746        }       
747        printf(" );\n");
748        printf("select AddGeometryColumn('%s', 'way', 4326, 'GEOMETRY', 2 );\n", table_name);
749        printf("begin;\n");
750       
751        streamFile(argv[1]);
752       
753        printf("commit;\n");
754        printf("vacuum analyze %s;\n", table_name);
755        printf("CREATE INDEX way_index ON %s USING GIST (way GIST_GEOMETRY_OPS);\n", table_name);
756        printf("vacuum analyze %s;\n", table_name);
757       
758        xmlCleanupParser();
759        xmlMemoryDump();
760       
761        fprintf(stderr, "\n");
762       
763        if (count_all_node) {
764        fprintf(stderr, "Node stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
765                count_node, count_dupe_node, 100.0 * count_dupe_node / count_all_node, count_all_node);
766        }
767        if (count_all_segment) {
768        fprintf(stderr, "Segment stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
769                count_segment, count_dupe_segment, 100.0 * count_dupe_segment / count_all_segment, count_all_segment);
770        }
771        if (count_all_way) {
772        fprintf(stderr, "Way stats: out(%d), dupe(%d) (%.1f%%), total(%d)\n",
773                count_way, count_dupe_way, 100.0 * count_dupe_way / count_all_way, count_all_way);
774        }
775        fprintf(stderr, "Way stats: duplicate segments in ways %d\n", count_way_seg);
776
777        return 0;
778}
Note: See TracBrowser for help on using the repository browser.