source: subversion/applications/rendering/gosmore/libgosm.cpp @ 24484

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

Rebuild now possible under Windows.

  • Property svn:executable set to *
File size: 99.5 KB
Line 
1#ifndef _WIN32
2#include <sys/mman.h>
3#include <fcntl.h>
4#include <sys/stat.h>
5#include <sys/types.h>
6#else
7#include <windows.h>
8#endif
9
10#include <stdio.h>
11#include <unistd.h>
12#include <vector>
13#include <deque>
14#include <string>
15#include <map>
16#include <assert.h>
17#include <float.h>
18using namespace std;
19
20#include "libgosm.h"
21
22routeNodeType *route = NULL, *shortest = NULL;
23routeHeapType *routeHeap;
24long dhashSize, dLength;
25int routeHeapSize, tlat, tlon, flat, flon, rlat, rlon, routeHeapMaxSize;
26int *hashTable, bucketsMin1, pakHead = 0xEB3A943, routeSuccess = FALSE;
27char *gosmData, *gosmSstr[searchCnt];
28
29ndType *ndBase;
30styleStruct *style;
31int stylecount;
32wayType *gosmSway[searchCnt];
33
34// store the maximum speeds (over all waytypes) of each vehicle type
35int TagCmp (const char *a, const char *b)
36{ // This works like the ordering of books in a library : We ignore
37  // meaningless words like "the", "street" and "north". We (should) also map
38  // deprecated words to their new words, like petrol to fuel
39  // TODO : We should consider an algorithm like double metasound.
40  static const char *omit[] = { /* "the", in the middle of a name ?? */
41    "ave", "avenue", "blvd", "boulevard", "byp", "bypass",
42    "cir", "circle", "close", "cres", "crescent", "ct", "court", "ctr",
43      "center",
44    "dr", "drive", "hwy", "highway", "ln", "lane", "loop",
45    "pass", "pky", "parkway", "pl", "place", "plz", "plaza",
46    /* "run" */ "rd", "road", "sq", "square", "st", "street",
47    "ter", "terrace", "tpke", "turnpike", /*trce, trace, trl, trail */
48    "walk",  "way"
49  };
50  static const char *words[] = { "", "first", "second", "third", "fourth",
51    "fifth", "sixth", "seventh", "eighth", "nineth", "tenth", "eleventh",
52    "twelth", "thirteenth", "fourteenth", "fifthteenth", "sixteenth",
53    "seventeenth", "eighteenth", "nineteenth", "twentieth" };
54  static const char *teens[] = { "", "", "twenty ", "thirty ", "fourty ",
55    "fifty ", "sixty ", "seventy ", "eighty ", "ninety " };
56 
57  if (strncasecmp (a, "the ", 4) == 0) a += 4;
58  else if (strncasecmp (a, "rue ", 4) == 0) a += 4;
59  else if (strncasecmp (a, "avenue ", 7) == 0) a += 7;
60  else if (strncasecmp (a, "boulevard ", 10) == 0) a += 10;
61  if (strncasecmp (a, "de ", 3) == 0) a += 3;
62 
63  if (strncasecmp (b, "the ", 4) == 0) b += 4;
64  else if (strncasecmp (b, "rue ", 4) == 0) b += 4;
65  else if (strncasecmp (b, "avenue ", 7) == 0) b += 7;
66  else if (strncasecmp (b, "boulevard ", 10) == 0) b += 10;
67  if (strncasecmp (b, "de ", 3) == 0) b += 3;
68 
69  if (strchr ("WEST", a[0]) && a[1] == ' ') a += 2; // e.g. N 21st St
70  if (strchr ("WEST", b[0]) && b[1] == ' ') b += 2;
71
72  for (;;) {
73    char n[2][30] = { "", "" };
74    const char *ptr[2];
75    int wl[2];
76    for (int i = 0; i < 2; i++) {
77      const char **p = i ? &b : &a;
78      if ((*p)[0] == ' ') {
79        for (int i = 0; i < int (sizeof (omit) / sizeof (omit[0])); i++) {
80          if (strncasecmp (*p + 1, omit[i], strlen (omit[i])) == 0 &&
81              !isalpha ((*p)[1 + strlen (omit[i])])) {
82            (*p) += 1 + strlen (omit[i]);
83            break;
84          }
85        }
86      }
87      if (isdigit (**p) && (!isdigit((*p)[1]) || !isdigit ((*p)[2]))
88              /* && isalpha (*p + strcspn (*p, "0123456789"))*/) {
89        // while (atoi (*p) > 99) (*p)++; // Buggy
90        if (atoi (*p) > 20) strcpy (n[i], teens[atoi ((*p)++) / 10]);
91        strcat (n[i], words[atoi (*p)]);
92        while (isdigit (**p) /*|| isalpha (**p)*/) (*p)++;
93        ptr[i] = n[i];
94        wl[i] = strlen (n[i]);
95      }
96      else {
97        ptr[i] = *p;
98        wl[i] = **p == ' ' ? 1 : strcspn (*p , " \n");
99      }
100    }
101    int result = strncasecmp (ptr[0], ptr[1], wl[0] < wl[1] ? wl[1] : wl[0]);
102    if (result || *ptr[0] == '\0' || *ptr[0] == '\n') return result;
103    if (n[0][0] == '\0') a += wl[1]; // In case b was 21st
104    if (n[1][0] == '\0') b += wl[0]; // In case a was 32nd
105  }
106}
107
108/* 1. Bsearch idx such that
109      ZEnc (way[idx]) < ZEnc (clon/lat) < ZEnc (way[idx+1])
110   2. Fill the list with ways around idx.
111   3. Now there's a circle with clon/clat as its centre and that runs through
112      the worst way just found. Let's say it's diameter is d. There exist
113      4 Z squares smaller that 2d by 2d that cover this circle. Find them
114      with binary search and search through them for the nearest ways.
115   The worst case is when the nearest nodes are far along a relatively
116   straight line.
117*/
118int *GosmIdxSearch (const char *key, unsigned z)
119{
120  int *idx =
121    (int *)(ndBase + hashTable[bucketsMin1 + (bucketsMin1 >> 7) + 2]);
122  for (int l = 0, h = hashTable - idx; ;) {
123    char *tag = gosmData + idx[(h + l) / 2];
124    int diff = TagCmp (tag, key);
125    while (*--tag) {}
126    if (diff > 0 || (diff == 0 &&
127      ZEnc ((unsigned)((wayType *)tag)[-1].clat >> 16, 
128            (unsigned)((wayType *)tag)[-1].clon >> 16) >= z)) h = (h + l) / 2;
129    else l = (h + l) / 2 + 1;
130    if (l >= h) return idx + h;
131  }
132}
133
134void GosmSearch (int clon, int clat, const char *key)
135{
136  __int64 dista[searchCnt];
137  int *idx =
138    (int *)(ndBase + hashTable[bucketsMin1 + (bucketsMin1 >> 7) + 2]);
139  int l = GosmIdxSearch (key, 0) - idx, count;
140//  char *lastName = data + idx[min (hashTable - idx),
141//    int (sizeof (gosmSway) / sizeof (gosmSway[0]))) + l - 1];
142  int cz = ZEnc ((unsigned) clat >> 16, (unsigned) clon >> 16);
143  for (count = 0; count + l < hashTable - idx && count < searchCnt;) {
144    int m[2], c = count, ipos, dir, bits;
145    m[0] = GosmIdxSearch (gosmData + idx[count + l], cz) - idx;
146    m[1] = m[0] - 1;
147    __int64 distm[2] = { -1, -1 }, big = ((unsigned __int64) 1 << 63) - 1;
148    while (c < searchCnt && (distm[0] < big || distm[1] < big)) {
149      dir = distm[0] < distm[1] ? 0 : 1;
150      if (distm[dir] != -1) {
151        for (ipos = c; count < ipos && distm[dir] < dista[ipos - 1]; ipos--) {
152          dista[ipos] = dista[ipos - 1];
153          gosmSway[ipos] = gosmSway[ipos - 1];
154          gosmSstr[ipos] = gosmSstr[ipos - 1];
155        }
156        char *tag = gosmData + idx[m[dir]];
157        gosmSstr[ipos] = tag;
158        while (*--tag) {}
159        gosmSway[ipos] = (wayType*)tag - 1;
160        dista[ipos] = distm[dir];
161        c++;
162      }
163      m[dir] += dir ? 1 : -1;
164
165      if (0 <= m[dir] && m[dir] < hashTable - idx &&
166        TagCmp (gosmData + idx[m[dir]], gosmData + idx[count + l]) == 0) {
167        char *tag = gosmData + idx[m[dir]];
168        while (*--tag) {}
169        distm[dir] = Sqr ((__int64)(clon - ((wayType*)tag)[-1].clon)) +
170          Sqr ((__int64)(clat - ((wayType*)tag)[-1].clat));
171      }
172      else distm[dir] = big;
173    }
174    if (count == c) break; // Something's wrong. idx[count + l] not found !
175    if (c >= searchCnt) {
176      c = count; // Redo the adding
177      for (bits = 0; bits < 16 && dista[searchCnt - 1] >> (bits * 2 + 32);
178        bits++) {}
179/* Print Z's for first solution
180      for (int j = c; j < searchCnt; j++) {
181        for (int i = 0; i < 32; i++) printf ("%d%s",
182          (ZEnc ((unsigned) gosmSway[j]->clat >> 16,
183                 (unsigned) gosmSway[j]->clon >> 16) >> (31 - i)) & 1,
184          i == 31 ? " y\n" : i % 2 ? " " : "");
185      } */
186/* Print centre, up, down, right and left to see if they're in the square
187      for (int i = 0; i < 32; i++) printf ("%d%s", (cz >> (31 - i)) & 1,
188        i == 31 ? " x\n" : i % 2 ? " " : "");
189      for (int i = 0; i < 32; i++) printf ("%d%s", (
190        ZEnc ((unsigned)(clat + (int) sqrt (dista[searchCnt - 1])) >> 16,
191              (unsigned)clon >> 16) >> (31 - i)) & 1,
192        i == 31 ? " x\n" : i % 2 ? " " : "");
193      for (int i = 0; i < 32; i++) printf ("%d%s", (
194        ZEnc ((unsigned)(clat - (int) sqrt (dista[searchCnt - 1])) >> 16,
195              (unsigned)clon >> 16) >> (31 - i)) & 1,
196        i == 31 ? " x\n" : i % 2 ? " " : "");
197      for (int i = 0; i < 32; i++) printf ("%d%s", (
198        ZEnc ((unsigned)clat >> 16,
199              (unsigned)(clon + (int) sqrt (dista[searchCnt - 1])) >> 16) >> (31 - i)) & 1,
200        i == 31 ? " x\n" : i % 2 ? " " : "");
201      for (int i = 0; i < 32; i++) printf ("%d%s", (
202        ZEnc ((unsigned)clat >> 16,
203              (unsigned)(clon - (int) sqrt (dista[searchCnt - 1])) >> 16) >> (31 - i)) & 1,
204        i == 31 ? " x\n" : i % 2 ? " " : "");
205*/     
206      int swap = cz ^ ZEnc (
207        (unsigned) (clat + (clat & (1 << (bits + 16))) * 4 -
208                                              (2 << (bits + 16))) >> 16,
209        (unsigned) (clon + (clon & (1 << (bits + 16))) * 4 -
210                                              (2 << (bits + 16))) >> 16);
211      // Now we search through the 4 squares around (clat, clon)
212      for (int mask = 0, maskI = 0; maskI < 4; mask += 0x55555555, maskI++) {
213        int s = GosmIdxSearch (gosmData + idx[count + l],
214          (cz ^ (mask & swap)) & ~((4 << (bits << 1)) - 1)) - idx;
215/* Print the square
216        for (int i = 0; i < 32; i++) printf ("%d%s",
217          (((cz ^ (mask & swap)) & ~((4 << (bits << 1)) - 1)) >> (31 - i)) & 1,
218          i == 31 ? "\n" : i % 2 ? " " : "");
219        for (int i = 0; i < 32; i++) printf ("%d%s",
220          (((cz ^ (mask & swap)) | ((4 << (bits << 1)) - 1)) >> (31 - i)) & 1,
221          i == 31 ? "\n" : i % 2 ? " " : "");
222*/
223        for (;;) {
224          char *tag = gosmData + idx[s++];
225          if (TagCmp (gosmData + idx[count + l], tag) != 0) break;
226          while (*--tag) {}
227          wayType *w = (wayType*)tag - 1;
228          if ((ZEnc ((unsigned)w->clat >> 16, (unsigned) w->clon >> 16) ^
229               cz ^ (mask & swap)) >> (2 + (bits << 1))) break;
230          __int64 d = Sqr ((__int64)(w->clat - clat)) +
231                      Sqr ((__int64)(w->clon - clon));
232          if (count < searchCnt || d < dista[count - 1]) {
233            if (count < searchCnt) count++;
234            for (ipos = count - 1; ipos > c && d < dista[ipos - 1]; ipos--) {
235              dista[ipos] = dista[ipos - 1];
236              gosmSway[ipos] = gosmSway[ipos - 1];
237              gosmSstr[ipos] = gosmSstr[ipos - 1];
238            }
239            gosmSway[ipos] = w;
240            dista[ipos] = d;
241            gosmSstr[ipos] = gosmData + idx[s - 1];
242          }
243        } // For each entry in the square
244      } // For each of the 4 squares
245      break; // count < searchCnt implies a bug. Don't loop infinitely.
246    } // If the search list is filled by tags with this text
247    count = c;
248  } // For each
249  for (int k = count; k < searchCnt; k++) gosmSstr[k] = NULL;
250}
251
252/*------------------------------- OsmItr --------------------------------*/
253int Next (OsmItr &itr) /* Friend of osmItr */
254{
255  do {
256    itr.nd[0]++;
257    while (itr.nd[0] >= itr.end) {
258      if ((itr.slon += itr.tsize) == itr.right) {
259        itr.slon = itr.left;  /* Here we wrap around from N85 to S85 ! */
260        if ((itr.slat += itr.tsize) == itr.bottom) return FALSE;
261      }
262      int bucket = Hash (itr.slon, itr.slat, itr.tsize != TILESIZE);
263      itr.nd[0] = ndBase + hashTable[bucket];
264      itr.end = ndBase + hashTable[bucket + 1];
265    }
266  } while (((itr.nd[0]->lon ^ itr.slon) & (~(itr.tsize - 1))) ||
267           ((itr.nd[0]->lat ^ itr.slat) & (~(itr.tsize - 1))));
268/*      ((itr.hs[1] = (halfSegType *) (data + itr.hs[0]->other)) > itr.hs[0] &&
269       itr.left <= itr.hs[1]->lon && itr.hs[1]->lon < itr.right &&
270       itr.top <= itr.hs[1]->lat && itr.hs[1]->lat < itr.bottom)); */
271/* while nd[0] is a hash collision, */ 
272  return TRUE;
273}
274
275/* Routing starts at the 'to' point and moves to the 'from' point. This will
276   help when we do in car navigation because the 'from' point will change
277   often while the 'to' point stays fixed, so we can keep the array of nodes.
278   It also makes the generation of the directions easier.
279
280   We use "double hashing" to keep track of the shortest distance to each
281   node. So we guess an upper limit for the number of nodes that will be
282   considered and then multiply by a few so that there won't be too many
283   clashes. For short distances we allow for dense urban road networks,
284   but beyond a certain point there is bound to be farmland or seas.
285
286   We call nodes that recently had their "best" increased "active". The
287   active nodes are stored in a heap so that we can quickly find the most
288   promissing one.
289   
290   OSM nodes are not our "graph-theor"etic nodes. Our "graph-theor"etic nodes
291   are "states", namely the ability to reach nd directly from nd->other[dir]
292*/
293#ifdef ROUTE_CALIBRATE
294int routeAddCnt;
295#define ROUTE_SET_ADDND_COUNT(x) routeAddCnt = (x)
296#define ROUTE_SHOW_STATS printf ("%d / %d\n", routeAddCnt, dhashSize); \
297  fprintf (stderr, "flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&fast=%d&v=motorcar\n", \
298    LatInverse (flat), LonInverse (flon), LatInverse (tlat), \
299    LonInverse (tlon), fast)
300// This ratio must be around 0.5. Close to 0 or 1 is bad
301#else
302#define ROUTE_SET_ADDND_COUNT(x)
303#define ROUTE_SHOW_STATS
304#endif
305
306static ndType *endNd[2] = { NULL, NULL}, from;
307static int toEndNd[2][2];
308
309void GosmFreeRoute (void)
310{
311  if (route) {
312  #ifndef _WIN32
313    munmap (route, (sizeof (*route)) * dhashSize);
314  #else
315    free (route);
316  #endif
317    free (routeHeap);
318    route = NULL;
319  }   
320  routeSuccess = FALSE;
321}
322
323routeNodeType *AddNd (ndType *nd, int dir, int cost, routeNodeType *newshort)
324{ /* This function is called when we find a valid route that consists of the
325     segments (hs, hs->other), (newshort->hs, newshort->hs->other),
326     (newshort->shortest->hs, newshort->shortest->hs->other), .., 'to'
327     with cost 'cost'.
328     
329     When cost is -1, this function just returns the entry for nd without
330     modifying anything. */
331  if (nd->lat == INT_MIN) return NULL; // Nodes missing from OSM-XML
332  unsigned i = 0, hash = (intptr_t) nd / 10 + dir;
333  routeNodeType *n;
334
335  //if ((routeHeapSize & 0xff) == 0) printf ("%d %d\n", dhashSize, routeHeapSize);
336  do {
337    if (i++ > 10) {
338      //fprintf (stderr, "Double hash bailout : Table full. %9d %p\n",
339      //  routeHeapSize, nd);
340      // If you get the
341      return NULL;
342    }
343    n = route + (/*(hash >> 16) ^ */hash) % dhashSize;
344
345    hash -= hash << 6;
346    hash ^= hash >> 17;
347    hash -= hash << 9;
348    hash ^= hash << 4;
349    hash -= hash << 3;
350    hash ^= hash << 10;
351    hash ^= hash >> 15;
352
353//    hash = (unsigned) (hash * (__int64) 1664525 + 1013904223);
354           
355    if (n->nd == NULL) { /* First visit of this node */
356      if (cost < 0) return NULL;
357      if (routeHeapSize >= routeHeapMaxSize) {
358        //printf ("Route Heap too big\n");
359        return NULL;
360      }
361      n->nd = nd;
362      routeHeap[routeHeapSize].best = 0x7fffffff;
363      /* Will do later : routeHeap[routeHeapSize].r = n; */
364      n->heapIdx = routeHeapSize++;
365      n->dir = dir;
366      n->remain = lrint (sqrt (Sqr ((__int64)(nd->lat - rlat)) +
367                               Sqr ((__int64)(nd->lon - rlon))));
368      if (!shortest || n->remain < shortest->remain) shortest = n;
369
370      ROUTE_SET_ADDND_COUNT (routeAddCnt + 1);
371    }
372  } while (n->nd != nd || n->dir != dir);
373
374  routeHeapType h;
375  h.r = n;
376  h.best = cost + n->remain - (!newshort ? 0 : newshort->heapIdx < 0
377    ? newshort->remain + newshort->heapIdx
378    : newshort->remain - routeHeap[newshort->heapIdx].best);
379  // TODO make sure newshort is never in the heap and exploit it.
380  if (cost >= 0 && (n->heapIdx < 0 ? -n->heapIdx : routeHeap[n->heapIdx].best)
381                   > h.best) {
382    n->shortest = newshort;
383    if (n->heapIdx < 0) n->heapIdx = routeHeapSize++;
384    for (; n->heapIdx > 1 && h.best < routeHeap[n->heapIdx / 2].best; n->heapIdx /= 2) {
385      memcpy (routeHeap + n->heapIdx, routeHeap + n->heapIdx / 2,
386        sizeof (*routeHeap));
387      routeHeap[n->heapIdx].r->heapIdx = n->heapIdx;
388    }
389    memcpy (&routeHeap[n->heapIdx], &h, sizeof (routeHeap[n->heapIdx]));
390  }
391  return n;
392}
393
394inline int IsOneway (wayType *w, int Vehicle)
395{
396  return Vehicle != footR &&
397    (w->bits & (1 << (Vehicle == bicycleR ? bicycleOneway : onewayR)));
398  //!((Vehicle == footR || Vehicle == bicycleR) &&
399  //  (w->bits & (1 << motorcarR))) && (w->bits & (1<<onewayR));
400}
401
402// left-hand drive country aproximate bounding boxes
403static const int lhtBbox[][4] = {
404  { Longitude (10.2), Latitude (-85.0), Longitude (42.1), Latitude (4.7) },
405  // Africa. Not correct for Angola, DRC and a few other poor countries.
406  { Longitude (-14.11), Latitude (49.83), Longitude (1.84), Latitude (60.03) },
407  // UK & IE
408  { Longitude (68.0), Latitude (0.0), Longitude (90.2), Latitude (31.4) },
409  // India & Sri Lanka
410  { Longitude (9.3), Latitude (-85.0), Longitude (179.0), Latitude (19.1) },
411  // Aus, NZ, Indonesia, Malazia, Thailand.
412  { Longitude (129.55), Latitude (18.0), Longitude (145.84), Latitude (45.55) }
413  // Japan
414};
415
416static int lht = FALSE, Vehicle, fast;
417
418void Route (int recalculate, int plon, int plat, int _vehicle, int _fast)
419{ /* Recalculate is faster but only valid if 'to', 'Vehicle' and
420     'fast' did not change */
421/* We start by finding the segment that is closest to 'from' and 'to' */
422  ROUTE_SET_ADDND_COUNT (0);
423  shortest = NULL;
424  routeSuccess = FALSE;
425  Vehicle = _vehicle;
426  fast = _fast;
427  for (int i = recalculate ? 0 : 1; i < 2; i++) {
428    int lon = i ? flon : tlon, lat = i ? flat : tlat;
429    __int64 bestd = (__int64) 1 << 62;
430    /* find min (Sqr (distance)). Use long long so we don't loose accuracy */
431    OsmItr itr (lon - 100000, lat - 100000, lon + 100000, lat + 100000);
432    /* Search 1km x 1km around 'from' for the nearest segment to it */
433    while (Next (itr)) {
434      // We don't do for (int dir = 0; dir < 1; dir++) {
435      // because if our search box is large enough, it will also give us
436      // the other node.
437      if (!(Way (itr.nd[0])->bits & (1 << Vehicle))) {
438        continue;
439      }
440      if (itr.nd[0]->other[0] == 0) continue;
441      __int64 lon0 = lon - itr.nd[0]->lon, lat0 = lat - itr.nd[0]->lat,
442              lon1 = lon - (itr.nd[0] + itr.nd[0]->other[0])->lon,
443              lat1 = lat - (itr.nd[0] + itr.nd[0]->other[0])->lat,
444              dlon = lon1 - lon0, dlat = lat1 - lat0;
445      /* We use Pythagoras to test angles for being greater that 90 and
446         consequently if the point is behind hs[0] or hs[1].
447         If the point is "behind" hs[0], measure distance to hs[0] with
448         Pythagoras. If it's "behind" hs[1], use Pythagoras to hs[1]. If
449         neither, use perpendicular distance from a point to a line */
450      int segLen = lrint (sqrt ((double)(Sqr(dlon) + Sqr (dlat))));
451      __int64 d = dlon * lon0 >= - dlat * lat0 ? Sqr (lon0) + Sqr (lat0) :
452        dlon * lon1 <= - dlat * lat1 ? Sqr (lon1) + Sqr (lat1) :
453        Sqr ((dlon * lat1 - dlat * lon1) / segLen);
454     
455      wayType *w = Way (itr.nd[0]);
456      if (i) { // For 'from' we take motion into account
457        __int64 motion = segLen ? 3 * (dlon * plon + dlat * plat) / segLen
458          : 0;
459        // What is the most appropriate multiplier for motion ?
460        if (motion > 0 && IsOneway (w, Vehicle)) d += Sqr (motion);
461        else d -= Sqr (motion);
462        // Is it better to say :
463        // d = lrint (sqrt ((double) d));
464        // if (motion < 0 || IsOneway (w)) d += motion;
465        // else d -= motion;
466      }
467     
468      if (d < bestd) {
469        bestd = d;
470        double invSpeed = !fast ? 1.0 : Style (w)->invSpeed[Vehicle];
471        //printf ("%d %lf\n", i, invSpeed);
472        toEndNd[i][0] =
473          lrint (sqrt ((double)(Sqr (lon0) + Sqr (lat0))) * invSpeed);
474        toEndNd[i][1] =
475          lrint (sqrt ((double)(Sqr (lon1) + Sqr (lat1))) * invSpeed);
476//        if (dlon * lon1 <= -dlat * lat1) toEndNd[i][1] += toEndNd[i][0] * 9;
477//        if (dlon * lon0 >= -dlat * lat0) toEndNd[i][0] += toEndNd[i][1] * 9;
478
479        if (IsOneway (w, Vehicle)) toEndNd[i][1 - i] = 200000000;
480        /*  It's possible to go up a oneway at the end, but at a huge penalty*/
481        endNd[i] = itr.nd[0];
482        /* The router only stops after it has traversed endHs[1], so if we
483           want 'limit' to be accurate, we must subtract it's length
484        if (i) {
485          toEndHs[1][0] -= segLen;
486          toEndHs[1][1] -= segLen;
487        } */
488      }
489    } /* For each candidate segment */
490    if (bestd == ((__int64) 1 << 62) || !endNd[0]) {
491      endNd[i] = NULL;
492      //fprintf (stderr, "No segment nearby\n");
493      return;
494    }
495  } /* For 'from' and 'to', find segment that passes nearby */
496  from.lat = flat;
497  from.lon = flon;
498  if (recalculate || !route) {
499    GosmFreeRoute ();
500    routeHeapSize = 1; /* Leave position 0 open to simplify the math */
501    #ifndef _WIN32
502    // Google "zero-fill-on-demand". Basically all the reasons they mention are valid.
503    // In particular, while gosmore is paused while a page is swapped in, the OS can
504    // zero some pages for us.
505    int dzero = open ("/dev/zero", O_RDWR);
506    long long ds = sysconf (_SC_PAGESIZE) * (long long) sysconf (_SC_PHYS_PAGES) /
507      (sizeof (*routeHeap) + sizeof (*route) + 40);
508    dhashSize = ds > INT_MAX ? INT_MAX : ds;
509    routeHeapMaxSize = lrint (sqrt (dhashSize)) * 3;
510    routeHeap = (routeHeapType*) malloc (routeHeapMaxSize * sizeof (*routeHeap));
511    if (!routeHeap || dzero == -1 ||
512        (route = (routeNodeType*) mmap (NULL, dhashSize * sizeof (*route),
513        PROT_READ | PROT_WRITE, MAP_SHARED, dzero, 0)) == MAP_FAILED) {
514      fprintf (stderr, "Error: Mmap of dnull for routing arrays\n");
515      route = NULL;
516      return;
517    }
518    if (dzero != -1) close (dzero);
519    #else
520    MEMORYSTATUS memStat;
521    GlobalMemoryStatus (&memStat);
522    dhashSize = (memStat.dwAvailPhys - 400000) /
523                 (sizeof (*route) + sizeof (*routeHeap) + 40);
524
525    routeHeapMaxSize = lrint (sqrt (dhashSize)) * 3;
526    routeHeap = (routeHeapType*) malloc (routeHeapMaxSize * sizeof (*routeHeap));
527    if (!routeHeap) return;
528    while (!(route = (routeNodeType*) calloc (sizeof (*route), dhashSize))) {
529      logprintf("calloc(%d) failed ( availPhys=%d , dhashSize=%d )\n",
530        (sizeof(*route)*dhashSize), memStat.dwAvailPhys,dhashSize);
531      dhashSize*=7; dhashSize/=8;
532      if(dhashSize<200000) return;
533    }
534    #endif
535
536    rlat = flat;
537    rlon = flon;
538    AddNd (endNd[0], 0, toEndNd[0][0], NULL);
539    AddNd (endNd[0] + endNd[0]->other[0], 1, toEndNd[0][1], NULL);
540    AddNd (endNd[0], 1, toEndNd[0][0], NULL);
541    AddNd (endNd[0] + endNd[0]->other[0], 0, toEndNd[0][1], NULL);
542
543    #ifdef INSPECT
544    printf ("\ncycleonewa: %s\n",
545      Way (endNd[0])->bits & (1 << bicycleOneway) ? "yes" : "no");
546    #define M(x) printf ("%10s: %s\n", #x, \
547                   Way (endNd[0])->bits & (1 << x ## R) ? "yes" : "no");
548    RESTRICTIONS
549    #undef M
550    // A bit confusing when the user clicks a way on which the selected
551    // vehicle type is not allowed, because endNd will then be a different
552    // way.
553    #endif
554  }
555  else {
556    routeNodeType *frn = AddNd (&from, 0, -1, NULL);
557    if (frn) {
558      if (frn->heapIdx < 0) frn->heapIdx = -0x7fffffff;
559      else routeHeap[frn->heapIdx].best = 0x7fffffff;
560    }
561
562    routeNodeType *rn = AddNd (endNd[1], 0, -1, NULL);
563    if (rn) AddNd (&from, 0, toEndNd[1][1], rn);
564    routeNodeType *rno = AddNd (endNd[1] + endNd[1]->other[0], 1, -1, NULL);
565    if (rno) AddNd (&from, 0, toEndNd[1][0], rno);
566  }
567  lht = FALSE;
568  // keep lht true if we are not in any of the lhtBbox
569  for (size_t i = 0; i < sizeof (lhtBbox) / sizeof (lhtBbox[0]); i++) {
570    lht = lht || (lhtBbox[i][0] < tlon && lhtBbox[i][1] < tlat &&
571                  tlon < lhtBbox[i][2] && tlat < lhtBbox[i][3]);
572  }
573  // printf (lht ? "Left Hand Traffic\n" : "Right Hand Traffic\n");
574}
575
576int RouteLoop (void)
577{
578  // printf ("%ld %ld\n", clock (), CLOCKS_PER_SEC); // Calibrate loop below
579  for (int i = 0; i < 20000 && routeHeapSize > 1; i++) {
580    routeNodeType *root = routeHeap[1].r;
581    root->heapIdx = -routeHeap[1].best; /* Root now removed from the heap */
582    routeHeapSize--;
583    for (int i = 2; i / 2 < routeHeapSize; ) {
584      routeHeapType *end = &routeHeap[routeHeapSize];
585      int sml = i >= routeHeapSize || routeHeap[i].best > end->best
586        ? (i + 1 >= routeHeapSize || routeHeap[i].best > end->best
587           ? routeHeapSize : i + 1)
588        : routeHeap[i].best < routeHeap[i + 1].best ? i : i + 1;
589      memcpy (routeHeap + i / 2, routeHeap + sml, sizeof (*routeHeap));
590      routeHeap[i / 2].r->heapIdx = i / 2;
591      i = sml * 2;
592    }
593    if (root->nd == &from) { // Remove 'from' from the heap in case we
594      shortest = root->shortest; // get called with recalculate=0
595      routeSuccess = TRUE;
596      return FALSE;
597    }
598    if (root->nd == (!root->dir ? endNd[1] : endNd[1] + endNd[1]->other[0])) {
599      AddNd (&from, 0, toEndNd[1][1 - root->dir], root);
600    }
601    ndType *nd = root->nd, *other, *firstNd, *restrictItr;
602    while (nd > ndBase && nd[-1].lon == nd->lon &&
603      nd[-1].lat == nd->lat) nd--; /* Find first nd in node */
604    firstNd = nd; // Save it for checking layout and restrictions
605    int rootIsAdestination = Way (root->nd)->destination & (1 << Vehicle);
606    /* Now work through the segments connected to root. */
607   
608    unsigned layout[4] = { 0, 0, 0, 0 }, lmask = 1, motorRoads = 0;
609    ndType *rtother = root->nd + root->nd->other[root->dir], *layoutNd[4];
610    // We categorize each segment leaving this junction according to the
611    // angle it form with the 'root' segment. The angles are 315 to 45,
612    // 45 to 135, 135 to 225 and 225 to 315 degrees.
613    do {
614      lmask <<= 2;
615      for (int dir = 0; dir < 2; dir++) {
616        if (nd->other[dir] != 0) {
617          other = nd + nd->other[dir];
618          int dot = (other->lat - nd->lat) * (nd->lat - rtother->lat) +
619                    (other->lon - nd->lon) * (nd->lon - rtother->lon);
620          int cross = (other->lat - nd->lat) * (nd->lon - rtother->lon) -
621                      (other->lon - nd->lon) * (nd->lat - rtother->lat);
622          int azimuth = (dot > cross ? 0 : 3) ^ (dot + cross > 0 ? 0 : 1);
623          layout[azimuth] |= lmask << dir;
624          layoutNd[azimuth] = nd;
625          if ((Way (nd)->bits & (1 << motorcarR))) motorRoads++;
626        }
627      }
628    } while (++nd < ndBase + hashTable[bucketsMin1 + 1] &&
629             nd->lon == nd[-1].lon && nd->lat == nd[-1].lat);
630             
631    //printf ("%d %d %d %d\n", layout[0], layout[1], layout[2], layout[3]);
632    nd = firstNd;
633    lmask = 1;
634    do {
635      if (StyleNr (Way (nd)) >= barrier_bollard &&
636          StyleNr (Way (nd)) <= barrier_toll_booth &&
637          !(Way (nd)->bits & (1 << Vehicle))) break;
638      lmask <<= 2;
639      #ifdef _WIN32_WCE
640      if (root->remain > 5500000 && -root->heapIdx - root->remain > 5500000 &&
641      #else
642      if (root->remain > 25500000 && -root->heapIdx - root->remain > 25500000 &&
643      #endif
644          (StyleNr (Way (nd)) == highway_residential ||
645           StyleNr (Way (nd)) == highway_service ||
646           StyleNr (Way (nd)) == highway_living_street ||
647           StyleNr (Way (nd)) == highway_unclassified)) continue;
648      /* When more than 75km from the start and the finish, ignore minor
649         roads. This reduces the number of calculations. */
650      for (int dir = 0; dir < 2; dir++) {
651        if (nd == root->nd && dir == root->dir) continue;
652        /* Don't consider an immediate U-turn to reach root->hs->other.
653           This doesn't exclude 179.99 degree turns though. */
654       
655        if (nd->other[dir] == 0) continue;
656        if (Vehicle != footR && Vehicle != bicycleR) {
657          for (restrictItr = firstNd; restrictItr->other[0] == 0 &&
658                          restrictItr->other[1] == 0; restrictItr++) {
659            wayType *= Way (restrictItr);
660            if (StyleNr (w) >= restriction_no_right_turn &&
661                StyleNr (w) <= restriction_only_straight_on &&
662                atoi ((char*)(w + 1) + 1) == nd->wayPtr &&
663            (StyleNr (w) <= restriction_no_straight_on) ==
664            (atoi (strchr ((char*)(w + 1) + 1, ' ')) == root->nd->wayPtr)) {
665              break;
666            }
667          }
668          if (restrictItr->other[0] == 0 &&
669              restrictItr->other[1] == 0) continue;
670        }
671        // Tagged node, start or end of way or restriction.
672       
673        other = nd + nd->other[dir];
674        wayType *w = Way (nd);
675
676        // // DEBUGGING
677        // char label[255], *strings;
678        // strings=(char*)(w+1)+1;
679        // memset(label,0,255);
680        // strncpy(label,strings,strcspn(strings,"\n"));
681        // printf ("DEBUG: %s (%d) %lf\n", label, StyleNr(w),
682        //      Style(w)->invSpeed[Vehicle]);
683
684
685        int myV = Vehicle == bicycleR && (!(w->bits & (1 << bicycleR)) 
686          || ((w->bits & (1 << bicycleOneway)) && !dir)) ? footR : Vehicle;
687        // If pedestrians are allowed and cyclists not, we can dismount and
688        // walk. The same applies when we can't cycle in the wrong direction.
689        if ((w->bits & (1 << myV)) && (dir || !IsOneway (w, myV))) {
690          int d = lrint (sqrt ((double)
691            (Sqr ((__int64)(nd->lon - other->lon)) +
692             Sqr ((__int64)(nd->lat - other->lat)))) *
693            (!fast ? 1.0 : Style (w)->invSpeed[Vehicle]));
694          if (Vehicle != myV) d *= 4; // Penalty for dismounting
695          if (rootIsAdestination && !(w->destination & (1 << Vehicle))) {
696            d += 5000000; // 500km penalty for entering v='destination' area.
697          }
698         
699          // If (lmask<<dir)&layout[x] is set, we are going approximately
700          // in direction x * 90 degrees, relative to the direction we
701          // are going to (Remember that we are coming from 'root')
702          // If layout[x] is not zero, there are segments going in that
703          // direction
704          if (layout[lht ? 1 : 3] && ((lmask << dir) & layout[lht ? 3 : 1])
705              && fast && Style (w)->scaleMax > 100000) {
706            d += 50000 * (fast ? Style (w)->invSpeed[Vehicle] : 1);
707          // Turning right in the UK (or left in the rest of the world), when
708          // we are on a major road (secondary+) that continues straight on,
709          // you will probably have to wait for oncoming traffic.
710          }
711         
712          if (motorRoads > 2 && fast) d += 5000 * (motorRoads - 2) *
713            (fast ? Style (w)->invSpeed[Vehicle] : 1);
714          // T-junction 50m penalty. 4-way junction 100m penalty.
715         
716          if (layout[1] && layout[3] && ((lmask << dir) & layout[0]) &&
717              Style (Way (layoutNd[1]))->invSpeed[bicycleR] > 1.4) {
718            // Straight over a 4 way junction and it is not preferred by
719            // cyclists. Then there is likely to be traffic that will delay us
720//              d += (Style (Way (layoutNd[1]))->invSpeed[motorcarR] <
721//                    Style (w)->invSpeed[motorcarR] && ? 10000 : 3000) *
722//                    (fast ? Style (w)->invSpeed[Vehicle] : 1);
723            // Crossing a road that is faster that the road we are traveling
724            // on incurs a 100m penalty. If they are equal, the penality is
725            // 30m.
726          }
727         
728          ndType *n2 = root->nd + root->nd->other[root->dir];
729          __int64 straight =
730            (n2->lat - nd->lat) * (__int64)(nd->lat - other->lat) +
731            (n2->lon - nd->lon) * (__int64)(nd->lon - other->lon), left =
732            (n2->lat - nd->lat) * (__int64)(nd->lon - other->lon) -
733            (n2->lon - nd->lon) * (__int64)(nd->lat - other->lat);
734          // Note: We need not calculate these, because we can check the relevant
735          // bits in layout
736           
737          // The code below adds a penalty to making a U-turn when an oncoming road
738          // exists for example where a bidirectional road splits into two oneways.
739          // We can add an extra condition to allow a right turn in right hand
740          // traffic countries. Something like '&& lht ? left : -left > 0)'
741         
742          // Currently the threshold angle is 45 degrees (a turn of more than 135 degrees).
743          // We can vary it using this line:
744          // straight = straight * lrint (tan (M_PI / 180 * 45) * 100) / 100;
745          if (straight < -left && straight < left && layout[2]) d += 50000 *
746            (fast ? Style (w)->invSpeed[Vehicle] : 1);
747          // Note: The layout values I've seen during debugging didn't add up.
748         
749          AddNd (other, 1 - dir, d, root);
750        } // If we found a segment we may follow
751      } // for each direction
752    } while (++nd < ndBase + hashTable[bucketsMin1 + 1] &&
753             nd->lon == nd[-1].lon && nd->lat == nd[-1].lat);
754  } // While there are active nodes left
755  ROUTE_SHOW_STATS;
756//  if (fastest) printf ("%lf
757//  printf ("%lf km\n", limit / 100000.0);
758  return routeHeapSize > 1;
759}
760
761int JunctionType (ndType *nd)
762{
763  int ret = 'j';
764  while (nd > ndBase && nd[-1].lon == nd->lon &&
765    nd[-1].lat == nd->lat) nd--;
766  int segCnt = 0; // Count number of segments at x->shortest
767  do {
768    // TODO : Only count segment traversable by 'Vehicle'
769    // Except for the case where a cyclist passes a motorway_link.
770    // TODO : Don't count oneways entering the roundabout
771    if (nd->other[0] != 0) segCnt++;
772    if (nd->other[1] != 0) segCnt++;
773    if (StyleNr (Way (nd)) == highway_traffic_signals) {
774      ret = 't';
775    }
776    if (StyleNr (Way (nd)) == highway_mini_roundabout) {
777      ret = 'm';
778    }   
779  } while (++nd < ndBase + hashTable[bucketsMin1 + 1] &&
780           nd->lon == nd[-1].lon && nd->lat == nd[-1].lat);
781  return segCnt > 2 ? toupper (ret) : ret;
782}
783
784int GosmInit (void *d, long size)
785{
786  if (!d) return FALSE;
787  gosmData = (char*) d;
788  ndBase = (ndType *)(gosmData + ((int*)(gosmData + size))[-1]);
789  bucketsMin1 = ((int *) (gosmData + size))[-2];
790  stylecount = ((int *) (gosmData + size))[-3];
791  style = (struct styleStruct *)
792    (gosmData + size - sizeof (stylecount) * 3) - stylecount;
793  hashTable = (int *) (style) - bucketsMin1 - (bucketsMin1 >> 7) - 3;
794 
795  memset (gosmSway, 0, sizeof (gosmSway));
796
797  return ndBase && hashTable && *(int*) gosmData == pakHead;
798}
799
800#ifndef _WIN32_WCE
801
802void CalculateInvSpeeds (styleStruct *srec, int styleCnt)
803{
804  // for vehicle
805  for (int i = 0; i < layerBit1; i++) {
806    double maxspeed = 0; // More vehicle limit than (legal) maxspeed.
807    for (int j = 0; j < styleCnt; j++) {
808      maxspeed = max (srec[j].aveSpeed[i], maxspeed);
809    }
810    // for style
811    for (int j = 0; j < styleCnt; j++) {
812      // if no speed is defined for a vehicle on this style, then
813      // set the aveSpeed to be the maximum of any other
814      // vehicles. This speed will only be used if vehicle=yes is
815      // defined on the way. (e.g. highway=foot motorcar=yes)
816      if (srec[j].aveSpeed[i] == 0) { 
817        for (int k = 0; k < layerBit1; k++) {
818          if (srec[j].aveSpeed[i] < srec[j].aveSpeed[k]) {
819            srec[j].aveSpeed[i] = srec[j].aveSpeed[k];
820          } 
821        } // without breaking the normal maximum speed for this vehicle
822        if (srec[j].aveSpeed[i] > maxspeed) {
823          srec[j].aveSpeed[i] = maxspeed;
824        }
825      }
826      // store the proportion of maxspeed for routing
827      srec[j].invSpeed[i] = maxspeed / srec[j].aveSpeed[i];
828    }
829  }
830}
831
832void GosmLoadAltStyle(const char* elemstylefile, const char* iconscsvfile) {
833//  static styleStruct srec[2 << STYLE_BITS];
834  elemstyleMapping map[2 << STYLE_BITS]; // this is needed for
835                                         // LoadElemstyles but ignored
836  styleStruct *old = style;
837  style = (styleStruct*) malloc (stylecount * sizeof (*style)); // Mem leak
838  memcpy (style, old, stylecount * sizeof (*style));
839  //memset (&srec, 0, sizeof (srec)); // defined globally
840  memset (&map, 0, sizeof (map));
841  LoadElemstyles(elemstylefile, iconscsvfile, style, map);
842  CalculateInvSpeeds (style, stylecount);
843}
844
845/*--------------------------------- Rebuild code ---------------------------*/
846// These defines are only used during rebuild
847
848#include <libxml/xmlreader.h>
849#ifndef _WIN32
850#include <sys/mman.h>
851#else
852#define PROT_READ  0x1                       /* Page can be read.  */
853#define PROT_WRITE 0x2                       /* Page can be written.  */
854#define MAP_SHARED 0x01                      /* Share changes.  */
855
856void *mmap (void *ptr, long size, long prot, long type, long handle, long offset)
857{
858  HANDLE file_h, map_h;
859
860  file_h = (HANDLE)_get_osfhandle(handle);
861  map_h  = CreateFileMapping(file_h, 0, PAGE_READWRITE, 0, 0, 0);
862  if (!map_h) return (char *)(-1L);
863  ptr = (void *) MapViewOfFile(map_h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
864
865  CloseHandle(map_h);
866  return ptr;
867}
868
869long munmap (void *ptr, long size)
870{
871  return UnmapViewOfFile (ptr) ? 0 : -1;
872}
873                                               
874#endif
875
876#define MAX_BUCKETS (1<<26)
877#define IDXGROUPS 676
878#define NGROUPS 60
879#define MAX_NODES 17000000 /* Max in a group */
880#define S2GROUPS 129 // Last group is reserved for lowzoom halfSegs
881#define NGROUP(x)  ((x) / MAX_NODES % NGROUPS + IDXGROUPS)
882#define S1GROUPS NGROUPS
883#define S1GROUP(x) ((x) / MAX_NODES % NGROUPS + IDXGROUPS + NGROUPS)
884#define S2GROUP(x) ((x) / (MAX_BUCKETS / (S2GROUPS - 1)) + IDXGROUPS + NGROUPS * 2)
885#define PAIRS (16 * 1024 * 1024)
886#define PAIRGROUPS 120
887#define PAIRGROUP(x) ((x) / PAIRS + S2GROUP (0) + S2GROUPS)
888#define PAIRGROUPS2 120
889#define PAIRGROUP2(x) ((x) / PAIRS + PAIRGROUP (0) + PAIRGROUPS)
890#define FIRST_LOWZ_OTHER (PAIRS * (PAIRGROUPS - 1))
891
892#define REBUILDWATCH(x) fprintf (stderr, "%3d %s\n", ++rebuildCnt, #x); x
893
894#define TO_HALFSEG -1 // Rebuild only
895
896struct halfSegType { // Rebuild only
897  int lon, lat, other, wayPtr;
898};
899
900struct nodeType {
901  int id, lon, lat;
902};
903
904char *data;
905
906inline nodeType *FindNode (nodeType *table, int id)
907{
908  unsigned hash = id;
909  for (;;) {
910    nodeType *n = &table[hash % MAX_NODES];
911    if (n->id < 0 || n->id == id) return n;
912    hash = hash * (__int64) 1664525 + 1013904223;
913  }
914}
915
916int HalfSegCmp (const halfSegType *a, const halfSegType *b)
917{
918  int lowz = a->other < -2 || FIRST_LOWZ_OTHER <= a->other;
919  int hasha = Hash (a->lon, a->lat, lowz), hashb = Hash (b->lon, b->lat, lowz);
920  return hasha != hashb ? hasha - hashb : a->lon != b->lon ? a->lon - b->lon :
921    a->lat != b->lat ? a->lat - b->lat :
922    (b->other < 0 && b[1].other < 0 ? 1 : 0) -
923    (a->other < 0 && a[1].other < 0 ? 1 : 0);
924} // First sort by hash bucket, then by lon, then by lat.
925// If they are all the same, the nodes goes in the front where so that it's
926// easy to iterate through the turn restrictions.
927
928int IdxCmp (const void *aptr, const void *bptr)
929{
930  char *ta = data + *(unsigned *)aptr, *tb = data + *(unsigned *)bptr;
931  int tag = TagCmp (ta, tb);
932  while (*--ta) {}
933  while (*--tb) {}
934  unsigned a = ZEnc ((unsigned)((wayType *)ta)[-1].clat >> 16, 
935                     (unsigned)((wayType *)ta)[-1].clon >> 16);
936  unsigned b = ZEnc ((unsigned)((wayType *)tb)[-1].clat >> 16, 
937                     (unsigned)((wayType *)tb)[-1].clon >> 16);
938  return tag ? tag : a < b ? -1 : 1;
939}
940
941/* To reduce the number of cache misses and disk seeks we need to construct
942 the pack file so that waysTypes that are physically close to each other, are
943 also close to each other in the file. We only know where ways are physically
944 after the first pass, so the reordering is one done during a bbox rebuild.
945 
946 Finding an optimal solution is quite similar to find a soluting to the
947 traveling salesman problem. Instead we just place them in 2-D Hilbert curve
948 order using a qsort. */
949typedef struct {
950  wayType *w;
951  int idx;
952} masterWayType;
953
954int MasterWayCmp (const void *a, const void *b)
955{
956  int r[2], t, s, i, lead;
957  for (i = 0; i < 2; i++) {
958    t = ZEnc (((masterWayType *)(i ? b : a))->w->clon >> 16,
959      ((unsigned)((masterWayType *)(i ? b : a))->w->clat) >> 16);
960    s = ((((unsigned)t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1)) ^ ~t;
961    for (lead = 1 << 30; lead; lead >>= 2) {
962      if (!(t & lead)) t ^= ((t & (lead << 1)) ? s : ~s) & (lead - 1);
963    }
964    r[i] = ((t & 0xaaaaaaaa) >> 1) ^ t;
965  }
966  return r[0] < r[1] ? 1 : r[0] > r[1] ? -1 : 0;
967}
968
969int LoadElemstyles(/* in */ const char *elemstylesfname, 
970                   const char *iconsfname,
971                   /* out */ styleStruct *srec, elemstyleMapping *map)
972{
973   //------------------------- elemstyle.xml : --------------------------
974    int ruleCnt = 0, styleCnt = firstElemStyle;
975    // zero-out elemstyle-to-stylestruct mappings
976    FILE *icons_csv = fopen (iconsfname, "rb");
977    xmlTextReaderPtr sXml = xmlNewTextReaderFilename (elemstylesfname);
978    if (!sXml || !icons_csv) {
979      fprintf (stderr, "Either icons.csv or elemstyles.xml not found\n");
980      return 3;
981    }
982    styleStruct s;
983    memset (&s, 0, sizeof (s));
984    s.lineColour = -1;
985    s.areaColour = -1;
986
987    for (int i = 0; i < styleCnt; i++) memcpy (&srec[i], &s, sizeof (s));
988
989    /* If elemstyles contain these, we can delete these assignments : */
990    for (int i = restriction_no_right_turn;
991            i <= restriction_only_straight_on; i++) {
992      strcpy(map[i].style_k,"restriction");
993      srec[i].scaleMax = 1;
994      srec[i].lineColour = 0; // Make it match.
995    }
996    strcpy(map[restriction_no_right_turn].style_v,"no_right_turn");
997    strcpy(map[restriction_no_left_turn].style_v,"no_left_turn");
998    strcpy(map[restriction_no_u_turn].style_v,"no_u_turn");
999    strcpy(map[restriction_no_straight_on].style_v,"no_straight_on");
1000    strcpy(map[restriction_only_right_turn].style_v,"only_right_turn");
1001    strcpy(map[restriction_only_left_turn].style_v,"only_left_turn");
1002    strcpy(map[restriction_only_straight_on].style_v,"only_straight_on");
1003    /* These strcpys are necessary because elemstyles does not contain them */
1004   
1005    while (xmlTextReaderRead (sXml)) {
1006      char *name = (char*) xmlTextReaderName (sXml);
1007      //xmlChar *val = xmlTextReaderValue (sXml);
1008      if (xmlTextReaderNodeType (sXml) == XML_READER_TYPE_ELEMENT) {
1009        if (strcasecmp (name, "scale_max") == 0) {
1010          while (xmlTextReaderRead (sXml) && // memory leak :
1011            xmlStrcmp (xmlTextReaderName (sXml), BAD_CAST "#text") != 0) {}
1012          s.scaleMax = atoi ((char *) xmlTextReaderValue (sXml));
1013        }
1014        while (xmlTextReaderMoveToNextAttribute (sXml)) {
1015          char *n = (char *) xmlTextReaderName (sXml);
1016          char *v = (char *) xmlTextReaderValue (sXml);
1017          if (strcasecmp (name, "condition") == 0) {
1018            if (strcasecmp (n, "k") == 0) strcpy(map[styleCnt].style_k, v);
1019            if (strcasecmp (n, "v") == 0) strcpy(map[styleCnt].style_v, v);
1020          }
1021          if (strcasecmp (name, "line") == 0) {
1022            if (strcasecmp (n, "width") == 0) {
1023              s.lineWidth = atoi (v);
1024            }
1025            if (strcasecmp (n, "realwidth") == 0) {
1026              s.lineRWidth = atoi (v);
1027            }
1028            if (strcasecmp (n, "colour") == 0) {
1029              sscanf (v, "#%x", &s.lineColour);
1030            }
1031            if (strcasecmp (n, "colour_bg") == 0) {
1032              sscanf (v, "#%x", &s.lineColourBg);
1033            }
1034            s.dashed = s.dashed ||
1035              (strcasecmp (n, "dashed") == 0 && strcasecmp (v, "true") == 0);
1036          }
1037          if (strcasecmp (name, "area") == 0) {
1038            if (strcasecmp (n, "colour") == 0) {
1039              sscanf (v, "#%x", &s.areaColour);
1040            }
1041          }
1042          if (strcasecmp (name, "icon") == 0) {
1043            if (strcasecmp (n, "src") == 0) {
1044              /*while (v[strcspn ((char *) v, "/ ")]) {
1045                v[strcspn ((char *) v, "/ ")] = '_';
1046              }*/
1047              char line[400], fnd = FALSE;
1048              static const char *set[] = { "map-icons/classic.big/",
1049                "map-icons/classic.small/", "map-icons/square.big/",
1050                "map-icons/square.small/" };
1051              for (int i = 0; i < 4; i++) {
1052                s.x[i * 4 + 2] = s.x[i * 4 + 3] = 1;
1053              // Default to 1x1 dummys
1054                int slen = strlen (set[i]), vlen = strlen (v);
1055                rewind (icons_csv);
1056                while (fgets (line, sizeof (line) - 1, icons_csv)) {
1057                  if (strncmp (line, set[i], slen) == 0 &&
1058                      strncmp (line + slen, v, vlen - 1) == 0) {
1059                    sscanf (line + slen + vlen, ":%d:%d:%d:%d",
1060                      s.x + i * 4,     s.x + i * 4 + 1,
1061                      s.x + i * 4 + 2, s.x + i * 4 + 3);
1062                    fnd = TRUE;
1063                  }
1064                }
1065              }
1066              if (!fnd) fprintf (stderr, "Icon %s not found\n", v);
1067            }
1068          }
1069          if (strcasecmp (name, "routing") == 0 && atoi (v) > 0) {
1070            #define M(field) if (strcasecmp (n, #field) == 0) {\
1071              map[styleCnt].defaultRestrict |= 1 << field ## R; \
1072              s.aveSpeed[field ## R] = atof (v); \
1073            }
1074            RESTRICTIONS
1075            #undef M
1076          }
1077         
1078          xmlFree (v);
1079          xmlFree (n);
1080        }
1081      }
1082      else if (xmlTextReaderNodeType (sXml) == XML_READER_TYPE_END_ELEMENT
1083                  && strcasecmp ((char *) name, "rule") == 0) {
1084        int ipos;
1085        #define s(k,v,shortname,extraTags) { #k, #v },
1086        static const char *stylet[][2] = { STYLES };
1087        #undef s
1088        for (ipos = 0; ipos < firstElemStyle; ipos++) {
1089          if (strcmp (stylet[ipos][0], map[styleCnt].style_k) == 0 && 
1090              strcmp (stylet[ipos][1], map[styleCnt].style_v) == 0) break;
1091        }
1092        map[ipos < firstElemStyle ? ipos : styleCnt].ruleNr = ruleCnt++;
1093        if (ipos < firstElemStyle) {
1094          memcpy (&srec[ipos], &s, sizeof (srec[ipos]));
1095          map[ipos].defaultRestrict = map[styleCnt].defaultRestrict;
1096          map[styleCnt].defaultRestrict = 0;
1097          strcpy(map[ipos].style_k,map[styleCnt].style_k);
1098          strcpy(map[ipos].style_v,map[styleCnt].style_v);
1099        }
1100        else if (styleCnt < (2 << STYLE_BITS) - 2) {
1101          memcpy (&srec[styleCnt++], &s, sizeof (srec[0]));
1102        }
1103        else fprintf (stderr, "Too many rules. Increase STYLE_BITS\n");
1104
1105        memset (&s, 0, sizeof (s));
1106        s.lineColour = -1;
1107        s.areaColour = -1;
1108      }
1109      xmlFree (name);
1110      //xmlFree (val);     
1111    }
1112
1113    xmlFreeTextReader (sXml);
1114
1115    return styleCnt;
1116}
1117
1118struct ltstr
1119{
1120  bool operator ()(const char *a, const char *b) const
1121  {
1122    return strcmp (a, b) < 0;
1123  }
1124};
1125
1126struct k2vType {
1127  map<const char *, const char *, ltstr> m;
1128  const char *operator[](const char *k) const
1129  {
1130    return m.find (k) == m.end () ? NULL : m.find (k)->second;
1131  } // For std:map the operator[] is not const, so we wrap it in a new class
1132};
1133
1134typedef char *membershipType;
1135
1136inline char *Role (membershipType rt)
1137{
1138  return !rt ? NULL : rt + strlen (rt) + 1;
1139}
1140
1141char *Find (membershipType rt, const char *key)
1142{
1143  if (!rt) return NULL;
1144  rt += strlen (rt) + 1; // id
1145  rt += strlen (rt) + 1; // role
1146  while (*rt != '\0' && strcmp (key, rt) != 0) {
1147    rt += strlen (rt) + 1; // id
1148    rt += strlen (rt) + 1; // role   
1149  }
1150  return *rt == '\0' ? NULL : rt + strlen (rt) + 1;
1151}
1152
1153membershipType Next (membershipType rt)
1154{
1155  if (!rt) return NULL;
1156  membershipType old = rt;
1157  while (*rt != '\0') {
1158    rt += strlen (rt) + 1; // id or k
1159    rt += strlen (rt) + 1; // role or v
1160  }
1161  return strcmp (rt + 1, old) == 0 ? rt + 1 : NULL; // Compare ids
1162}
1163
1164//----------------------------[ Osm2Gosmore ]-----------------------------
1165// This function translates the complicated and ever changing language of
1166// OSM into the superfast Gosmore language.
1167//
1168// Before Gosmore calls this function it will have matched the tags to
1169// an entry in elemstyles.xml and filled in 's'. If there are multiple
1170// matches, the first one is chosen. You can modify the values of 's',
1171// but be aware that the number of different 's' records are limited. So
1172// you should map (quantitize) rarely used values (like 38 km/h) to more
1173// frequently used values (like 40 km/h).
1174//
1175// It will also have filled in the access and destination fields of w.
1176// During a second pass, the center point of w will also be valid. So
1177// you can test if the way was inside any object for which you have data,
1178// like a city. Or you can adjust the average speed of unpaved ways based on
1179// an average annual rainfall map.
1180//
1181// You are also supplied with the relations table (rStart and rEnd). It has
1182// one entry for each relation that the the object is a member of. Use
1183// Next () to iterate through them, Role () to determine how it affects this
1184// way and Find () to examine the it's tags.
1185//
1186// You must return a list of strings which will be concatenated into the
1187// storage of the object and indexed for searching purposes. Normally each
1188// string will occupy one line (end in '\n'). For
1189// example { "Macdonalds\n", "restaurant\n" }.
1190// Empty lines are removed and will not be indexed. And strings can span
1191// any number of lines. So
1192//   { "Jerusalem\nar:", "al-Quds\n" } is equivalent to
1193//   { "Jerusalem\n", "\nar:", "al-Quds\n" }
1194// and it means that the object can be searched for as Jerusalem and al-Quds.
1195// Furthermore, a clever renderer can then render the correct name.
1196// A single line can also be indexed multiple times. For example
1197// { "city:", "Paris\n" } will be indexed as "Paris" and "city:Paris".
1198//
1199// NOTE: Gosmore currently requires that you return the same strings during
1200// both passes of the rebuild, i.e. the strings cannot depend on w.clat or clon
1201
1202deque<string> Osm2Gosmore (int /*id*/, k2vType &k2v, wayType &w,
1203  styleStruct &s, int isNode, int isRelation, membershipType membership,
1204  k2vType &wayRole /* Only for relations, and only for those members who are ways.
1205                      role->file offset in decimal */)
1206{
1207  deque<string> result;
1208 
1209/*  char idStr[12]; // Add way id so that it appear in cgi-bin output
1210  sprintf (idStr, "%d", idStr);
1211  result.push_front (string (idStr) + '\n'); */
1212 
1213  // First add name and 'ref' to the front so that they are displayed
1214  if (k2v["name"]) {
1215    result.push_front (string (k2v["name"]) + "\n");
1216    if (k2v["place"] && strcmp (k2v["place"], "city") == 0) {
1217      result.push_back ("city:" + string (k2v["name"]) + "\n");
1218    }
1219  }
1220  else if (k2v["left:district"]) {
1221    result.push_front (string ("\n") + k2v["left:district"] + '\n');
1222  }
1223  else if (k2v["right:district"]) {
1224    result.push_front (string ("\n") + k2v["right:district"] + '\n');
1225  }
1226  else if (k2v["left:municipality"]) {
1227    result.push_front (string ("\n") + k2v["left:municipality"] + '\n');
1228  }
1229  else if (k2v["right:municipality"]) {
1230    result.push_front (string ("\n") + k2v["right:municipality"] + '\n');
1231  }
1232  else {
1233    membershipType m; // Could be something like a boundary
1234    for (m = membership; m && !Find (m, "name"); m = Next (m)) {}
1235    if (m) result.push_front (string ("\n") + Find (m, "name") + '\n');
1236    // Put name on a new line so that it will not be indexed.
1237  }
1238 
1239  if (k2v["ref"]) result.push_back (string (k2v["ref"]) + "\n");
1240  if (k2v["operator"]) result.push_back (string (k2v["operator"]) + "\n");
1241  map<const char *, const char *, ltstr>::iterator i = k2v.m.begin ();
1242  // Go through all the tags and add all the interesting things to 'result'
1243  // so that they will be indexed.
1244  for (; i != k2v.m.end (); i++) {
1245    if (strcmp (i->first, "name") != 0 &&
1246        strcmp (i->first, "ref") != 0 &&
1247        strcmp (i->first, "operator") != 0 &&
1248        strncasecmp (i->first, "tiger:", 6) != 0 &&
1249        strcmp (i->first, "created_by") != 0 &&
1250        strcmp (i->first, "converted_by") != 0 &&
1251        strncasecmp (i->first, "source", 6) != 0 &&
1252        strncasecmp (i->first, "AND_", 4) != 0 &&
1253        strncasecmp (i->first, "AND:", 4) != 0 &&
1254        strncasecmp (i->first, "kms:", 4) != 0 &&
1255        strncasecmp (i->first, "LandPro08:", 10) != 0 &&
1256        strncasecmp (i->first, "NHD:", 4) != 0 &&
1257        strncasecmp (i->first, "massgis:", 8) != 0 &&
1258        strncasecmp (i->first, "scgis-shp:", 10) != 0 &&
1259        strcmp (i->first, "addr:street") != 0 &&
1260        strcmp (i->first, "addr:postcode") != 0 &&
1261        strcmp (i->first, "addr:district") != 0 &&
1262        strcmp (i->first, "addr:region") != 0 &&
1263        strcmp (i->first, "addr:state") != 0 &&
1264        strcmp (i->first, "addr:city") != 0 &&
1265        strcmp (i->first, "addr:country") != 0 &&
1266        !(strcmp (i->first, "addr:conscriptionnumber") == 0 && k2v["addr:housenumber"]) &&
1267        // The mvcr:adresa import sets both the conscription number & housenumber
1268        !(strcmp (i->first, "postal_code") == 0 && !isNode) &&
1269        // Many European ways include the postal code. Although it's nice to be able to
1270        // highlight all the streets in a postal code (after searching), it's more likely
1271        // to slow down the software unnecessarily.
1272
1273        strncasecmp (i->first, "KSJ2:", 5) != 0 && 
1274        strncasecmp (i->first, "geobase:", 8)  != 0 &&
1275        strncasecmp (i->first, "kms:", 4)  != 0 &&
1276        strncasecmp (i->first, "openGeoDB:", 10)  != 0 &&
1277        strncasecmp (i->first, "gnis:", 5)  != 0 &&
1278        strncasecmp (i->first, "CLC:", 4)  != 0 && // CORINE Land Cover
1279
1280        strcmp (i->second, // Abuse of the 'note' tag !
1281          "Experimental import of Irish places and POIs from GNS Dataset") != 0 &&
1282        strcmp (i->second, // What is the difference between Key:comment and Key:note ?
1283          "Experimental import of Canadian places and POIs from GNS Dataset") != 0 &&
1284       
1285        strncasecmp (i->first, "gns:", 4)  != 0 &&
1286        strcmp (i->first, "place_county") != 0 && 
1287       
1288        strcmp (i->first, "code_department") != 0 && // France / EtienneChoveBot
1289        strcmp (i->first, "ref:INSEE") != 0 && // France / EtienneChoveBot
1290
1291        strncasecmp (i->first, "it:fvg:ctrn:", 12)  != 0 && // What is this??
1292
1293        strncasecmp (i->first, "3dshapes:", 9)  != 0 && // Import in the Netherlands
1294
1295        strncasecmp (i->first, "TMC:", 4)  != 0 && // Traffic broadcast info esp. Germany
1296
1297        strncasecmp (i->first, "cladr:", 6)  != 0 && // Some Russian import
1298       
1299        strncmp (i->first, "BP:", 2)  != 0 && // British Petroleum import
1300        strcmp (i->first, "amenity:eftpos") != 0 && // Payment method not important
1301
1302        strncasecmp (i->first, "chile:", 6)  != 0 && // vialidad.cl import
1303        strncasecmp (i->first, "navibot:", 8)  != 0 && // navimont's tag
1304       
1305        strncasecmp (i->first, "is_in:", 6)  != 0 && // teryt
1306       
1307        strncasecmp (i->first, "teryt:", 6)  != 0 && // in Poland
1308
1309        strncasecmp (i->first, "naptan:", 7)  != 0 && // UK bus stops
1310        !((strcmp (i->first, "local_ref") == 0 || strcmp (i->first, "name") == 0 ||
1311          /* strcmp (i->first, "route_ref") == 0 ||*/ strcmp (i->first, "asset_ref") == 0 ||
1312           strcmp (i->first, "ref") == 0) && k2v["naptan:CommonName"]) &&
1313        // This second test removes the names, refs and local_refs from naptan bus stops,
1314        // as the information is not very useful.
1315       
1316        (strcmp (i->first, "census:population") != 0 || !k2v["population"]) && // GNIS import
1317       
1318        strncmp (i->first, "qroti:", 6) != 0 &&
1319
1320        strcmp (i->first, "area") != 0 && // Too vague
1321        strcmp (i->first, "building") != 0 &&
1322        strcmp (i->first, "building:use") != 0 &&
1323
1324        strcmp (i->second, "surveillance") != 0 && // man_made=...
1325        strcmp (i->first, "surveillance") != 0 && // e.g. ...=indoor
1326        // I doubt anyone will have a legal reason to search for a security camera
1327       
1328        strcmp (i->first, "note:ja") != 0 &&
1329       
1330        !(strcmp (i->first, "ref") == 0 && strncmp (i->second, "http://", 7) == 0) &&
1331        // Abused during the EPA import
1332
1333        strcmp (i->second, "tree") != 0 && // A few of these in Berlin
1334       
1335        strncasecmp (i->first, "CoCT:",5) != 0 && // Cape Town import
1336       
1337        strcmp (i->first, "import_uuid") != 0 &&
1338        strcmp (i->first, "attribution") /* Mostly MassGIS */ != 0 &&
1339        strcmp (i->second, "paved") != 0 && //surface=paved is the default
1340        strcmp (i->first, "layer") != 0 &&
1341        strcmp (i->first, "history") != 0 &&
1342        strcmp (i->first, "direction") != 0 &&
1343        strcmp (i->first, "maxspeed") != 0 &&
1344        strcmp (i->first, "maxwidth") != 0 &&
1345        strcmp (i->first, "access") != 0 &&
1346        strcmp (i->first, "motorcar") != 0 &&
1347        strcmp (i->first, "bicycle") != 0 &&
1348        strcmp (i->first, "foot") != 0 &&
1349        strcmp (i->first, "goods") != 0 &&
1350        strcmp (i->first, "hgv") != 0 &&
1351        strcmp (i->first, "horse") != 0 &&
1352        strcmp (i->first, "motorcycle") != 0 &&
1353        strcmp (i->first, "psv") != 0 &&
1354        strcmp (i->first, "moped") != 0 &&
1355        strcmp (i->first, "mofa") != 0 &&
1356        strcmp (i->first, "motorboat") != 0 &&
1357        strcmp (i->first, "boat") != 0 &&
1358        strcmp (i->first, "oneway") != 0 &&
1359        strcmp (i->first, "roundabout") != 0 &&
1360        strcmp (i->first, "time") != 0 &&
1361        strcmp (i->first, "timestamp") != 0 && // User WanMil in Luxembourg
1362        strcmp (i->first, "ele") != 0 &&
1363        strcmp (i->first, "hdop") != 0 &&
1364        strcmp (i->first, "sat") != 0 &&
1365        strcmp (i->first, "pdop") != 0 &&
1366        strcmp (i->first, "speed") != 0 &&
1367        strcmp (i->first, "course") != 0 &&
1368        strcmp (i->first, "fix") != 0 &&
1369        strcmp (i->first, "vdop") != 0 &&
1370        strcmp (i->first, "image") != 0 && // =http://www.flickr...
1371        strcmp (i->second, "no") != 0      &&
1372        strcmp (i->second, "false") != 0 &&
1373        strcmp (i->first, "sagns_id") != 0 &&
1374        strcmp (i->first, "sangs_id") != 0 &&
1375        strcmp (i->first, "is_in") != 0 &&
1376        strcmp (i->second, "level_crossing") != 0 && // railway=level_crossing
1377        strcmp (i->second, "living_street") != 0 &&
1378        strcmp (i->second, "residential") != 0 &&
1379        strcmp (i->second, "unclassified") != 0 &&
1380        strcmp (i->second, "tertiary") != 0 &&
1381        strcmp (i->second, "secondary") != 0 && 
1382        strcmp (i->second, "primary") != 0 && // Esp. ValidateMode
1383        strcmp (i->first, "service") != 0 && // =driveway/parking_aisle is trivial
1384        strcmp (i->second, "junction") != 0 && 
1385   /* Not approved and when it isn't obvious
1386      from the ways that it's a junction, the tag will
1387      often be something ridiculous like
1388      junction=junction ! */
1389        // blocked as highway:  strcmp (i->second, "mini_roundabout") != 0
1390        //                      && strcmp (i->second, "roundabout") != 0
1391        strcmp (i->second, "place_of_worship") != 0 && // Too vague to include
1392        strcmp (i->first, "crossing") != 0 &&
1393        strcmp (i->first, "barrier") != 0 &&
1394        strcmp (i->second, "traffic_signals") != 0 &&
1395        strcmp (i->first, "editor") != 0 &&
1396        strcmp (i->first, "power") != 0 && // Power towers
1397        strcmp (i->first, "class") != 0 /* esp. class=node */ &&
1398        strcmp (i->first, "type") != 0 &&
1399        /* "type=..." is only allow for boules grounds. We block it because it
1400        is often misused. */
1401         0 != strcmp (i->second, 
1402  "National-Land Numerical Information (Railway) 2007, MLIT Japan") &&
1403         0 != strcmp (i->second, 
1404  "National-Land Numerical Information (Lake and Pond) 2005, MLIT Japan") &&
1405         0 != strcmp (i->second, 
1406  "National-Land Numerical Information (Administrative area) 2007, MLIT Japan") &&
1407         strcmp (i->second, "coastline_old") != 0 &&
1408         strcmp (i->first, "upload_tag") != 0 &&
1409         strcmp (i->first, "admin_level") != 0 &&
1410         (!isNode || (strcmp (i->first, "highway") != 0 &&
1411                      strcmp (i->second, "water") != 0 &&
1412                      strcmp (i->first, "abutters") != 0 &&
1413                      strcmp (i->second, "coastline") != 0))) {
1414      result.push_back (
1415        strcmp (i->first, "population") == 0 ? string ("\npop. ") + i->second + '\n':
1416        // Don't index population figures, but make it obvious what it is.
1417        strcmp (i->first, "highway") == 0 ? string ("\n ") :
1418        // This is to save space. We don't drop the tag completely because we don't
1419        // footways, service roads, cycleways etc to have empty strings because
1420        // ValidateMode will highlight them.
1421        strcmp (i->first, "phone") == 0 || strcmp (i->first, "addr:housenumber") == 0 ?
1422          string ("\n") + i->second + '\n':
1423        // Don't index highway types, phonenumbers or housenumbers.
1424        // Some day I hope to include housenumber data into the data for the street it is on.
1425        // Then, when the user enters a housenumber and a street name,
1426        // we search by street and filter by housenumber
1427        strcmp (i->first, "noexit") == 0 ? string ("\nnoexit\n") :
1428        // Don't index noexit
1429        strncasecmp (i->first, "wikipedia", 9) == 0 ?
1430                         string ("\nwikipedia\n") :
1431        // Don't index wikipedia names, but make it obvious that it's on there.
1432        string (strcmp (i->second, "true") == 0 ||
1433                strcmp (i->second, "yes") == 0 || strcmp (i->second, "1") == 0
1434                ? strncasecmp (i->first, "amenity:", 8) == 0 ? i->first + 8
1435                // Strip off amenity: from things like amenity:restaurant (BP import)
1436                : strcmp (i->first, "bridge") == 0 ? "\nbridge"
1437                // No need to index bridge
1438                : i->first : i->second) + "\n");
1439    }
1440  }
1441  membershipType m;
1442  for (m = membership; m && !(Find (m, "route") &&
1443    strcmp (Find (m, "route"), "bicycle") == 0); m = Next (m)) {}
1444  // We go through all the relations (regardless of role), but stop if we find
1445  // one with route=bicycle. Then m will be set.
1446  if (m || k2v["lcn_ref"] || k2v["rcn_ref"] || k2v["ncn_ref"]) {
1447    // if part of a cycle route relation or if it has a cycle network reference
1448    s.aveSpeed[bicycleR] = 20;
1449    // then we say cyclists will love it.
1450  }
1451  for (m = membership; m; m = Next (m)) {
1452    if (Find (m, "route")) {
1453      result.push_back (string (Find (m, "relation_id")) + '\n');
1454    } // If it's a route add it's relation_id and index it.
1455  }
1456 
1457  if (isRelation && k2v["restriction"] && wayRole["from"] && wayRole["to"]) {
1458    result.push_front (
1459      string ("\n") + wayRole["from"] + ' ' + wayRole["to"] + '\n');
1460    // A turn restriction with both a 'from' and a 'to'. Put the offsets (not
1461    // OSM-ids) encoded as decimal (ASCII) where the router expects them.
1462   
1463  }
1464  // Reduce the aveSpeeds when maxspeed mandates it
1465  if (k2v["maxspeed"] && isdigit (k2v["maxspeed"][0])) {
1466    const char *m = k2v["maxspeed"];
1467    double maxs = atof (m), best = 30, m2km = 1.609344;
1468    // Here we find the first alphabetic character and compare it to 'm'
1469    if (tolower (m[strcspn (m, "KMPSkmps")]) == 'm') maxs *= m2km;
1470    // choose the closest of these values ...
1471    int v[] = { 5,7,10,15,20,30,32,40,45,50,60,70,80,90,100,110,120,130 };
1472    for (unsigned i = 0; i < sizeof (v) / sizeof (v[1]); i++) {
1473      // ... either in km/h
1474      if (fabs (maxs - best) > fabs (maxs - v[i])) best = v[i];
1475      // ... or in miles/h
1476      if (fabs (maxs - best) > fabs (maxs - v[i] * m2km)) best = v[i] * m2km;
1477    }
1478    s.aveSpeed[accessR] = best;
1479    for (int i = 0; i < layerBit1; i++) {
1480      if (s.aveSpeed[i] > best) s.aveSpeed[i] = best;
1481    }
1482  }
1483  // Now adjust for track type.
1484  if (k2v["tracktype"] && isdigit (k2v["tracktype"][5])) {
1485    s.aveSpeed[motorcarR] *= ('6' - k2v["tracktype"][5]) / 5.0;
1486    // Alternatively use ... (6 - atoi (k2v["tracktype"] + 5)) / 5.0;
1487    // TODO: Mooaar
1488  }
1489  if ((w.bits & (1 << onewayR)) && !(k2v["cycleway"] &&
1490    (strcmp (k2v["cycleway"], "opposite_lane") == 0 ||
1491     strcmp (k2v["cycleway"], "opposite_track") == 0 ||
1492     strcmp (k2v["cycleway"], "opposite") == 0)) &&
1493     !(k2v["oneway:bicyle"] && (strcmp (k2v["oneway:bicycle"], "0") == 0 ||
1494                                strcmp (k2v["oneway:bicycle"], "no") == 0))) {
1495    // On oneway roads, cyclists are only allowed to go in the opposite
1496    // direction, if the cycleway tag exist and starts with "opposite"
1497    w.bits |= 1 << bicycleOneway;
1498  }
1499//  printf ("%.5lf %.5lf\n", LonInverse (w.clon), LatInverse (w.clat));
1500  return result;
1501}
1502
1503#define FWRITEY(y) { perror ("fwrite @ " #y); exit (1); }
1504#define FWRITEX(x) FWRITEY (x) // Use argument prescan feature of CPP
1505#define FWRITE(addr,size,count,f) { if (fwrite (addr, size, count, f) \
1506                                      != (size_t)(count)) FWRITEX (__LINE__) }
1507
1508ndType *LFollow (ndType *nd, ndType *ndItr, wayType *w, int forward)
1509{ // Helper function when a way is copied into lowzoom table.
1510  if (forward) {
1511    nd += nd->other[1];
1512    if (nd->other[1]) return nd;
1513  }
1514  if (nd->lat == nd[1].lat && nd->lon == nd[1].lon) {
1515    if ((nd->lat != nd[2].lat || nd->lon != nd[2].lon) &&
1516        (nd->lat != nd[-1].lat || nd->lon != nd[-1].lon ||
1517         // If there is a 3rd object there,
1518         (nd[-1].other[0] == 0 && nd[-1].other[0] == 0)) &&
1519        // then it must be a node
1520        nd + 1 != ndItr && nd[1].other[!forward ? 1 : 0] == 0
1521        // Must not loop back to start and must not be T juntion
1522        && StyleNr (w) == StyleNr ((wayType*)(data + nd[1].wayPtr))) nd++;
1523  }
1524  else if (nd->lat == nd[-1].lat && nd->lon == nd[-1].lon &&
1525           (nd->lat != nd[-2].lat || nd->lon != nd[-2].lon ||
1526            // If there is a 3rd object there,
1527            (nd[-2].other[0] == 0 && nd[-2].other[0] == 0)) &&
1528            // then it must be a node
1529           nd - 1 != ndItr && nd[-1].other[!forward ? 1 : 0] == 0
1530           // Must not loop back to start and must not be T juntion
1531           && StyleNr (w) == StyleNr ((wayType*)(data + nd[-1].wayPtr))) nd--;
1532  // If nd ends at a point where exactly two ways meet and they have the same
1533  // StyleNr we can 'route' across it.
1534  // But we can't go back to wayPtr, e.g. circular way.
1535  return nd;
1536}
1537
1538int RebuildPak(const char* pakfile, const char* elemstylefile, 
1539               const char* iconscsvfile, const char* masterpakfile, 
1540               const int bbox[4]) {
1541  assert (layerBit3 < 32);
1542
1543  int rebuildCnt = 0;
1544  FILE *pak, *masterf;
1545  int ndStart;
1546  wayType *master = NULL;
1547  if (strcmp(masterpakfile,"")) {
1548    if (!(masterf = fopen64 (masterpakfile, "rb")) ||
1549        fseek (masterf, -sizeof (ndStart), SEEK_END) != 0 ||
1550        fread (&ndStart, sizeof (ndStart), 1, masterf) != 1 ||
1551        (long)(master = (wayType *)mmap (NULL, ndStart, PROT_READ,
1552                                         MAP_SHARED, fileno (masterf), 
1553                                         0)) == -1) {
1554      fprintf (stderr, "Unable to open %s for bbox rebuild\n",masterpakfile);
1555      return 4;
1556    }
1557  }
1558 
1559  if (!(pak = fopen64 (pakfile, "w+b"))) {
1560    fprintf (stderr, "Cannot create %s\n",pakfile);
1561    return 2;
1562  }
1563  FWRITE (&pakHead, sizeof (pakHead), 1, pak);
1564
1565  //------------------------ elemstylesfile : -----------------------------
1566  styleStruct *srec =
1567    (styleStruct*) calloc ((2 << STYLE_BITS), sizeof (*srec));
1568  elemstyleMapping *eMap =
1569    (elemstyleMapping*) calloc ((2 << STYLE_BITS), sizeof (*eMap));
1570 
1571  int elemCnt = LoadElemstyles(elemstylefile, iconscsvfile,
1572                                srec, eMap), styleCnt = elemCnt;
1573 
1574 
1575  //------------------ OSM Data File (/dev/stdin) : ------------------------
1576  xmlTextReaderPtr xml = xmlReaderForFd (STDIN_FILENO, "", NULL, 0);
1577  FILE *groupf[PAIRGROUP2 (0) + PAIRGROUPS2];
1578  char groupName[PAIRGROUP2 (0) + PAIRGROUPS2][9];
1579  for (int i = 0; i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
1580    sprintf (groupName[i], "%c%c%d.tmp", i / 26 % 26 + 'a', i % 26 + 'a',
1581             i / 26 / 26);
1582    if (i < S2GROUP (0) && !(groupf[i] = fopen64 (groupName[i], "w+b"))) {
1583      perror ("Cannot create temporary file.\n"
1584               "Possibly too many open files, in which case you must run "
1585               "ulimit -n or recompile\n");
1586      return 9;
1587     
1588    }
1589  }
1590 
1591#if 0 // For making sure we have a Hilbert curve
1592  bucketsMin1 = MAX_BUCKETS - 1;
1593  for (int x = 0; x < 16; x++) {
1594    for (int y = 0; y < 16; y++) {
1595      printf ("%7d ", Hash (x << TILEBITS, y << TILEBITS));
1596    }
1597    printf ("\n");
1598  }
1599#endif
1600   
1601  nodeType nd;
1602  halfSegType s[2];
1603  int nOther = 0, lowzOther = FIRST_LOWZ_OTHER, isNode = 0;
1604  int yesMask = 0, noMask = 0;
1605  struct {
1606    wayType *w; // Pointer to the first version in the master file.
1607    int off;
1608  } *wayFseek = NULL;
1609  int wStyle = elemCnt, ref = 0;
1610  int relationType = 0, onewayReverse = 0;
1611  vector<int> wayMember;
1612  map<int,int> wayId;
1613  wayType w;
1614  w.clat = 0;
1615  w.clon = 0;
1616  w.dlat = INT_MIN;
1617  w.dlon = INT_MIN;
1618  w.bits = 0;
1619  w.destination = 0;
1620 
1621  // if we are doing a second pass bbox rebuild
1622  if (master) {
1623    masterWayType *masterWay = (masterWayType *) 
1624      malloc (sizeof (*masterWay) * (ndStart / (sizeof (wayType) + 4)));
1625   
1626    unsigned i = 0, offset = ftell (pak), wcnt;
1627    wayType *m = (wayType *)(((char *)master) + offset);
1628    for (wcnt = 0; (char*) m < (char*) master + ndStart; wcnt++) {
1629      if (bbox[0] <= m->clat + m->dlat && bbox[1] <= m->clon + m->dlon &&
1630          m->clat - m->dlat <= bbox[2] && m->clon - m->dlon <= bbox[3]) {
1631        masterWay[i].idx = wcnt;
1632        masterWay[i++].w = m;
1633      }
1634      m = (wayType*)((char*)m +
1635                     ((1 + strlen ((char*)(m + 1) + 1) + 1 + 3) & ~3)) + 1;
1636    }
1637    qsort (masterWay, i, sizeof (*masterWay), MasterWayCmp);
1638    assert (wayFseek = (typeof (wayFseek)) calloc (sizeof (*wayFseek),
1639                                      ndStart / (sizeof (wayType) + 4)));
1640    for (unsigned j = 0; j < i; j++) {
1641      wayFseek[masterWay[j].idx].off = offset;
1642      wayFseek[masterWay[j].idx].w = masterWay[j].w;
1643      offset += sizeof (*masterWay[j].w) +
1644        ((1 + strlen ((char*)(masterWay[j].w + 1) + 1) + 1 + 3) & ~3);
1645    }
1646    wayFseek[wcnt].off = offset;
1647    fflush (pak);
1648    if (ftruncate (fileno (pak), offset) != 0) perror ("ftruncate");
1649    free (masterWay);
1650    fseek (pak, wayFseek->off, SEEK_SET);
1651  }
1652 
1653  char *relationTable;
1654  FILE *relationTableFile = fopen ("relations.tbl", "rb");
1655  if (!relationTableFile || fseek (relationTableFile, 0, SEEK_END) != 0 ||
1656      (relationTable = (char*) mmap (NULL, ftell (relationTableFile), PROT_READ,
1657        MAP_SHARED, fileno (relationTableFile), 0)) == (char*)-1) {
1658    relationTable = (char*) "z1"; // Stopper
1659    fprintf (stderr, "Processing without relations table\n");
1660  }
1661 
1662  char *tag_k = NULL, *role = NULL; //, *tags = (char *) BAD_CAST xmlStrdup (BAD_CAST "");
1663  //char *nameTag = NULL;
1664  k2vType k2v, wayRole; // wayRole should be a vector< struct{char*,int} > ...
1665  deque<int> wayNd;
1666  map<int, deque<int> > outer;
1667  REBUILDWATCH (while (xmlTextReaderRead (xml) == 1)) {
1668    char *name = (char *) BAD_CAST xmlTextReaderName (xml);
1669    //xmlChar *value = xmlTextReaderValue (xml); // always empty
1670    if (xmlTextReaderNodeType (xml) == XML_READER_TYPE_ELEMENT) {
1671      isNode = stricmp (name, "way") != 0 && stricmp (name, "relation") != 0
1672        && (stricmp (name, "node") == 0 || isNode);
1673      while (xmlTextReaderMoveToNextAttribute (xml)) {
1674        char *aname = (char *) BAD_CAST xmlTextReaderName (xml);
1675        char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
1676        //        if (xmlStrcasecmp (name, "node") == 0)
1677        if (stricmp (aname, "id") == 0) nd.id = atoi (avalue);
1678        if (stricmp (aname, "lat") == 0) nd.lat = Latitude (atof (avalue));
1679        if (stricmp (aname, "lon") == 0) nd.lon = Longitude (atof (avalue));
1680        if (stricmp (aname, "ref") == 0) ref = atoi (avalue);
1681        if (stricmp (aname, "type") == 0) relationType = avalue[0];
1682
1683#define K_IS(x) (stricmp (tag_k, x) == 0)
1684#define V_IS(x) (stricmp (avalue, x) == 0)
1685
1686        if (stricmp (aname, "role") == 0) role = avalue;
1687        else if (stricmp (aname, "v") == 0) {
1688         
1689          int newStyle = 0;
1690          // TODO: this for loop could be clearer as a while
1691          for (; newStyle < elemCnt && !(K_IS (eMap[newStyle].style_k) &&
1692                                          (eMap[newStyle].style_v[0] == '\0' || V_IS (eMap[newStyle].style_v)) &&
1693                                          (isNode ? srec[newStyle].x[2] :
1694                                           srec[newStyle].lineColour != -1 ||
1695                                           srec[newStyle].areaColour != -1)); newStyle++) {}
1696          // elemstyles rules are from most important to least important
1697          // Ulf has placed rules at the beginning that will highlight
1698          // errors, like oneway=true -> icon=deprecated. So they must only
1699          // match nodes when no line or area colour was given and only
1700          // match ways when no icon was given.
1701          if (K_IS ("junction") && V_IS ("roundabout")) {
1702            yesMask |= (1 << onewayR) | (1 << roundaboutR);
1703          }
1704          else if (newStyle < elemCnt && 
1705                   (wStyle == elemCnt || 
1706                    eMap[wStyle].ruleNr > eMap[newStyle].ruleNr)) {
1707            wStyle = newStyle;
1708          }
1709         
1710          if (K_IS ("layer")) w.bits |= atoi (avalue) << 29;
1711         
1712#define M(field) else if (K_IS (#field)) {                              \
1713            if (V_IS ("yes") || V_IS ("1") || V_IS ("permissive") ||    \
1714                V_IS ("true") || V_IS ("designated") ||                 \
1715                V_IS ("official") || V_IS ("-1")) {                     \
1716              yesMask |= 1 << field ## R;                               \
1717              if (K_IS ("oneway") && V_IS ("-1")) onewayReverse = TRUE; \
1718            } else if (V_IS ("no") || V_IS ("0") || V_IS ("private")) { \
1719              noMask |= 1 << field ## R;                                \
1720            }                                                           \
1721            else if (V_IS ("destination")) {                            \
1722              yesMask |= 1 << field ## R;                               \
1723              w.destination |= 1 << field ## R;                         \
1724            }                                                           \
1725          }
1726          RESTRICTIONS
1727#undef M
1728           
1729          k2v.m[tag_k] = avalue; // Will be freed after Osm2Gosmore()
1730        }
1731        else if (stricmp (aname, "k") == 0) tag_k = avalue;
1732        else xmlFree (avalue); // Not "k", "v" or "role"
1733       
1734        xmlFree (aname);
1735      } /* While it's an attribute */
1736      if (/*relationType == 'w' && */ stricmp (name, "member") == 0) {
1737        //map<int,int>::iterator refId = wayId.find (ref);
1738        //if (refId != wayId.end ()) wayMember.push_back (refId->second);
1739        wayMember.push_back (ref);
1740      }
1741      if (!wayFseek || wayFseek->off) { // This test / guard is no longer needed.
1742        if (stricmp (name, "member") == 0 && role) {
1743          if (relationType == 'n' && stricmp (role, "via") == 0) wayNd.push_back (ref);
1744         
1745          map<int,int>::iterator refId = wayId.find (ref);
1746          if (relationType == 'w' && refId != wayId.end ()) {
1747            char tmp[12];
1748            sprintf (tmp, "%d", refId->second);
1749            wayRole.m[role] = (char*) xmlStrdup (BAD_CAST tmp);
1750          }
1751          else xmlFree (role);
1752          role = NULL;
1753        }
1754        else if (stricmp (name, "nd") == 0) wayNd.push_back (ref);
1755      }
1756      if (stricmp (name, "node") == 0 && bbox[0] <= nd.lat &&
1757          bbox[1] <= nd.lon && nd.lat <= bbox[2] && nd.lon <= bbox[3]) {
1758        FWRITE (&nd, sizeof (nd), 1, groupf[NGROUP (nd.id)]);
1759      }
1760    }
1761    if (xmlTextReaderNodeType (xml) == XML_READER_TYPE_END_ELEMENT) {
1762      int nameIsNode = stricmp (name, "node") == 0;
1763      int nameIsRelation = stricmp (name, "relation") == 0;
1764      if (nameIsRelation && k2v["type"] &&
1765          strcmp (k2v["type"], "multipolygon") == 0) {
1766        while (!wayMember.empty ()) {
1767          int idx;
1768          for (idx = wayMember.size () - 1; !outer[wayMember[idx]].empty () ; idx--) {
1769            deque<int> *o = &outer[wayMember[idx]];
1770            if (wayNd.empty () || wayNd.back () == o->front () || idx == 0) {
1771              if (!wayNd.empty () && wayNd.back () == o->front ()) wayNd.pop_back ();
1772              wayNd.insert (wayNd.end (), o->begin (), o->end ());
1773              break;
1774            }
1775            if (wayNd.back () == o->back ()) {
1776              wayNd.pop_back ();
1777              wayNd.insert (wayNd.end (), o->rbegin (), o->rend ());
1778              break;
1779            }
1780          }
1781          //printf ("iiiiiiiii %d %d %d %u %s %s\n", idx, nd.id, wayMember[idx],
1782          //  outer[wayMember[idx]].size (), eMap[wStyle].style_k, eMap[wStyle].style_v);
1783          wayMember[idx] = wayMember.back ();
1784          wayMember.pop_back ();
1785        }
1786      }
1787      if (nameIsRelation) wayMember.clear ();
1788      if (stricmp (name, "way") == 0 || nameIsNode || nameIsRelation) {
1789        if (!nameIsRelation && !nameIsNode) {
1790          wayId[nd.id] = ftell (pak);
1791        }
1792        /*if (nameTag) {
1793          char *oldTags = tags;
1794          tags = (char *) xmlStrdup (BAD_CAST "\n");
1795          tags = (char *) xmlStrcat (BAD_CAST tags, BAD_CAST nameTag);
1796          tags = (char *) xmlStrcat (BAD_CAST tags, BAD_CAST oldTags);
1797          xmlFree (oldTags);
1798          xmlFree (nameTag);
1799          nameTag = NULL;
1800        }*/
1801        while (*relationTable < (isNode ? 'n' : nameIsRelation ? 'x' : 'w') ||
1802            (*relationTable == (isNode ? 'n' : nameIsRelation ? 'x' : 'w') &&
1803             atoi (relationTable + 1) < nd.id)) {
1804          do {
1805            relationTable += strlen (relationTable) + 1;
1806            relationTable += strlen (relationTable) + 1;
1807          } while (*relationTable++ != '\0');
1808        }
1809        membershipType membership =
1810          *relationTable == (isNode ? 'n' : nameIsRelation ? 'x' : 'w') &&
1811              atoi (relationTable + 1) == nd.id ? relationTable : NULL;
1812
1813        for (membershipType m = membership; m; m = Next (m)) {
1814          if (strcmp (Role (m), "inner") == 0 && wStyle == elemCnt) {
1815            for (wStyle = 0; wStyle < elemCnt; wStyle++) {
1816              if (strcmp (eMap[wStyle].style_k, "natural") == 0 &&
1817                  strcmp (eMap[wStyle].style_v, "glacier") == 0) break;
1818              // Rendering does not support holes, so we just render something
1819              // close to the background colour
1820            }
1821          }
1822          else if (strcmp (Role (m), "outer") == 0) {
1823            outer[nd.id] = deque<int> ();
1824            outer[nd.id].insert (outer[nd.id].end (), wayNd.begin (), wayNd.end ());
1825          }
1826        }
1827       
1828        #ifdef ONLY_ROUTING
1829        if (wStyle != highway_traffic_signals &&
1830            wStyle != highway_mini_roundabout &&
1831            !(wStyle >= restriction_no_right_turn &&
1832              wStyle <= restriction_only_straight_on) &&
1833            !(wStyle >= barrier_bollard &&
1834              wStyle <= barrier_toll_booth) &&
1835            !eMap[wStyle].defaultRestrict) wStyle = elemCnt;
1836        #endif
1837        if (wStyle == elemCnt /* 1 trick that did help enough to make files < 400MB
1838          || (!k2v["name"] && srec[wStyle].areaColour != -1)*/ ) wayNd.clear ();
1839        else {
1840          s[0].other = -2;
1841          while (!wayNd.empty ()) {
1842            s[0].wayPtr = ftell (pak);
1843            s[1].wayPtr = TO_HALFSEG;
1844            s[1].other = s[0].other + 1;
1845            s[0].lat = onewayReverse ? wayNd.back () : wayNd.front ();
1846            /*if (lowzListCnt >=
1847                int (sizeof (lowzList) / sizeof (lowzList[0]))) lowzListCnt--;
1848            lowzList[lowzListCnt++] = s[0].lat; */
1849            if (onewayReverse) wayNd.pop_back ();
1850            else wayNd.pop_front ();
1851            s[0].other = wayNd.empty () ? -2 : nOther++ * 2;
1852            FWRITE (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
1853          }
1854          if (nameIsNode && (!wayFseek || wayFseek->off)) {
1855            s[0].lat = nd.id; // Create 2 fake halfSegs
1856            s[0].wayPtr = ftell (pak);
1857            s[1].wayPtr = TO_HALFSEG;
1858            s[0].other = -2; // No next
1859            s[1].other = -1; // No prev
1860            //lowzList[lowzListCnt++] = nd.id;
1861            FWRITE (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
1862          }
1863         
1864          w.bits |= ~noMask & ((yesMask & (1 << accessR)) 
1865                               ? yesMask | ((1 << onewayR) - (1 << (accessR + 1)))
1866                               : yesMask | (eMap[wStyle].defaultRestrict &
1867                                          ((noMask & (1 << accessR)) ? (1 << onewayR) : ~0)));
1868          if (w.destination & (1 << accessR)) w.destination = ~0;
1869          memcpy (&srec[styleCnt], &srec[wStyle], sizeof (srec[0]));
1870          if (wayFseek && wayFseek->off) {
1871            w.clat = wayFseek->w->clat;
1872            w.clon = wayFseek->w->clon;
1873            w.dlat = wayFseek->w->dlat;
1874            w.dlon = wayFseek->w->dlon;
1875          }
1876          deque<string> tags = Osm2Gosmore (nd.id, k2v, w, srec[styleCnt], isNode,
1877            nameIsRelation, membership, wayRole);
1878          while (memcmp (&srec[styleCnt], &srec[wStyle], sizeof (srec[0]))
1879                 != 0) wStyle++;
1880          w.bits += wStyle;
1881          if (wStyle == styleCnt) {
1882            if (styleCnt == (2 << STYLE_BITS) - 2) {
1883              fprintf (stderr, "*** Warning: Too many styles !!!\n");
1884            }
1885            if (styleCnt < (2 << STYLE_BITS) - 1) styleCnt++;
1886          }
1887         
1888          /*if (srec[StyleNr (&w)].scaleMax > 10000000 &&
1889              (!wayFseek || wayFseek->off)) {
1890            for (int i = 0; i < lowzListCnt; i++) {
1891              if (i % 10 && i < lowzListCnt - 1) continue; // Skip some
1892              s[0].lat = lowzList[i];
1893              s[0].wayPtr = ftell (pak);
1894              s[1].wayPtr = TO_HALFSEG;
1895              s[1].other = i == 0 ? -4 : lowzOther++;
1896              s[0].other = i == lowzListCnt -1 ? -4 : lowzOther++;
1897              FWRITE (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
1898            }
1899          }
1900          lowzListCnt = 0; */
1901         
1902          /*if (StyleNr (&w) < elemCnt && stricmp (eMap[StyleNr (&w)].style_v,
1903                                                  "city") == 0 && tags[0] == '\n') {
1904            int nlen = strcspn (tags + 1, "\n");
1905            char *n = (char *) xmlMalloc (strlen (tags) + 1 + nlen + 5 + 1);
1906            strcpy (n, tags);
1907            memcpy (n + strlen (tags), tags, 1 + nlen);
1908            strcpy (n + strlen (tags) + 1 + nlen, " City");
1909            //fprintf (stderr, "Mark : %s\n", n + strlen (tags) + 1);
1910            xmlFree (tags);
1911            tags = n;
1912          }
1913          char *compact = tags[0] == '\n' ? tags + 1 : tags; */
1914          if (!wayFseek || wayFseek->off) {
1915            FWRITE (&w, sizeof (w), 1, pak);
1916            FWRITE ("", 1, 1, pak); // '\0' at the front
1917            unsigned newln = 0;
1918            for (; !tags.empty (); tags.pop_front ()) {
1919              if (newln) FWRITE ("\n", 1, 1, pak);
1920              const char *compact = tags.front().c_str ();
1921              if (tags.front ()[0] == '\n') compact++;
1922              else {
1923                #ifndef ONLY_ROUTING
1924                // If all the idxes went into a single file, this can
1925                // be simplified a lot. One day when RAM is cheap.
1926                string line;
1927                deque<string>::iterator tItr = tags.begin ();
1928                do line += *tItr;
1929                while (!strchr ((*tItr++).c_str (), '\n') &&
1930                       tItr != tags.end ());
1931               
1932                unsigned grp, idx = ftell (pak);
1933                for (grp = 0; grp < IDXGROUPS - 1 &&
1934                 TagCmp (groupName[grp], (char*) line.c_str ()) < 0; grp++) {}
1935                FWRITE (&idx, sizeof (idx), 1, groupf[grp]);
1936                #endif
1937              }
1938              unsigned l = strlen (compact);
1939              newln = l > 0 && compact[l - 1] == '\n' ? 1 : 0;
1940              if (l > newln) FWRITE (compact, l - newln, 1, pak);
1941            }
1942            FWRITE ("", 1, 1, pak); // '\0' at the back
1943/*          for (char *ptr = tags; *ptr != '\0'; ) {
1944              if (*ptr++ == '\n') {
1945                unsigned idx = ftell (pak) + ptr - 1 - tags, grp;
1946                for (grp = 0; grp < IDXGROUPS - 1 &&
1947                       TagCmp (groupName[grp], ptr) < 0; grp++) {}
1948                FWRITE (&idx, sizeof (idx), 1, groupf[grp]);
1949              }
1950            }
1951            FWRITE (compact, strlen (compact) + 1, 1, pak); */
1952           
1953            // Write variable length tags and align on 4 bytes
1954            if (ftell (pak) & 3) {
1955              FWRITE ("   ", 4 - (ftell (pak) & 3), 1, pak);
1956            }
1957          }
1958          if (wayFseek) fseek (pak, (++wayFseek)->off, SEEK_SET);
1959          //xmlFree (tags); // Just set tags[0] = '\0'
1960          //tags = (char *) xmlStrdup (BAD_CAST "");
1961        }
1962        //tags[0] = '\0'; // Erase nodes with short names
1963        yesMask = noMask = 0;
1964        w.bits = 0;
1965        w.destination = 0;
1966        wStyle = elemCnt;
1967        onewayReverse = FALSE;
1968        while (!k2v.m.empty ()) {
1969          xmlFree ((char*) k2v.m.begin()->second);
1970          xmlFree ((char*) k2v.m.begin()->first);
1971          k2v.m.erase (k2v.m.begin ());
1972        }
1973        while (!wayRole.m.empty ()) {
1974          xmlFree ((char*) wayRole.m.begin()->second);
1975          xmlFree ((char*) wayRole.m.begin()->first);
1976          wayRole.m.erase (wayRole.m.begin ());
1977        }
1978      }
1979    } // if it was </...>
1980    xmlFree (name);
1981  } // While reading xml
1982  wayId.clear ();
1983  assert (nOther * 2 < FIRST_LOWZ_OTHER);
1984  bucketsMin1 = (nOther >> 5) | (nOther >> 4);
1985  bucketsMin1 |= bucketsMin1 >> 2;
1986  bucketsMin1 |= bucketsMin1 >> 4;
1987  bucketsMin1 |= bucketsMin1 >> 8;
1988  bucketsMin1 |= bucketsMin1 >> 16;
1989  assert (bucketsMin1 < MAX_BUCKETS);
1990 
1991  for (int i = 0; i < IDXGROUPS; i++) fclose (groupf[i]);
1992  for (int i = S2GROUP (0); i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
1993    assert (groupf[i] = fopen64 (groupName[i], "w+b"));
1994  } // Avoid exceeding ulimit
1995 
1996  nodeType *nodes = (nodeType *) malloc (sizeof (*nodes) * MAX_NODES);
1997  if (!nodes) {
1998    fprintf (stderr, "Out of memory. Reduce MAX_NODES and increase GRPs\n");
1999    return 3;
2000  }
2001  for (int i = NGROUP (0); i < NGROUP (0) + NGROUPS; i++) {
2002    rewind (groupf[i]);
2003    memset (nodes, -1, sizeof (*nodes) * MAX_NODES);
2004    REBUILDWATCH (while (fread (&nd, sizeof (nd), 1, groupf[i]) == 1)) {
2005      memcpy (FindNode (nodes, nd.id), &nd, sizeof (nd));
2006    }
2007    fclose (groupf[i]);
2008    unlink (groupName[i]);
2009    rewind (groupf[i + NGROUPS]);
2010    REBUILDWATCH (while (fread (s, sizeof (s), 1, groupf[i + NGROUPS])
2011                         == 1)) {
2012      nodeType *n = FindNode (nodes, s[0].lat);
2013      //if (n->id == -1) printf ("** Undefined node %d\n", s[0].lat);
2014      s[0].lat = s[1].lat = n->id != -1 ? n->lat : INT_MIN;
2015      s[0].lon = s[1].lon = n->id != -1 ? n->lon : INT_MIN;
2016      FWRITE (s, sizeof (s), 1,
2017              groupf[-2 <= s[0].other && s[0].other < FIRST_LOWZ_OTHER
2018                     ? S2GROUP (Hash (s[0].lon, s[0].lat)) : PAIRGROUP (0) - 1]);
2019    }
2020    fclose (groupf[i + NGROUPS]);
2021    unlink (groupName[i + NGROUPS]);
2022  }
2023  free (nodes);
2024 
2025  struct {
2026    int nOther1, final;
2027  } offsetpair;
2028  offsetpair.final = 0;
2029 
2030  hashTable = (int *) malloc (sizeof (*hashTable) *
2031                              (bucketsMin1 + (bucketsMin1 >> 7) + 3));
2032  int bucket = -1;
2033  for (int i = S2GROUP (0); i < S2GROUP (0) + S2GROUPS; i++) {
2034    fflush (groupf[i]);
2035    size_t size = ftell (groupf[i]);
2036    rewind (groupf[i]);
2037    REBUILDWATCH (halfSegType *seg = (halfSegType *) mmap (NULL, size,
2038                                                           PROT_READ | PROT_WRITE, MAP_SHARED, fileno (groupf[i]), 0));
2039    qsort (seg, size / sizeof (s), sizeof (s),
2040           (int (*)(const void *, const void *))HalfSegCmp);
2041    for (int j = 0; j < int (size / sizeof (seg[0])); j++) {
2042      if (!(j & 1)) {
2043        while (bucket < Hash (seg[j].lon, seg[j].lat, FALSE)) {
2044//                            i >= S2GROUP (0) + S2GROUPS - 1)) {
2045          hashTable[++bucket] = offsetpair.final / 2;
2046        }
2047      }
2048      offsetpair.nOther1 = seg[j].other;
2049      if (seg[j].other >= 0) FWRITE (&offsetpair, sizeof (offsetpair), 1,
2050                                     groupf[PAIRGROUP (offsetpair.nOther1)]);
2051      offsetpair.final++;
2052    }
2053    munmap (seg, size);
2054  }
2055  while (bucket < bucketsMin1 + 1) {
2056    hashTable[++bucket] = offsetpair.final / 2;
2057  }
2058 
2059  ndType ndWrite;
2060  ndWrite.wayPtr = s[0].wayPtr; // sizeof (pakHead); // Anything halfvalid
2061  ndWrite.lon = ndWrite.lat = INT_MIN;
2062  ndWrite.other[0] = ndWrite.other[1] = 0;
2063  FWRITE (&ndWrite, sizeof (ndWrite), 1, pak); // Insert 'stopper' record
2064
2065  ndStart = ftell (pak);
2066 
2067  int *pairing = (int *) malloc (sizeof (*pairing) * PAIRS);
2068  for (int i = PAIRGROUP (0); i < PAIRGROUP (0) + PAIRGROUPS; i++) {
2069    REBUILDWATCH (rewind (groupf[i]));
2070    while (fread (&offsetpair, sizeof (offsetpair), 1, groupf[i]) == 1) {
2071      pairing[offsetpair.nOther1 % PAIRS] = offsetpair.final;
2072    }
2073    int pairs = ftell (groupf[i]) / sizeof (offsetpair);
2074    for (int j = 0; j < pairs; j++) {
2075      offsetpair.final = pairing[j ^ 1];
2076      offsetpair.nOther1 = pairing[j];
2077      FWRITE (&offsetpair, sizeof (offsetpair), 1,
2078              groupf[PAIRGROUP2 (offsetpair.nOther1)]);
2079    }
2080    fclose (groupf[i]);
2081    unlink (groupName[i]);
2082  }
2083  free (pairing);
2084 
2085  int s2grp = S2GROUP (0), pairs, totalp = 0;
2086  halfSegType *seg = (halfSegType *) malloc (PAIRS * sizeof (*seg));
2087  assert (seg /* Out of memory. Reduce PAIRS for small scale rebuilds. */);
2088  for (int i = PAIRGROUP2 (0); i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
2089    REBUILDWATCH (for (pairs = 0; pairs < PAIRS &&
2090                         s2grp < S2GROUP (0) + S2GROUPS; )) {
2091      if (fread (&seg[pairs], sizeof (seg[0]), 2, groupf [s2grp]) == 2) {
2092        pairs += 2;
2093      }
2094      else {
2095        fclose (groupf[s2grp]);
2096        unlink (groupName[s2grp]);
2097        s2grp++;
2098      }
2099    }
2100    rewind (groupf[i]);
2101    while (fread (&offsetpair, sizeof (offsetpair), 1, groupf[i]) == 1) {
2102      seg[offsetpair.nOther1 % PAIRS].other = offsetpair.final;
2103    }
2104    for (int j = 0; j < pairs; j += 2) {
2105      ndWrite.wayPtr = seg[j].wayPtr;
2106      ndWrite.lat = seg[j].lat;
2107      ndWrite.lon = seg[j].lon;
2108      ndWrite.other[0] = //seg[j].other >> 1; // Right shift handles -1 the
2109        seg[j].other < 0 ? 0 : (seg[j].other >> 1) - totalp;
2110      ndWrite.other[1] = //seg[j + 1].other >> 1; // way we want.
2111        seg[j + 1].other < 0 ? 0 : (seg[j + 1].other >> 1) - totalp;
2112      totalp++;
2113      FWRITE (&ndWrite, sizeof (ndWrite), 1, pak);
2114    }
2115    fclose (groupf[i]);
2116    unlink (groupName[i]);
2117  }
2118  free (seg);
2119  ndWrite.wayPtr = s[0].wayPtr; // sizeof (pakHead); // Anything halfvalid
2120  ndWrite.lon = ndWrite.lat = INT_MIN;
2121  ndWrite.other[0] = ndWrite.other[1] = 0;
2122  FWRITE (&ndWrite, sizeof (ndWrite), 1, pak); // Insert 'stopper' record
2123  hashTable[bucket]++; // And reserve space for it.
2124 
2125  fflush (pak);
2126  data = (char *) mmap (NULL, ftell (pak),
2127                        PROT_READ | PROT_WRITE, MAP_SHARED, fileno (pak), 0);
2128  fseek (pak, ftell (pak), SEEK_SET);
2129  vector<halfSegType> lseg;
2130  ndBase = (ndType*)(data + ndStart);
2131  REBUILDWATCH (for (ndType *ndItr = ndBase;
2132                ndItr < ndBase + hashTable[bucketsMin1 + 1]; ndItr++)) {
2133  //while (fread (&ndWrite, sizeof (ndWrite), 1, pak) == 1)) {
2134    wayType *way = (wayType*) (data + ndItr->wayPtr);
2135    /* The difficult way of calculating bounding boxes,
2136       namely to adjust the centerpoint (it does save us a pass) : */
2137    // Block lost nodes with if (ndItr->lat == INT_MIN) continue;
2138    if (way->clat + way->dlat < ndItr->lat) {
2139      way->dlat = way->dlat < 0 ? 0 : // Bootstrap
2140        (way->dlat - way->clat + ndItr->lat) / 2;
2141      way->clat = ndItr->lat - way->dlat;
2142    }
2143    if (way->clat - way->dlat > ndItr->lat) {
2144      way->dlat = (way->dlat + way->clat - ndItr->lat) / 2;
2145      way->clat = ndItr->lat + way->dlat;
2146    }
2147    if (way->clon + way->dlon < ndItr->lon) {
2148      way->dlon = way->dlon < 0 ? 0 : // Bootstrap
2149        (way->dlon - way->clon + ndItr->lon) / 2;
2150      way->clon = ndItr->lon - way->dlon;
2151    }
2152    if (way->clon - way->dlon > ndItr->lon) {
2153      way->dlon = (way->dlon + way->clon - ndItr->lon) / 2;
2154      way->clon = ndItr->lon + way->dlon;
2155    }
2156
2157    #ifndef ONLY_ROUTING
2158    // This is a simplified version of the rebuild: It does not use groups or files
2159    // and the lats & lons have been dereferenced previously. So the pairing is
2160    // simplified a lot.
2161    ndType *prev = LFollow (ndItr, ndItr, way, 0);
2162    if (!ndItr->other[0] && prev->wayPtr >= ndItr->wayPtr) {
2163      int length = 0;
2164      ndType *end;
2165      for (end = ndItr; end->other[1]; end = LFollow (end, ndItr, way, 1)) {
2166        length += lrint (sqrt (Sqr ((double)(end->lat - end[end->other[1]].lat)) +
2167                               Sqr ((double)(end->lon - end[end->other[1]].lon))));
2168        if (prev != ndItr && end->wayPtr < ndItr->wayPtr) break;
2169        // If it is circular and we didn't start at the way with the lowest
2170        // wayPtr, then we abort
2171      }
2172      if ((prev == ndItr || prev == end) && (length > 500000 ||
2173                  (end == ndItr && srec[StyleNr (way)].scaleMax > 100000))) {
2174        //printf (prev == ndItr ? "%3d Non circular %s\n" : "%3d Circular %s\n",
2175        //  ndItr - ndBase, (char*)(way+1)+1);
2176        //if (prev == ndItr) printf ("Circular\n");
2177        //printf ("%d\n", srec[StyleNr (way)].scaleMax);
2178        deque<ndType*> dp (1, end); // Stack for Ramer-Douglas-Peucker algorithm
2179        for (ndType *nd = ndItr; ; ) {
2180          ndType *worst = NULL, *dpItr; // Look for worst between nd and dp.back()
2181          if (nd != end) {
2182            double len = sqrt (Sqr ((double)(dp.back()->lon - nd->lon)) +
2183                               Sqr ((double)(nd->lat - dp.back ()->lat)));
2184            double latc = (dp.back ()->lon - nd->lon) / len, maxeps = 10000;
2185            double lonc = (nd->lat - dp.back ()->lat) / len, eps;
2186            for (dpItr = nd; dpItr != dp.back (); dpItr = LFollow (dpItr, ndItr, way, 1)) {
2187              eps = len == 0 ? sqrt (Sqr ((double)(dpItr->lat - nd->lat) -
2188                                          (double)(dpItr->lon - nd->lon))) :
2189                fabs ((dpItr->lat - nd->lat) * latc + (dpItr->lon - nd->lon) * lonc);
2190              if (eps > maxeps) {
2191                maxeps = eps;
2192                worst = dpItr;
2193              }
2194            }
2195          }
2196          if (worst) dp.push_back (worst);
2197          else { // The segment is reasonable
2198            lseg.push_back (halfSegType ());
2199            lseg.back ().lon = nd->lon;
2200            lseg.back ().lat = nd->lat;
2201            lseg.back ().wayPtr = ndItr->wayPtr;
2202            lseg.push_back (halfSegType ());
2203            lseg.back ().lon = nd->lon; // Unnecessary !
2204            lseg.back ().lat = nd->lat; // Unnecessary !
2205            lseg.back ().wayPtr = TO_HALFSEG; // Unnecessary !
2206            lseg.back ().other = nd == ndItr ? -4 : lowzOther++;
2207            (&lseg.back ())[-1].other = nd == end ? -4 : lowzOther++;
2208            // Be careful of the conditional post increment when rewriting this code !
2209            if (nd == end) break;
2210            nd = dp.back ();
2211            dp.pop_back ();
2212          }
2213        } // While DP has not passed the end
2214        //printf ("%d %d\n", lowzOther, lseg.size ());
2215      } // If the way belongs in the lowzoom
2216    } // If it was the start of a way
2217    #endif
2218  } // For each highzoom nd
2219  REBUILDWATCH (qsort (&lseg[0], lseg.size () / 2, sizeof (lseg[0]) * 2, 
2220    (int (*)(const void *, const void *))HalfSegCmp));
2221  int *lpair = new int[lowzOther - FIRST_LOWZ_OTHER];
2222  for (unsigned i = 0; i < lseg.size (); i++) {
2223    if (!(i & 1)) {
2224      while (bucket < Hash (lseg[i].lon, lseg[i].lat, TRUE)) {
2225        hashTable[++bucket] = i / 2 + hashTable[bucketsMin1 + 1];
2226      }
2227    }
2228    if (lseg[i].other >= 0) lpair[lseg[i].other - FIRST_LOWZ_OTHER] = i;
2229  }
2230  while (bucket < bucketsMin1 + (bucketsMin1 >> 7) + 2) {
2231    hashTable[++bucket] = lseg.size () / 2 + hashTable[bucketsMin1 + 1];
2232  }
2233  for (int i = 0; i < lowzOther - FIRST_LOWZ_OTHER; i += 2) {
2234    lseg[lpair[i]].other = lpair[i + 1];
2235    lseg[lpair[i + 1]].other = lpair[i];
2236  }
2237  delete lpair;
2238  for (unsigned i = 0; i < lseg.size (); i += 2) {
2239    ndWrite.lat = lseg[i].lat;
2240    ndWrite.lon = lseg[i].lon;
2241    ndWrite.wayPtr = lseg[i].wayPtr;
2242    ndWrite.other[0] = lseg[i].other < 0 ? 0 : (lseg[i].other >> 1) - i / 2;
2243    ndWrite.other[1] = lseg[i + 1].other < 0 ? 0 : (lseg[i + 1].other >> 1) - i / 2;
2244    FWRITE (&ndWrite, sizeof (ndWrite), 1, pak);
2245    //printf ("%3d %10d %10d %10d %3d %3d\n", i / 2, ndWrite.lat, ndWrite.lon, ndWrite.wayPtr,
2246    //  ndWrite.other[0], ndWrite.other[1]);
2247  }
2248 
2249  REBUILDWATCH (for (int i = 0; i < IDXGROUPS; i++)) {
2250    assert (groupf[i] = fopen64 (groupName[i], "r+b"));
2251    fseek (groupf[i], 0, SEEK_END);
2252    int fsize = ftell (groupf[i]);
2253    if (fsize > 0) {
2254      fflush (groupf[i]);
2255      unsigned *idx = (unsigned *) mmap (NULL, fsize,
2256                                         PROT_READ | PROT_WRITE, MAP_SHARED, fileno (groupf[i]), 0);
2257      qsort (idx, fsize / sizeof (*idx), sizeof (*idx), IdxCmp);
2258      FWRITE (idx, fsize, 1, pak);
2259#if 0
2260      for (int j = 0; j < fsize / (int) sizeof (*idx); j++) {
2261        printf ("%.*s\n", strcspn (data + idx[j], "\n"), data + idx[j]);
2262      }
2263#endif
2264      munmap (idx, fsize);
2265    }
2266    fclose (groupf[i]);
2267    unlink (groupName[i]);
2268  }
2269  //    printf ("ndCount=%d\n", ndCount);
2270  munmap (data, ndStart);
2271  FWRITE (hashTable, sizeof (*hashTable),
2272          bucketsMin1 + (bucketsMin1 >> 7) + 3, pak);
2273         
2274  CalculateInvSpeeds (srec, styleCnt);
2275  FWRITE (srec, sizeof (srec[0]), styleCnt, pak);
2276  FWRITE (&styleCnt, sizeof(styleCnt), 1, pak); // File ends with these
2277  FWRITE (&bucketsMin1, sizeof (bucketsMin1), 1, pak); // 3 variables
2278  FWRITE (&ndStart, sizeof (ndStart), 1, pak); /* for ndBase */
2279
2280  fclose (pak);
2281  free (hashTable);
2282
2283  return 0;
2284}
2285
2286/*==================================== SortRelations ======================================*/
2287int XmlTee (void * /*context*/, char *buf, int len)
2288{
2289  int n = fread (buf, 1, len, stdin);
2290  fwrite (buf, 1, n, stdout);
2291  return n; // == 0 ? -1 : n;
2292}
2293
2294int XmlClose (void */*context*/) { return 0; }
2295
2296struct memberType {
2297  int ref, type;
2298  const char *role, *tags;
2299};
2300
2301int MemberCmp (const memberType *a, const memberType *b)
2302{
2303  return a->type == b->type ? a->ref - b->ref : a->type - b->type;
2304}
2305
2306int SortRelations (void)
2307{
2308  xmlTextReaderPtr xml = xmlReaderForIO (XmlTee, XmlClose, NULL, "", NULL, 0);
2309    //xmlReaderForFd (STDIN_FILENO, "", NULL, 0);
2310  vector<memberType> member;
2311  unsigned rStart = 0, rel = FALSE;
2312  string *s = new string ();
2313  #ifdef MKDENSITY_CSV
2314  int lat, lon, *cnt = (int *) calloc (1024 * 1024, sizeof (*cnt));
2315  #endif
2316  while (xmlTextReaderRead (xml) == 1) {
2317    if (xmlTextReaderNodeType (xml) == XML_READER_TYPE_ELEMENT) {
2318      char *name = (char *) BAD_CAST xmlTextReaderName (xml);
2319     
2320      #ifdef MKDENSITY_CSV
2321      if (stricmp (name, "node") == 0) {
2322        while (xmlTextReaderMoveToNextAttribute (xml)) {
2323          char *aname = (char *) BAD_CAST xmlTextReaderName (xml); 
2324          char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
2325          if (stricmp (aname, "lat") == 0) lat = Latitude (atof (avalue));
2326          if (stricmp (aname, "lon") == 0) lon = Longitude (atof (avalue));
2327          xmlFree (aname);
2328          xmlFree (avalue);
2329        }
2330        cnt[(lat / (1 << 22) + 512) * 1024 + (lon / (1 << 22) + 512)]++;
2331      }
2332      xmlFree (name);
2333      continue;
2334      #endif
2335     
2336      rel = rel || stricmp (name, "relation") == 0;
2337      if (stricmp (name, "relation") == 0 && rStart < member.size ()) {
2338        while (rStart < member.size ()) member[rStart++].tags = s->c_str ();
2339        s = new string (); // It leaks memory, but it cannot be freed until
2340                           // moments before exit.
2341        while (xmlTextReaderMoveToNextAttribute (xml)) {
2342          char *aname = (char *) BAD_CAST xmlTextReaderName (xml); 
2343          if (stricmp (aname, "id") == 0) {
2344            char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
2345            *s += "relation_id\nr";
2346            *s += avalue;
2347            *s += '\n';
2348            xmlFree (avalue);
2349          }
2350          xmlFree (aname);
2351        }
2352      }
2353     
2354      if (rel && (stricmp (name, "member") == 0 || stricmp (name, "tag") == 0)) {
2355        if (name[0] == 'm') member.push_back (memberType ());
2356        while (xmlTextReaderMoveToNextAttribute (xml)) {
2357          char *aname = (char *) BAD_CAST xmlTextReaderName (xml); 
2358          char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
2359          if (stricmp (aname, "type") == 0) {
2360            member.back ().type = avalue[0] == 'r' ? 'x' : avalue[0];
2361          }
2362          else if (stricmp (aname, "ref") == 0) member.back ().ref = atoi (avalue);
2363          else if (name[0] == 't' && stricmp (aname, "k") == 0) {
2364            *s += avalue;
2365            *s += '\n';
2366          } // I assume that "<tag" implies "k=..." followed by "v=..."
2367          else if (name[0] == 't' && stricmp (aname, "v") == 0) {
2368            *s += avalue;
2369            *s += '\n';
2370          }
2371         
2372          if (stricmp (aname, "role") == 0) member.back ().role = avalue;
2373          else xmlFree (avalue);
2374         
2375          xmlFree (aname);
2376        }
2377      }
2378      xmlFree (name);
2379    }
2380  }
2381  #ifdef MKDENSITY_CSV
2382  FILE *df = fopen ("density.csv", "wb");
2383  for (lat = 1023; lat >= 0; lat--) {
2384    for (lon = 0; lon < 1024; lon++) {
2385      fprintf (df, "%d%c", cnt[lat * 1024 + lon], lon == 1023 ? '\n' : ' ');
2386    }
2387  }
2388  return 0;
2389  #endif
2390  while (rStart < member.size ()) member[rStart++].tags = s->c_str ();
2391  qsort (&member[0], member.size (), sizeof (member[0]),
2392         (int (*)(const void *, const void *)) MemberCmp);
2393  FILE *idx = fopen ("relations.tbl", "wb");
2394  for (unsigned i = 0; i < member.size (); i++) {
2395    fprintf (idx, "%c%d%c%s%c", member[i].type, member[i].ref, '\0', member[i].role, '\0');
2396    for (const char *ptr = member[i].tags; *ptr; ptr += strcspn (ptr, "\n") + 1) {
2397      fprintf (idx, "%.*s%c", (int) strcspn (ptr, "\n"), ptr, '\0');
2398    }
2399    fprintf (idx, "%c", '\0');
2400  }
2401  fprintf (idx, "z1%c", '\0'); // Insert stopper
2402  return 0;
2403}
2404
2405#endif
Note: See TracBrowser for help on using the repository browser.