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

Last change on this file since 10694 was 10637, checked in by daviddean, 11 years ago

WinCE: Will now attempt to reconnect if connection dies

(this may also allow for changing COM/BAUD w/o restarting,

but I haven't tested this yet).

Added logging helper functions
WinCE: Connections and Disconnects are currently logged

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