source: subversion/applications/rendering/gosmore/bboxSplit.cpp @ 27129

Last change on this file since 27129 was 24484, checked in by nic, 9 years ago

bboxSplit: Fix bug in handling of copyright comment in planet file
dailyUpdate now using ftp

  • Property svn:executable set to *
File size: 8.6 KB
Line 
1#include <stdlib.h>
2#include <ctype.h>
3#include <string.h>
4#include <stdio.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <fcntl.h>
8//#include <libxml/xmlreader.h>
9//#include <libxml/xmlwriter.h>
10#include <vector>
11#include <map>
12#include <assert.h>
13using namespace std;
14
15struct younion { // Union of 1 or more bboxes. Terminated with -1.
16  int *i;
17  younion (int *_i) : i (_i) {}
18};
19
20bool operator < (const younion &a, const younion &b)
21{
22  int *ap = a.i, *bp;
23  for (bp = b.i; *bp == *ap && *bp != -1; bp++) ap++;
24  return *ap < *bp;
25}
26
27char buf[2048000]; // I assume the largest object will fit in 1 MB
28
29int main (int argc, char *argv[])
30{
31  int bcnt = (argc - 1) / 6;
32  double b[bcnt][4], lat, lon;
33  FILE *f[bcnt];
34  if (argc <= 1 || argc % 6 != 1) {
35    fprintf (stderr, "Usage: %s bottom left top right pname fname [...]\n"
36      "Reads an OSM-XML file from standard in and cut it into the given rectangles.\n"
37      "pname is exectuted for each rectangle and the XML is piped to it. It's output\n"
38      "is redirected to 'fname'. %s does not properly implement job control, but\n"
39      "gzip, bzip and cat are acceptable values for pname\n" , argv[0], argv[0]);
40    return 1;
41  }
42  for (int i = 0; i < bcnt; i++) {
43    #if 0
44    int p[2]; //p[(argc - 1) / 6][2], i;
45    pipe (p);
46    if (fork () == 0) {
47      close (p[STDOUT_FILENO]);
48      //for (i--; i >= 0; i--) close (p[i][STDOUT_FILENO]);
49      dup2 (p[STDIN_FILENO], STDIN_FILENO);
50      FILE *out = fopen (argv[i * 6 + 6], "w");
51      dup2 (fileno (out), STDOUT_FILENO);
52      execlp (argv[i * 6 + 5], argv[i * 6 + 5], NULL);
53    }
54    f[i] = fdopen (p[STDOUT_FILENO], "w");
55    #else
56    FILE *out = fopen (argv[i*6+6], "w");
57    dup2 (fileno (out), STDOUT_FILENO);
58    f[i] = popen (argv[i*6+5], "w");
59    assert (f[i]);
60    fclose (out);
61    #endif
62    fprintf (f[i], "<?xml version='1.0' encoding='UTF-8'?>\n"
63      "<osm version=\"0.6\" generator=\"bboxSplit %s\">\n"
64      "<bound box=\"%s,%s,%s,%s\"" 
65      /* origin=\"http://www.openstreetmap.org/api/0.6\" */ "/>\n" , __DATE__,
66      argv[i * 6 + 1],  argv[i * 6 + 2], argv[i * 6 + 3], argv[i * 6 + 4]);
67    for (int j = 0; j < 4; j++) b[i][j] = atof (argv[i * 6 + j + 1]);
68  }
69  vector<int*> areas;
70  // This vector maps area ids to a list of bboxes and 'amap' maps a list
71  // of bboxes back to the id.
72  areas.push_back (new int[1]); // Tiny once off memory leak.
73  areas.back ()[0] = -1; // Make 0 the empty area
74  map<younion,int> amap;
75  amap[younion (areas.back ())] = 0;
76 
77  areas.push_back (new int[bcnt + 1]); // Tiny once off memory leak.
78  areas.back ()[0] = -1; // Always have an empty set ready.
79 
80  #define areasIndexType unsigned short
81  vector<areasIndexType> nwr[3]; // Nodes, relations, ways
82  char *start = buf;
83  long tipe[10], id, olevel = 0, memberTipe = 0, ref, acnt = 0, level;
84  for (int cnt = 0, i; (i = fread (buf + cnt, 1, sizeof (buf) - cnt, stdin)) > 0;) {
85    cnt += i;
86    char *ptr = start, *n;
87    level = olevel;
88    do {
89      //printf ("-- %d %.20s\n", level, ptr);
90      int isEnd = (ptr + 1 < buf + cnt) &&
91        ((ptr[0] == '<' && ptr[1] == '/') || (ptr[0] == '/' && ptr[1] == '>'));
92      for (n = ptr; n < buf + cnt &&
93                    (isEnd ? *n != '>' : !isspace (*n) && *n != '/'); n++) {
94        if (*n == '\"') {
95          for (++n; n < buf + cnt && *n != '\"'; n++) {}
96        }
97        else if (*n == '\'') {
98          for (++n; n < buf + cnt && *n != '\''; n++) {}
99        }
100      }
101      if (isEnd && n < buf + cnt) n++; // Get rid of the '>'
102      while (n < buf + cnt && isspace (*n)) n++;
103     
104      if (isEnd && level == 2 && tipe[level - 1] == 'o') { // Note: n may be at buf + cnt
105        nwr[0].clear (); // Free some memory for in case one or more
106        nwr[1].clear (); // processes does heavy postprocessing.
107        nwr[2].clear ();
108        for (int j = 0; j < bcnt; j++) fprintf (f[j], "</osm>\n");
109        // By splitting these two steps we allow downstream XML converters
110        // like gosmore to do their post-XML processing in parallel.
111        for (int j = 0; j < bcnt; j++) pclose (f[j]);
112       
113        // Should we close the files and wait for the children to exit ?
114        fprintf (stderr, "%s done using %ld area combinations\n", argv[0], areas.size () - 1);
115        return 0;
116      }
117      if (n >= buf + cnt) {}
118      else if (isEnd) {
119        //printf ("Ending %c at %d\n", tipe[level - 1], level);
120        if (--level == 2 && tipe[level] == 'n') { // End of a node
121          for (int j = 0; j < bcnt; j++) {
122            if (b[j][0] < lat && b[j][1] < lon && lat < b[j][2] && lon < b[j][3]) {
123              areas.back ()[acnt++] = j;
124            }
125          }
126          areas.back ()[acnt] = -1;
127        }
128        else if ((tipe[level] == 'n' || tipe[level] == 'm')
129                 && level == 3) { // End of an '<nd ..>' or a '<member ...>
130          memberTipe = tipe[2] == 'w' || memberTipe == 'n' ? 0
131                       : memberTipe == 'w' ? 1 : 2;
132          if (ref < nwr[memberTipe].size ()) {
133            for (int j = 0, k = 0; areas[nwr[memberTipe][ref]][j] != -1; j++) {
134              while (k < acnt && areas.back()[k] < areas[nwr[memberTipe][ref]][j]) k++;
135              if (k >= acnt || areas.back()[k] > areas[nwr[memberTipe][ref]][j]) {
136                memmove (&areas.back()[k + 1], &areas.back()[k],
137                  sizeof (areas[0][0]) * (acnt++ - k));
138                areas.back()[k] = areas[nwr[memberTipe][ref]][j];
139              }
140            } // Merge the two lists
141          }
142        }
143        if (level == 2 && acnt > 0) { // areas.back()[0] != -1) {
144        //(tipe[2] == 'n' || tipe[2] == 'w' || tipe[2] == 'r')) { // not needed for valid OSM-XML
145          for (int j = 0; j < acnt /* areas.back()[j] != -1*/; j++) {
146            //assert (areas.back ()[j] < bcnt);
147            fwrite (start, 1, n - start, f[areas.back()[j]]);
148          }
149          areas.back ()[acnt] = -1;
150          map<younion,int>::iterator mf = amap.find (younion (areas.back()));
151          if (mf == amap.end ()) {
152            int pos = areas.size () - 1;
153            if (pos >> (sizeof (areasIndexType) * 8)) {
154              for (int j = 0; j < bcnt; j++) fprintf (f[j], "</osm>\n");
155              // By splitting these two steps we allow downstream XML converters
156              // like gosmore to do their post-XML processing in parallel.
157              for (int j = 0; j < bcnt; j++) pclose (f[j]);
158              fprintf (stderr, "%s FATAL: Too many combinations of areas\n", argv[0]);
159              return 2;
160            }
161            amap[younion (areas.back ())] = pos;
162            mf = amap.find (younion (areas.back()));
163            areas.push_back (new int[bcnt + 1]); // Tiny once off memory leak.
164            //assert (f != amap.end());
165          }
166          int nwrIdx = tipe[2] == 'n' ? 0 : tipe[2] == 'w' ? 1 : 2;
167          //printf (stderr, "Extending %c to %ld\n", tipe[2], id);
168          while (nwr[nwrIdx].size () <= id) nwr[nwrIdx].push_back (0);
169          // Initialize nwr with 0 which implies the empty union
170          nwr[nwrIdx][id] = mf->second;
171          areas.back ()[0] = -1;
172          acnt = 0;
173        } // if we found an entity that belongs to at least 1 bbox
174        if (level == 2) {
175          start = n;
176          olevel = level;
177        }
178      } // If it's /> or </..>
179      else if (*ptr == '<') {
180        if (ptr[1] != '!') tipe[level++] = ptr[1];
181      }
182      // The tests for 'level' is not necessary for valid OSM-XML
183      else if (level == 3 && strncasecmp (ptr, "id=", 3) == 0) {
184        id = atoi (ptr[3] == '\'' || ptr[3] == '\"' ? ptr + 4 : ptr + 3);
185      }
186      else if (level == 3 && strncasecmp (ptr, "lat=", 4) == 0) {
187        lat = atof (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
188      }
189      else if (level == 3 && strncasecmp (ptr, "lon=", 4) == 0) {
190        lon = atof (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
191      }
192      else if (level == 4 && strncasecmp (ptr, "type=", 4) == 0) {
193        memberTipe = ptr[5] == '\'' || ptr[5] == '\"' ? ptr[6] : ptr[5];
194      }
195      else if (level == 4 && strncasecmp (ptr, "ref=", 4) == 0) {
196        ref = atoi (ptr[4] == '\'' || ptr[4] == '\"' ? ptr + 5 : ptr + 4);
197      }
198      ptr = n;
199    } while (ptr + 1 < buf + cnt);
200    memmove (buf, start, buf + cnt - start);
201    cnt -= start - buf;
202    start = buf;
203  }
204  for (int j = 0; j < bcnt; j++) fprintf (f[j], "</osm>\n");
205  // By splitting these two steps we allow downstream XML converters
206  // like gosmore to do their post-XML processing in parallel.
207  for (int j = 0; j < bcnt; j++) pclose (f[j]);
208  fprintf (stderr, "Warning: Xml termination not found. Files should be OK.\n");
209  fprintf (stderr, "%s done using %ld area combinations\n", argv[0], areas.size () - 1);
210  return 1;
211}
Note: See TracBrowser for help on using the repository browser.