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

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

Allow k=oneway, v=true

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