source: subversion/applications/rendering/gosmore/gosmore.cpp @ 8745

Last change on this file since 8745 was 8745, checked in by nic, 11 years ago

Prepare for Debian packaging
Abort on pak file version mismatch
Rendering of icons less cluttered

  • Property svn:executable set to *
File size: 114.1 KB
Line 
1/* This software is placed by in the public domain by its authors. */
2/* Written by Nic Roets with contribution(s) from Dave Hansen. */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <math.h>
8#include <ctype.h>
9#include <assert.h>
10#ifndef _WIN32
11#include <sys/mman.h>
12#include <libxml/xmlreader.h>
13#include <arpa/inet.h>
14#include <sys/types.h>
15#include <sys/socket.h>
16#define TEXT(x) x
17#else
18#include <windows.h>
19#define M_PI 3.14159265358979323846 // Not in math ??
20#endif
21#ifdef _WIN32_WCE
22#include <windowsx.h>
23#include <winuserm.h>
24#include <sipapi.h>
25#include "resource.h"
26typedef int intptr_t;
27#define DOC_PREFIX "\\My Documents\\"
28
29// Unfortunately eMbedded Visual C++ TEXT() function does not use UTF8
30// So we have to repeat the OPTIONS table
31#define OPTIONS \
32  o (FollowGPSr,      "?", "?", "?", "?", "?", 0, 2) \
33  o (Search,          "?", "?", "?", "?", "?", 0, 1) \
34  o (StartRoute,      "?", "?", "?", "?", "?", 0, 1) \
35  o (EndRoute,        "?", "?", "?", "?", "?", 0, 1) \
36  o (FastestRoute,    "?", "?", "?", "?", "?", 0, 2) \
37  o (Vehicle,         "?", "?", "?", "?", "?", motorcarR, onewayR) \
38  o (English,         "Deutsch", "Español", "Français", "Italiano", \
39                      "Nederlands", 0, 6) \
40  o (ButtonSize,      "?", "?", "?", "?", "?", 1, 5) \
41  o (IconSet,         "?", "?", "?", "?", "?", 0, 4) \
42  o (DetailLevel,     "?", "?", "?", "?", "?", 0, 5) \
43  o (CommPort,        "?", "?", "?", "?", "?", 0, 13) \
44  o (BaudRate,        "?", "?", "?", "?", "?", 0, 6) \
45  o (Exit,            "?", "?", "?", "?", "?", 0, 2) \
46  o (ZoomInKey,       "?", "?", "?", "?", "?", 0, 1) \
47  o (ZoomOutKey,      "?", "?", "?", "?", "?", 0, 1) \
48  o (HideZoomButtons, "?", "?", "?", "?", "?", 0, 2) \
49  o (ShowCoordinates, "?", "?", "?", "?", "?", 0, 2) \
50  o (AnsiCodePage,    "?", "?", "?", "?", "?", 0, 2) \
51  o (ModelessDialog,  "?", "?", "?", "?", "?", 0, 2)
52#else
53#include <unistd.h>
54#include <sys/stat.h>
55#include <string>
56using namespace std;
57#define wchar_t char
58#define wsprintf sprintf
59#define DOC_PREFIX ""
60#define OPTIONS \
61  o (FollowGPSr,      "?", "?", "?", "?", "?", 0, 2) \
62  o (Search,          "?", "?", "?", "?", "?", 0, 1) \
63  o (StartRoute,      "?", "?", "?", "?", "?", 0, 1) \
64  o (EndRoute,        "?", "?", "?", "?", "?", 0, 1) \
65  o (FastestRoute,    "?", "?", "?", "?", "?", 0, 2) \
66  o (Vehicle,         "?", "?", "?", "?", "?", motorcarR, onewayR) \
67  o (English,         "Deutsch", "Español", "Français", "Italiano", \
68                      "Nederlands", 0, 6) \
69  o (ButtonSize,      "?", "?", "?", "?", "?", 1, 5) \
70  o (IconSet,         "?", "?", "?", "?", "?", 0, 4) \
71  o (DetailLevel,     "?", "?", "?", "?", "?", 0, 5) \
72
73#define HideZoomButtons 0
74#endif
75#ifndef TRUE
76#define TRUE 1
77#define FALSE 0
78#endif
79
80#if !defined (HEADLESS) && !defined (_WIN32_WCE)
81#include <gtk/gtk.h>
82#include "icons.xpm"
83#endif
84
85#ifndef _WIN32
86#define stricmp strcasecmp
87typedef long long __int64;
88#else
89#define strncasecmp _strnicmp
90#define stricmp _stricmp
91#define lrint(x) int ((x) < 0 ? (x) - 0.5 : (x) + 0.5)
92// We emulate just enough of gtk to make it work
93#endif
94#ifdef _WIN32_WCE
95#define gtk_widget_queue_clear(x) // After Click() returns we Invalidate
96HWND hwndList;
97wchar_t appendTmp[50];
98char searchStr[50];
99#define gtk_clist_append(x,str) { \
100   MultiByteToWideChar (AnsiCodePage ? CP_ACP : CP_UTF8, 0, *str, \
101     strlen (*str) + 1, appendTmp, sizeof (appendTmp)); \
102   SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) appendTmp); \
103  }
104#define gtk_entry_get_text(x) searchStr
105#define gtk_clist_freeze(x)
106#define gtk_clist_clear(x)
107#define gtk_clist_thaw(x)
108#define gtk_toggle_button_set_active(x,y) // followGPRr
109struct GtkWidget { 
110  struct {
111    int width, height;
112  } allocation;
113  int window;
114};
115typedef int GtkComboBox;
116struct GdkEventButton {
117  int x, y, button;
118};
119
120HINSTANCE hInst;
121HWND   mWnd, dlgWnd = NULL;
122
123BOOL CALLBACK DlgSearchProc (
124        HWND hwnd, 
125        UINT Msg, 
126        WPARAM wParam, 
127        LPARAM lParam);
128#else
129const char *FindResource (char *fname)
130{
131  static string s;
132  struct stat dummy;
133  if (stat (fname, &dummy) == 0) return fname;
134  s = (string) getenv ("HOME") + "/.gosmore/" + fname;
135  if (stat (s.c_str (), &dummy) != 0) s = (string) RES_DIR + fname;
136  return s.c_str ();
137}
138#endif
139
140#define TILEBITS (18)
141#define TILESIZE (1<<TILEBITS)
142#ifndef INT_MIN
143#define INT_MIN -2147483648
144#endif
145
146#define RESTRICTIONS M (access) M (motorcar) M (bicycle) M (foot) M (goods) \
147  M (hgv) M (horse) M (motorcycle) M (psv) M (motorboat) M (boat) \
148  M (oneway) M (modifier)
149
150#define M(field) field ## R,
151enum { STYLE_BITS = 8, RESTRICTIONS l1,l2,l3 };
152#undef M
153
154struct styleStruct {
155  int  x[16], lineWidth, lineRWidth, lineColour, lineColourBg, dashed;
156  int  scaleMax, areaColour, dummy /* pad to 8 for 64 bit compatibility */;
157  double aveSpeed[l1], invSpeed[l1];
158};
159
160struct ndType {
161  int wayPtr, lat, lon, other[2];
162};
163
164struct wayType {
165  int bits;
166  int clat, clon, dlat, dlon; /* Centre coordinates and (half)diameter */
167};
168
169inline int Layer (wayType *w) { return w->bits >> 29; }
170
171inline int Latitude (double lat)
172{ /* Mercator projection onto a square means we have to clip
173     everything beyond N85.05 and S85.05 */
174  return lat > 85.051128779 ? 2147483647 : lat < -85.051128779 ? -2147483647 :
175    lrint (log (tan (M_PI / 4 + lat * M_PI / 360)) / M_PI * 2147483648.0);
176}
177
178inline int Longitude (double lon)
179{
180  return lrint (lon / 180 * 2147483648.0);
181}
182
183inline double LatInverse (int lat)
184{
185  return (atan (exp (lat / 2147483648.0 * M_PI)) - M_PI / 4) / M_PI * 360;
186}
187
188inline double LonInverse (int lon)
189{
190  return lon / 2147483648.0 * 180;
191}
192
193/*---------- Global variables -----------*/
194int *hashTable, bucketsMin1, pakHead = 0xEB3A942;
195char *data;
196ndType *ndBase;
197styleStruct *style;
198
199inline int StyleNr (wayType *w) { return w->bits & ((2 << STYLE_BITS) - 1); }
200
201inline styleStruct *Style (wayType *w) { return &style[StyleNr (w)]; }
202
203unsigned inline ZEnc (int lon, int lat)
204{ // Input as bits : lon15,lon14,...lon0 and lat15,lat14,...,lat0
205  int t = (lon << 16) | lat;
206  t = (t & 0xff0000ff) | ((t & 0x00ff0000) >> 8) | ((t & 0x0000ff00) << 8);
207  t = (t & 0xf00ff00f) | ((t & 0x0f000f00) >> 4) | ((t & 0x00f000f0) << 4);
208  t = (t & 0xc3c3c3c3) | ((t & 0x30303030) >> 2) | ((t & 0x0c0c0c0c) << 2);
209  return (t & 0x99999999) | ((t & 0x44444444) >> 1) | ((t & 0x22222222) << 1);
210} // Output as bits : lon15,lat15,lon14,lat14,...,lon0,lat0
211
212inline int Hash (int lon, int lat, int lowz = 0)
213{ /* All the normal tiles (that make up a super tile) are mapped to sequential
214     buckets thereby improving caching and reducing the number of disk tracks
215     required to render / route through a super tile sized area.
216     The map to sequential buckets is a 2-D Hilbert curve. */
217  if (lowz) {
218    lon >>= 7;
219    lat >>= 7;
220  }
221 
222  int t = ZEnc (lon >> TILEBITS, ((unsigned) lat) >> TILEBITS);
223  int s = ((((unsigned)t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1)) ^ ~t;
224  // s=ZEnc(lon,lat)^ZEnc(lat,lon), so it can be used to swap lat and lon.
225  #define SUPERTILEBITS (TILEBITS + 8)
226  for (int lead = 1 << (SUPERTILEBITS * 2 - TILEBITS * 2); lead; lead >>= 2) {
227    if (!(t & lead)) t ^= ((t & (lead << 1)) ? s : ~s) & (lead - 1);
228  }
229
230  return (((((t & 0xaaaaaaaa) >> 1) ^ t) + (lon >> SUPERTILEBITS) * 0x00d20381
231    + (lat >> SUPERTILEBITS) * 0x75d087d9) &
232    (lowz ? bucketsMin1 >> 7 : bucketsMin1)) + (lowz ? bucketsMin1 + 1 : 0);
233}
234
235int TagCmp (char *a, char *b)
236{ // This works like the ordering of books in a library : We ignore
237  // meaningless words like "the", "street" and "north". We (should) also map
238  // deprecated words to their new words, like petrol to fuel
239  // TODO : We should consider an algorithm like double metasound.
240  static char *omit[] = { /* "the", in the middle ?? */ "ave", "avenue", 
241    "blvd", "boulevard", "byp", "bypass",
242    "cir", "circle", "close", "cres", "crescent", "ct", "court", "ctr",
243      "center",
244    "dr", "drive", "hwy", "highway", "ln", "lane", "loop",
245    "pass", "pky", "parkway", "pl", "place", "plz", "plaza",
246    /* "run" */ "rd", "road", "sq", "square", "st", "street",
247    "ter", "terrace", "tpke", "turnpike", /*trce, trace, trl, trail */
248    "walk",  "way"
249  };
250  static char *words[] = { "", "first", "second", "third", "fourth", "fifth",
251    "sixth", "seventh", "eighth", "nineth", "tenth", "eleventh", "twelth",
252    "thirteenth", "fourteenth", "fifthteenth", "sixteenth", "seventeenth",
253    "eighteenth", "nineteenth", "twentieth" };
254  static char *teens[] = { "", "", "twenty ", "thirty ", "fourty ",
255    "fifty ", "sixty ", "seventy ", "eighty ", "ninety " };
256 
257  if (stricmp (a, "the ") == 0) a += 4;
258  if (stricmp (b, "the ") == 0) b += 4;
259  if (strchr ("WEST", a[0]) && a[1] == ' ') a += 2; // e.g. N 21st St
260  if (strchr ("WEST", b[0]) && b[1] == ' ') b += 2;
261
262  for (;;) {
263    char n[2][30] = { "", "" }, *ptr[2];
264    int wl[2];
265    for (int i = 0; i < 2; i++) {
266      char **p = i ? &b : &a;
267      if ((*p)[0] == ' ') {
268        for (int i = 0; i < int (sizeof (omit) / sizeof (omit[0])); i++) {
269          if (strncasecmp (*p + 1, omit[i], strlen (omit[i])) == 0 &&
270              !isalpha ((*p)[1 + strlen (omit[i])])) {
271            (*p) += 1 + strlen (omit[i]);
272            break;
273          }
274        }
275      }
276      if (isdigit (**p) && (!isdigit((*p)[1]) || !isdigit ((*p)[2]))
277              /* && isalpha (*p + strcspn (*p, "0123456789"))*/) {
278        // while (atoi (*p) > 99) (*p)++; // Buggy
279        if (atoi (*p) > 20) strcpy (n[i], teens[atoi ((*p)++) / 10]);
280        strcat (n[i], words[atoi (*p)]);
281        while (isdigit (**p) /*|| isalpha (**p)*/) (*p)++;
282        ptr[i] = n[i];
283        wl[i] = strlen (n[i]);
284      }
285      else {
286        ptr[i] = *p;
287        wl[i] = **p == ' ' ? 1 : strcspn (*p , " \n");
288      }
289    }
290    int result = strncasecmp (ptr[0], ptr[1], wl[0] < wl[1] ? wl[1] : wl[0]);
291    if (result || *ptr[0] == '\0' || *ptr[0] == '\n') return result;
292    if (n[0][0] == '\0') a += wl[1]; // In case b was 21st
293    if (n[1][0] == '\0') b += wl[0]; // In case a was 32nd
294  }
295}
296
297struct OsmItr { // Iterate over all the objects in a square
298  ndType *nd[1]; /* Readonly. Either can be 'from' or 'to', but you */
299  /* can be guaranteed that nodes will be in hs[0] */
300 
301  int slat, slon, left, right, top, bottom, tsize; /* Private */
302  ndType *end;
303 
304  OsmItr (int l, int t, int r, int b)
305  {
306    tsize = r - l > 10000000 ? TILESIZE << 7 : TILESIZE;
307    left = l & (~(tsize - 1));
308    right = (r + tsize - 1) & (~(tsize-1));
309    top = t & (~(tsize - 1));
310    bottom = (b + tsize - 1) & (~(tsize-1));
311   
312    slat = top;
313    slon = left - tsize;
314    nd[0] = end = NULL;
315  }
316};
317
318int Next (OsmItr &itr) /* Friend of osmItr */
319{
320  do {
321    itr.nd[0]++;
322    while (itr.nd[0] >= itr.end) {
323      if ((itr.slon += itr.tsize) == itr.right) {
324        itr.slon = itr.left;  /* Here we wrap around from N85 to S85 ! */
325        if ((itr.slat += itr.tsize) == itr.bottom) return FALSE;
326      }
327      int bucket = Hash (itr.slon, itr.slat, itr.tsize != TILESIZE);
328      itr.nd[0] = ndBase + hashTable[bucket];
329      itr.end = ndBase + hashTable[bucket + 1];
330    }
331  } while (((itr.nd[0]->lon ^ itr.slon) & (~(itr.tsize - 1))) ||
332           ((itr.nd[0]->lat ^ itr.slat) & (~(itr.tsize - 1))));
333/*      ((itr.hs[1] = (halfSegType *) (data + itr.hs[0]->other)) > itr.hs[0] &&
334       itr.left <= itr.hs[1]->lon && itr.hs[1]->lon < itr.right &&
335       itr.top <= itr.hs[1]->lat && itr.hs[1]->lat < itr.bottom)); */
336/* while nd[0] is a hash collision, */ 
337  return TRUE;
338}
339
340enum { langEn, langDe, langEs, langFr, langIt, langNl, numberOfLang };
341
342#define notImplemented \
343  o (OrientNorthward, "?", "?", "?", "?", "?") \
344  o (ShowCompass,     "?", "?", "?", "?", "?") \
345  o (ShowPrecision,   "?", "?", "?", "?", "?") \
346  o (ShowSpeed,       "?", "?", "?", "?", "?") \
347  o (ShowHeading,     "?", "?", "?", "?", "?") \
348  o (ShowElevation,   "?", "?", "?", "?", "?") \
349  o (ShowDate,        "?", "?", "?", "?", "?") \
350  o (ShowTime,        "?", "?", "?", "?", "?") \
351  o (ShowSearchButton,"?", "?", "?", "?", "?") \
352  o (ShowCreatePoint, "?", "?", "?", "?", "?") \
353  o (ConfigureKey,    "?", "?", "?", "?", "?") \
354  o (HideConfButton,  "?", "?", "?", "?", "?") \
355  o (SmallIcons,      "?", "?", "?", "?", "?") \
356  o (SquareIcons,     "?", "?", "?", "?", "?") \
357  o (PedestrianRoute, "?", "?", "?", "?", "?")
358
359#define o(en,de,es,fr,it,nl,min,max) en ## Num,
360enum { OPTIONS numberOfOptions };
361#undef o
362
363#define o(en,de,es,fr,it,nl,min,max) { \
364  TEXT (#en), TEXT (de), TEXT (es), TEXT (fr), TEXT (it), TEXT (nl) },
365wchar_t *optionNameTable[][numberOfLang] = { OPTIONS };
366#undef o
367
368#define o(en,de,es,fr,it,nl,min,max) int en = min;
369OPTIONS
370#undef o
371
372#define Sqr(x) ((x)*(x))
373/* Routing starts at the 'to' point and moves to the 'from' point. This will
374   help when we do in car navigation because the 'from' point will change
375   often while the 'to' point stays fixed, so we can keep the array of nodes.
376   It also makes the generation of the directions easier.
377
378   We use "double hashing" to keep track of the shortest distance to each
379   node. So we guess an upper limit for the number of nodes that will be
380   considered and then multiply by a few so that there won't be too many
381   clashes. For short distances we allow for dense urban road networks,
382   but beyond a certain point there is bound to be farmland or seas.
383
384   We call nodes that rescently had their "best" increased "active". The
385   active nodes are stored in a heap so that we can quickly find the most
386   promissing one.
387   
388   OSM nodes are not our "graph-theor"etic nodes. Our "graph-theor"etic nodes
389   are "states", namely the ability to reach nd directly from nd->other[dir]
390*/
391struct routeNodeType {
392  ndType *nd;
393  routeNodeType *shortest;
394  int best, heapIdx, dir, remain; // Dir is 0 or 1
395} *route = NULL, *shortest = NULL, **routeHeap;
396int dhashSize, routeHeapSize, tlat, tlon, flat, flon;
397
398#ifdef ROUTE_CALIBRATE
399int routeAddCnt;
400#define ROUTE_SET_ADDND_COUNT(x) routeAddCnt = (x)
401#define ROUTE_SHOW_STATS printf ("%d / %d\n", routeAddCnt, dhashSize); \
402  fprintf (stderr, "flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&fast=%d&v=motorcar\n", \
403    LatInverse (flat), LonInverse (flon), LatInverse (tlat), \
404    LonInverse (tlon), FastestRoute)
405// This ratio must be around 0.5. Close to 0 or 1 is bad
406#else
407#define ROUTE_SET_ADDND_COUNT(x)
408#define ROUTE_SHOW_STATS
409#endif
410
411void AddNd (ndType *nd, int dir, int cost, routeNodeType *newshort)
412{ /* This function is called when we find a valid route that consists of the
413     segments (hs, hs->other), (newshort->hs, newshort->hs->other),
414     (newshort->shortest->hs, newshort->shortest->hs->other), .., 'to'
415     with cost 'cost'. */
416  unsigned hash = (intptr_t) nd / 10 + dir, i = 0;
417  routeNodeType *n;
418  do {
419    if (i++ > 10) {
420      //fprintf (stderr, "Double hash bailout : Table full, hash function "
421      //  "bad or no route exists\n");
422      return;
423    }
424    n = route + hash % dhashSize;
425    /* Linear congruential generator from wikipedia */
426    hash = (unsigned) (hash * (__int64) 1664525 + 1013904223);
427    if (n->nd == NULL) { /* First visit of this node */
428      n->nd = nd;
429      n->best = 0x7fffffff;
430      /* Will do later : routeHeap[routeHeapSize] = n; */
431      n->heapIdx = routeHeapSize++;
432      n->dir = dir;
433      n->remain = nd == ndBase - 1 ? 0
434        : lrint (sqrt (Sqr ((__int64)(nd->lat - flat)) +
435                       Sqr ((__int64)(nd->lon - flon))));
436      if (!shortest || n->remain < shortest->remain) shortest = n;
437      ROUTE_SET_ADDND_COUNT (routeAddCnt + 1);
438    }
439  } while (n->nd != nd || n->dir != dir);
440
441  int diff = n->remain + (newshort ? newshort->best - newshort->remain : 0);
442  if (n->best > cost + diff) {
443    n->best = cost + diff;
444    n->shortest = newshort;
445    if (n->heapIdx < 0) n->heapIdx = routeHeapSize++;
446    for (; n->heapIdx > 1 &&
447         n->best < routeHeap[n->heapIdx / 2]->best; n->heapIdx /= 2) {
448      routeHeap[n->heapIdx] = routeHeap[n->heapIdx / 2];
449      routeHeap[n->heapIdx]->heapIdx = n->heapIdx;
450    }
451    routeHeap[n->heapIdx] = n;
452  }
453}
454
455void Route (int recalculate)
456{ /* Recalculate is faster but only valid if 'to', 'car' and 'fastest' did not
457     change */
458/* We start by finding the segment that is closest to 'from' and 'to' */
459  ndType *endNd[2];
460  int toEndNd[2][2];
461 
462  ROUTE_SET_ADDND_COUNT (0);
463  shortest = NULL;
464  for (int i = recalculate ? 0 : 1; i < 2; i++) {
465    int lon = i ? flon : tlon, lat = i ? flat : tlat;
466    __int64 bestd = (__int64) 1 << 62;
467    /* find min (Sqr (distance)). Use long long so we don't loose accuracy */
468    OsmItr itr (lon - 100000, lat - 100000, lon + 100000, lat + 100000);
469    /* Search 1km x 1km around 'from' for the nearest segment to it */
470    while (Next (itr)) {
471      // We don't do for (int dir = 0; dir < 1; dir++) {
472      // because if our search box is large enough, it will also give us
473      // the other node.
474      if (!(((wayType*)(data + itr.nd[0]->wayPtr))->bits & (1<<Vehicle))) {
475        continue;
476      }
477      if (itr.nd[0]->other[0] < 0) continue;
478      __int64 lon0 = lon - itr.nd[0]->lon, lat0 = lat - itr.nd[0]->lat,
479              lon1 = lon - (ndBase + itr.nd[0]->other[0])->lon,
480              lat1 = lat - (ndBase + itr.nd[0]->other[0])->lat,
481              dlon = lon1 - lon0, dlat = lat1 - lat0;
482      /* We use Pythagoras to test angles for being greater that 90 and
483         consequently if the point is behind hs[0] or hs[1].
484         If the point is "behind" hs[0], measure distance to hs[0] with
485         Pythagoras. If it's "behind" hs[1], use Pythagoras to hs[1]. If
486         neither, use perpendicular distance from a point to a line */
487      int segLen = lrint (sqrt ((double)(Sqr(dlon) + Sqr (dlat))));
488      __int64 d = dlon * lon0 >= - dlat * lat0 ? Sqr (lon0) + Sqr (lat0) :
489        dlon * lon1 <= - dlat * lat1 ? Sqr (lon1) + Sqr (lat1) :
490        Sqr ((dlon * lat1 - dlat * lon1) / segLen);
491      if (d < bestd) {
492        wayType *w = (wayType *)(data + itr.nd[0]->wayPtr);
493        bestd = d;
494        double invSpeed = 1;//!fastest ? 1.0 : Style (w)->invSpeed[car];
495        //printf ("%d %lf\n", i, invSpeed);
496        toEndNd[i][0] =
497          lrint (sqrt ((double)(Sqr (lon0) + Sqr (lat0))) * invSpeed);
498        toEndNd[i][1] =
499          lrint (sqrt ((double)(Sqr (lon1) + Sqr (lat1))) * invSpeed);
500        if (dlon * lon1 <= -dlat * lat1) toEndNd[i][1] += toEndNd[i][0] * 9;
501        if (dlon * lon0 >= -dlat * lat0) toEndNd[i][0] += toEndNd[i][1] * 9;
502
503        if (w->bits & (1 << onewayR)) toEndNd[i][1] = 200000000;
504        /* It's possible to go up a oneway at the end, but at a huge penalty*/
505        /* It's also possible to go up a 1 segment of a footway with a car
506           without penalty. */
507        endNd[i] = itr.nd[0];
508        /* The router only stops after it has traversed endHs[1], so if we
509           want 'limit' to be accurate, we must subtract it's length
510        if (i) {
511          toEndHs[1][0] -= segLen;
512          toEndHs[1][1] -= segLen;
513        } */
514      }
515    } /* For each candidate segment */
516    if (bestd == (__int64) 1 << 62) {
517      fprintf (stderr, "No segment nearby\n");
518      return;
519    }
520  } /* For 'from' and 'to', find segment that passes nearby */
521  if (recalculate) {
522    free (route);
523    dhashSize = Sqr ((tlon - flon) >> 16) + Sqr ((tlat - flat) >> 16) + 20;
524    dhashSize = dhashSize < 10000 ? dhashSize * 1000 : 10000000;
525    // This memory management may not match computer capabilities
526    route = (routeNodeType*) calloc (dhashSize, sizeof (*route));
527  }
528
529  routeHeapSize = 1; /* Leave position 0 open to simplify the math */
530  routeHeap = ((routeNodeType**) malloc (dhashSize*sizeof (*routeHeap))) - 1;
531 
532  if (recalculate) {
533    AddNd (endNd[0], 0, toEndNd[0][0], NULL);
534    AddNd (ndBase + endNd[0]->other[0], 1, toEndNd[0][1], NULL);
535    AddNd (endNd[0], 1, toEndNd[0][0], NULL);
536    AddNd (ndBase + endNd[0]->other[0], 0, toEndNd[0][1], NULL);
537  }
538  else {
539    for (int i = 0; i < dhashSize; i++) {
540      if (route[i].nd) {
541        route[i].best++; // Force re-add to the heap
542        AddNd (route[i].nd, route[i].dir, route[i].best - 1,
543          route[i].shortest);
544      }
545    }
546  }
547 
548  while (routeHeapSize > 1) {
549    routeNodeType *root = routeHeap[1];
550    if (root->nd == ndBase - 1) { // ndBase - 1 is a marker for 'from'
551      shortest = root->shortest;
552      break;
553    }
554    routeHeapSize--;
555    int beste = routeHeap[routeHeapSize]->best;
556    for (int i = 2; ; ) {
557      int besti = i < routeHeapSize ? routeHeap[i]->best : beste;
558      int bestipp = i + 1 < routeHeapSize ? routeHeap[i + 1]->best : beste;
559      if (besti > bestipp) i++;
560      else bestipp = besti;
561      if (beste <= bestipp) {
562        routeHeap[i / 2] = routeHeap[routeHeapSize];
563        routeHeap[i / 2]->heapIdx = i / 2;
564        break;
565      }
566      routeHeap[i / 2] = routeHeap[i];
567      routeHeap[i / 2]->heapIdx = i / 2;
568      i = i * 2;
569    }
570    root->heapIdx = -1; /* Root now removed from the heap */
571    if (root->nd == (!root->dir ? endNd[1] : ndBase + endNd[1]->other[0])) {
572      AddNd (ndBase - 1, 0, toEndNd[1][1 - root->dir], root);
573    }
574    ndType *nd = root->nd, *other;
575    while (nd > ndBase && nd[-1].lon == nd->lon &&
576      nd[-1].lat == nd->lat) nd--; /* Find first nd in node */
577
578    /* Now work through the segments connected to root. */
579    do {
580      for (int dir = 0; dir < 2; dir++) {
581        if (nd == root->nd && dir == root->dir) continue;
582        /* Don't consider an immediate U-turn to reach root->hs->other.
583           This doesn't exclude 179.99 degree turns though. */
584       
585        if (nd->other[dir] < 0) continue; // Named node
586       
587        other = ndBase + nd->other[dir];
588        wayType *w = (wayType *)(data + nd->wayPtr);
589        if ((w->bits & (1<<Vehicle)) && (dir || !(w->bits & (1 << onewayR)))) {
590          int d = lrint (sqrt ((double)
591            (Sqr ((__int64)(nd->lon - other->lon)) +
592             Sqr ((__int64)(nd->lat - other->lat)))) *
593                        (FastestRoute ? Style (w)->invSpeed[Vehicle] : 1.0));                 
594          AddNd (other, 1 - dir, d, root);
595        } // If we found a segment we may follow
596      }
597    } while (++nd < ndBase + hashTable[bucketsMin1 + 1] &&
598             nd->lon == nd[-1].lon && nd->lat == nd[-1].lat);
599  } // While there are active nodes left
600  free (routeHeap + 1);
601  ROUTE_SHOW_STATS;
602//  if (fastest) printf ("%lf
603//  printf ("%lf km\n", limit / 100000.0);
604}
605
606#ifndef HEADLESS
607#define STATUS_BAR    0
608
609GtkWidget *draw, *location, *followGPSr;
610GtkComboBox *iconSet, *carBtn, *fastestBtn, *detailBtn;
611int clon, clat, zoom, option = EnglishNum, gpsSockTag, setLocBusy = FALSE;
612/* zoom is the amount that fits into the window (regardless of window size) */
613
614inline void SetLocation (int nlon, int nlat)
615{
616  clon = nlon;
617  clat = nlat;
618  #ifndef _WIN32_WCE
619  char lstr[50];
620  int zl = 0;
621  while (zl < 32 && (zoom >> zl)) zl++;
622  sprintf (lstr, "?lat=%.5lf&lon=%.5lf&zoom=%d", LatInverse (nlat),
623    LonInverse (nlon), 33 - zl);
624  setLocBusy = TRUE;
625  gtk_entry_set_text (GTK_ENTRY (location), lstr);
626  setLocBusy = FALSE;
627  #endif
628}
629
630#ifndef _WIN32_WCE
631int ChangeLocation (void)
632{
633  if (setLocBusy) return FALSE;
634  char *lstr = (char *) gtk_entry_get_text (GTK_ENTRY (location));
635  double lat, lon;
636  while (*lstr != '?' && *lstr != '\0') lstr++;
637  if (sscanf (lstr, "?lat=%lf&lon=%lf&zoom=%d", &lat, &lon, &zoom) == 3) {
638    clat = Latitude (lat);
639    clon = Longitude (lon);
640    zoom = 0xffffffff >> (zoom - 1);
641    gtk_widget_queue_clear (draw);
642  }
643  return FALSE;
644}
645
646int ChangeOption (void)
647{
648  IconSet = gtk_combo_box_get_active (iconSet);
649  Vehicle = gtk_combo_box_get_active (carBtn) + motorcarR;
650  DetailLevel = 4 - gtk_combo_box_get_active (detailBtn);
651  FollowGPSr = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (followGPSr));
652  FastestRoute = !gtk_combo_box_get_active (fastestBtn);
653  gtk_widget_queue_clear (draw);
654  return FALSE;
655}
656#endif
657/*-------------------------------- NMEA processing ------------------------*/
658/* My TGPS 374 frequently produces corrupt NMEA output (probably when the
659   CPU goes into sleep mode) and this may also be true for GPS receivers on
660   long serial lines. To overcome this, we ignore badly formed sentences and
661   we interpolate the date where the jumps in time values seems plausible.
662   
663   For the GPX output there is an extra layer of filtering : The minimum
664   number of observations are dropped so that the remaining observations does
665   not imply any impossible manuavers like traveling back in time or
666   reaching supersonic speed. This effeciently implemented transforming the
667   problem into one of finding the shortest path through a graph :
668   The nodes {a_i} are the list of n observations. Add the starting and
669   ending nodes a_0 and a_n+1, which are both connected to all the other
670   nodes. 2 observation nodes are connected if it's possible that the one
671   will follow the other. If two nodes {a_i} and {a_j} are connected, the
672   cost (weight) of the connection is j - 1 - i, i.e. the number of nodes
673   that needs to be dropped. */
674struct gpsNewStruct {
675  struct {
676    double latitude, longitude, track, speed, hdop, ele;
677    char date[6], tm[6];
678    int mode;
679  } fix;
680  unsigned dropped;
681  struct gpsNewStruct *dptr;
682} gpsTrack[18000], *gpsNew = gpsTrack;
683
684void FlushGpx (void)
685{
686  struct gpsNewStruct *a, *best, *first = NULL;
687  for (best = gpsNew; gpsTrack <= best && best->dropped == 0; best--) {}
688  gpsNew = gpsTrack;
689  if (best <= gpsTrack) return; // No observations
690  for (a = best - 1; gpsTrack <= a && best < a + best->dropped; a--) {
691    if (best->dropped > best - a + a->dropped) best = a;
692  }
693  // We want .., best->dptr->dptr->dptr, best->dptr->dptr, best->dptr, best
694  // Now we reverse the linked list :
695  while (best) {
696    a = best->dptr;
697    best->dptr = first;
698    first = best;
699    best = a;
700  }
701  char fname[18];
702  sprintf (fname, DOC_PREFIX "%.2s%.2s%.2s-%.6s.gpx", first->fix.date + 4,
703    first->fix.date + 2, first->fix.date, first->fix.tm);
704  FILE *gpx = fopen (fname, "wb");
705  if (!gpx) return;
706  fprintf (gpx, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
707<gpx\n\
708 version=\"1.0\"\n\
709creator=\"gosmore\"\n\
710xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\
711xmlns=\"http://www.topografix.com/GPX/1/0\"\n\
712xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\n\">\n\
713<trk>\n\
714<trkseg>\n");
715  for (; first; first = first->dptr) { // Iterate the linked list
716    fprintf (gpx, "<trkpt lat=\"%12.9lf\" lon=\"%12.9lf\">\n\
717<time>20%.2s-%.2s-%.2sT%.2s:%.2s:%.2sZ</time>\n\
718</trkpt>\n", first->fix.latitude, first->fix.longitude, first->fix.date + 4,
719      first->fix.date + 2, first->fix.date,
720      first->fix.tm, first->fix.tm + 2, first->fix.tm + 4);
721   
722//    if (first->next && ) fprintf (gpx, "</trkseg>\n</trk>\n<trk>\n<trkseg>\n");
723  }
724  fprintf (gpx, "</trkseg>\n\
725</trk>\n\
726</gpx>\n");
727}
728
729int ProcessNmea (char *rx, unsigned *got)
730{
731  unsigned dataReady = FALSE, i;
732  for (i = 0; i < *got && rx[i] != '$'; i++, (*got)--) {}
733  while (rx[i] == '$') {
734    //for (j = 0; j < got; i++, j++) rx[j] = rx[i];
735    int fLen[19], fStart[19], fNr;
736    memmove (rx, rx + i, *got);
737    for (i = 1, fNr = 0; i < *got && rx[i] != '$' && fNr < 19; fNr++) {
738      fStart[fNr] = i;
739      while (i < *got && (rx[i] == '.' || isdigit (rx[i]))) i++;
740      fLen[fNr] = i - fStart[fNr];
741      while (i < *got && rx[i] != '$' && rx[i++] != ',') {}
742    }
743    while (i < *got && rx[i] != '$') i++;
744    int col = memcmp (rx, "$GPGLL", 6) == 0 ? 1 :
745      memcmp (rx, "$GPGGA", 6) == 0 ? 2 :
746      memcmp (rx, "$GPRMC", 6) == 0 ? 3 : 0;
747    // latitude is at fStart[col], longitude is at fStart[col + 2].
748    if (fNr >= (col == 0 ? 2 : col == 1 ? 6 : col == 2 ? 13 : 10)) {
749      if (col > 0 && fLen[col] > 6 && memchr ("SsNn", rx[fStart[col + 1]], 4)
750        && fLen[col + 2] > 7 && memchr ("EeWw", rx[fStart[col + 3]], 4) &&
751        fLen[col == 1 ? 5 : 1] >= 6 &&
752          memcmp (gpsNew->fix.tm, rx + fStart[col == 1 ? 5 : 1], 6) != 0) {
753        double nLat = (rx[fStart[col]] - '0') * 10 + rx[fStart[col] + 1]
754          - '0' + atof (rx + fStart[col] + 2) / 60;
755        double nLon = ((rx[fStart[col + 2]] - '0') * 10 +
756          rx[fStart[col + 2] + 1] - '0') * 10 + rx[fStart[col + 2] + 2]
757          - '0' + atof (rx + fStart[col + 2] + 3) / 60;
758        if (tolower (rx[fStart[col + 1]]) == 's') nLat = -nLat;
759        if (tolower (rx[fStart[col + 3]]) == 'w') nLon = -nLon;
760        if (fabs (nLat) < 90 && fabs (nLon) < 180) {
761          if (gpsTrack + sizeof (gpsTrack) / sizeof (gpsTrack[0]) <=
762            ++gpsNew) FlushGpx ();
763          memcpy (gpsNew->fix.tm, rx + fStart[col == 1 ? 5 : 1], 6);
764          gpsNew->dropped = 0;
765          dataReady = TRUE; // Notify only when parsing is complete
766          gpsNew->fix.latitude = nLat;
767          gpsNew->fix.longitude = nLon;
768        }
769      }
770      if (col == 2) gpsNew->fix.hdop = atof (rx + fStart[8]);
771      if (col == 3 && fLen[7] > 0 && fLen[8] > 0 && fLen[9] >= 6) {
772        memcpy (gpsNew->fix.date, rx + fStart[9], 6);
773        gpsNew->fix.speed = atof (rx + fStart[7]);
774        gpsNew->fix.track = atof (rx + fStart[8]);
775       
776        //-------------------------------------------------------------
777        // Now fix the dates and do a little bit of shortest path work
778        int i, j, k, l; // TODO : Change indexes into pointers
779        for (i = 0; gpsTrack < gpsNew + i && !gpsNew[i - 1].dropped &&
780             (((((gpsNew[i].fix.tm[0] - gpsNew[i - 1].fix.tm[0]) * 10 +
781                  gpsNew[i].fix.tm[1] - gpsNew[i - 1].fix.tm[1]) * 6 +
782                  gpsNew[i].fix.tm[2] - gpsNew[i - 1].fix.tm[2]) * 10 +
783                  gpsNew[i].fix.tm[3] - gpsNew[i - 1].fix.tm[3]) * 6 +
784                  gpsNew[i].fix.tm[4] - gpsNew[i - 1].fix.tm[4]) * 10 +
785                  gpsNew[i].fix.tm[5] - gpsNew[i - 1].fix.tm[5] < 30; i--) {}
786        // Search backwards for a discontinuity in tm
787       
788        for (j = i; gpsTrack < gpsNew + j && !gpsNew[j - 1].dropped; j--) {}
789        // Search backwards for the first observation missing its date
790       
791        for (k = j; k <= 0; k++) {
792          memcpy (gpsNew[k].fix.date,
793            gpsNew[gpsTrack < gpsNew + j && k < i ? j - 1 : 0].fix.date, 6);
794          gpsNew[k].dptr = NULL; // Try gpsNew[k] as first observation
795          gpsNew[k].dropped = gpsNew + k - gpsTrack + 1;
796          for (l = k - 1; gpsTrack < gpsNew + l && k - l < 300 &&
797               gpsNew[k].dropped > unsigned (k - l - 1); l--) {
798            // At the point where we consider 300 bad observations, we are
799            // more likely to be wasting CPU cycles.
800            int tdiff =
801              ((((((((gpsNew[k].fix.date[4] - gpsNew[l].fix.date[4]) * 10 +
802              gpsNew[k].fix.date[5] - gpsNew[l].fix.date[5]) * 12 +
803              (gpsNew[k].fix.date[2] - gpsNew[l].fix.date[2]) * 10 +
804              gpsNew[k].fix.date[3] - gpsNew[l].fix.date[3]) * 31 +
805              (gpsNew[k].fix.date[0] - gpsNew[l].fix.date[0]) * 10 +
806              gpsNew[k].fix.date[1] - gpsNew[l].fix.date[1]) * 24 +
807              (gpsNew[k].fix.tm[0] - gpsNew[l].fix.tm[0]) * 10 +
808              gpsNew[k].fix.tm[1] - gpsNew[l].fix.tm[1]) * 6 +
809              gpsNew[k].fix.tm[2] - gpsNew[l].fix.tm[2]) * 10 +
810              gpsNew[k].fix.tm[3] - gpsNew[l].fix.tm[3]) * 6 +
811              gpsNew[k].fix.tm[4] - gpsNew[l].fix.tm[4]) * 10 +
812              gpsNew[k].fix.tm[5] - gpsNew[l].fix.tm[5];
813             
814            /* Calculate as if every month has 31 days. It causes us to
815               underestimate the speed travelled in very rare circumstances,
816               (e.g. midnight GMT on Feb 28) allowing a few bad observation
817               to sneek in. */
818            if (0 < tdiff && tdiff < 3600 * 24 * 62 /* Assume GPS used more */
819                /* frequently than once every 2 months */ &&
820                fabs (gpsNew[k].fix.latitude - gpsNew[l].fix.latitude) +
821                fabs (gpsNew[k].fix.longitude - gpsNew[l].fix.longitude) *
822                  cos (gpsNew[k].fix.latitude * (M_PI / 180.0)) <
823                    tdiff * (1600 / 3600.0 * 360 / 40000) && // max 1600 km/h
824                gpsNew[k].dropped > gpsNew[l].dropped + k - l - 1) {
825              gpsNew[k].dropped = gpsNew[l].dropped + k - l - 1;
826              gpsNew[k].dptr = gpsNew + l;
827            }
828          } // For each possible connection
829        } // For each new observation
830      } // If it's a properly formatted RMC
831    } // If the sentence had enough columns for our purposes.
832    else if (i == *got) break; // Retry when we receive more data
833    *got -= i;
834  } /* If we know the sentence type */
835  return dataReady;
836}
837
838#ifndef _WIN32_WCE
839#ifdef ROUTE_TEST
840gint RouteTest (GtkWidget *widget, GdkEventButton *event, void *)
841{
842  static int ptime = 0;
843  if (TRUE) {
844    ptime = time (NULL);
845    int w = draw->allocation.width;
846    int perpixel = zoom / w;
847    clon += lrint ((event->x - w / 2) * perpixel);
848    clat -= lrint ((event->y - draw->allocation.height / 2) * perpixel);
849    int plon = clon + lrint ((event->x - w / 2) * perpixel);
850    int plat = clat -
851      lrint ((event->y - draw->allocation.height / 2) * perpixel);
852#else
853// void GpsMove (gps_data_t *gps, char */*buf*/, size_t /*len*/, int /*level*/)
854void ReceiveNmea (gpointer /*data*/, gint source, GdkInputCondition /*c*/)
855{
856  static char rx[1200];
857  static unsigned got = 0;
858  int cnt = read (source, rx + got, sizeof (rx) - got);
859  if (cnt == 0) {
860    gdk_input_remove (gpsSockTag);
861    return;
862  }
863  got += cnt;
864  gpsNewStruct *gps = gpsNew;
865 
866  if (ProcessNmea (rx, &got) && /*gps->fix.mode >= MODE_2D &&*/ FollowGPSr) {
867    SetLocation (Longitude (gps->fix.longitude),Latitude (gps->fix.latitude));
868    int plon = Longitude (gps->fix.longitude + gps->fix.speed * 3600.0 /
869      40000000.0 / cos (gps->fix.latitude * (M_PI / 180.0)) *
870      sin (gps->fix.track * (M_PI / 180.0)));
871    int plat = Latitude (gps->fix.latitude + gps->fix.speed * 3600.0 /
872      40000000.0 * cos (gps->fix.track * (M_PI / 180.0)));
873    // Predict the vector that will be traveled in the next 10seconds
874//    printf ("%5.1lf m/s Heading %3.0lf\n", gps->fix.speed, gps->fix.track);
875//    printf ("%lf %lf\n", gps->fix.latitude, gps->fix.longitude);
876#endif
877   
878    flon = clon;
879    flat = clat;
880    #if 0
881    Route (FALSE);
882    if (shortest) {
883      __int64 dlon = plon - clon, dlat = plat - clat;
884      if (!shortest->shortest && dlon * (tlon - clon) > dlat * (clat - tlat)
885                             && dlon * (tlon - plon) < dlat * (plat - tlat)) {
886        // Only stop once both C and P are acute angles in CPT, according to
887        // Pythagoras.
888        fprintf (flitePipe, "%ld Stop\n", (long)time (NULL));
889      }
890      char *oldName = NULL;
891      for (routeNodeType *ahead = shortest; ahead;
892           ahead = ahead->shortest) {
893        __int64 alon = ((halfSegType *)(ahead->hs->other + data))->lon -
894          ahead->hs->lon;
895        __int64 alat = ((halfSegType *)(ahead->hs->other + data))->lat -
896          ahead->hs->lat;
897        __int64 divisor = dlon * alat - dlat * alon;
898        __int64 dividend = dlon * alon + dlat * alat;
899        __int64 slon = ahead->hs->lon - clon;
900        __int64 slat = ahead->hs->lat - clat;
901        if (ahead == shortest && ahead->shortest && dividend < 0 &&
902            dividend < divisor && divisor < -dividend &&
903            Sqr (slon + alon) + Sqr (slat + alat) > 64000000) {
904          fprintf (flitePipe, "%ld U turn\n", (long)time (NULL));
905          break; // Only when first node is far behind us.
906        }
907        __int64 dintercept = divisor == 0 ? 9223372036854775807LL :
908            dividend * (dlon * slat - dlat * slon) /
909            divisor + dlon * slon + dlat * slat;
910        char *name = data + ((wayType *)(data +
911          (ahead->hs->wayPtr == TO_HALFSEG ? (halfSegType*)
912                  (ahead->hs->other + data) : ahead->hs)->wayPtr))->name;
913        if (dividend < 0 || divisor > dividend || divisor < -dividend) {
914          // If segment goes "back" or makes a 45 degree angle with the
915          // motion vector.
916          //flite_text_to_speech ("U turn", fliteV, "play");
917          if (dintercept < dlon * dlon + dlat * dlat) {
918            // Found a turn that should be made in the next 10 seconds.
919            fprintf (flitePipe, "%ld %s in %s\n", (long)time (NULL),
920              divisor > 0 ? "Left" : "Right", name);
921          }
922          break;
923        }
924        if (name[0] != '\0') {
925          if (oldName && stricmp (oldName, name)) {
926            if (dintercept < dlon * dlon + dlat * dlat) {
927              fprintf (flitePipe, "%ld %s\n", (long)time (NULL), name);
928            }
929            break;
930          }
931          oldName = name;
932        }
933      } // While looking for a turn ahead.
934    } // If the routing was successful
935    #endif
936    gtk_widget_queue_clear (draw);
937  } // If following the GPSr and it has a fix.
938}
939#endif // _WIN32_WCE
940
941void HitButton (int b)
942{
943    if (b == 0) option = (option + 1) % (numberOfOptions + 1);
944    else if (option == StartRouteNum) {
945      flon = clon;
946      flat = clat;
947    }
948    else if (option == EndRouteNum) {
949      tlon = clon;
950      tlat = clat;
951      Route (TRUE);
952    }
953    #ifdef _WIN32_WCE
954    else if (option == SearchNum) {
955      SipShowIM (SIPF_ON);
956      if (ModelessDialog) ShowWindow (dlgWnd, SW_SHOW);
957      else DialogBox (hInst, MAKEINTRESOURCE(IDD_DLGSEARCH),
958               NULL, (DLGPROC)DlgSearchProc);
959    }
960    else if (option == BaudRateNum) BaudRate += b * 4800 - 7200;
961    #endif
962    #define o(en,de,es,fr,it,nl,min,max) else if (option == en ## Num) \
963      en = (en - (min) + (b == 2 ? 1 : (max) - (min) - 1)) % \
964        ((max) - (min)) + (min);
965    OPTIONS
966    #undef o
967    else {
968      if (b == 2) zoom = zoom / 4 * 3;
969      if (b == 1) zoom = zoom / 3 * 4;
970      if (b > 0) SetLocation (clon, clat);
971    }
972    if (b > 0 && option <= FastestRouteNum) option = numberOfOptions;
973}
974
975int Click (GtkWidget * /*widget*/, GdkEventButton *event, void * /*para*/)
976{
977  int w = draw->allocation.width;
978  #ifdef ROUTE_TEST
979  if (event->state) {
980    return RouteTest (widget, event, para);
981  }
982  #endif
983  if (ButtonSize <= 0) ButtonSize = 4;
984  int b = (draw->allocation.height - lrint (event->y)) / (ButtonSize * 20);
985  if (event->x > w - ButtonSize * 20 && b <
986      (HideZoomButtons && option == numberOfOptions ? 1 : 3)) HitButton (b);
987  else {
988    int perpixel = zoom / w;
989    if (event->button == 1) {
990      SetLocation (clon + lrint ((event->x - w / 2) * perpixel),
991        clat - lrint ((event->y - draw->allocation.height / 2) * perpixel));
992
993      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (followGPSr), FALSE);
994      FollowGPSr = 0;
995    }
996    else if (event->button == 2) {
997      flon = clon + lrint ((event->x - w / 2) * perpixel);
998      flat = clat - lrint ((event->y - draw->allocation.height/2) * perpixel);
999    }
1000    else {
1001      tlon = clon + lrint ((event->x - w / 2) * perpixel);
1002      tlat = clat -
1003        lrint ((event->y - draw->allocation.height / 2) * perpixel);
1004      //car = !gtk_combo_box_get_active (carBtn) ? motorcarR : bicycleR;
1005      //fastest = !gtk_combo_box_get_active (fastestBtn);
1006      Route (TRUE);
1007    }
1008  }
1009  gtk_widget_queue_clear (draw);
1010  return FALSE;
1011}
1012
1013#if 0
1014void GetDirections (GtkWidget *, gpointer)
1015{
1016  char *msg;
1017  if (!shortest) msg = strdup (
1018    "Mark the starting point with the middle button and the\n"
1019    "end point with the right button. Then click Get Directions again\n");
1020  else {
1021    for (int i = 0; i < 2; i++) {
1022      int len = 0;
1023      char *last = "";
1024      __int64 dlon = 0, dlat = 1, bSqr = 1; /* Point North */
1025      for (routeNodeType *x = shortest; x; x = x->shortest) {
1026        halfSegType *other = (halfSegType *)(data + x->hs->other);
1027        int forward = x->hs->wayPtr != TO_HALFSEG;
1028        wayType *w = (wayType *)(data + (forward ? x->hs : other)->wayPtr);
1029       
1030        // I think the formula below can be substantially simplified using
1031        // the method used in GpsMove
1032        __int64 nlon = other->lon - x->hs->lon, nlat = other->lat-x->hs->lat;
1033        __int64 cSqr = Sqr (nlon) + Sqr (nlat);
1034        __int64 lhs = bSqr + cSqr - Sqr (nlon - dlon) - Sqr (nlat - dlat);
1035        /* Use cosine rule to determine if the angle is obtuse or greater than
1036           45 degrees */
1037        if (lhs < 0 || Sqr (lhs) < 2 * bSqr * cSqr) {
1038          /* (-nlat,nlon) is perpendicular to (nlon,nlat). Then we use
1039             Pythagoras test for obtuse angle for left and right */
1040          if (!i) len += 11;
1041          else len += sprintf (msg + len, "%s turn\n",
1042            nlon * dlat < nlat * dlon ? "Left" : "Right");
1043        }
1044        dlon = nlon;
1045        dlat = nlat;
1046        bSqr = cSqr;
1047       
1048        if (strcmp (w->name + data, last)) {
1049          last = w->name + data;
1050          if (!i) len += strlen (last) + 1;
1051          else len += sprintf (msg + len, "%s\n", last);
1052        }
1053      }
1054      if (!i) msg = (char*) malloc (len + 1);
1055    } // First calculate len, then create message.
1056  }
1057  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1058  GtkWidget *view = gtk_text_view_new ();
1059  GtkWidget *scrol = gtk_scrolled_window_new (NULL, NULL);
1060//  gtk_scrolled_winGTK_POLICY_AUTOMATIC,
1061//    GTK_POLICY_ALWAYS);
1062  GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
1063  gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
1064  gtk_text_buffer_set_text (buffer, msg, -1);
1065  free (msg);
1066  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrol), view);
1067  gtk_container_add (GTK_CONTAINER (window), scrol);
1068  gtk_widget_set_size_request (window, 300, 300);
1069  gtk_widget_show (view);
1070  gtk_widget_show (scrol);
1071  gtk_widget_show (window);
1072}
1073
1074#endif
1075
1076struct name2renderType { // Build a list of names, sort by name,
1077  wayType *w;            // make unique by name, sort by y, then render
1078  int x, y, width;       // only if their y's does not overlap
1079};
1080
1081#ifdef _WIN32_WCE
1082int Expose (HDC mygc, HDC icons, HPEN *pen)
1083{
1084  struct {
1085    int width, height;
1086  } clip;
1087/*  clip.width = GetSystemMetrics(SM_CXSCREEN);
1088  clip.height = GetSystemMetrics(SM_CYSCREEN); */
1089  HFONT sysFont = (HFONT) GetStockObject (SYSTEM_FONT);
1090  LOGFONT logFont;
1091  GetObject (sysFont, sizeof (logFont), &logFont);
1092  WCHAR wcTmp[70];
1093  int detail = 2;
1094
1095#define gtk_combo_box_get_active(x) 1
1096#define gdk_draw_drawable(win,dgc,sdc,x,y,dx,dy,w,h) \
1097  BitBlt (dgc, dx, dy, w, h, sdc, x, y, SRCCOPY)
1098#define gdk_draw_line(win,gc,sx,sy,dx,dy) \
1099  MoveToEx (gc, sx, sy, NULL); LineTo (gc, dx, dy)
1100#else
1101gint Scroll (GtkWidget * /*widget*/, GdkEventScroll *event, void * /*w_cur*/)
1102{
1103  if (event->direction == GDK_SCROLL_UP) zoom = zoom / 4 * 3;
1104  if (event->direction == GDK_SCROLL_DOWN) zoom = zoom / 3 * 4;
1105  SetLocation (clon, clat);
1106  gtk_widget_queue_clear (draw);
1107  return FALSE;
1108}
1109
1110gint Expose (void)
1111{
1112  static GdkColor styleColour[2 << STYLE_BITS][2], routeColour;
1113  static GdkPixmap *icons = NULL;
1114  static GdkGC *mygc = NULL;
1115  if (!mygc) {
1116    mygc = gdk_gc_new (draw->window);
1117    for (int i = 0; i < 1 || style[i - 1].scaleMax; i++) {
1118      for (int j = 0; j < 2; j++) {
1119        int c = !j ? style[i].areaColour 
1120          : style[i].lineColour ? style[i].lineColour
1121          : (style[i].areaColour >> 1) & 0xefefef; // Dark border
1122        styleColour[i][j].red =    (c >> 16)        * 0x101;
1123        styleColour[i][j].green = ((c >> 8) & 0xff) * 0x101;
1124        styleColour[i][j].blue =   (c       & 0xff) * 0x101;
1125        gdk_colormap_alloc_color (gdk_window_get_colormap (draw->window),
1126          &styleColour[i][j], FALSE, TRUE);
1127      }
1128    }
1129    routeColour.red = 0xffff;
1130    routeColour.green = routeColour.blue = 0;
1131    gdk_colormap_alloc_color (gdk_window_get_colormap (draw->window),
1132      &routeColour, FALSE, TRUE);
1133    gdk_gc_set_fill (mygc, GDK_SOLID);
1134    #ifndef WIN32
1135    icons = gdk_pixmap_create_from_xpm (draw->window, NULL, NULL,
1136      FindResource ("icons.xpm"));
1137    #else
1138    icons = gdk_pixmap_create_from_xpm_d (draw->window, NULL, NULL,
1139      icons_xpm);
1140    #endif
1141  } 
1142
1143//  gdk_gc_set_clip_rectangle (mygc, &clip);
1144//  gdk_gc_set_foreground (mygc, &styleColour[0][0]);
1145//  gdk_gc_set_line_attributes (mygc,
1146//    1, GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
1147   
1148//  clip.width = draw->allocation.width - ZOOM_PAD_SIZE;
1149//  gdk_gc_set_clip_rectangle (mygc, &clip);
1150 
1151  GdkFont *f = gtk_style_get_font (draw->style);
1152  int detail = DetailLevel; //4 - gtk_combo_box_get_active (detailBtn);
1153  GdkRectangle clip;
1154  clip.x = 0;
1155  clip.y = 0;
1156#endif // !_WIN32_WCE
1157  clip.height = draw->allocation.height - STATUS_BAR;
1158  clip.width = draw->allocation.width;
1159  if (ButtonSize <= 0) ButtonSize = 4;
1160  #ifdef CAIRO_VERSION
1161  cairo_t *cai = gdk_cairo_create (draw->window);
1162  if (detail < 4) {
1163    cairo_font_options_t *caiFontOptions = cairo_font_options_create ();
1164    cairo_get_font_options (cai, caiFontOptions);
1165    cairo_font_options_set_antialias (caiFontOptions, CAIRO_ANTIALIAS_NONE);
1166    cairo_set_font_options (cai, caiFontOptions);
1167  }
1168  cairo_matrix_t mat;
1169  cairo_matrix_init_identity (&mat);
1170  #endif
1171  if (option == numberOfOptions) {
1172    if (zoom < 0) zoom = 2012345678;
1173    if (zoom / clip.width == 0) zoom += 4000;
1174    int perpixel = zoom / clip.width;
1175    int doAreas = TRUE;
1176  //    zoom / sqrt (draw->allocation.width * draw->allocation.height);
1177    for (int thisLayer = -5, nextLayer; thisLayer < 6;
1178         thisLayer = nextLayer, doAreas = !doAreas) {
1179      OsmItr itr (clon - perpixel * clip.width / 2 - 10000,
1180        clat - perpixel * clip.height / 2 - 10000,
1181        clon + perpixel * clip.width / 2 + 10000,
1182        clat + perpixel * clip.height / 2 + 10000);
1183      // Widen this a bit so that we render nodes that are just a bit offscreen ?
1184      nextLayer = 6;
1185     
1186      while (Next (itr)) {
1187        wayType *w = (wayType *)(data + itr.nd[0]->wayPtr);
1188        if (Style (w)->scaleMax < perpixel * 175 / (detail + 4)) continue;
1189       
1190        if (detail < 4 && Style (w)->areaColour) {
1191          if (thisLayer > -5) continue;  // Draw all areas with layer -5
1192        }
1193        else if (zoom < 100000*100) {
1194        // Under low-zoom we draw everything on layer -5 (faster)
1195          if (thisLayer < Layer (w) && Layer (w) < nextLayer) {
1196            nextLayer = Layer (w);
1197          }
1198          if (detail == 4) {
1199            if (doAreas) nextLayer = thisLayer;
1200            if (Style (w)->areaColour ? !doAreas : doAreas) continue;
1201          }
1202          if (Layer (w) != thisLayer) continue;
1203        }
1204        ndType *nd = itr.nd[0];
1205        if (itr.nd[0]->other[0] >= 0) {
1206          nd = ndBase + itr.nd[0]->other[0];
1207          if (nd->lat == INT_MIN) nd = itr.nd[0]; // Node excluded from build
1208          else if (itr.left <= nd->lon && nd->lon < itr.right &&
1209              itr.top  <= nd->lat && nd->lat < itr.bottom) continue;
1210        } // Only process this way when the Itr gives us the first node, or
1211        // the first node that's inside the viewing area
1212
1213        #ifndef _WIN32_WCE
1214        __int64 maxLenSqr = 0;
1215        double x0, y0;
1216        #else
1217        int best = 0, bestW, bestH, x0, y0;
1218        #endif
1219        int len = strcspn ((char *)(w + 1) + 1, "\n");
1220       
1221        if (nd->other[0] < 0 && nd->other[1] < 0) {
1222          int x = clip.width / 2 + (nd->lon - clon) / perpixel;
1223          int y = clip.height / 2 - (nd->lat - clat) / perpixel;
1224          int *icon = Style (w)->x + 4 * IconSet;
1225          if (icons && icon[2] != 0) {
1226            gdk_draw_drawable (draw->window, mygc, icons,
1227              icon[0], icon[1], x - icon[2] / 2, y - icon[3] / 2,
1228              icon[2], icon[3]);
1229          }
1230         
1231          #ifdef _WIN32_WCE
1232          SelectObject (mygc, sysFont);
1233          MultiByteToWideChar (AnsiCodePage ? CP_ACP : CP_UTF8, 0, (char *)(w + 1) + 1,
1234            len, wcTmp, sizeof (wcTmp));
1235          ExtTextOut (mygc, x - len * 3, y + icon[3] / 2, 0, NULL,
1236                wcTmp, len, NULL);     
1237          #endif
1238          #ifdef CAIRO_VERSION
1239          //if (Style (w)->scaleMax > zoom / 2 || zoom < 2000) {
1240            mat.xx = mat.yy = 12.0;
1241            mat.xy = mat.yx = 0;
1242            x0 = x - mat.xx / 12.0 * 3 * len; /* Render the name of the node */
1243            y0 = y + mat.xx * f->ascent / 12.0 + icon[3] / 2;
1244            maxLenSqr = Sqr ((__int64) Style (w)->scaleMax);
1245            //4000000000000LL; // Without scaleMax, use 400000000
1246          //}
1247          #endif
1248        }
1249        else if (Style (w)->areaColour) {
1250          #ifndef _WIN32_WCE
1251          while (nd->other[0] >= 0) nd = ndBase + nd->other[0];
1252          static GdkPoint pt[1000];
1253          unsigned pts;
1254          for (pts = 0; pts < sizeof (pt) / sizeof (pt[0]) && nd->other[1] >= 0;
1255               nd = ndBase + nd->other[1]) {
1256            if (nd->lat != INT_MIN) {
1257              pt[pts].x = (nd->lon - clon) / perpixel + clip.width / 2;
1258              pt[pts++].y = clip.height / 2 - (nd->lat - clat) / perpixel;
1259            }
1260          }
1261          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][0]);
1262          gdk_draw_polygon (draw->window, mygc, TRUE, pt, pts);
1263          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][1]);
1264          gdk_gc_set_line_attributes (mygc, Style (w)->lineWidth,
1265            Style (w)->dashed ? GDK_LINE_ON_OFF_DASH
1266            : GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
1267          gdk_draw_polygon (draw->window, mygc, FALSE, pt, pts);
1268          #endif
1269        }
1270        else if (nd->other[1] >= 0) {
1271          #ifndef _WIN32_WCE
1272          gdk_gc_set_foreground (mygc, &styleColour[Style (w) - style][1]);
1273          gdk_gc_set_line_attributes (mygc, Style (w)->lineWidth,
1274            Style (w)->dashed ? GDK_LINE_ON_OFF_DASH
1275            : GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
1276          #else
1277          SelectObject (mygc, pen[StyleNr (w) + 1]);
1278          #endif
1279          do {
1280            ndType *next = ndBase + nd->other[1];
1281            if (next->lat == INT_MIN) break; // Node excluded from build
1282            gdk_draw_line (draw->window, mygc,
1283              (nd->lon - clon) / perpixel + clip.width / 2,
1284              clip.height / 2 - (nd->lat - clat) / perpixel,
1285              (next->lon - clon) / perpixel + clip.width / 2,
1286              clip.height / 2 - (next->lat - clat) / perpixel);
1287            #ifdef _WIN32_WCE
1288            int newb = nd->lon > next->lon
1289              ? nd->lon - next->lon : next->lon - nd->lon;
1290            if (newb < nd->lat - next->lat) newb = nd->lat - next->lat;
1291            if (newb < next->lat - nd->lat) newb = next->lat - nd->lat;
1292            if (best < newb) {
1293              best = newb;
1294              bestW = (next->lon > nd->lon ? -1 : 1) * (next->lon - nd->lon);
1295              bestH = (next->lon > nd->lon ? -1 : 1) * (next->lat - nd->lat);
1296              x0 = next->lon / 2 + nd->lon / 2;
1297              y0 = next->lat / 2 + nd->lat / 2;
1298            }
1299            #endif
1300            #ifdef CAIRO_VERSION
1301            __int64 lenSqr = (nd->lon - next->lon) * (__int64)(nd->lon - next->lon) +
1302                               (nd->lat - next->lat) * (__int64)(nd->lat - next->lat);
1303            if (lenSqr > maxLenSqr) {
1304              maxLenSqr = lenSqr;
1305              mat.yy = mat.xx = 12 * fabs (nd->lon - next->lon) / sqrt (lenSqr);
1306              mat.xy = (nd->lon > next->lon ? 12.0 : -12.0) *
1307                                          (nd->lat - next->lat) / sqrt (lenSqr);
1308              mat.yx = -mat.xy;
1309              x0 = clip.width / 2 + (nd->lon / 2 + next->lon / 2 - clon) /
1310                perpixel + mat.yx * f->descent / 12.0 - mat.xx / 12.0 * 3 * len;
1311              y0 = clip.height / 2 - (nd->lat / 2 + next->lat / 2 - clat) /
1312                perpixel - mat.xx * f->descent / 12.0 - mat.yx / 12.0 * 3 * len;
1313            }
1314            #endif
1315            nd = next;
1316          } while (itr.left <= nd->lon && nd->lon < itr.right &&
1317                   itr.top  <= nd->lat && nd->lat < itr.bottom &&
1318                   nd->other[1] >= 0);
1319        } /* If it has one or more segments */
1320
1321        #ifdef _WIN32_WCE
1322        if (best > perpixel * len * 4) {
1323          double hoek = atan2 (bestH, bestW);
1324          logFont.lfEscapement = logFont.lfOrientation =
1325            1800 + int ((1800 / M_PI) * hoek);
1326         
1327          HFONT customFont = CreateFontIndirect (&logFont);
1328          HGDIOBJ oldf = SelectObject (mygc, customFont);
1329          MultiByteToWideChar (AnsiCodePage ? CP_ACP : CP_UTF8, 0, (char *)(w + 1) + 1,
1330            len, wcTmp, sizeof (wcTmp));
1331          ExtTextOut (mygc, (x0 - clon) / perpixel + clip.width / 2 +
1332                int (len * 3 * cos (hoek)),
1333                clip.height / 2 - (y0 - clat) / perpixel -
1334                int (len * 3 * sin (hoek)), 0, NULL,
1335                wcTmp, len, NULL);
1336          SelectObject (mygc, customFont);
1337          DeleteObject (customFont);
1338        }
1339        #endif
1340        #ifdef CAIRO_VERSION
1341        if (maxLenSqr * detail > perpixel * (__int64) perpixel *
1342            len * len * 100 && len > 0) {
1343          for (char *txt = (char *)(w + 1) + 1; *txt != '\0';) {
1344            cairo_set_font_matrix (cai, &mat);
1345            char *line = (char *) malloc (strcspn (txt, "\n") + 1);
1346            memcpy (line, txt, strcspn (txt, "\n"));
1347            line[strcspn (txt, "\n")] = '\0';
1348            cairo_move_to (cai, x0, y0);
1349            cairo_show_text (cai, line);
1350            free (line);
1351            if (perpixel > 10) break;
1352            y0 += mat.xx * (f->ascent + f->descent) / 12;
1353            x0 += mat.xy * (f->ascent + f->descent) / 12;
1354            while (*txt != '\0' && *txt++ != '\n') {}
1355          }
1356        }
1357        #endif
1358      } /* for each visible tile */
1359    }
1360  //  gdk_gc_set_foreground (draw->style->fg_gc[0], &highwayColour[rail]);
1361  //  gdk_gc_set_line_attributes (draw->style->fg_gc[0],
1362  //    1, GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
1363    routeNodeType *x;
1364    if (shortest && (x = shortest->shortest)) {
1365      #ifndef _WIN32_WCE
1366      gdk_gc_set_foreground (mygc, &routeColour);
1367      gdk_gc_set_line_attributes (mygc, 5,
1368        GDK_LINE_SOLID, GDK_CAP_PROJECTING, GDK_JOIN_MITER);
1369      #else
1370      SelectObject (mygc, pen[0]);
1371      #endif
1372      if (routeHeapSize > 1) {
1373        gdk_draw_line (draw->window, mygc,
1374          (flon - clon) / perpixel + clip.width / 2,
1375          clip.height / 2 - (flat - clat) / perpixel,
1376          (x->nd->lon - clon) / perpixel + clip.width / 2,
1377          clip.height / 2 - (x->nd->lat - clat) / perpixel);
1378      }
1379      for (; x->shortest; x = x->shortest) {
1380        gdk_draw_line (draw->window, mygc,
1381          (x->nd->lon - clon) / perpixel + clip.width / 2,
1382          clip.height / 2 - (x->nd->lat - clat) / perpixel,
1383          (x->shortest->nd->lon - clon) / perpixel + clip.width / 2,
1384          clip.height / 2 - (x->shortest->nd->lat - clat) / perpixel);
1385      }
1386      gdk_draw_line (draw->window, mygc,
1387        (x->nd->lon - clon) / perpixel + clip.width / 2,
1388        clip.height / 2 - (x->nd->lat - clat) / perpixel,
1389        (tlon - clon) / perpixel + clip.width / 2,
1390        clip.height / 2 - (tlat - clat) / perpixel);
1391    }
1392  } // Not in the menu
1393  else {
1394    wchar_t optStr[30];
1395    if (option == VehicleNum) {
1396      #define M(v) Vehicle == v ## R ? TEXT (#v) :
1397      wsprintf (optStr, TEXT ("%s : %s"), optionNameTable[option][English],
1398        RESTRICTIONS NULL);
1399      #undef M
1400    }
1401    else wsprintf (optStr, TEXT ("%s : %d"), optionNameTable[option][English],
1402    #define o(en,de,es,fr,it,nl,min,max) option == en ## Num ? en :
1403    OPTIONS
1404    #undef o
1405      0);
1406    #ifndef _WIN32_WCE
1407    cairo_move_to (cai, 50, draw->allocation.height / 2);
1408    cairo_show_text (cai, optStr);
1409    #else
1410    SelectObject (mygc, sysFont);
1411//    MultiByteToWideChar (CP_UTF8, 0 /* MB_ERR_INVALID_CHARS*/, optStr,
1412//       strlen (optStr), wcTmp, sizeof (wcTmp));
1413    ExtTextOut (mygc, 50, draw->allocation.height / 2, 0, NULL,
1414       optStr, wcslen (optStr), NULL); 
1415    #endif
1416  }
1417  #ifndef _WIN32_WCE
1418  gdk_draw_rectangle (draw->window, draw->style->bg_gc[0], TRUE,
1419    clip.width - ButtonSize * 20, clip.height - ButtonSize * 60,
1420    clip.width, clip.height);
1421  for (int i = 0; i < 3; i++) {
1422    gdk_draw_string (draw->window, f, draw->style->fg_gc[0],
1423      clip.width - ButtonSize * 10 - 5, clip.height + (f->ascent - f->descent)
1424      / 2 - ButtonSize * (20 * i + 10), i == 0 ? "O" : i == 1 ? "-" : "+");
1425  }
1426  #else
1427  int i = (HideZoomButtons && option == numberOfOptions ? 1 : 3);
1428  RECT r;
1429  r.left = clip.width - ButtonSize * 20;
1430  r.top = clip.height - ButtonSize * 20 * i;
1431  r.right = clip.width;
1432  r.bottom = clip.height;
1433  FillRect (mygc, &r, (HBRUSH) GetStockObject(LTGRAY_BRUSH));
1434  SelectObject (mygc, sysFont);
1435  while (--i >= 0) {
1436    ExtTextOut (mygc, clip.width - ButtonSize * 10 - 5, clip.height - 5 -
1437        ButtonSize * (20 * i + 10), 0, NULL, i == 0 ? TEXT ("O") :
1438        i == 1 ? TEXT ("-") : TEXT ("+"), 1, NULL);
1439  }
1440
1441  wchar_t coord[21];
1442  if (ShowCoordinates) {
1443    wsprintf (coord, TEXT ("%9.5lf %10.5lf"), LatInverse (clat),
1444      LonInverse (clon));
1445    ExtTextOut (mygc, 0, clip.height - 15, 0, NULL, coord, 20, NULL);
1446  }
1447  #endif
1448  #ifdef CAIRO_VERSION
1449  cairo_destroy (cai);
1450  #endif
1451/*
1452  clip.height = draw->allocation.height;
1453  gdk_gc_set_clip_rectangle (draw->style->fg_gc[0], &clip);
1454  gdk_draw_string (draw->window, f, draw->style->fg_gc[0],
1455    clip.width/2, clip.height - f->descent, "gosmore");
1456  */
1457  return FALSE;
1458}
1459
1460GtkWidget *searchW;
1461GtkWidget *list;
1462#define numIncWays 40
1463wayType *incrementalWay[numIncWays];
1464
1465int IdxSearch (int *idx, int h, char *key, unsigned z)
1466{
1467  for (int l = 0; l < h;) {
1468    char *tag = data + idx[(h + l) / 2];
1469    int diff = TagCmp (tag, key);
1470    while (*--tag) {}
1471    if (diff > 0 || (diff == 0 &&
1472      ZEnc ((unsigned)((wayType *)tag)[-1].clat >> 16, 
1473            (unsigned)((wayType *)tag)[-1].clon >> 16) >= z)) h = (h + l) / 2;
1474    else l = (h + l) / 2 + 1;
1475  }
1476  return h;
1477}
1478
1479/* 1. Bsearch idx such that
1480      ZEnc (way[idx]) < ZEnc (clon/lat) < ZEnc (way[idx+1])
1481   2. Fill the list with ways around idx.
1482   3. Now there's a circle with clon/clat as its centre and that runs through
1483      the worst way just found. Let's say it's diameter is d. There exist
1484      4 Z squares smaller that 2d by 2d that cover this circle. Find them
1485      with binary search and search through them for the nearest ways.
1486   The worst case is when the nearest nodes are far along a relatively
1487   straight line.
1488*/
1489int IncrementalSearch (void)
1490{
1491  __int64 dista[numIncWays];
1492  char *taga[numIncWays];
1493  char *key = (char *) gtk_entry_get_text (GTK_ENTRY (searchW));
1494  int *idx =
1495    (int *)(ndBase + hashTable[bucketsMin1 + (bucketsMin1 >> 7) + 2]);
1496  int l = IdxSearch (idx, hashTable - idx, key, 0), count;
1497//  char *lastName = data + idx[min (hashTable - idx),
1498//    int (sizeof (incrementalWay) / sizeof (incrementalWay[0]))) + l - 1];
1499  int cz = ZEnc ((unsigned) clat >> 16, (unsigned) clon >> 16);
1500  for (count = 0; count + l < hashTable - idx && count < numIncWays;) {
1501    int m[2], c = count, ipos, dir, bits;
1502    m[0] = IdxSearch (idx, hashTable - idx, data + idx[count + l], cz);
1503    m[1] = m[0] - 1;
1504    __int64 distm[2] = { -1, -1 }, big = ((unsigned __int64) 1 << 63) - 1;
1505    while (c < numIncWays && (distm[0] < big || distm[1] < big)) {
1506      dir = distm[0] < distm[1] ? 0 : 1;
1507      if (distm[dir] != -1) {
1508        for (ipos = c; count < ipos && distm[dir] < dista[ipos - 1]; ipos--) {
1509          dista[ipos] = dista[ipos - 1];
1510          incrementalWay[ipos] = incrementalWay[ipos - 1];
1511          taga[ipos] = taga[ipos - 1];
1512        }
1513        char *tag = data + idx[m[dir]];
1514        taga[ipos] = tag;
1515        while (*--tag) {}
1516        incrementalWay[ipos] = (wayType*)tag - 1;
1517        dista[ipos] = distm[dir];
1518        c++;
1519      }
1520      m[dir] += dir ? 1 : -1;
1521
1522      if (0 <= m[dir] && m[dir] < hashTable - idx &&
1523        TagCmp (data + idx[m[dir]], data + idx[count + l]) == 0) {
1524        char *tag = data + idx[m[dir]];
1525        while (*--tag) {}
1526        distm[dir] = Sqr ((__int64)(clon - ((wayType*)tag)[-1].clon)) +
1527          Sqr ((__int64)(clat - ((wayType*)tag)[-1].clat));
1528      }
1529      else distm[dir] = big;
1530    }
1531    if (c >= numIncWays) {
1532      c = count; // Redo the adding
1533      for (bits = 0; bits < 16 && dista[numIncWays - 1] >> (bits * 2 + 32);
1534        bits++) {}
1535/* Print Z's for first solution
1536      for (int j = c; j < numIncWays; j++) {
1537        for (int i = 0; i < 32; i++) printf ("%d%s",
1538          (ZEnc ((unsigned) incrementalWay[j]->clat >> 16,
1539                 (unsigned) incrementalWay[j]->clon >> 16) >> (31 - i)) & 1,
1540          i == 31 ? " x\n" : i % 2 ? " " : "");
1541      } */
1542/* Print centre, up, down, right and left to see if they're in the square
1543      for (int i = 0; i < 32; i++) printf ("%d%s", (cz >> (31 - i)) & 1,
1544        i == 31 ? " x\n" : i % 2 ? " " : "");
1545      for (int i = 0; i < 32; i++) printf ("%d%s", (
1546        ZEnc ((unsigned)(clat + (int) sqrt (dista[numIncWays - 1])) >> 16,
1547              (unsigned)clon >> 16) >> (31 - i)) & 1,
1548        i == 31 ? " x\n" : i % 2 ? " " : "");
1549      for (int i = 0; i < 32; i++) printf ("%d%s", (
1550        ZEnc ((unsigned)(clat - (int) sqrt (dista[numIncWays - 1])) >> 16,
1551              (unsigned)clon >> 16) >> (31 - i)) & 1,
1552        i == 31 ? " x\n" : i % 2 ? " " : "");
1553      for (int i = 0; i < 32; i++) printf ("%d%s", (
1554        ZEnc ((unsigned)clat >> 16,
1555              (unsigned)(clon + (int) sqrt (dista[numIncWays - 1])) >> 16) >> (31 - i)) & 1,
1556        i == 31 ? " x\n" : i % 2 ? " " : "");
1557      for (int i = 0; i < 32; i++) printf ("%d%s", (
1558        ZEnc ((unsigned)clat >> 16,
1559              (unsigned)(clon - (int) sqrt (dista[numIncWays - 1])) >> 16) >> (31 - i)) & 1,
1560        i == 31 ? " x\n" : i % 2 ? " " : "");
1561*/     
1562      int swap = cz ^ ZEnc (
1563        (unsigned) (clat + (clat & (1 << (bits + 16))) * 4 -
1564                                              (2 << (bits + 16))) >> 16,
1565        (unsigned) (clon + (clon & (1 << (bits + 16))) * 4 -
1566                                              (2 << (bits + 16))) >> 16);
1567      // Now we search through the 4 squares around (clat, clon)
1568      for (int mask = 0; (mask & 7) != 4; mask += 0x55555555) {
1569        int s = IdxSearch (idx, hashTable - idx, data + idx[count + l],
1570          (cz ^ (mask & swap)) & ~((4 << (bits << 1)) - 1));
1571/* Print the square
1572        for (int i = 0; i < 32; i++) printf ("%d%s",
1573          (((cz ^ (mask & swap)) & ~((4 << (bits << 1)) - 1)) >> (31 - i)) & 1,
1574          i == 31 ? "\n" : i % 2 ? " " : "");
1575        for (int i = 0; i < 32; i++) printf ("%d%s",
1576          (((cz ^ (mask & swap)) | ((4 << (bits << 1)) - 1)) >> (31 - i)) & 1,
1577          i == 31 ? "\n" : i % 2 ? " " : "");
1578*/
1579        for (;;) {
1580          char *tag = data + idx[s++];
1581          if (TagCmp (data + idx[count + l], tag) != 0) break;
1582          while (*--tag) {}
1583          wayType *w = (wayType*)tag - 1;
1584          if ((ZEnc ((unsigned)w->clat >> 16, (unsigned) w->clon >> 16) ^
1585               cz ^ (mask & swap)) >> (2 + (bits << 1))) break;
1586          __int64 d = Sqr ((__int64)(w->clat - clat)) +
1587                      Sqr ((__int64)(w->clon - clon));
1588          if (count == c || d < dista[c - 1]) {
1589            if (c < numIncWays) c++;
1590            for (ipos = c - 1; ipos > count && d < dista[ipos - 1]; ipos--) {
1591              dista[ipos] = dista[ipos - 1];
1592              incrementalWay[ipos] = incrementalWay[ipos - 1];
1593              taga[ipos] = taga[ipos - 1];
1594            }
1595            incrementalWay[ipos] = w;
1596            dista[ipos] = d;
1597            taga[ipos] = data + idx[s - 1];
1598          }
1599        } // For each entry in the square
1600      } // For each of the 4 squares
1601    } // If the search list is filled by tags with this text
1602    count = c;
1603  } // For each
1604  gtk_clist_freeze (GTK_CLIST (list));
1605  gtk_clist_clear (GTK_CLIST (list));
1606  for (int i = 0; i < count; i++) {
1607    char *m = (char *) malloc (strcspn (taga[i], "\n") + 1);
1608    sprintf (m, "%.*s", strcspn (taga[i], "\n"), taga[i]);
1609    gtk_clist_append (GTK_CLIST (list), &m);
1610    free (m);
1611  }
1612  gtk_clist_thaw (GTK_CLIST (list));
1613  return FALSE;
1614}
1615
1616void SelectName (GtkWidget * /*w*/, int row, int /*column*/,
1617  GdkEventButton * /*ev*/, void * /*data*/)
1618{
1619  SetLocation (incrementalWay[row]->clon, incrementalWay[row]->clat);
1620  zoom = incrementalWay[row]->dlat + incrementalWay[row]->dlon + (1 << 15);
1621  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (followGPSr), FALSE);
1622  FollowGPSr = FALSE;
1623  gtk_widget_queue_clear (draw);
1624}
1625
1626void InitializeOptions (void)
1627{
1628  char *tag = data +
1629    *(int *)(ndBase + hashTable[bucketsMin1 + (bucketsMin1 >> 7) + 2]);
1630  while (*--tag) {}
1631  SetLocation (((wayType*)tag)[-1].clon, ((wayType*)tag)[-1].clat);
1632  zoom = ((wayType*)tag)[-1].dlat + ((wayType*)tag)[-1].dlon + (1 << 15);
1633}
1634
1635#endif // HEADLESS
1636
1637#ifndef _WIN32_WCE
1638int UserInterface (int argc, char *argv[])
1639{
1640  #if defined (__linux__)
1641  FILE *gmap = fopen64 ("gosmore.pak", "r");
1642  #else
1643  GMappedFile *gmap = g_mapped_file_new ("gosmore.pak", FALSE, NULL);
1644  #endif
1645  if (gmap) {
1646    #ifdef __linux__
1647    int ndCount[3];
1648    fseek (gmap, -sizeof (ndCount), SEEK_END);
1649    fread (ndCount, sizeof (ndCount), 1, gmap);
1650    long pakSize = ftello64 (gmap);
1651    data = (char *) mmap (NULL, ndCount[2],
1652                   PROT_READ, MAP_SHARED, fileno (gmap), 0);
1653
1654    ndBase = (ndType *) ((char *)mmap (NULL, pakSize - (ndCount[2] & ~0xfff),
1655    //ndCount[0] * sizeof (*ndBase),
1656         PROT_READ, MAP_SHARED, fileno (gmap), ndCount[2] & ~0xfff) +
1657       (ndCount[2] & 0xfff));
1658    bucketsMin1 = ndCount[1];
1659    hashTable = (int *)((char *)ndBase + pakSize - ndCount[2]) - bucketsMin1
1660      - (bucketsMin1 >> 7) - 5;
1661    #else
1662    data = (char*) g_mapped_file_get_contents (gmap);
1663    bucketsMin1 = ((int *) (data + g_mapped_file_get_length (gmap)))[-2];
1664    hashTable = (int *) (data + g_mapped_file_get_length (gmap)) -
1665      bucketsMin1 - (bucketsMin1 >> 7) - 5;
1666    ndBase = (ndType *)(data + hashTable[bucketsMin1 + (bucketsMin1 >> 7) + 4]);
1667    #endif
1668  }
1669  if (!gmap || !data || !ndBase || !hashTable || *(int*) data != pakHead) {
1670    fprintf (stderr, "Cannot read gosmore.pak\nYou can (re)build it from\n"
1671      "the planet file e.g. bzip2 -d planet-...osm.bz2 | %s rebuild\n",
1672      argv[0]);
1673    #ifndef HEADLESS
1674    gtk_init (&argc, &argv);
1675    gtk_dialog_run (GTK_DIALOG (gtk_message_dialog_new (NULL,
1676      GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1677      "Cannot read gosmore.pak\nYou can (re)build it from\n"
1678      "the planet file e.g. bzip2 -d planet-...osm.bz2 | %s rebuild\n",
1679      argv[0])));
1680    #endif
1681    return 8;
1682  }
1683  style = (struct styleStruct *)(data + 4);
1684
1685  if (getenv ("QUERY_STRING")) {
1686    double x0, y0, x1, y1;
1687    char vehicle[20];
1688    sscanf (getenv ("QUERY_STRING"),
1689      "flat=%lf&flon=%lf&tlat=%lf&tlon=%lf&fast=%d&v=%19[a-z]",
1690      &y0, &x0, &y1, &x1, &FastestRoute, vehicle);
1691    flat = Latitude (y0);
1692    flon = Longitude (x0);
1693    tlat = Latitude (y1);
1694    tlon = Longitude (x1);
1695    #define M(v) if (strcmp (vehicle, #v) == 0) Vehicle = v ## R;
1696    RESTRICTIONS
1697    #undef M
1698    Route (TRUE);
1699    printf ("Content-Type: text/plain\n\r\n\r");
1700    if (!shortest) printf ("No route found\n\r");
1701    else if (routeHeapSize <= 1) printf ("Jump\n\r");
1702    for (; shortest; shortest = shortest->shortest) {
1703      printf ("%lf,%lf\n\r", LatInverse (shortest->nd->lat),
1704        LonInverse (shortest->nd->lon));
1705    }
1706    return 0;
1707  }
1708
1709  printf ("%s is in the public domain and comes without warrantee\n",argv[0]);
1710  #ifndef HEADLESS
1711 
1712  gtk_init (&argc, &argv);
1713  draw = gtk_drawing_area_new ();
1714  gtk_signal_connect (GTK_OBJECT (draw), "expose_event",
1715    (GtkSignalFunc) Expose, NULL);
1716  gtk_signal_connect (GTK_OBJECT (draw), "button_press_event",
1717    (GtkSignalFunc) Click, NULL);
1718  gtk_widget_set_events (draw, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
1719    GDK_POINTER_MOTION_MASK);
1720  gtk_signal_connect (GTK_OBJECT (draw), "scroll_event",
1721                       (GtkSignalFunc) Scroll, NULL);
1722 
1723  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1724  GtkWidget *hbox = gtk_hbox_new (FALSE, 5), *vbox = gtk_vbox_new (FALSE, 0);
1725  gtk_container_add (GTK_CONTAINER (window), hbox);
1726  gtk_box_pack_start (GTK_BOX (hbox), draw, TRUE, TRUE, 0);
1727  gtk_box_pack_end (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
1728
1729  searchW = gtk_entry_new ();
1730  gtk_box_pack_start (GTK_BOX (vbox), searchW, FALSE, FALSE, 5);
1731  gtk_entry_set_text (GTK_ENTRY (searchW), "Search");
1732  gtk_signal_connect (GTK_OBJECT (searchW), "changed",
1733    GTK_SIGNAL_FUNC (IncrementalSearch), NULL);
1734 
1735  list = gtk_clist_new (1);
1736  gtk_clist_set_selection_mode (GTK_CLIST (list), GTK_SELECTION_SINGLE);
1737  gtk_box_pack_start (GTK_BOX (vbox), list, TRUE, TRUE, 5);
1738  gtk_signal_connect (GTK_OBJECT (list), "select_row",
1739    GTK_SIGNAL_FUNC (SelectName), NULL);
1740   
1741  carBtn = GTK_COMBO_BOX (gtk_combo_box_new_text ());
1742  #define M(x) if (motorcarR <= x ## R && x ## R < onewayR) \
1743                             gtk_combo_box_append_text (carBtn, #x);
1744  RESTRICTIONS
1745  #undef M
1746  gtk_combo_box_set_active (carBtn, 0);
1747  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (carBtn), FALSE, FALSE, 5);
1748  gtk_signal_connect (GTK_OBJECT (carBtn), "changed",
1749    GTK_SIGNAL_FUNC (ChangeOption), NULL);
1750
1751  fastestBtn = GTK_COMBO_BOX (gtk_combo_box_new_text ());
1752  gtk_combo_box_append_text (fastestBtn, "fastest");
1753  gtk_combo_box_append_text (fastestBtn, "shortest");
1754  gtk_combo_box_set_active (fastestBtn, 0);
1755  gtk_box_pack_start (GTK_BOX (vbox),
1756    GTK_WIDGET (fastestBtn), FALSE, FALSE, 5);
1757  gtk_signal_connect (GTK_OBJECT (fastestBtn), "changed",
1758    GTK_SIGNAL_FUNC (ChangeOption), NULL);
1759
1760  detailBtn = GTK_COMBO_BOX (gtk_combo_box_new_text ());
1761  gtk_combo_box_append_text (detailBtn, "Highest");
1762  gtk_combo_box_append_text (detailBtn, "High");
1763  gtk_combo_box_append_text (detailBtn, "Normal");
1764  gtk_combo_box_append_text (detailBtn, "Low");
1765  gtk_combo_box_append_text (detailBtn, "Lowest");
1766  gtk_combo_box_set_active (detailBtn, 2);
1767  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (detailBtn), FALSE, FALSE,5);
1768  gtk_signal_connect (GTK_OBJECT (detailBtn), "changed",
1769    GTK_SIGNAL_FUNC (ChangeOption), NULL);
1770
1771  iconSet = GTK_COMBO_BOX (gtk_combo_box_new_text ());
1772  gtk_combo_box_append_text (iconSet, "Classic.Big");
1773  gtk_combo_box_append_text (iconSet, "Classic.Small                       ");
1774  gtk_combo_box_append_text (iconSet, "Square.Big");
1775  gtk_combo_box_append_text (iconSet, "Square.Small");
1776  gtk_combo_box_set_active (iconSet, 1);
1777  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (iconSet), FALSE, FALSE, 5);
1778  gtk_signal_connect (GTK_OBJECT (iconSet), "changed",
1779    GTK_SIGNAL_FUNC (ChangeOption), NULL);
1780
1781  GtkWidget *getDirs = gtk_button_new_with_label ("Get Directions");
1782/*  gtk_box_pack_start (GTK_BOX (vbox), getDirs, FALSE, FALSE, 5);
1783  gtk_signal_connect (GTK_OBJECT (getDirs), "clicked",
1784    GTK_SIGNAL_FUNC (GetDirections), NULL);
1785*/
1786  location = gtk_entry_new ();
1787  gtk_box_pack_start (GTK_BOX (vbox), location, FALSE, FALSE, 5);
1788  gtk_signal_connect (GTK_OBJECT (location), "changed",
1789    GTK_SIGNAL_FUNC (ChangeLocation), NULL);
1790 
1791  followGPSr = gtk_check_button_new_with_label ("Follow GPSr");
1792 
1793  #ifndef WIN32 
1794  struct sockaddr_in sa;
1795  int gpsSock = socket (PF_INET, SOCK_STREAM, 0);
1796  sa.sin_family = AF_INET;
1797  sa.sin_port = htons (2947);
1798  sa.sin_addr.s_addr = htonl (0x7f000001); //(204<<24)|(17<<16)|(205<<8)|18);
1799  if (gpsSock != -1 &&
1800      connect (gpsSock, (struct sockaddr *)&sa, sizeof (sa)) == 0) {
1801    send (gpsSock, "R\n", 2, 0);
1802    gpsSockTag = gdk_input_add (/*gpsData->gps_fd*/ gpsSock, GDK_INPUT_READ,
1803      (GdkInputFunction) ReceiveNmea /*gps_poll*/, NULL);
1804
1805    gtk_box_pack_start (GTK_BOX (vbox), followGPSr, FALSE, FALSE, 5);
1806    gtk_signal_connect (GTK_OBJECT (followGPSr), "clicked",
1807      GTK_SIGNAL_FUNC (ChangeOption), NULL);
1808    gtk_widget_show (followGPSr);
1809  }
1810  #endif
1811
1812  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1813    GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
1814 
1815  gtk_widget_set_usize (window, 750, 550);
1816  gtk_widget_show (searchW);
1817  gtk_widget_show (list);
1818  gtk_widget_show (location);
1819  gtk_widget_show (draw);
1820  gtk_widget_show (GTK_WIDGET (carBtn));
1821  gtk_widget_show (GTK_WIDGET (fastestBtn));
1822  gtk_widget_show (GTK_WIDGET (detailBtn));
1823  gtk_widget_show (GTK_WIDGET (iconSet));
1824/*  gtk_widget_show (getDirs); */
1825  gtk_widget_show (hbox);
1826  gtk_widget_show (vbox);
1827  gtk_widget_show (window);
1828  option = numberOfOptions;
1829  ChangeOption ();
1830  IncrementalSearch ();
1831  InitializeOptions ();
1832  gtk_main ();
1833  FlushGpx ();
1834 
1835  #endif // HEADLESS
1836  return 0;
1837}
1838#endif // !_WIN32_WCE
1839
1840/*--------------------------------- Rebuid code ---------------------------*/
1841#ifndef _WIN32_WCE
1842// These defines are only used during rebuild
1843#define MAX_BUCKETS (1<<26)
1844#define IDXGROUPS 676
1845#define NGROUPS 30
1846#define NGROUP(x)  ((x) / 9000000 % NGROUPS + IDXGROUPS)
1847#define S1GROUPS NGROUPS
1848#define S1GROUP(x) ((x) / 9000000 % NGROUPS + IDXGROUPS + NGROUPS)
1849#define S2GROUPS 33 // Last group is reserved for lowzoom halfSegs
1850#define S2GROUP(x) ((x) / (MAX_BUCKETS / (S2GROUPS - 1)) + IDXGROUPS + NGROUPS * 2)
1851#define PAIRS (16 * 1024 * 1024)
1852#define PAIRGROUPS 100
1853#define PAIRGROUP(x) ((x) / PAIRS + S2GROUP (0) + S2GROUPS)
1854#define PAIRGROUPS2 100
1855#define PAIRGROUP2(x) ((x) / PAIRS + PAIRGROUP (0) + PAIRGROUPS)
1856#define MAX_NODES 9000000 /* Max in a group */
1857#define FIRST_LOWZ_OTHER (PAIRS * (PAIRGROUPS - 1))
1858
1859#define REBUILDWATCH(x) fprintf (stderr, "%3d %s\n", ++rebuildCnt, #x); x
1860
1861#define TO_HALFSEG -1 // Rebuild only
1862
1863struct halfSegType { // Rebuild only
1864  int lon, lat, other, wayPtr;
1865};
1866
1867struct nodeType {
1868  int id, lon, lat;
1869};
1870
1871inline nodeType *FindNode (nodeType *table, int id)
1872{
1873  unsigned hash = id;
1874  for (;;) {
1875    nodeType *n = &table[hash % MAX_NODES];
1876    if (n->id < 0 || n->id == id) return n;
1877    hash = hash * (__int64) 1664525 + 1013904223;
1878  }
1879}
1880
1881int HalfSegCmp (const halfSegType *a, const halfSegType *b)
1882{
1883  int lowz = a->other < -2 || FIRST_LOWZ_OTHER <= a->other;
1884  int hasha = Hash (a->lon, a->lat, lowz), hashb = Hash (b->lon, b->lat, lowz);
1885  return hasha != hashb ? hasha - hashb : a->lon != b->lon ? a->lon - b->lon :
1886    a->lat - b->lat;
1887}
1888
1889int IdxCmp (const void *aptr, const void *bptr)
1890{
1891  char *ta = data + *(unsigned *)aptr, *tb = data + *(unsigned *)bptr;
1892  int tag = TagCmp (ta, tb);
1893  while (*--ta) {}
1894  while (*--tb) {}
1895  unsigned a = ZEnc ((unsigned)((wayType *)ta)[-1].clat >> 16, 
1896                     (unsigned)((wayType *)ta)[-1].clon >> 16);
1897  unsigned b = ZEnc ((unsigned)((wayType *)tb)[-1].clat >> 16, 
1898                     (unsigned)((wayType *)tb)[-1].clon >> 16);
1899  return tag ? tag : a < b ? -1 : 1;
1900}
1901
1902/* To reduce the number of cache misses and disk seeks we need to construct
1903 the pack file so that waysTypes that are physically close to each other, are
1904 also close to each other in the file. We only know where ways are physically
1905 after the first pass, so the reordering is one done during a bbox rebuild.
1906 
1907 Finding an optimal solution is quite similar to find a soluting to the
1908 traveling salesman problem. Instead we just place them in 2-D Hilbert curve
1909 order using a qsort. */
1910typedef struct {
1911  wayType *w;
1912  int idx;
1913} masterWayType;
1914
1915int MasterWayCmp (const void *a, const void *b)
1916{
1917  int r[2], t, s, i, lead;
1918  for (i = 0; i < 2; i++) {
1919    t = ZEnc (((masterWayType *)(i ? b : a))->w->clon >> 16,
1920      ((unsigned)((masterWayType *)(i ? b : a))->w->clat) >> 16);
1921    s = ((((unsigned)t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1)) ^ ~t;
1922    for (lead = 1 << 30; lead; lead >>= 2) {
1923      if (!(t & lead)) t ^= ((t & (lead << 1)) ? s : ~s) & (lead - 1);
1924    }
1925    r[i] = ((t & 0xaaaaaaaa) >> 1) ^ t;
1926  }
1927  return r[0] < r[1] ? 1 : r[0] > r[1] ? -1 : 0;
1928}
1929
1930int main (int argc, char *argv[])
1931{
1932  assert (l3 < 32);
1933  #ifndef WIN32
1934  int rebuildCnt = 0;
1935  if (argc > 1) {
1936    if ((argc != 6 && argc > 2) || stricmp (argv[1], "rebuild")) {
1937      fprintf (stderr, "Usage : %s [rebuild [bbox for 2 pass]]\n"
1938      "See http://wiki.openstreetmap.org/index.php/gosmore\n", argv[0]);
1939      return 1;
1940    }
1941    FILE *pak, *masterf;
1942    int styleCnt = 0, ndStart;
1943    int bbox[4] = { INT_MIN, INT_MIN, 0x7fffffff, 0x7fffffff };
1944    wayType *master = /* shutup gcc */ NULL;
1945    if (argc == 6) {
1946      if (!(masterf = fopen64 ("master.pak", "r")) ||
1947          fseek (masterf, -sizeof (ndStart), SEEK_END) != 0 ||
1948          fread (&ndStart, sizeof (ndStart), 1, masterf) != 1 ||
1949          (long)(master = (wayType *)mmap (NULL, ndStart, PROT_READ,
1950                                MAP_SHARED, fileno (masterf), 0)) == -1) {
1951        fprintf (stderr, "Unable to open master.pak for bbox rebuild\n");
1952        return 4;
1953      }
1954      bbox[0] = Latitude (atof (argv[2]));
1955      bbox[1] = Longitude (atof (argv[3]));
1956      bbox[2] = Latitude (atof (argv[4]));
1957      bbox[3] = Longitude (atof (argv[5]));
1958    }
1959    if (!(pak = fopen64 ("gosmore.pak", "w+"))) {
1960      fprintf (stderr, "Cannot create gosmore.pak\n");
1961      return 2;
1962    }
1963    fwrite (&pakHead, sizeof (pakHead), 1, pak);
1964   
1965    //------------------------- elemstyle.xml : --------------------------
1966    char *style_k[2 << STYLE_BITS], *style_v[2 << STYLE_BITS];
1967    int defaultRestrict[2 << STYLE_BITS];
1968    memset (defaultRestrict, 0, sizeof (defaultRestrict));
1969    FILE *icons_csv = fopen ("icons.csv", "r");
1970    if (!icons_csv) icons_csv = fopen (FindResource ("icons.csv"), "r");
1971    xmlTextReaderPtr sXml = xmlNewTextReaderFilename (
1972      FindResource ("elemstyles.xml"));
1973    if (!sXml || !icons_csv) {
1974      fprintf (stderr, "Either icons.csv or elemstyles.xml not found\n");
1975      return 3;
1976    }
1977    styleStruct srec[2 << STYLE_BITS];
1978    memset (&srec, 0, sizeof (srec));
1979    while (xmlTextReaderRead (sXml)) {
1980      char *name = (char*) xmlTextReaderName (sXml);
1981      //xmlChar *val = xmlTextReaderValue (sXml);
1982      if (xmlTextReaderNodeType (sXml) == XML_READER_TYPE_ELEMENT) {
1983        if (strcasecmp (name, "scale_max") == 0) {
1984          while (xmlTextReaderRead (sXml) && // memory leak :
1985            xmlStrcmp (xmlTextReaderName (sXml), BAD_CAST "#text") != 0) {}
1986          srec[styleCnt].scaleMax = atoi ((char *) xmlTextReaderValue (sXml));
1987        }
1988        while (xmlTextReaderMoveToNextAttribute (sXml)) {
1989          char *n = (char *) xmlTextReaderName (sXml);
1990          char *v = (char *) xmlTextReaderValue (sXml);
1991          if (strcasecmp (name, "condition") == 0) {
1992            if (strcasecmp (n, "k") == 0) style_k[styleCnt] = strdup (v);
1993            if (strcasecmp (n, "v") == 0) style_v[styleCnt] = strdup (v);
1994          }                                     // memory leak -^
1995          if (strcasecmp (name, "line") == 0) {
1996            if (strcasecmp (n, "width") == 0) {
1997              srec[styleCnt].lineWidth = atoi (v);
1998            }
1999            if (strcasecmp (n, "realwidth") == 0) {
2000              srec[styleCnt].lineRWidth = atoi (v);
2001            }
2002            if (strcasecmp (n, "colour") == 0) {
2003              sscanf (v, "#%x", &srec[styleCnt].lineColour);
2004            }
2005            if (strcasecmp (n, "colour_bg") == 0) {
2006              sscanf (v, "#%x", &srec[styleCnt].lineColourBg);
2007            }
2008            srec[styleCnt].dashed = srec[styleCnt].dashed ||
2009              (strcasecmp (n, "dashed") == 0 && strcasecmp (v, "true") == 0);
2010          }
2011          if (strcasecmp (name, "area") == 0) {
2012            if (strcasecmp (n, "colour") == 0) {
2013              sscanf (v, "#%x", &srec[styleCnt].areaColour);
2014            }
2015          }
2016          if (strcasecmp (name, "icon") == 0) {
2017            if (strcasecmp (n, "src") == 0) {
2018              while (v[strcspn ((char *) v, "/ ")]) {
2019                v[strcspn ((char *) v, "/ ")] = '_';
2020              }
2021              char line[80];
2022              static char *set[] = { "classic.big_", "classic.small_",
2023                "square.big_", "square.small_" };
2024              for (int i = 0; i < 4; i++) {
2025                int slen = strlen (set[i]), vlen = strlen (v);
2026                rewind (icons_csv);
2027                while (fgets (line, sizeof (line) - 1, icons_csv)) {
2028                  if (strncmp (line, set[i], slen) == 0 &&
2029                      strncmp (line + slen, v, vlen - 1) == 0) {
2030                    sscanf (line + slen + vlen, ":%d:%d:%d:%d",
2031                      srec[styleCnt].x + i * 4, srec[styleCnt].x + i * 4 + 1,
2032                      srec[styleCnt].x + i * 4 + 2,
2033                      srec[styleCnt].x + i * 4 + 3);
2034                  }
2035                }
2036              }
2037            }
2038          }
2039          if (strcasecmp (name, "routing") == 0 && atoi (v) > 0) {
2040            #define M(field) if (strcasecmp (n, #field) == 0) {\
2041              defaultRestrict[styleCnt] |= 1 << field ## R; \
2042              srec[styleCnt].aveSpeed[field ## R] = atof (v); \
2043            }
2044            RESTRICTIONS
2045            #undef M
2046          }
2047         
2048          xmlFree (v);
2049          xmlFree (n);
2050        }
2051      }
2052      else if (xmlTextReaderNodeType (sXml) == XML_READER_TYPE_END_ELEMENT
2053                  && strcasecmp ((char *) name, "rule") == 0) {
2054        if (styleCnt < (2 << STYLE_BITS) - 1) styleCnt++;
2055        else fprintf (stderr, "Too many rules. Increase STYLE_BITS\n");
2056      }
2057      xmlFree (name);
2058      //xmlFree (val);     
2059    }
2060    for (int i = 0; i < l1; i++) {
2061      double max = 0;
2062      for (int j = 0; j < styleCnt; j++) {
2063        if (srec[j].aveSpeed[i] > max) max = srec[j].aveSpeed[i];
2064      }
2065      for (int j = 0; j < styleCnt; j++) {
2066        if (srec[j].aveSpeed[i] == 0) { // e.g. highway=foot motorcar=yes
2067          for (int k = 0; k < l1; k++) {
2068            if (srec[j].aveSpeed[i] < srec[j].aveSpeed[k]) {
2069              srec[j].aveSpeed[i] = srec[j].aveSpeed[k];
2070            } // As fast as any other vehicle,
2071          } // without breaking our own speed limit :
2072          if (srec[j].aveSpeed[i] > max) srec[j].aveSpeed[i] = max;
2073        }
2074        srec[j].invSpeed[i] = max / srec[j].aveSpeed[i];
2075      }
2076    }
2077    fwrite (&srec, sizeof (srec[0]), styleCnt + 1, pak);   
2078    xmlFreeTextReader (sXml);
2079
2080    //-------------------------- OSM Data File : ---------------------------
2081    xmlTextReaderPtr xml = xmlReaderForFd (STDIN_FILENO, "", NULL, 0);
2082//    xmlTextReaderPtr xml = xmlReaderForFile ("/dosc/osm/r28_2.osm", "", 0);
2083    FILE *groupf[PAIRGROUP2 (0) + PAIRGROUPS2];
2084    char groupName[PAIRGROUP2 (0) + PAIRGROUPS2][9];
2085    for (int i = 0; i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
2086      sprintf (groupName[i], "%c%c%d.tmp", i / 26 % 26 + 'a', i % 26 + 'a',
2087        i / 26 / 26);
2088      if (!(groupf[i] = fopen64 (groupName[i], "w+"))) {
2089        fprintf (stderr, "Cannot create temporary file.\nPossibly too many"
2090          " open files, in which case you must run ulimit -n or recompile\n");
2091        return 9;
2092      }
2093    }
2094   
2095    #if 0 // For making sure we have a Hilbert curve
2096    bucketsMin1 = MAX_BUCKETS - 1;
2097    for (int x = 0; x < 16; x++) {
2098      for (int y = 0; y < 16; y++) {
2099        printf ("%7d ", Hash (x << TILEBITS, y << TILEBITS));
2100      }
2101      printf ("\n");
2102    }
2103    #endif
2104   
2105    nodeType nd;
2106    halfSegType s[2];
2107    int nOther = 0, lowzOther = FIRST_LOWZ_OTHER, isNode = 0;
2108    int yesMask = 0, noMask = 0, *wayFseek = NULL;
2109    int lowzList[1000], lowzListCnt = 0;
2110    s[0].lat = 0; // Should be -1 ?
2111    s[0].other = -2;
2112    s[1].other = -1;
2113    wayType w;
2114    w.clat = 0;
2115    w.clon = 0;
2116    w.dlat = INT_MIN;
2117    w.dlon = INT_MIN;
2118    w.bits = styleCnt;
2119   
2120    if (argc >= 6) {
2121      masterWayType *masterWay = (masterWayType *) malloc (
2122        sizeof (*masterWay) * (ndStart / (sizeof (wayType) + 4)));
2123
2124      unsigned i = 0, offset = ftell (pak), wcnt;
2125      wayType *m = (wayType *)(((char *)master) + offset);
2126      for (wcnt = 0; (char*) m < (char*) master + ndStart; wcnt++) {
2127        if (bbox[0] <= m->clat + m->dlat && bbox[1] <= m->clon + m->dlon &&
2128            m->clat - m->dlat <= bbox[2] && m->clon - m->dlon <= bbox[3]) {
2129          masterWay[i].idx = wcnt;
2130          masterWay[i++].w = m;
2131        }
2132        m = (wayType*)((char*)m +
2133          ((1 + strlen ((char*)(m + 1) + 1) + 1 + 3) & ~3)) + 1;
2134      }
2135      qsort (masterWay, i, sizeof (*masterWay), MasterWayCmp);
2136      assert (wayFseek = (int*) calloc (sizeof (*wayFseek),
2137        ndStart / (sizeof (wayType) + 4)));
2138      for (unsigned j = 0; j < i; j++) {
2139        wayFseek[masterWay[j].idx] = offset;
2140        offset += sizeof (*masterWay[j].w) +
2141          ((1 + strlen ((char*)(masterWay[j].w + 1) + 1) + 1 + 3) & ~3);
2142      }
2143      wayFseek[wcnt] = offset;
2144      fflush (pak);
2145      ftruncate (fileno (pak), offset); // fflush first ?
2146      free (masterWay);
2147      fseek (pak, *wayFseek, SEEK_SET);
2148    }
2149   
2150    char *tag_k = NULL, *tags = (char *) BAD_CAST xmlStrdup (BAD_CAST "");
2151    REBUILDWATCH (while (xmlTextReaderRead (xml))) {
2152      char *name = (char *) BAD_CAST xmlTextReaderName (xml);
2153      //xmlChar *value = xmlTextReaderValue (xml); // always empty
2154      if (xmlTextReaderNodeType (xml) == XML_READER_TYPE_ELEMENT) {
2155        isNode = stricmp (name, "way") != 0 && 
2156                 (stricmp (name, "node") == 0 || isNode);
2157        while (xmlTextReaderMoveToNextAttribute (xml)) {
2158          char *aname = (char *) BAD_CAST xmlTextReaderName (xml);
2159          char *avalue = (char *) BAD_CAST xmlTextReaderValue (xml);
2160  //        if (xmlStrcasecmp (name, "node") == 0)
2161          if (stricmp (aname, "id") == 0) nd.id = atoi (avalue);
2162          if (stricmp (aname, "lat") == 0) nd.lat = Latitude (atof (avalue));
2163          if (stricmp (aname, "lon") == 0) nd.lon = Longitude (atof (avalue));
2164          if (stricmp (name, "nd") == 0 && stricmp (aname, "ref") == 0
2165              && (!wayFseek || *wayFseek)) {
2166            if (s[0].lat) {
2167              fwrite (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
2168            }
2169            s[0].wayPtr = ftell (pak);
2170            s[1].wayPtr = TO_HALFSEG;
2171            s[1].other = s[0].other + 1;
2172            s[0].other = nOther++ * 2;
2173            s[0].lat = atoi (avalue);
2174            if (lowzListCnt >=
2175                int (sizeof (lowzList) / sizeof (lowzList[0]))) lowzListCnt--;
2176            lowzList[lowzListCnt++] = atoi (avalue);
2177          }
2178          #define K_IS(x) (stricmp (tag_k, x) == 0)
2179          #define V_IS(x) (stricmp (avalue, x) == 0)
2180          if (stricmp (aname, "v") == 0) {
2181            int newStyle = 0;
2182            for (; newStyle < styleCnt && !(K_IS (style_k[newStyle])
2183                             && V_IS (style_v[newStyle])); newStyle++) {}
2184            if (defaultRestrict[newStyle] & (1 << modifierR)) {
2185              yesMask |= defaultRestrict[newStyle];
2186            }
2187            else if (newStyle < styleCnt) {
2188              w.bits = (w.bits & ~((2<<STYLE_BITS) - 1)) + newStyle;
2189            }
2190
2191            if (K_IS ("name")) {
2192              xmlChar *tmp = xmlStrdup (BAD_CAST "\n");
2193              tmp = xmlStrcat (BAD_CAST tmp, BAD_CAST avalue);
2194              avalue = tags; // Old 'tags' will be freed
2195              tags = (char*) xmlStrcat (tmp, BAD_CAST tags);
2196              // name always first tag.
2197            }
2198            else if (K_IS ("layer")) w.bits |= atoi (avalue) << 29;
2199           
2200            #define M(field) else if (K_IS (#field)) { \
2201                if (V_IS ("yes") || V_IS ("1") || V_IS ("permissive")) { \
2202                  yesMask |= 1 << field ## R; \
2203                } else if (V_IS ("no") || V_IS ("0") || V_IS ("private")) { \
2204                  noMask |= 1 << field ## R; \
2205                } \
2206              }
2207            RESTRICTIONS
2208            #undef M
2209           
2210            else if (!V_IS ("no") && !V_IS ("false") && 
2211              !K_IS ("sagns_id") && !K_IS ("sangs_id") && 
2212              !K_IS ("is_in") && !V_IS ("residential") &&
2213              !V_IS ("junction") && /* Not approved and when it isn't obvious
2214                from the ways that it's a junction, the tag will often be
2215                something ridiculous like junction=junction ! */
2216// blocked as highway:  !V_IS ("mini_roundabout") && !V_IS ("roundabout") &&
2217              !V_IS ("traffic_signals") && !K_IS ("editor") &&
2218              !K_IS ("class") /* esp. class=node */ &&
2219              !K_IS ("type") /* This is only for boules, but we drop it
2220                because it's often misused */ &&
2221              !V_IS ("coastline_old") &&
2222              !K_IS ("upload_tag") && !K_IS ("admin_level") &&
2223              (!isNode || (!K_IS ("highway") && !V_IS ("water") &&
2224                           !K_IS ("abutters") && !V_IS ("coastline")))) {
2225              // First block out tags that will bloat the index, will not make
2226              // sense or are implied.
2227
2228              // tags = xmlStrcat (tags, tag_k); // with this it's
2229              // tags = xmlStrcat (tags, "="); // it's amenity=fuel
2230              tags = (char *) xmlStrcat (BAD_CAST tags, BAD_CAST "\n");
2231              tags = (char *) BAD_CAST xmlStrcat (BAD_CAST tags, 
2232                V_IS ("yes") || V_IS ("1") || V_IS ("true")
2233                ? BAD_CAST tag_k : BAD_CAST avalue);
2234            }
2235          }
2236          if (stricmp (aname, "k") == 0) {
2237            xmlFree (tag_k);
2238            tag_k = avalue;
2239            if (strncasecmp (tag_k, "tiger:", 6) == 0 ||
2240                K_IS ("created_by") || K_IS ("converted_by") ||
2241                strncasecmp (tag_k, "source", 6) == 0 ||
2242                K_IS ("attribution") /* Mostly MassGIS */ ||
2243                K_IS ("time") || K_IS ("ele") || K_IS ("hdop") ||
2244                K_IS ("sat") || K_IS ("pdop") || K_IS ("speed") ||
2245                K_IS ("course") || K_IS ("fix") || K_IS ("vdop")) {
2246              xmlFree (aname);
2247              break;
2248            }
2249          }
2250          else xmlFree (avalue);
2251          xmlFree (aname);
2252        } /* While it's an attribute */
2253        if (stricmp (name, "node") == 0 && bbox[0] <= nd.lat &&
2254            bbox[1] <= nd.lon && nd.lat <= bbox[2] && nd.lon <= bbox[3]) {
2255          fwrite (&nd, sizeof (nd), 1, groupf[NGROUP (nd.id)]);
2256        }
2257      }
2258      if (xmlTextReaderNodeType (xml) == XML_READER_TYPE_END_ELEMENT) {
2259        int nameIsNode = stricmp (name, "node") == 0;
2260        if (stricmp (name, "way") == 0 || nameIsNode) {
2261          if (!nameIsNode || (strlen (tags) > 8 || StyleNr (&w)!=styleCnt)) {
2262            if (nameIsNode && (!wayFseek || *wayFseek)) {
2263              if (s[0].lat) { // Flush s
2264                fwrite (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
2265              }
2266              s[0].lat = nd.id; // Create 2 fake halfSegs
2267              s[0].wayPtr = ftell (pak);
2268              s[1].wayPtr = TO_HALFSEG;
2269              s[0].other = -2; // No next
2270              s[1].other = -1; // No prev
2271              lowzList[lowzListCnt++] = nd.id;
2272            }
2273            if (s[0].other > -2) { // Not lowz
2274              if (s[0].other >= 0) nOther--; // Reclaim unused 'other' number
2275              s[0].other = -2;
2276            }
2277
2278            if (srec[StyleNr (&w)].scaleMax > 10000000 &&
2279                                                  (!wayFseek || *wayFseek)) {
2280              for (int i = 0; i < lowzListCnt; i++) {
2281                if (i % 4 && i < lowzListCnt - 1) continue; // Skip some
2282                if (s[0].lat) { // Flush s
2283                  fwrite (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
2284                }
2285                s[0].lat = lowzList[i];
2286                s[0].wayPtr = ftell (pak);
2287                s[1].wayPtr = TO_HALFSEG;
2288                s[1].other = i == 0 ? -4 : lowzOther++;
2289                s[0].other = i == lowzListCnt -1 ? -4 : lowzOther++;
2290              }
2291            }
2292            lowzListCnt = 0;
2293         
2294            if (StyleNr (&w) < styleCnt && stricmp (style_v[StyleNr (&w)],
2295                                     "city") == 0 && tags[0] == '\n') {
2296              int nlen = strcspn (tags + 1, "\n");
2297              char *n = (char *) xmlMalloc (strlen (tags) + 1 + nlen + 5 + 1);
2298              strcpy (n, tags);
2299              memcpy (n + strlen (tags), tags, 1 + nlen);
2300              strcpy (n + strlen (tags) + 1 + nlen, " City");
2301              //fprintf (stderr, "Mark : %s\n", n + strlen (tags) + 1);
2302              xmlFree (tags);
2303              tags = n; 
2304            }
2305            w.bits |= (defaultRestrict[StyleNr (&w)] | yesMask) &
2306              ((noMask & accessR) ? 0 : ~noMask);
2307            char *compact = tags[0] == '\n' ? tags + 1 : tags;
2308            if (!wayFseek || *wayFseek) {
2309              fwrite (&w, sizeof (w), 1, pak);
2310              fwrite (tags + strlen (tags), 1, 1, pak); // '\0' at the front
2311              for (char *ptr = tags; *ptr != '\0'; ) {
2312                if (*ptr++ == '\n') {
2313                  unsigned idx = ftell (pak) + ptr - 1 - tags, grp;
2314                  for (grp = 0; grp < IDXGROUPS - 1 &&
2315                     TagCmp (groupName[grp], ptr) < 0; grp++) {}
2316                  fwrite (&idx, sizeof (idx), 1, groupf[grp]);
2317                }
2318              }
2319              fwrite (compact, strlen (compact) + 1, 1, pak);
2320           
2321              // Write variable length tags and align on 4 bytes
2322              if (ftell (pak) & 3) {
2323                fwrite (tags, 4 - (ftell (pak) & 3), 1, pak);
2324              }
2325            }
2326            if (wayFseek) fseek (pak, *++wayFseek, SEEK_SET);
2327            //xmlFree (tags); // Just set tags[0] = '\0'
2328            //tags = (char *) xmlStrdup (BAD_CAST "");
2329          }
2330          tags[0] = '\0'; // Erase nodes with short names
2331          yesMask = noMask = 0;
2332          w.bits = styleCnt;
2333        }
2334      } // if it was </...>
2335      xmlFree (name);
2336    } // While reading xml
2337    if (s[0].lat && (!wayFseek || *wayFseek)) {
2338      fwrite (s, sizeof (s), 1, groupf[S1GROUP (s[0].lat)]);
2339    }
2340    assert (nOther * 2 < FIRST_LOWZ_OTHER);
2341    bucketsMin1 = (nOther >> 5) | (nOther >> 4);
2342    bucketsMin1 |= bucketsMin1 >> 2;
2343    bucketsMin1 |= bucketsMin1 >> 4;
2344    bucketsMin1 |= bucketsMin1 >> 8;
2345    bucketsMin1 |= bucketsMin1 >> 16;
2346    assert (bucketsMin1 < MAX_BUCKETS);
2347   
2348    nodeType *nodes = (nodeType *) malloc (sizeof (*nodes) * MAX_NODES);
2349    if (!nodes) {
2350      fprintf (stderr, "Out of memory. Reduce MAX_NODES and increase GRPs\n");
2351      return 3;
2352    }
2353    for (int i = NGROUP (0); i < NGROUP (0) + NGROUPS; i++) {
2354      rewind (groupf[i]);
2355      memset (nodes, -1, sizeof (*nodes) * MAX_NODES);
2356      REBUILDWATCH (while (fread (&nd, sizeof (nd), 1, groupf[i]) == 1)) {
2357        memcpy (FindNode (nodes, nd.id), &nd, sizeof (nd));
2358      }
2359      fclose (groupf[i]);
2360      unlink (groupName[i]);
2361      rewind (groupf[i + NGROUPS]);
2362      REBUILDWATCH (while (fread (s, sizeof (s), 1, groupf[i + NGROUPS])
2363          == 1)) {
2364        nodeType *n = FindNode (nodes, s[0].lat);
2365        //if (n->id == -1) printf ("** Undefined node %d\n", s[0].lat);
2366        s[0].lat = s[1].lat = n->id != -1 ? n->lat : INT_MIN;
2367        s[0].lon = s[1].lon = n->id != -1 ? n->lon : INT_MIN;
2368        fwrite (s, sizeof (s), 1,
2369          groupf[-2 <= s[0].other && s[0].other < FIRST_LOWZ_OTHER
2370            ? S2GROUP (Hash (s[0].lon, s[0].lat)) : PAIRGROUP (0) - 1]);
2371      }
2372      fclose (groupf[i + NGROUPS]);
2373      unlink (groupName[i + NGROUPS]);
2374    }
2375    free (nodes);
2376   
2377    struct {
2378      int nOther1, final;
2379    } offsetpair;
2380    offsetpair.final = 0;
2381   
2382    hashTable = (int *) malloc (sizeof (*hashTable) *
2383      (bucketsMin1 + (bucketsMin1 >> 7) + 3));
2384    int bucket = -1;
2385    for (int i = S2GROUP (0); i < S2GROUP (0) + S2GROUPS; i++) {
2386      fflush (groupf[i]);
2387      size_t size = ftell (groupf[i]);
2388      rewind (groupf[i]);
2389      REBUILDWATCH (halfSegType *seg = (halfSegType *) mmap (NULL, size,
2390        PROT_READ | PROT_WRITE, MAP_SHARED, fileno (groupf[i]), 0));
2391      qsort (seg, size / sizeof (s), sizeof (s),
2392        (int (*)(const void *, const void *))HalfSegCmp);
2393      for (int j = 0; j < int (size / sizeof (seg[0])); j++) {
2394        if (!(j & 1)) {
2395          while (bucket < Hash (seg[j].lon, seg[j].lat,
2396                               i >= S2GROUP (0) + S2GROUPS - 1)) {
2397            hashTable[++bucket] = offsetpair.final / 2;
2398          }
2399        }
2400        offsetpair.nOther1 = seg[j].other;
2401        if (seg[j].other >= 0) fwrite (&offsetpair, sizeof (offsetpair), 1,
2402          groupf[PAIRGROUP (offsetpair.nOther1)]);
2403        offsetpair.final++;
2404      }
2405      munmap (seg, size);
2406    }
2407    while (bucket < bucketsMin1 + (bucketsMin1 >> 7) + 2) {
2408      hashTable[++bucket] = offsetpair.final / 2;
2409    }
2410   
2411    ndStart = ftell (pak);
2412   
2413    int *pairing = (int *) malloc (sizeof (*pairing) * PAIRS);
2414    for (int i = PAIRGROUP (0); i < PAIRGROUP (0) + PAIRGROUPS; i++) {
2415      REBUILDWATCH (rewind (groupf[i]));
2416      while (fread (&offsetpair, sizeof (offsetpair), 1, groupf[i]) == 1) {
2417        pairing[offsetpair.nOther1 % PAIRS] = offsetpair.final;
2418      }
2419      int pairs = ftell (groupf[i]) / sizeof (offsetpair);
2420      for (int j = 0; j < pairs; j++) {
2421        offsetpair.final = pairing[j ^ 1];
2422        offsetpair.nOther1 = pairing[j];
2423        fwrite (&offsetpair, sizeof (offsetpair), 1,
2424          groupf[PAIRGROUP2 (offsetpair.nOther1)]);
2425      }
2426      fclose (groupf[i]);
2427      unlink (groupName[i]);
2428    }
2429    free (pairing);
2430   
2431    int s2grp = S2GROUP (0), pairs;
2432    halfSegType *seg = (halfSegType *) malloc (PAIRS * sizeof (*seg));
2433    assert (seg /* Out of memory. Reduce PAIRS for small scale rebuilds. */);
2434    ndType ndWrite;
2435    for (int i = PAIRGROUP2 (0); i < PAIRGROUP2 (0) + PAIRGROUPS2; i++) {
2436      REBUILDWATCH (for (pairs = 0; pairs < PAIRS &&
2437                                s2grp < S2GROUP (0) + S2GROUPS; )) {
2438        if (fread (&seg[pairs], sizeof (seg[0]), 2, groupf [s2grp]) == 2) {
2439          pairs += 2;
2440        }
2441        else {
2442          fclose (groupf[s2grp]);
2443          unlink (groupName[s2grp]);
2444          s2grp++;
2445        }
2446      }
2447      rewind (groupf[i]);
2448      while (fread (&offsetpair, sizeof (offsetpair), 1, groupf[i]) == 1) {
2449        seg[offsetpair.nOther1 % PAIRS].other = offsetpair.final;
2450      }
2451      for (int j = 0; j < pairs; j += 2) {
2452        ndWrite.wayPtr = seg[j].wayPtr;
2453        ndWrite.lat = seg[j].lat;
2454        ndWrite.lon = seg[j].lon;
2455        ndWrite.other[0] = seg[j].other >> 1; // Right shift handles -1 the
2456        ndWrite.other[1] = seg[j + 1].other >> 1; // way we want.
2457        fwrite (&ndWrite, sizeof (ndWrite), 1, pak);
2458      }
2459      fclose (groupf[i]);
2460      unlink (groupName[i]);
2461    }
2462    free (seg);
2463   
2464    fflush (pak);
2465    data = (char *) mmap (NULL, ndStart,
2466      PROT_READ | PROT_WRITE, MAP_SHARED, fileno (pak), 0);
2467    fseek (pak, ndStart, SEEK_SET);
2468    REBUILDWATCH (while (fread (&ndWrite, sizeof (ndWrite), 1, pak) == 1)) {
2469      //if (bucket > Hash (ndWrite.lon, ndWrite.lat)) printf ("unsorted !\n");
2470      wayType *way = (wayType*) (data + ndWrite.wayPtr);
2471     
2472      /* The difficult way of calculating bounding boxes,
2473         namely to adjust the centerpoint (it does save us a pass) : */
2474      // Block lost nodes with if (ndWrite.lat == INT_MIN) continue;
2475      if (way->clat + way->dlat < ndWrite.lat) {
2476        way->dlat = way->dlat < 0 ? 0 : // Bootstrap
2477          (way->dlat - way->clat + ndWrite.lat) / 2;
2478        way->clat = ndWrite.lat - way->dlat;
2479      }
2480      if (way->clat - way->dlat > ndWrite.lat) {
2481        way->dlat = (way->dlat + way->clat - ndWrite.lat) / 2;
2482        way->clat = ndWrite.lat + way->dlat;
2483      }
2484      if (way->clon + way->dlon < ndWrite.lon) {
2485        way->dlon = way->dlon < 0 ? 0 : // Bootstrap
2486          (way->dlon - way->clon + ndWrite.lon) / 2;
2487        way->clon = ndWrite.lon - way->dlon;
2488      }
2489      if (way->clon - way->dlon > ndWrite.lon) {
2490        way->dlon = (way->dlon + way->clon - ndWrite.lon) / 2;
2491        way->clon = ndWrite.lon + way->dlon;
2492      }
2493    }
2494    REBUILDWATCH (for (int i = 0; i < IDXGROUPS; i++)) {
2495      int fsize = ftell (groupf[i]);
2496      fflush (groupf[i]);
2497      unsigned *idx = (unsigned *) mmap (NULL, fsize,
2498        PROT_READ | PROT_WRITE, MAP_SHARED, fileno (groupf[i]), 0);
2499      qsort (idx, fsize / sizeof (*idx), sizeof (*idx), IdxCmp);
2500      fwrite (idx, fsize, 1, pak);
2501      #if 0
2502      for (int j = 0; j < fsize / (int) sizeof (*idx); j++) {
2503        printf ("%.*s\n", strcspn (data + idx[j], "\n"), data + idx[j]);
2504      }
2505      #endif
2506      munmap (idx, fsize);
2507      fclose (groupf[i]);
2508      unlink (groupName[i]);
2509    }
2510//    printf ("ndCount=%d\n", ndCount);
2511    munmap (pak, ndStart);
2512    fwrite (hashTable, sizeof (*hashTable),
2513      bucketsMin1 + (bucketsMin1 >> 7) + 3, pak);
2514    fwrite (&bucketsMin1, sizeof (bucketsMin1), 1, pak);
2515    fwrite (&ndStart, sizeof (ndStart), 1, pak); /* for ndBase */
2516    fclose (pak);
2517    free (hashTable);
2518  } /* if rebuilding */
2519  #endif // WIN32
2520  return UserInterface (argc, argv);
2521}
2522#else // _WIN32_WCE
2523//----------------------------- _WIN32_WCE ------------------
2524HANDLE port = INVALID_HANDLE_VALUE;
2525
2526HBITMAP bmp;
2527HDC memDc, bufDc;
2528HPEN pen[2 << STYLE_BITS];
2529int pakSize;
2530
2531BOOL CALLBACK DlgSearchProc (
2532        HWND hwnd, 
2533        UINT Msg, 
2534        WPARAM wParam, 
2535        LPARAM lParam)
2536{
2537    switch (Msg) {
2538    case WM_COMMAND:
2539      if (LOWORD (wParam) == IDC_EDIT1) {
2540        HWND edit = GetDlgItem (hwnd, IDC_EDIT1);
2541        memset (appendTmp, 0, sizeof (appendTmp));
2542        int wstrlen = Edit_GetLine (edit, 0, appendTmp, sizeof (appendTmp));
2543        //wstr[wstrlen] = 0;
2544        WideCharToMultiByte (AnsiCodePage ? CP_ACP : CP_UTF8, 0, appendTmp,
2545          wstrlen, searchStr, sizeof (searchStr), NULL, NULL);
2546        hwndList = GetDlgItem (hwnd, IDC_LIST1);
2547        SendMessage (hwndList, LB_RESETCONTENT, 0, 0);
2548        IncrementalSearch ();
2549        return TRUE;
2550      }
2551      else if (wParam == IDC_SEARCHGO
2552         || LOWORD (wParam) == IDC_LIST1 && HIWORD (wParam) == LBN_DBLCLK) {
2553        HWND hwndList = GetDlgItem (hwnd, IDC_LIST1);
2554        int idx = SendMessage (hwndList, LB_GETCURSEL, 0, 0);
2555        SipShowIM (SIPF_OFF);
2556        if (ModelessDialog) ShowWindow (hwnd, SW_HIDE);
2557        else EndDialog (hwnd, 0);
2558        if (idx != LB_ERR) SelectName (NULL, idx, 0, NULL, NULL);
2559        InvalidateRect (mWnd, NULL, FALSE);
2560        return TRUE;
2561      }
2562      else if (wParam == IDC_BUTTON1) {
2563        SipShowIM (SIPF_OFF);
2564        if (ModelessDialog) ShowWindow (hwnd, SW_HIDE);
2565        else EndDialog (hwnd, 0);
2566      }
2567    }
2568    return FALSE;
2569}
2570
2571LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
2572                                  WPARAM wParam,LPARAM lParam)
2573{
2574  PAINTSTRUCT ps;
2575  RECT rect;
2576  static wchar_t msg[200] = TEXT("No coms");
2577  static int done = FALSE;
2578
2579  switch(message) {
2580    #if 0
2581    case WM_HOTKEY:
2582      if (VK_TBACK == HIWORD(lParam) && (0 != (MOD_KEYUP & LOWORD(lParam)))) {
2583        PostQuitMessage (0);
2584      }
2585      break;
2586    #endif
2587
2588    case WM_DESTROY:
2589      PostQuitMessage(0);
2590      break;
2591    case WM_PAINT:
2592      do { // Keep compiler happy.
2593      BeginPaint (hWnd, &ps);
2594      //GetClientRect (hWnd, &r);
2595      //SetBkColor(ps.hdc,RGB(63,63,63));
2596      //SetTextColor(ps.hdc,(i==state)?RGB(0,128,0):RGB(0,0,0));
2597      //r.left = 50;
2598      // r.top = 50;
2599      if (data) {
2600        if (!done) {
2601          bmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDB_BITMAP1));
2602          memDc = CreateCompatibleDC (ps.hdc);
2603          SelectObject(memDc, bmp);
2604
2605          bufDc = CreateCompatibleDC (ps.hdc); //bufDc //GetDC (hWnd));
2606          bmp = CreateCompatibleBitmap (ps.hdc, GetSystemMetrics(SM_CXSCREEN),
2607            GetSystemMetrics(SM_CYSCREEN));
2608          SelectObject (bufDc, bmp);
2609          pen[0] = CreatePen (PS_SOLID, 4, 0xff);
2610          for (int i = 0; i < 1 || style[i - 1].scaleMax; i++) {
2611            pen[i + 1] = CreatePen (style[i].dashed ? PS_DASH : PS_SOLID,
2612              style[i].lineWidth, (style[i].lineColour >> 16) |
2613                (style[i].lineColour & 0xff00) |
2614                ((style[i].lineColour & 0xff) << 16));
2615          }
2616          done = TRUE;
2617        }
2618        rect.top = rect.left = 0;
2619        rect.right = GetSystemMetrics(SM_CXSCREEN);
2620        rect.bottom = GetSystemMetrics(SM_CYSCREEN);
2621        Expose (bufDc, memDc, pen);
2622        BitBlt (ps.hdc, 0, 0, rect.right,  rect.bottom, bufDc, 0, 0, SRCCOPY);
2623        FillRect (bufDc, &rect, (HBRUSH) GetStockObject(WHITE_BRUSH));
2624      }
2625      else {
2626        wsprintf (msg, TEXT ("Can't allocate %d bytes"), pakSize);
2627//        wsprintf (msg, TEXT ("%x bytes"), *(int*)&w);
2628        ExtTextOut (ps.hdc, 50, 50, 0, NULL, msg, wcslen (msg), NULL);
2629      }
2630//      HPEN pen = CreatePen (a[c2].lineDashed ? PS_DASH : PS_SOLID,
2631      EndPaint (hWnd, &ps);
2632      } while (0);
2633      break;
2634    case WM_CHAR:
2635
2636      break;
2637    case WM_KEYDOWN:
2638      // The TGPS 375 can generate 12 keys :
2639      // VK_RETURN, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
2640      // 193=0xC1=Zoom in, 194=0xC2=Zoom out, 198=0xC6=menu 197=0xC5=settings
2641      // 195=0xC3=V+, 196=0xC4=V- which is VK_APP1 to VK_APP6
2642      // and WM_CHAR:VK_BACK
2643      InvalidateRect (hWnd, NULL, FALSE);
2644      if (wParam == '0') HitButton (0);
2645      if (wParam == '8') HitButton (1);
2646      if (wParam == '9') HitButton (2);
2647      if (Exit) PostMessage (hWnd, WM_CLOSE, 0, 0);
2648      if (ZoomInKeyNum <= option && option < HideZoomButtonsNum) {
2649        #define o(en,de,es,fr,it,nl,min,max) if (option == en ## Num) en = wParam;
2650        OPTIONS
2651        #undef o
2652        break;
2653      }
2654      if (wParam == 198) {
2655        SipShowIM (SIPF_ON);
2656        if (ModelessDialog) ShowWindow (dlgWnd, SW_SHOW);
2657        else DialogBox(hInst, MAKEINTRESOURCE(IDD_DLGSEARCH),
2658          NULL, (DLGPROC)DlgSearchProc);
2659      }
2660      if (wParam == (DWORD) ZoomInKey) zoom = zoom * 3 / 4;
2661      if (wParam == (DWORD) ZoomOutKey) zoom = zoom * 4 / 3;
2662      if (wParam == 197) FollowGPSr = !FollowGPSr;
2663
2664      do { // Keep compiler happy
2665        int oldCsum = clat + clon;
2666        if (VK_DOWN == wParam) clat -= zoom / 2;
2667        else if (VK_UP == wParam) clat += zoom / 2;
2668        else if (VK_LEFT == wParam) clon -= zoom / 2;
2669        else if (VK_RIGHT == wParam) clon += zoom / 2;
2670        if (oldCsum != clat + clon) FollowGPSr = FALSE;
2671      } while (0);
2672      break;
2673    case WM_USER + 1:
2674      /*
2675      wsprintf (msg, TEXT ("%c%c %c%c %9.5lf %10.5lf %lf %lf"),
2676        gpsNew.fix.date[0], gpsNew.fix.date[1],
2677        gpsNew.fix.tm[4], gpsNew.fix.tm[5],
2678        gpsNew.fix.latitude, gpsNew.fix.longitude, gpsNew.fix.ele,
2679        gpsNew.fix.hdop); */
2680      if (FollowGPSr) {
2681        SetLocation (Longitude (((gpsNewStruct*)lParam)->fix.longitude),
2682          Latitude (((gpsNewStruct*)lParam)->fix.latitude));
2683        InvalidateRect (hWnd, NULL, FALSE);
2684      }
2685      break;
2686    case WM_LBUTTONDOWN:
2687      //MoveTo (LOWORD(lParam), HIWORD(lParam));
2688      //PostQuitMessage (0);
2689      //if (HIWORD(lParam) < 30) {
2690        // state=LOWORD(lParam)/STATEWID;
2691      //}
2692      GdkEventButton ev;
2693      ev.x = LOWORD (lParam);
2694      ev.y = HIWORD (lParam);
2695      ev.button = 1;
2696      Click (NULL, &ev, NULL);
2697      if (Exit) PostMessage (hWnd, WM_CLOSE, 0, 0);
2698      InvalidateRect (hWnd, NULL, FALSE);
2699      break;
2700    case WM_LBUTTONUP:
2701      break;
2702    case WM_MOUSEMOVE:
2703      //LineTo (LOWORD(lParam), HIWORD(lParam));
2704      break;
2705    /*case WM_COMMAND:
2706     //switch(wParam) {
2707     //}
2708     break; */
2709    default:
2710      return(DefWindowProc(hWnd,message,wParam,lParam));
2711  }
2712  return(NULL);
2713}
2714
2715BOOL InitApplication (void)
2716{
2717  WNDCLASS wc;
2718
2719  wc.style=0;
2720  wc.lpfnWndProc=(WNDPROC)MainWndProc;
2721  wc.cbClsExtra=0;
2722  wc.cbWndExtra=0;
2723  wc.hInstance= hInst;
2724  wc.hIcon=NULL; 
2725  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
2726  wc.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH);
2727  wc.lpszMenuName = NULL;
2728  wc.lpszClassName = TEXT ("GosmoreWClass");
2729
2730  return(RegisterClass(&wc));
2731}
2732
2733HWND InitInstance(int nCmdShow)
2734{
2735  mWnd = CreateWindow (TEXT ("GosmoreWClass"), TEXT ("gosmore"), WS_DLGFRAME,
2736    0, 0, CW_USEDEFAULT/* 20 */,/* 240*/CW_USEDEFAULT,NULL,NULL, hInst,NULL);
2737
2738  if(!mWnd) return(FALSE);
2739
2740  ShowWindow (mWnd,nCmdShow);
2741  //UpdateWindow (mWnd);
2742
2743
2744  return mWnd;
2745}
2746
2747volatile int guiDone = FALSE;
2748
2749DWORD WINAPI NmeaReader (LPVOID lParam)
2750{
2751 // $GPGLL,2546.6752,S,02817.5780,E,210130.812,V,S*5B
2752  DWORD nBytes;
2753//  COMMTIMEOUTS commTiming;
2754  char rx[1200];
2755
2756  //ReadFile(port, rx, sizeof(rx), &nBytes, NULL);
2757//  Sleep (1000);
2758  /* It seems as the CreateFile before returns the action has been completed, causing
2759  the subsequent change of baudrate to fail. This read / sleep ensures that the port is open
2760  before continuing. */
2761    #if 0
2762    GetCommTimeouts (port, &commTiming);
2763    commTiming.ReadIntervalTimeout=20; /* Blocking reads */
2764    commTiming.ReadTotalTimeoutMultiplier=0;
2765    commTiming.ReadTotalTimeoutConstant=0;
2766
2767    commTiming.WriteTotalTimeoutMultiplier=5; /* No writing */
2768    commTiming.WriteTotalTimeoutConstant=5;
2769    SetCommTimeouts (port, &commTiming);
2770    #endif
2771    if (BaudRate) {
2772      DCB portState;
2773      if(!GetCommState(port, &portState)) {
2774        MessageBox (NULL, TEXT ("GetCommState Error"), TEXT (""),
2775          MB_APPLMODAL|MB_OK);
2776        return(1);
2777      }
2778      portState.BaudRate = BaudRate;
2779      portState.Parity=0;
2780      portState.StopBits=ONESTOPBIT;
2781      portState.ByteSize=8;
2782      portState.fBinary=1;
2783      portState.fParity=0;
2784      portState.fOutxCtsFlow=0;
2785      portState.fOutxDsrFlow=0;
2786      portState.fDtrControl=DTR_CONTROL_ENABLE;
2787      portState.fDsrSensitivity=0;
2788      portState.fTXContinueOnXoff=1;
2789      portState.fOutX=0;
2790      portState.fInX=0;
2791      portState.fErrorChar=0;
2792      portState.fNull=0;
2793      portState.fRtsControl=RTS_CONTROL_ENABLE;
2794      portState.fAbortOnError=1;
2795
2796      if(!SetCommState(port, &portState)) {
2797        MessageBox (NULL, TEXT ("SetCommState Error"), TEXT (""),
2798          MB_APPLMODAL|MB_OK);
2799        return(1);
2800      }
2801    }
2802
2803  #if 0
2804  PurgeComm (port, PURGE_RXCLEAR); /* Baud rate wouldn't change without this ! */
2805  DWORD nBytes2 = 0;
2806  COMSTAT cStat;
2807  ClearCommError (port, &nBytes, &cStat);
2808  rx2 = (char*) malloc (600);
2809  ReadFile(port, rx, sizeof(rx), &nBytes, NULL);
2810    if(!GetCommState(port, &portState)) {
2811      MessageBox (NULL, TEXT ("GetCommState Error"), TEXT (""),
2812        MB_APPLMODAL|MB_OK);
2813      return(1);
2814    }
2815  ReadFile(port, rx2, 600, &nBytes2, NULL);
2816  #endif
2817  //FILE *log = fopen ("\\My Documents\\log.nmea", "a");
2818  while (!guiDone) {
2819    //nBytes = sizeof (rx) - got;
2820    //got = 0;
2821    if (!ReadFile(port, rx, sizeof(rx), &nBytes, NULL) || nBytes <= 0) {
2822      continue;
2823    }
2824    //if (log) fwrite (rx, nBytes, 1, log);
2825
2826    //wndStr[0]='\0';
2827    //FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
2828    //MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),wndStr,STRLEN,NULL);
2829   
2830    if (ProcessNmea (rx, (unsigned*)&nBytes)) {
2831      PostMessage (mWnd, WM_USER + 1, 0, (intptr_t) gpsNew);
2832    }
2833  }
2834  guiDone = FALSE;
2835  //if (log) fclose (log);
2836  CloseHandle (port);
2837  return 0;
2838}
2839
2840int WINAPI WinMain(
2841    HINSTANCE  hInstance,         // handle of current instance
2842    HINSTANCE  hPrevInstance,     // handle of previous instance
2843    LPWSTR  lpszCmdLine,                  // pointer to command line
2844    int  nCmdShow)                // show state of window
2845{
2846  if(hPrevInstance) return(FALSE);
2847  hInst = hInstance;
2848  wchar_t argv0[80];
2849  GetModuleFileName (NULL, argv0, sizeof (argv0));
2850  wcscpy (argv0 + wcslen (argv0) - 8, TEXT ("ore.pak")); // _arm.exe to ore.pak
2851  FILE *gmap = _wfopen (/*"./gosmore.pak"*/ argv0, TEXT ("rb"));
2852
2853  if (!gmap) {
2854    MessageBox (NULL, TEXT ("No pak file"), TEXT (""), MB_APPLMODAL|MB_OK);
2855    return 1;
2856  }
2857  fseek (gmap, 0, SEEK_END);
2858  pakSize = ftell (gmap);
2859  fseek (gmap, 0, SEEK_SET);
2860  data = (char *) malloc (pakSize);
2861  if (!data) {
2862    MessageBox (NULL, TEXT ("Out of memory"), TEXT (""), MB_APPLMODAL|MB_OK);
2863    return 1; // This may mean memory is available, but fragmented.
2864  } // Splitting the 5 parts may help.
2865  fread (data, pakSize, 1, gmap);
2866  style = (struct styleStruct *)(data + 4);
2867  hashTable = (int *) (data + pakSize);
2868  ndBase = (ndType *)(data + hashTable[-1]);
2869  bucketsMin1 = hashTable[-2];
2870  hashTable -= bucketsMin1 + (bucketsMin1 >> 7) + 5;
2871
2872  if(!InitApplication ()) return(FALSE);
2873  if (!InitInstance (nCmdShow)) return(FALSE);
2874
2875  wcscpy (argv0 + wcslen (argv0) - 3, TEXT ("opt")); // _arm.exe to ore.pak
2876  FILE *optFile = _wfopen (argv0, TEXT ("r"));
2877 
2878  if (!optFile) optFile = fopen (DOC_PREFIX "gosmore.opt", "r");
2879  IconSet = 1;
2880  DetailLevel = 3;
2881  ButtonSize = 4;
2882  if (optFile) {
2883    #define o(en,de,es,fr,it,nl,min,max) fread (&en, sizeof (en), 1, optFile);
2884    OPTIONS
2885    #undef o
2886    fclose (optFile);
2887    option = numberOfOptions;
2888  }
2889  Exit = 0;
2890  IncrementalSearch ();
2891  InitializeOptions ();
2892
2893  GtkWidget dumdraw;
2894  dumdraw.allocation.width = GetSystemMetrics(SM_CXSCREEN);
2895  dumdraw.allocation.height = GetSystemMetrics(SM_CYSCREEN);
2896  draw = &dumdraw;
2897
2898  dlgWnd = CreateDialog (hInst, MAKEINTRESOURCE(IDD_DLGSEARCH),
2899    NULL, (DLGPROC)DlgSearchProc); // Just in case user goes modeless
2900
2901  DWORD threadId;
2902  wchar_t portname[6];
2903  wsprintf (portname, TEXT ("COM%d:"), CommPort);
2904  if (CommPort == 0) {}
2905  else if((port=CreateFile (portname, GENERIC_READ | GENERIC_WRITE, 0,
2906          NULL, OPEN_EXISTING, 0, 0)) != INVALID_HANDLE_VALUE) {
2907    CreateThread (NULL, 0, NmeaReader, NULL, 0, &threadId);
2908  }
2909  else MessageBox (NULL, TEXT ("No Port"), TEXT (""), MB_APPLMODAL|MB_OK);
2910
2911  MSG    msg;
2912  while (GetMessage (&msg, NULL, 0, 0)) {
2913    TranslateMessage (&msg);
2914    DispatchMessage (&msg);
2915  }
2916  guiDone = TRUE;
2917  while (port != INVALID_HANDLE_VALUE && guiDone) Sleep (1000);
2918  optFile = _wfopen (argv0, TEXT ("r+"));
2919  if (!optFile) optFile = fopen (DOC_PREFIX "gosmore.opt", "w");
2920  if (optFile) {
2921    #define o(en,de,es,fr,it,nl,min,max) fwrite (&en, sizeof (en),1, optFile);
2922    OPTIONS
2923    #undef o
2924    fclose (optFile);
2925  }
2926  return 0;
2927}
2928#endif
Note: See TracBrowser for help on using the repository browser.