Codebase list mkgmap / 4b918eb
New upstream version 0.0.0+svn4398 Bas Couwenberg 4 years ago
34 changed file(s) with 7811 addition(s) and 2060 deletion(s). Raw diff Collapse all Expand all
406406 <include name="styles/default/**"/>
407407 <include name="styles/noname/**"/>
408408 <include name="chars/ascii/row02.trans"/>
409 <include name="typ-files/**"/>
409410 </fileset>
410411 </copy>
411412
0 svn.version: 4380
1 build.timestamp: 2019-11-28T14:08:04+0000
0 svn.version: 4398
1 build.timestamp: 2019-12-18T08:25:16+0000
4343 prefix2:it = "del ", "dei ", "della ", "delle ", "di "
4444
4545 # portugese
46 prefix1:pt = "Rua", "Avenida", "Travessa"
47 prefix2:pt = "da ", "do ", "de ", "das ", "dos "
46 prefix1:pt = "Rua", "Avenida", "Travessa", "Alameda", "Beco", "Estrada", "Rodovia"
47 prefix2:pt = "da ", "do ", "de ", "das ", "dos ", "d'"
4848
4949 # spanish
5050 prefix1:es = "Avenida", "Calle", "Paseo"
5555 # Map three letter ISO country codes to list of used languages for road names.
5656 # It is assumed that the style sets mkgmap:country to one of these ISO codes.
5757
58 lang:AGO = pt
5859 lang:AND = es, ca
5960 lang:ARG = es
6061 lang:BOL = es
62 lang:BRA = pt
6163 lang:CAN = en, fr
6264 lang:CHE = de, fr, it
6365 lang:CHL = es
7173 lang:ESP = es, gl, eu, ca
7274 lang:FRA = fr
7375 lang:GBR = en
76 lang:GNB = pt
7477 lang:GTM = es
7578 lang:GUY = en
7679 lang:HND = es
7780 lang:MEX = es
81 lang:MOZ = pt
7882 lang:NIC = es
7983 lang:PAN = es
8084 lang:PER = es
0
1 [_id]
2 ProductCode=1
3 CodePage=65001
4 [End]
5 [_comments]
6 ;https://github.com/Jorisbo/Mkgmap-Mapnik-Style-Garmin
7 ;Jorisbo@hotmail.com
8 ;
9 ;This program is free software; you can redistribute it and/or modify
10 ;it under the terms of the GNU General Public License version 3 or
11 ;version 2 as published by the Free Software Foundation.
12 ;
13 ;This program is distributed in the hope that it will be useful, but
14 ;WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 ;General Public License for more details.
17 ;
18 ;Auto generated: 20191209 18:13
19 ;From master: MKG
20 ;As subset: mkgmap
21 ;Based on mkgmap default style version: r4389
22 ;
23 [End]
24 [_drawOrder]
25 Type=0x04b,1
26 Type=0x002,2
27 Type=0x003,2
28 Type=0x007,2
29 Type=0x009,2
30 Type=0x00a,2
31 Type=0x010,2
32 Type=0x011,2
33 Type=0x012,2
34 Type=0x015,2
35 Type=0x016,2
36 Type=0x018,2
37 Type=0x01a,2
38 Type=0x01c,2
39 Type=0x01d,2
40 Type=0x020,2
41 Type=0x021,2
42 Type=0x022,2
43 Type=0x024,2
44 Type=0x025,2
45 Type=0x026,2
46 Type=0x03b,2
47 Type=0x03d,2
48 Type=0x046,2
49 Type=0x047,2
50 Type=0x048,2
51 Type=0x04c,2
52 Type=0x04d,2
53 Type=0x051,2
54 Type=0x053,2
55 Type=0x008,3
56 Type=0x00b,3
57 Type=0x00c,3
58 Type=0x00f,3
59 Type=0x032,3
60 Type=0x04e,3
61 Type=0x050,3
62 Type=0x052,3
63 Type=0x06b,3
64 Type=0x017,4
65 Type=0x04f,4
66 Type=0x005,5
67 Type=0x019,5
68 Type=0x03c,5
69 Type=0x03f,5
70 Type=0x041,5
71 Type=0x006,6
72 Type=0x00e,6
73 Type=0x013,7
74 Type=0x023,7
75 Type=0x06a,7
76 Type=0x06c,8
77 Type=0x004,9
78 [End]
79 [_polygon]
80 type=0x02
81 ;GRMN_TYPE: Urban Areas/SMALL_CITY/Small urban area, less than 200 000 inhabitants/Non NT
82 String1=0x01,Résidentiel
83 String2=0x02,Wohngebiet
84 String3=0x04,Residential
85 String4=0x03,Bebouwing
86 String7=0x15,Obszar mieszkalny
87 String8=0x10,Residencial
88 String9=0x05,Area residenziale
89 ExtendedLabels=Y
90 FontStyle=NoLabel (invisible)
91 CustomColor=No
92 Xpm="0 0 1 0"
93 "1 c #E0DFDF"
94 [end]
95 [_polygon]
96 type=0x03
97 ;GRMN_TYPE: Urban Areas/TOWN/Urban area, less than 50 000 inhabitants/Non NT
98 String1=0x01,Résidentiel
99 String2=0x02,Wohngebiet
100 String3=0x04,Residential
101 String4=0x03,Bebouwing
102 String7=0x15,Obszar mieszkalny
103 String8=0x10,Residencial
104 String9=0x05,Area residenziale
105 ExtendedLabels=Y
106 FontStyle=NoLabel (invisible)
107 CustomColor=No
108 Xpm="0 0 1 0"
109 "1 c #E0DFDF"
110 [end]
111 [_polygon]
112 type=0x04
113 ;GRMN_TYPE: Large Manmade Areas/MILITARY_BASE/Military base area/Non NT
114 String1=0x01,Domaine militaire
115 String2=0x02,Militärisches Sperrgebiet
116 String3=0x04,Military
117 String4=0x03,Militair domein
118 String7=0x15,Teren wojskowy
119 String8=0x10,Militar
120 String9=0x05,Area militare
121 ExtendedLabels=Y
122 FontStyle=NoLabel (invisible)
123 CustomColor=No
124 Xpm="32 32 2 1"
125 "! c #FF958B"
126 " c none"
127 " !! !! "
128 "!! !! "
129 "! !! !"
130 " !! !!"
131 " !! !! "
132 " !! !! "
133 " !! !! "
134 " !! !! "
135 " !! !! "
136 " !! !! "
137 " !! !! "
138 " !! !! "
139 " !! !! "
140 " !! !! "
141 " !! !! "
142 " !! !! "
143 " !! !! "
144 "!! !! "
145 "! !! !"
146 " !! !!"
147 " !! !! "
148 " !! !! "
149 " !! !! "
150 " !! !! "
151 " !! !! "
152 " !! !! "
153 " !! !! "
154 " !! !! "
155 " !! !! "
156 " !! !! "
157 " !! !! "
158 " !! !! "
159 ;12345678901234567890123456789012
160 [end]
161 [_polygon]
162 type=0x05
163 ;GRMN_TYPE: Large Manmade Areas/PARKING_LOT/Parking lot area/Non NT
164 String1=0x01,Parking
165 String2=0x02,Parkplatz
166 String3=0x04,Parking
167 String4=0x03,Parkeerterrein
168 String7=0x15,Parking
169 String8=0x10,Estacionamento
170 String9=0x05,Parcheggio
171 ExtendedLabels=Y
172 FontStyle=NoLabel (invisible)
173 CustomColor=No
174 Xpm="0 0 1 0"
175 "1 c #EEEEEE"
176 [end]
177 [_polygon]
178 type=0x06
179 ;GRMN_TYPE: Large Manmade Areas/PARKING_GARAGE/Parking garage area/Non NT
180 String1=0x01,Garages
181 String2=0x02,Garagen
182 String3=0x04,Garages
183 String4=0x03,Garages
184 String7=0x15,Garaże
185 String8=0x10,Garagem
186 String9=0x05,Garage
187 ExtendedLabels=Y
188 FontStyle=NoLabel (invisible)
189 CustomColor=No
190 Xpm="0 0 1 0"
191 "1 c #DFDDCE"
192 [end]
193 [_polygon]
194 type=0x07
195 ;GRMN_TYPE: Large Manmade Areas/AIRPORT/Airport area/Non NT
196 String1=0x01,Aéroport
197 String2=0x02,Flughafen
198 String3=0x04,Airport
199 String4=0x03,Vliegveld
200 String7=0x15,Lotnisko
201 String8=0x10,Aeroporto
202 String9=0x05,Aerodromo
203 ExtendedLabels=Y
204 FontStyle=NoLabel (invisible)
205 CustomColor=No
206 Xpm="0 0 1 0"
207 "1 c #E9E7E2"
208 [end]
209 [_polygon]
210 type=0x08
211 ;GRMN_TYPE: Large Manmade Areas/SHOPPING_AREA/Shopping area/Non NT
212 String1=0x01,Zone commerciale
213 String2=0x02,Gewerbegebiet
214 String3=0x04,Commercial area
215 String4=0x03,Commercieel gebied
216 String7=0x15,Obszar handlowy
217 String8=0x10,Área comercial
218 String9=0x05,Area commerciale
219 ExtendedLabels=Y
220 FontStyle=NoLabel (invisible)
221 CustomColor=No
222 Xpm="0 0 1 0"
223 "1 c #F2DAD9"
224 [end]
225 [_polygon]
226 type=0x09
227 ;GRMN_TYPE: Large Manmade Areas/MARINA/Marina area/Non NT
228 String1=0x01,Piscine
229 String2=0x02,Schwimmbad
230 String3=0x04,Swimmingpool
231 String4=0x03,Zwembad
232 String7=0x15,Basen
233 String8=0x10,Piscina
234 String9=0x05,Piscina
235 ExtendedLabels=Y
236 FontStyle=NoLabel (invisible)
237 CustomColor=No
238 Xpm="0 0 1 0"
239 "1 c #AAD3DF"
240 [end]
241 [_polygon]
242 type=0x0a
243 ;GRMN_TYPE: Large Manmade Areas/COLLEGE/College or university area/Non NT
244 String1=0x01,École
245 String2=0x02,Schule
246 String3=0x04,Education
247 String4=0x03,School
248 String7=0x15,Edukacja
249 String8=0x10,Escola
250 String9=0x05,Scuola
251 ExtendedLabels=Y
252 FontStyle=NoLabel (invisible)
253 CustomColor=No
254 Xpm="0 0 1 0"
255 "1 c #FFFFE5"
256 [end]
257 [_polygon]
258 type=0x0b
259 ;GRMN_TYPE: Large Manmade Areas/HOSPITAL/Hospital area/Non NT
260 String1=0x01,Hôpital
261 String2=0x02,Krankenhaus
262 String3=0x04,Hospital
263 String4=0x03,Ziekenhuis
264 String7=0x15,Szpital
265 String8=0x10,Hospital
266 String9=0x05,Ospedale
267 ExtendedLabels=Y
268 FontStyle=NoLabel (invisible)
269 CustomColor=No
270 Xpm="0 0 1 0"
271 "1 c #FFFFE5"
272 [end]
273 [_polygon]
274 type=0x0c
275 ;GRMN_TYPE: Large Manmade Areas/INDUSTRIAL_COMPLEX/Industrial complex area/Non NT
276 String1=0x01,Zone industrielle
277 String2=0x02,Industriegebiet
278 String3=0x04,Industrial area
279 String4=0x03,Industriegebied
280 String7=0x15,Obszar przemysłowy
281 String8=0x10,Área industrial
282 String9=0x05,Area industriale
283 ExtendedLabels=Y
284 FontStyle=NoLabel (invisible)
285 CustomColor=No
286 Xpm="0 0 1 0"
287 "1 c #EBDBE8"
288 [end]
289 [_polygon]
290 type=0x0e
291 ;GRMN_TYPE: Large Manmade Areas/AIRPORT_RUNWAYS/Airport runway area/Non NT
292 String1=0x01,Aérodrome
293 String2=0x02,Flugfeld
294 String3=0x04,Aeroway
295 String4=0x03,Landingsbaan
296 String7=0x15,Pas startowy
297 String8=0x10,Aeródromo
298 String9=0x05,Pista di aviazione
299 ExtendedLabels=Y
300 FontStyle=NoLabel (invisible)
301 CustomColor=No
302 Xpm="0 0 1 0"
303 "1 c #BBBBCC"
304 [end]
305 [_polygon]
306 type=0x0f
307 ;GRMN_TYPE: //
308 String1=0x01,Zone commerciale
309 String2=0x02,Gewerbegebiet
310 String3=0x04,Commercial area
311 String4=0x03,Commercieel gebied
312 String7=0x15,Obszar handlowy
313 String8=0x10,Área comercial
314 String9=0x05,Area commerciale
315 ExtendedLabels=Y
316 FontStyle=NoLabel (invisible)
317 CustomColor=No
318 Xpm="0 0 1 0"
319 "1 c #F2DAD9"
320 [end]
321 [_polygon]
322 type=0x10
323 ;GRMN_TYPE: //
324 String1=0x01,Résidentiel
325 String2=0x02,Wohngebiet
326 String3=0x04,Residential
327 String4=0x03,Bebouwing
328 String7=0x15,Obszar mieszkalny
329 String8=0x10,Residencial
330 String9=0x05,Area residenziale
331 ExtendedLabels=Y
332 FontStyle=NoLabel (invisible)
333 CustomColor=No
334 Xpm="0 0 1 0"
335 "1 c #E0DFDF"
336 [end]
337 [_polygon]
338 type=0x11
339 ;GRMN_TYPE: //
340 String1=0x01,Domaine militair
341 String2=0x02,Militärisches Sperrgebiet
342 String3=0x04,Military dangerzone
343 String4=0x03,Miltaire gevarenzone
344 ExtendedLabels=Y
345 FontStyle=NoLabel (invisible)
346 CustomColor=No
347 Xpm="32 32 2 1"
348 "! c #FFFFFF"
349 "# c #FCD8DB"
350 "################################"
351 "################################"
352 "################################"
353 "################################"
354 "################################"
355 "################################"
356 "################################"
357 "################################"
358 "################################"
359 "################################"
360 "################################"
361 "################################"
362 "################################"
363 "#############!###!##############"
364 "##############!#!###############"
365 "###############!################"
366 "##############!#!###############"
367 "#############!###!##############"
368 "################################"
369 "################################"
370 "################################"
371 "################################"
372 "################################"
373 "################################"
374 "################################"
375 "################################"
376 "################################"
377 "################################"
378 "################################"
379 "################################"
380 "################################"
381 "################################"
382 ;12345678901234567890123456789012
383 [end]
384 [_polygon]
385 type=0x12
386 ;GRMN_TYPE: //
387 String1=0x01,Aire
388 String2=0x02,Raststätte
389 String3=0x04,Service
390 String4=0x03,Snelweg rustplaats
391 ExtendedLabels=Y
392 FontStyle=NoLabel (invisible)
393 CustomColor=No
394 Xpm="0 0 1 0"
395 "1 c #EFC8C8"
396 [end]
397 [_polygon]
398 type=0x13
399 ;GRMN_TYPE: Large Manmade Areas/GENERIC_MANMADE/Other or generic manmade area, such as a building/Non NT
400 String1=0x01,Bâtiment
401 String2=0x02,Gebäude
402 String3=0x04,Building
403 String4=0x03,Gebouw
404 String7=0x15,Budynek
405 String8=0x10,Edifício
406 String9=0x05,Edificio
407 ExtendedLabels=Y
408 FontStyle=NoLabel (invisible)
409 CustomColor=No
410 Xpm="0 0 1 0"
411 "1 c #D9D0C9"
412 [end]
413 [_polygon]
414 type=0x15
415 ;GRMN_TYPE: Park Areas/NATIONAL_PARK/National park/Non NT
416 String1=0x01,Espace vert
417 String2=0x02,Grün
418 String3=0x04,Village green
419 String4=0x03,Stadsgroen
420 ExtendedLabels=Y
421 FontStyle=NoLabel (invisible)
422 CustomColor=No
423 Xpm="0 0 1 0"
424 "1 c #CDEBB0"
425 [end]
426 [_polygon]
427 type=0x16
428 ;GRMN_TYPE: Park Areas/NATIONAL_PARK_OTHER/Small or misc sized national park/Non NT
429 String1=0x01,Espace vert
430 String2=0x02,Grün
431 String3=0x04,Green area
432 String4=0x03,Groen
433 String7=0x15,Zieleń
434 String8=0x10,Área verde
435 String9=0x05,Area naturale
436 ExtendedLabels=Y
437 FontStyle=NoLabel (invisible)
438 CustomColor=No
439 Xpm="0 0 1 0"
440 "1 c #DBF1C6"
441 [end]
442 [_polygon]
443 type=0x17
444 ;GRMN_TYPE: Park Areas/URBAN_PARK/Small urban park, typically only a few square blocks in size/Non NT
445 String1=0x01,Parc
446 String2=0x02,Park
447 String3=0x04,Park
448 String4=0x03,Park
449 String7=0x15,Park
450 String8=0x10,Parque
451 String9=0x05,Parco
452 ExtendedLabels=Y
453 FontStyle=NoLabel (invisible)
454 CustomColor=No
455 Xpm="0 0 1 0"
456 "1 c #C8FACC"
457 [end]
458 [_polygon]
459 type=0x18
460 ;GRMN_TYPE: Large Manmade Areas/GOLF_COURSE/Golf course area/Non NT
461 String1=0x01,Golf
462 String2=0x02,Golfplatz
463 String3=0x04,Golf course
464 String4=0x03,Golfbaan
465 String7=0x15,Pole golfowe
466 String8=0x10,Campo de Golfe
467 String9=0x05,Campo da golf
468 ExtendedLabels=Y
469 FontStyle=NoLabel (invisible)
470 CustomColor=No
471 Xpm="0 0 1 0"
472 "1 c #B5E3B5"
473 [end]
474 [_polygon]
475 type=0x19
476 ;GRMN_TYPE: Large Manmade Areas/SPORTS_COMPLEX/Sports arena or stadium/Non NT
477 String1=0x01,Terrain de sport
478 String2=0x02,Sportplatz
479 String3=0x04,Sports pitch
480 String4=0x03,Sportveld
481 String7=0x15,Teren sportowy
482 String8=0x10,Campo de esportes
483 String9=0x05,Campo sportivo
484 ExtendedLabels=Y
485 FontStyle=NoLabel (invisible)
486 CustomColor=No
487 Xpm="0 0 1 0"
488 "1 c #AAE0CB"
489 [end]
490 [_polygon]
491 type=0x1a
492 ;GRMN_TYPE: Large Manmade Areas/CEMETARY/Cemetary/Non NT
493 String1=0x01,Cimetière
494 String2=0x02,Friedhof
495 String3=0x04,Cemetry
496 String4=0x03,Begraafplaats
497 String7=0x15,Cmentarz
498 String8=0x10,Cemitério
499 String9=0x05,Cimitero
500 ExtendedLabels=Y
501 FontStyle=NoLabel (invisible)
502 CustomColor=No
503 Xpm="32 32 2 1"
504 "! c #88B78E"
505 "# c #AACBAF"
506 "################################"
507 "################################"
508 "################################"
509 "################################"
510 "#######!!#######################"
511 "######!!!!######################"
512 "######!!!!######################"
513 "######!!!!######################"
514 "######!!!!######################"
515 "######!!!!######################"
516 "######!!!!######################"
517 "####!!!!!!!!####################"
518 "################################"
519 "################################"
520 "################################"
521 "################################"
522 "################################"
523 "################################"
524 "################################"
525 "################################"
526 "################################"
527 "################################"
528 "################################"
529 "################################"
530 "################################"
531 "################################"
532 "################################"
533 "################################"
534 "################################"
535 "################################"
536 "################################"
537 "################################"
538 ;12345678901234567890123456789012
539 [end]
540 [_polygon]
541 type=0x1c
542 ;GRMN_TYPE: //
543 String2=0x02,Wiese
544 String3=0x04,Meadow
545 String4=0x03,Weide
546 ExtendedLabels=Y
547 FontStyle=NoLabel (invisible)
548 CustomColor=No
549 Xpm="0 0 1 0"
550 "1 c #CDEBB0"
551 [end]
552 [_polygon]
553 type=0x1d
554 ;GRMN_TYPE: //
555 String1=0x01,Parc
556 String2=0x02,Park
557 String3=0x04,Park
558 String4=0x03,Park
559 String7=0x15,Park
560 String8=0x10,Parque
561 String9=0x05,Parco
562 ExtendedLabels=Y
563 FontStyle=NoLabel (invisible)
564 CustomColor=No
565 Xpm="0 0 1 0"
566 "1 c #C8FACC"
567 [end]
568 [_polygon]
569 type=0x20
570 ;GRMN_TYPE: Park Areas/STATE_PARK_OTHER/Small or misc sized state park/Non NT
571 String1=0x01,Jardin
572 String2=0x02,Garten
573 String3=0x04,Garden
574 String4=0x03,Tuin
575 ExtendedLabels=Y
576 FontStyle=NoLabel (invisible)
577 CustomColor=No
578 Xpm="32 32 2 1"
579 "! c #8CB873"
580 "# c #CDEBB0"
581 "################################"
582 "################################"
583 "################################"
584 "###!#######!#######!#######!####"
585 "################################"
586 "################################"
587 "################################"
588 "################################"
589 "################################"
590 "################################"
591 "################################"
592 "###!#######!#######!#######!####"
593 "################################"
594 "################################"
595 "################################"
596 "################################"
597 "################################"
598 "################################"
599 "################################"
600 "###!#######!#######!#######!####"
601 "################################"
602 "################################"
603 "################################"
604 "################################"
605 "################################"
606 "################################"
607 "################################"
608 "###!#######!#######!#######!####"
609 "################################"
610 "################################"
611 "################################"
612 "################################"
613 ;12345678901234567890123456789012
614 [end]
615 [_polygon]
616 type=0x21
617 ;GRMN_TYPE: //
618 String3=0x04,Tourism
619 String4=0x03,Toeristische attractie
620 ExtendedLabels=Y
621 FontStyle=NoLabel (invisible)
622 CustomColor=No
623 Xpm="0 0 1 0"
624 "1 c #CDEBB0"
625 [end]
626 [_polygon]
627 type=0x22
628 ;GRMN_TYPE: //
629 String1=0x01,Patrimoine historique
630 String2=0x02,Historisches Gebiet / Gebäude
631 String3=0x04,Historic area/building
632 String4=0x03,Historisch gebied/gebouw
633 String7=0x15,Historyczny teren / budynek
634 String8=0x10,Edifício histórico
635 String9=0x05,Luogo storico
636 ExtendedLabels=Y
637 FontStyle=NoLabel (invisible)
638 CustomColor=No
639 Xpm="0 0 1 0"
640 "1 c #D9D0C9"
641 [end]
642 [_polygon]
643 type=0x23
644 ;GRMN_TYPE: //
645 String1=0x01,Bâtiment
646 String2=0x02,Gebäude
647 String3=0x04,Building
648 String4=0x03,Gebouw
649 String7=0x15,Budynek
650 String8=0x10,Edifício
651 String9=0x05,Edificio
652 ExtendedLabels=Y
653 FontStyle=NoLabel (invisible)
654 CustomColor=No
655 Xpm="0 0 1 0"
656 "1 c #D9D0C9"
657 [end]
658 [_polygon]
659 type=0x24
660 ;GRMN_TYPE: //
661 String2=0x02,Konstruktion
662 String3=0x04,Construction
663 String4=0x03,Constructie
664 ExtendedLabels=Y
665 FontStyle=NoLabel (invisible)
666 CustomColor=No
667 Xpm="0 0 1 0"
668 "1 c #B8B8B8"
669 [end]
670 [_polygon]
671 type=0x25
672 ;GRMN_TYPE: //
673 String1=0x01,Zone piétonne
674 String2=0x02,Fußgängerzone
675 String3=0x04,Pedestrians
676 String4=0x03,Voetgangersgebied
677 String7=0x15,Pieszy
678 String8=0x10,Pedestre
679 String9=0x05,Area pedonale
680 ExtendedLabels=Y
681 FontStyle=NoLabel (invisible)
682 CustomColor=No
683 Xpm="0 0 1 0"
684 "1 c #DDDDE8"
685 [end]
686 [_polygon]
687 type=0x26
688 ;GRMN_TYPE: //
689 String1=0x01,Ferme
690 String2=0x02,Bauernhof
691 String3=0x04,Farm
692 String4=0x03,Boerenbedrijf
693 ExtendedLabels=Y
694 FontStyle=NoLabel (invisible)
695 CustomColor=No
696 Xpm="0 0 1 0"
697 "1 c #F5DCBA"
698 [end]
699 [_polygon]
700 type=0x32
701 ;GRMN_TYPE: Water Areas/SEA/Sea/Non NT
702 String1=0x01,Mer
703 String2=0x02,Meer
704 String3=0x04,Sea
705 String4=0x03,Zee
706 String7=0x15,Morze
707 String8=0x10,Mar
708 String9=0x05,Mare
709 ExtendedLabels=Y
710 FontStyle=NormalFont
711 CustomColor=Day
712 DaycustomColor:#4D80B3
713 Xpm="0 0 1 0"
714 "1 c #AAD3DF"
715 [end]
716 [_polygon]
717 type=0x3b
718 ;GRMN_TYPE: //
719 String1=0x01,Eau
720 String2=0x02,Wasser
721 String3=0x04,Water
722 String4=0x03,Water
723 String7=0x15,Woda
724 String8=0x10,Água
725 String9=0x05,Acqua
726 ExtendedLabels=Y
727 FontStyle=SmallFont
728 CustomColor=Day
729 DaycustomColor:#4D80B3
730 Xpm="0 0 1 0"
731 "1 c #AAD3DF"
732 [end]
733 [_polygon]
734 type=0x3c
735 ;GRMN_TYPE: Water Areas/LAKE_100MI/Lake less than 250 sq mi but greater or equal to 100 sq mi in area/Non NT
736 String1=0x01,Eau
737 String2=0x02,Wasser
738 String3=0x04,Water
739 String4=0x03,Water
740 String7=0x15,Woda
741 String8=0x10,Água
742 String9=0x05,Acqua
743 ExtendedLabels=Y
744 FontStyle=SmallFont
745 CustomColor=Day
746 DaycustomColor:#4D80B3
747 Xpm="0 0 1 0"
748 "1 c #AAD3DF"
749 [end]
750 [_polygon]
751 type=0x3d
752 ;GRMN_TYPE: Water Areas/LAKE_30MI, LARGE_LAKE/Large lake, typically between 30 and 500 sq mi in area/Non NT
753 String1=0x01,Baie
754 String2=0x02,Bucht
755 String3=0x04,Bay
756 String4=0x03,Baai
757 String7=0x15,Zatoka
758 String8=0x10,Baia
759 String9=0x05,Baia
760 ExtendedLabels=Y
761 FontStyle=NoLabel (invisible)
762 CustomColor=No
763 Xpm="0 0 1 0"
764 "1 c #F2EFE9"
765 [end]
766 [_polygon]
767 type=0x3f
768 ;GRMN_TYPE: Water Areas/LAKE, LAKE_5MI/Medium sized lake, typically between 5 and 30 sq mi in area/Non NT
769 String1=0x01,Eau
770 String2=0x02,Wasser
771 String3=0x04,Water
772 String4=0x03,Water
773 String7=0x15,Woda
774 String8=0x10,Água
775 String9=0x05,Acqua
776 ExtendedLabels=Y
777 FontStyle=NoLabel (invisible)
778 CustomColor=No
779 Xpm="0 0 1 0"
780 "1 c #AAD3DF"
781 [end]
782 [_polygon]
783 type=0x41
784 ;GRMN_TYPE: Water Areas/LAKE_LT_1MI, SMALL_LAKE/Small lake, typically less than 5 sq mi in area/Non NT
785 String1=0x01,Eau
786 String2=0x02,Wasser
787 String3=0x04,Water
788 String4=0x03,Water
789 String7=0x15,Woda
790 String8=0x10,Água
791 String9=0x05,Acqua
792 ExtendedLabels=Y
793 FontStyle=SmallFont
794 CustomColor=Day
795 DaycustomColor:#4D80B3
796 Xpm="0 0 1 0"
797 "1 c #AAD3DF"
798 [end]
799 [_polygon]
800 type=0x46
801 ;GRMN_TYPE: Water Areas/LARGE_RIVER/Major river, typically at least 700 ft in width/Non NT
802 String1=0x01,Eau
803 String2=0x02,Wasser
804 String3=0x04,Water
805 String4=0x03,Water
806 String7=0x15,Woda
807 String8=0x10,Água
808 String9=0x05,Acqua
809 ExtendedLabels=Y
810 FontStyle=NoLabel (invisible)
811 CustomColor=No
812 Xpm="0 0 1 0"
813 "1 c #AAD3DF"
814 [end]
815 [_polygon]
816 type=0x47
817 ;GRMN_TYPE: Water Areas/RIVER_GT_700FT/Major river greater or equal to 700 ft in width/Non NT
818 String1=0x01,Eau
819 String2=0x02,Wasser
820 String3=0x04,Water
821 String4=0x03,Water
822 String7=0x15,Woda
823 String8=0x10,Água
824 String9=0x05,Acqua
825 ExtendedLabels=Y
826 FontStyle=SmallFont
827 CustomColor=Day
828 DaycustomColor:#4D80B3
829 Xpm="0 0 1 0"
830 "1 c #AAD3DF"
831 [end]
832 [_polygon]
833 type=0x48
834 ;GRMN_TYPE: Water Areas/RIVER_100FT, SMALL_RIVER/Minor river, typically less than 700 ft in width/Non NT
835 String1=0x01,Eau
836 String2=0x02,Wasser
837 String3=0x04,Water
838 String4=0x03,Water
839 String7=0x15,Woda
840 String8=0x10,Água
841 String9=0x05,Acqua
842 ExtendedLabels=Y
843 FontStyle=SmallFont
844 CustomColor=Day
845 DaycustomColor:#4D80B3
846 Xpm="0 0 1 0"
847 "1 c #AAD3DF"
848 [end]
849 [_polygon]
850 type=0x4b
851 ;GRMN_TYPE: Map Bounds/DATA_BOUNDS/Bounds of map after creation/Non NT
852 String1=0x01,Sol
853 String2=0x02,Hintergrund
854 String3=0x04,Non mapped area
855 String4=0x03,Achtergrond
856 String7=0x15,Obszar niezmapowany
857 String8=0x10,Área não mapeada
858 String9=0x05,Sfondo
859 ExtendedLabels=Y
860 FontStyle=LargeFont
861 CustomColor=Day
862 DaycustomColor:#00FFFF
863 Xpm="0 0 1 0"
864 "1 c #F2EFE9"
865 [end]
866 [_polygon]
867 type=0x4c
868 ;GRMN_TYPE: Water Areas/INTERMITTENT_LAKE/An intermittent or dry lake/Non NT
869 String1=0x01,Eau
870 String2=0x02,Wasser
871 String3=0x04,Water
872 String4=0x03,Water
873 String7=0x15,Woda
874 String8=0x10,Água
875 String9=0x05,Acqua
876 ExtendedLabels=Y
877 FontStyle=SmallFont
878 CustomColor=Day
879 DaycustomColor:#4D80B3
880 Xpm="0 0 1 0"
881 "1 c #AAD3DF"
882 [end]
883 [_polygon]
884 type=0x4d
885 ;GRMN_TYPE: Surface Cover Areas/GLACIER/Large area of compacted snow and ice/Non NT
886 String1=0x01,Glacier
887 String2=0x02,Gletscher
888 String3=0x04,Glacier
889 String4=0x03,Gletsjer
890 String7=0x15,Lodowiec
891 String8=0x10,Geleira
892 String9=0x05,Ghiacciaio
893 ExtendedLabels=Y
894 FontStyle=SmallFont
895 CustomColor=Day
896 DaycustomColor:#4DA0D7
897 Xpm="0 0 1 0"
898 "1 c #DDECEC"
899 [end]
900 [_polygon]
901 type=0x4e
902 ;GRMN_TYPE: Surface Cover Areas/ORCHARD/Orchard or plantation area/Non NT
903 String1=0x01,Agriculture
904 String2=0x02,Ackerland
905 String3=0x04,Farmland
906 String4=0x03,Landbouw / Glastuinbouw
907 String7=0x15,Tereny rolnicze
908 String8=0x10,Lavoura
909 String9=0x05,Terreno coltivato
910 ExtendedLabels=Y
911 FontStyle=NoLabel (invisible)
912 CustomColor=No
913 Xpm="0 0 1 0"
914 "1 c #EEF0D5"
915 [end]
916 [_polygon]
917 type=0x4f
918 ;GRMN_TYPE: Surface Cover Areas/SCRUB/Scrub brush area/Non NT
919 String1=0x01,Broussailles
920 String2=0x02,Gebüsch
921 String3=0x04,Scrub
922 String4=0x03,Kreupelbos
923 String7=0x15,Zarośla
924 String8=0x10,Arbusto
925 String9=0x05,Terreno incolto
926 ExtendedLabels=Y
927 FontStyle=NoLabel (invisible)
928 CustomColor=No
929 Xpm="32 32 2 1"
930 "! c #B0BE93"
931 "# c #C8D7AB"
932 "################################"
933 "#######################!########"
934 "#######################!########"
935 "#####################!#!#!######"
936 "#####################!!!!!######"
937 "######################!!!#######"
938 "####################!!!!!!!#####"
939 "################################"
940 "################################"
941 "################################"
942 "################################"
943 "################################"
944 "################################"
945 "################################"
946 "################################"
947 "################################"
948 "################################"
949 "################################"
950 "################################"
951 "################################"
952 "##############!#################"
953 "##############!#################"
954 "############!#!#!###############"
955 "############!!!!!###############"
956 "#############!!!################"
957 "###########!!!!!!!##############"
958 "################################"
959 "################################"
960 "################################"
961 "################################"
962 "################################"
963 "################################"
964 ;12345678901234567890123456789012
965 [end]
966 [_polygon]
967 type=0x50
968 ;GRMN_TYPE: Surface Cover Areas/WOODS/Wooded or forested area/Non NT
969 String1=0x01,Forêt
970 String2=0x02,Wald
971 String3=0x04,Forest
972 String4=0x03,Bos
973 String7=0x15,Las
974 String8=0x10,Floresta
975 String9=0x05,Selva
976 ExtendedLabels=Y
977 FontStyle=NoLabel (invisible)
978 CustomColor=No
979 Xpm="32 32 2 1"
980 "! c #8AB379"
981 "# c #ADD19E"
982 "################################"
983 "################################"
984 "################################"
985 "#####!!!###!####################"
986 "####!###!##!####################"
987 "####!###!#!#!###################"
988 "####!###!#!#!###################"
989 "#####!!!##!#!###################"
990 "######!##!###!##################"
991 "######!##!!!!!##################"
992 "######!####!####################"
993 "######!####!####################"
994 "################################"
995 "################################"
996 "################################"
997 "################################"
998 "################################"
999 "################################"
1000 "################################"
1001 "################################"
1002 "################################"
1003 "###############!!!###!##########"
1004 "##############!###!##!##########"
1005 "##############!###!#!#!#########"
1006 "##############!###!#!#!#########"
1007 "###############!!!##!#!#########"
1008 "################!##!###!########"
1009 "################!##!!!!!########"
1010 "################!####!##########"
1011 "################!####!##########"
1012 "################################"
1013 "################################"
1014 ;12345678901234567890123456789012
1015 [end]
1016 [_polygon]
1017 type=0x51
1018 ;GRMN_TYPE: Surface Cover Areas/WETLAND/Wetland or swamp area/Non NT
1019 String1=0x01,Marais
1020 String2=0x02,Sumpf
1021 String3=0x04,Marsh
1022 String4=0x03,Nat gebied
1023 String7=0x15,Mokradła
1024 String8=0x10,Pântano
1025 String9=0x05,Palude
1026 ExtendedLabels=Y
1027 FontStyle=NoLabel (invisible)
1028 CustomColor=No
1029 Xpm="32 32 2 1"
1030 "! c #49A6FA"
1031 " c none"
1032 " "
1033 " "
1034 " !!!!!! !!!!!! "
1035 " "
1036 " "
1037 " !!!!!! !!!!!! "
1038 " "
1039 "!!!!! !!!!! "
1040 " "
1041 " "
1042 " !!!!!! !!!!!! "
1043 " "
1044 " "
1045 " !!!!!! !!!!! "
1046 "!!!!!! "
1047 " "
1048 " "
1049 " "
1050 " !!!!!! !!!!!! "
1051 " "
1052 " !!!!!! "
1053 "!!!!!! "
1054 " !!!!!"
1055 " !!!!!! "
1056 " "
1057 " "
1058 " !!!!!! !!!!!! "
1059 " "
1060 " "
1061 " !!!!!! !!!!!! "
1062 "!!!!!! "
1063 " !!!!! "
1064 ;12345678901234567890123456789012
1065 [end]
1066 [_polygon]
1067 type=0x52
1068 ;GRMN_TYPE: Surface Cover Areas/TUNDRA/Area of nearly always freezing soil/Non NT
1069 String3=0x04,Tundra
1070 String4=0x03,Toendra
1071 ExtendedLabels=Y
1072 FontStyle=NoLabel (invisible)
1073 CustomColor=No
1074 Xpm="0 0 1 0"
1075 "1 c #D6D99F"
1076 [end]
1077 [_polygon]
1078 type=0x53
1079 ;GRMN_TYPE: Surface Cover Areas/FLAT/Sand, tidal, mud, etc. flat area/Non NT
1080 String1=0x01,Terre
1081 String2=0x02,Land
1082 String3=0x04,Land
1083 String4=0x03,Land
1084 String7=0x15,Land
1085 String8=0x10,Terra
1086 String9=0x05,Terra
1087 ExtendedLabels=Y
1088 FontStyle=NoLabel (invisible)
1089 CustomColor=No
1090 Xpm="0 0 1 0"
1091 "1 c #F2EFE9"
1092 [end]
1093 [_polygon]
1094 type=0x6a
1095 ;GRMN_TYPE: //
1096 String1=0x01,Gare
1097 String2=0x02,Bahnhof
1098 String3=0x04,Station
1099 String4=0x03,Station
1100 String7=0x15,Stacja
1101 String8=0x10,Estação
1102 String9=0x05,Stazione
1103 ExtendedLabels=Y
1104 FontStyle=NoLabel (invisible)
1105 CustomColor=No
1106 Xpm="0 0 1 0"
1107 "1 c #AF9C8D"
1108 [end]
1109 [_polygon]
1110 type=0x6b
1111 ;GRMN_TYPE: //
1112 String1=0x01,Zone piétonne
1113 String2=0x02,Fußgängerzone
1114 String3=0x04,Pedestrians
1115 String4=0x03,Voetgangersgebied
1116 String7=0x15,Pieszy
1117 String8=0x10,Pedestre
1118 String9=0x05,Area pedonale
1119 ExtendedLabels=Y
1120 FontStyle=NoLabel (invisible)
1121 CustomColor=No
1122 Xpm="0 0 1 0"
1123 "1 c #DDDDE8"
1124 [end]
1125 [_polygon]
1126 type=0x6c
1127 ;GRMN_TYPE: //
1128 String1=0x01,Quai
1129 String2=0x02,Bahnsteig
1130 String3=0x04,Platform
1131 String4=0x03,Perron
1132 String7=0x15,Platform
1133 String8=0x10,Plataforma
1134 String9=0x05,Banchina
1135 ExtendedLabels=Y
1136 FontStyle=NoLabel (invisible)
1137 CustomColor=No
1138 Xpm="0 0 1 0"
1139 "1 c #BBBBBB"
1140 [end]
1141 [_line]
1142 type=0x01
1143 ;GRMN_TYPE: Roads/INTERSTATE, MAJOR_HWY/Primary, divided, limited-access highway, akin to an interstate in the US/Non NT, NT
1144 UseOrientation=N
1145 LineWidth=8
1146 BorderWidth=1
1147 Xpm="0 0 2 0"
1148 "1 c #E892A2"
1149 "2 c #FF008B"
1150 String1=0x01,Autoroute
1151 String2=0x02,Autobahn
1152 String3=0x04,Motorway
1153 String4=0x03,Snelweg
1154 String7=0x15,Autostrada
1155 String8=0x10,Autoestrada
1156 String9=0x05,Autostrada
1157 ExtendedLabels=Y
1158 FontStyle=SmallFont
1159 CustomColor=No
1160 [end]
1161 [_line]
1162 type=0x02
1163 ;GRMN_TYPE: Roads/PRINCIPAL_HWY/Principal highway, usually divided and limited access, akin to US highways/Non NT, NT
1164 UseOrientation=N
1165 LineWidth=8
1166 BorderWidth=1
1167 Xpm="0 0 2 0"
1168 "1 c #F9B29C"
1169 "2 c #D87559"
1170 String1=0x01,Voie rapide
1171 String2=0x02,Schnellstraße
1172 String3=0x04,Trunk
1173 String4=0x03,Autoweg
1174 String7=0x15,Droga szybkiego ruchu
1175 String8=0x10,Via expressa
1176 String9=0x05,Superstrada
1177 ExtendedLabels=Y
1178 FontStyle=SmallFont
1179 CustomColor=No
1180 [end]
1181 [_line]
1182 type=0x03
1183 ;GRMN_TYPE: Roads/OTHER_HWY/Other highway road, akin to a state highway in the US/Non NT, NT
1184 UseOrientation=N
1185 LineWidth=8
1186 BorderWidth=1
1187 Xpm="0 0 2 0"
1188 "1 c #FCD6A4"
1189 "2 c #C5A363"
1190 String1=0x01,Route primaire
1191 String2=0x02,Bundesstraße
1192 String3=0x04,Primary
1193 String4=0x03,Primair
1194 String7=0x15,Droga krajowa
1195 String8=0x10,Via primária
1196 String9=0x05,Strada principale
1197 ExtendedLabels=Y
1198 FontStyle=SmallFont
1199 CustomColor=No
1200 [end]
1201 [_line]
1202 type=0x04
1203 ;GRMN_TYPE: Roads/ARTERIAL/Main city thoroughfare/Non NT, NT
1204 UseOrientation=N
1205 LineWidth=8
1206 BorderWidth=1
1207 Xpm="0 0 2 0"
1208 "1 c #F7FABF"
1209 "2 c #BBC279"
1210 String1=0x01,Route secondaire
1211 String2=0x02,Bundesstraße
1212 String3=0x04,Secondary
1213 String4=0x03,Secundair
1214 String7=0x15,Droga wojewódzka
1215 String8=0x10,Via secundária
1216 String9=0x05,Strada principale
1217 ExtendedLabels=Y
1218 FontStyle=SmallFont
1219 CustomColor=No
1220 [end]
1221 [_line]
1222 type=0x05
1223 ;GRMN_TYPE: Roads/COLLECTOR/Secondary city thoroughfare/Non NT, NT
1224 UseOrientation=N
1225 LineWidth=8
1226 BorderWidth=1
1227 Xpm="0 0 2 0"
1228 "1 c #FFFFFF"
1229 "2 c #C5C5C5"
1230 String1=0x01,Route tertiaire
1231 String2=0x02,Straße
1232 String3=0x04,Tertiary
1233 String4=0x03,Tertiair
1234 String7=0x15,Droga powiatowa
1235 String8=0x10,Via terciária
1236 String9=0x05,Strada
1237 ExtendedLabels=Y
1238 FontStyle=SmallFont
1239 CustomColor=No
1240 [end]
1241 [_line]
1242 type=0x06
1243 ;GRMN_TYPE: Roads/RESIDENTIAL/Residential street, these are typically the most numerous roads in a detailed city map and do not show up until the user is zoomed in quite far/Non NT, NT
1244 UseOrientation=N
1245 LineWidth=7
1246 BorderWidth=1
1247 Xpm="0 0 2 0"
1248 "1 c #FFFFFF"
1249 "2 c #C5C5C5"
1250 String1=0x01,Rue
1251 String2=0x02,Straße
1252 String3=0x04,Residential
1253 String4=0x03,Weg
1254 String7=0x15,Droga
1255 String8=0x10,Residencial
1256 String9=0x05,Strada residenziale
1257 ExtendedLabels=Y
1258 FontStyle=SmallFont
1259 CustomColor=No
1260 [end]
1261 [_line]
1262 type=0x07
1263 ;GRMN_TYPE: Roads/ALLEY, DRIVEWAY/Alleyway, private driveway to residence/Non NT, NT
1264 UseOrientation=N
1265 LineWidth=3
1266 BorderWidth=1
1267 Xpm="0 0 2 0"
1268 "1 c #FFFFFF"
1269 "2 c #C5C5C5"
1270 String1=0x01,Rue
1271 String2=0x02,Straße
1272 String3=0x04,Street
1273 String4=0x03,Straat
1274 String7=0x15,Ulica
1275 String8=0x10,Rua
1276 String9=0x05,Strada
1277 ExtendedLabels=Y
1278 FontStyle=SmallFont
1279 CustomColor=Day
1280 DaycustomColor:#626262
1281 [end]
1282 [_line]
1283 type=0x08
1284 ;GRMN_TYPE: Roads/LOW_SPEED_RAMP/Highway ramp which is to be driven at low speeds/Non NT, NT
1285 UseOrientation=Y
1286 LineWidth=5
1287 BorderWidth=1
1288 Xpm="0 0 2 0"
1289 "1 c #F7FABF"
1290 "2 c #BBC279"
1291 String1=0x01,Voie d’accès
1292 String2=0x02,Bundesstraße (Verbindung)
1293 String3=0x04,Secondary (Link)
1294 String4=0x03,Secundair (Verbinding)
1295 String7=0x15,Droga wojewódzka (łącznik)
1296 String8=0x10,Ligação de via secundária
1297 String9=0x05,Strada principale (collegamento)
1298 ExtendedLabels=Y
1299 FontStyle=NoLabel (invisible)
1300 CustomColor=No
1301 [end]
1302 [_line]
1303 type=0x09
1304 ;GRMN_TYPE: Roads/HIGH_SPEED_RAMP, RAMP/Highway ramp which is to be driven at high speeds/Non NT, NT
1305 UseOrientation=N
1306 LineWidth=5
1307 BorderWidth=1
1308 Xpm="0 0 2 0"
1309 "1 c #F9B29C"
1310 "2 c #D87559"
1311 String1=0x01,Voie d’accès
1312 String2=0x02,Schnellstraße (verbindung)
1313 String3=0x04,Trunk (Link)
1314 String4=0x03,Autoweg (Verbinding)
1315 String7=0x15,Droga szybkiego ruchu (łącznik)
1316 String8=0x10,Ligação de via expressa
1317 String9=0x05,Superstrada (collegamento)
1318 ExtendedLabels=Y
1319 FontStyle=NoLabel (invisible)
1320 CustomColor=No
1321 [end]
1322 [_line]
1323 type=0x0a
1324 ;GRMN_TYPE: Roads/UNPAVED_ROAD/Gravel or dirt road/Non NT, NT
1325 UseOrientation=Y
1326 Xpm="32 2 2 1"
1327 "! c #BD6500"
1328 " c none"
1329 "!!!!! !! !!!!! !! !!!!! !! "
1330 "!!!!! !! !!!!! !! !!!!! !! "
1331 ;12345678901234567890123456789012
1332 String1=0x01,Sans revêtement
1333 String2=0x02,Unbefestigt
1334 String3=0x04,Track (Grade unknown)
1335 String4=0x03,Veldweg (Onbekend)
1336 String7=0x15,Droga gruntowa (klasa nieznana)
1337 String8=0x10,Estrada agrícola
1338 String9=0x05,Sentiero carrabile
1339 ExtendedLabels=Y
1340 FontStyle=NoLabel (invisible)
1341 CustomColor=No
1342 [end]
1343 [_line]
1344 type=0x0b
1345 ;GRMN_TYPE: Roads/MAJOR_CONNECTOR/Major highway connector/Non NT, NT
1346 UseOrientation=N
1347 LineWidth=5
1348 BorderWidth=1
1349 Xpm="0 0 2 0"
1350 "1 c #F9B29C"
1351 "2 c #D87559"
1352 String1=0x01,Voie d’accès
1353 String2=0x02,Schnellstraße (verbindung)
1354 String3=0x04,Trunk (Link)
1355 String4=0x03,Autoweg (Verbinding)
1356 String7=0x15,Droga szybkiego ruchu (łącznik)
1357 String8=0x10,Ligação de via expressa
1358 String9=0x05,Superstrada (collegamento)
1359 ExtendedLabels=Y
1360 FontStyle=NoLabel (invisible)
1361 CustomColor=No
1362 [end]
1363 [_line]
1364 type=0x0c
1365 ;GRMN_TYPE: Roads/ROUNDABOUT/Roundabout/Non NT, NT
1366 UseOrientation=N
1367 LineWidth=7
1368 BorderWidth=1
1369 Xpm="0 0 2 0"
1370 "1 c #FFFFFF"
1371 "2 c #C5C5C5"
1372 String1=0x01,Rond point
1373 String2=0x02,Kreisverkehr
1374 String3=0x04,Roundabout
1375 String4=0x03,Rotonde
1376 String7=0x15,Rondo
1377 String8=0x10,Rotatória
1378 String9=0x05,Rotatoria
1379 ExtendedLabels=Y
1380 FontStyle=SmallFont
1381 CustomColor=No
1382 [end]
1383 [_line]
1384 type=0x11
1385 ;GRMN_TYPE: Customizable Line Types/CUSTOMIZABLE_ROUTE_LINE_5/Routable customizable line/Non NT, NT
1386 UseOrientation=N
1387 Xpm="32 2 2 1"
1388 "! c #0030FF"
1389 " c none"
1390 " !!!! !!!! !!!! !!!! "
1391 " !!!! !!!! !!!! !!!! "
1392 ;12345678901234567890123456789012
1393 String1=0x01,Piste cyclable
1394 String2=0x02,Radweg
1395 String3=0x04,Cycleway
1396 String4=0x03,Fietspad
1397 String7=0x15,Ścieżka rowerowa
1398 String8=0x10,Ciclovia
1399 String9=0x05,Pista ciclabile
1400 ExtendedLabels=Y
1401 FontStyle=NoLabel (invisible)
1402 CustomColor=Day
1403 DaycustomColor:#0030FF
1404 [end]
1405 [_line]
1406 type=0x14
1407 ;GRMN_TYPE: Misc. Line Types/RAILROAD/Railroad/Non NT
1408 UseOrientation=Y
1409 Xpm="32 3 2 1"
1410 "! c #737373"
1411 "# c #FFFFFF"
1412 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1413 "!!!!!!!!########!!!!!!!!########"
1414 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1415 ;12345678901234567890123456789012
1416 String1=0x01,Voie ferrée
1417 String2=0x02,Gleis
1418 String3=0x04,Railway
1419 String4=0x03,Spoorweg
1420 String7=0x15,Kolej
1421 String8=0x10,Ferrovia
1422 String9=0x05,Ferrovia
1423 ExtendedLabels=Y
1424 FontStyle=NoLabel (invisible)
1425 CustomColor=No
1426 [end]
1427 [_line]
1428 type=0x15
1429 ;GRMN_TYPE: Misc. Line Types/SHORELINE/Shoreline of water body (typically only used when a water area is not available)/Non NT
1430 UseOrientation=N
1431 Xpm="32 1 2 1"
1432 "! c #000000"
1433 " c none"
1434 " "
1435 ;12345678901234567890123456789012
1436 String1=0x01,Littoral
1437 String2=0x02,Küstelinien
1438 String3=0x04,Coastline
1439 String4=0x03,Kustlijn
1440 String7=0x15,Wybrzeże
1441 String8=0x10,Litoral / Costal
1442 String9=0x05,Costa
1443 ExtendedLabels=Y
1444 FontStyle=SmallFont
1445 CustomColor=Day
1446 DaycustomColor:#838383
1447 [end]
1448 [_line]
1449 type=0x16
1450 ;GRMN_TYPE: Roads/TRAIL/Walkway or trail/Non NT, NT
1451 UseOrientation=N
1452 Xpm="32 1 2 1"
1453 "! c #FF0000"
1454 " c none"
1455 " !!!!! !!!!! !!!!! !!!!! "
1456 ;12345678901234567890123456789012
1457 String1=0x01,Sentier
1458 String2=0x02,Fußweg
1459 String3=0x04,Path
1460 String4=0x03,Wandelpad
1461 String7=0x15,Ścieżka
1462 String8=0x10,Trilha
1463 String9=0x05,Sentiero
1464 ExtendedLabels=Y
1465 FontStyle=NoLabel (invisible)
1466 CustomColor=No
1467 [end]
1468 [_line]
1469 type=0x17
1470 ;GRMN_TYPE: //
1471 UseOrientation=N
1472 LineWidth=1
1473 Xpm="0 0 1 0"
1474 "1 c #AAAAAA"
1475 String3=0x04,Barrier
1476 String4=0x03,Barrière
1477 ExtendedLabels=Y
1478 FontStyle=NoLabel (invisible)
1479 CustomColor=No
1480 [end]
1481 [_line]
1482 type=0x18
1483 ;GRMN_TYPE: Water Features/STREAM/Small stream or creek/Non NT
1484 UseOrientation=Y
1485 LineWidth=2
1486 Xpm="0 0 1 0"
1487 "1 c #AAD3DF"
1488 String1=0x01,Ruisseau
1489 String2=0x02,Bach
1490 String3=0x04,Stream
1491 String4=0x03,Beek
1492 String7=0x15,Strumień
1493 String8=0x10,Córrego
1494 String9=0x05,Ruscello
1495 ExtendedLabels=Y
1496 FontStyle=SmallFont
1497 CustomColor=Day
1498 DaycustomColor:#4D80B3
1499 [end]
1500 [_line]
1501 type=0x1a
1502 ;GRMN_TYPE: Roads/INTERNATIONAL_FERRY/Major water or rail ferry/Non NT, NT
1503 UseOrientation=N
1504 Xpm="32 1 2 1"
1505 "! c #0030FF"
1506 " c none"
1507 " !!!! !!!! !!!! !!!! "
1508 ;12345678901234567890123456789012
1509 String1=0x01,Ferry
1510 String2=0x02,Fähre
1511 String3=0x04,Ferry
1512 String4=0x03,Ferry
1513 String7=0x15,Prom
1514 String8=0x10,Balsa
1515 String9=0x05,Traghetto
1516 ExtendedLabels=Y
1517 FontStyle=SmallFont
1518 CustomColor=Day
1519 DaycustomColor:#0065D5
1520 [end]
1521 [_line]
1522 type=0x1b
1523 ;GRMN_TYPE: Roads/FERRY/Water or rail ferry/Non NT, NT
1524 UseOrientation=N
1525 Xpm="32 1 2 1"
1526 "! c #0030FF"
1527 " c none"
1528 " !!!! !!!! !!!! !!!! "
1529 ;12345678901234567890123456789012
1530 String1=0x01,Ferry
1531 String2=0x02,Fähre
1532 String3=0x04,Ferry
1533 String4=0x03,Ferry
1534 String7=0x15,Prom
1535 String8=0x10,Balsa
1536 String9=0x05,Traghetto
1537 ExtendedLabels=Y
1538 FontStyle=SmallFont
1539 CustomColor=Day
1540 DaycustomColor:#0065D5
1541 [end]
1542 [_line]
1543 type=0x1c
1544 ;GRMN_TYPE: Political Borders/MJR_PLTCL_BDRY/Major political boundary (typically used for state, provincial borders)/Non NT
1545 UseOrientation=N
1546 Xpm="32 9 2 1"
1547 "! c #BD95D5"
1548 " c none"
1549 " !!!! !!!! !!!! !!!! "
1550 " !!!! !!!! !!!! !!!! "
1551 " "
1552 " "
1553 " "
1554 " "
1555 " "
1556 " "
1557 " "
1558 ;12345678901234567890123456789012
1559 String1=0x01,Limite communale
1560 String2=0x02,Grenze
1561 String3=0x04,Boundary
1562 String4=0x03,Gemeentegrens
1563 String7=0x15,Granica
1564 String8=0x10,Limite Municipal
1565 String9=0x05,Confine
1566 ExtendedLabels=Y
1567 FontStyle=NoLabel (invisible)
1568 CustomColor=No
1569 [end]
1570 [_line]
1571 type=0x1d
1572 ;GRMN_TYPE: Political Borders/MNR_PLTCL_BDRY/Minor political boundary (typically used for county/parish borders)
1573 UseOrientation=N
1574 Xpm="32 9 2 1"
1575 "! c #BD95D5"
1576 " c none"
1577 "!!!!!!!!!!!!!! !! "
1578 "!!!!!!!!!!!!!! !! "
1579 " "
1580 " "
1581 " "
1582 " "
1583 " "
1584 " "
1585 " "
1586 ;12345678901234567890123456789012
1587 String1=0x01,Limite départementale
1588 String2=0x02,Landesgrenze
1589 String3=0x04,State Boundary
1590 String4=0x03,Provinciegrens 3
1591 String7=0x15,Granica województwa
1592 String8=0x10,Limite Estadual
1593 String9=0x05,Confine regionale
1594 ExtendedLabels=Y
1595 FontStyle=SmallFont
1596 CustomColor=Day
1597 DaycustomColor:#BD30B4
1598 [end]
1599 [_line]
1600 type=0x1e
1601 ;GRMN_TYPE: Political Borders/INTRN_PLTCL_BDRY/International boundary/Non NT
1602 UseOrientation=N
1603 Xpm="32 9 2 1"
1604 "! c #BD95D5"
1605 "# c #FFFFFF"
1606 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1607 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1608 "#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!"
1609 "!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#"
1610 "#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!"
1611 "!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#"
1612 "#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!"
1613 "!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#"
1614 "#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!"
1615 ;12345678901234567890123456789012
1616 String1=0x01,Frontière nationale
1617 String2=0x02,Staatsgrenze
1618 String3=0x04,National boundary
1619 String4=0x03,Landsgrens
1620 String7=0x15,Granica państwa
1621 String8=0x10,Limite Nacional
1622 String9=0x05,Confine nazionale
1623 ExtendedLabels=Y
1624 FontStyle=NormalFont
1625 CustomColor=Day
1626 DaycustomColor:#BD30B4
1627 [end]
1628 [_line]
1629 type=0x1f
1630 ;GRMN_TYPE: Water Features/RIVER/Large stream or river/Non NT
1631 UseOrientation=Y
1632 LineWidth=7
1633 Xpm="0 0 1 0"
1634 "1 c #AAD3DF"
1635 String1=0x01,Rivière, Canal
1636 String2=0x02,Fluß, Kanal
1637 String3=0x04,River, Canal
1638 String4=0x03,Rivier, Kanaal
1639 String7=0x15,Rzeka, Kanał
1640 String8=0x10,Rio / Canal
1641 String9=0x05,Fiume/Canale
1642 ExtendedLabels=Y
1643 FontStyle=SmallFont
1644 CustomColor=Day
1645 DaycustomColor:#4D80B3
1646 [end]
1647 [_line]
1648 type=0x20
1649 ;GRMN_TYPE: Contour Lines/MINOR_CONTOUR/Minor land-based contour line/Non NT
1650 UseOrientation=N
1651 Xpm="32 1 2 1"
1652 "! c #DBB793"
1653 " c none"
1654 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1655 ;12345678901234567890123456789012
1656 String1=0x01,Courbe de niveau (20 m)
1657 String2=0x02,Höhenlinie (20 m)
1658 String3=0x04,Contour (20 m)
1659 String4=0x03,Contour (20 m)
1660 String7=0x15,Warstwica (20 m)
1661 String8=0x10,Contorno (20 m)
1662 String9=0x05,Curva di livello (20 m)
1663 ExtendedLabels=Y
1664 FontStyle=NoLabel (invisible)
1665 CustomColor=No
1666 [end]
1667 [_line]
1668 type=0x21
1669 ;GRMN_TYPE: Contour Lines/INT_CONTOUR/Intermediate contour (should be used for about every 5th contour line)/Non NT
1670 UseOrientation=N
1671 LineWidth=1
1672 Xpm="0 0 1 0"
1673 "1 c #D3A87C"
1674 String1=0x01,Courbe de niveau (100 m)
1675 String2=0x02,Höhenlinie(100 m)
1676 String3=0x04,Contour (100 m)
1677 String4=0x03,Contour (100 m)
1678 String7=0x15,Warstwica (100 m)
1679 String8=0x10,Contorno (100 m)
1680 String9=0x05,Curva di livello (100 m)
1681 ExtendedLabels=Y
1682 FontStyle=SmallFont
1683 CustomColor=Day
1684 DaycustomColor:#996633
1685 [end]
1686 [_line]
1687 type=0x22
1688 ;GRMN_TYPE: Contour Lines/MAJOR_CONTOUR/Major contour (should be used for about every 10th contour line)/Non NT
1689 UseOrientation=N
1690 LineWidth=1
1691 Xpm="0 0 1 0"
1692 "1 c #CC9966"
1693 String1=0x01,Courbe de niveau (500 m)
1694 String2=0x02,Höhenlinie (500 m)
1695 String3=0x04,Contour (500 m)
1696 String4=0x03,Contour (500 m)
1697 String7=0x15,Warstwica (500 m)
1698 String8=0x10,Contorno (500 m)
1699 String9=0x05,Curva di livello (500 m)
1700 ExtendedLabels=Y
1701 FontStyle=SmallFont
1702 CustomColor=Day
1703 DaycustomColor:#996633
1704 [end]
1705 [_line]
1706 type=0x26
1707 ;GRMN_TYPE: Water Features/INTERMITTENT_STREAM/Intermittent or dry stream, creek, or ditch/Non NT
1708 UseOrientation=Y
1709 Xpm="32 3 2 1"
1710 "! c #AAD3DF"
1711 " c none"
1712 " !!!!! !!!!! !!!!! !!!!! "
1713 " !!!!! !!!!! !!!!! !!!!! "
1714 " !!!!! !!!!! !!!!! !!!!! "
1715 ;12345678901234567890123456789012
1716 String1=0x01,Ruisseau intermittent
1717 String2=0x02,Wasserlauf (periodisch)
1718 String3=0x04,Stream (Intermittent)
1719 String4=0x03,Beek (Periodiek)
1720 String7=0x15,Strumień
1721 String8=0x10,Córrego intermitente
1722 String9=0x05,Torrente (discontinuo)
1723 ExtendedLabels=Y
1724 FontStyle=SmallFont
1725 CustomColor=Day
1726 DaycustomColor:#4D80B3
1727 [end]
1728 [_line]
1729 type=0x27
1730 ;GRMN_TYPE: Misc. Line Types/AIRPORT_RUNWAY/Airport runway centerline/Non NT
1731 UseOrientation=Y
1732 LineWidth=12
1733 Xpm="0 0 1 0"
1734 "1 c #BBBBCC"
1735 String1=0x01,Piste d’aviation
1736 String2=0x02,Startbahn
1737 String3=0x04,Runway
1738 String4=0x03,Landingsbaan
1739 String7=0x15,Pas startowy
1740 String8=0x10,Pista
1741 String9=0x05,Pista di aviazione
1742 ExtendedLabels=Y
1743 FontStyle=NoLabel (invisible)
1744 CustomColor=No
1745 [end]
1746 [_line]
1747 type=0x28
1748 ;GRMN_TYPE: Misc. Line Types/PIPELINE/Oil or water pipeline/Non NT
1749 UseOrientation=Y
1750 Xpm="32 5 2 1"
1751 "! c #626262"
1752 " c none"
1753 " ! ! ! ! "
1754 " ! ! ! ! "
1755 " !!!!!!!!!!!!!! !!!!!!!!!!!!!! "
1756 " ! ! ! ! "
1757 " ! ! ! ! "
1758 ;12345678901234567890123456789012
1759 String1=0x01,Pipeline
1760 String2=0x02,Rohr
1761 String3=0x04,Pipe
1762 String4=0x03,Pijpleiding
1763 String7=0x15,Rurociąg
1764 String8=0x10,Tubulação
1765 String9=0x05,Conduttura
1766 ExtendedLabels=Y
1767 FontStyle=NoLabel (invisible)
1768 CustomColor=No
1769 [end]
1770 [_line]
1771 type=0x29
1772 ;GRMN_TYPE: Misc. Line Types/POWERLINE/Powerline/Non NT
1773 UseOrientation=Y
1774 LineWidth=1
1775 Xpm="0 0 2 0"
1776 "1 c #737373"
1777 "2 c #FFFFFF"
1778 String1=0x01,Ligne électrique
1779 String2=0x02,Hochspannungskabel
1780 String3=0x04,Power cable
1781 String4=0x03,Hoogspanningskabel
1782 String7=0x15,Kabel wysokiego napięcia
1783 String8=0x10,Cabo de força
1784 String9=0x05,Linea elettrica
1785 ExtendedLabels=Y
1786 FontStyle=NoLabel (invisible)
1787 CustomColor=No
1788 [end]
1789 [_line]
1790 type=0x30
1791 ;GRMN_TYPE: //
1792 UseOrientation=Y
1793 LineWidth=7
1794 Xpm="0 0 1 0"
1795 "1 c #FFC0CB"
1796 String1=0x01,Circuit
1797 String2=0x02,Rennstrecke
1798 String3=0x04,Raceway
1799 String4=0x03,Circuit
1800 String7=0x15,Tor wyścigowy
1801 String8=0x10,Pista de corrida
1802 String9=0x05,Pista
1803 ExtendedLabels=Y
1804 FontStyle=NoLabel (invisible)
1805 CustomColor=No
1806 [end]
1807 [_line]
1808 type=0x10801
1809 ;GRMN_TYPE: //
1810 UseOrientation=N
1811 LineWidth=5
1812 BorderWidth=1
1813 Xpm="0 0 2 0"
1814 "1 c #F9B29C"
1815 "2 c #D87559"
1816 String1=0x01,Voie d’accès
1817 String2=0x02,Schnellstraße (verbindung)
1818 String3=0x04,Trunk (Link)
1819 String4=0x03,Autoweg (Verbinding)
1820 String7=0x15,Droga szybkiego ruchu (łącznik)
1821 String8=0x10,Ligação de via expressa
1822 String9=0x05,Superstrada (collegamento)
1823 ExtendedLabels=Y
1824 FontStyle=NoLabel (invisible)
1825 CustomColor=No
1826 [end]
1827 [_line]
1828 type=0x10802
1829 ;GRMN_TYPE: //
1830 UseOrientation=N
1831 LineWidth=5
1832 BorderWidth=1
1833 Xpm="0 0 2 0"
1834 "1 c #FCD6A4"
1835 "2 c #C5A363"
1836 String1=0x01,Voie d’accès
1837 String2=0x02,Bundesstraße (Verbindung)
1838 String3=0x04,Primary (Link)
1839 String4=0x03,Primair (Verbinding)
1840 String7=0x15,Droga krajowa (łącznik)
1841 String8=0x10,Ligação de via primária
1842 String9=0x05,Strada principale (collegamento)
1843 ExtendedLabels=Y
1844 FontStyle=NoLabel (invisible)
1845 CustomColor=No
1846 [end]
1847 [_line]
1848 type=0x10803
1849 ;GRMN_TYPE: //
1850 UseOrientation=Y
1851 LineWidth=5
1852 BorderWidth=1
1853 Xpm="0 0 2 0"
1854 "1 c #F7FABF"
1855 "2 c #BBC279"
1856 String1=0x01,Voie d’accès
1857 String2=0x02,Bundesstraße (Verbindung)
1858 String3=0x04,Secondary (Link)
1859 String4=0x03,Secundair (Verbinding)
1860 String7=0x15,Droga wojewódzka (łącznik)
1861 String8=0x10,Ligação de via secundária
1862 String9=0x05,Strada principale (collegamento)
1863 ExtendedLabels=Y
1864 FontStyle=NoLabel (invisible)
1865 CustomColor=No
1866 [end]
1867 [_line]
1868 type=0x10804
1869 ;GRMN_TYPE: //
1870 UseOrientation=N
1871 LineWidth=8
1872 BorderWidth=1
1873 Xpm="0 0 2 0"
1874 "1 c #FFFFFF"
1875 "2 c #C5C5C5"
1876 String1=0x01,Route tertiaire
1877 String2=0x02,Straße
1878 String3=0x04,Tertiary
1879 String4=0x03,Tertiair
1880 String7=0x15,Droga powiatowa
1881 String8=0x10,Via terciária
1882 String9=0x05,Strada
1883 ExtendedLabels=Y
1884 FontStyle=SmallFont
1885 CustomColor=No
1886 [end]
1887 [_line]
1888 type=0x10a02
1889 ;GRMN_TYPE: Water Features/INTERMITTENT_STREAM(NT)/Intermittent or dry stream, creek, or ditch/NT
1890 UseOrientation=Y
1891 Xpm="32 6 2 1"
1892 "! c #AAD3DF"
1893 " c none"
1894 " !! !! !! !! !! !! !! !! "
1895 " !! !! !! !! !! !! !! !! "
1896 " !! !! !! !! !! !! !! !! "
1897 " !! !! !! !! !! !! !! !! "
1898 " !! !! !! !! !! !! !! !! "
1899 " !! !! !! !! !! !! !! !! "
1900 ;12345678901234567890123456789012
1901 String1=0x01,Cours d’eau (intermittent)
1902 String2=0x02,Fluß (Periodisch)
1903 String3=0x04,River, Wadi (Intermittent)
1904 String4=0x03,Rivier (Periodiek)
1905 String7=0x15,Rzeka
1906 String8=0x10,Rio intermitente
1907 String9=0x05,Fiume (discontinuo)
1908 ExtendedLabels=Y
1909 FontStyle=NoLabel (invisible)
1910 CustomColor=No
1911 [end]
1912 [_line]
1913 type=0x10a06
1914 ;GRMN_TYPE: //
1915 UseOrientation=N
1916 LineWidth=4
1917 BorderWidth=1
1918 Xpm="0 0 2 0"
1919 "1 c #BBBBBB"
1920 "2 c #949494"
1921 String1=0x01,Quai
1922 String2=0x02,Plattform
1923 String3=0x04,Platform
1924 String4=0x03,Perron
1925 String7=0x15,Peron
1926 String8=0x10,Plataforma
1927 String9=0x05,Piattaforma
1928 ExtendedLabels=Y
1929 FontStyle=NoLabel (invisible)
1930 CustomColor=No
1931 [end]
1932 [_line]
1933 type=0x10c06
1934 ;GRMN_TYPE: //
1935 UseOrientation=Y
1936 Xpm="32 7 2 1"
1937 "! c #99CCCC"
1938 "# c #FFFFFF"
1939 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1940 "!!####!!!!####!!!!####!!!!####!!"
1941 "!!####!!!!####!!!!####!!!!####!!"
1942 "!!####!!!!####!!!!####!!!!####!!"
1943 "!!####!!!!####!!!!####!!!!####!!"
1944 "!!####!!!!####!!!!####!!!!####!!"
1945 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1946 ;12345678901234567890123456789012
1947 String1=0x01,Route (en travaux)
1948 String2=0x02,Weg (Im bau)
1949 String3=0x04,Road (Construction)
1950 String4=0x03,Weg (In aanleg)
1951 String7=0x15,Droga (w budowie)
1952 String8=0x10,Rodovia em construção
1953 String9=0x05,Strada in costruzione
1954 ExtendedLabels=Y
1955 FontStyle=NoLabel (invisible)
1956 CustomColor=No
1957 [end]
1958 [_point]
1959 type=0x001
1960 subtype=0x00
1961 ;GRMN_TYPE: Political Entities/CITY_10M/Large city with >10 million inhabitants/Non NT
1962 String1=0x01,Capitale
1963 String2=0x02,Hauptstadt
1964 String3=0x04,Capital
1965 String4=0x03,Hoofdstad
1966 String7=0x15,Stolica
1967 String8=0x10,Capital
1968 String9=0x05,Metropoli
1969 ExtendedLabels=Y
1970 FontStyle=NormalFont
1971 CustomColor=Day
1972 DaycustomColor:#414141
1973 DayXpm="11 11 2 1" Colormode=16
1974 "! c #737373"
1975 " c none"
1976 " !!!!! "
1977 " ! ! "
1978 " ! ! "
1979 "! !!! !"
1980 "! !!!!! !"
1981 "! !!!!! !"
1982 "! !!!!! !"
1983 "! !!! !"
1984 " ! ! "
1985 " ! ! "
1986 " !!!!! "
1987 ;12345678901
1988 [end]
1989 [_point]
1990 type=0x002
1991 subtype=0x00
1992 ;GRMN_TYPE: Political Entities/CITY_5M, LARGE_CITY/Large city center, typically 1M+ inhabitants/Non NT
1993 String1=0x01,Capitale
1994 String2=0x02,Hauptstadt
1995 String3=0x04,Capital
1996 String4=0x03,Hoofdstad
1997 String7=0x15,Stolica
1998 String8=0x10,Capital
1999 String9=0x05,Metropoli
2000 ExtendedLabels=Y
2001 FontStyle=NormalFont
2002 CustomColor=Day
2003 DaycustomColor:#414141
2004 DayXpm="11 11 2 1" Colormode=16
2005 "! c #737373"
2006 " c none"
2007 " !!!!! "
2008 " ! ! "
2009 " ! ! "
2010 "! !!! !"
2011 "! !!!!! !"
2012 "! !!!!! !"
2013 "! !!!!! !"
2014 "! !!! !"
2015 " ! ! "
2016 " ! ! "
2017 " !!!!! "
2018 ;12345678901
2019 [end]
2020 [_point]
2021 type=0x003
2022 subtype=0x00
2023 ;GRMN_TYPE: Political Entities/CITY_2M/Large city with a range of (2, 5] million inhabitants/Non NT
2024 String1=0x01,Ville (>200k)
2025 String2=0x02,Stadt (200t)
2026 String3=0x04,City (>200k)
2027 String4=0x03,Stad (>200k)
2028 String7=0x15,Miasto (>200 tys.)
2029 String8=0x10,Cidade (>200k)
2030 String9=0x05,Città
2031 ExtendedLabels=Y
2032 FontStyle=LargeFont
2033 CustomColor=Day
2034 DaycustomColor:#414141
2035 DayXpm="9 9 2 1" Colormode=16
2036 "! c #737373"
2037 " c none"
2038 " !!!!! "
2039 " ! ! "
2040 "! !"
2041 "! !"
2042 "! !"
2043 "! !"
2044 "! !"
2045 " ! ! "
2046 " !!!!! "
2047 ;123456789
2048 [end]
2049 [_point]
2050 type=0x004
2051 subtype=0x00
2052 ;GRMN_TYPE: Political Entities/CITY_1M/Large city with a range of (1, 2] million inhabitants/Non NT
2053 String1=0x01,Ville (>200k)
2054 String2=0x02,Stadt (200t)
2055 String3=0x04,City (>200k)
2056 String4=0x03,Stad (>200k)
2057 String7=0x15,Miasto (>200 tys.)
2058 String8=0x10,Cidade (>200k)
2059 String9=0x05,Città
2060 ExtendedLabels=Y
2061 FontStyle=LargeFont
2062 CustomColor=Day
2063 DaycustomColor:#414141
2064 DayXpm="9 9 2 1" Colormode=16
2065 "! c #737373"
2066 " c none"
2067 " !!!!! "
2068 " ! ! "
2069 "! !"
2070 "! !"
2071 "! !"
2072 "! !"
2073 "! !"
2074 " ! ! "
2075 " !!!!! "
2076 ;123456789
2077 [end]
2078 [_point]
2079 type=0x005
2080 subtype=0x00
2081 ;GRMN_TYPE: Political Entities/CITY_500K/City with the range of (0.5, 1] million inhabitants/Non NT
2082 String1=0x01,Ville (>200k)
2083 String2=0x02,Stadt (200t)
2084 String3=0x04,City (>200k)
2085 String4=0x03,Stad (>200k)
2086 String7=0x15,Miasto (>200 tys.)
2087 String8=0x10,Cidade (>200k)
2088 String9=0x05,Città
2089 ExtendedLabels=Y
2090 FontStyle=LargeFont
2091 CustomColor=Day
2092 DaycustomColor:#414141
2093 DayXpm="9 9 2 1" Colormode=16
2094 "! c #737373"
2095 " c none"
2096 " !!!!! "
2097 " ! ! "
2098 "! !"
2099 "! !"
2100 "! !"
2101 "! !"
2102 "! !"
2103 " ! ! "
2104 " !!!!! "
2105 ;123456789
2106 [end]
2107 [_point]
2108 type=0x006
2109 subtype=0x00
2110 ;GRMN_TYPE: Political Entities/CITY_200K/City with the range of (200, 500] thousand inhabitants/Non NT
2111 String1=0x01,Ville (>50k)
2112 String2=0x02,Stadt (50t)
2113 String3=0x04,City (>50k)
2114 String4=0x03,Woonplaats (>50k)
2115 String7=0x15,Miasto (>50 tys.)
2116 String8=0x10,Cidade (>50k)
2117 String9=0x05,Città
2118 ExtendedLabels=Y
2119 FontStyle=LargeFont
2120 CustomColor=Day
2121 DaycustomColor:#414141
2122 DayXpm="9 9 2 1" Colormode=16
2123 "! c #737373"
2124 " c none"
2125 " !!!!! "
2126 " ! ! "
2127 "! !"
2128 "! !"
2129 "! !"
2130 "! !"
2131 "! !"
2132 " ! ! "
2133 " !!!!! "
2134 ;123456789
2135 [end]
2136 [_point]
2137 type=0x007
2138 subtype=0x00
2139 ;GRMN_TYPE: Political Entities/CITY_100K/City with the range of (100, 200] thousand inhabitants/Non NT
2140 String1=0x01,Ville (>10k)
2141 String2=0x02,Stadt (10t)
2142 String3=0x04,City (>10k)
2143 String4=0x03,Woonplaats (>10k)
2144 String7=0x15,Miasto (>10 tys.)
2145 String8=0x10,Cidade (>10k)
2146 String9=0x05,Città
2147 ExtendedLabels=Y
2148 FontStyle=Default
2149 CustomColor=Day
2150 DaycustomColor:#414141
2151 DayXpm="1 1 2 1" Colormode=16
2152 "! c #00FF4B"
2153 " c none"
2154 " "
2155 ;1
2156 [end]
2157 [_point]
2158 type=0x008
2159 subtype=0x00
2160 ;GRMN_TYPE: Political Entities/CITY_50K, MEDIUM_CITY/Medium city center, typically 50K-1M inhabitants/Non NT
2161 String1=0x01,Village (>5k)
2162 String2=0x02,Dorf (>5t)
2163 String3=0x04,Village (>5k)
2164 String4=0x03,Dorp (>5k)
2165 String7=0x15,Wieś (>5 tys.)
2166 String8=0x10,Povoado (>5k)
2167 String9=0x05,Cittadina
2168 ExtendedLabels=Y
2169 FontStyle=Default
2170 CustomColor=Day
2171 DaycustomColor:#414141
2172 DayXpm="1 1 2 1" Colormode=16
2173 "! c #00FF4B"
2174 " c none"
2175 " "
2176 ;1
2177 [end]
2178 [_point]
2179 type=0x009
2180 subtype=0x00
2181 ;GRMN_TYPE: Political Entities/CITY_20K/City with the range of (20, 50] thousand inhabitants/Non NT
2182 String1=0x01,Village (>5k)
2183 String2=0x02,Dorf (>5t)
2184 String3=0x04,Village (>5k)
2185 String4=0x03,Dorp (>5k)
2186 String7=0x15,Wieś (>5 tys.)
2187 String8=0x10,Povoado (>5k)
2188 String9=0x05,Cittadina
2189 ExtendedLabels=Y
2190 FontStyle=Default
2191 CustomColor=Day
2192 DaycustomColor:#414141
2193 DayXpm="1 1 2 1" Colormode=16
2194 "! c #00FF4B"
2195 " c none"
2196 " "
2197 ;1
2198 [end]
2199 [_point]
2200 type=0x00a
2201 subtype=0x00
2202 ;GRMN_TYPE: Political Entities/CITY_10K/City with the range of (10, 20] thousand inhabitants/Non NT
2203 String1=0x01,Hameau
2204 String2=0x02,Ort, Weiler
2205 String3=0x04,Hamlet
2206 String4=0x03,Gehucht
2207 String7=0x15,Wioska
2208 String8=0x10,Lugarejo
2209 String9=0x05,Paese
2210 ExtendedLabels=Y
2211 FontStyle=NormalFont
2212 CustomColor=Day
2213 DaycustomColor:#737373
2214 DayXpm="1 1 2 1" Colormode=16
2215 "! c #00FF4B"
2216 " c none"
2217 " "
2218 ;1
2219 [end]
2220 [_point]
2221 type=0x00b
2222 subtype=0x00
2223 ;GRMN_TYPE: Political Entities/CITY_5K/City with the range of (5, 10] thousand inhabitants/Non NT
2224 String1=0x01,Nom
2225 String2=0x02,Name
2226 String3=0x04,Name
2227 String4=0x03,Naam
2228 String7=0x15,Nazwa
2229 String8=0x10,Nome
2230 String9=0x05,Borgo
2231 ExtendedLabels=Y
2232 FontStyle=SmallFont
2233 CustomColor=Day
2234 DaycustomColor:#737373
2235 DayXpm="1 1 2 1" Colormode=16
2236 "! c #00FF4B"
2237 " c none"
2238 " "
2239 ;1
2240 [end]
2241 [_point]
2242 type=0x021
2243 subtype=0x00
2244 ;GRMN_TYPE: //
2245 String1=0x01,Sortie
2246 String2=0x02,Ausfahrt
2247 String3=0x04,Ext
2248 String4=0x03,Afrit
2249 String7=0x15,Zjazd
2250 String8=0x10,Saída
2251 String9=0x05,Uscita
2252 ExtendedLabels=Y
2253 FontStyle=SmallFont
2254 CustomColor=Day
2255 DaycustomColor:#BD3000
2256 DayXpm="8 4 2 1" Colormode=16
2257 "! c #BD3000"
2258 " c none"
2259 " !! "
2260 "!!!! "
2261 "!!!! "
2262 " !! "
2263 ;12345678
2264 [end]
2265 [_point]
2266 type=0x021
2267 subtype=0x0f
2268 ;GRMN_TYPE: //
2269 String1=0x01,Sortie
2270 String2=0x02,Ausfahrt
2271 String3=0x04,Ext
2272 String4=0x03,Afrit
2273 String7=0x15,Zjazd
2274 String8=0x10,Saída
2275 String9=0x05,Uscita
2276 ExtendedLabels=Y
2277 FontStyle=SmallFont
2278 CustomColor=Day
2279 DaycustomColor:#BD3000
2280 DayXpm="8 4 2 1" Colormode=16
2281 "! c #BD3000"
2282 " c none"
2283 " !! "
2284 "!!!! "
2285 "!!!! "
2286 " !! "
2287 ;12345678
2288 [end]
2289 [_point]
2290 type=0x02a
2291 subtype=0x00
2292 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT/General restaurant of unknown genre/Non NT
2293 String1=0x01,Restaurant
2294 String2=0x02,Restaurant
2295 String3=0x04,Restaurant
2296 String4=0x03,Restaurant
2297 String7=0x15,Restauracja
2298 String8=0x10,Restaurante
2299 String9=0x05,Ristorante
2300 ExtendedLabels=Y
2301 FontStyle=NoLabel (invisible)
2302 CustomColor=No
2303 DayXpm="15 16 3 1" Colormode=16
2304 "! c #C77400"
2305 "# c #BD956A"
2306 " c none"
2307 " ! !# ! !! "
2308 " ! !# ! !!!! "
2309 " ! !# ! #!!!!#"
2310 " ! !# ! !!!!!!"
2311 " ! !# ! !!!!!!"
2312 " ! !# ! !!!!!!"
2313 " ! !# ! !!!!!!"
2314 " !!!!!! !!!!!!"
2315 " !!!!!! !!!! "
2316 " !!!! !! "
2317 " !! !! "
2318 " !! !! "
2319 " !! !! "
2320 " !! !! "
2321 " !! !! "
2322 " !! !! "
2323 ;123456789012345
2324 [end]
2325 [_point]
2326 type=0x02a
2327 subtype=0x01
2328 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_AMERICAN/American cuisine/Non NT
2329 String1=0x01,Restaurant (Américain)
2330 String2=0x02,Restaurant
2331 String3=0x04,Restaurant (American)
2332 String4=0x03,Restaurant (Amerikaans)
2333 String7=0x15,Restauracja (Amerykańska)
2334 String8=0x10,Restaurante americano
2335 String9=0x05,Ristorante americano
2336 ExtendedLabels=Y
2337 FontStyle=NoLabel (invisible)
2338 CustomColor=No
2339 DayXpm="15 16 3 1" Colormode=16
2340 "! c #C77400"
2341 "# c #BD956A"
2342 " c none"
2343 " ! !# ! !! "
2344 " ! !# ! !!!! "
2345 " ! !# ! #!!!!#"
2346 " ! !# ! !!!!!!"
2347 " ! !# ! !!!!!!"
2348 " ! !# ! !!!!!!"
2349 " ! !# ! !!!!!!"
2350 " !!!!!! !!!!!!"
2351 " !!!!!! !!!! "
2352 " !!!! !! "
2353 " !! !! "
2354 " !! !! "
2355 " !! !! "
2356 " !! !! "
2357 " !! !! "
2358 " !! !! "
2359 ;123456789012345
2360 [end]
2361 [_point]
2362 type=0x02a
2363 subtype=0x02
2364 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_ASIAN/Asian cuisine/Non NT
2365 String1=0x01,Restaurant (Asiatique)
2366 String2=0x02,Restaurant (Asiatisch)
2367 String3=0x04,Restaurant (Asia)
2368 String4=0x03,Restaurant (Aziatisch)
2369 String7=0x15,Restauracja (Azjatycka)
2370 String8=0x10,Restaurante asiático
2371 String9=0x05,Ristorante asiatico
2372 ExtendedLabels=Y
2373 FontStyle=NoLabel (invisible)
2374 CustomColor=No
2375 DayXpm="15 16 3 1" Colormode=16
2376 "! c #C77400"
2377 "# c #BD956A"
2378 " c none"
2379 " ! !# ! !! "
2380 " ! !# ! !!!! "
2381 " ! !# ! #!!!!#"
2382 " ! !# ! !!!!!!"
2383 " ! !# ! !!!!!!"
2384 " ! !# ! !!!!!!"
2385 " ! !# ! !!!!!!"
2386 " !!!!!! !!!!!!"
2387 " !!!!!! !!!! "
2388 " !!!! !! "
2389 " !! !! "
2390 " !! !! "
2391 " !! !! "
2392 " !! !! "
2393 " !! !! "
2394 " !! !! "
2395 ;123456789012345
2396 [end]
2397 [_point]
2398 type=0x02a
2399 subtype=0x03
2400 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_BARBECUE/Barbecue cuisine/Non NT
2401 String1=0x01,Restaurant (Grill)
2402 String2=0x02,Restaurant
2403 String3=0x04,Restaurant (BBQ)
2404 String4=0x03,Restaurant (BBQ)
2405 String7=0x15,Restauracja (Grill)
2406 String8=0x10,Churrascaria
2407 String9=0x05,Ristorante di grigliate
2408 ExtendedLabels=Y
2409 FontStyle=NoLabel (invisible)
2410 CustomColor=No
2411 DayXpm="15 16 3 1" Colormode=16
2412 "! c #C77400"
2413 "# c #BD956A"
2414 " c none"
2415 " ! !# ! !! "
2416 " ! !# ! !!!! "
2417 " ! !# ! #!!!!#"
2418 " ! !# ! !!!!!!"
2419 " ! !# ! !!!!!!"
2420 " ! !# ! !!!!!!"
2421 " ! !# ! !!!!!!"
2422 " !!!!!! !!!!!!"
2423 " !!!!!! !!!! "
2424 " !!!! !! "
2425 " !! !! "
2426 " !! !! "
2427 " !! !! "
2428 " !! !! "
2429 " !! !! "
2430 " !! !! "
2431 ;123456789012345
2432 [end]
2433 [_point]
2434 type=0x02a
2435 subtype=0x04
2436 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_CHINESE/Chinese cuisine/Non NT
2437 String1=0x01,Restaurant (Chinois)
2438 String2=0x02,Restaurant (Chinesisch)
2439 String3=0x04,Restaurant (Chinese)
2440 String4=0x03,Restaurant (Chinees)
2441 String7=0x15,Restauracja (Chińska)
2442 String8=0x10,Restaurante chinês
2443 String9=0x05,Ristorante cinese
2444 ExtendedLabels=Y
2445 FontStyle=NoLabel (invisible)
2446 CustomColor=No
2447 DayXpm="15 16 3 1" Colormode=16
2448 "! c #C77400"
2449 "# c #BD956A"
2450 " c none"
2451 " ! !# ! !! "
2452 " ! !# ! !!!! "
2453 " ! !# ! #!!!!#"
2454 " ! !# ! !!!!!!"
2455 " ! !# ! !!!!!!"
2456 " ! !# ! !!!!!!"
2457 " ! !# ! !!!!!!"
2458 " !!!!!! !!!!!!"
2459 " !!!!!! !!!! "
2460 " !!!! !! "
2461 " !! !! "
2462 " !! !! "
2463 " !! !! "
2464 " !! !! "
2465 " !! !! "
2466 " !! !! "
2467 ;123456789012345
2468 [end]
2469 [_point]
2470 type=0x02a
2471 subtype=0x05
2472 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_DELI/Deli or sandwich shop/Non NT
2473 String1=0x01,Restaurant (Grec)
2474 String2=0x02,Restaurant (Griechisch)
2475 String3=0x04,Restaurant (Greek)
2476 String4=0x03,Restaurant (Delicatesse)
2477 String7=0x15,Restauracja (Grecka)
2478 String8=0x10,Restaurante grego
2479 String9=0x05,Gastronomia
2480 ExtendedLabels=Y
2481 FontStyle=NoLabel (invisible)
2482 CustomColor=No
2483 DayXpm="15 16 3 1" Colormode=16
2484 "! c #C77400"
2485 "# c #BD956A"
2486 " c none"
2487 " ! !# ! !! "
2488 " ! !# ! !!!! "
2489 " ! !# ! #!!!!#"
2490 " ! !# ! !!!!!!"
2491 " ! !# ! !!!!!!"
2492 " ! !# ! !!!!!!"
2493 " ! !# ! !!!!!!"
2494 " !!!!!! !!!!!!"
2495 " !!!!!! !!!! "
2496 " !!!! !! "
2497 " !! !! "
2498 " !! !! "
2499 " !! !! "
2500 " !! !! "
2501 " !! !! "
2502 " !! !! "
2503 ;123456789012345
2504 [end]
2505 [_point]
2506 type=0x02a
2507 subtype=0x06
2508 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_INTRNTNL/International cuisine/Non NT
2509 String1=0x01,Restaurant (International)
2510 String2=0x02,Restaurant
2511 String3=0x04,Restaurant (International)
2512 String4=0x03,Restaurant (Internationaal)
2513 String7=0x15,Restauracja (Międzynarodowa)
2514 String8=0x10,Restaurante Internacional
2515 String9=0x05,Ristorante internazionale
2516 ExtendedLabels=Y
2517 FontStyle=NoLabel (invisible)
2518 CustomColor=No
2519 DayXpm="15 16 3 1" Colormode=16
2520 "! c #C77400"
2521 "# c #BD956A"
2522 " c none"
2523 " ! !# ! !! "
2524 " ! !# ! !!!! "
2525 " ! !# ! #!!!!#"
2526 " ! !# ! !!!!!!"
2527 " ! !# ! !!!!!!"
2528 " ! !# ! !!!!!!"
2529 " ! !# ! !!!!!!"
2530 " !!!!!! !!!!!!"
2531 " !!!!!! !!!! "
2532 " !!!! !! "
2533 " !! !! "
2534 " !! !! "
2535 " !! !! "
2536 " !! !! "
2537 " !! !! "
2538 " !! !! "
2539 ;123456789012345
2540 [end]
2541 [_point]
2542 type=0x02a
2543 subtype=0x07
2544 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_FAST_FOOD/Fast food establishment, i.e. McDonalds/Non NT
2545 String1=0x01,Restauration rapide
2546 String2=0x02,Restaurant (Fastfood)
2547 String3=0x04,Restaurant (Fastfood)
2548 String4=0x03,Restaurant (Fastfood)
2549 String7=0x15,Restauracja (Fastfood)
2550 String8=0x10,Lanchonete
2551 String9=0x05,Fast food
2552 ExtendedLabels=Y
2553 FontStyle=NoLabel (invisible)
2554 CustomColor=No
2555 DayXpm="14 9 3 1" Colormode=16
2556 "! c #C77400"
2557 "# c #CD9649"
2558 " c none"
2559 " #!!!!!!!!# "
2560 " #!!!!!!!!!!# "
2561 " !!!!!!!!!!!! "
2562 " !!!!!!!!!!!! "
2563 " "
2564 "#!!!!!!!!!!!!#"
2565 " "
2566 " !!!!!!!!!!!! "
2567 " #!!!!!!!!!!# "
2568 ;12345678901234
2569 [end]
2570 [_point]
2571 type=0x02a
2572 subtype=0x08
2573 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_ITALIAN/Italian cuisine/Non NT
2574 String1=0x01,Restaurant (Italien)
2575 String2=0x02,Restaurant (Italienisch)
2576 String3=0x04,Restaurant (Italian)
2577 String4=0x03,Restaurant (Italiaans)
2578 String7=0x15,Restauracja (Włoska)
2579 String8=0x10,Restaurante italiano
2580 String9=0x05,Ristorante italiano
2581 ExtendedLabels=Y
2582 FontStyle=NoLabel (invisible)
2583 CustomColor=No
2584 DayXpm="15 16 3 1" Colormode=16
2585 "! c #C77400"
2586 "# c #BD956A"
2587 " c none"
2588 " ! !# ! !! "
2589 " ! !# ! !!!! "
2590 " ! !# ! #!!!!#"
2591 " ! !# ! !!!!!!"
2592 " ! !# ! !!!!!!"
2593 " ! !# ! !!!!!!"
2594 " ! !# ! !!!!!!"
2595 " !!!!!! !!!!!!"
2596 " !!!!!! !!!! "
2597 " !!!! !! "
2598 " !! !! "
2599 " !! !! "
2600 " !! !! "
2601 " !! !! "
2602 " !! !! "
2603 " !! !! "
2604 ;123456789012345
2605 [end]
2606 [_point]
2607 type=0x02a
2608 subtype=0x09
2609 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_MEXICAN/Mexican cuisine/Non NT
2610 String1=0x01,Restaurant (Mexicain)
2611 String2=0x02,Restaurant (Mexikanisch)
2612 String3=0x04,Restaurant (Mexican)
2613 String4=0x03,Restaurant (Mexicaans)
2614 String7=0x15,Restauracja (Meksykańska)
2615 String8=0x10,Restaurante mexicano
2616 String9=0x05,Ristorante messicano
2617 ExtendedLabels=Y
2618 FontStyle=NoLabel (invisible)
2619 CustomColor=No
2620 DayXpm="15 16 3 1" Colormode=16
2621 "! c #C77400"
2622 "# c #BD956A"
2623 " c none"
2624 " ! !# ! !! "
2625 " ! !# ! !!!! "
2626 " ! !# ! #!!!!#"
2627 " ! !# ! !!!!!!"
2628 " ! !# ! !!!!!!"
2629 " ! !# ! !!!!!!"
2630 " ! !# ! !!!!!!"
2631 " !!!!!! !!!!!!"
2632 " !!!!!! !!!! "
2633 " !!!! !! "
2634 " !! !! "
2635 " !! !! "
2636 " !! !! "
2637 " !! !! "
2638 " !! !! "
2639 " !! !! "
2640 ;123456789012345
2641 [end]
2642 [_point]
2643 type=0x02a
2644 subtype=0x0a
2645 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_PIZZA/Pizzeria/Non NT
2646 String1=0x01,Pizzeria
2647 String2=0x02,Restaurant (Pizza)
2648 String3=0x04,Restaurant (Pizza)
2649 String4=0x03,Restaurant (Pizza)
2650 String7=0x15,Restauracja (Pizza)
2651 String8=0x10,Pizzaria
2652 String9=0x05,Pizzeria
2653 ExtendedLabels=Y
2654 FontStyle=NoLabel (invisible)
2655 CustomColor=No
2656 DayXpm="15 16 3 1" Colormode=16
2657 "! c #C77400"
2658 "# c #BD956A"
2659 " c none"
2660 " ! !# ! !! "
2661 " ! !# ! !!!! "
2662 " ! !# ! #!!!!#"
2663 " ! !# ! !!!!!!"
2664 " ! !# ! !!!!!!"
2665 " ! !# ! !!!!!!"
2666 " ! !# ! !!!!!!"
2667 " !!!!!! !!!!!!"
2668 " !!!!!! !!!! "
2669 " !!!! !! "
2670 " !! !! "
2671 " !! !! "
2672 " !! !! "
2673 " !! !! "
2674 " !! !! "
2675 " !! !! "
2676 ;123456789012345
2677 [end]
2678 [_point]
2679 type=0x02a
2680 subtype=0x0b
2681 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_SEAFOOD/Seafood restaurant/Non NT
2682 String1=0x01,Restaurant (Poissons/Fruits de mer)
2683 String2=0x02,Restaurant (Fisch)
2684 String3=0x04,Restaurant (Fisch)
2685 String4=0x03,Restaurant (Vis)
2686 String7=0x15,Restauracja (Ryby)
2687 String8=0x10,Restaurante Frutos do Mar
2688 String9=0x05,Ristorante di pesce
2689 ExtendedLabels=Y
2690 FontStyle=NoLabel (invisible)
2691 CustomColor=No
2692 DayXpm="15 16 3 1" Colormode=16
2693 "! c #C77400"
2694 "# c #BD956A"
2695 " c none"
2696 " ! !# ! !! "
2697 " ! !# ! !!!! "
2698 " ! !# ! #!!!!#"
2699 " ! !# ! !!!!!!"
2700 " ! !# ! !!!!!!"
2701 " ! !# ! !!!!!!"
2702 " ! !# ! !!!!!!"
2703 " !!!!!! !!!!!!"
2704 " !!!!!! !!!! "
2705 " !!!! !! "
2706 " !! !! "
2707 " !! !! "
2708 " !! !! "
2709 " !! !! "
2710 " !! !! "
2711 " !! !! "
2712 ;123456789012345
2713 [end]
2714 [_point]
2715 type=0x02a
2716 subtype=0x0c
2717 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_STEAK/Grill and steak brew pub restaurant/Non NT
2718 String1=0x01,Restaurant (Steak)
2719 String2=0x02,Restaurant (Steak)
2720 String3=0x04,Restaurant (Steak)
2721 String4=0x03,Restaurant (Steak)
2722 String7=0x15,Restauracja (Steki)
2723 String8=0x10,Restaurante de carnes
2724 String9=0x05,Ristorante di carne
2725 ExtendedLabels=Y
2726 FontStyle=NoLabel (invisible)
2727 CustomColor=No
2728 DayXpm="15 16 3 1" Colormode=16
2729 "! c #C77400"
2730 "# c #BD956A"
2731 " c none"
2732 " ! !# ! !! "
2733 " ! !# ! !!!! "
2734 " ! !# ! #!!!!#"
2735 " ! !# ! !!!!!!"
2736 " ! !# ! !!!!!!"
2737 " ! !# ! !!!!!!"
2738 " ! !# ! !!!!!!"
2739 " !!!!!! !!!!!!"
2740 " !!!!!! !!!! "
2741 " !!!! !! "
2742 " !! !! "
2743 " !! !! "
2744 " !! !! "
2745 " !! !! "
2746 " !! !! "
2747 " !! !! "
2748 ;123456789012345
2749 [end]
2750 [_point]
2751 type=0x02a
2752 subtype=0x0d
2753 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_DONUTS/Donut shop/Non NT
2754 String1=0x01,Restaurant (Beignets)
2755 String2=0x02,Restaurant (Bagel)
2756 String3=0x04,Restaurant (Donuts)
2757 String4=0x03,Restaurant (Donuts)
2758 String7=0x15,Restauracja (Pączki)
2759 String8=0x10,Doceria
2760 String9=0x05,Panetteria
2761 ExtendedLabels=Y
2762 FontStyle=NoLabel (invisible)
2763 CustomColor=No
2764 DayXpm="13 12 3 1" Colormode=16
2765 "! c #CD9344"
2766 "# c #C77400"
2767 " c none"
2768 " ######### "
2769 " ########### "
2770 " ######### #"
2771 " ######### #"
2772 " ######### #"
2773 " ########### "
2774 " ######### "
2775 " ####### "
2776 " ##### "
2777 " "
2778 "########### "
2779 " !#######! "
2780 ;1234567890123
2781 [end]
2782 [_point]
2783 type=0x02a
2784 subtype=0x0e
2785 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_CAFES/Cafe or coffee shop/Non NT
2786 String1=0x01,Café
2787 String2=0x02,Cafe
2788 String3=0x04,Cafe
2789 String4=0x03,Cafe
2790 String7=0x15,Kawiarnia
2791 String8=0x10,Café
2792 String9=0x05,Caffetteria
2793 ExtendedLabels=Y
2794 FontStyle=NoLabel (invisible)
2795 CustomColor=No
2796 DayXpm="13 12 3 1" Colormode=16
2797 "! c #CD9344"
2798 "# c #C77400"
2799 " c none"
2800 " ######### "
2801 " ########### "
2802 " ######### #"
2803 " ######### #"
2804 " ######### #"
2805 " ########### "
2806 " ######### "
2807 " ####### "
2808 " ##### "
2809 " "
2810 "########### "
2811 " !#######! "
2812 ;1234567890123
2813 [end]
2814 [_point]
2815 type=0x02a
2816 subtype=0x0f
2817 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_FRENCH/French cuisine/Non NT
2818 String1=0x01,Restaurant (Français)
2819 String2=0x02,Restaurant
2820 String3=0x04,Restaurant (French)
2821 String4=0x03,Restaurant (Frans)
2822 String7=0x15,Restauracja (Francuska)
2823 String8=0x10,Restaurante francês
2824 String9=0x05,Ristorante francese
2825 ExtendedLabels=Y
2826 FontStyle=NoLabel (invisible)
2827 CustomColor=No
2828 DayXpm="15 16 3 1" Colormode=16
2829 "! c #C77400"
2830 "# c #BD956A"
2831 " c none"
2832 " ! !# ! !! "
2833 " ! !# ! !!!! "
2834 " ! !# ! #!!!!#"
2835 " ! !# ! !!!!!!"
2836 " ! !# ! !!!!!!"
2837 " ! !# ! !!!!!!"
2838 " ! !# ! !!!!!!"
2839 " !!!!!! !!!!!!"
2840 " !!!!!! !!!! "
2841 " !!!! !! "
2842 " !! !! "
2843 " !! !! "
2844 " !! !! "
2845 " !! !! "
2846 " !! !! "
2847 " !! !! "
2848 ;123456789012345
2849 [end]
2850 [_point]
2851 type=0x02a
2852 subtype=0x10
2853 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_GERMAN/German cuisine/Non NT
2854 String1=0x01,Restaurant (Allemand)
2855 String2=0x02,Restaurant (Deutsch)
2856 String3=0x04,Restaurant (German)
2857 String4=0x03,Restaurant (Duits)
2858 String7=0x15,Restauracja (Niemiecka)
2859 String8=0x10,Restaurante alemão
2860 String9=0x05,Ristorante tedesco
2861 ExtendedLabels=Y
2862 FontStyle=NoLabel (invisible)
2863 CustomColor=No
2864 DayXpm="15 16 3 1" Colormode=16
2865 "! c #C77400"
2866 "# c #BD956A"
2867 " c none"
2868 " ! !# ! !! "
2869 " ! !# ! !!!! "
2870 " ! !# ! #!!!!#"
2871 " ! !# ! !!!!!!"
2872 " ! !# ! !!!!!!"
2873 " ! !# ! !!!!!!"
2874 " ! !# ! !!!!!!"
2875 " !!!!!! !!!!!!"
2876 " !!!!!! !!!! "
2877 " !!!! !! "
2878 " !! !! "
2879 " !! !! "
2880 " !! !! "
2881 " !! !! "
2882 " !! !! "
2883 " !! !! "
2884 ;123456789012345
2885 [end]
2886 [_point]
2887 type=0x02a
2888 subtype=0x11
2889 ;GRMN_TYPE: Business - Food and Drink/RESTAURANT_BRITISH/British cuisine/Non NT
2890 String1=0x01,Restaurant (Anglais)
2891 String2=0x02,Restaurant
2892 String3=0x04,Restaurant (British)
2893 String4=0x03,Restaurant (Brits)
2894 String7=0x15,Restauracja (Angielska)
2895 String8=0x10,Restaurante inglês
2896 String9=0x05,Ristorante britannico
2897 ExtendedLabels=Y
2898 FontStyle=NoLabel (invisible)
2899 CustomColor=No
2900 DayXpm="15 16 3 1" Colormode=16
2901 "! c #C77400"
2902 "# c #BD956A"
2903 " c none"
2904 " ! !# ! !! "
2905 " ! !# ! !!!! "
2906 " ! !# ! #!!!!#"
2907 " ! !# ! !!!!!!"
2908 " ! !# ! !!!!!!"
2909 " ! !# ! !!!!!!"
2910 " ! !# ! !!!!!!"
2911 " !!!!!! !!!!!!"
2912 " !!!!!! !!!! "
2913 " !!!! !! "
2914 " !! !! "
2915 " !! !! "
2916 " !! !! "
2917 " !! !! "
2918 " !! !! "
2919 " !! !! "
2920 ;123456789012345
2921 [end]
2922 [_point]
2923 type=0x02a
2924 subtype=0x12
2925 ;GRMN_TYPE: //
2926 String1=0x01,Restaurant (Spécialités)
2927 String2=0x02,Restaurant
2928 String3=0x04,Restaurant (Special)
2929 String4=0x03,Restaurant (Speciaal)
2930 String7=0x15,Restauracja (Specjalna)
2931 String8=0x10,Restaurante especial
2932 String9=0x05,Ristorante tipico
2933 ExtendedLabels=Y
2934 FontStyle=NoLabel (invisible)
2935 CustomColor=No
2936 DayXpm="15 16 3 1" Colormode=16
2937 "! c #C77400"
2938 "# c #BD956A"
2939 " c none"
2940 " ! !# ! !! "
2941 " ! !# ! !!!! "
2942 " ! !# ! #!!!!#"
2943 " ! !# ! !!!!!!"
2944 " ! !# ! !!!!!!"
2945 " ! !# ! !!!!!!"
2946 " ! !# ! !!!!!!"
2947 " !!!!!! !!!!!!"
2948 " !!!!!! !!!! "
2949 " !!!! !! "
2950 " !! !! "
2951 " !! !! "
2952 " !! !! "
2953 " !! !! "
2954 " !! !! "
2955 " !! !! "
2956 ;123456789012345
2957 [end]
2958 [_point]
2959 type=0x02a
2960 subtype=0x13
2961 ;GRMN_TYPE: //
2962 String1=0x01,Restaurant (Végétarien)
2963 String2=0x02,Restaurant (Vegetarisch)
2964 String3=0x04,Restaurant (Vegetarian)
2965 String4=0x03,Restaurant (Vegetarisch)
2966 String7=0x15,Restauracja (Wegetariańska)
2967 String8=0x10,Restaurante vegetariano
2968 String9=0x05,Ristorante vegetariano
2969 ExtendedLabels=Y
2970 FontStyle=NoLabel (invisible)
2971 CustomColor=No
2972 DayXpm="15 16 3 1" Colormode=16
2973 "! c #C77400"
2974 "# c #BD956A"
2975 " c none"
2976 " ! !# ! !! "
2977 " ! !# ! !!!! "
2978 " ! !# ! #!!!!#"
2979 " ! !# ! !!!!!!"
2980 " ! !# ! !!!!!!"
2981 " ! !# ! !!!!!!"
2982 " ! !# ! !!!!!!"
2983 " !!!!!! !!!!!!"
2984 " !!!!!! !!!! "
2985 " !!!! !! "
2986 " !! !! "
2987 " !! !! "
2988 " !! !! "
2989 " !! !! "
2990 " !! !! "
2991 " !! !! "
2992 ;123456789012345
2993 [end]
2994 [_point]
2995 type=0x02a
2996 subtype=0x14
2997 ;GRMN_TYPE: //
2998 String1=0x01,Restaurant (Régional)
2999 String2=0x02,Restaurant
3000 String3=0x04,Restaurant (Regional)
3001 String4=0x03,Restaurant (Regionaal)
3002 String7=0x15,Restauracja (Regionalna)
3003 String8=0x10,Restaurante regional
3004 String9=0x05,Ristorante regionale
3005 ExtendedLabels=Y
3006 FontStyle=NoLabel (invisible)
3007 CustomColor=No
3008 DayXpm="15 16 3 1" Colormode=16
3009 "! c #C77400"
3010 "# c #BD956A"
3011 " c none"
3012 " ! !# ! !! "
3013 " ! !# ! !!!! "
3014 " ! !# ! #!!!!#"
3015 " ! !# ! !!!!!!"
3016 " ! !# ! !!!!!!"
3017 " ! !# ! !!!!!!"
3018 " ! !# ! !!!!!!"
3019 " !!!!!! !!!!!!"
3020 " !!!!!! !!!! "
3021 " !!!! !! "
3022 " !! !! "
3023 " !! !! "
3024 " !! !! "
3025 " !! !! "
3026 " !! !! "
3027 " !! !! "
3028 ;123456789012345
3029 [end]
3030 [_point]
3031 type=0x02b
3032 subtype=0x01
3033 ;GRMN_TYPE: Business - Lodging/HOTEL/Hotel/Non NT
3034 String1=0x01,Hôtel
3035 String2=0x02,Hotel
3036 String3=0x04,Hotel
3037 String4=0x03,Hotel
3038 String7=0x15,Hotel
3039 String8=0x10,Hotel
3040 String9=0x05,Albergo
3041 ExtendedLabels=Y
3042 FontStyle=SmallFont
3043 CustomColor=Day
3044 DaycustomColor:#0065D5
3045 DayXpm="21 10 2 1" Colormode=16
3046 "! c #0095FF"
3047 " c none"
3048 "!! "
3049 "!! "
3050 "!! !! !!!!! "
3051 "!! !! !!!!!! !! "
3052 "!! !! "
3053 "!!!!!!!!!!!!!!!! "
3054 "!!!!!!!!!!!!!!!! "
3055 "!! !! "
3056 "!! !! "
3057 "!! !! "
3058 ;123456789012345678901
3059 [end]
3060 [_point]
3061 type=0x02b
3062 subtype=0x02
3063 ;GRMN_TYPE: Business - Lodging/BED_AND_BREAKFAST/Bed and breakfast inn/Non NT
3064 String1=0x01,Chambre d'hôtes
3065 String2=0x02,Pension
3066 String3=0x04,Guesthouse
3067 String4=0x03,Bed en breakfast
3068 String7=0x15,Pensjonat
3069 String8=0x10,Pensão
3070 String9=0x05,Pensione/Bed and breakfast
3071 ExtendedLabels=Y
3072 FontStyle=SmallFont
3073 CustomColor=Day
3074 DaycustomColor:#0065D5
3075 DayXpm="17 16 3 1" Colormode=16
3076 "! c #0095FF"
3077 "# c #7BCAFF"
3078 " c none"
3079 " # "
3080 " ### "
3081 " ####### "
3082 " ########### "
3083 " ############# "
3084 " ######### "
3085 "!! ######### "
3086 "!! ######### "
3087 "!! !!!####### "
3088 "!! !!!#!!!!!! !!"
3089 "!! !!!#!!!!!!! !!"
3090 "!! ### ### !!"
3091 "!!!!!!!!!!!!!!!!!"
3092 "!!!!!!!!!!!!!!!!!"
3093 "!! ### ### !!"
3094 "!! !!"
3095 ;12345678901234567
3096 [end]
3097 [_point]
3098 type=0x02b
3099 subtype=0x05
3100 ;GRMN_TYPE: //
3101 String1=0x01,Camping
3102 String2=0x02,Campingplatz
3103 String3=0x04,Campsite
3104 String4=0x03,Camping
3105 String7=0x15,Kemping
3106 String8=0x10,Camping
3107 String9=0x05,Campeggio
3108 ExtendedLabels=Y
3109 FontStyle=SmallFont
3110 CustomColor=Day
3111 DaycustomColor:#0095FF
3112 DayXpm="22 13 2 1" Colormode=16
3113 "! c #0095FF"
3114 " c none"
3115 " !!!!!!!!!!!!!! "
3116 "!!!!!!!!!!!!!!!! "
3117 "!! !!!! !!! "
3118 "!! !!!! !! "
3119 "!! !!!! !! "
3120 "!!!!!!!!!!!!!!!!! "
3121 "!!!!!!!!!!!!!!!!! "
3122 "!!!!!!!!!!!!!!!!! "
3123 "!!!!!! !!!!!!! "
3124 "!!!!! !! !!!!!!!!! !"
3125 " !!!! !!!! !!!!!!!!! !"
3126 " !!!! "
3127 " !! "
3128 ;1234567890123456789012
3129 [end]
3130 [_point]
3131 type=0x02b
3132 subtype=0x06
3133 ;GRMN_TYPE: //
3134 String1=0x01,Abri
3135 String2=0x02,Schutzhütte
3136 String3=0x04,Shelter
3137 String4=0x03,Schuilplek
3138 String7=0x15,Schronienie
3139 String8=0x10,Cabana
3140 String9=0x05,Rifugio
3141 ExtendedLabels=Y
3142 FontStyle=NoLabel (invisible)
3143 CustomColor=No
3144 DayXpm="16 16 2 1" Colormode=16
3145 "! c #666666"
3146 " c none"
3147 " "
3148 " ! ! "
3149 " ! ! "
3150 " ! ! "
3151 " ! ! "
3152 " ! ! "
3153 " ! !! ! "
3154 " !!!! "
3155 " !!! !!! "
3156 " !!! !!! "
3157 " ! ! "
3158 " ! ! "
3159 " ! ! "
3160 " ! ! "
3161 " ! ! "
3162 " ! ! "
3163 ;1234567890123456
3164 [end]
3165 [_point]
3166 type=0x02b
3167 subtype=0x07
3168 ;GRMN_TYPE: //
3169 String1=0x01,Refuge
3170 String2=0x02,Bergschutzhütte
3171 String3=0x04,Shelter
3172 String4=0x03,Bergschuilhut
3173 String7=0x15,Schronisko
3174 String8=0x10,Cabana
3175 String9=0x05,Bivacco
3176 ExtendedLabels=Y
3177 FontStyle=SmallFont
3178 CustomColor=Day
3179 DaycustomColor:#0065D5
3180 DayXpm="14 14 2 1" Colormode=16
3181 "! c #0095FF"
3182 " c none"
3183 " !! "
3184 " !! "
3185 " !!!!! "
3186 " !!!!!!!! "
3187 " !!!!! !!!!! "
3188 "!!! !! !!!"
3189 "!!! !! !!!"
3190 " !! !! !! "
3191 " !! !! !! "
3192 " !! !!!!!! !! "
3193 " !! !!!!!! !! "
3194 " !! !! !! !! "
3195 " !! !! !! !! "
3196 " !! !!!!!! !! "
3197 ;12345678901234
3198 [end]
3199 [_point]
3200 type=0x02c
3201 subtype=0x01
3202 ;GRMN_TYPE: Business - Attractions/THEME_PARK/Amusement or theme park, i.e. Disneyland/Non NT
3203 String1=0x01,Parc d'attractions
3204 String2=0x02,Freizeitpark
3205 String3=0x04,Themepark
3206 String4=0x03,Attractiepark
3207 String7=0x15,Park rozrywki
3208 String8=0x10,Parque temático / diversão
3209 String9=0x05,Parco a tema
3210 ExtendedLabels=Y
3211 FontStyle=SmallFont
3212 CustomColor=Day
3213 DaycustomColor:#006500
3214 DayXpm="1 1 2 1" Colormode=16
3215 "! c #009500"
3216 " c none"
3217 " "
3218 ;1
3219 [end]
3220 [_point]
3221 type=0x02c
3222 subtype=0x02
3223 ;GRMN_TYPE: Business - Attractions/MUSEUM/Museum or historical society/Non NT
3224 String1=0x01,Musée
3225 String2=0x02,Museum
3226 String3=0x04,Museum
3227 String4=0x03,Museum
3228 String7=0x15,Muzeum
3229 String8=0x10,Museu
3230 String9=0x05,Museo
3231 ExtendedLabels=Y
3232 FontStyle=SmallFont
3233 CustomColor=Day
3234 DaycustomColor:#734A08
3235 DayXpm="20 13 2 1" Colormode=16
3236 "! c #734A08"
3237 " c none"
3238 " !! "
3239 " !!!!!! "
3240 " !!!!!!!!!! "
3241 " !!!!!!!!!!!!!! "
3242 " "
3243 " !!!!!!!!!!!!!! "
3244 " !!! !!!! !!! "
3245 " !! !! !! "
3246 " !! !! !! "
3247 " !! !! !! "
3248 " !! !! !! "
3249 " !!!!!!!!!!!!!! "
3250 "!!!!!!!!!!!!!!!! "
3251 ;12345678901234567890
3252 [end]
3253 [_point]
3254 type=0x02c
3255 subtype=0x03
3256 ;GRMN_TYPE: Business - Attractions/LIBRARY/Library/Non NT
3257 String1=0x01,Bibliothèque
3258 String2=0x02,Bibliothek
3259 String3=0x04,Library
3260 String4=0x03,Bibliotheek
3261 String7=0x15,Biblioteka
3262 String8=0x10,Biblioteca
3263 String9=0x05,Biblioteca
3264 ExtendedLabels=Y
3265 FontStyle=SmallFont
3266 CustomColor=Day
3267 DaycustomColor:#734A08
3268 DayXpm="20 12 2 1" Colormode=16
3269 "! c #734A08"
3270 " c none"
3271 "! ! "
3272 "! !!! !!! ! "
3273 "! !!!!! !!!!! ! "
3274 "! !!!!! !!!!! ! "
3275 "! !!!!! !!!!! ! "
3276 "! !!!!! !!!!! ! "
3277 "! !!!!! !!!!! ! "
3278 "! !!!! !!!! ! "
3279 "! !! !! ! "
3280 "!!! !!! "
3281 " !! !! "
3282 " !!!!! "
3283 ;12345678901234567890
3284 [end]
3285 [_point]
3286 type=0x02c
3287 subtype=0x04
3288 ;GRMN_TYPE: Business - Attractions/LANDMARK/Landmark/Non NT
3289 String1=0x01,Point de vue, œuvre d'art, attraction
3290 String2=0x02,Aussichtspunkt, Kunstwerk, Attraktion
3291 String3=0x04,Artwork,Attraction, Viewpoint
3292 String4=0x03,Bezienswaardigheid
3293 String7=0x15,Sztuka, Atrakcja, Punkt widokowy
3294 String8=0x10,Atração
3295 String9=0x05,Opera/Veduta
3296 ExtendedLabels=Y
3297 FontStyle=SmallFont
3298 CustomColor=Day
3299 DaycustomColor:#734A08
3300 DayXpm="12 17 2 1" Colormode=16
3301 "! c #734A08"
3302 " c none"
3303 " !! "
3304 " !!!! "
3305 " !!!! "
3306 " !! "
3307 " "
3308 " !!!!!! "
3309 " !!!!!! "
3310 " !!!!!! "
3311 " !!!! "
3312 " !! "
3313 " !! "
3314 " !! "
3315 " "
3316 " !!!!!! "
3317 " "
3318 "!!!!!!!! "
3319 "!!!!!!!! "
3320 ;123456789012
3321 [end]
3322 [_point]
3323 type=0x02c
3324 subtype=0x05
3325 ;GRMN_TYPE: Business - Attractions/SCHOOL/School/Non NT
3326 String1=0x01,École
3327 String2=0x02,Schule
3328 String3=0x04,Education
3329 String4=0x03,Educatie
3330 String7=0x15,Edukacja
3331 String8=0x10,Escola
3332 String9=0x05,Scuola
3333 ExtendedLabels=Y
3334 FontStyle=NormalFont
3335 CustomColor=Day
3336 DaycustomColor:#4D4D00
3337 DayXpm="1 1 2 1" Colormode=16
3338 "! c #009500"
3339 " c none"
3340 " "
3341 ;1
3342 [end]
3343 [_point]
3344 type=0x02c
3345 subtype=0x06
3346 ;GRMN_TYPE: Business - Attractions/GARDEN, PARK/Garden, park/Non NT
3347 String1=0x01,Aire de jeu
3348 String2=0x02,Spielplatz
3349 String3=0x04,Playground
3350 String4=0x03,Speelplaats
3351 String7=0x15,Plac zabaw
3352 String8=0x10,Parque infantil
3353 String9=0x05,Parco giochi
3354 ExtendedLabels=Y
3355 FontStyle=NoLabel (invisible)
3356 CustomColor=No
3357 DayXpm="18 17 2 1" Colormode=16
3358 "! c #009500"
3359 " c none"
3360 " !! "
3361 " !!!! "
3362 " !!!! !! "
3363 " !! !!!! "
3364 " !!!! "
3365 " !! !! "
3366 " !! "
3367 " !!!! !! "
3368 " !!!! !! "
3369 "!!!!!!! !!!! "
3370 "!!!!!!!!!! !!!! "
3371 " !!!!!!!!!!!!!"
3372 " !! !!!!!!"
3373 " !! "
3374 " !!!! "
3375 " !!!!!! "
3376 " !!!!!!!! "
3377 ;123456789012345678
3378 [end]
3379 [_point]
3380 type=0x02c
3381 subtype=0x07
3382 ;GRMN_TYPE: Business - Attractions/ZOO/Zoo/Non NT
3383 String1=0x01,Zoo
3384 String2=0x02,Zoo
3385 String3=0x04,Zoo
3386 String4=0x03,Dierentuin
3387 String7=0x15,Zoo
3388 String8=0x10,Zoológico
3389 String9=0x05,Zoo/Acquario
3390 ExtendedLabels=Y
3391 FontStyle=NormalFont
3392 CustomColor=Day
3393 DaycustomColor:#660033
3394 DayXpm="1 1 2 1" Colormode=16
3395 "! c #009500"
3396 " c none"
3397 " "
3398 ;1
3399 [end]
3400 [_point]
3401 type=0x02c
3402 subtype=0x08
3403 ;GRMN_TYPE: Business - Attractions/ARENA/Arena or track/Non NT
3404 String1=0x01,Sport
3405 String2=0x02,Sport
3406 String3=0x04,Sport
3407 String4=0x03,Sport
3408 String7=0x15,Sport
3409 String8=0x10,Esporte
3410 String9=0x05,Sport
3411 ExtendedLabels=Y
3412 FontStyle=SmallFont
3413 CustomColor=Day
3414 DaycustomColor:#3D9171
3415 DayXpm="1 1 2 1" Colormode=16
3416 "! c #009500"
3417 " c none"
3418 " "
3419 ;1
3420 [end]
3421 [_point]
3422 type=0x02c
3423 subtype=0x09
3424 ;GRMN_TYPE: Business - Attractions/HALL/Auditorium or hall/Non NT
3425 String1=0x01,Auditorium
3426 String2=0x02,Konferenzzentrum
3427 String3=0x04,Conference
3428 String4=0x03,Conferentiecentrum
3429 String7=0x15,Centrum konferencyjne
3430 String8=0x10,Conferência
3431 String9=0x05,Fiera
3432 ExtendedLabels=Y
3433 FontStyle=NoLabel (invisible)
3434 CustomColor=No
3435 DayXpm="1 1 2 1" Colormode=16
3436 "! c #00FF4B"
3437 " c none"
3438 " "
3439 ;1
3440 [end]
3441 [_point]
3442 type=0x02c
3443 subtype=0x0a
3444 ;GRMN_TYPE: Business - Attractions/WINERY/Winery/Non NT
3445 String1=0x01,Cave à vin
3446 String2=0x02,Weinkeller
3447 String3=0x04,Winery
3448 String4=0x03,Wijnmaker
3449 String7=0x15,Winiarnia
3450 String8=0x10,Adega
3451 String9=0x05,Cantina
3452 ExtendedLabels=Y
3453 FontStyle=NoLabel (invisible)
3454 CustomColor=No
3455 DayXpm="1 1 2 1" Colormode=16
3456 "! c #00FF4B"
3457 " c none"
3458 " "
3459 ;1
3460 [end]
3461 [_point]
3462 type=0x02c
3463 subtype=0x0b
3464 ;GRMN_TYPE: Business - Attractions/PLACE_OF_WORSHIP/Religious place of worship/Non NT
3465 String1=0x01,Lieu de culte
3466 String2=0x02,Religiöses Gebäude
3467 String3=0x04,Religious building
3468 String4=0x03,Gebedshuis
3469 String7=0x15,Budynek religijny
3470 String8=0x10,Edifício religioso
3471 String9=0x05,Luogo di culto
3472 ExtendedLabels=Y
3473 FontStyle=SmallFont
3474 CustomColor=Day
3475 DaycustomColor:#000000
3476 DayXpm="12 15 2 1" Colormode=16
3477 "! c #000000"
3478 " c none"
3479 " !! "
3480 " !!!! "
3481 " !!!! "
3482 " !! "
3483 " ! "
3484 "!! !!!! "
3485 " !!!!!!!! "
3486 " !! !!!! "
3487 " !!!! "
3488 " !!!! "
3489 " !!!! "
3490 " !!! "
3491 " !!! "
3492 " !!!!!!! "
3493 " !!!!!!!!"
3494 ;123456789012
3495 [end]
3496 [_point]
3497 type=0x02c
3498 subtype=0x0c
3499 ;GRMN_TYPE: //
3500 String1=0x01,Volcan
3501 String2=0x02,Vulkan
3502 String3=0x04,Vulcano
3503 String4=0x03,Vulkaan
3504 String7=0x15,Wulkan
3505 String8=0x10,Vulcão
3506 String9=0x05,Vulcano
3507 ExtendedLabels=Y
3508 FontStyle=SmallFont
3509 CustomColor=Day
3510 DaycustomColor:#BD3000
3511 DayXpm="14 10 2 1" Colormode=16
3512 "! c #D40000"
3513 " c none"
3514 " ! "
3515 " ! "
3516 " !!! "
3517 " !!! "
3518 " !!!!! "
3519 " !!!!! "
3520 " !!!!!!! "
3521 " !!!!!!! "
3522 "!!!!!!!!! "
3523 "!!!!!!!!! "
3524 ;12345678901234
3525 [end]
3526 [_point]
3527 type=0x02c
3528 subtype=0x0d
3529 ;GRMN_TYPE: Business - Attractions/POW_MOSQUE/Religious place of worship/Non NT
3530 String1=0x01,Attraction touristique
3531 String2=0x02,Touristenattraktion
3532 String3=0x04,Tourist attraction
3533 String4=0x03,Touristische attractie
3534 String7=0x15,Atrakcja turystyczna
3535 String8=0x10,Atração turística
3536 String9=0x05,Attrazione turistica
3537 ExtendedLabels=Y
3538 FontStyle=SmallFont
3539 CustomColor=Day
3540 DaycustomColor:#660033
3541 DayXpm="10 5 2 1" Colormode=16
3542 "! c #660033"
3543 " c none"
3544 " !!! "
3545 "!!!!! "
3546 "!!!!! "
3547 "!!!!! "
3548 " !!! "
3549 ;1234567890
3550 [end]
3551 [_point]
3552 type=0x02d
3553 subtype=0x01
3554 ;GRMN_TYPE: Business - Entertainment/LIVE_THEATER/Live theater/Non NT
3555 String1=0x01,Théâtre
3556 String2=0x02,Theater
3557 String3=0x04,Theatre
3558 String4=0x03,Theater
3559 String7=0x15,Teatr
3560 String8=0x10,Teatro
3561 String9=0x05,Teatro
3562 ExtendedLabels=Y
3563 FontStyle=SmallFont
3564 CustomColor=Day
3565 DaycustomColor:#734A08
3566 DayXpm="18 13 2 1" Colormode=16
3567 "! c #734A08"
3568 " c none"
3569 "!!!!!!!! "
3570 "! ! "
3571 "! ! ! ! "
3572 "! !!!!!!!! "
3573 "! ! !!!!!!!!! "
3574 "! ! !!! !! !! "
3575 "! !! !!!!!!!! "
3576 "! !!!!!!!! "
3577 " ! !!! !!! "
3578 " !!!!!! !! !! "
3579 " !! !! !! "
3580 " !!!!!! "
3581 " !!!! "
3582 ;123456789012345678
3583 [end]
3584 [_point]
3585 type=0x02d
3586 subtype=0x02
3587 ;GRMN_TYPE: Business - Entertainment/BAR/Bar or club/Non NT
3588 String1=0x01,Bar
3589 String2=0x02,Bar
3590 String3=0x04,Bar
3591 String4=0x03,Bar
3592 String7=0x15,Bar
3593 String8=0x10,Bar
3594 String9=0x05,Bar
3595 ExtendedLabels=Y
3596 FontStyle=NoLabel (invisible)
3597 CustomColor=No
3598 DayXpm="13 12 2 1" Colormode=16
3599 "! c #C77400"
3600 " c none"
3601 "!!!!!!!!!!!!!"
3602 " !!!!!!!!!!! "
3603 " !!!!!!!!! "
3604 " !!!!!!! "
3605 " !!!!! "
3606 " !!! "
3607 " ! "
3608 " ! "
3609 " ! "
3610 " ! "
3611 " !!! "
3612 " !!!!!!! "
3613 ;1234567890123
3614 [end]
3615 [_point]
3616 type=0x02d
3617 subtype=0x03
3618 ;GRMN_TYPE: Business - Entertainment/MOVIE_THEATER/Movie theater or cinema/Non NT
3619 String1=0x01,Cinéma
3620 String2=0x02,Kino
3621 String3=0x04,Cinema
3622 String4=0x03,Bioscoop
3623 String7=0x15,Kino
3624 String8=0x10,Cinema
3625 String9=0x05,Cinema
3626 ExtendedLabels=Y
3627 FontStyle=SmallFont
3628 CustomColor=Day
3629 DaycustomColor:#734A08
3630 DayXpm="16 13 2 1" Colormode=16
3631 "! c #734A08"
3632 " c none"
3633 "!!!!!!!!!!!! "
3634 "! ! ! ! "
3635 "!!! !!! "
3636 "! ! ! ! "
3637 "!!! !!! "
3638 "! ! ! ! "
3639 "!!!!!!!!!!!! "
3640 "! ! ! ! "
3641 "!!! !!! "
3642 "! ! ! ! "
3643 "!!! !!! "
3644 "! ! ! ! "
3645 "!!!!!!!!!!!! "
3646 ;1234567890123456
3647 [end]
3648 [_point]
3649 type=0x02d
3650 subtype=0x04
3651 ;GRMN_TYPE: Business - Entertainment/CASINO/Casino/Non NT
3652 String1=0x01,Casino
3653 String2=0x02,Casino
3654 String3=0x04,Casino
3655 String4=0x03,Casino
3656 String7=0x15,Kasyno
3657 String8=0x10,Cassino
3658 String9=0x05,Sala da gioco
3659 ExtendedLabels=Y
3660 FontStyle=SmallFont
3661 CustomColor=Day
3662 DaycustomColor:#734A08
3663 DayXpm="16 15 2 1" Colormode=16
3664 "! c #734A08"
3665 " c none"
3666 " !!! "
3667 " !!!!! "
3668 " !!! !! "
3669 " !!!! !!! "
3670 "!!!!!!!!!!! "
3671 "!!!!!!! "
3672 "!! !! !!!!!!! "
3673 "!! !! !!!!!!!!!"
3674 " !!!!! !!!!! !!"
3675 " !!!! !!!!! !!"
3676 " !!! !!!!!!!!!"
3677 " !! !! !!!!!"
3678 " !! !!!!!"
3679 " !!!!!!!!!"
3680 " !!!!!!! "
3681 ;1234567890123456
3682 [end]
3683 [_point]
3684 type=0x02d
3685 subtype=0x05
3686 ;GRMN_TYPE: Business - Entertainment/GOLF_COURSE/Golf course/Non NT
3687 String1=0x01,Golf
3688 String2=0x02,Golfplatz
3689 String3=0x04,Golf course
3690 String4=0x03,Golfbaan
3691 String7=0x15,Golf
3692 String8=0x10,Campo de golfe
3693 String9=0x05,Campo da golf
3694 ExtendedLabels=Y
3695 FontStyle=SmallFont
3696 CustomColor=Day
3697 DaycustomColor:#009500
3698 DayXpm="19 18 2 1" Colormode=16
3699 "! c #009500"
3700 " c none"
3701 " !! "
3702 "! !! "
3703 "!! !! "
3704 "!!! !! !! "
3705 "!!!! !!!! !! "
3706 "!!!!! !!!! !! "
3707 "!!!! !! !! "
3708 "!!! !! "
3709 "!! !!!! "
3710 "! !!!! "
3711 "! !!!! "
3712 "! !!!! "
3713 "! !!!! "
3714 "! !! !! "
3715 "! !! !! "
3716 "! !! !! "
3717 "! !! !! "
3718 "! !! !! "
3719 ;1234567890123456789
3720 [end]
3721 [_point]
3722 type=0x02d
3723 subtype=0x06
3724 ;GRMN_TYPE: Business - Entertainment/SKI_CENTER/Ski area or resort/Non NT
3725 String1=0x01,Ski
3726 String2=0x02,Ski
3727 String3=0x04,Ski
3728 String4=0x03,Ski
3729 String7=0x15,Narty
3730 String8=0x10,Esqui
3731 String9=0x05,Centro sciistico
3732 ExtendedLabels=Y
3733 FontStyle=SmallFont
3734 CustomColor=Day
3735 DaycustomColor:#009500
3736 DayXpm="16 13 2 1" Colormode=16
3737 "! c #009500"
3738 " c none"
3739 " ! "
3740 " !!! "
3741 " !!!!! ! "
3742 " !!!!!! !!!"
3743 " !! !!! !!!"
3744 " !! !! ! "
3745 "!! !!! ! "
3746 "!!!! !! !! "
3747 " !!!! "
3748 " !!!! "
3749 " !!!! "
3750 " !!!! ! "
3751 " !!!!! "
3752 ;1234567890123456
3753 [end]
3754 [_point]
3755 type=0x02d
3756 subtype=0x07
3757 ;GRMN_TYPE: Business - Entertainment/BOWLING/Bowling alley/Non NT
3758 String1=0x01,Bowling
3759 String2=0x02,Bowling
3760 String3=0x04,Bowling alley
3761 String4=0x03,Bowlingbaan
3762 String7=0x15,Kręgle
3763 String8=0x10,Boliche
3764 String9=0x05,Sala da bowling
3765 ExtendedLabels=Y
3766 FontStyle=SmallFont
3767 CustomColor=Day
3768 DaycustomColor:#009500
3769 DayXpm="18 16 2 1" Colormode=16
3770 "! c #009500"
3771 " c none"
3772 " !! "
3773 " !!!! "
3774 " !!!! "
3775 " !! "
3776 " "
3777 " !! "
3778 " "
3779 " !!! !! "
3780 " !!! !!! !!!! "
3781 " !!! !! !!!!!! "
3782 "!!!!!!!!! !!!!! "
3783 "!!!! ! ! !!!!! "
3784 "!!! ! !! !!!!! "
3785 " !!!!!!! !!!!!! "
3786 " !!!!!!! !!!!!! "
3787 " !!! !!!! "
3788 ;123456789012345678
3789 [end]
3790 [_point]
3791 type=0x02d
3792 subtype=0x08
3793 ;GRMN_TYPE: Business - Entertainment/ICE_SKATING/Ice skating rink/Non NT
3794 String1=0x01,Patinoire
3795 String2=0x02,Eisbahn
3796 String3=0x04,Ice skating
3797 String4=0x03,Schaatsbaan
3798 String7=0x15,Lodowisko
3799 String8=0x10,Patinação no gelo
3800 String9=0x05,Pista di pattinaggio
3801 ExtendedLabels=Y
3802 FontStyle=SmallFont
3803 CustomColor=Day
3804 DaycustomColor:#009500
3805 DayXpm="15 12 3 1" Colormode=16
3806 "! c #009500"
3807 "# c #009500"
3808 " c none"
3809 " ##### "
3810 " #!!!! "
3811 " #!!!! "
3812 " #!!!!! "
3813 " #!!!!!!! "
3814 " #!!!!!!!!! "
3815 " #!!!!!!!!!! "
3816 " !!!!!!!!!! "
3817 " ! ! "
3818 " ! ! #"
3819 "###!!!!!!!!!###"
3820 "############## "
3821 ;123456789012345
3822 [end]
3823 [_point]
3824 type=0x02d
3825 subtype=0x09
3826 ;GRMN_TYPE: Business - Entertainment/SWIMMING_POOL/Swimming pool/Non NT
3827 String1=0x01,Piscine
3828 String2=0x02,Schwimmbad
3829 String3=0x04,Swimmingpool
3830 String4=0x03,Zwembad
3831 String7=0x15,Basen
3832 String8=0x10,Piscina
3833 String9=0x05,Piscina
3834 ExtendedLabels=Y
3835 FontStyle=SmallFont
3836 CustomColor=Day
3837 DaycustomColor:#009500
3838 DayXpm="19 13 2 1" Colormode=16
3839 "! c #009500"
3840 " c none"
3841 " !! "
3842 " !!!! "
3843 " !!! "
3844 " !! !! "
3845 " !!! !!!! "
3846 " !!! !!!! "
3847 " !!!!!! !! "
3848 " !!!!!!!!! "
3849 " ! !!! ! "
3850 " "
3851 " !!! !!! !!! "
3852 "!!!!!!!!!!!!!!! "
3853 "! !! !! ! "
3854 ;1234567890123456789
3855 [end]
3856 [_point]
3857 type=0x02d
3858 subtype=0x0a
3859 ;GRMN_TYPE: Business - Entertainment/FITNESS_CENTER/Fitness center or gym/Non NT
3860 String1=0x01,Centre sportif
3861 String2=0x02,Sportzentrum
3862 String3=0x04,Sports centre
3863 String4=0x03,Sportcentrum
3864 String7=0x15,Centrum sportowe
3865 String8=0x10,Centro esportivo
3866 String9=0x05,Centro sportivo
3867 ExtendedLabels=Y
3868 FontStyle=Default
3869 CustomColor=Day
3870 DaycustomColor:#006500
3871 DayXpm="1 1 2 1" Colormode=16
3872 "! c #009500"
3873 " c none"
3874 " "
3875 ;1
3876 [end]
3877 [_point]
3878 type=0x02d
3879 subtype=0x0b
3880 ;GRMN_TYPE: Business - Entertainment/SPORT_AIRPORT/Sport or R-C airport/Non NT
3881 String1=0x01,Aéroport
3882 String2=0x02,Flughafen
3883 String3=0x04,Airport
3884 String4=0x03,Luchthaven
3885 String7=0x15,Lotnisko
3886 String8=0x10,Aeroporto
3887 String9=0x05,Aerodromo
3888 ExtendedLabels=Y
3889 FontStyle=NormalFont
3890 CustomColor=Day
3891 DaycustomColor:#8461C4
3892 DayXpm="16 16 2 1" Colormode=16
3893 "! c #8461C4"
3894 " c none"
3895 " !! "
3896 " !! "
3897 " !! "
3898 " !! "
3899 " !! "
3900 " !!!! "
3901 " !!!!!!!! "
3902 " !!!!!!!!!!!! "
3903 " !!!!!!!!!!!!!! "
3904 "!!!! !! !!!!"
3905 " !! "
3906 " !! "
3907 " !! "
3908 " !!!! "
3909 " !!!!!!!! "
3910 " !!!! !!!! "
3911 ;1234567890123456
3912 [end]
3913 [_point]
3914 type=0x02e
3915 subtype=0x01
3916 ;GRMN_TYPE: Business - Shopping/DEPARTMENT_STORE/Department store/Non NT
3917 String1=0x01,Hypermarché
3918 String2=0x02,Kaufhaus
3919 String3=0x04,Mall
3920 String4=0x03,Warenhuis
3921 String7=0x15,Centrum handlowe
3922 String8=0x10,Shopping Center
3923 String9=0x05,Grande magazzino
3924 ExtendedLabels=Y
3925 FontStyle=NoLabel (invisible)
3926 CustomColor=No
3927 DayXpm="14 17 2 1" Colormode=16
3928 "! c #BD30B4"
3929 " c none"
3930 " !!!!!! "
3931 " !!!!!! "
3932 " ! ! "
3933 " ! ! "
3934 " ! ! "
3935 "!!!!!!!!!!!!!!"
3936 "!!!!!!!!!!!!!!"
3937 "!!!!!!!!!!!!!!"
3938 "!!!!!! !!!!!!"
3939 "!!!!! !! !!!!!"
3940 "!!!!! ! !!!!!"
3941 "!!!!! !!!!!!"
3942 "!!!! !! !!!!"
3943 "!!!! !!! !!!!"
3944 "!!!! !!!"
3945 "!!!!!!!!!!!!!!"
3946 "!!!!!!!!!!!!!!"
3947 ;12345678901234
3948 [end]
3949 [_point]
3950 type=0x02e
3951 subtype=0x02
3952 ;GRMN_TYPE: Business - Shopping/GROCERY_STORE/Grocery store/Non NT
3953 String1=0x01,Boulangerie
3954 String2=0x02,Bäckerei
3955 String3=0x04,Backery
3956 String4=0x03,Bakker
3957 String7=0x15,Piekarnia
3958 String8=0x10,Padaria
3959 String9=0x05,Alimentari/Drogheria
3960 ExtendedLabels=Y
3961 FontStyle=NoLabel (invisible)
3962 CustomColor=No
3963 DayXpm="14 8 2 1" Colormode=16
3964 "! c #BD30B4"
3965 " c none"
3966 " ! ! ! !! "
3967 " !! !! !! ! "
3968 " !! ! ! !! "
3969 "!!! !! !! !!!"
3970 "!!!!!!!!!!!!!!"
3971 "!!!!!!!!!!!!!!"
3972 "!!!!!!!!!!!!!!"
3973 " !!!!!!!!!!!! "
3974 ;12345678901234
3975 [end]
3976 [_point]
3977 type=0x02e
3978 subtype=0x03
3979 ;GRMN_TYPE: Business - Shopping/GENERAL_STORE/General store/Non NT
3980 String1=0x01,Supermarché
3981 String2=0x02,Supermarkt
3982 String3=0x04,Generic store
3983 String4=0x03,Algemeen
3984 String7=0x15,Supermarket
3985 String8=0x10,Loja
3986 String9=0x05,Supermercato
3987 ExtendedLabels=Y
3988 FontStyle=NoLabel (invisible)
3989 CustomColor=No
3990 DayXpm="13 11 2 1" Colormode=16
3991 "! c #BD30B4"
3992 " c none"
3993 " ! "
3994 " !! "
3995 " !! "
3996 " ! "
3997 "!!!!!!!!!!!!!"
3998 "!! ! ! !!"
3999 " !!!!!!!!!!! "
4000 " ! ! ! ! "
4001 " !!!!!!!!!!! "
4002 " !! ! ! "
4003 " !!!!!!!!! "
4004 ;1234567890123
4005 [end]
4006 [_point]
4007 type=0x02e
4008 subtype=0x04
4009 ;GRMN_TYPE: Business - Shopping/SHOPPING_CENTER/Shopping center or mall/Non NT
4010 String1=0x01,Centre commercial
4011 String2=0x02,Einkaufszentrum
4012 String3=0x04,Shopping center
4013 String4=0x03,Winkelcentrum
4014 String7=0x15,Centrum handlowe
4015 String8=0x10,Shopping Center
4016 String9=0x05,Centro commerciale
4017 ExtendedLabels=Y
4018 FontStyle=NoLabel (invisible)
4019 CustomColor=No
4020 DayXpm="14 17 2 1" Colormode=16
4021 "! c #BD30B4"
4022 " c none"
4023 " !!!!!! "
4024 " !!!!!! "
4025 " ! ! "
4026 " ! ! "
4027 " ! ! "
4028 "!!!!!!!!!!!!!!"
4029 "!!!!!!!!!!!!!!"
4030 "!!!!!!!!!!!!!!"
4031 "!!!!!! !!!!!!"
4032 "!!!!! !! !!!!!"
4033 "!!!!! ! !!!!!"
4034 "!!!!! !!!!!!"
4035 "!!!! !! !!!!"
4036 "!!!! !!! !!!!"
4037 "!!!! !!!"
4038 "!!!!!!!!!!!!!!"
4039 "!!!!!!!!!!!!!!"
4040 ;12345678901234
4041 [end]
4042 [_point]
4043 type=0x02e
4044 subtype=0x05
4045 ;GRMN_TYPE: Business - Shopping/PHARMACY/Pharmacy/Non NT
4046 String1=0x01,Pharmacie
4047 String2=0x02,Apotheke
4048 String3=0x04,Pharmacy
4049 String4=0x03,Apotheek
4050 String7=0x15,Apteka
4051 String8=0x10,Farmácia
4052 String9=0x05,Farmacia
4053 ExtendedLabels=Y
4054 FontStyle=NoLabel (invisible)
4055 CustomColor=No
4056 DayXpm="10 14 2 1" Colormode=16
4057 "! c #BF0000"
4058 " c none"
4059 " !!!!!! "
4060 " !!!!!! "
4061 " !!!!!! "
4062 " "
4063 " !!!!!!!! "
4064 "!!!!!!!!!!"
4065 "!!!! !!!!"
4066 "!!!! !!!!"
4067 "!! !!"
4068 "!! !!"
4069 "!!!! !!!!"
4070 "!!!! !!!!"
4071 "!!!!!!!!!!"
4072 "!!!!!!!!!!"
4073 ;1234567890
4074 [end]
4075 [_point]
4076 type=0x02e
4077 subtype=0x06
4078 ;GRMN_TYPE: Business - Shopping/CONVENIENCE_STORE/Convenience store/Non NT
4079 String1=0x01,Station-service
4080 String2=0x02,Tankstellenshop
4081 String3=0x04,Gasstation shop
4082 String4=0x03,Tankstation shop
4083 String7=0x15,Sklep na stacji paliw
4084 String8=0x10,Loja de conveniência
4085 String9=0x05,Negozio
4086 ExtendedLabels=Y
4087 FontStyle=NoLabel (invisible)
4088 CustomColor=No
4089 DayXpm="5 5 2 1" Colormode=16
4090 "! c #BD30B4"
4091 " c none"
4092 " !!! "
4093 "!!!!!"
4094 "!!!!!"
4095 "!!!!!"
4096 " !!! "
4097 ;12345
4098 [end]
4099 [_point]
4100 type=0x02e
4101 subtype=0x07
4102 ;GRMN_TYPE: Business - Shopping/CLOTHING_RETAIL/Clothing store/Non NT
4103 String1=0x01,Magasin de vêtements
4104 String2=0x02,Bekleidungsgeschäft
4105 String3=0x04,Clothing store
4106 String4=0x03,Kleding
4107 String7=0x15,Sklep odzieżowy
4108 String8=0x10,Loja de roupas
4109 String9=0x05,Negozio di abbigliamento
4110 ExtendedLabels=Y
4111 FontStyle=NoLabel (invisible)
4112 CustomColor=No
4113 DayXpm="14 11 2 1" Colormode=16
4114 "! c #BD30B4"
4115 " c none"
4116 " !!! !!! "
4117 " !!!!! !!!!! "
4118 " !!!!!!!!!!!! "
4119 "!!!!!!!!!!!!!!"
4120 "!!!!!!!!!!!!!!"
4121 " !!!!!!!! "
4122 " !!!!!!!! "
4123 " !!!!!!!! "
4124 " !!!!!!!! "
4125 " !!!!!!!! "
4126 " !!!!!!!! "
4127 ;12345678901234
4128 [end]
4129 [_point]
4130 type=0x02e
4131 subtype=0x08
4132 ;GRMN_TYPE: Business - Shopping/HOME_AND_GARDEN_STORE/House and garden store/Non NT
4133 String1=0x01,Jardinerie
4134 String2=0x02,Gartencentrum
4135 String3=0x04,Garden center
4136 String4=0x03,Huis- en tuin
4137 String7=0x15,Centrum ogrodnicze
4138 String8=0x10,Loja de jardinagem
4139 String9=0x05,Negozio di giardinaggio
4140 ExtendedLabels=Y
4141 FontStyle=NoLabel (invisible)
4142 CustomColor=No
4143 DayXpm="16 15 2 1" Colormode=16
4144 "! c #BD30B4"
4145 " c none"
4146 " !!! "
4147 " !!!!! "
4148 " !! !! "
4149 " !! !!"
4150 " !! !! !!"
4151 " !!! !! !!"
4152 "!!!! !!!!!!!!!"
4153 "!!!!! !!!!!!!!!"
4154 " !!! !!!!!!!!!"
4155 " !!!!!!!!!!!!"
4156 " !!!!!!!!!! "
4157 " !!!!!!!!! "
4158 " !!!!!!!! "
4159 " !!!!!! "
4160 " !!!!! "
4161 ;1234567890123456
4162 [end]
4163 [_point]
4164 type=0x02e
4165 subtype=0x09
4166 ;GRMN_TYPE: Business - Shopping/HOME_FURNISHINGS_STORE/Furniture store/Non NT
4167 String1=0x01,Magasin d’ameublement
4168 String2=0x02,Möbelgeschäft
4169 String3=0x04,Furniture
4170 String4=0x03,Meubels
4171 String7=0x15,Meble
4172 String8=0x10,Loja de móveis
4173 String9=0x05,Negozio di arredamento
4174 ExtendedLabels=Y
4175 FontStyle=NoLabel (invisible)
4176 CustomColor=No
4177 DayXpm="14 10 2 1" Colormode=16
4178 "! c #BD30B4"
4179 " c none"
4180 " !!!!!!!!!! "
4181 " !!!!!!!!!!!! "
4182 " !!!!!!!! "
4183 "!! !!!!!!!! !!"
4184 "!!! !!!!!! !!!"
4185 " !! !! "
4186 " !!!!!!!!!!!! "
4187 " !!!!!!!!!!!! "
4188 " !!!!!!!!!!!! "
4189 " !!! !!! "
4190 ;12345678901234
4191 [end]
4192 [_point]
4193 type=0x02e
4194 subtype=0x0a
4195 ;GRMN_TYPE: Business - Shopping/SPECIALTY_RETAIL/Specialty store/Non NT
4196 String1=0x01,Magasin
4197 String2=0x02,Geschäft
4198 String3=0x04,Shop
4199 String4=0x03,Winkel
4200 String7=0x15,Sklep
4201 String8=0x10,Loja
4202 String9=0x05,Negozio
4203 ExtendedLabels=Y
4204 FontStyle=NoLabel (invisible)
4205 CustomColor=No
4206 DayXpm="5 5 2 1" Colormode=16
4207 "! c #BD30B4"
4208 " c none"
4209 " !!! "
4210 "!!!!!"
4211 "!!!!!"
4212 "!!!!!"
4213 " !!! "
4214 ;12345
4215 [end]
4216 [_point]
4217 type=0x02e
4218 subtype=0x0b
4219 ;GRMN_TYPE: Business - Shopping/SOFTWARE_RETAIL/Computer software store/Non NT
4220 String1=0x01,Magasin d’électronique
4221 String2=0x02,Computerhandel
4222 String3=0x04,Electronics
4223 String4=0x03,Elektronica
4224 String7=0x15,Elektronika
4225 String8=0x10,Loja de eletrônicos
4226 String9=0x05,Negozio di elettronica
4227 ExtendedLabels=Y
4228 FontStyle=NoLabel (invisible)
4229 CustomColor=No
4230 DayXpm="14 14 2 1" Colormode=16
4231 "! c #BD30B4"
4232 " c none"
4233 " !! !! "
4234 " !! !! "
4235 " !!!! "
4236 " !! "
4237 " !!!!!!!!!!!! "
4238 "!!!!!!!!!!!!!!"
4239 "!!! !! !"
4240 "!! ! !"
4241 "!! !!!!"
4242 "!! ! !"
4243 "!! ! !"
4244 "!!! !!!!!"
4245 "!!!!!!!!!!!!!!"
4246 " !!!!!!!!!!!! "
4247 ;12345678901234
4248 [end]
4249 [_point]
4250 type=0x02e
4251 subtype=0x0c
4252 ;GRMN_TYPE: //
4253 String1=0x01,Magasin
4254 String2=0x02,Geschäft
4255 String3=0x04,Shop
4256 String4=0x03,Winkel
4257 String7=0x15,Sklep
4258 String8=0x10,Loja
4259 String9=0x05,Negozio
4260 ExtendedLabels=Y
4261 FontStyle=NoLabel (invisible)
4262 CustomColor=No
4263 DayXpm="5 5 2 1" Colormode=16
4264 "! c #BD30B4"
4265 " c none"
4266 " !!! "
4267 "!!!!!"
4268 "!!!!!"
4269 "!!!!!"
4270 " !!! "
4271 ;12345
4272 [end]
4273 [_point]
4274 type=0x02f
4275 subtype=0x01
4276 ;GRMN_TYPE: Business - Services/GAS_STATION/Gas, fuel station/Non NT
4277 String1=0x01,Station-essence
4278 String2=0x02,Tankstelle
4279 String3=0x04,Gas station
4280 String4=0x03,Tankstation
4281 String7=0x15,Stacja paliw
4282 String8=0x10,Posto de combustível
4283 String9=0x05,Stazione di servizio
4284 ExtendedLabels=Y
4285 FontStyle=SmallFont
4286 CustomColor=Day
4287 DaycustomColor:#3E8BFD
4288 DayXpm="12 14 3 1" Colormode=16
4289 "! c #0095FF"
4290 "# c #F2EFE9"
4291 " c none"
4292 " !! "
4293 " !!!!!! !!!"
4294 "!!!!!!!! !!"
4295 "! ! !"
4296 "! !! #!"
4297 "! ! !#!"
4298 "!!!!!!!! !#!"
4299 "!!!!!!!!#!#!"
4300 "!!!!!!!!#!#!"
4301 "!!!!!!!!#!#!"
4302 "!!!!!!!!#! !"
4303 "!!!!!!!!# ! "
4304 "!!!!!!!!####"
4305 "!!!!!!!! "
4306 ;123456789012
4307 [end]
4308 [_point]
4309 type=0x02f
4310 subtype=0x02
4311 ;GRMN_TYPE: Business - Services/AUTO_RENTAL/Car rental location/Non NT
4312 String1=0x01,Location de voitures
4313 String2=0x02,Autoverleih
4314 String3=0x04,Car rental
4315 String4=0x03,Autoverhuur
4316 String7=0x15,Wypożyczalnia samochodów
4317 String8=0x10,Aluguel de carro
4318 String9=0x05,Noleggio veicoli
4319 ExtendedLabels=Y
4320 FontStyle=NoLabel (invisible)
4321 CustomColor=No
4322 DayXpm="10 14 2 1" Colormode=16
4323 "! c #0095FF"
4324 " c none"
4325 " !!! "
4326 "! !!!!!! "
4327 "!! !!!!!!!"
4328 " !! "
4329 " "
4330 " "
4331 " !!!!!! "
4332 " ! ! "
4333 " !! !! "
4334 "!!!!!!!!!!"
4335 "! !!!! !"
4336 "! !!!! !"
4337 "!!!!!!!!!!"
4338 " !! !! "
4339 ;1234567890
4340 [end]
4341 [_point]
4342 type=0x02f
4343 subtype=0x03
4344 ;GRMN_TYPE: Business - Services/AUTO_REPAIR/Car repair, mechanic/Non NT
4345 String1=0x01,Réparation automobile
4346 String2=0x02,Autowerkstatt
4347 String3=0x04,Garage
4348 String4=0x03,Autogarage
4349 String7=0x15,Garaż
4350 String8=0x10,Garagem
4351 String9=0x05,Riparazione veicoli
4352 ExtendedLabels=Y
4353 FontStyle=NoLabel (invisible)
4354 CustomColor=No
4355 DayXpm="10 14 2 1" Colormode=16
4356 "! c #734A08"
4357 " c none"
4358 " !!! "
4359 " !!!!!! "
4360 " !!!!!! "
4361 " !!! "
4362 " "
4363 " "
4364 " !!!!!! "
4365 " ! ! "
4366 " !! !! "
4367 " !!!!!!!! "
4368 "! !!!! !"
4369 "! !!!! !"
4370 "!!!!!!!!!!"
4371 " !! !! "
4372 ;1234567890
4373 [end]
4374 [_point]
4375 type=0x02f
4376 subtype=0x04
4377 ;GRMN_TYPE: Business - Services/AIRPORT/Airport/Non NT
4378 String1=0x01,Aéroport
4379 String2=0x02,Flughafen
4380 String3=0x04,Airport
4381 String4=0x03,Luchthaven
4382 String7=0x15,Lotnisko
4383 String8=0x10,Aeroporto
4384 String9=0x05,Aerodromo
4385 ExtendedLabels=Y
4386 FontStyle=NormalFont
4387 CustomColor=Day
4388 DaycustomColor:#8461C4
4389 DayXpm="16 16 2 1" Colormode=16
4390 "! c #8461C4"
4391 " c none"
4392 " !! "
4393 " !! "
4394 " !! "
4395 " !! "
4396 " !! "
4397 " !!!! "
4398 " !!!!!!!! "
4399 " !!!!!!!!!!!! "
4400 " !!!!!!!!!!!!!! "
4401 "!!!! !! !!!!"
4402 " !! "
4403 " !! "
4404 " !! "
4405 " !!!! "
4406 " !!!!!!!! "
4407 " !!!! !!!! "
4408 ;1234567890123456
4409 [end]
4410 [_point]
4411 type=0x02f
4412 subtype=0x05
4413 ;GRMN_TYPE: Business - Services/POST_OFFICE/Post office/Non NT
4414 String1=0x01,Poste
4415 String2=0x02,Postamt
4416 String3=0x04,Postoffice
4417 String4=0x03,Postkantoor
4418 String7=0x15,Poczta
4419 String8=0x10,Correio
4420 String9=0x05,Poste
4421 ExtendedLabels=Y
4422 FontStyle=NoLabel (invisible)
4423 CustomColor=No
4424 DayXpm="14 10 2 1" Colormode=16
4425 "! c #734A08"
4426 " c none"
4427 "!!!!!!!!!!!!!!"
4428 " !!!!!!!!!! "
4429 "! !!!!!!!! !"
4430 "!! !!!!!! !!"
4431 "!!! !!!! !!!"
4432 "!!!! !! !!!!"
4433 "!!! ! ! !!!"
4434 "!! !!! !!! !!"
4435 "! !!!!!!!!!! !"
4436 " !!!!!!!!!!!! "
4437 ;12345678901234
4438 [end]
4439 [_point]
4440 type=0x02f
4441 subtype=0x06
4442 ;GRMN_TYPE: Business - Services/BANK/Bank/Non NT
4443 String1=0x01,Banque
4444 String2=0x02,Bank
4445 String3=0x04,Bank
4446 String4=0x03,Bank
4447 String7=0x15,Bank
4448 String8=0x10,Banco
4449 String9=0x05,Banca/Sportello
4450 ExtendedLabels=Y
4451 FontStyle=SmallFont
4452 CustomColor=Day
4453 DaycustomColor:#734A08
4454 DayXpm="16 11 2 1" Colormode=16
4455 "! c #734A08"
4456 " c none"
4457 "!!!!!!!!!!!!!! "
4458 "!!! !!! "
4459 "!! !! !! "
4460 "! !!!! ! "
4461 "! !!!! ! "
4462 "! !!!! ! "
4463 "!! !! !! "
4464 "!!! !!! "
4465 "!!!!!!!!!!!!!! "
4466 " "
4467 "!!!!!!!!!!!!!! "
4468 ;1234567890123456
4469 [end]
4470 [_point]
4471 type=0x02f
4472 subtype=0x07
4473 ;GRMN_TYPE: Business - Services/DEALER/Dealer of manufactured goods/Non NT
4474 String1=0x01,Concessionnaire automobile
4475 String2=0x02,Autohändler
4476 String3=0x04,Car dealer
4477 String4=0x03,Autodealer
4478 String7=0x15,Sprzedaż samochodów
4479 String8=0x10,Revenda de carros
4480 String9=0x05,Vendita veicoli
4481 ExtendedLabels=Y
4482 FontStyle=SmallFont
4483 CustomColor=Day
4484 DaycustomColor:#BD30B4
4485 DayXpm="13 10 2 1" Colormode=16
4486 "! c #BD30B4"
4487 " c none"
4488 " !!!!!!! "
4489 " !! !! "
4490 " ! ! "
4491 " ! ! "
4492 " !!!!!!!!!!! "
4493 "!! !!!!! !!"
4494 "!! !!!!! !!"
4495 "!!!!!!!!!!!!!"
4496 " !!! !!! "
4497 " !!! !!! "
4498 ;1234567890123
4499 [end]
4500 [_point]
4501 type=0x02f
4502 subtype=0x08
4503 ;GRMN_TYPE: Business - Services/GND_TRANSPORT/Ground transportation status, i.e. a bus station/Non NT
4504 String1=0x01,Gare routière
4505 String2=0x02,Busbahnhof
4506 String3=0x04,Busstation
4507 String4=0x03,Busstation
4508 String7=0x15,Przystanek autobusowy
4509 String8=0x10,Estação de ônibus
4510 String9=0x05,Stazione
4511 ExtendedLabels=Y
4512 FontStyle=Default
4513 CustomColor=Day
4514 DaycustomColor:#0065FF
4515 DayXpm="21 16 3 1" Colormode=16
4516 "! c #0095FF"
4517 "# c #F2EFE9"
4518 " c none"
4519 "!!!!!!!!!!!!!!!! "
4520 "!!!!########!!!! "
4521 "!!!###!!!!###!!! "
4522 "!!############!! "
4523 "!!##!!!!!!!!##!! "
4524 "!!##!!!!!!!!##!! "
4525 "!!##!!!!!!!!##!! "
4526 "!!##!!!!!!!!##!! "
4527 "!!############!! "
4528 "!!############!! "
4529 "!!#!!######!!#!! "
4530 "!!#!!######!!#!! "
4531 "!!############!! "
4532 "!!!##!!!!!!##!!! "
4533 "!!!##!!!!!!##!!! "
4534 "!!!!!!!!!!!!!!!! "
4535 ;123456789012345678901
4536 [end]
4537 [_point]
4538 type=0x02f
4539 subtype=0x09
4540 ;GRMN_TYPE: Business - Services/MARINA/Marina/Non NT
4541 String1=0x01,Magasin accastillage et bateaux
4542 String2=0x02,Bootsgeschäft
4543 String3=0x04,Yacht shop
4544 String4=0x03,Botenwinkel
4545 String7=0x15,Sklep żeglarski
4546 String8=0x10,Loja de iates
4547 String9=0x05,Assistenza imbarcazioni
4548 ExtendedLabels=Y
4549 FontStyle=NoLabel (invisible)
4550 CustomColor=No
4551 DayXpm="5 5 2 1" Colormode=16
4552 "! c #BD30B4"
4553 " c none"
4554 " !!! "
4555 "!!!!!"
4556 "!!!!!"
4557 "!!!!!"
4558 " !!! "
4559 ;12345
4560 [end]
4561 [_point]
4562 type=0x02f
4563 subtype=0x0a
4564 ;GRMN_TYPE: Business - Services/WRECKER_SERVICE/Wrecker service/Non NT
4565 String1=0x01,Dépanneuse
4566 String2=0x02,Schleppdienst
4567 String3=0x04,Wrecker service
4568 String4=0x03,Sleepdienst
4569 String7=0x15,Holowanie
4570 String8=0x10,Guincho
4571 String9=0x05,Soccorso stradale
4572 ExtendedLabels=Y
4573 FontStyle=NoLabel (invisible)
4574 CustomColor=No
4575 DayXpm="5 5 2 1" Colormode=16
4576 "! c #BD30B4"
4577 " c none"
4578 " !!! "
4579 "!!!!!"
4580 "!!!!!"
4581 "!!!!!"
4582 " !!! "
4583 ;12345
4584 [end]
4585 [_point]
4586 type=0x02f
4587 subtype=0x0b
4588 ;GRMN_TYPE: Business - Services/PARKING/Parking/Non NT
4589 String1=0x01,Parking
4590 String2=0x02,Parking
4591 String3=0x04,Parking
4592 String4=0x03,Parkeerplaats
4593 String7=0x15,Parking
4594 String8=0x10,Estacionamento
4595 String9=0x05,Parcheggio
4596 ExtendedLabels=Y
4597 FontStyle=SmallFont
4598 CustomColor=Day
4599 DaycustomColor:#3E8BFD
4600 DayXpm="15 13 2 1" Colormode=16
4601 "! c #0095FF"
4602 " c none"
4603 "!!!!!!! "
4604 "!!!!!!!! "
4605 "!! !!! "
4606 "!! !! "
4607 "!! !! "
4608 "!! !!! "
4609 "!!!!!!!! "
4610 "!!!!!!! "
4611 "!! "
4612 "!! "
4613 "!! "
4614 "!! "
4615 "!! "
4616 ;123456789012345
4617 [end]
4618 [_point]
4619 type=0x02f
4620 subtype=0x0c
4621 ;GRMN_TYPE: Business - Services/REST_AREA_TOURIST_INFO/Rest area, Tourist information/Non NT
4622 String1=0x01,WC
4623 String2=0x02,WC
4624 String3=0x04,WC
4625 String4=0x03,Toilet
4626 String7=0x15,Toaleta
4627 String8=0x10,Banheiro
4628 String9=0x05,Servizi igienici
4629 ExtendedLabels=Y
4630 FontStyle=NoLabel (invisible)
4631 CustomColor=No
4632 DayXpm="15 14 2 1" Colormode=16
4633 "! c #734A08"
4634 " c none"
4635 " ! "
4636 " !! ! !! "
4637 " !!!! ! !!!! "
4638 " !! ! !! "
4639 " ! "
4640 " !!!! ! !!!!!!"
4641 " !!!! ! !!!!!!"
4642 " !! ! !!!! "
4643 " !! ! !!!! "
4644 " !!!! ! !! "
4645 "!!!!!! ! !! "
4646 " !! ! !! "
4647 " !! ! !! "
4648 " !! ! !! "
4649 ;123456789012345
4650 [end]
4651 [_point]
4652 type=0x02f
4653 subtype=0x0d
4654 ;GRMN_TYPE: Business - Services/AUTO_CLUB/Automobile club/Non NT
4655 String1=0x01,Club automobile
4656 String2=0x02,Automobilclub
4657 String3=0x04,Automobile club
4658 String4=0x03,Auto club
4659 String7=0x15,Klub samochodowy
4660 String8=0x10,Clube automobilístico
4661 String9=0x05,Amministrazione veicoli
4662 ExtendedLabels=Y
4663 FontStyle=NoLabel (invisible)
4664 CustomColor=No
4665 DayXpm="1 1 2 1" Colormode=16
4666 "! c #00FF4B"
4667 " c none"
4668 " "
4669 ;1
4670 [end]
4671 [_point]
4672 type=0x02f
4673 subtype=0x0e
4674 ;GRMN_TYPE: Business - Services/CAR_WASH/Car wash/Non NT
4675 String1=0x01,Lavage-auto
4676 String2=0x02,Autowaschanlage
4677 String3=0x04,Carwash
4678 String4=0x03,Autowasstraat
4679 String7=0x15,Myjnia
4680 String8=0x10,Lava jato
4681 String9=0x05,Lavaggio veicoli
4682 ExtendedLabels=Y
4683 FontStyle=NoLabel (invisible)
4684 CustomColor=No
4685 DayXpm="10 14 2 1" Colormode=16
4686 "! c #734A08"
4687 " c none"
4688 " !!!!!! "
4689 " "
4690 " ! !! ! "
4691 " ! !! ! "
4692 "! !! !"
4693 " "
4694 " !!!!!! "
4695 " ! ! "
4696 " !! !! "
4697 "!!!!!!!!!!"
4698 "! !!!! !"
4699 "! !!!! !"
4700 "!!!!!!!!!!"
4701 " !! !! "
4702 ;1234567890
4703 [end]
4704 [_point]
4705 type=0x02f
4706 subtype=0x10
4707 ;GRMN_TYPE: Business - Services/SERVICES_PERSONAL/Personal services/Non NT
4708 String1=0x01,Coiffeur
4709 String2=0x02,Friseur
4710 String3=0x04,Hairdresser
4711 String4=0x03,Kapper
4712 String7=0x15,Fryzjer
4713 String8=0x10,Cabeleireiro
4714 String9=0x05,Servizi per la persona
4715 ExtendedLabels=Y
4716 FontStyle=NoLabel (invisible)
4717 CustomColor=No
4718 DayXpm="14 14 2 1" Colormode=16
4719 "! c #BD30B4"
4720 " c none"
4721 " !! !!!!! "
4722 " !! !!!!!!"
4723 " !! !!"
4724 " !! !!!!!!"
4725 " !! !!"
4726 " !! !!!!!!"
4727 " !! !!"
4728 " !! !!!!!!"
4729 " !! !!"
4730 " !!!!!!!! !!"
4731 "!! !!!! !! !!"
4732 "! !! ! !!"
4733 "!! !!!! !! !!"
4734 " !!! !!! !!"
4735 ;12345678901234
4736 [end]
4737 [_point]
4738 type=0x02f
4739 subtype=0x12
4740 ;GRMN_TYPE: Business - Services/COMMUNICATION_SERVICES/Communication services/Non NT
4741 String1=0x01,Wifi
4742 String2=0x02,Wifi
4743 String3=0x04,Wifi
4744 String4=0x03,Wifi
4745 String7=0x15,Wifi
4746 String8=0x10,Wifi
4747 String9=0x05,Servizi di comunicazione
4748 ExtendedLabels=Y
4749 FontStyle=NoLabel (invisible)
4750 CustomColor=No
4751 DayXpm="11 11 2 1" Colormode=16
4752 "! c #737373"
4753 " c none"
4754 " !!!!!!"
4755 " !! "
4756 " ! !!!!!"
4757 " ! !! "
4758 " ! ! !!!"
4759 "! ! !! "
4760 "! ! ! "
4761 "! ! ! !!!"
4762 "! ! ! !!!!"
4763 "! ! ! !!!!"
4764 "! ! ! !!!!"
4765 ;12345678901
4766 [end]
4767 [_point]
4768 type=0x02f
4769 subtype=0x13
4770 ;GRMN_TYPE: Business - Services/REPAIR_SERVICE/Repair service/Non NT
4771 String1=0x01,Vélo
4772 String2=0x02,Rad
4773 String3=0x04,Bicycle
4774 String4=0x03,Fietsen
4775 String7=0x15,Rower
4776 String8=0x10,Bicicleta
4777 String9=0x05,Servizi di riparazione
4778 ExtendedLabels=Y
4779 FontStyle=SmallFont
4780 CustomColor=Day
4781 DaycustomColor:#BD30B4
4782 DayXpm="16 11 2 1" Colormode=16
4783 "! c #BD30B4"
4784 " c none"
4785 " ! "
4786 " !!!! !! "
4787 " !! ! "
4788 " !!!!!! "
4789 " !! !! "
4790 " !!!! !!!!!! "
4791 "!! !!! !! !! "
4792 "! ! ! ! "
4793 "! ! ! ! "
4794 "!! !! !! !! "
4795 " !!!! !!!! "
4796 ;1234567890123456
4797 [end]
4798 [_point]
4799 type=0x02f
4800 subtype=0x14
4801 ;GRMN_TYPE: Business - Services/SOCIAL_SERVICES/Social services/Non NT
4802 String1=0x01,Services sociaux
4803 String2=0x02,Soziale Einrichtung
4804 String3=0x04,Social
4805 String4=0x03,Sociale instelling
4806 String7=0x15,Social
4807 String8=0x10,Social
4808 String9=0x05,Istituzione sociale
4809 ExtendedLabels=Y
4810 FontStyle=SmallFont
4811 CustomColor=Day
4812 DaycustomColor:#734A08
4813 DayXpm="19 16 2 1" Colormode=16
4814 "! c #734A08"
4815 " c none"
4816 " !! "
4817 " !!!! "
4818 "!! !!!! !! "
4819 "!! !! !! "
4820 "!! !! "
4821 "!! !! !! "
4822 "!! !!!! !! "
4823 "!! !!!! !! "
4824 "!! !!!! !! "
4825 "!! !!!! !! "
4826 " !! !! "
4827 " !! !! "
4828 " !!!! !!!! "
4829 " !!!! !!!! "
4830 " !!!! !!!! "
4831 " !!!! !!!! "
4832 ;1234567890123456789
4833 [end]
4834 [_point]
4835 type=0x02f
4836 subtype=0x15
4837 ;GRMN_TYPE: Business - Services/UTILITY/Utility (gas, electric, water) services/Non NT
4838 String1=0x01,Déchetterie
4839 String2=0x02,Recycling
4840 String3=0x04,Recycling
4841 String4=0x03,Glasbak
4842 String7=0x15,Recykling
4843 String8=0x10,Reciclagem
4844 String9=0x05,Punto di raccolta
4845 ExtendedLabels=Y
4846 FontStyle=NoLabel (invisible)
4847 CustomColor=No
4848 DayXpm="17 17 2 1" Colormode=16
4849 "! c #734A08"
4850 " c none"
4851 " !! !! "
4852 " !! !!! "
4853 " !!! !! ! "
4854 " !!! !!!! "
4855 " !!! !!! "
4856 " !! !!!! "
4857 " "
4858 " !!!! !!! "
4859 " !!! !!! "
4860 " !!!! !!!"
4861 "!!! ! !!!"
4862 "!!! !!"
4863 "!!! ! "
4864 " ! !!! !!!!! "
4865 " !!!!! !!!!!! "
4866 " !!!!! !!!! "
4867 " ! "
4868 ;12345678901234567
4869 [end]
4870 [_point]
4871 type=0x02f
4872 subtype=0x16
4873 ;GRMN_TYPE: Business - Services/TRUCK_STOP/Truck stop/Non NT
4874 String1=0x01,Station-essence
4875 String2=0x02,Tankstelle
4876 String3=0x04,Gas station
4877 String4=0x03,Tankstation
4878 String7=0x15,Stacja paliw
4879 String8=0x10,Posto de combustível
4880 String9=0x05,Stazione di servizio
4881 ExtendedLabels=Y
4882 FontStyle=SmallFont
4883 CustomColor=Day
4884 DaycustomColor:#3E8BFD
4885 DayXpm="12 14 3 1" Colormode=16
4886 "! c #0095FF"
4887 "# c #F2EFE9"
4888 " c none"
4889 " !! "
4890 " !!!!!! !!!"
4891 "!!!!!!!! !!"
4892 "! ! !"
4893 "! !! #!"
4894 "! ! !#!"
4895 "!!!!!!!! !#!"
4896 "!!!!!!!!#!#!"
4897 "!!!!!!!!#!#!"
4898 "!!!!!!!!#!#!"
4899 "!!!!!!!!#! !"
4900 "!!!!!!!!# ! "
4901 "!!!!!!!!####"
4902 "!!!!!!!! "
4903 ;123456789012
4904 [end]
4905 [_point]
4906 type=0x02f
4907 subtype=0x17
4908 ;GRMN_TYPE: Business - Services/TRANSIT_SERVICES/Mass transit services/Non NT
4909 String1=0x01,Arrêt de bus
4910 String2=0x02,Haltestelle
4911 String3=0x04,Busstop
4912 String4=0x03,Bushalte
4913 String7=0x15,Przystanek
4914 String8=0x10,Parada de ônibus
4915 String9=0x05,Fermata mezzi pubblici
4916 ExtendedLabels=Y
4917 FontStyle=NoLabel (invisible)
4918 CustomColor=No
4919 DayXpm="9 11 3 1" Colormode=16
4920 "! c #0095FF"
4921 "# c #F2EFE9"
4922 " c none"
4923 " !!!!!!!#"
4924 "!! ### !!"
4925 "!!!!!!!!!"
4926 "!#######!"
4927 "!#######!"
4928 "!#######!"
4929 "!!!!!!!!!"
4930 "!##!!! #!"
4931 "!##!!! #!"
4932 "!!!!!!!!!"
4933 "#!!###!!#"
4934 ;123456789
4935 [end]
4936 [_point]
4937 type=0x030
4938 subtype=0x01
4939 ;GRMN_TYPE: Business - Emergency and Government/POLICE_STATION/Police station/Non NT
4940 String1=0x01,Police
4941 String2=0x02,Polizei
4942 String3=0x04,Police
4943 String4=0x03,Politiekantoor
4944 String7=0x15,Policja
4945 String8=0x10,Polícia
4946 String9=0x05,Forze dell’Ordine
4947 ExtendedLabels=Y
4948 FontStyle=SmallFont
4949 CustomColor=Day
4950 DaycustomColor:#734A08
4951 DayXpm="15 15 2 1" Colormode=16
4952 "! c #734A08"
4953 " c none"
4954 " !!!!!! "
4955 " !!!!!! "
4956 " "
4957 " !!!!!! "
4958 " !!!!!! "
4959 " !!!! "
4960 " "
4961 " !!!!!!!! "
4962 "!!!!!!! !! "
4963 "!!!!!! !!! "
4964 "!!!!! !!!! "
4965 "!!!! !!!!! "
4966 "!!! !!!!!! "
4967 "!! !!!!!!! "
4968 "! !!!!!!!! "
4969 ;123456789012345
4970 [end]
4971 [_point]
4972 type=0x030
4973 subtype=0x02
4974 ;GRMN_TYPE: Business - Emergency and Government/HOSPITAL/Hospital/Non NT
4975 String1=0x01,Hôpital
4976 String2=0x02,Krankenhaus
4977 String3=0x04,Hospital
4978 String4=0x03,Ziekenhuis
4979 String7=0x15,Szpital
4980 String8=0x10,Hospital
4981 String9=0x05,Ospedale
4982 ExtendedLabels=Y
4983 FontStyle=SmallFont
4984 CustomColor=Day
4985 DaycustomColor:#BF0000
4986 DayXpm="19 14 2 1" Colormode=16
4987 "! c #BF0000"
4988 " c none"
4989 " !!!!!! "
4990 " !!!!!!!!!! "
4991 " !!!!! !!!!! "
4992 " !!!!! !!!!! "
4993 "!!!!!! !!!!!! "
4994 "!!!!!! !!!!!! "
4995 "!! !! "
4996 "!! !! "
4997 "!!!!!! !!!!!! "
4998 "!!!!!! !!!!!! "
4999 " !!!!! !!!!! "
5000 " !!!!! !!!!! "
5001 " !!!!!!!!!! "
5002 " !!!!!! "
5003 ;1234567890123456789
5004 [end]
5005 [_point]
5006 type=0x030
5007 subtype=0x03
5008 ;GRMN_TYPE: Business - Emergency and Government/CITY_HALL/City hall/Non NT
5009 String1=0x01,Mairie
5010 String2=0x02,Rathaus
5011 String3=0x04,Townhall
5012 String4=0x03,Stadhuis
5013 String7=0x15,Ratusz
5014 String8=0x10,Prefeitura
5015 String9=0x05,Municipio/Ambasciata
5016 ExtendedLabels=Y
5017 FontStyle=SmallFont
5018 CustomColor=Day
5019 DaycustomColor:#734A08
5020 DayXpm="16 14 2 1" Colormode=16
5021 "! c #734A08"
5022 " c none"
5023 " !!!!!! "
5024 " !!!! "
5025 " !!!!!! "
5026 " !! "
5027 " !! "
5028 " !!!!!! "
5029 " !!!!!!!!!! "
5030 " "
5031 "!!!!!!!!!!!! "
5032 " !!!! !!!! "
5033 " !!! !!! "
5034 " !!! !!! "
5035 " !!! !!! "
5036 "!!!!!!!!!!!! "
5037 ;1234567890123456
5038 [end]
5039 [_point]
5040 type=0x030
5041 subtype=0x04
5042 ;GRMN_TYPE: Business - Emergency and Government/COURTHOUSE/Courthouse/Non NT
5043 String1=0x01,Tribunal
5044 String2=0x02,Gericht
5045 String3=0x04,Courthouse
5046 String4=0x03,Gerechtsgebouw
5047 String7=0x15,Sąd
5048 String8=0x10,Tribunal
5049 String9=0x05,Tribunale
5050 ExtendedLabels=Y
5051 FontStyle=SmallFont
5052 CustomColor=Day
5053 DaycustomColor:#734A08
5054 DayXpm="18 15 2 1" Colormode=16
5055 "! c #734A08"
5056 " c none"
5057 " !! "
5058 " !!!!!!!! "
5059 " !!!!!!!!!! "
5060 " !! !! !! "
5061 " ! !! ! "
5062 " !!! !! !!! "
5063 " !!!!! !! !!!!! "
5064 " ! ! !! ! ! "
5065 "!!!!!!! !! !!!!!!!"
5066 " !!!!! !! !!!!! "
5067 " !! "
5068 " !! "
5069 " !! "
5070 " !!!!!!!!! "
5071 " !!!!!!!!!!! "
5072 ;123456789012345678
5073 [end]
5074 [_point]
5075 type=0x030
5076 subtype=0x05
5077 ;GRMN_TYPE: Business - Emergency and Government/COMMUNITY_CENTER/Community center/Non NT
5078 String1=0x01,Associations culturelles
5079 String2=0x02,Gemeindezentrum
5080 String3=0x04,Community centre
5081 String4=0x03,Gemeenschapscentrum
5082 String7=0x15,Ośrodek kultury
5083 String8=0x10,Centro comunitário
5084 String9=0x05,Centro comunitario
5085 ExtendedLabels=Y
5086 FontStyle=SmallFont
5087 CustomColor=Day
5088 DaycustomColor:#734A08
5089 DayXpm="18 15 2 1" Colormode=16
5090 "! c #734A08"
5091 " c none"
5092 " !! !! "
5093 " !!!! !!!! "
5094 " !!!! !!!! "
5095 " !! !! "
5096 " "
5097 "!!!!!!!!!!!!!!! "
5098 " "
5099 " !! !! "
5100 " !!!! !!!! "
5101 " ! ! ! ! "
5102 " !! !! !! !! "
5103 " !! !! !! !! "
5104 "!! ! ! !! "
5105 "!! !!! !! "
5106 "! ! ! "
5107 ;123456789012345678
5108 [end]
5109 [_point]
5110 type=0x030
5111 subtype=0x06
5112 ;GRMN_TYPE: Business - Emergency and Government/BORDER_CROSSING/Border crossing/Non NT
5113 String1=0x01,Douane
5114 String2=0x02,Zoll
5115 String3=0x04,Bordercontrol
5116 String4=0x03,Douane
5117 String7=0x15,Kontrola graniczna
5118 String8=0x10,Alfândega
5119 String9=0x05,Dogana
5120 ExtendedLabels=Y
5121 FontStyle=NoLabel (invisible)
5122 CustomColor=No
5123 DayXpm="1 1 2 1" Colormode=16
5124 "! c #00FF4B"
5125 " c none"
5126 " "
5127 ;1
5128 [end]
5129 [_point]
5130 type=0x030
5131 subtype=0x07
5132 ;GRMN_TYPE: Business - Emergency and Government/GOV_OFFICE/Government Office/Non NT
5133 String1=0x01,Prison
5134 String2=0x02,Gefängnis
5135 String3=0x04,Prison
5136 String4=0x03,Gevangenis
5137 String7=0x15,Więzienie
5138 String8=0x10,Prisão
5139 String9=0x05,Istituto governativo
5140 ExtendedLabels=Y
5141 FontStyle=SmallFont
5142 CustomColor=Day
5143 DaycustomColor:#734A08
5144 DayXpm="16 14 2 1" Colormode=16
5145 "! c #734A08"
5146 " c none"
5147 "!!!!!!!!!!!!!! "
5148 "! ! ! ! "
5149 "! ! ! ! "
5150 "! ! !! ! ! "
5151 "! !!!!!! ! "
5152 "! !!!!!! ! "
5153 "! ! !! ! ! "
5154 "! ! ! ! "
5155 "! !!!!!! ! "
5156 "! !!!!!! ! "
5157 "! !!!!!!!! ! "
5158 "! !!!!!!!! ! "
5159 "! !!!!!!!! ! "
5160 "!!!!!!!!!!!!!! "
5161 ;1234567890123456
5162 [end]
5163 [_point]
5164 type=0x030
5165 subtype=0x08
5166 ;GRMN_TYPE: Business - Emergency and Government/FIRE_DEPT/Fire department/Non NT
5167 String1=0x01,Pompiers
5168 String2=0x02,Feuerwehr
5169 String3=0x04,Firestation
5170 String4=0x03,Brandweer
5171 String7=0x15,Straż pożarna
5172 String8=0x10,Bombeiros
5173 String9=0x05,Vigili del fuoco
5174 ExtendedLabels=Y
5175 FontStyle=SmallFont
5176 CustomColor=Day
5177 DaycustomColor:#734A08
5178 DayXpm="13 17 2 1" Colormode=16
5179 "! c #734A08"
5180 " c none"
5181 " ! "
5182 " !! "
5183 " !!! ! "
5184 " !!!! !! "
5185 " !!!! !!! "
5186 " !!!!! !!!! "
5187 " !!!!!!!!!! "
5188 "!!!! !!!!!!! "
5189 "!!!! !!!!!! "
5190 "!!!! !!!!!!!"
5191 "!!!! !! !!!"
5192 " !!! ! !!!"
5193 " !!!! !! "
5194 " !!! !! "
5195 " !!! !! "
5196 " !!! !! "
5197 " !! ! "
5198 ;1234567890123
5199 [end]
5200 [_point]
5201 type=0x032
5202 subtype=0x00
5203 ;GRMN_TYPE: //
5204 String1=0x01,Barrière
5205 String2=0x02,Poller
5206 String3=0x04,Bollard
5207 String4=0x03,Paaltje
5208 String7=0x15,Słupek
5209 String8=0x10,Barreira
5210 String9=0x05,Ostacolo
5211 ExtendedLabels=Y
5212 FontStyle=NoLabel (invisible)
5213 CustomColor=No
5214 DayXpm="5 5 2 1" Colormode=16
5215 "! c #3F3F3F"
5216 " c none"
5217 " !!! "
5218 "!!!!!"
5219 "!!!!!"
5220 "!!!!!"
5221 " !!! "
5222 ;12345
5223 [end]
5224 [_point]
5225 type=0x043
5226 subtype=0x00
5227 ;GRMN_TYPE: //
5228 String1=0x01,Marina
5229 String2=0x02,Bootshafen
5230 String3=0x04,Marina
5231 String4=0x03,Jachthaven
5232 String7=0x15,Przystań
5233 String8=0x10,Marina
5234 String9=0x05,Porto
5235 ExtendedLabels=Y
5236 FontStyle=SmallFont
5237 CustomColor=Day
5238 DaycustomColor:#697EE2
5239 DayXpm="1 1 2 1" Colormode=16
5240 "! c #FFFFFF"
5241 " c none"
5242 " "
5243 ;1
5244 [end]
5245 [_point]
5246 type=0x043
5247 subtype=0x01
5248 ;GRMN_TYPE: //
5249 String1=0x01,Gare
5250 String2=0x02,Bahnhof
5251 String3=0x04,Trainstation
5252 String4=0x03,Treinstation
5253 String7=0x15,Dworzec kolejowy
5254 String8=0x10,Estação de trem
5255 String9=0x05,Stazione
5256 ExtendedLabels=Y
5257 FontStyle=Default
5258 CustomColor=Day
5259 DaycustomColor:#4A58AD
5260 DayXpm="12 7 2 1" Colormode=16
5261 "! c #7981B0"
5262 " c none"
5263 "!!!!!!! "
5264 "!!!!!!! "
5265 "!!!!!!! "
5266 "!!!!!!! "
5267 "!!!!!!! "
5268 "!!!!!!! "
5269 "!!!!!!! "
5270 ;123456789012
5271 [end]
5272 [_point]
5273 type=0x043
5274 subtype=0x02
5275 ;GRMN_TYPE: //
5276 String1=0x01,Tramway
5277 String2=0x02,Straßenbahn
5278 String3=0x04,Tram / Metro
5279 String4=0x03,Tram / Metro
5280 String7=0x15,Tramwaj / Metro
5281 String8=0x10,Metrô
5282 String9=0x05,Stazione
5283 ExtendedLabels=Y
5284 FontStyle=SmallFont
5285 CustomColor=Day
5286 DaycustomColor:#4A58AD
5287 DayXpm="8 4 2 1" Colormode=16
5288 "! c #7981B0"
5289 " c none"
5290 "!!!! "
5291 "!!!! "
5292 "!!!! "
5293 "!!!! "
5294 ;12345678
5295 [end]
5296 [_point]
5297 type=0x043
5298 subtype=0x03
5299 ;GRMN_TYPE: //
5300 String1=0x01,Terminal Ferry
5301 String2=0x02,Fährhafen
5302 String3=0x04,Ferry terminal
5303 String4=0x03,Ferry terminal
5304 String7=0x15,Terminal promowy
5305 String8=0x10,Terminal de balsa
5306 String9=0x05,Terminal
5307 ExtendedLabels=Y
5308 FontStyle=Default
5309 CustomColor=Day
5310 DaycustomColor:#8461C4
5311 DayXpm="11 15 2 1" Colormode=16
5312 "! c #8A68C6"
5313 " c none"
5314 " !! "
5315 " !!!! "
5316 " !!!! "
5317 " !! "
5318 " !! "
5319 " !!!!!!!! "
5320 " !!!!!!!! "
5321 " !! "
5322 " !! "
5323 "! !! ! "
5324 "!! !! !! "
5325 "!!! !! !!! "
5326 " !!!!!!!! "
5327 " !!!!!! "
5328 " !! "
5329 ;12345678901
5330 [end]
5331 [_point]
5332 type=0x04a
5333 subtype=0x00
5334 ;GRMN_TYPE: Misc. Points of Interest/PICNIC_AREA/Picnic area/Non NT, NT
5335 String1=0x01,Pique-nique
5336 String2=0x02,Picknick
5337 String3=0x04,Picnic area
5338 String4=0x03,Picknick plaats
5339 String7=0x15,Miejsce piknikowe
5340 String8=0x10,Piquenique
5341 String9=0x05,Area picnic
5342 ExtendedLabels=Y
5343 FontStyle=NoLabel (invisible)
5344 CustomColor=No
5345 DayXpm="13 10 2 1" Colormode=16
5346 "! c #009500"
5347 " c none"
5348 " !!!!!!!!!!! "
5349 " !!!!!!!!!!! "
5350 " !! !! "
5351 " !! !! "
5352 " !! !! "
5353 "!!!!!!!!!!!!!"
5354 " !! !! "
5355 " !!! !!! "
5356 " !!! !!! "
5357 " !! !! "
5358 ;1234567890123
5359 [end]
5360 [_point]
5361 type=0x04c
5362 subtype=0x00
5363 ;GRMN_TYPE: Misc. Points of Interest/INFORMATION/Information/Non NT, NT
5364 String1=0x01,Office du Tourisme
5365 String2=0x02,Touristeninformation
5366 String3=0x04,Tourist information
5367 String4=0x03,Touristen informatie
5368 String7=0x15,Informacja turystyczna
5369 String8=0x10,Informações turísticas
5370 String9=0x05,Informazioni turistiche
5371 ExtendedLabels=Y
5372 FontStyle=NoLabel (invisible)
5373 CustomColor=No
5374 DayXpm="6 13 2 1" Colormode=16
5375 "! c #666666"
5376 " c none"
5377 " !! "
5378 " !! "
5379 " "
5380 " "
5381 " !!! "
5382 " !!! "
5383 " !! "
5384 " !! "
5385 " !! "
5386 " !! "
5387 " !! "
5388 " !! "
5389 "!!!!!!"
5390 ;123456
5391 [end]
5392 [_point]
5393 type=0x04e
5394 subtype=0x00
5395 ;GRMN_TYPE: Misc. Points of Interest/RESTROOMS/Restrooms/Non NT, NT
5396 String1=0x01,WC
5397 String2=0x02,WC
5398 String3=0x04,WC
5399 String4=0x03,Toilet
5400 String7=0x15,Toaleta
5401 String8=0x10,Banheiro
5402 String9=0x05,Servizi igienici
5403 ExtendedLabels=Y
5404 FontStyle=NoLabel (invisible)
5405 CustomColor=No
5406 DayXpm="15 14 2 1" Colormode=16
5407 "! c #734A08"
5408 " c none"
5409 " ! "
5410 " !! ! !! "
5411 " !!!! ! !!!! "
5412 " !! ! !! "
5413 " ! "
5414 " !!!! ! !!!!!!"
5415 " !!!! ! !!!!!!"
5416 " !! ! !!!! "
5417 " !! ! !!!! "
5418 " !!!! ! !! "
5419 "!!!!!! ! !! "
5420 " !! ! !! "
5421 " !! ! !! "
5422 " !! ! !! "
5423 ;123456789012345
5424 [end]
5425 [_point]
5426 type=0x050
5427 subtype=0x00
5428 ;GRMN_TYPE: Misc. Points of Interest/DRINKING_WATER/Drinking water/Non NT, NT
5429 String1=0x01,Eau potable
5430 String2=0x02,Trinkwasser
5431 String3=0x04,Drinking water
5432 String4=0x03,Drinkwater
5433 String7=0x15,Woda pitna
5434 String8=0x10,Bebedouro
5435 String9=0x05,Acqua potabile
5436 ExtendedLabels=Y
5437 FontStyle=NoLabel (invisible)
5438 CustomColor=No
5439 DayXpm="13 16 2 1" Colormode=16
5440 "! c #734A08"
5441 " c none"
5442 " "
5443 " !!!!!! "
5444 " !! "
5445 " !! "
5446 " !!!!!!!!!"
5447 " !!!!!!!!!!"
5448 " !! "
5449 " "
5450 "!!!!!!!! "
5451 "!! !! "
5452 "!! !! "
5453 " !!!!!! "
5454 " !!!!!! "
5455 " !!!!!! "
5456 " !!!! "
5457 " !!!! "
5458 ;1234567890123
5459 [end]
5460 [_point]
5461 type=0x059
5462 subtype=0x04
5463 ;GRMN_TYPE: //
5464 String1=0x01,Héliport
5465 String2=0x02,Hubschrauberlandeplatz
5466 String3=0x04,Heli
5467 String4=0x03,Helihaven
5468 String7=0x15,Lądowisko helikopterowe
5469 String8=0x10,Heliponto
5470 String9=0x05,Eliporto
5471 ExtendedLabels=Y
5472 FontStyle=NoLabel (invisible)
5473 CustomColor=No
5474 DayXpm="18 17 2 1" Colormode=16
5475 "! c #8461C4"
5476 " c none"
5477 " !!!!!! "
5478 " !! !! "
5479 " ! ! "
5480 " ! ! "
5481 " ! !! !! ! "
5482 " ! !! !! ! "
5483 "! !! !! !"
5484 "! !!!!!!!! !"
5485 "! !!!!!!!! !"
5486 "! !! !! !"
5487 "! !! !! !"
5488 " ! !! !! ! "
5489 " ! !! !! ! "
5490 " ! ! "
5491 " ! ! "
5492 " !! !! "
5493 " !!!!!! "
5494 ;123456789012345678
5495 [end]
5496 [_point]
5497 type=0x064
5498 subtype=0x03
5499 ;GRMN_TYPE: Geographical Named Points of Interest/CEMETERY/Cemetery/Non NT, NT
5500 String1=0x01,Cimetière
5501 String2=0x02,Friedhof
5502 String3=0x04,Cemetry
5503 String4=0x03,Begraafplaats
5504 String7=0x15,Cmentarz
5505 String8=0x10,Cemitério
5506 String9=0x05,Cimitero
5507 ExtendedLabels=Y
5508 FontStyle=Default
5509 CustomColor=Day
5510 DaycustomColor:#495E48
5511 DayXpm="1 1 2 1" Colormode=16
5512 "! c #009500"
5513 " c none"
5514 " "
5515 ;1
5516 [end]
5517 [_point]
5518 type=0x064
5519 subtype=0x0b
5520 ;GRMN_TYPE: Geographical Named Points of Interest/MILITARY/Military point of interest/Non NT, NT
5521 String1=0x01,Militaire
5522 String2=0x02,Militär
5523 String3=0x04,Military
5524 String4=0x03,Militair
5525 String7=0x15,Wojsko
5526 String8=0x10,Militar
5527 String9=0x05,Elemento militare
5528 ExtendedLabels=Y
5529 FontStyle=SmallFont
5530 CustomColor=Day
5531 DaycustomColor:#8B0606
5532 DayXpm="1 1 2 1" Colormode=16
5533 "! c #009500"
5534 " c none"
5535 " "
5536 ;1
5537 [end]
5538 [_point]
5539 type=0x064
5540 subtype=0x11
5541 ;GRMN_TYPE: Geographical Named Points of Interest/TOWER/Tower/Non NT, NT
5542 String1=0x01,Tour/Pylône
5543 String2=0x02,Turm
5544 String3=0x04,Tower
5545 String4=0x03,Toren
5546 String7=0x15,Wieża
5547 String8=0x10,Torre
5548 String9=0x05,Torre/Pilone
5549 ExtendedLabels=Y
5550 FontStyle=NoLabel (invisible)
5551 CustomColor=No
5552 DayXpm="10 15 2 1" Colormode=16
5553 "! c #666666"
5554 " c none"
5555 " !! "
5556 " !! "
5557 " !! "
5558 " !! "
5559 " !! "
5560 " !! "
5561 " !! "
5562 " !! "
5563 " !! "
5564 " !! "
5565 " !! "
5566 " !! "
5567 " !!!! "
5568 "!!!!!!!! "
5569 "!!!!!!!! "
5570 ;1234567890
5571 [end]
5572 [_point]
5573 type=0x065
5574 subtype=0x05
5575 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/CANAL/Canal/Non NT, NT
5576 String1=0x01,Barrage
5577 String2=0x02,Wehr
5578 String3=0x04,Weir
5579 String4=0x03,Stuw
5580 String7=0x15,Tama
5581 String8=0x10,Açude
5582 String9=0x05,Diga
5583 ExtendedLabels=Y
5584 FontStyle=SmallFont
5585 CustomColor=Day
5586 DaycustomColor:#5E5E5D
5587 DayXpm="9 9 2 1" Colormode=16
5588 "! c #A4A4A4"
5589 " c none"
5590 " !!!!! "
5591 " !!!!!!! "
5592 "!!! !!!"
5593 "!! !!"
5594 "!! !!"
5595 "!! !!"
5596 "!!! !!!"
5597 " !!!!!!! "
5598 " !!!!! "
5599 ;123456789
5600 [end]
5601 [_point]
5602 type=0x065
5603 subtype=0x08
5604 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/WATERFALL/Waterfall/Non NT, NT
5605 String1=0x01,Chute d'eau
5606 String2=0x02,Wasserfall
5607 String3=0x04,Waterfall
5608 String4=0x03,Waterval
5609 String7=0x15,Wodospad
5610 String8=0x10,Cachoeira
5611 String9=0x05,Cascata
5612 ExtendedLabels=Y
5613 FontStyle=SmallFont
5614 CustomColor=Day
5615 DaycustomColor:#4863A0
5616 DayXpm="15 14 2 1" Colormode=16
5617 "! c #4D80B3"
5618 " c none"
5619 " !!!!!!!!!! "
5620 " !!!!!!!!!!! "
5621 " !! !! !!! "
5622 " !! !! !! "
5623 " !! !! !! "
5624 " !! !! !! "
5625 " !! !! !! "
5626 " !! !! !! "
5627 " ! ! !! "
5628 " ! "
5629 " "
5630 " !!! !!! !!! "
5631 "!!!!!!!!!!!!!!!"
5632 "! !! !! !"
5633 ;123456789012345
5634 [end]
5635 [_point]
5636 type=0x065
5637 subtype=0x0a
5638 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/GLACIER/Glacier/Non NT, NT
5639 String1=0x01,Glacier
5640 String2=0x02,Gletscher
5641 String3=0x04,Gletcher
5642 String4=0x03,Gletsjer
5643 String7=0x15,Lodowiec
5644 String8=0x10,Geleira
5645 String9=0x05,Ghiacciaio
5646 ExtendedLabels=Y
5647 FontStyle=NoLabel (invisible)
5648 CustomColor=No
5649 DayXpm="1 1 2 1" Colormode=16
5650 "! c #00FF4B"
5651 " c none"
5652 " "
5653 ;1
5654 [end]
5655 [_point]
5656 type=0x065
5657 subtype=0x0c
5658 ;GRMN_TYPE: //
5659 String1=0x01,Île
5660 String2=0x02,Insel
5661 String3=0x04,Island
5662 String4=0x03,Eiland
5663 String7=0x15,Wyspa
5664 String8=0x10,Ilha
5665 String9=0x05,Isola
5666 ExtendedLabels=Y
5667 FontStyle=SmallFont
5668 CustomColor=Day
5669 DaycustomColor:#414141
5670 DayXpm="1 1 2 1" Colormode=16
5671 "! c #00FF4B"
5672 " c none"
5673 " "
5674 ;1
5675 [end]
5676 [_point]
5677 type=0x065
5678 subtype=0x0f
5679 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/RESERVOIR/Reservoir/Non NT, NT
5680 String1=0x01,Eau
5681 String2=0x02,Wasser
5682 String3=0x04,Water
5683 String4=0x03,Water
5684 String7=0x15,Woda
5685 String8=0x10,Água
5686 String9=0x05,Acqua
5687 ExtendedLabels=Y
5688 FontStyle=SmallFont
5689 CustomColor=Day
5690 DaycustomColor:#4D80B3
5691 DayXpm="1 1 2 1" Colormode=16
5692 "! c #009500"
5693 " c none"
5694 " "
5695 ;1
5696 [end]
5697 [_point]
5698 type=0x065
5699 subtype=0x11
5700 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/SPRING/Spring/Non NT, NT
5701 String1=0x01,Source
5702 String2=0x02,Quelle
5703 String3=0x04,Well
5704 String4=0x03,Waterbron
5705 String7=0x15,Źródło
5706 String8=0x10,Poço
5707 String9=0x05,Sorgente
5708 ExtendedLabels=Y
5709 FontStyle=SmallFont
5710 CustomColor=Day
5711 DaycustomColor:#4D80B3
5712 DayXpm="9 9 2 1" Colormode=16
5713 "! c #7BBCEC"
5714 " c none"
5715 " !!!!! "
5716 " !!!!!!! "
5717 "!!! !!!"
5718 "!! !!"
5719 "!! !!"
5720 "!! !!"
5721 "!!! !!!"
5722 " !!!!!!! "
5723 " !!!!! "
5724 ;123456789
5725 [end]
5726 [_point]
5727 type=0x065
5728 subtype=0x12
5729 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/STREAM/Stream/Non NT, NT
5730 String1=0x01,Eau
5731 String2=0x02,Wasser
5732 String3=0x04,Water
5733 String4=0x03,Water
5734 String7=0x15,Woda
5735 String8=0x10,Água
5736 String9=0x05,Acqua
5737 ExtendedLabels=Y
5738 FontStyle=SmallFont
5739 CustomColor=Day
5740 DaycustomColor:#4D80B3
5741 DayXpm="1 1 2 1" Colormode=16
5742 "! c #009500"
5743 " c none"
5744 " "
5745 ;1
5746 [end]
5747 [_point]
5748 type=0x065
5749 subtype=0x13
5750 ;GRMN_TYPE: Geographical Named Points of Interest - Water Related/SWAMP/Swamp/Non NT, NT
5751 String1=0x01,Marais
5752 String2=0x02,Sumpf
5753 String3=0x04,Swamp
5754 String4=0x03,Moeras
5755 String7=0x15,Bagno
5756 String8=0x10,Pântano
5757 String9=0x05,Palude
5758 ExtendedLabels=Y
5759 FontStyle=SmallFont
5760 CustomColor=Day
5761 DaycustomColor:#4D80B3
5762 DayXpm="1 1 2 1" Colormode=16
5763 "! c #009500"
5764 " c none"
5765 " "
5766 ;1
5767 [end]
5768 [_point]
5769 type=0x066
5770 subtype=0x01
5771 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/ARCH/Arch/Non NT, NT
5772 String1=0x01,Grotte
5773 String2=0x02,Höhle
5774 String3=0x04,Cave
5775 String4=0x03,Grot
5776 String7=0x15,Jaskinia
5777 String8=0x10,Caverna
5778 String9=0x05,Grotta
5779 ExtendedLabels=Y
5780 FontStyle=NoLabel (invisible)
5781 CustomColor=No
5782 DayXpm="11 6 2 1" Colormode=16
5783 "! c #000000"
5784 " c none"
5785 " !!!!! "
5786 " ! ! "
5787 " ! !!! ! "
5788 "! !!!!! !"
5789 "! !!!!!!! !"
5790 "! !!!!!!! !"
5791 ;12345678901
5792 [end]
5793 [_point]
5794 type=0x066
5795 subtype=0x03
5796 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/BASIN/Basin/Non NT, NT
5797 String1=0x01,Eau
5798 String2=0x02,Wasser
5799 String3=0x04,Water
5800 String4=0x03,Water
5801 String7=0x15,Woda
5802 String8=0x10,Água
5803 String9=0x05,Acqua
5804 ExtendedLabels=Y
5805 FontStyle=SmallFont
5806 CustomColor=Day
5807 DaycustomColor:#4D80B3
5808 DayXpm="1 1 2 1" Colormode=16
5809 "! c #009500"
5810 " c none"
5811 " "
5812 ;1
5813 [end]
5814 [_point]
5815 type=0x066
5816 subtype=0x04
5817 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/BEACH/Beach/Non NT, NT
5818 String1=0x01,Plage
5819 String2=0x02,Strand
5820 String3=0x04,Beach
5821 String4=0x03,Strand
5822 String7=0x15,Plaża
5823 String8=0x10,Praia
5824 String9=0x05,Spiaggia
5825 ExtendedLabels=Y
5826 FontStyle=SmallFont
5827 CustomColor=Day
5828 DaycustomColor:#907712
5829 DayXpm="1 1 2 1" Colormode=16
5830 "! c #009500"
5831 " c none"
5832 " "
5833 ;1
5834 [end]
5835 [_point]
5836 type=0x066
5837 subtype=0x06
5838 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/CAPE/Cape/Non NT, NT
5839 String1=0x01,Cap
5840 String2=0x02,Kap
5841 String3=0x04,Cape
5842 String4=0x03,Kaap
5843 String7=0x15,Przylądek
5844 String8=0x10,Cabo
5845 String9=0x05,Capo
5846 ExtendedLabels=Y
5847 FontStyle=NoLabel (invisible)
5848 CustomColor=No
5849 DayXpm="1 1 2 1" Colormode=16
5850 "! c #00FF4B"
5851 " c none"
5852 " "
5853 ;1
5854 [end]
5855 [_point]
5856 type=0x066
5857 subtype=0x07
5858 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/CLIFF/Cliff/Non NT, NT
5859 String1=0x01,Falaise
5860 String2=0x02,Klippe
5861 String3=0x04,Cliff
5862 String4=0x03,Klif
5863 String7=0x15,Klif
5864 String8=0x10,Penhasco
5865 String9=0x05,Dirupo
5866 ExtendedLabels=Y
5867 FontStyle=NoLabel (invisible)
5868 CustomColor=No
5869 DayXpm="1 1 2 1" Colormode=16
5870 "! c #00FF4B"
5871 " c none"
5872 " "
5873 ;1
5874 [end]
5875 [_point]
5876 type=0x066
5877 subtype=0x12
5878 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/RESERVE/Reserve/Non NT, NT
5879 String1=0x01,Réserve naturelle
5880 String2=0x02,Naturschutzgebiet
5881 String3=0x04,Nature reserve
5882 String4=0x03,Natuurgebied
5883 String7=0x15,Rezerwat przyrody
5884 String8=0x10,Reserva natural
5885 String9=0x05,Riserva
5886 ExtendedLabels=Y
5887 FontStyle=Default
5888 CustomColor=Day
5889 DaycustomColor:#006500
5890 DayXpm="1 1 2 1" Colormode=16
5891 "! c #009500"
5892 " c none"
5893 " "
5894 ;1
5895 [end]
5896 [_point]
5897 type=0x066
5898 subtype=0x14
5899 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/ROCK/Rock/Non NT, NT
5900 String1=0x01,Roche
5901 String2=0x02,Felsen
5902 String3=0x04,Rock
5903 String4=0x03,Rotsen
5904 String7=0x15,Skała
5905 String8=0x10,Rochedo
5906 String9=0x05,Roccia
5907 ExtendedLabels=Y
5908 FontStyle=NormalFont
5909 CustomColor=Day
5910 DaycustomColor:#967757
5911 DayXpm="1 1 2 1" Colormode=16
5912 "! c #009500"
5913 " c none"
5914 " "
5915 ;1
5916 [end]
5917 [_point]
5918 type=0x066
5919 subtype=0x16
5920 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/SUMMIT/Summit, top of a hill or mountain/Non NT, NT
5921 String1=0x01,Sommet
5922 String2=0x02,Gipfel
5923 String3=0x04,Summit
5924 String4=0x03,Bergtop
5925 String7=0x15,Szczyt
5926 String8=0x10,Pico
5927 String9=0x05,Picco
5928 ExtendedLabels=Y
5929 FontStyle=SmallFont
5930 CustomColor=Day
5931 DaycustomColor:#734A08
5932 DayXpm="14 10 2 1" Colormode=16
5933 "! c #D08F55"
5934 " c none"
5935 " ! "
5936 " ! "
5937 " !!! "
5938 " !!! "
5939 " !!!!! "
5940 " !!!!! "
5941 " !!!!!!! "
5942 " !!!!!!! "
5943 "!!!!!!!!! "
5944 "!!!!!!!!! "
5945 ;12345678901234
5946 [end]
5947 [_point]
5948 type=0x066
5949 subtype=0x18
5950 ;GRMN_TYPE: Geographical Named Points of Interest - Land Related/WOODS/Wooded area/Non NT, NT
5951 String1=0x01,Forêt
5952 String2=0x02,Wald
5953 String3=0x04,Woods
5954 String4=0x03,Bos
5955 String7=0x15,Drzewa
5956 String8=0x10,Mata / Bosque
5957 String9=0x05,Selva
5958 ExtendedLabels=Y
5959 FontStyle=SmallFont
5960 CustomColor=Day
5961 DaycustomColor:#527247
5962 DayXpm="1 1 2 1" Colormode=16
5963 "! c #009500"
5964 " c none"
5965 " "
5966 ;1
5967 [end]
0 ;-------------------------------------------------------------------------------
1 ; This is an example TYP file.
2 ; A TYP file controls how the Garmin device renders polygons, lines and points.
3 ; See https://wiki.openstreetmap.org/wiki/Mkgmap/help/typ_compile
4 ; for more information.
5 ;
6 ; This example sets most polygons to have the same drawOrder
7 ; See https://wiki.openstreetmap.org/wiki/Editing_OSM_Map_On_Garmin/Area_Types
8 ; so that mkgmap option --order-by-decreasing-area works in an optimum manner.
9 ; It exposes all the known non-extended Garmin polygon representations, eg
10 ; 0x01-0x03=City and provides some hidden polygons for naming large areas such
11 ; as Counties, Islands...
12 ;-------------------------------------------------------------------------------
13 ;
14 [_drawOrder]
15 ; nothing shows, even with: Type=0x00,2
16 Type=0x01,2
17 Type=0x02,2
18 Type=0x03,2
19 Type=0x04,2
20 Type=0x05,2
21 Type=0x06,2
22 ; 0x07/Airport default drawOrder is lower that most other polygons on some Garmin devices; make it the same.
23 Type=0x07,2
24 Type=0x08,2
25 Type=0x09,2
26 Type=0x0a,2
27 Type=0x0b,2
28 Type=0x0c,2
29 Type=0x0d,2
30 Type=0x0e,2
31 Type=0x0f,2
32 Type=0x10,2
33 Type=0x11,2
34 Type=0x12,2
35 Type=0x13,2
36 ; the following Greens default drawOrder is lower than most on some Garmin devices; make them the same.
37 Type=0x14,2
38 Type=0x15,2
39 Type=0x16,2
40 Type=0x17,2
41 Type=0x18,2
42 Type=0x19,2
43 Type=0x1a,2
44 Type=0x1b,2
45 Type=0x1c,2
46 Type=0x1d,2
47 Type=0x1e,2
48 Type=0x1f,2
49 Type=0x20,2
50 ; to here
51 Type=0x21,2
52 Type=0x22,2
53 Type=0x23,2
54 Type=0x24,2
55 Type=0x25,2
56 Type=0x26,2
57 Type=0x27,2
58 Type=0x28,2
59 Type=0x29,2
60 Type=0x2a,2
61 Type=0x2b,2
62 Type=0x2c,2
63 Type=0x2d,2
64 Type=0x2e,2
65 Type=0x2f,2
66 Type=0x30,2
67 Type=0x31,2
68 Type=0x32,2
69 Type=0x33,2
70 Type=0x34,2
71 Type=0x35,2
72 Type=0x36,2
73 Type=0x37,2
74 Type=0x38,2
75 Type=0x39,2
76 Type=0x3a,2
77 Type=0x3b,2
78 Type=0x3c,2
79 Type=0x3d,2
80 Type=0x3e,2
81 Type=0x3f,2
82 Type=0x40,2
83 Type=0x41,2
84 Type=0x42,2
85 Type=0x43,2
86 Type=0x44,2
87 Type=0x45,2
88 Type=0x46,2
89 Type=0x47,2
90 Type=0x48,2
91 Type=0x49,2
92 ; The following two are overview/main background. Give them a lower drawOrder.
93 Type=0x4a,1
94 Type=0x4b,1
95 Type=0x4c,2
96 Type=0x4d,2
97 Type=0x4e,2
98 Type=0x4f,2
99 Type=0x50,2
100 Type=0x51,2
101 Type=0x52,2
102 Type=0x53,2
103 Type=0x54,2
104 Type=0x55,2
105 ; The following don't seem to have any known pre-defined meaning to Garmin
106 ; devices and can be used to give a 'hover' or 'select' name and details without
107 ; other representation, being hidden with a lower drawOrder than the background.
108 Type=0x56,0
109 Type=0x57,0
110 Type=0x58,0
111 Type=0x59,0
112 Type=0x5a,0
113 Type=0x5b,0
114 Type=0x5c,0
115 Type=0x5d,0
116 Type=0x5e,0
117 Type=0x5f,0
118 [end]
9494 return s.trim();
9595 }
9696
97 /**
98 * two or more whitespace characters are replaced by a single space
99 * @param s string to trim
100 * @return the trimmed string or null if s is null or empty
101 */
97102 public static String squashSpaces(String s) {
98103 if(s == null || s.isEmpty())
99104 return null;
1313
1414 import java.util.LinkedHashMap;
1515 import java.util.Map;
16
1617 import uk.me.parabola.mkgmap.reader.osm.Element;
1718 import uk.me.parabola.mkgmap.reader.osm.TagDict;
1819
2223 *
2324 */
2425 public final class AccessTagsAndBits {
26
27 private AccessTagsAndBits() {
28 // private constructor to hide the implicit public one
29 }
30
2531 // constants for vehicle class
2632 public static final byte FOOT = 0x01;
2733 public static final byte BIKE = 0x02;
5965 for (Map.Entry<String, Byte> entry : ACCESS_TAGS.entrySet()) {
6066 ACCESS_TAGS_COMPILED.put(TagDict.getInstance().xlate(entry.getKey()), entry.getValue());
6167 }
62 };
68 }
6369
70
6471 public static final Map<String, Byte> ROUTE_TAGS;
6572 static {
6673 ROUTE_TAGS = new LinkedHashMap<>();
4545
4646 private boolean ignoreSharpAngles;
4747 private boolean cycleMap;
48 // private final Coord test = new Coord(48.074815,16.272771);
49
50 private final int MIN_ANGLE = 0x10;
51 private final int MIN_LOW_SPEED_ANGLE = 0x20;
48
49 private static final int MIN_ANGLE = 0x10;
50 private static final int MIN_LOW_SPEED_ANGLE = 0x20;
5251
5352 private int mask;
5453 private int mrnd;
7574 orAccessMask |= arc.getRoadDef().getAccess();
7675 roadDefs.add(arc.getRoadDef());
7776 }
77
7878 public float getInitialHeading() {
7979 return initialHeading;
8080 }
81
8182 public boolean isOneway() {
8283 return isOneWayTrueCount == arcs.size();
8384 }
85
8486 public boolean isForward() {
8587 return isForwardTrueCount == arcs.size();
8688 }
89
8790 /**
8891 * @return
8992 */
9093 public void setInitialHeading(float modIH) {
9194 while (modIH > 180)
92 modIH -= 360;
95 modIH -= 360;
9396 while (modIH < -180)
94 modIH += 360;
97 modIH += 360;
9598 initialHeading = modIH;
96 imgHeading = calcEncodedBearing(initialHeading);
97
98 for (RouteArc arc : arcs){
99 imgHeading = calcEncodedBearing(initialHeading);
100
101 for (RouteArc arc : arcs) {
99102 arc.setInitialHeading(modIH);
100103 }
101104 }
102
103 public String toString(){
105
106 public String toString() {
104107 return arcs.get(0).toString();
105108 }
106109 }
107110
108111
109 private byte calcEncodedBearing (float b) {
112 private byte calcEncodedBearing(float b) {
110113 return (byte) ((RouteArc.directionFromDegrees(b) + mrnd) & mask);
111114 }
112
115
113116 public void config(EnhancedProperties props) {
114117 // undocumented option - usually used for debugging only
115118 ignoreSharpAngles = props.getProperty("ignore-sharp-angles", false);
116119 cycleMap = props.getProperty("cycle-map", false);
117 // float a = 0;
118 // for (int i = 0; i <= 1440; i++){
119 // int ar = (int) Math.round(a * 256.0 / 360);
120 // int am = ar & 0xf0;
121 // log.error(a,ar,"0x" + Integer.toHexString(am));
122 // a +=0.25;
123 // if (a >= 180)
124 // a -= 360;
125 // }
126 return;
127120 }
128121
129122 public void check(Map<Integer, RouteNode> nodes) {
182175 if (angleAttr.maskedAngle < 0)
183176 angleAttr.maskedAngle += 256;
184177
185 if (ag1.isOneway() && ag1.isForward()){
186 // the "incoming" arc is a wrong direction oneway
178 if (ag1.isOneway() && ag1.isForward()
179 || ag2.isOneway() && !ag2.isForward()) {
180 // the "incoming" arc or the "outgoing" is a wrong direction oneway
187181 angleAttr.noAccess = true;
188 } else if (ag2.isOneway() && ag2.isForward() == false){
189 // the "outgoing" arc is a wrong direction oneway
190 angleAttr.noAccess = true;
191182 }
192183
193 // if (node.getCoord().distance(test) < 2){
194 // if (angleAttr.angle == 20){
195 // angleAttr.maskedMinAngle = 0x30;
196 // continue;
197 // }
198 // }
199184 int sumSpeeds = ag1.maxRoadSpeed + ag2.maxRoadSpeed;
200185 if (sumSpeeds <= 1)
201186 continue;
202187 byte pathAccessMask = (byte) (ag1.orAccessMask & ag2.orAccessMask);
203 if (pathAccessMask == 0){
188 if (pathAccessMask == 0) {
204189 // no common vehicle allowed on both arcs
205190 angleAttr.noAccess = true;
206191 }
289274 int modIH = ag2.imgHeading + usedIncrement;
290275 if (modIH > 128)
291276 modIH -= 256;
292 ag2.setInitialHeading(modIH * 360/256);
277 ag2.setInitialHeading(modIH * 360 / 256f);
293278 int modAngle = Math.round(ag2.getInitialHeading() - ag1.getInitialHeading());
294279 if (modAngle < 0)
295280 modAngle += 360;
308293 int modIH = ag1.imgHeading - usedIncrement;
309294 if (modIH < -128)
310295 modIH += 256;
311 ag1.setInitialHeading(modIH * 360/256);
296 ag1.setInitialHeading(modIH * 360 / 256f);
312297 int modAngle = Math.round(ag2.getInitialHeading() - ag1.getInitialHeading());
313298 if (modAngle < 0)
314299 modAngle += 360;
328313 log.info(sharpAngle, "don't know how to enlarge it further");
329314 }
330315 }
331 return;
332316 }
333317
334318
379363 ag.addArc(arc2);
380364 } else{
381365 arc1 = arc2;
382 if (iter.hasNext() == false)
366 if (!iter.hasNext())
383367 addArc1 = true;
384368 break;
385369 }
3636 private final NETHeader netHeader = new NETHeader();
3737
3838 // To begin with we only need LBL offsets.
39 private final Map<Integer, Integer> offsetLabelMap = new HashMap<Integer, Integer>();
39 private final Map<Integer, Integer> offsetLabelMap = new HashMap<>();
4040 private List<Integer> offsets;
4141
4242 private List<City> cities;
7878 */
7979 public List<RoadDef> getRoads() {
8080 ImgFileReader reader = getReader();
81 int start = netHeader.getRoadDefinitionsStart();
82
83 List<RoadDef> roads = new ArrayList<RoadDef>();
81 long start = netHeader.getRoadDefinitionsStart();
82
83 List<RoadDef> roads = new ArrayList<>();
8484 int record = 0;
8585 for (int off : offsets) {
8686 reader.position(start + off);
181181 initFlag >>= 5;
182182 }
183183 node += skip + 1;
184 int right = 0, left = 0;
184 int right = 0;
185 int left = 0;
185186 if (initFlag == 0) {
186187 right = left = getCityOrZip(reader, size, endPos);
187188 } else if ((initFlag & 0x4) != 0) {
207208 assert false : "ERRROR overflow";
208209 return 0;
209210 }
210 int cnum = reader.getNu(size);
211 return cnum;
211 return reader.getNu(size);
212212 }
213213
214214 /**
251251 private void readLabelOffsets() {
252252 ImgFileReader reader = getReader();
253253 offsets = readOffsets();
254 int start = netHeader.getRoadDefinitionsStart();
254 long start = netHeader.getRoadDefinitionsStart();
255255 for (int off : offsets) {
256256 reader.position(start + off);
257257 int labelOffset = reader.get3u();
258 // TODO what if top bit is not set?, there can be more than one name and we will miss them
259258 offsetLabelMap.put(off, labelOffset & 0x7fffff);
260259 }
261260 }
282281 }
283282
284283 // Sort in address order in the hope of speeding up reading.
285 List<Integer> offsets = new ArrayList<>(allOffsets);
286 allOffsets = null;
287 offsets.sort(null);
288 return offsets;
284 List<Integer> sortedOffsets = new ArrayList<>(allOffsets);
285 sortedOffsets.sort(null);
286 return sortedOffsets;
289287 }
290288
291289 public void setCities(List<City> cities) {
1515 */
1616 package uk.me.parabola.imgfmt.app.net;
1717
18 import uk.me.parabola.imgfmt.ReadFailedException;
1918 import uk.me.parabola.imgfmt.app.CommonHeader;
2019 import uk.me.parabola.imgfmt.app.ImgFileReader;
2120 import uk.me.parabola.imgfmt.app.ImgFileWriter;
5049 *
5150 * @param reader The header is read from here.
5251 */
53 protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
52 protected void readFileHeader(ImgFileReader reader) {
5453 roadDefinitions.readSectionInfo(reader, false);
5554 roadShift = reader.get1u();
5655
6666 // maximal width and height of the bounding box, since
6767 // NOD 1 coordinate offsets are at most 16 bit wide.
6868 private static final int MAX_SIZE_UNSAFE = 1 << 16;
69 // private static final int MAX_SIZE = MAX_SIZE_UNSAFE / 2;
7069 private static final int MAX_SIZE = MAX_SIZE_UNSAFE - 0x800;
7170
7271 // Table A has at most 0x100 entries
7372 private static final int MAX_TABA_UNSAFE = 0x100;
74 // private static final int MAX_TABA = MAX_TABA_UNSAFE / 2;
7573 private static final int MAX_TABA = MAX_TABA_UNSAFE - 0x8;
7674
7775 // Table B has at most 0x100 entries
7876 private static final int MAX_TABB_UNSAFE = 0x100;
79 // private static final int MAX_TABB = MAX_TABB_UNSAFE / 2;
8077 private static final int MAX_TABB = MAX_TABB_UNSAFE - 0x2;
8178
8279 // Nodes size is max 0x2000 to cope with signed 14 bit node offsets
182179 // The area that actually has nodes.
183180 private final BBox bboxActual = new BBox();
184181
185 private List<RouteNode> nodes = new ArrayList<RouteNode>();
182 private List<RouteNode> nodes = new ArrayList<>();
186183 private TableA tabA = new TableA();
187 private Map<RouteNode,RouteNode> destNodes = new LinkedHashMap<RouteNode, RouteNode>();
184 private Map<RouteNode,RouteNode> destNodes = new LinkedHashMap<>();
188185
189186 /**
190187 * Create an unbounded NOD1Part.
217214 * external arc at a deeper level of recursion.
218215 */
219216 public void addNode(RouteNode node) {
220 assert bbox == null || bbox.contains(node.getCoord())
221 : "trying to add out-of-bounds node: " + node;
217 assert bbox == null || bbox.contains(node.getCoord()) : "trying to add out-of-bounds node: " + node;
222218
223219 bboxActual.extend(node.getCoord());
224220 nodes.add(node);
225221 for (RouteArc arc : node.arcsIteration()) {
226222 tabA.addArc(arc);
227223 RouteNode dest = arc.getDest();
228 if (arc.isInternal() == false){
224 if (!arc.isInternal()) {
229225 destNodes.put(dest, dest);
230 }
231 else if (bbox != null && !bbox.contains(dest.getCoord()) || dest.getGroup() != node.getGroup()) {
226 } else if (bbox != null && !bbox.contains(dest.getCoord()) || dest.getGroup() != node.getGroup()) {
232227 arc.setInternal(false);
233228 destNodes.put(dest, dest);
234229 }
242237 if (arc.getSource() != node){
243238 tabA.addArc(arc);
244239 RouteNode dest = arc.getDest();
245 if (arc.isInternal() == false)
240 if (!arc.isInternal())
246241 destNodes.put(dest, dest);
247242 else if (bbox != null && !bbox.contains(dest.getCoord()) || dest.getGroup() != node.getGroup()) {
248243 arc.setInternal(false);
267262 * Subdivide this part recursively until it satisfies the constraints.
268263 */
269264 protected List<RouteCenter> subdivideHelper(int depth) {
270 List<RouteCenter> centers = new LinkedList<RouteCenter>();
265 List<RouteCenter> centers = new LinkedList<>();
271266
272267 if (satisfiesConstraints()) {
273268 centers.add(this.toRouteCenter());
1717
1818 import java.util.Arrays;
1919
20 import uk.me.parabola.imgfmt.ReadFailedException;
2120 import uk.me.parabola.imgfmt.app.CommonHeader;
2221 import uk.me.parabola.imgfmt.app.ImgFileReader;
2322 import uk.me.parabola.imgfmt.app.ImgFileWriter;
6059 *
6160 * @param reader The header is read from here.
6261 */
63 protected void readFileHeader(ImgFileReader reader) throws ReadFailedException {
62 protected void readFileHeader(ImgFileReader reader) {
6463 nodes.readSectionInfo(reader, false);
6564 flags = reader.get2u();
6665 reader.get2u();
9190
9291 // multiplier shift for road + arc length values, the smaller the shift the higher the precision and NOD size
9392 // as it has an influence on the number of bits needed to encode a length
94 final static int DISTANCE_MULT_SHIFT = 1; // 0..7 1 seems to be a good compromise
95 final static int DISTANCE_MULT = 1 << DISTANCE_MULT_SHIFT;
93 static final int DISTANCE_MULT_SHIFT = 1; // 0..7 1 seems to be a good compromise
94 static final int DISTANCE_MULT = 1 << DISTANCE_MULT_SHIFT;
9695 protected void writeFileHeader(ImgFileWriter writer) {
9796 nodes.setPosition(HEADER_LEN);
9897 nodes.writeSectionInfo(writer);
237237 /**
238238 * The current state of the writing process.
239239 */
240 static abstract class State {
240 abstract static class State {
241241
242242 protected final Side left = new Side(true);
243243 protected final Side right = new Side(false);
325325 }
326326
327327 public Iterable<RouteArc> arcsIteration() {
328 return () -> arcs.iterator();
328 return arcs::iterator;
329329 }
330330
331331 public List<RouteRestriction> getRestrictions() {
361361 }
362362 }
363363 }
364 if (roundaboutArcs.size() > 0) {
364 if (!roundaboutArcs.isEmpty()) {
365365 // get the coordinates of a box bounding the junctions of the roundabout
366366 int minRoundaboutLat = coord.getHighPrecLat();
367367 int maxRoundaboutLat = minRoundaboutLat;
483483 log.warn("Roundabout " + rd + " overlaps " + fb.getRoadDef() + " at " + coord.toOSMURL());
484484 }
485485 }
486 else if(fb.isForward()) {
487 if(!rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
488 log.warn("Roundabout " + rd + " forks at " + coord.toOSMURL());
489 }
486 else if (fb.isForward()
487 && !rd.messagePreviouslyIssued("roundabout forks/overlaps")) {
488 log.warn("Roundabout " + rd + " forks at " + coord.toOSMURL());
490489 }
491490 }
492491 }
556555 boolean connectsToNonRoundaboutSegment = false;
557556 RouteArc nextRoundaboutArc = null;
558557 for (RouteArc nba : nb.arcs) {
559 if (nba.isDirect() == false)
558 if (!nba.isDirect())
560559 continue;
561560 if (!nba.getRoadDef().isSynthesised()) {
562561 if (nba.getRoadDef().isRoundabout()) {
563562 if (nba.isForward())
564563 nextRoundaboutArc = nba;
565 } else
564 } else {
566565 connectsToNonRoundaboutSegment = true;
566 }
567567 }
568568 }
569569
722722
723723 if (nodes.size() < 3)
724724 return;
725 // System.out.println(road + " " + nodes.size() + " " + forwardArcs.size());
726725 ArrayList<RouteArc> newArcs = new ArrayList<>();
727726 IntArrayList arcPositions = forwardArcPositions;
728727 List<RouteArc> roadArcs = forwardArcs;
771770 newArc.setIndirect();
772771 newArcs.add(newArc);
773772 arcToStepNode = newArc;
774 stepNode = destNode;
775773
776774 partialArcLength = 0;
777775 if (cl >= finalClass)
778776 break;
779777 }
780778 }
781 if (newArcs.isEmpty() == false){
782 int directArcPos = arcPositions.getInt(i);
779 if (!newArcs.isEmpty()) {
780 int directArcPos = arcPositions.getInt(i);
783781 assert nodes.get(i).arcs.get(directArcPos).isDirect();
784782 assert nodes.get(i).arcs.get(directArcPos).getRoadDef() == newArcs.get(0).getRoadDef();
785783 assert nodes.get(i).arcs.get(directArcPos).isForward() == newArcs.get(0).isForward();
789787 int reverseArcPos = reverseArcPositions.get(i-1); // i-1 because first node doesn't have reverse arc
790788 if (directArcPos < reverseArcPos)
791789 reverseArcPositions.set(i - 1, reverseArcPos + newArcs.size());
792
793790 }
794791 }
795792 }
3737 * @author Robert Vollmert
3838 */
3939 public class RouteRestriction {
40 //private static final Logger log = Logger.getLogger(RouteRestriction.class);
41
4240 // first three bytes of the header -- might specify the type of restriction
4341 // and when it is active
4442 private static final byte RESTRICTION_TYPE = 0x05; // 0x07 spotted, meaning?
6260 private final byte exceptMask;
6361 private final byte flags; // meaning of bits 0x01 and 0x10 are not clear
6462
65 private final static byte F_EXCEPT_FOOT = 0x02;
66 private final static byte F_EXCEPT_EMERGENCY = 0x04;
67 private final static byte F_MORE_EXCEPTIONS = 0x08;
68
69 private final static byte EXCEPT_CAR = 0x01;
70 private final static byte EXCEPT_BUS = 0x02;
71 private final static byte EXCEPT_TAXI = 0x04;
72 private final static byte EXCEPT_DELIVERY = 0x10;
73 private final static byte EXCEPT_BICYCLE = 0x20;
74 private final static byte EXCEPT_TRUCK = 0x40;
63 private static final byte F_EXCEPT_FOOT = 0x02;
64 private static final byte F_EXCEPT_EMERGENCY = 0x04;
65 private static final byte F_MORE_EXCEPTIONS = 0x08;
66
67 private static final byte EXCEPT_CAR = 0x01;
68 private static final byte EXCEPT_BUS = 0x02;
69 private static final byte EXCEPT_TAXI = 0x04;
70 private static final byte EXCEPT_DELIVERY = 0x10;
71 private static final byte EXCEPT_BICYCLE = 0x20;
72 private static final byte EXCEPT_TRUCK = 0x40;
7573
7674 /**
7775 *
8684 RouteArc arc = arcs.get(i);
8785 assert arc.getDest() != viaNode;
8886 }
89 byte flags = 0;
87 byte tmpFlags = 0;
9088
9189 if ((mkgmapExceptMask & FOOT) != 0)
92 flags |= F_EXCEPT_FOOT;
90 tmpFlags |= F_EXCEPT_FOOT;
9391 if ((mkgmapExceptMask & EMERGENCY) != 0)
94 flags |= F_EXCEPT_EMERGENCY;
92 tmpFlags |= F_EXCEPT_EMERGENCY;
9593
9694 exceptMask = translateExceptMask(mkgmapExceptMask);
9795 if(exceptMask != 0)
98 flags |= F_MORE_EXCEPTIONS;
96 tmpFlags |= F_MORE_EXCEPTIONS;
9997
10098 int numArcs = arcs.size();
10199 assert numArcs < 8;
102 flags |= ((numArcs) << 5);
103 this.flags = flags;
100 tmpFlags |= ((numArcs) << 5);
101 this.flags = tmpFlags;
104102 }
105103
106104
169167 offsets[pos++] = calcOffset(arc.getDest(), tableOffset);
170168 else
171169 offsets[pos++] = arc.getIndexB();
172 if (arc.getSource() == viaNode){
170 if (!viaWritten && arc.getSource() == viaNode) {
173171 // there will be two nodes with source node = viaNode, but we write the source only once
174 if (!viaWritten){
175 offsets[pos++] = calcOffset(viaNode, tableOffset);
176 viaWritten = true;
177 }
172 offsets[pos++] = calcOffset(viaNode, tableOffset);
173 viaWritten = true;
178174 }
179175 }
180176
3838 private int offset;
3939
4040 // arcs for roundabouts
41 private final HashMap<RoadDef,Integer> roundaboutArcs = new LinkedHashMap<RoadDef,Integer>();
41 private final HashMap<RoadDef,Integer> roundaboutArcs = new LinkedHashMap<>();
4242 // arcs for unpaved ways
43 private final HashMap<RoadDef,Integer> unpavedArcs = new LinkedHashMap<RoadDef,Integer>();
43 private final HashMap<RoadDef,Integer> unpavedArcs = new LinkedHashMap<>();
4444 // arcs for ferry ways
45 private final HashMap<RoadDef,Integer> ferryArcs = new LinkedHashMap<RoadDef,Integer>();
45 private final HashMap<RoadDef,Integer> ferryArcs = new LinkedHashMap<>();
4646 // arcs for paved ways
47 private final HashMap<RoadDef,Integer> pavedArcs = new LinkedHashMap<RoadDef,Integer>();
47 private final HashMap<RoadDef,Integer> pavedArcs = new LinkedHashMap<>();
4848
4949 private static int count;
5050
2424 */
2525 public class TableB {
2626
27 private final ArrayList<RouteNode> nodes = new ArrayList<RouteNode>();
27 private final ArrayList<RouteNode> nodes = new ArrayList<>();
2828
29 private final static int ITEM_SIZE = 3;
29 private static final int ITEM_SIZE = 3;
3030
3131 private int offset;
3232
6363 public void addNode(RouteNode node) {
6464 int i = nodes.indexOf(node);
6565 if (i < 0) {
66 //i = nodes.size();
6766 nodes.add(node);
6867 }
6968 }
3030
3131 private final TableA tabA;
3232
33 private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>();
33 private final List<RouteRestriction> restrictions = new ArrayList<>();
3434
3535 public TableC(TableA tabA) {
3636 this.tabA = tabA;
129129 * @param resolution The current resolution of the layer.
130130 */
131131 private void addPolygons(MapDataSource src, final int resolution) {
132 MapFilterChain chain = new MapFilterChain() {
133 public void doFilter(MapElement element) {
134 MapShape shape = (MapShape) element;
135 addShape(shape);
136 }
137 };
132 MapFilterChain chain = element -> addShape((MapShape) element);
138133
139134 PolygonSubdivSizeSplitterFilter filter = new PolygonSubdivSizeSplitterFilter();
140135 FilterConfig config = new FilterConfig();
165160 private void addLines(MapDataSource src, final int resolution) {
166161 // Split lines for size, such that it is appropriate for the
167162 // resolution that it is at.
168 MapFilterChain chain = new MapFilterChain() {
169 public void doFilter(MapElement element) {
170 MapLine line = (MapLine) element;
171 addLine(line);
172 }
173 };
163 MapFilterChain chain = element -> addLine((MapLine) element);
174164
175165 LineSizeSplitterFilter filter = new LineSizeSplitterFilter();
176166 FilterConfig config = new FilterConfig();
308298 } else {
309299 for (MapLine l : this.lines) {
310300 // Drop any zero sized lines.
311 if (l instanceof MapRoad == false && l.getRect().height <= 0 && l.getRect().width <= 0)
301 if (!(l instanceof MapRoad) && l.getRect().height <= 0 && l.getRect().width <= 0)
312302 continue;
313303 Area lineBounds = l.getBounds();
314304 int areaIndex = pickArea(mapAreas, l, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
890880 * @return true if this area contains any data
891881 */
892882 public boolean hasData() {
893 if (points.isEmpty() && lines.isEmpty() && shapes.isEmpty())
894 return false;
895 return true;
883 return !points.isEmpty() || !lines.isEmpty() || !shapes.isEmpty();
896884 }
897885
898886 @Override
8484 param.setFamilyId(family);
8585 if (product != -1)
8686 param.setProductId(product);
87 if (cp != -1)
87 if (cp != -1 && param.getCodePage() == 0)
8888 param.setCodePage(cp);
8989
9090 File outFile = new File(filename);
157157 private final Tags styleOptionTags;
158158 private static final String STYLE_OPTION_PREF = "mkgmap:option:";
159159 private final PrefixSuffixFilter prefixSuffixFilter;
160 private final boolean keepBlanks;
160161
161162 private LineAdder lineAdder;
162163
224225 // control calculation of extra nodes in NOD3 / NOD4
225226 admLevelNod3 = props.getProperty("add-boundary-nodes-at-admin-boundaries", 2);
226227 addBoundaryNodesAtAdminBoundaries = routable && admLevelNod3 > 0;
228 keepBlanks = props.containsKey("keep-blanks");
227229 }
228230
229231 /**
321323 roads.add(cw);
322324 numRoads++;
323325 if (!cw.isFerry()) {
324 String country = way.getTag(countryTagKey);
325 if (country != null) {
326 boolean drivingSideIsLeft = LocatorConfig.get().getDriveOnLeftFlag(country);
326 String countryIso = LocatorConfig.get().getCountryISOCode(way.getTag(countryTagKey));
327 if (countryIso != null) {
328 boolean drivingSideIsLeft = LocatorConfig.get().getDriveOnLeftFlag(countryIso);
327329 if (drivingSideIsLeft)
328330 numDriveOnLeftRoads++;
329331 else
12621264 private static final short phoneTagKey = TagDict.getInstance().xlate("mkgmap:phone");
12631265 private static final short is_inTagKey = TagDict.getInstance().xlate("mkgmap:is_in");
12641266
1265 private static void elementSetup(MapElement ms, GType gt, Element element) {
1267 private void elementSetup(MapElement ms, GType gt, Element element) {
12661268 String[] labels = new String[4];
1267 int noLabels = 0;
1269 int numLabels = 0;
12681270 for (int labelNo = 0; labelNo < 4; labelNo++) {
12691271 String label1 = element.getTag(labelTagKeys[labelNo]);
1270 String label = Label.squashSpaces(label1);
1272 String label = keepBlanks ? label1 : Label.squashSpaces(label1);
12711273 if (label != null) {
1272 labels[noLabels] = label;
1273 noLabels++;
1274 labels[numLabels] = label;
1275 numLabels++;
12741276 }
12751277 }
12761278
1717 import java.util.Locale;
1818 import java.util.Map.Entry;
1919
20 import uk.me.parabola.imgfmt.app.Coord;
2120 import uk.me.parabola.log.Logger;
2221 import uk.me.parabola.mkgmap.reader.osm.Element;
2322 import uk.me.parabola.mkgmap.reader.osm.Relation;
4443 return nf.format(length);
4544 }
4645
47 private double calcLength(Element el) {
46 private static double calcLength(Element el) {
4847 if (el instanceof Way) {
49 Way w = (Way)el;
50 double length = 0;
51 Coord prevC = null;
52 for (Coord c : w.getPoints()) {
53 if (prevC != null) {
54 length += prevC.distance(c);
55 }
56 prevC = c;
57 }
58 return length;
48 return ((Way) el).calcLengthInMetres();
5949 } else if (el instanceof Relation) {
6050 Relation rel = (Relation)el;
6151 double length = 0;
7565 }
7666 }
7767
68 @Override
7869 public String getName() {
7970 return "length";
8071 }
8172
73 @Override
8274 public boolean supportsWay() {
8375 return true;
8476 }
8577
78 @Override
8679 public boolean supportsRelation() {
8780 return true;
8881 }
9393 Collection<Way> loadedCoastlines = loadFile(coastlineFile);
9494 log.info(loadedCoastlines.size(), "coastline ways from", coastlineFile, "loaded.");
9595
96 ArrayList<Way> ways = SeaGenerator.joinWays(loadedCoastlines);
96 List<Way> ways = SeaGenerator.joinWays(loadedCoastlines);
9797 ListIterator<Way> wayIter = ways.listIterator();
98 ways = null;
9998 while (wayIter.hasNext()) {
10099 Way way = wayIter.next();
101100 wayIter.remove();
1212
1313 package uk.me.parabola.mkgmap.reader.osm;
1414
15 import java.util.AbstractMap;
1615 import java.util.ArrayDeque;
1716 import java.util.ArrayList;
1817 import java.util.Arrays;
1918 import java.util.Collections;
2019 import java.util.HashSet;
2120 import java.util.IdentityHashMap;
22 import java.util.LinkedHashMap;
2321 import java.util.LinkedHashSet;
2422 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
2723 import java.util.Queue;
2824 import java.util.Set;
2925
3026 import uk.me.parabola.imgfmt.app.Coord;
3127 import uk.me.parabola.log.Logger;
3228 import uk.me.parabola.mkgmap.osmstyle.NameFinder;
33 import uk.me.parabola.mkgmap.osmstyle.function.LengthFunction;
29 import uk.me.parabola.mkgmap.osmstyle.housenumber.ExtNumbers;
3430 import uk.me.parabola.util.EnhancedProperties;
3531 import uk.me.parabola.util.MultiHashMap;
3632
3733 /**
38 * Copies the destination tag from motorway_link and trunk_link ways to the
39 * first adjacent non link way so that the Garmin is able to display a valid
40 * destination.
41 * @author WanMil
34 * Cuts link ways into parts and adds destination/exit hints to a new part so
35 * that the Garmin is able to display a valid destination.
36 * @author Gerd Petermann
37 * @author WanMil (initial versions)
4238 */
4339 public class LinkDestinationHook implements OsmReadingHooks {
4440 private static final Logger log = Logger.getLogger(LinkDestinationHook.class);
4844 /** Maps which ways can be driven from a given Coord */
4945 private IdentityHashMap<Coord, Set<Way>> adjacentWays = new IdentityHashMap<>();
5046 /** Contains all _link ways that have to be processed */
51 private Map<Long, Way> destinationLinkWays = new LinkedHashMap<>();
47 private LinkedHashSet<Way> destinationLinkWays = new LinkedHashSet<>();
5248
5349 private static final Set<String> highwayTypes = new LinkedHashSet<>(Arrays.asList(
5450 "motorway", "trunk", "primary", "secondary", "tertiary",
5551 "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link"));
56 private HashSet<String> linkTypes = new HashSet<>(Arrays.asList(
52 private static final Set<String> linkTypes = new LinkedHashSet<>(Arrays.asList(
5753 "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link"));
58
5954
6055 /** Map way ids to its restriction relations so that the relations can easily be updated when the way is split. */
6156 private MultiHashMap<Long, RestrictionRelation> restrictions = new MultiHashMap<>();
6762
6863 private boolean processDestinations;
6964 private boolean processExits;
65
66 private static final short TAG_KEY_HIGHWAY = TagDict.getInstance().xlate("highway");
67 private static final short TAG_KEY_ONEWAY = TagDict.getInstance().xlate("oneway");
68 private static final short TAG_KEY_EXIT_TO = TagDict.getInstance().xlate("exit_to");
69 private static final short TAG_KEY_DEST_HINT_WORK = TagDict.getInstance().xlate("mkgmap:dest_hint_work");
7070
7171 @Override
7272 public boolean init(ElementSaver saver, EnhancedProperties props) {
8080 /**
8181 * Fills the internal lists
8282 */
83 private void retrieveWays() {
83 private void retrieveWaysAndRelations() {
8484 // collect all ways tagged with highway
8585 for (Way w : saver.getWays().values()) {
8686 if (w.getPoints().size() < 2) {
8787 // ignore one-node or zero-node ways
8888 continue;
8989 }
90 String highwayTag = w.getTag("highway");
90 String highwayTag = w.getTag(TAG_KEY_HIGHWAY);
9191 if (highwayTag != null && highwayTypes.contains(highwayTag)) {
92 // the points of the way are kept so that it is easy to get
93 // the adjacent ways for a given _link way
94 String directedDestination = null;
95 String directedDestinationLanes = null;
96 String directionSuffix = null;
97 List<Coord> points;
98
99 if (isOnewayInDirection(w)) {
100 // oneway => don't need the last point because the
101 // way cannot be driven standing at the last point
102 points = w.getPoints().subList(0, w.getPoints().size() - 1);
103 directedDestination = w.getTag("destination:forward");
104 directedDestinationLanes = w.getTag("destination:lanes:forward");
105 directionSuffix = "forward";
106 } else if (isOnewayOppositeDirection(w)) {
107 // reverse oneway => don't need the first point because the
108 // way cannot be driven standing at the first point
109 points = w.getPoints().subList(1, w.getPoints().size());
110 directedDestination = w.getTag("destination:backward");
111 directedDestinationLanes = w.getTag("destination:lanes:backward");
112 directionSuffix = "backward";
113 } else {
114 points = w.getPoints();
115 }
116 for (Coord c : points) {
117 Set<Way> ways = adjacentWays.get(c);
118 if (ways == null) {
119 ways = new HashSet<>(4);
120 adjacentWays.put(c, ways);
121 }
122 ways.add(w);
123 }
124 registerPointsOfWay(w);
125
126 // if the way is a link way and has a destination tag
127 // put it the list of ways that have to be processed
128 if (linkTypes.contains(highwayTag)) {
129 String destSourceTagKey = "destination";
130 String destinationTag = w.getTag("destination");
131 if (destinationTag == null) {
132 // destination is not set
133 // => check if destination:lanes is without any lane specific information (no |)
134 destSourceTagKey = "destination:lanes";
135 String destLanesTag = w.getTag(destSourceTagKey);
136 if (destLanesTag == null && directedDestinationLanes != null){
137 destLanesTag = directedDestinationLanes;
138 destSourceTagKey += ":" + directionSuffix;
139 }
140 if (destLanesTag != null && !destLanesTag.contains("|")) {
141 // the destination:lanes tag contains no | => no lane specific information
142 // use this tag as destination tag
143 destinationTag = destLanesTag;
144 }
145 if (destinationTag == null && directedDestination != null) {
146 // use the destination:forward or :backward value
147 destinationTag = directedDestination;
148 destSourceTagKey = "destination:" + directionSuffix;
149 }
150 if (destinationTag == null){
151 // try to use the destination:street value
152 destSourceTagKey = "destination:street";
153 destinationTag = w.getTag(destSourceTagKey);
154 }
155
156 }
157 if (destinationTag != null) {
158 w.addTag("mkgmap:dest_hint_work", destinationTag);
159 if (!"destination".equals(destSourceTagKey) && log.isDebugEnabled()) {
160 if (destSourceTagKey.startsWith("destination:lanes")) {
161 log.debug("Use", destSourceTagKey,
162 "as destination tag because there is one lane information only. Way ",
163 w.getId(), w.toTagString());
164 } else {
165 log.debug("Use", destSourceTagKey, "as destination tag. Way ", w.getId(),
166 w.toTagString());
167 }
168 }
169 destinationLinkWays.put(w.getId(), w);
170 }
171 }
92 processHighWay(w, highwayTag);
17293 }
17394 }
17495
183104 }
184105 }
185106
186
107 private void processHighWay(Way w, String highwayTag) {
108 // the points of the way are kept so that it is easy to get
109 // the adjacent ways for a given _link way
110 List<Coord> points;
111 String directionSuffix = null;
112
113 if (isOnewayInDirection(w)) {
114 // oneway => don't need the last point because the
115 // way cannot be driven standing at the last point
116 points = w.getPoints().subList(0, w.getPoints().size() - 1);
117 directionSuffix = "forward";
118 } else if (isOnewayOppositeDirection(w)) {
119 // reverse oneway => don't need the first point because the
120 // way cannot be driven standing at the first point
121 points = w.getPoints().subList(1, w.getPoints().size());
122 directionSuffix = "backward";
123 } else {
124 points = w.getPoints();
125 }
126 for (Coord c : points) {
127 adjacentWays.computeIfAbsent(c, k -> new HashSet<>(4)).add(w);
128 }
129 registerPointsOfWay(w);
130 checkIfUsableLink(w, highwayTag, directionSuffix);
131 }
132
133 private void checkIfUsableLink(Way w, String highwayTag, String directionSuffix) {
134 // if the way is a link way and has a destination tag
135 // put it the list of ways that have to be processed
136 if (!linkTypes.contains(highwayTag))
137 return;
138
139 final String destinationLanes = "destination:lanes";
140 final String standardTagKey = "destination";
141 String destSourceTagKey = standardTagKey; // for log messages
142 String destHint = w.getTag(standardTagKey);
143 if (destHint == null) {
144 // destination is not set
145 // => check if destination:lanes is without any lane specific information (no |)
146 destSourceTagKey = destinationLanes;
147 String destLanesTag = w.getTag(destSourceTagKey);
148 if (destLanesTag == null && directionSuffix != null) {
149 destSourceTagKey += ":" + directionSuffix;
150 destLanesTag = w.getTag(destSourceTagKey);
151 }
152 if (destLanesTag != null && !destLanesTag.contains("|")) {
153 // the destination:lanes tag contains no | => no lane specific information
154 // use this tag as destination tag
155 destHint = destLanesTag;
156 }
157
158 if (destHint == null && directionSuffix != null) {
159 // use the destination:forward or :backward value
160 destSourceTagKey = "destination:" + directionSuffix;
161 destHint = w.getTag(destSourceTagKey);
162
163 }
164 if (destHint == null) {
165 // try to use the destination:street value
166 destSourceTagKey = "destination:street";
167 destHint = w.getTag(destSourceTagKey);
168 }
169 }
170
171 if (destHint != null) {
172 w.addTag(TAG_KEY_DEST_HINT_WORK, destHint);
173 destinationLinkWays.add(w);
174
175 if (log.isDebugEnabled() && !standardTagKey.equals(destSourceTagKey)) {
176 String msg = destSourceTagKey.startsWith(destinationLanes)
177 ? "as destination tag because there is one lane information only." : "as destination tag.";
178 log.debug("Use", destSourceTagKey, msg, "Way ", w.getId(), w.toTagString());
179 }
180 }
181 }
182
187183 /**
188184 * Registers the points of the given way for the internal data structures.
189185 * @param w a new way
190186 */
191187 private void registerPointsOfWay(Way w) {
192188 for (Coord c : w.getPoints()) {
193 Set<Way> ways = wayNodes.get(c);
194 if (ways == null) {
195 ways = new HashSet<>(4);
196 wayNodes.put(c, ways);
197 }
198 ways.add(w);
189 wayNodes.computeIfAbsent(c, k-> new HashSet<>()).add(w);
199190 }
200191 }
201192
234225 for (RestrictionRelation rr : new ArrayList<>(wayRestrictions)) {
235226 Coord lastPointNewWay = newWay.getFirstPoint();
236227 List<Coord> viaCoords = rr.getViaCoords();
237 for (Coord via : viaCoords){
228 for (Coord via : viaCoords) {
238229 if (via == lastPointNewWay) {
239230 if (rr.isToWay(oldWay.getId())) {
240231 log.debug("Change to-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL());
242233 restrictions.removeMapping(oldWay.getId(), rr);
243234 restrictions.add(newWay.getId(), rr);
244235
245 } else if (rr.isFromWay(oldWay.getId())){
236 } else if (rr.isFromWay(oldWay.getId())) {
246237 log.debug("Change from-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL());
247238 rr.replaceWay(oldWay.getId(), newWay.getId());
248239 restrictions.removeMapping(oldWay.getId(), rr);
260251 * @param maxLength the cut off way is no longer than this value
261252 * @return the cut off way or <code>null</code> if cutting not possible
262253 */
263 private Way cutoffWay(Way w, double cutLength, double maxLength, Coord c1, Coord c2) {
264 if (w.getPoints().size()<2) {
254 private Way cutoffWay(Way w, double cutLength, double maxLength) {
255 if (w.getPoints().size() < 2) {
265256 return null;
266257 }
267
258
268259 if (w.getPoints().size() >= 3) {
269260 // try to use existing points - that does not deform the way
270261 Coord firstPoint = w.getPoints().get(0);
287278 // check and update relations so that they use the new way if appropriate
288279 changeWayIdInRelations(w, precedingWay);
289280
290 log.debug("Cut way", w, "at existing point 1. New way:",
291 precedingWay);
281 log.debug("Cut way", w, "at existing point 1. New way:", precedingWay);
292282
293283 // return the new way
294284 return precedingWay;
295285 } else {
296 log.debug("Cannot cut way", w,
297 "on existing nodes because the first distance is too big:", dist);
286 log.debug("Cannot cut way", w, "on existing nodes because the first distance is too big:", dist);
298287 }
299288 }
300289
307296
308297 if (startSegmentLength + segmentLength >= cutLength) {
309298 double frac = (cutLength - startSegmentLength) / segmentLength;
310 // insert a new point at the minimum distance
299 // insert a new point at the minimum distance
311300 Coord cConnection = lastC.makeBetweenPoint(c, frac);
312
313 if (c1 != null && c2 != null && cConnection != null) {
314 // test if the way using the new point still uses the same
315 // orientation to the main motorway
316 double oldAngle = getAngle(c1, c2, c);
317 double newAngle = getAngle(c1, c2, cConnection);
318 if (Math.signum(oldAngle) != Math.signum(newAngle)) {
319 double bestAngleDiff = 180.0d;
320 Coord bestCoord = cConnection;
321 for (Coord cNeighbour : getDirectNeighbours(cConnection)) {
322 double neighbourAngle = getAngle(c1, c2, cNeighbour);
323 if (Math.signum(oldAngle) == Math.signum(neighbourAngle) &&
324 Math.abs(oldAngle - neighbourAngle) < bestAngleDiff) {
325 bestAngleDiff = Math.abs(oldAngle - neighbourAngle);
326 bestCoord = cNeighbour;
327 }
328 }
329 if (log.isDebugEnabled()) {
330 log.debug("Changed orientation:", oldAngle, "to",
331 newAngle);
332 log.debug("on Link", w);
333 log.debug("Corrected coord ", cConnection, "to",
334 bestCoord);
335 }
336 cConnection = bestCoord;
337 }
338 }
339
301 // check if we find a point which is closer to Garmin point in 24 resolution
302 Coord alternative = ExtNumbers.rasterLineNearPoint(c, lastC, cConnection, false);
303 if (alternative != null)
304 cConnection = alternative;
340305 // create the new way with identical tags
341 w.getPoints().add(i,cConnection);
342 Way precedingWay = new Way(w.getOriginalId(), new ArrayList<Coord>(w.getPoints().subList(0, i+1)));
306 w.getPoints().add(i, cConnection);
307 Way precedingWay = new Way(w.getOriginalId(), new ArrayList<Coord>(w.getPoints().subList(0, i + 1)));
343308 precedingWay.setFakeId();
344309 precedingWay.copyTags(w);
345310
353318 changeWayIdInRelations(w, precedingWay);
354319
355320 // return the split way
356 return precedingWay;
321 return precedingWay;
357322 }
358323 lastC = c;
359324 }
363328 }
364329
365330 /**
366 * TODO: move to Coord class?
367 * Retrieve a list of all Coords that are the direct neighbours of
368 * the given Coord. A neighbours latitude and longitude does not differ
369 * more than one Garmin unit from the given Coord.
370 * @param c the Coord for which the neighbours should be retrieved.
371 * @return all neighbours of c
372 */
373 private List<Coord> getDirectNeighbours(Coord c) {
374 List<Coord> neighbours = new ArrayList<>(8);
375 for (int dLat = -1; dLat < 2; dLat++) {
376 for (int dLon = -1; dLon < 2; dLon++) {
377 if (dLat != 0 || dLon != 0) {
378 neighbours.add(new Coord(c.getLatitude() + dLat, c.getLongitude() + dLon));
379 }
380 }
381 }
382 return neighbours;
383 }
384
385 /**
386 * Retrieves if the given node is tagged as motorway exit. So it must contain at least the tags
331 * Retrieves if the given node is tagged as usable exit. So it must contain at least the tags
387332 * highway=motorway_junction and one of the tags ref, name or exit_to.
388333 * @param node the node to check
389 * @return <code>true</code> the node is a motorway exit, <code>false</code> the node is not a
390 * motorway exit
334 * @return <code>true</code> if the node is a usable exit, else <code>false</code>
391335 */
392336 private boolean isTaggedAsExit(Node node) {
393 return "motorway_junction".equals(node.getTag("highway"))
394 && (node.getTag("ref") != null || (nameFinder.getName(node) != null) || node.getTag("exit_to") != null);
395 }
396
397 /**
398 * Retrieve all nodes that are connected to the given node either in
399 * driving direction or reverse.
400 * @param node a coord
401 * @param drivingDirection <code>true</code> driving direction; <code>false</code> reverse direction
402 * @return a list of all coords an the connection ways
403 */
404 private List<Entry<Coord, Way>> getNextNodes(Coord node, boolean drivingDirection) {
405 List<Entry<Coord, Way>> nextNodes = new ArrayList<>();
406
407 Set<Way> connectedWays = wayNodes.get(node);
408 for (Way w : connectedWays) {
409 // get the index of the node
410 int index = w.getPoints().indexOf(node);
411 if (index < 0) {
412 // this should not happen
413 log.error("Cannot find node "+node+" in way "+w);
414 continue;
415 }
416
417 boolean oneWayDirection = isOnewayInDirection(w);
418 // calc the index of the next node
419 index += (drivingDirection ? 1 : -1) * (oneWayDirection ? 1 : -1);
420
421 if (index >= 0 && index < w.getPoints().size()) {
422 nextNodes.add(new AbstractMap.SimpleEntry<Coord, Way>(w.getPoints().get(index), w));
423 }
424 }
425
426 return nextNodes;
427 }
428
429 /**
430 * Cuts motorway_link and trunk_link ways into three parts to be able to get
337 return "motorway_junction".equals(node.getTag(TAG_KEY_HIGHWAY))
338 && (node.getTag("ref") != null || (nameFinder.getName(node) != null) || node.getTag(TAG_KEY_EXIT_TO) != null);
339 }
340
341 /**
342 * Cuts major roads into three parts to be able to get
431343 * a hint on Garmin GPS. This happens if the the option process-exits is set
432344 * and the way is connected to an exit node (highway=motorway_junction)
433345 * and/or the option process-destination is set and the destination tag is
449361 * mkgmap:exit_hint_ref, mkgmap:exit_hint_name and/or mkgmap:exit_hint_exit_to.
450362 */
451363 private void processWays() {
364 cleanupLinkDestWays();
365 createExitHints();
366 createDestinationHints();
367 }
368
369 private void cleanupLinkDestWays() {
452370 // remove the adjacent links from the destinationLinkWays list
453371 // to avoid duplicate dest_hints
454 Queue<Way> linksWithDestination = new ArrayDeque<>();
455 linksWithDestination.addAll(destinationLinkWays.values());
372 Queue<Way> linksWithDestination = new ArrayDeque<>(destinationLinkWays);
456373 log.debug(destinationLinkWays.size(),"links with destination tag");
457374 while (!linksWithDestination.isEmpty()) {
458375 Way linkWay = linksWithDestination.poll();
459 String destination = linkWay.getTag("mkgmap:dest_hint_work");
376 String destination = linkWay.getTag(TAG_KEY_DEST_HINT_WORK);
460377 if (log.isDebugEnabled())
461 log.debug("Check way",linkWay.getId(),linkWay.toTagString());
378 log.debug("Check way", linkWay.getId(), linkWay.toTagString());
462379
463380 // Retrieve all adjacent ways of the current link
464 Coord c = linkWay.getLastPoint();
465 if (isOnewayOppositeDirection(linkWay)) {
466 c = linkWay.getFirstPoint();
467 }
381 Coord c = isOnewayOppositeDirection(linkWay) ? linkWay.getFirstPoint() : linkWay.getLastPoint();
468382
469383 Set<Way> nextWays = adjacentWays.get(c);
470384 if (nextWays != null) {
471385 for (Way connectedWay : nextWays) {
472 String nextDest = connectedWay.getTag("mkgmap:dest_hint_work");
386 String nextDest = connectedWay.getTag(TAG_KEY_DEST_HINT_WORK);
473387
474388 if (log.isDebugEnabled())
475389 log.debug("Followed by",connectedWay.getId(),connectedWay.toTagString());
476
390
477391 // remove the way from destination handling only if both ways are connected with start/end points
478392 // otherwise it is a crossroads and therefore both ways need to be handled
479 boolean startEndConnection = c.equals(connectedWay.getFirstPoint());
480 if (startEndConnection && !connectedWay.equals(linkWay)
481 && connectedWay.getTag("highway").endsWith("_link")
393 Coord c2 = isOnewayOppositeDirection(connectedWay) ? connectedWay.getLastPoint()
394 : connectedWay.getFirstPoint();
395
396 boolean startEndConnection = c == c2;
397 if (startEndConnection && !connectedWay.equals(linkWay)
398 && connectedWay.getTag(TAG_KEY_HIGHWAY).endsWith("_link")
482399 && destination.equals(nextDest)) {
483400 // do not use this way because there is another link before that with the same destination
484 destinationLinkWays.remove(connectedWay.getId());
485 if (log.isDebugEnabled())
486 log.debug("Removed",connectedWay.getId(),connectedWay.toTagString());
487 }
488 }
489 }
490 }
491 log.debug(destinationLinkWays.size(),"links with destination tag after cleanup");
492
493 if (processExits) {
494 // collect all nodes of highway=motorway/trunk ways so that we can check if an exit node
495 // belongs to a motorway/trunk or is a "subexit" within a motorway/trunk junction
496
497 Map<String, Set<Coord>> highwayCoords = new LinkedHashMap<>();
498 for (String type : highwayTypes){
499 highwayCoords.put(type, new HashSet<Coord>());
500 }
501 for (Way w : saver.getWays().values()) {
502 String highwayTag = w.getTag("highway");
503 if (highwayTag == null)
504 continue;
505 if (highwayTypes.contains(highwayTag)){
506 Set<Coord> set = highwayCoords.get(highwayTag);
507 set.addAll(w.getPoints());
508 }
509 }
510
511 // get all nodes tagged with highway=motorway_junction
512 for (Node exitNode : saver.getNodes().values()) {
513 if (isTaggedAsExit(exitNode) && saver.getBoundingBox().contains(exitNode.getLocation())) {
514 String expectedHighwayTag = null;
515 for (Entry<String, Set<Coord>> entry : highwayCoords.entrySet()){
516 if (entry.getValue().contains(exitNode.getLocation())){
517 expectedHighwayTag = entry.getKey();
518 break;
519 }
520 }
521 if (expectedHighwayTag == null){
522 // use exits only if they are located on a motorway or trunk
523 if (log.isDebugEnabled())
524 log.debug("Skip non highway exit:", exitNode.toBrowseURL(), exitNode.toTagString());
525 continue;
526 }
527 // retrieve all ways with this exit node
528 Set<Way> exitWays = adjacentWays.get(exitNode.getLocation());
529 if (exitWays==null) {
530 log.debug("Exit node", exitNode, "has no connected ways. Skip it.");
531 continue;
532 }
533
534 // retrieve the next node on the highway to be able to check if
535 // the inserted node has the correct orientation
536 List<Entry<Coord, Way>> nextNodes = getNextNodes(exitNode.getLocation(), true);
537 Coord nextHighwayNode = null;
538 int countMatches = 0;
539 for (Entry<Coord, Way> nextNode : nextNodes) {
540 if (expectedHighwayTag.equals(nextNode.getValue().getTag("highway"))) {
541 nextHighwayNode = nextNode.getKey();
542 countMatches++;
543 }
544 }
545 if (countMatches > 1){
546 // may happen when the highway is a link which splits further into two or more links
547 // ignore the node
548 nextHighwayNode = null;
549 }
550
551 // use link ways only
552 for (Way w : exitWays) {
553 destinationLinkWays.remove(w.getId());
554 if (isNotOneway(w)) {
555 log.warn("Ignore way",w,"because it is not oneway");
556 continue;
557 }
558 if (w.isViaWay()){
559 log.warn("Ignore way",w,"because it is a via way in a restriction relation");
560 continue;
561 }
562
563 String highwayLinkTag = w.getTag("highway");
564 if (highwayLinkTag.endsWith("_link")) {
565 log.debug("Try to cut",highwayLinkTag, w, "into three parts for giving hint to exit", exitNode);
566 // calc the way length to decide how to cut the way
567 double wayLength = getLength(w);
568 if (wayLength < 10 && w.getPoints().size() < 3) {
569 log.info("Way", w, "is too short (", wayLength," m) to cut it into several pieces. Cannot place exit hint.");
570 continue;
571 }
572
573
574 // now create three parts:
575 // wayPart1: original tags only
576 // hintWay: original tags plus the mkgmap:exit_hint* tags
577 // w: rest of the original way
578
579 double cut1 = Math.min(wayLength/2,20.0);
580 double cut2 = Math.min(wayLength, 100);
581 Way wayPart1 = cutoffWay(w,cut1, cut2, exitNode.getLocation(), nextHighwayNode);
582 if (wayPart1 == null) {
583 log.info("Way", w, "is too short to cut at least ",cut1,"m from it. Cannot create exit hint.");
584 continue;
585 } else {
586 if (log.isDebugEnabled())
587 log.debug("Cut off way", wayPart1, wayPart1.toTagString());
588 }
589
590 Way hintWay = w;
591 if (wayLength > 50) {
592 hintWay = cutoffWay(w, 10.0, 50.0, exitNode.getLocation(), nextHighwayNode);
593 }
594 if (hintWay == null) {
595 log.info("Way", w, "is too short to cut at least 20m from it. Cannot create exit hint.");
596 } else {
597 hintWay.addTag("mkgmap:exit_hint", "true");
598 if (processDestinations) {
599 String hint = hintWay.getTag("mkgmap:dest_hint_work");
600 if (hint != null){
601 hintWay.deleteTag("mkgmap:dest_hint_work");
602 hintWay.addTag("mkgmap:dest_hint", hint);
603 }
604 }
605 if (exitNode.getTag("ref") != null)
606 hintWay.addTag("mkgmap:exit_hint_ref", exitNode.getTag("ref"));
607 if (countMatches == 1 && exitNode.getTag("exit_to") != null) {
608 hintWay.addTag("mkgmap:exit_hint_exit_to", exitNode.getTag("exit_to"));
609 }
610 if (nameFinder.getName(exitNode) != null){
611 hintWay.addTag("mkgmap:exit_hint_name", nameFinder.getName(exitNode));
612 }
613
614 if (log.isInfoEnabled())
615 log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
616 }
401 boolean removed = destinationLinkWays.remove(connectedWay);
402 if (removed && log.isDebugEnabled()) {
403 log.debug("Removed", connectedWay.getId(), connectedWay.toTagString());
617404 }
618405 }
619406 }
620407 }
621408 }
622
409 log.debug(destinationLinkWays.size(),"links with destination tag after cleanup");
410 }
411
412 private void createExitHints() {
413 if(!processExits)
414 return;
415
416 List<String> hwSorted = new ArrayList<>(highwayTypes);
417 for (Node exitNode : saver.getNodes().values()) {
418 if (isTaggedAsExit(exitNode) && saver.getBoundingBox().contains(exitNode.getLocation())) {
419 // node is tagged with highway=motorway_junction and has usable exit info
420 processExitNode(exitNode, hwSorted);
421 }
422 }
423 }
424
425 /**
426 * Check if we can add an exit hint for the given exit node.
427 * @param exitNode
428 * @param hwSorted
429 * @param highwayCoords
430 */
431 private void processExitNode(Node exitNode, List<String> hwSorted) {
432 // retrieve all ways with this exit node
433 Set<Way> exitWays = adjacentWays.get(exitNode.getLocation());
434 if (exitWays == null) {
435 log.debug("Exit node", exitNode, "has no connected ways. Skip it.");
436 return;
437 }
438 String exitTo = exitNode.getTag(TAG_KEY_EXIT_TO);
439 if (exitTo != null) {
440 int countMatches = 0;
441 int preferred = Integer.MAX_VALUE;
442 for (Way w : exitWays) {
443 String hw = w.getTag(TAG_KEY_HIGHWAY);
444 int pos = hwSorted.indexOf(hw);
445 if (pos < preferred) {
446 preferred = pos;
447 countMatches = 1;
448 } else if (pos == preferred) {
449 countMatches++;
450 }
451 }
452 if (countMatches != 1)
453 exitTo = null; // don't use exit_to info, it typically contains info for all the ways
454 }
455
456 // use link ways only
457 for (Way w : exitWays) {
458 destinationLinkWays.remove(w);
459 if(!canSplit(w))
460 continue;
461 processExitWay(exitNode, w, exitTo);
462 }
463 }
464
465 private void processExitWay(Node exitNode, Way w, String exitTo) {
466 String highwayLinkTag = w.getTag(TAG_KEY_HIGHWAY);
467 if (highwayLinkTag.endsWith("_link")) {
468 log.debug("Try to cut", highwayLinkTag, w, "into three parts for giving hint to exit", exitNode);
469 Way hintWay = splitWay(w, "exit");
470 if (hintWay != null) {
471 fixDestHint(hintWay);
472 hintWay.addTag("mkgmap:exit_hint", "true");
473 if (exitNode.getTag("ref") != null)
474 hintWay.addTag("mkgmap:exit_hint_ref", exitNode.getTag("ref"));
475 if (exitTo != null) {
476 hintWay.addTag("mkgmap:exit_hint_exit_to", exitTo);
477 }
478 if (nameFinder.getName(exitNode) != null) {
479 hintWay.addTag("mkgmap:exit_hint_name", nameFinder.getName(exitNode));
480 }
481
482 if (log.isInfoEnabled())
483 log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
484 }
485 }
486 }
487
488 private String fixDestHint(Way hintWay) {
623489 if (processDestinations) {
624 // use link ways only
625 while (!destinationLinkWays.isEmpty()) {
626 Way w = destinationLinkWays.values().iterator().next();
627 destinationLinkWays.remove(w.getId());
628 if (isNotOneway(w)) {
629 log.warn("Ignore way",w,"because it is not oneway");
630 continue;
490 String hint = hintWay.getTag(TAG_KEY_DEST_HINT_WORK);
491 if (hint != null) {
492 hintWay.deleteTag(TAG_KEY_DEST_HINT_WORK);
493 hintWay.addTag("mkgmap:dest_hint", hint);
494 }
495 return hint;
496 }
497 return null;
498 }
499
500 private void createDestinationHints() {
501 if (!processDestinations)
502 return;
503 // use link ways only
504 while (!destinationLinkWays.isEmpty()) {
505 Way w = destinationLinkWays.iterator().next();
506 destinationLinkWays.remove(w);
507 String highwayLinkTag = w.getTag(TAG_KEY_HIGHWAY);
508 if (!canSplit(w) || !highwayLinkTag.endsWith("_link"))
509 continue;
510
511 log.debug("Try to cut",highwayLinkTag, w, "into three parts for giving hint");
512
513 Way hintWay = splitWay(w, "destination");
514 if (hintWay != null) {
515 String hint = fixDestHint(hintWay);
516 if (hint == null) {
517 log.error("Internal error in process_destination with way", hintWay);
631518 }
632 if (w.isViaWay()){
633 log.warn("Ignore way",w,"because it is a via way in a restriction relation");
634 continue;
635 }
636
637 String highwayLinkTag = w.getTag("highway");
638 if (highwayLinkTag.endsWith("_link")) {
639 log.debug("Try to cut",highwayLinkTag, w, "into three parts for giving hint");
640
641 Coord firstNode = w.getPoints().get(0);
642 Coord secondNode = w.getPoints().get(1);
643 // retrieve the next node on the highway to be able to check if
644 // the inserted node has the correct orientation
645 List<Entry<Coord, Way>> nextNodes = getNextNodes(firstNode, true);
646 Coord nextHighwayNode = null;
647 double angle = Double.MAX_VALUE;
648 for (Entry<Coord, Way> nextNode : nextNodes) {
649 if (nextNode.getValue().equals(w)) {
650 continue;
651 }
652 double thisAngle = getAngle(firstNode, secondNode, nextNode.getKey());
653 if (Math.abs(thisAngle) < angle) {
654 angle = Math.abs(thisAngle);
655 nextHighwayNode = nextNode.getKey();
656 }
657 }
658
659 // calc the way length to decide how to cut the way
660 double wayLength = getLength(w);
661 if (wayLength < 10) {
662 log.info("Way", w, "is too short (", wayLength," m) to cut it into several pieces. Cannot place destination hint.");
663 continue;
664 }
665
666 // now create three parts:
667 // wayPart1: original tags only
668 // hintWay: original tags plus the mkgmap:exit_hint* tags
669 // w: rest of the original way
670
671 double cut1 = Math.min(wayLength/2, 20.0);
672 double cut2 = Math.min(wayLength, 100);
673 Way wayPart1 = cutoffWay(w, cut1, cut2, firstNode, nextHighwayNode);
674 if (wayPart1 == null) {
675 log.info("Way", w, "is too short to cut at least 10m from it. Cannot create destination hint.");
676 continue;
677 } else {
678 if (log.isDebugEnabled())
679 log.debug("Cut off way", wayPart1, wayPart1.toTagString());
680 }
681
682 Way hintWay = w;
683 if (wayLength > 50) {
684 hintWay = cutoffWay(w, 10.0, 50.0, firstNode, nextHighwayNode);
685 }
686 if (hintWay == null) {
687 log.info("Way", w, "is too short to cut at least 20m from it. Cannot create destination hint.");
688 } else {
689 String hint = hintWay.getTag("mkgmap:dest_hint_work");
690 if (hint != null){
691 hintWay.deleteTag("mkgmap:dest_hint_work");
692 hintWay.addTag("mkgmap:dest_hint", hint);
693 } else {
694 log.error("Internal error in process_destination with way",hintWay);
695 }
696
697 if (log.isInfoEnabled())
698 log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
699 }
700 }
701 }
702 }
703 }
704
705 /**
706 * Retrieves the angle in clockwise direction between the line (cCenter, c1)
707 * and the line (cCenter, c2).
708 * @param cCenter the common point of both lines
709 * @param c1 point of the first line
710 * @param c2 point of the second line
711 * @return the angle [-180; 180]
712 */
713 private double getAngle(Coord cCenter, Coord c1, Coord c2)
714 {
715 int dx1 = c1.getLongitude() - cCenter.getLongitude();
716 int dy1 = -(c1.getLatitude() - cCenter.getLatitude());
717
718 int dx2 = c2.getLongitude() - cCenter.getLongitude();
719 int dy2 = -(c2.getLatitude() - cCenter.getLatitude());
720
721 double inRads1 = Math.atan2(dy1, dx1);
722 double inRads2 = Math.atan2(dy2, dx2);
723
724 return Math.toDegrees(inRads2) - Math.toDegrees(inRads1);
519
520 if (log.isInfoEnabled())
521 log.info("Cut off exit hint way", hintWay, hintWay.toTagString());
522 }
523 }
524 }
525
526 /**
527 * Try to split the way. If successful, it creates two or three parts.
528 * <ul>
529 * <li>wayPart1: original tags only</li>
530 * <li>hintWay: original tags plus the mkgmap:exit_hint* tags</li>
531 * <li>rest of the original way (if any remains)</li>
532 * </ul>
533 * @param w the way to split
534 * @param hintType the type of hint that is added (exit or destination), use for logging only
535 * @return null if not successful, else the hintWay
536 */
537 private Way splitWay(Way w, String hintType) {
538 // calc the way length to decide how to cut the way
539 double wayLength = w.calcLengthInMetres();
540 double cut1 = Math.min(wayLength / 2, 20.0);
541 double cut2 = Math.min(wayLength, 100);
542 Way wayPart1 = cutoffWay(w, cut1, cut2);
543 if (wayPart1 == null) {
544 log.info("Way", w, "is too short to cut at least", cut1, "m from it. Cannot create", hintType, "hint.");
545 return null;
546 }
547 if (log.isDebugEnabled())
548 log.debug("Cut off way", wayPart1, wayPart1.toTagString());
549
550 Way hintWay = w;
551 if (wayLength > 50) {
552 hintWay = cutoffWay(w, 10.0, 50.0);
553 }
554 if (hintWay == null) {
555 log.info("Way", w, "is too short to cut at least 20m from it. Cannot create", hintType, "hint.");
556 }
557 return hintWay;
558 }
559
560 private static boolean canSplit(Way w) {
561 if (isNotOneway(w)) {
562 log.warn("Ignore way", w, "because it is not oneway");
563 return false;
564 }
565 if (w.isViaWay()) {
566 log.warn("Ignore way", w, "because it is a via way in a restriction relation");
567 return false;
568 }
569 return w.calcLengthInMetres() >= 0.3;
725570 }
726571
727572 /**
731576 adjacentWays = null;
732577 wayNodes = null;
733578 destinationLinkWays = null;
734 linkTypes = null;
735579 saver = null;
736580 nameFinder = null;
737581 }
746590 // referenced in the style file
747591 Set<String> tags = new HashSet<>();
748592 tags.add("highway");
593 tags.add("oneway");
749594 tags.add("destination");
750595 tags.add("destination:lanes");
751596 tags.add("destination:lanes:forward");
753598 tags.add("destination:forward");
754599 tags.add("destination:backward");
755600 tags.add("destination:street");
756 if (processExits){
601 if (processExits) {
757602 tags.add("exit_to");
758603 tags.add("ref");
759604 }
764609 public void end() {
765610 log.info("LinkDestinationHook started");
766611
767 retrieveWays();
768
769 if (processExits || processDestinations)
770 processWays();
771
612 retrieveWaysAndRelations();
613 processWays();
772614 cleanup();
773615
774616 log.info("LinkDestinationHook finished");
779621 * @param w the way
780622 * @return <code>true</code> way is oneway
781623 */
782 private boolean isOnewayInDirection(Way w) {
783 if (w.tagIsLikeYes("oneway")) {
624 private static boolean isOnewayInDirection(Way w) {
625 if (w.tagIsLikeYes(TAG_KEY_ONEWAY)) {
784626 return true;
785627 }
786628
787629 // check if oneway is set implicitly by the highway type (motorway and motorway_link)
788 String onewayTag = w.getTag("oneway");
789 String highwayTag = w.getTag("highway");
630 String onewayTag = w.getTag(TAG_KEY_ONEWAY);
631 String highwayTag = w.getTag(TAG_KEY_HIGHWAY);
790632 return onewayTag == null && highwayTag != null
791 && (highwayTag.equals("motorway") || highwayTag.equals("motorway_link"));
633 && ("motorway".equals(highwayTag)|| "motorway_link".equals(highwayTag));
792634 }
793635
794636 /**
796638 * @param w the way
797639 * @return <code>true</code> way is oneway in opposite direction
798640 */
799 private boolean isOnewayOppositeDirection(Way w) {
800 return "-1".equals(w.getTag("oneway"));
641 private static boolean isOnewayOppositeDirection(Way w) {
642 return "-1".equals(w.getTag(TAG_KEY_ONEWAY));
801643 }
802644
803645 /**
805647 * @param w the way
806648 * @return <code>true</code> way is not oneway
807649 */
808 private boolean isNotOneway(Way w) {
809 return "no".equals(w.getTag("oneway")) || (!isOnewayInDirection(w) && !isOnewayOppositeDirection(w));
810 }
811
812 /** Private length function without caching */
813 private LengthFunction length = new LengthFunction() {
814 @Override
815 public boolean isCached() {
816 return false;
817 }
818 };
819
820 /**
821 * Retrieve the length of the given way.
822 * @param w way
823 * @return length in m
824 */
825 private double getLength(Way w) {
826 String lengthValue = length.value(w);
827 try {
828 return Math.round(Double.valueOf(lengthValue));
829 } catch (Exception exp) {
830 return 0;
831 }
832 }
833
650 private static boolean isNotOneway(Way w) {
651 return "no".equals(w.getTag(TAG_KEY_ONEWAY)) || (!isOnewayInDirection(w) && !isOnewayOppositeDirection(w));
652 }
834653 }
4242 public class RestrictionRelation extends Relation {
4343 private static final Logger log = Logger.getLogger(RestrictionRelation.class);
4444
45 private List<Long> fromWayIds = new ArrayList<>(2);
46 private List<Long> toWayIds = new ArrayList<>(2);
47 private List<Long> viaWayIds = new ArrayList<>(2);
48 private List<Coord> viaPoints = new ArrayList<>(2);
49 private Map<Long, List<Coord>> updatedViaWays = new HashMap<>();
50 private Coord viaCoord;
51 private String restriction;
45 private List<Long> fromWayIds = new ArrayList<>(2);
46 private List<Long> toWayIds = new ArrayList<>(2);
47 private List<Long> viaWayIds = new ArrayList<>(2);
48 private List<Coord> viaPoints = new ArrayList<>(2);
49 private Map<Long, List<Coord>> updatedViaWays = new HashMap<>();
50 private Coord viaCoord;
51 private String restriction;
5252 private byte exceptMask;
53 private char dirIndicator;
54 private String messagePrefix;
55 private boolean valid;
56 private boolean evalWasCalled;
53 private char dirIndicator;
54 private String msgPrefix;
55 private boolean valid;
56 private boolean evalWasCalled;
5757
5858 // These tags are not loaded by default but if they exist issue a warning
59 private final static String[] unsupportedTags = { "day_on", "day_off", "hour_on", "hour_off" };
60
61 private final static byte DEFAULT_EXCEPT_MASK = AccessTagsAndBits.FOOT | AccessTagsAndBits.EMERGENCY;
62
63 private final static List<String> supportedRestrictions = Arrays.asList(
59 private static final String[] unsupportedTags = { "day_on", "day_off", "hour_on", "hour_off" };
60
61 private static final byte DEFAULT_EXCEPT_MASK = AccessTagsAndBits.FOOT | AccessTagsAndBits.EMERGENCY;
62
63 private static final List<String> supportedRestrictions = Arrays.asList(
6464 "no_right_turn", "no_left_turn", "no_u_turn", "no_straight_on",
6565 "only_right_turn", "only_left_turn", "only_straight_on",
6666 "no_entry", "no_exit"
7474 */
7575 public RestrictionRelation(Relation other) {
7676 setId(other.getId());
77 messagePrefix = "Turn restriction " + toBrowseURL();
77 msgPrefix = "Turn restriction " + toBrowseURL();
7878 copyTags(other);
7979 for (Map.Entry<String, Element> pair : other.getElements()) {
8080 addElement(pair.getKey(), pair.getValue());
8181 }
8282 }
83
83
8484 /**
8585 * The evaluation should happen after style processing.
8686 * Normally this is called from the {@link RelationStyleHook}
8787 * Performs also diverse plausibility checks.
8888 * @param bbox tile boundary
8989 */
90 public void eval(Area bbox){
91 if (evalWasCalled){
92 log.error(messagePrefix,"internal error: eval() was already called");
90 public void eval(Area bbox) {
91 if (evalWasCalled) {
92 log.error(msgPrefix, "internal error: eval() was already called");
9393 fromWayIds.clear();
9494 toWayIds.clear();
9595 viaWayIds.clear();
9696 }
9797 evalWasCalled = true;
98 if (getTag("type") == null){
98 if (getTag("type") == null) {
9999 // style removed the tag
100 log.info(messagePrefix, "type tag was removed, relation is ignored");
101 valid = false;
102 return;
103 }
104
105 List<Way> fromWays = new ArrayList<>();
106 List<Way> toWays = new ArrayList<>();
107 List<Way> viaWays = new ArrayList<>();
100 log.info(msgPrefix, "type tag was removed, relation is ignored");
101 valid = false;
102 return;
103 }
104
105 List<Way> fromWays = new ArrayList<>();
106 List<Way> toWays = new ArrayList<>();
107 List<Way> viaWays = new ArrayList<>();
108108 final String browseURL = toBrowseURL();
109109 valid = true;
110110 // find out what kind of restriction we have and to which vehicles it applies
111111 exceptMask = DEFAULT_EXCEPT_MASK;
112 String specifc_type = getTag("restriction");
113 int count_unknown = 0;
112 String specificType = getTag("restriction");
113 int countUnknown = 0;
114114 Map<String, String> vehicles = getTagsWithPrefix("restriction:", true);
115 if (vehicles.isEmpty() == false){
115 if (!vehicles.isEmpty()) {
116116 exceptMask = (byte) 0xff;
117117 Iterator<Entry<String, String>> iter = vehicles.entrySet().iterator();
118 while (iter.hasNext()){
118 while (iter.hasNext()) {
119119 Map.Entry<String, String> entry = iter.next();
120120 String vehicle = entry.getKey();
121 if (setExceptMask(vehicle, false) == false)
122 count_unknown++;
123 if (specifc_type == null)
124 specifc_type = entry.getValue();
125 else if (specifc_type.equals(entry.getValue()) == false){
126 log.warn(messagePrefix, "is invalid, it specifies different kinds of turns");
121 if (!setExceptMask(vehicle, false))
122 countUnknown++;
123 if (specificType == null)
124 specificType = entry.getValue();
125 else if (!specificType.equals(entry.getValue())) {
126 log.warn(msgPrefix, "is invalid, it specifies different kinds of turns");
127127 valid = false;
128128 break;
129129 }
130130 }
131 if (valid && vehicles.size() == count_unknown){
132 log.warn(messagePrefix, "no supported vehicle in turn restriction");
131 if (valid && vehicles.size() == countUnknown) {
132 log.warn(msgPrefix, "no supported vehicle in turn restriction");
133133 valid = false;
134134 return;
135135 }
136136 }
137 if (specifc_type == null){
137 if (specificType == null) {
138138 // style removed the tag
139 log.info(messagePrefix, "no valid restriction tag found");
140 valid = false;
141 return;
142 }
143 restriction = specifc_type.trim();
144
145 messagePrefix = "Turn restriction (" + restriction + ") " + browseURL;
146 if (supportedRestrictions.contains(restriction) == false){
147 log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
148 valid = false;
149 return;
150 }
151
152 String dirInfo = "";
139 log.info(msgPrefix, "no valid restriction tag found");
140 valid = false;
141 return;
142 }
143 restriction = specificType.trim();
144
145 msgPrefix = "Turn restriction (" + restriction + ") " + browseURL;
146 if (!supportedRestrictions.contains(restriction)) {
147 log.warn(msgPrefix, "ignoring unsupported restriction type '" + restriction + "'");
148 valid = false;
149 return;
150 }
151
152 dirIndicator = '?';
153153 if (restriction.contains("left"))
154 dirInfo += "l";
155 if (restriction.contains("right"))
156 dirInfo += "r";
157 if (restriction.contains("straight"))
158 dirInfo += "s";
159 if (restriction.endsWith("u_turn"))
160 dirInfo += "u";
161 if (dirInfo.length() > 1){
162 log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
163 valid = false;
164 return;
165 } else if (dirInfo.length() == 1){
166 dirIndicator = dirInfo.charAt(0);
167 } else
168 dirIndicator = '?';
169
154 dirIndicator = 'l';
155 else if (restriction.contains("right"))
156 dirIndicator = 'r';
157 else if (restriction.contains("straight"))
158 dirIndicator = 's';
159 else if (restriction.endsWith("u_turn"))
160 dirIndicator = 'u';
170161 String type = getTag("type");
171 if (type.startsWith("restriction:")){
162 if (type.startsWith("restriction:")) {
172163 exceptMask = (byte) 0xff;
173164 String vehicle = type.substring("restriction:".length());
174 if (setExceptMask(vehicle, false) == false) {
175 log.warn(messagePrefix, "ignoring unsupported '" + vehicle + "' in turn restriction");
165 if (!setExceptMask(vehicle, false)) {
166 log.warn(msgPrefix, "ignoring unsupported '" + vehicle + "' in turn restriction");
176167 valid = false;
177168 return;
178169 }
179170 }
180171
181172 String except = getTag("except");
182 if(except != null) {
183 for(String vehicle : except.split("[,;]")) { // be nice
173 if (except != null) {
174 for (String vehicle : except.split("[,;]")) { // be nice
184175 vehicle = vehicle.trim();
185176 setExceptMask(vehicle, true);
186177 }
187178 }
188
179
189180 for (String unsupportedTag : unsupportedTags) {
190181 if (getTag(unsupportedTag) != null) {
191 log.warn(messagePrefix, "ignoring unsupported '" + unsupportedTag + "' tag");
182 log.warn(msgPrefix, "ignoring unsupported '" + unsupportedTag + "' tag");
192183 }
193184 }
194185
199190
200191 Coord location = null;
201192
202 if(viaCoord != null)
193 if (viaCoord != null)
203194 location = viaCoord;
204 else if(!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty())
195 else if (!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty())
205196 location = fromWays.get(0).getFirstPoint();
206 else if(!toWays.isEmpty() && !toWays.get(0).getPoints().isEmpty())
197 else if (!toWays.isEmpty() && !toWays.get(0).getPoints().isEmpty())
207198 location = toWays.get(0).getFirstPoint();
208 else if(!viaWays.isEmpty() && !viaWays.get(0).getPoints().isEmpty())
199 else if (!viaWays.isEmpty() && !viaWays.get(0).getPoints().isEmpty())
209200 location = viaWays.get(0).getFirstPoint();
210201
211 if(location != null)
212 messagePrefix = "Turn restriction (" + restriction + ") " + browseURL + " (at " + location.toOSMURL() + ")";
213
214 if("to".equals(role)) {
215 if(!(el instanceof Way)) {
216 log.warn(messagePrefix, "'to' member", el.toBrowseURL(), "is not a way but it should be");
217 }
218 else if(((Way)el).getPoints().isEmpty()) {
219 log.warn(messagePrefix, "ignoring empty 'to' way", el.toBrowseURL());
220 }
221 else
222 toWays.add((Way)el);
223 }
224 else if("from".equals(role)) {
225 if(!(el instanceof Way)) {
226 log.warn(messagePrefix, "'from' member", el.toBrowseURL(), "is not a way but it should be");
227 }
228 else if(((Way)el).getPoints().isEmpty()) {
229 log.warn(messagePrefix, "ignoring empty 'from' way", el.toBrowseURL());
230 }
231 else
232 fromWays.add((Way)el);
233 }
234 else if("via".equals(role)) {
235 if(el instanceof Node) {
236 if (viaCoord != null){
237 log.warn(messagePrefix, "has extra 'via' node", el.toBrowseURL());
238 valid = false;
239 } else
240 viaCoord = ((Node)el).getLocation();
241 }
242 else if(el instanceof Way) {
243 if (viaCoord != null){
244 log.warn(messagePrefix, "has extra 'via' way", el.toBrowseURL());
245 valid = false;
246 } else
247 viaWays.add((Way)el);
248 }
249 else {
250 log.warn(messagePrefix, "'via' member", el.toBrowseURL(), "is not a node or way");
251 }
252 }
253 else if("location_hint".equals(role)) {
202 if (location != null)
203 msgPrefix = "Turn restriction (" + restriction + ") " + browseURL + " (at " + location.toOSMURL() + ")";
204
205 if ("to".equals(role)) {
206 if (!(el instanceof Way)) {
207 log.warn(msgPrefix, "'to' member", el.toBrowseURL(), "is not a way but it should be");
208 } else if (((Way) el).getPoints().isEmpty()) {
209 log.warn(msgPrefix, "ignoring empty 'to' way", el.toBrowseURL());
210 } else {
211 toWays.add((Way) el);
212 }
213 } else if ("from".equals(role)) {
214 if (!(el instanceof Way)) {
215 log.warn(msgPrefix, "'from' member", el.toBrowseURL(), "is not a way but it should be");
216 } else if (((Way) el).getPoints().isEmpty()) {
217 log.warn(msgPrefix, "ignoring empty 'from' way", el.toBrowseURL());
218 } else {
219 fromWays.add((Way) el);
220 }
221 } else if ("via".equals(role)) {
222 if (el instanceof Node) {
223 if (viaCoord != null) {
224 log.warn(msgPrefix, "has extra 'via' node", el.toBrowseURL());
225 valid = false;
226 } else {
227 viaCoord = ((Node) el).getLocation();
228 }
229 } else if (el instanceof Way) {
230 if (viaCoord != null) {
231 log.warn(msgPrefix, "has extra 'via' way", el.toBrowseURL());
232 valid = false;
233 } else {
234 viaWays.add((Way) el);
235 }
236 } else {
237 log.warn(msgPrefix, "'via' member", el.toBrowseURL(), "is not a node or way");
238 }
239 } else if ("location_hint".equals(role)) {
254240 // relax - we don't care about this
255 }
256 else {
257 log.warn(messagePrefix, "unknown member role '" + role + "'");
258 }
259 }
260
241 } else {
242 log.warn(msgPrefix, "unknown member role '" + role + "'");
243 }
244 }
261245
262246 if (!valid)
263247 return;
264
265 if ("no_entry".equals(restriction) == false){
266 if (fromWays.size() > 1){
267 log.warn(messagePrefix, "multiple 'from' members are only accepted for no_entry restrictions");
268 valid = false;
269 return;
270 }
271 }
272 if ("no_exit".equals(restriction) == false){
273 if (toWays.size() > 1){
274 log.warn(messagePrefix, "multiple 'to' members are only accepted for no_exit restrictions");
275 valid = false;
276 return;
277 }
278 }
279 if (viaWays.isEmpty() && viaCoord == null && fromWays.size() == 1 && toWays.size() == 1){
248
249 if (!"no_entry".equals(restriction) && fromWays.size() > 1) {
250 log.warn(msgPrefix, "multiple 'from' members are only accepted for no_entry restrictions");
251 valid = false;
252 return;
253 }
254 if (!"no_exit".equals(restriction) && toWays.size() > 1) {
255 log.warn(msgPrefix, "multiple 'to' members are only accepted for no_exit restrictions");
256 valid = false;
257 return;
258 }
259 if (viaWays.isEmpty() && viaCoord == null && fromWays.size() == 1 && toWays.size() == 1) {
280260 Way fromWay = fromWays.get(0);
281261 Way toWay = toWays.get(0);
282 List<Coord>fromPoints = fromWay.getPoints();
283 List<Coord>toPoints = toWay.getPoints();
262 List<Coord> fromPoints = fromWay.getPoints();
263 List<Coord> toPoints = toWay.getPoints();
284264 int countSame = 0;
285 for(Coord fp : fromPoints) {
286 for(Coord tp : toPoints) {
287 if(fp == tp){
265 for (Coord fp : fromPoints) {
266 for (Coord tp : toPoints) {
267 if (fp == tp) {
288268 countSame++;
289269 viaCoord = fp;
290270 }
291271 }
292272 }
293 if (countSame > 1){
294 log.warn(messagePrefix, "lacks 'via' node and way and the 'from' (", fromWay.toBrowseURL(), ") and 'to' (", toWay.toBrowseURL(), ") ways connect in more than one place");
273 if (countSame > 1) {
274 log.warn(msgPrefix, "lacks 'via' node and way and the 'from' (", fromWay.toBrowseURL(),
275 ") and 'to' (", toWay.toBrowseURL(), ") ways connect in more than one place");
295276 valid = false;
296 } else if (viaCoord == null){
297 log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect");
277 } else if (viaCoord == null) {
278 log.warn(msgPrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' ("
279 + toWay.toBrowseURL() + ") ways don't connect");
298280 valid = false;
299281 } else {
300 if (fromPoints.get(0) != viaCoord && fromPoints.get(fromPoints.size()-1) != viaCoord ||
301 toPoints.get(0) != viaCoord && toPoints.get(toPoints.size()-1) != viaCoord){
302 log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect at an end point");
282 if (fromPoints.get(0) != viaCoord && fromPoints.get(fromPoints.size() - 1) != viaCoord
283 || toPoints.get(0) != viaCoord && toPoints.get(toPoints.size() - 1) != viaCoord) {
284 log.warn(msgPrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' ("
285 + toWay.toBrowseURL() + ") ways don't connect at an end point");
303286 valid = false;
304 } else
305 log.warn(messagePrefix, "lacks 'via' node (guessing it should be at", viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");
306 }
307 }
308
309 if(fromWays.isEmpty() ) {
310 log.warn(messagePrefix, "lacks 'from' way");
311 valid = false;
312 }
313
314 if(toWays.isEmpty()) {
315 log.warn(messagePrefix, "lacks 'to' way");
316 valid = false;
317 }
318
319 if ((fromWays.size() > 1 || toWays.size() > 1) && viaWays.isEmpty() == false){
320 log.warn(messagePrefix, "'via' way(s) are not supported with multiple 'from' or 'to' ways");
287 } else {
288 log.warn(msgPrefix, "lacks 'via' node (guessing it should be at",
289 viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");
290 }
291 }
292 }
293
294 if (fromWays.isEmpty()) {
295 log.warn(msgPrefix, "lacks 'from' way");
296 valid = false;
297 }
298
299 if (toWays.isEmpty()) {
300 log.warn(msgPrefix, "lacks 'to' way");
301 valid = false;
302 }
303
304 if ((fromWays.size() > 1 || toWays.size() > 1) && !viaWays.isEmpty()) {
305 log.warn(msgPrefix, "'via' way(s) are not supported with multiple 'from' or 'to' ways");
321306 valid = false;
322307 }
323308 if (!valid)
325310 for (List<Way> ways : Arrays.asList(fromWays,viaWays,toWays)){
326311 for (Way way : ways){
327312 if (way.getPoints().size() < 2){
328 log.warn(messagePrefix,"way",way.toBrowseURL(),"has less than 2 points, restriction is ignored");
313 log.warn(msgPrefix,"way",way.toBrowseURL(),"has less than 2 points, restriction is ignored");
329314 valid = false;
330315 } else {
331316 if (way.hasIdenticalEndPoints()){
332317 if (ways == toWays && dirIndicator != '?')
333318 continue; // we try to determine the correct part in RoadNetwork
334 log.warn(messagePrefix, "way", way.toBrowseURL(), "starts and ends at same node, don't know which one to use");
319 log.warn(msgPrefix, "way", way.toBrowseURL(), "starts and ends at same node, don't know which one to use");
335320 valid = false;
336321 }
337322 }
339324 }
340325 if (!valid)
341326 return;
342 if (viaPoints.isEmpty() == false)
327 if (!viaPoints.isEmpty())
343328 viaCoord = viaPoints.get(0);
344329
345330 if(viaCoord == null && viaWays.isEmpty()) {
350335 viaPoints.clear();
351336 Coord v1 = viaCoord;
352337 Coord v2 = viaCoord;
353 if (viaWays.isEmpty() == false){
338 if (!viaWays.isEmpty()) {
354339 v1 = viaWays.get(0).getFirstPoint();
355340 v2 = viaWays.get(0).getLastPoint();
356341 }
357342 // check if all from ways are connected at the given via point or with the given via ways
358 for (Way fromWay : fromWays){
343 for (Way fromWay : fromWays) {
359344 Coord e1 = fromWay.getFirstPoint();
360345 Coord e2 = fromWay.getLastPoint();
361346 if (e1 == v1 || e2 == v1)
363348 else if (e1 == v2 || e2 == v2)
364349 viaCoord = v2;
365350 else {
366 log.warn(messagePrefix, "'from' way", fromWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
351 log.warn(msgPrefix, "'from' way", fromWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
367352 valid = false;
368 }
353 }
369354 }
370355 if (!valid)
371356 return;
372357 viaPoints.add(viaCoord);
373358 // check if via ways are connected in the given order
374 for (int i = 0; i < viaWays.size();i++){
359 for (int i = 0; i < viaWays.size(); i++) {
375360 Way way = viaWays.get(i);
376 Coord v = viaPoints.get(viaPoints.size()-1);
361 Coord v = viaPoints.get(viaPoints.size() - 1);
377362 if (way.getFirstPoint() == v)
378363 v2 = way.getLastPoint();
379364 else if (way.getLastPoint() == v)
380365 v2 = way.getFirstPoint();
381366 else {
382 log.warn(messagePrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at",v.toDegreeString());
367 log.warn(msgPrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at", v.toDegreeString());
383368 valid = false;
384369 }
385370 viaPoints.add(v2);
387372
388373 // check if all via points are inside the bounding box
389374 int countInside = 0;
390 for (Coord via: viaPoints){
391 if(bbox.contains(via))
375 for (Coord via : viaPoints) {
376 if (bbox.contains(via))
392377 ++countInside;
393378 }
394379 if (countInside == 0)
395380 valid = false;
396 else if (countInside > 0 && countInside < viaPoints.size()){
397 log.warn(messagePrefix,"via way crosses tile boundary. Don't know how to save that, ignoring it");
398 valid = false;
399 }
400
381 else if (countInside > 0 && countInside < viaPoints.size()) {
382 log.warn(msgPrefix, "via way crosses tile boundary. Don't know how to save that, ignoring it");
383 valid = false;
384 }
385
401386 if (!valid)
402387 return;
403388 // check if all to ways are connected to via point or last via way
404 Coord lastVia = viaPoints.get(viaPoints.size()-1);
405 for (Way toWay : toWays){
389 Coord lastVia = viaPoints.get(viaPoints.size() - 1);
390 for (Way toWay : toWays) {
406391 Coord e1 = toWay.getFirstPoint();
407392 Coord e2 = toWay.getLastPoint();
408 if(e1 != lastVia && e2 != lastVia) {
409 log.warn(messagePrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
393 if (e1 != lastVia && e2 != lastVia) {
394 log.warn(msgPrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
410395 valid = false;
411 }
412 }
413 if (valid && !viaWays.isEmpty() && restriction.startsWith("only")){
414 log.warn(messagePrefix, "check: 'via' way(s) are used in",restriction,"restriction");
415 }
416 if (valid){
417 // make sure that via way(s) don't appear in the from or to lists
418 for (Way w: viaWays){
419 if (fromWays.contains(w)){
420 log.warn(messagePrefix, "'via' way",w.toBrowseURL(),"appears also as 'from' way");
396 }
397 }
398 if (valid && !viaWays.isEmpty() && restriction.startsWith("only")) {
399 log.warn(msgPrefix, "check: 'via' way(s) are used in", restriction, "restriction");
400 }
401 if (valid) {
402 // make sure that via way(s) don't appear in the from or to lists
403 for (Way w : viaWays) {
404 if (fromWays.contains(w)) {
405 log.warn(msgPrefix, "'via' way", w.toBrowseURL(), "appears also as 'from' way");
421406 valid = false;
422407 }
423 if (toWays.contains(w)){
424 log.warn(messagePrefix, "'via' way",w.toBrowseURL(),"appears also as 'to' way");
408 if (toWays.contains(w)) {
409 log.warn(msgPrefix, "'via' way", w.toBrowseURL(), "appears also as 'to' way");
425410 valid = false;
426411 }
427412 }
428413 }
429 if (valid){
430 for (Way w: fromWays)
414 if (valid) {
415 for (Way w : fromWays)
431416 fromWayIds.add(w.getId());
432 for (Way w: toWays)
417 for (Way w : toWays)
433418 toWayIds.add(w.getId());
434 for (Way w: viaWays){
419 for (Way w : viaWays) {
435420 w.setViaWay(true);
436421 viaWayIds.add(w.getId());
437422 }
438 for (Coord v: viaPoints)
423 for (Coord v : viaPoints)
439424 v.setViaNodeOfRestriction(true);
440425 }
441426 }
476461 else if(vehicle.equals("foot"))
477462 flag = AccessTagsAndBits.FOOT;
478463 if (flag == 0){
479 log.warn(messagePrefix, "ignoring unsupported vehicle class '" + vehicle + "' in turn restriction");
464 log.warn(msgPrefix, "ignoring unsupported vehicle class '" + vehicle + "' in turn restriction");
480465 return false;
481466 }
482467
500485 if (viaPoints.get(i) == oldP){
501486 viaPoints.set(i, newP);
502487 if (log.isDebugEnabled()){
503 log.debug(messagePrefix, restriction, "'via' coord redefined from",
488 log.debug(msgPrefix, restriction, "'via' coord redefined from",
504489 oldP.toOSMURL(), "to", newP.toOSMURL());
505490 }
506491 return;
515500 for (Coord v: viaPoints){
516501 CoordNode vn = nodeIdMap.get(v);
517502 if (vn == null){
518 log.warn(messagePrefix,"via node is not a routing node, restriction relation is ignored");
503 log.warn(msgPrefix,"via node is not a routing node, restriction relation is ignored");
519504 return;
520505 }
521506 viaNodes.add(vn);
522507 }
523508
524509 if (viaNodes.size() > 6){
525 log.warn(messagePrefix,"has more than 6 via nodes, this is not supported");
510 log.warn(msgPrefix,"has more than 6 via nodes, this is not supported");
526511 return;
527512 }
528513 if(restriction == null){
534519 if(restriction.startsWith("no_")){
535520 for (long fromWayId : fromWayIds){
536521 for (long toWayId : toWayIds){
537 grr = new GeneralRouteRestriction("not", exceptMask, messagePrefix);
522 grr = new GeneralRouteRestriction("not", exceptMask, msgPrefix);
538523 grr.setFromWayId(fromWayId);
539524 grr.setToWayId(toWayId);
540525 grr.setViaNodes(viaNodes);
544529 }
545530 }
546531 if (log.isInfoEnabled())
547 log.info(messagePrefix, restriction, "translated to",addedRestrictions,"img file restrictions");
532 log.info(msgPrefix, restriction, "translated to",addedRestrictions,"img file restrictions");
548533 }
549534 else if(restriction.startsWith("only_")){
550 grr = new GeneralRouteRestriction("only", exceptMask, messagePrefix);
535 grr = new GeneralRouteRestriction("only", exceptMask, msgPrefix);
551536 grr.setFromWayId(fromWayIds.get(0));
552537 grr.setToWayId(toWayIds.get(0));
553538 grr.setViaNodes(viaNodes);
555540 grr.setDirIndicator(dirIndicator);
556541 int numAdded = collector.addRestriction(grr);
557542 if (numAdded > 0)
558 log.info(messagePrefix, restriction, "added - allows routing to way", toWayIds.get(0));
543 log.info(msgPrefix, restriction, "added - allows routing to way", toWayIds.get(0));
559544
560545 }
561546 else {
569554 // relax
570555 }
571556
557 @Override
572558 public String toString() {
573559 String s = "[restriction id = " + getId() + "(" + restriction + ")";
574560 if (!fromWayIds.isEmpty() && !toWayIds.isEmpty() && viaCoord != null )
622608 public boolean replaceWay(long oldWayId, long newWayId) {
623609 assert evalWasCalled;
624610 boolean matched = false;
625 for (List<Long> ways: Arrays.asList(fromWayIds, viaWayIds, toWayIds)){
626 for (int i = 0; i < ways.size(); i++){
627 if (ways.get(i) == oldWayId){
611 for (List<Long> ways : Arrays.asList(fromWayIds, viaWayIds, toWayIds)) {
612 for (int i = 0; i < ways.size(); i++) {
613 if (ways.get(i) == oldWayId) {
628614 ways.set(i, newWayId);
629615 matched = true;
630616 }
634620 }
635621
636622 /**
637 * check if restriction is still valid if the way with the given id is not in the map
638 * @param wayId
639 * @return
623 * Check if restriction is still valid if the way with the given id is not in the map.
624 * Can be true if the restriction is a no_exit or no_entry restriction.
625 * @param wayId the id of the way that was removed
626 * @return true if the restriction is still valid without this way
640627 */
641628 public boolean isValidWithoutWay(long wayId) {
642629 assert evalWasCalled;
643630 if (viaWayIds.contains(wayId))
644631 return false;
645632 fromWayIds.remove(wayId);
646 if (fromWayIds.isEmpty())
647 return false;
648 // else it must be a no_entry restriction which still is valid
649
650633 toWayIds.remove(wayId);
651 if (toWayIds.isEmpty())
652 return false;
653 // else it must be a no_exit restriction which still is valid
654 return true;
634 return (!fromWayIds.isEmpty() && !toWayIds.isEmpty());
655635 }
656636
657637 /**
661641 * @param nodeIndices
662642 */
663643 public void updateViaWay(Way way, List<Integer> nodeIndices) {
664 if (!valid)
665 return;
666 if (viaWayIds.contains(way.getId()) == false)
644 if (!valid || !viaWayIds.contains(way.getId()))
667645 return;
668646 List<Coord> wayViaPoints = new ArrayList<>();
669647 for (int i : nodeIndices) {
670648 wayViaPoints.add(way.getPoints().get(i));
671649 }
672 List<Coord> prevViaPoints = updatedViaWays.get(way.getId());
673 if(prevViaPoints != null){
650 List<Coord> prevViaPoints = updatedViaWays.get(way.getId());
651 if (prevViaPoints != null) {
674652 // we may get here when the style adds multiple routable ways for the
675653 // OSM way
676654 if (prevViaPoints.equals(wayViaPoints)) {
677655 // already up to date
678656 return;
679657 } else {
680 log.error(messagePrefix, "internal error: via way is updated again with different nodes");
658 log.error(msgPrefix, "internal error: via way is updated again with different nodes");
681659 }
682660 }
683661 Coord first = wayViaPoints.get(0);
684 Coord last = wayViaPoints.get(wayViaPoints.size()-1);
662 Coord last = wayViaPoints.get(wayViaPoints.size() - 1);
685663 int posFirst = -1;
686664 int posLast = -1;
687665 for (int i = 0; i < viaPoints.size(); i++) {
688 if (first == viaPoints.get(i))
666 if (first == viaPoints.get(i))
689667 posFirst = i;
690 if (last== viaPoints.get(i))
668 if (last == viaPoints.get(i))
691669 posLast = i;
692 if (posFirst >= 0 && posLast >= 0){
693 if (Math.abs(posLast - posFirst) == 1){
670 if (posFirst >= 0 && posLast >= 0) {
671 if (Math.abs(posLast - posFirst) == 1) {
694672 break;
695673 } else {
696 // log.error(messagePrefix, "check self intersection!");
697 }
698 }
699 }
700 if (posFirst < 0 || posLast < 0){
701 log.error(messagePrefix, "internal error: via way doesn't contain expected points");
702 valid = false;
703 return;
704 }
705 if (Math.abs(posLast - posFirst) != 1){
706 log.error(messagePrefix, "internal error: via way doesn't contain points in expected position");
707 valid = false;
708 return;
709 }
710 List<Coord> midPoints = new ArrayList<>(wayViaPoints.subList(1, wayViaPoints.size()-1));
711 if (posFirst < posLast){
674 // check self intersection ?
675 }
676 }
677 }
678 if (posFirst < 0 || posLast < 0) {
679 log.error(msgPrefix, "internal error: via way doesn't contain expected points");
680 valid = false;
681 return;
682 }
683 if (Math.abs(posLast - posFirst) != 1) {
684 log.error(msgPrefix, "internal error: via way doesn't contain points in expected position");
685 valid = false;
686 return;
687 }
688 List<Coord> midPoints = new ArrayList<>(wayViaPoints.subList(1, wayViaPoints.size() - 1));
689 if (posFirst < posLast) {
712690 if (posLast - posFirst > 1)
713 viaPoints.subList(posFirst+1, posLast).clear();
691 viaPoints.subList(posFirst + 1, posLast).clear();
714692 viaPoints.addAll(posFirst + 1, midPoints);
715 }
716 else {
693 } else {
717694 if (posFirst - posLast > 1)
718695 viaPoints.subList(posLast + 1, posFirst).clear();
719696 Collections.reverse(midPoints);
721698 }
722699
723700 int wayPos = viaWayIds.indexOf(way.getId());
724 while(viaWayIds.size() > wayPos + 1 && viaWayIds.get(wayPos+1) == way.getId())
701 while (viaWayIds.size() > wayPos + 1 && viaWayIds.get(wayPos + 1) == way.getId())
725702 viaWayIds.remove(wayPos);
726 for (int i = 0; i < midPoints.size(); i++){
727 viaWayIds.add(wayPos+1, way.getId());
728 }
729 if (viaPoints.size() != viaWayIds.size()+1){
730 log.error(messagePrefix,"internal error: number of via points and via ways no longer fits");
731 valid = false;
732 } else if (viaPoints.size() > 6){
733 log.warn(messagePrefix,"has more than 6 via nodes, this is not supported");
703 for (int i = 0; i < midPoints.size(); i++) {
704 viaWayIds.add(wayPos + 1, way.getId());
705 }
706 if (viaPoints.size() != viaWayIds.size() + 1) {
707 log.error(msgPrefix, "internal error: number of via points and via ways no longer fits");
708 valid = false;
709 } else if (viaPoints.size() > 6) {
710 log.warn(msgPrefix, "has more than 6 via nodes, this is not supported");
734711 valid = false;
735712 }
736713 updatedViaWays.put(way.getId(), wayViaPoints);
5959 public class SeaGenerator implements OsmReadingHooks {
6060 private static final Logger log = Logger.getLogger(SeaGenerator.class);
6161
62 private String precompSea;
6263 private boolean generateSeaUsingMP = true;
6364 private int maxCoastlineGap;
6465 private boolean allowSeaSectors = true;
7273
7374 private ElementSaver saver;
7475
75 private List<Way> shoreline = new ArrayList<Way>();
76 private boolean roadsReachBoundary; // todo needs setting somehow
76 private List<Way> shoreline = new ArrayList<>();
7777 private boolean generateSeaBackground = true;
7878
7979 private String[] coastlineFilenames;
8080 private StyleImpl fbRules;
8181
8282 /** The size (lat and long) of the precompiled sea tiles */
83 public final static int PRECOMP_RASTER = 1 << 15;
84
85 /**
86 * The directory of the precompiled sea tiles or <code>null</code> if
87 * precompiled sea should not be used.
88 */
89 private File precompSeaDir;
90
83 public static final int PRECOMP_RASTER = 1 << 15;
84
85 // flags used in the index
9186 private static final byte SEA_TILE = 's';
9287 private static final byte LAND_TILE = 'l';
9388 private static final byte MIXED_TILE = 'm';
9489
95 private static ThreadLocal<PrecompData> precompIndex = new ThreadLocal<PrecompData>();
90 private static ThreadLocal<PrecompData> precompIndex = new ThreadLocal<>();
9691
9792 // useful constants defining the min/max map units of the precompiled sea tiles
9893 private static final int MIN_LAT = Utils.toMapUnit(-90.0);
9994 private static final int MAX_LAT = Utils.toMapUnit(90.0);
10095 private static final int MIN_LON = Utils.toMapUnit(-180.0);
10196 private static final int MAX_LON = Utils.toMapUnit(180.0);
102 private final static Pattern keySplitter = Pattern.compile(Pattern.quote("_"));
97 private static final Pattern KEY_SPLITTER = Pattern.compile(Pattern.quote("_"));
98 private static final Pattern SEMICOLON_SPLITTER = Pattern.compile(Pattern.quote(";"));
10399
104100 /**
105101 * When order-by-decreasing-area we need all bit of sea to be output consistently.
118114 * Returns true only if the option to generate the sea is active, so that
119115 * the whole thing is omitted if not used.
120116 */
117 @Override
121118 public boolean init(ElementSaver saver, EnhancedProperties props) {
122119 this.saver = saver;
123120
124 String precompSea = props.getProperty("precomp-sea", null);
121 precompSea = props.getProperty("precomp-sea", null);
125122 if (precompSea != null) {
126 precompSeaDir = new File(precompSea);
127 if (precompSeaDir.exists()){
128 if (precompIndex.get() == null) {
129 PrecompData precompData = null;
130 String internalPath = null;
131 InputStream indexStream = null;
132 String indexFileName = "index.txt.gz";
133 ZipFile zipFile = null;
134 try{
135 if (precompSeaDir.isDirectory()){
136 File indexFile = new File(precompSeaDir, indexFileName);
137 if (indexFile.exists() == false) {
138 // check if the unzipped index file exists
139 indexFileName = "index.txt";
140 indexFile = new File(precompSeaDir, indexFileName);
141 }
142 if (indexFile.exists()) {
143 indexStream = new FileInputStream(indexFile);
144 }
145 } else if (precompSea.endsWith(".zip")){
146 zipFile = new ZipFile(precompSeaDir);
147 internalPath = "sea/";
148 ZipEntry entry = zipFile.getEntry(internalPath + indexFileName);
149 if (entry == null){
150 indexFileName = "index.txt";
151 entry = zipFile.getEntry(internalPath + indexFileName);
152 }
153 if (entry == null){
154 internalPath = "";
155 indexFileName = "index.txt.gz";
156 entry = zipFile.getEntry(internalPath + indexFileName);
157 }
158 if (entry != null){
159 indexStream = zipFile.getInputStream(entry);
160 } else
161 log.error("Don't know how to read " + precompSeaDir);
162 } else {
163 log.error("Don't know how to read " + precompSeaDir);
164 }
165 if (indexStream != null){
166 if (indexFileName.endsWith(".gz")) {
167 indexStream = new GZIPInputStream(indexStream);
168 }
169 precompData = loadIndex(indexStream);
170 if (precompData != null){
171 if (zipFile != null){
172 precompData.precompZipFileInternalPath = internalPath;
173 precompData.zipFile = zipFile;
174 }
175 precompIndex.set(precompData);
176 }
177 indexStream.close();
178 }
179 } catch (IOException exp) {
180 log.error("Cannot read index file", indexFileName, "in", precompSea, exp);
181 // exp.printStackTrace();
182 throw new ExitException("Failed to read required index file in " + precompSeaDir);
183 }
184 precompIndex.set(precompData);
185 }
186 } else {
187 log.error("Directory or zip file with precompiled sea does not exist: "
188 + precompSea);
189 System.err.println("Directory or zip file with precompiled sea does not exist: "
190 + precompSea);
191 precompSeaDir = null;
192 }
123 initPrecompSeaIndex(precompSea);
193124 }
194125 String gs = props.getProperty("generate-sea", null);
195 boolean generateSea = gs != null || precompSea != null;
196126 if (gs != null) {
197 for(String o : gs.split(",")) {
198 if("no-mp".equals(o) ||
199 "polygon".equals(o) ||
200 "polygons".equals(o))
201 generateSeaUsingMP = false;
202 else if("multipolygon".equals(o))
203 generateSeaUsingMP = true;
204 else if(o.startsWith("land-tag="))
205 landTag = o.substring(9).split("=");
206 else if (precompSea == null) {
207 // the other options are valid only if not using precompiled sea data
208 if(o.startsWith("close-gaps="))
209 maxCoastlineGap = (int)Double.parseDouble(o.substring(11));
210 else if("no-sea-sectors".equals(o))
211 allowSeaSectors = false;
212 else if("extend-sea-sectors".equals(o)) {
213 allowSeaSectors = false;
214 extendSeaSectors = true;
215 }
216 else if("floodblocker".equals(o))
217 floodblocker = true;
218 else if(o.startsWith("fbgap="))
219 fbGap = (int)Double.parseDouble(o.substring("fbgap=".length()));
220 else if(o.startsWith("fbratio="))
221 fbRatio = Double.parseDouble(o.substring("fbratio=".length()));
222 else if(o.startsWith("fbthres="))
223 fbThreshold = (int)Double.parseDouble(o.substring("fbthres=".length()));
224 else if("fbdebug".equals(o))
225 fbDebug = true;
226 else {
227 printOptionHelpMsg(precompSea != null, o);
228 }
229 }
230 else if(o.isEmpty())
231 continue;
232 else {
233 printOptionHelpMsg(precompSea != null, o);
234 }
235 }
127 parseGenerateSeaOption(gs, precompSea != null);
236128
237129 // init floodblocker and coastlinefile loader only
238130 // if precompSea is not set
239131 if (precompSea == null) {
240132 if (floodblocker) {
241 try {
242 fbRules = new StyleImpl(null, "floodblocker");
243 } catch (FileNotFoundException e) {
244 log.error("Cannot load file floodblocker rules. Continue floodblocking disabled.");
245 floodblocker = false;
246 }
133 loadFloodblockerStyle();
247134 }
248135
249136 String coastlineFileOpt = props.getProperty("coastlinefile", null);
250137 if (coastlineFileOpt != null) {
251138 coastlineFilenames = coastlineFileOpt.split(",");
252 CoastlineFileLoader.getCoastlineLoader().setCoastlineFiles(
253 coastlineFilenames);
139 CoastlineFileLoader.getCoastlineLoader().setCoastlineFiles(coastlineFilenames);
254140 CoastlineFileLoader.getCoastlineLoader().loadCoastlines();
255141 log.info("Coastlines loaded");
256142 } else {
259145 }
260146 }
261147
262 return generateSea;
148 return gs != null || precompSea != null;
149 }
150
151 private void loadFloodblockerStyle() {
152 try {
153 fbRules = new StyleImpl(null, "floodblocker");
154 } catch (FileNotFoundException e) {
155 log.error("Cannot load file floodblocker rules. Continue floodblocking disabled.");
156 floodblocker = false;
157 }
158 }
159
160 private void parseGenerateSeaOption(String gs, boolean forPrecompSea) {
161 for (String option : gs.split(",")) {
162 if ("no-mp".equals(option) || "polygon".equals(option) || "polygons".equals(option))
163 generateSeaUsingMP = false;
164 else if ("multipolygon".equals(option))
165 generateSeaUsingMP = true;
166 else if (option.startsWith("land-tag="))
167 landTag = option.substring(9).split("=");
168 else if (!forPrecompSea) {
169 // the other options are only valid if precompiled sea is not used
170 if (option.startsWith("close-gaps="))
171 maxCoastlineGap = (int) Double.parseDouble(option.substring(11));
172 else if ("no-sea-sectors".equals(option))
173 allowSeaSectors = false;
174 else if ("extend-sea-sectors".equals(option)) {
175 allowSeaSectors = false;
176 extendSeaSectors = true;
177 } else if ("floodblocker".equals(option)) {
178 floodblocker = true;
179 } else if (option.startsWith("fbgap=")) {
180 fbGap = (int) Double.parseDouble(option.substring("fbgap=".length()));
181 } else if (option.startsWith("fbratio=")) {
182 fbRatio = Double.parseDouble(option.substring("fbratio=".length()));
183 } else if (option.startsWith("fbthres=")) {
184 fbThreshold = (int) Double.parseDouble(option.substring("fbthres=".length()));
185 } else if ("fbdebug".equals(option)) {
186 fbDebug = true;
187 } else {
188 printOptionHelpMsg(forPrecompSea, option);
189 }
190 } else if (option.isEmpty()) {
191 // nothing to do
192 } else {
193 printOptionHelpMsg(forPrecompSea, option);
194 }
195 }
196 }
197
198 private static void initPrecompSeaIndex(String precompSea) {
199 if (precompIndex.get() != null) {
200 return;
201 }
202 /**
203 * The directory of the precompiled sea tiles or <code>null</code> if
204 * precompiled sea should not be used.
205 */
206 File precompSeaDir = new File(precompSea);
207 if (!precompSeaDir.exists()) {
208 log.error("Directory or zip file with precompiled sea does not exist: " + precompSea);
209 return;
210 }
211
212 String internalPath = null;
213 String indexFileName = "index.txt.gz";
214 ZipFile zipFile = null;
215 PrecompData precompData = null;
216 try {
217 if (precompSeaDir.isDirectory()) {
218 File indexFile = new File(precompSeaDir, indexFileName);
219 if (!indexFile.exists()) {
220 // check if the unzipped index file exists
221 indexFileName = "index.txt";
222 indexFile = new File(precompSeaDir, indexFileName);
223 }
224 if (indexFile.exists()) {
225 precompData = readIndexStream(indexFileName, new FileInputStream(indexFile));
226 }
227 } else if (precompSea.endsWith(".zip")) {
228 zipFile = new ZipFile(precompSeaDir); // don't close here!
229 internalPath = "sea/";
230 ZipEntry entry = zipFile.getEntry(internalPath + indexFileName);
231 if (entry == null) {
232 indexFileName = "index.txt";
233 entry = zipFile.getEntry(internalPath + indexFileName);
234 }
235 if (entry == null) {
236 internalPath = "";
237 indexFileName = "index.txt.gz";
238 entry = zipFile.getEntry(internalPath + indexFileName);
239 }
240 if (entry != null) {
241 precompData = readIndexStream(indexFileName, zipFile.getInputStream(entry));
242 } else {
243 log.error("Don't know how to read " + precompSeaDir);
244 }
245 } else {
246 log.error("Don't know how to read " + precompSeaDir);
247 }
248 if (precompData != null) {
249 precompData.dirFile = precompSeaDir;
250 if (zipFile != null) {
251 precompData.precompZipFileInternalPath = internalPath;
252 precompData.zipFile = zipFile;
253 }
254 precompIndex.set(precompData);
255 }
256 } catch (IOException exp) {
257 log.error("Cannot read index file", indexFileName, "in", precompSea, exp);
258 throw new ExitException("Failed to read required index file in " + precompSeaDir);
259 }
260 }
261
262 private static PrecompData readIndexStream(String indexFileName, InputStream indexStream) throws IOException {
263 if (indexFileName.endsWith(".gz")) {
264 indexStream = new GZIPInputStream(indexStream);
265 }
266 PrecompData precompData = loadIndex(indexStream);
267 indexStream.close();
268 return precompData;
263269 }
264270
265271 /**
266272 * Show valid generate-sea options
267273 * @param forPrecompSea set to true if --precomp-sea is used
268 * @param o either "help" or an option that was not recognized
269 */
270 void printOptionHelpMsg (boolean forPrecompSea, String o){
271
272 if(!"help".equals(o))
273 System.err.println("Unknown sea generation option '" + o + "'");
274 * @param option either "help" or an option that was not recognized
275 */
276 private static void printOptionHelpMsg(boolean forPrecompSea, String option) {
277 if(!"help".equals(option))
278 System.err.println("Unknown sea generation option '" + option + "'");
274279
275280 System.err.println("Known sea generation options " + (forPrecompSea ? "with" : "without") + " --precomp-sea are:");
276281 System.err.println(" multipolygon use a multipolygon (default)");
285290 System.err.println(" fbgap=NUM points closer to the coastline are ignored for flood blocking (default 40)");
286291 System.err.println(" fbthres=NUM min points contained in a polygon to be flood blocked (default 20)");
287292 System.err.println(" fbratio=NUM min ratio (points/area size) for flood blocking (default 0.5)");
288
289 }
293 }
294
290295 /**
291296 * Read the index from stream and populate the index grid.
292297 * @param fileStream already opened stream
293298 */
294 private PrecompData loadIndex(InputStream fileStream) throws IOException{
295 int indexWidth = (SeaGenerator.getPrecompTileStart(MAX_LON) - SeaGenerator.getPrecompTileStart(MIN_LON)) / SeaGenerator.PRECOMP_RASTER;
296 int indexHeight = (SeaGenerator.getPrecompTileStart(MAX_LAT) - SeaGenerator.getPrecompTileStart(MIN_LAT)) / SeaGenerator.PRECOMP_RASTER;
299 private static PrecompData loadIndex(InputStream fileStream) throws IOException{
300 int indexWidth = (getPrecompTileStart(MAX_LON) - getPrecompTileStart(MIN_LON)) / PRECOMP_RASTER;
301 int indexHeight = (getPrecompTileStart(MAX_LAT) - getPrecompTileStart(MIN_LAT)) / PRECOMP_RASTER;
297302 PrecompData pi = null;
298 LineNumberReader indexReader = new LineNumberReader(
299 new InputStreamReader(fileStream));
300 Pattern csvSplitter = Pattern.compile(Pattern
301 .quote(";"));
303 LineNumberReader indexReader = new LineNumberReader(new InputStreamReader(fileStream));
302304 String indexLine = null;
303305
304 byte[][] indexGrid = new byte[indexWidth+1][indexHeight+1];
306 byte[][] indexGrid = new byte[indexWidth + 1][indexHeight + 1];
305307 boolean detectExt = true;
306308 String prefix = null;
307309 String ext = null;
311313 // comment
312314 continue;
313315 }
314 String[] items = csvSplitter.split(indexLine);
316 String[] items = SEMICOLON_SPLITTER.split(indexLine);
315317 if (items.length != 2) {
316 log.warn("Invalid format in index file name:",
317 indexLine);
318 log.warn("Invalid format in index file name:", indexLine);
318319 continue;
319320 }
320321 String precompKey = items[0];
321322 byte type = updatePrecompSeaTileIndex(precompKey, items[1], indexGrid);
322 if (type == '?'){
323 log.warn("Invalid format in index file name:",
324 indexLine);
323 if (type == '?') {
324 log.warn("Invalid format in index file name:", indexLine);
325325 continue;
326326 }
327 if (type == MIXED_TILE){
327 if (type == MIXED_TILE) {
328328 // make sure that all file names are using the same name scheme
329329 int prePos = items[1].indexOf(items[0]);
330 if (prePos >= 0){
331 if (detectExt){
330 if (prePos >= 0) {
331 if (detectExt) {
332332 prefix = items[1].substring(0, prePos);
333 ext = items[1].substring(prePos+items[0].length());
333 ext = items[1].substring(prePos + items[0].length());
334334 detectExt = false;
335335 } else {
336 StringBuilder sb = new StringBuilder(prefix);
337 sb.append(precompKey);
338 sb.append(ext);
339 if (items[1].equals(sb.toString()) == false){
340 log.warn("Unexpected file name in index file:",
341 indexLine);
336 String fname = prefix + precompKey + ext;
337 if (!items[1].equals(fname)) {
338 log.warn("Unexpected file name in index file:", indexLine);
342339 }
343340 }
344341 }
353350 return pi;
354351 }
355352
356 /**
353 /**
357354 * Retrieves the start value of the precompiled tile.
358355 * @param value the value for which the start value is calculated
359356 * @return the tile start value
385382 }
386383 }
387384
385 @Override
388386 public Set<String> getUsedTags() {
389 HashSet<String> usedTags = new HashSet<String>();
387 HashSet<String> usedTags = new HashSet<>();
390388 if (coastlineFilenames == null) {
391389 usedTags.add("natural");
392390 }
393391 if (floodblocker) {
394392 usedTags.addAll(fbRules.getUsedTags());
395393 }
396
394
397395 if (log.isDebugEnabled())
398 log.debug("Sea generator used tags: "+usedTags);
399
396 log.debug("Sea generator used tags: " + usedTags);
397
400398 return usedTags;
401399 }
402400
405403 * we save it.
406404 * @param way The way to test.
407405 */
406 @Override
408407 public void onAddWay(Way way) {
409408 String natural = way.getTag("natural");
410 if(natural != null) {
411 if("coastline".equals(natural)) {
412 if (precompSeaDir != null)
413 splitCoastLineToLineAndShape(way, natural);
414 else {
415 if (coastlineFilenames == null){
416 way.deleteTag("natural");
417 shoreline.add(way);
418 }
419 }
420 } else if (natural.contains(";")) {
421 // cope with compound tag value
422 String others = null;
423 boolean foundCoastline = false;
424 for(String n : natural.split(";")) {
425 if("coastline".equals(n.trim()))
426 foundCoastline = true;
427 else if(others == null)
428 others = n;
429 else
430 others += ";" + n;
431 }
432
433 if(foundCoastline) {
434 if (precompSeaDir != null)
435 splitCoastLineToLineAndShape(way, natural);
436 else {
437 if (coastlineFilenames == null){
438 way.deleteTag("natural");
439 if(others != null)
440 way.addTag("natural", others);
441 shoreline.add(way);
442 }
443 }
444 }
445 }
409 if (natural == null)
410 return;
411
412 // cope with compound tag value
413 StringBuilder others = null;
414 boolean foundCoastline = false;
415 for (String n : SEMICOLON_SPLITTER.split(natural)) {
416 if ("coastline".equals(n.trim()))
417 foundCoastline = true;
418 else if (others == null)
419 others = new StringBuilder(n);
420 else
421 others.append(';').append(n);
422 }
423 if (!foundCoastline)
424 return;
425 if (precompSea != null)
426 splitCoastLineToLineAndShape(way, natural);
427 else if (coastlineFilenames == null) {
428 // create copy of way that has only the natural=coastline tag
429 Way shore = new Way(way.getOriginalId(), way.getPoints());
430 shore.setFakeId();
431 shore.addTag("natural", "coastline");
432 saver.addWay(shore);
433
434 way.deleteTag("natural");
435 if (others != null)
436 way.addTag("natural", others.toString());
437 shoreline.add(way);
446438 }
447439 }
448440
455447 * @param naturalVal the tag value
456448 */
457449 private void splitCoastLineToLineAndShape(Way way, String naturalVal){
458 if (precompSeaDir == null)
450 if (precompSea == null)
459451 return;
460452 if (way.hasIdenticalEndPoints()){
461453 // add a copy of this way to be able to draw it as a shape
479471 * @return all ways of the tile
480472 * @throws FileNotFoundException if the tile could not be found
481473 */
482 private Collection<Way> loadPrecompTile(InputStream is, String filename) {
474 private static Collection<Way> loadPrecompTile(InputStream is, String filename) {
483475 OsmPrecompSeaDataSource src = new OsmPrecompSeaDataSource();
484476 EnhancedProperties props = new EnhancedProperties();
485477 props.setProperty("style", "empty");
502494 */
503495 private List<String> getPrecompKeyNames() {
504496 Area bounds = saver.getBoundingBox();
505 List<String> precompKeys = new ArrayList<String>();
497 List<String> precompKeys = new ArrayList<>();
506498 for (int lat = getPrecompTileStart(bounds.getMinLat()); lat < getPrecompTileEnd(bounds
507499 .getMaxLat()); lat += PRECOMP_RASTER) {
508500 for (int lon = getPrecompTileStart(bounds.getMinLong()); lon < getPrecompTileEnd(bounds
518510 * @param precompKey The key name is compiled of {@code lat+"_"+lon}.
519511 * @return either "land" or "sea" or a file name or null
520512 */
521 private String getTileName(String precompKey){
513 private static String getTileName(String precompKey){
522514 PrecompData pi = precompIndex.get();
523 String[] tileCoords = keySplitter.split(precompKey);
524 int lat = Integer.valueOf(tileCoords[0]);
525 int lon = Integer.valueOf(tileCoords[1]);
515 String[] tileCoords = KEY_SPLITTER.split(precompKey);
516 int lat = Integer.parseInt(tileCoords[0]);
517 int lon = Integer.parseInt(tileCoords[1]);
526518 int latIndex = (MAX_LAT-lat) / PRECOMP_RASTER;
527519 int lonIndex = (MAX_LON-lon) / PRECOMP_RASTER;
528520 byte type = pi.precompIndex[lonIndex][latIndex];
542534 * @param indexGrid the previously allocated index grid
543535 * @return the byte that was saved in the index grid
544536 */
545 private byte updatePrecompSeaTileIndex (String precompKey, String fileName, byte[][] indexGrid){
546 String[] tileCoords = keySplitter.split(precompKey);
537 private static byte updatePrecompSeaTileIndex (String precompKey, String fileName, byte[][] indexGrid){
538 String[] tileCoords = KEY_SPLITTER.split(precompKey);
547539 byte type = '?';
548540 if (tileCoords.length == 2){
549 int lat = Integer.valueOf(tileCoords[0]);
550 int lon = Integer.valueOf(tileCoords[1]);
541 int lat = Integer.parseInt(tileCoords[0]);
542 int lon = Integer.parseInt(tileCoords[1]);
551543 int latIndex = (MAX_LAT - lat) / PRECOMP_RASTER;
552544 int lonIndex = (MAX_LON - lon) / PRECOMP_RASTER;
553545
572564
573565 // flag if all tiles contains sea or way only
574566 // this is important for polygon processing
575 boolean distinctTilesOnly = true;
567 boolean distinctTilesOnly;
576568
577 List<Way> landWays = new ArrayList<Way>();
578 List<Way> seaWays = new ArrayList<Way>();
579 List<java.awt.geom.Area> seaOnlyAreas = new ArrayList<java.awt.geom.Area>();
580 List<java.awt.geom.Area> landOnlyAreas = new ArrayList<java.awt.geom.Area>();
569 List<Way> landWays = new ArrayList<>();
570 List<Way> seaWays = new ArrayList<>();
581571
582572 // get the index with assignment key => sea/land/tilename
573 distinctTilesOnly = loadLandAndSee(landWays, seaWays);
574
575 if (generateSeaUsingMP || distinctTilesOnly) {
576 // when using multipolygons use the data directly from the precomp files
577 // also with polygons if all tiles are using either sea or land only
578 for (Way w : seaWays) {
579 w.setFullArea(SEA_SIZE);
580 saver.addWay(w);
581 }
582 } else {
583 // using polygons
584 // first add the complete bounding box as sea
585 saver.addWay(createSeaWay(saver.getBoundingBox(), false));
586 }
583587
584 ZipFile zipFile = null;
588 // check if the land tags need to be changed
589 boolean changeLadTag = landTag != null && ("natural".equals(landTag[0]) && !"land".equals(landTag[1]));
590 for (Way w : landWays) {
591 if (changeLadTag) {
592 w.deleteTag("natural");
593 w.addTag(landTag[0], landTag[1]);
594 }
595 saver.addWay(w);
596 }
597 }
598
599
600 private boolean loadLandAndSee(List<Way> landWays, List<Way> seaWays) {
601 boolean distinctTilesOnly = true;
602 List<java.awt.geom.Area> seaOnlyAreas = new ArrayList<>();
603 List<java.awt.geom.Area> landOnlyAreas = new ArrayList<>();
604
585605 PrecompData pd = precompIndex.get();
586 if (precompSeaDir.getName().endsWith(".zip")){
587 zipFile = pd.zipFile;
588 }
589606
590607 for (String precompKey : getPrecompKeyNames()) {
591608 String tileName = getTileName(precompKey);
592609
593 if (tileName == null ) {
594 log.error("Precompile sea tile "+precompKey+" is missing in the index. Skipping.");
610 if (tileName == null) {
611 log.error("Precompile sea tile " + precompKey + " is missing in the index. Skipping.");
595612 continue;
596613 }
597614
598615 if ("sea".equals(tileName) || "land".equals(tileName)) {
599616 // the whole precompiled tile is filled with either land or sea
600 // => create a rectangle that covers the whole precompiled tile
601 String[] tileCoords = keySplitter.split(precompKey);
602 int minLat = Integer.valueOf(tileCoords[0]);
603 int minLon = Integer.valueOf(tileCoords[1]);
604 Rectangle r = new Rectangle(minLon,minLat,PRECOMP_RASTER,PRECOMP_RASTER);
605
617 // => create a rectangle that covers the whole precompiled tile
618 String[] tileCoords = KEY_SPLITTER.split(precompKey);
619 int minLat = Integer.parseInt(tileCoords[0]);
620 int minLon = Integer.parseInt(tileCoords[1]);
621 Rectangle r = new Rectangle(minLon, minLat, PRECOMP_RASTER, PRECOMP_RASTER);
622
606623 if ("sea".equals(tileName)) {
607624 seaOnlyAreas = addWithoutCreatingHoles(seaOnlyAreas, new java.awt.geom.Area(r));
608625 } else {
610627 }
611628 } else {
612629 distinctTilesOnly = false;
613 try {
614 InputStream is = null;
615 if (zipFile != null){
616 ZipEntry entry = zipFile.getEntry(pd.precompZipFileInternalPath + tileName);
617 if (entry != null){
618 is = zipFile.getInputStream(entry);
619 } else {
620 log.error("Preompiled sea tile " + tileName + " not found.");
621 }
622 } else {
623 File precompTile = new File(precompSeaDir,tileName);
624 is = new FileInputStream(precompTile);
625 }
626 if (is != null){
627 Collection<Way> seaPrecompWays = loadPrecompTile(is, tileName);
628 if (log.isDebugEnabled())
629 log.debug(seaPrecompWays.size(), "precomp sea ways from",
630 tileName, "loaded.");
631
632 for (Way w : seaPrecompWays) {
633 // set a new id to be sure that the precompiled ids do not
634 // interfere with the ids of this run
635 w.setFakeId();
636
637 if ("land".equals(w.getTag("natural"))) {
638 landWays.add(w);
639 } else {
640 seaWays.add(w);
641 }
642 }
643 }
644 } catch (FileNotFoundException exp) {
645 log.error("Preompiled sea tile " + tileName + " not found.");
646 } catch (Exception exp) {
647 log.error(exp);
648 exp.printStackTrace();
649 }
630 loadMixedTile(pd, tileName, landWays, seaWays);
650631 }
651632 }
652633 landWays.addAll(areaToWays(landOnlyAreas,"land"));
653634 seaWays.addAll(areaToWays(seaOnlyAreas,"sea"));
654 landOnlyAreas = null;
655 seaOnlyAreas = null;
656
657 // check if the land tags need to be changed
658 if (landTag != null && ("natural".equals(landTag[0]) && "land".equals(landTag[1])) == false) {
659 for (Way w : landWays) {
660 w.deleteTag("natural");
661 w.addTag(landTag[0], landTag[1]);
662 }
663 }
664
665 if (generateSeaUsingMP || distinctTilesOnly) {
666 // when using multipolygons use the data directly from the precomp files
667 // also with polygons if all tiles are using either sea or land only
668 for (Way w : landWays) {
669 saver.addWay(w);
670 }
671 for (Way w : seaWays) {
672 w.setFullArea(SEA_SIZE);
673 saver.addWay(w);
674 }
675 } else {
676 // using polygons
677
678 Area bounds = saver.getBoundingBox();
679 // first add the complete bounding box as sea
680 Way sea = new Way(FakeIdGenerator.makeFakeId(),bounds.toCoords());
681 sea.addTag("natural", "sea");
682 sea.setFullArea(SEA_SIZE);
683
684 for (Way w : landWays) {
685 saver.addWay(w);
686 }
687 }
688 }
689
690
635 return distinctTilesOnly;
636 }
637
638 private static void loadMixedTile(PrecompData pd, String tileName, List<Way> landWays, List<Way> seaWays) {
639 try {
640 InputStream is = null;
641 if (pd.zipFile != null) {
642 ZipEntry entry = pd.zipFile.getEntry(pd.precompZipFileInternalPath + tileName);
643 if (entry != null) {
644 is = pd.zipFile.getInputStream(entry);
645 } else {
646 log.error("Preompiled sea tile " + tileName + " not found.");
647 }
648 } else {
649 File precompTile = new File(pd.dirFile, tileName);
650 is = new FileInputStream(precompTile);
651 }
652 if (is != null) {
653 Collection<Way> seaPrecompWays = loadPrecompTile(is, tileName);
654 if (log.isDebugEnabled())
655 log.debug(seaPrecompWays.size(), "precomp sea ways from", tileName, "loaded.");
656
657 for (Way w : seaPrecompWays) {
658 // set a new id to be sure that the precompiled ids do not
659 // interfere with the ids of this run
660 w.setFakeId();
661
662 if ("land".equals(w.getTag("natural"))) {
663 landWays.add(w);
664 } else {
665 seaWays.add(w);
666 }
667 }
668 }
669 } catch (FileNotFoundException exp) {
670 log.error("Preompiled sea tile " + tileName + " not found.");
671 } catch (Exception exp) {
672 log.error(exp);
673 exp.printStackTrace();
674 }
675 }
676
691677 /**
692678 * Try to merge an area with one or more other areas without creating holes.
693679 * If it cannot be merged, it is added to the list.
695681 * @param toAdd area to add
696682 * @return new list of areas
697683 */
698 private List<java.awt.geom.Area> addWithoutCreatingHoles(List<java.awt.geom.Area> areas,
684 private static List<java.awt.geom.Area> addWithoutCreatingHoles(List<java.awt.geom.Area> areas,
699685 final java.awt.geom.Area toAdd) {
700 List<java.awt.geom.Area> result = new LinkedList<java.awt.geom.Area>();
686 List<java.awt.geom.Area> result = new LinkedList<>();
701687 java.awt.geom.Area toMerge = new java.awt.geom.Area(toAdd);
702688
703 for (java.awt.geom.Area area:areas ){
689 for (java.awt.geom.Area area : areas) {
704690 java.awt.geom.Area mergedArea = new java.awt.geom.Area(area);
705691 mergedArea.add(toMerge);
706 if (mergedArea.isSingular() == false){
692 if (!mergedArea.isSingular()) {
707693 result.add(area);
708694 continue;
709695 }
710696 toMerge = mergedArea;
711697 }
712698 // create a sorted list with "smallest" area at the beginning
713 int dimNew = Math.max(toMerge.getBounds().width,toMerge.getBounds().height);
699 int dimNew = Math.max(toMerge.getBounds().width, toMerge.getBounds().height);
714700 boolean added = false;
715 for (int i = 0; i < result.size(); i++){
701 for (int i = 0; i < result.size(); i++) {
716702 java.awt.geom.Area area = result.get(i);
717 if (dimNew < Math.max(area.getBounds().width,area.getBounds().height)){
718 result.add(i,toMerge);
703 if (dimNew < Math.max(area.getBounds().width, area.getBounds().height)) {
704 result.add(i, toMerge);
719705 added = true;
720706 break;
721707 }
730716 * @param type
731717 * @return
732718 */
733 private List<Way> areaToWays(List<java.awt.geom.Area> areas, String type) {
734 List<Way> ways = new ArrayList<Way>();
735 // int count = 0;
719 private static List<Way> areaToWays(List<java.awt.geom.Area> areas, String type) {
720 List<Way> ways = new ArrayList<>();
736721 for (java.awt.geom.Area area : areas) {
737722 List<List<Coord>> shapes = Java2DConverter.areaToShapes(area);
738723 for (List<Coord> points : shapes) {
739 // uk.me.parabola.util.GpxCreator.createGpx(type + "_" + count++, points);
740724 Way w = new Way(FakeIdGenerator.makeFakeId(), points);
741725 w.addTag("natural", type);
742726 ways.add(w);
750734 * @param segments a list of closed and unclosed ways
751735 * @return a list of ways completely joined
752736 */
753 public static ArrayList<Way> joinWays(Collection<Way> segments) {
754 ArrayList<Way> joined = new ArrayList<Way>((int)Math.ceil(segments.size()*0.5));
755 Map<Coord, Way> beginMap = new IdentityHashMap<Coord, Way>();
737 public static List<Way> joinWays(Collection<Way> segments) {
738 ArrayList<Way> joined = new ArrayList<>((int) Math.ceil(segments.size() * 0.5));
739 Map<Coord, Way> beginMap = new IdentityHashMap<>();
756740
757741 for (Way w : segments) {
758742 if (w.hasIdenticalEndPoints()) {
759743 joined.add(w);
760 } else if (w.getPoints() != null && w.getPoints().size() > 1){
744 } else if (w.getPoints().size() > 1){
761745 beginMap.put(w.getFirstPoint(), w);
762746 } else {
763 log.info("Discard coastline way",w.getId(),"because consists of less than 2 points");
747 log.info("Discarding coastline way", w.getId(), "because it consists of less than 2 points");
764748 }
765749 }
766750 segments.clear();
767
768 int merged = 1;
769 while (merged > 0) {
770 merged = 0;
751
752 boolean merged;
753 do {
754 merged = false;
771755 for (Way w1 : beginMap.values()) {
772 if (w1.hasIdenticalEndPoints()) {
773 // this should not happen
774 log.error("joinWays2: Way "+w1+" is closed but contained in the begin map");
775 joined.add(w1);
776 beginMap.remove(w1.getPoints().get(0));
777 merged=1;
756 Way w2 = beginMap.get(w1.getLastPoint());
757 if (w2 != null) {
758 merge(beginMap, joined, w1, w2);
759 merged = true;
778760 break;
779761 }
780
781 List<Coord> points1 = w1.getPoints();
782 Way w2 = beginMap.get(points1.get(points1.size() - 1));
783 if (w2 != null) {
784 log.info("merging: ", beginMap.size(), w1.getId(),
785 w2.getId());
786 List<Coord> points2 = w2.getPoints();
787 Way wm;
788 if (FakeIdGenerator.isFakeId(w1.getId())) {
789 wm = w1;
790 } else {
791 wm = new Way(w1.getOriginalId());
792 wm.setFakeId();
793 wm.getPoints().addAll(points1);
794 beginMap.put(points1.get(0), wm);
795 }
796 wm.getPoints().addAll(points2.subList(1, points2.size()));
797 beginMap.remove(points2.get(0));
798 merged++;
799
800 if (wm.hasIdenticalEndPoints()) {
801 joined.add(wm);
802 beginMap.remove(wm.getFirstPoint());
803 }
804 break;
805 }
806 }
807 }
808 log.info(joined.size(),"closed ways.",beginMap.size(),"unclosed ways.");
762 }
763 } while (merged);
764
765 log.info(joined.size(), "closed ways.", beginMap.size(), "unclosed ways.");
809766 joined.addAll(beginMap.values());
810767 return joined;
811768 }
812769
770 // merge the ways and maintain maps and list
771 private static void merge(Map<Coord, Way> beginMap, List<Way> joined, Way w1, Way w2) {
772 log.info("merging: ", beginMap.size(), w1.getId(), w2.getId());
773 Way wm;
774 if (FakeIdGenerator.isFakeId(w1.getId())) {
775 wm = w1;
776 } else {
777 wm = new Way(w1.getOriginalId(), w1.getPoints());
778 wm.setFakeId();
779 beginMap.put(wm.getFirstPoint(), wm);
780 }
781 beginMap.remove(w2.getFirstPoint());
782 wm.getPoints().addAll(w2.getPoints().subList(1, w2.getPoints().size()));
783
784 if (wm.hasIdenticalEndPoints()) {
785 joined.add(wm);
786 beginMap.remove(wm.getFirstPoint());
787 }
788 }
789
813790 /**
814791 * All done, process the saved shoreline information and construct the polygons.
815792 */
793 @Override
816794 public void end() {
817795 // precompiled sea has highest priority
818796 // if it is set do not perform any other algorithm
819 if (precompSeaDir != null) {
797 if (precompSea != null && precompIndex.get() != null) {
820798 addPrecompSea();
821799 return;
822800 }
823801
824 final Area seaBounds = saver.getBoundingBox();
802 final Area tileBounds = saver.getBoundingBox();
825803 if (coastlineFilenames == null) {
826804 log.info("Shorelines before join", shoreline.size());
827805 shoreline = joinWays(shoreline);
828806 } else {
829 shoreline.addAll(CoastlineFileLoader.getCoastlineLoader()
830 .getCoastlines(seaBounds));
807 shoreline.addAll(CoastlineFileLoader.getCoastlineLoader().getCoastlines(tileBounds));
831808 log.info("Shorelines from extra file:", shoreline.size());
832809 }
833810
834 int closedS = 0;
835 int unclosedS = 0;
836 for (Way w : shoreline) {
837 if (w.hasIdenticalEndPoints()) {
838 closedS++;
839 } else {
840 unclosedS++;
841 }
842 }
843 log.info("Closed shorelines", closedS);
844 log.info("Unclosed shorelines", unclosedS);
845
811 if (log.isInfoEnabled()) {
812 long closed = shoreline.stream().filter(Way::hasIdenticalEndPoints).count();
813 log.info("Closed shorelines", closed);
814 log.info("Unclosed shorelines", shoreline.size() - closed);
815 }
816
846817 // clip all shoreline segments
847 clipShorlineSegments(shoreline, seaBounds);
848
849 log.info("generating sea, seaBounds=", seaBounds);
850 int minLat = seaBounds.getMinLat();
851 int maxLat = seaBounds.getMaxLat();
852 int minLong = seaBounds.getMinLong();
853 int maxLong = seaBounds.getMaxLong();
854 Coord nw = new Coord(minLat, minLong);
855 Coord ne = new Coord(minLat, maxLong);
856 Coord sw = new Coord(maxLat, minLong);
857 Coord se = new Coord(maxLat, maxLong);
818 clipShorlineSegments(shoreline, tileBounds);
858819
859820 if(shoreline.isEmpty()) {
860 // no sea required
861 // even though there is no sea, generate a land
821 // No sea required
822 // Even though there is no sea, generate a land
862823 // polygon so that the tile's background colour will
863824 // match the land colour on the tiles that do contain
864825 // some sea
865 long landId = FakeIdGenerator.makeFakeId();
866 Way land = new Way(landId, seaBounds.toCoords());
867 land.addTag(landTag[0], landTag[1]);
868 // no matter if the multipolygon option is used it is
826 // No matter if the multipolygon option is used it is
869827 // only necessary to create a land polygon
870 saver.addWay(land);
828 saver.addWay(createLandWay(tileBounds));
871829 // nothing more to do
872830 return;
873831 }
874832
875833 long multiId = FakeIdGenerator.makeFakeId();
876834 Relation seaRelation = null;
877 if(generateSeaUsingMP) {
878 log.debug("Generate seabounds relation",multiId);
835 if (generateSeaUsingMP) {
836 log.debug("Generate seabounds relation", multiId);
879837 seaRelation = new GeneralRelation(multiId);
880838 seaRelation.addTag("type", "multipolygon");
881839 seaRelation.addTag("natural", "sea");
882840 }
883
884 List<Way> islands = new ArrayList<Way>();
841
842
843 List<Way> islands = new ArrayList<>();
885844
886845 // handle islands (closed shoreline components) first (they're easy)
887 handleIslands(shoreline, seaBounds, islands);
846 handleIslands(shoreline, tileBounds, islands);
888847
889848 // the remaining shoreline segments should intersect the boundary
890849 // find the intersection points and store them in a SortedMap
891 NavigableMap<EdgeHit, Way> hitMap = findIntesectionPoints(shoreline, seaBounds, seaRelation);
850 NavigableMap<Double, Way> hitMap = findIntesectionPoints(shoreline, tileBounds, seaRelation);
892851
893852 // now construct inner ways from these segments
894 boolean shorelineReachesBoundary = createInnerWays(seaBounds, islands, hitMap);
895
896 if(!shorelineReachesBoundary && roadsReachBoundary) {
897 // try to avoid tiles being flooded by anti-lakes or other
898 // bogus uses of natural=coastline
899 generateSeaBackground = false;
900 }
853 createLandPolygons(tileBounds, islands, hitMap);
901854
902855 List<Way> antiIslands = removeAntiIslands(seaRelation, islands);
903856 if (islands.isEmpty()) {
911864 if (generateSeaBackground) {
912865 // the background is sea so all anti-islands should be
913866 // contained by land otherwise they won't be visible
914
915 for (Way ai : antiIslands) {
916 boolean containedByLand = false;
917 for(Way i : islands) {
918 if(i.containsPointsOf(ai)) {
919 containedByLand = true;
920 break;
921 }
922 }
923
924 if (!containedByLand) {
925 // found an anti-island that is not contained by
926 // land so convert it back into an island
927 ai.deleteTag("natural");
928 ai.addTag(landTag[0], landTag[1]);
929 if (generateSeaUsingMP) {
930 // create a "inner" way for the island
931 assert seaRelation != null;
932 seaRelation.addElement("inner", ai);
933 }
934 log.warn("Converting anti-island starting at", ai.getFirstPoint().toOSMURL() , "into an island as it is surrounded by water");
935 }
936 }
937
938 long seaId = FakeIdGenerator.makeFakeId();
939 Way sea = new Way(seaId);
940 // the sea background area must be a little bigger than all
941 // inner land areas. this is a workaround for a mp shortcoming:
942 // mp is not able to combine outer and inner if they intersect
943 // or have overlaying lines
944 // the added area will be clipped later by the style generator
945 sea.addPoint(new Coord(nw.getLatitude() - 1,
946 nw.getLongitude() - 1));
947 sea.addPoint(new Coord(sw.getLatitude() + 1,
948 sw.getLongitude() - 1));
949 sea.addPoint(new Coord(se.getLatitude() + 1,
950 se.getLongitude() + 1));
951 sea.addPoint(new Coord(ne.getLatitude() - 1,
952 ne.getLongitude() + 1));
953 sea.addPoint(sea.getFirstPoint()); // close shape
954 sea.addTag("natural", "sea");
955 sea.setFullArea(SEA_SIZE);
867 verifyIslands(islands, antiIslands, seaRelation);
868
869 Way sea = createSeaWay(tileBounds, true);
956870
957871 log.info("sea: ", sea);
958872 saver.addWay(sea);
959 if(generateSeaUsingMP) {
960 assert seaRelation != null;
873 if(seaRelation != null) {
961874 seaRelation.addElement("outer", sea);
962875 }
963876 } else {
966879 // generate a land polygon so that the tile's
967880 // background colour will match the land colour on the
968881 // tiles that do contain some sea
969 long landId = FakeIdGenerator.makeFakeId();
970 Way land = new Way(landId, seaBounds.toCoords());
971 land.addTag(landTag[0], landTag[1]);
882 Way land = createLandWay(tileBounds);
972883 saver.addWay(land);
973 if (generateSeaUsingMP) {
884 if(seaRelation != null) {
974885 seaRelation.addElement("inner", land);
975886 }
976887 }
992903 shoreline = null;
993904 }
994905
906 private void verifyIslands(List<Way> islands, List<Way> antiIslands, Relation seaRelation) {
907 for (Way ai : antiIslands) {
908 boolean containedByLand = false;
909 for (Way i : islands) {
910 if (i.containsPointsOf(ai)) {
911 containedByLand = true;
912 break;
913 }
914 }
915
916 if (!containedByLand) {
917 // found an anti-island that is not contained by
918 // land so convert it back into an island
919 ai.deleteTag("natural");
920 ai.addTag(landTag[0], landTag[1]);
921 if (seaRelation != null) {
922 // create a "inner" way for the island
923 seaRelation.addElement("inner", ai);
924 }
925 log.warn("Converting anti-island starting at", ai.getFirstPoint().toOSMURL(),
926 "into an island as it is surrounded by water");
927 }
928 }
929 }
930
931 private Way createLandWay(Area tileBounds) {
932 long landId = FakeIdGenerator.makeFakeId();
933 Way land = new Way(landId, tileBounds.toCoords());
934 land.addTag(landTag[0], landTag[1]);
935 return land;
936 }
937
938 /**
939 * Create a sea polygon from the given tile bounds
940 * @param tileBounds
941 * @param enlarge if true, make sure that the polygon is slightly larger than the tile bounds
942 * @return the created way
943 */
944 private static Way createSeaWay(Area tileBounds, boolean enlarge) {
945 log.info("generating sea, seaBounds=", tileBounds);
946 Area bbox = tileBounds;
947 long seaId = FakeIdGenerator.makeFakeId();
948 if (enlarge) {
949 // the sea background area must be a little bigger than all
950 // inner land areas. this is a workaround for a multipolygon shortcoming:
951 // mp is not able to combine outer and inner if they intersect
952 // or have overlaying lines
953 // the added area will be clipped later
954 bbox = new Area(bbox.getMinLat() - 1, bbox.getMinLong() - 1, bbox.getMaxLat() + 1, bbox.getMaxLong() + 1);
955 }
956 Way sea = new Way(seaId, bbox.toCoords());
957 sea.addTag("natural", "sea");
958 sea.setFullArea(SEA_SIZE);
959 return sea;
960 }
961
995962 /**
996963 * Clip the shoreline ways to the bounding box of the map.
997964 * @param shoreline All the the ways making up the coast.
998965 * @param bounds The map bounds.
999966 */
1000 private void clipShorlineSegments(List<Way> shoreline, Area bounds) {
1001 List<Way> toBeRemoved = new ArrayList<Way>();
1002 List<Way> toBeAdded = new ArrayList<Way>();
967 private static void clipShorlineSegments(List<Way> shoreline, Area bounds) {
968 List<Way> toBeRemoved = new ArrayList<>();
969 List<Way> toBeAdded = new ArrayList<>();
1003970 for (Way segment : shoreline) {
1004971 List<Coord> points = segment.getPoints();
1005972 List<List<Coord>> clipped = LineClipper.clip(bounds, points);
1024991 * shore line list and added to the island list.
1025992 *
1026993 * @param shoreline The collected shore line ways.
1027 * @param seaBounds The map boundary.
994 * @param tileBounds The map boundary.
1028995 * @param islands The islands are saved to this list.
1029996 */
1030 private void handleIslands(List<Way> shoreline, Area seaBounds, List<Way> islands) {
997 private void handleIslands(List<Way> shoreline, Area tileBounds, List<Way> islands) {
1031998 Iterator<Way> it = shoreline.iterator();
1032999 while (it.hasNext()) {
10331000 Way w = it.next();
10381005 }
10391006 }
10401007
1041 closeGaps(shoreline, seaBounds);
1008 closeGaps(shoreline, tileBounds);
10421009 // there may be more islands now
10431010 it = shoreline.iterator();
10441011 while (it.hasNext()) {
10511018 }
10521019 }
10531020
1054 private boolean createInnerWays(Area seaBounds, List<Way> islands, NavigableMap<EdgeHit, Way> hitMap) {
1055 NavigableSet<EdgeHit> hits = hitMap.navigableKeySet();
1056 boolean shorelineReachesBoundary = false;
1021 private void closeGaps(List<Way> shoreline, Area bounds) {
1022 if (maxCoastlineGap <= 0)
1023 return;
1024
1025 // join up coastline segments whose end points are less than
1026 // maxCoastlineGap metres apart
1027 boolean changed;
1028 do {
1029 changed = false;
1030 Iterator<Way> iter = shoreline.iterator();
1031 while (!changed && iter.hasNext()) {
1032 Way w1 = iter.next();
1033 if (w1.hasIdenticalEndPoints())
1034 continue;
1035 Coord w1e = w1.getLastPoint();
1036 if (!bounds.onBoundary(w1e)) {
1037 Way closed = tryCloseGap(shoreline, w1, bounds);
1038 if (closed != null) {
1039 saver.addWay(closed);
1040 changed = true;
1041 }
1042 }
1043 }
1044 } while (changed);
1045 }
1046
1047 private Way tryCloseGap(List<Way> shoreline, Way w1, Area bounds) {
1048 Coord w1e = w1.getLastPoint();
1049 Way nearest = null;
1050 double smallestGap = Double.MAX_VALUE;
1051 for (Way w2 : shoreline) {
1052 if (w1 == w2 || w2.hasIdenticalEndPoints())
1053 continue;
1054 Coord w2s = w2.getFirstPoint();
1055 if (!bounds.onBoundary(w2s)) {
1056 double gap = w1e.distance(w2s);
1057 if (gap < smallestGap) {
1058 nearest = w2;
1059 smallestGap = gap;
1060 }
1061 }
1062 }
1063 if (nearest != null && smallestGap < maxCoastlineGap) {
1064 Coord w2s = nearest.getFirstPoint();
1065 log.warn("Bridging " + (int) smallestGap + "m gap in coastline from " + w1e.toOSMURL() + " to "
1066 + w2s.toOSMURL());
1067 Way wm;
1068 if (FakeIdGenerator.isFakeId(w1.getId())) {
1069 wm = w1;
1070 } else {
1071 wm = new Way(w1.getOriginalId());
1072 wm.setFakeId();
1073 shoreline.remove(w1);
1074 shoreline.add(wm);
1075 wm.getPoints().addAll(w1.getPoints());
1076 wm.copyTags(w1);
1077 }
1078 wm.getPoints().addAll(nearest.getPoints());
1079 shoreline.remove(nearest);
1080 // make a line that shows the filled gap
1081 Way w = new Way(FakeIdGenerator.makeFakeId());
1082 w.addTag("natural", "mkgmap:coastline-gap");
1083 w.addPoint(w1e);
1084 w.addPoint(w2s);
1085 return w;
1086 }
1087 return null;
1088 }
1089
1090 /**
1091 * Add lines to ways that touch or cross the sea bounds so that the way is closed along the edges of the bounds.
1092 * Adds complete edges or parts of them. This is done counter-clockwise.
1093 * @param tileBounds the bounds
1094 * @param islands list of land masses to which the closed ways are added
1095 * @param hitMap A map of the 'hits' where the shore line intersects the boundary.
1096 */
1097 private void createLandPolygons(Area tileBounds, List<Way> islands, NavigableMap<Double, Way> hitMap) {
1098 NavigableSet<Double> hits = hitMap.navigableKeySet();
10571099 while (!hits.isEmpty()) {
1058 long id = FakeIdGenerator.makeFakeId();
1059 Way w = new Way(id);
1100 Way w = new Way(FakeIdGenerator.makeFakeId());
10601101 saver.addWay(w);
10611102
1062 EdgeHit hit = hits.first();
1063 EdgeHit hFirst = hit;
1103 Double hit = hits.first();
1104 Double hFirst = hit;
10641105 do {
10651106 Way segment = hitMap.get(hit);
10661107 log.info("current hit:", hit);
1067 EdgeHit hNext;
1108 Double hNext;
10681109 if (segment != null) {
10691110 // add the segment and get the "ending hit"
10701111 log.info("adding:", segment);
1071 for(Coord p : segment.getPoints())
1072 w.addPointIfNotEqualToLastPoint(p);
1073 hNext = getEdgeHit(seaBounds, segment.getLastPoint());
1112 segment.getPoints().forEach(w::addPointIfNotEqualToLastPoint);
1113
1114 hNext = getEdgeHit(tileBounds, segment.getLastPoint());
10741115 } else {
1075 w.addPointIfNotEqualToLastPoint(hit.getPoint(seaBounds));
1116 w.addPointIfNotEqualToLastPoint(getPoint(tileBounds, hit));
10761117 hNext = hits.higher(hit);
10771118 if (hNext == null)
10781119 hNext = hFirst;
1079
1080 Coord p;
1081 if (hit.compareTo(hNext) < 0) {
1082 log.info("joining: ", hit, hNext);
1083 for (int i=hit.edge; i<hNext.edge; i++) {
1084 EdgeHit corner = new EdgeHit(i, 1.0);
1085 p = corner.getPoint(seaBounds);
1086 log.debug("way: ", corner, p);
1087 w.addPointIfNotEqualToLastPoint(p);
1088 }
1089 } else if (hit.compareTo(hNext) > 0) {
1090 log.info("joining: ", hit, hNext);
1091 for (int i=hit.edge; i<4; i++) {
1092 EdgeHit corner = new EdgeHit(i, 1.0);
1093 p = corner.getPoint(seaBounds);
1094 log.debug("way: ", corner, p);
1095 w.addPointIfNotEqualToLastPoint(p);
1096 }
1097 for (int i=0; i<hNext.edge; i++) {
1098 EdgeHit corner = new EdgeHit(i, 1.0);
1099 p = corner.getPoint(seaBounds);
1100 log.debug("way: ", corner, p);
1101 w.addPointIfNotEqualToLastPoint(p);
1102 }
1103 }
1104 w.addPointIfNotEqualToLastPoint(hNext.getPoint(seaBounds));
1120 addCorners(w, tileBounds, hit, hNext);
1121
11051122 }
11061123 hits.remove(hit);
11071124 hit = hNext;
1108 } while (!hits.isEmpty() && !hit.equals(hFirst));
1109
1110 if (!w.hasIdenticalEndPoints())
1125 } while (!hits.isEmpty() && Double.compare(hFirst, hit) != 0);
1126
1127 if (!w.hasIdenticalEndPoints()) {
1128 if (w.getFirstPoint().highPrecEquals(w.getLastPoint())) {
1129 w.getPoints().remove(w.getPoints().size() - 1);
1130 }
11111131 w.addPoint(w.getFirstPoint()); // close shape
1132 }
11121133 log.info("adding non-island landmass, hits.size()=" + hits.size());
11131134 islands.add(w);
1114 shorelineReachesBoundary = true;
1115 }
1116 return shorelineReachesBoundary;
1135 }
1136 }
1137
1138 private static void addCorners(Way w, Area tileBounds, double hit, double hNext) {
1139 if (hit != hNext) {
1140 int startEdge = (int) hit;
1141 int endEdge = (int) hNext;
1142 if (endEdge < startEdge)
1143 endEdge += 4;
1144 log.info("joining: ", hit, hNext);
1145 for (int i = startEdge; i < endEdge; i++) {
1146 int edge = i < 4 ? i : i - 4;
1147 Coord p = getPoint(tileBounds, edge + 1.0);
1148 w.addPointIfNotEqualToLastPoint(p);
1149 }
1150 }
1151 w.addPointIfNotEqualToLastPoint(getPoint(tileBounds, hNext));
11171152 }
11181153
11191154 /**
11251160 * @return The so-called anti-islands.
11261161 */
11271162 private List<Way> removeAntiIslands(Relation seaRelation, List<Way> islands) {
1128 List<Way> antiIslands = new ArrayList<Way>();
1129 for (Way w : islands) {
1130
1163 List<Way> antiIslands = new ArrayList<>();
1164 Iterator<Way> iter = islands.iterator();
1165 while (iter.hasNext()) {
1166 Way w = iter.next();
11311167 if (!FakeIdGenerator.isFakeId(w.getId())) {
1132 Way w1 = new Way(w.getOriginalId());
1133 w1.setFakeId();
1134 w1.getPoints().addAll(w.getPoints());
1135 // only copy the name tags
1136 for (Entry<String, String> tagEntry : w.getTagEntryIterator()){
1137 if(tagEntry.getKey().equals("name") || tagEntry.getKey().contains("name"))
1138 w1.addTag(tagEntry.getKey(), tagEntry.getValue());
1139 }
1140 w = w1;
1168 w = copyWithNameTags(w);
11411169 }
11421170
11431171 // determine where the water is
11471175 // make it visible above the land)
11481176 w.addTag("natural", "water");
11491177 antiIslands.add(w);
1178 iter.remove();
11501179 saver.addWay(w);
11511180 } else {
11521181 // water on the outside of the poly, it's an island
11531182 w.addTag(landTag[0], landTag[1]);
11541183 saver.addWay(w);
1155 if(generateSeaUsingMP) {
1184 if (seaRelation != null) {
11561185 // create a "inner" way for each island
11571186 seaRelation.addElement("inner", w);
1158 }
1159 }
1160 }
1161
1162 islands.removeAll(antiIslands);
1187 }
1188 }
1189 }
11631190 return antiIslands;
1191 }
1192
1193 /**
1194 * Create copy of way, but ignore tags that don't contain "name" in the key
1195 * @param w
1196 * @return
1197 */
1198 private static Way copyWithNameTags(Way w) {
1199 Way w1 = new Way(w.getOriginalId(), w.getPoints());
1200 w1.setFakeId();
1201 for (Entry<String, String> tagEntry : w.getTagEntryIterator()) {
1202 if ("name".equals(tagEntry.getKey()) || tagEntry.getKey().contains("name")) {
1203 w1.addTag(tagEntry.getKey(), tagEntry.getValue());
1204 }
1205 }
1206 return w1;
11641207 }
11651208
11661209 /**
11681211 * map boundary.
11691212 *
11701213 * @param shoreline The remaining shore line segments.
1171 * @param seaBounds The map boundary.
1214 * @param tileBounds The map boundary.
11721215 * @param seaRelation If we are using a multi-polygon, this is it. Otherwise it will be null.
11731216 * @return A map of the 'hits' where the shore line intersects the boundary.
11741217 */
1175 private NavigableMap<EdgeHit, Way> findIntesectionPoints(List<Way> shoreline, Area seaBounds, Relation seaRelation) {
1176 assert !generateSeaUsingMP || seaRelation != null;
1177
1178 NavigableMap<EdgeHit, Way> hitMap = new TreeMap<EdgeHit, Way>();
1218 private NavigableMap<Double, Way> findIntesectionPoints(List<Way> shoreline, Area tileBounds, Relation seaRelation) {
1219 if (generateSeaUsingMP && seaRelation == null)
1220 throw new MapFailedException("seaRelation is null");
1221
1222 NavigableMap<Double, Way> hitMap = new TreeMap<>();
11791223 for (Way w : shoreline) {
1180 List<Coord> points = w.getPoints();
1181 Coord pStart = points.get(0);
1182 Coord pEnd = points.get(points.size()-1);
1183
1184 EdgeHit hStart = getEdgeHit(seaBounds, pStart);
1185 EdgeHit hEnd = getEdgeHit(seaBounds, pEnd);
1186 if (hStart == null || hEnd == null) {
1187
1224 Coord pStart = w.getFirstPoint();
1225 Coord pEnd = w.getLastPoint();
1226
1227 Double hStart = getEdgeHit(tileBounds, pStart);
1228 Double hEnd = getEdgeHit(tileBounds, pEnd);
1229 if (hStart != null && hEnd != null) {
1230 // nice case: both ends touch the boundary
1231 log.debug("hits: ", hStart, hEnd);
1232 hitMap.put(hStart, w);
1233 hitMap.put(hEnd, null);
1234 } else {
11881235 /*
11891236 * This problem occurs usually when the shoreline is cut by osmosis (e.g. country-extracts from geofabrik)
11901237 * There are two possibilities to solve this problem:
11961243 *
11971244 * Usually, the first choice is appropriate if the segment is "nearly" closed.
11981245 */
1199 double length = 0;
1200 Coord p0 = pStart;
1201 for (Coord p1 : points.subList(1, points.size()-1)) {
1202 length += p0.distance(p1);
1203 p0 = p1;
1204 }
1205 boolean nearlyClosed = pStart.distance(pEnd) < 0.1 * length;
1246 List<Coord> points = w.getPoints();
1247 boolean nearlyClosed = pStart.distance(pEnd) < 0.1 * w.calcLengthInMetres();
12061248
12071249 if (nearlyClosed) {
12081250 // close the way
1209 points.add(pStart);
1251 points.add(pStart); // XXX original way is modified, is that correct?
12101252
1211 if(!FakeIdGenerator.isFakeId(w.getId())) {
1212 Way w1 = new Way(w.getOriginalId());
1213 w1.setFakeId();
1214 w1.getPoints().addAll(w.getPoints());
1215 // only copy the name tags
1216 for (Entry<String, String> tagEntry : w.getTagEntryIterator()){
1217 if(tagEntry.getKey().equals("name") || tagEntry.getKey().contains("name"))
1218 w1.addTag(tagEntry.getKey(), tagEntry.getValue());
1219 }
1220 w = w1;
1253 if (!FakeIdGenerator.isFakeId(w.getId())) {
1254 w = copyWithNameTags(w);
12211255 }
12221256 w.addTag(landTag[0], landTag[1]);
12231257 saver.addWay(w);
1224 if(generateSeaUsingMP)
1225 {
1258 if (generateSeaUsingMP) {
12261259 seaRelation.addElement("inner", w);
12271260 }
12281261 } else if(allowSeaSectors) {
12291262 Way sea;
1230 if (seaRelation != null) {
1263 if (generateSeaUsingMP) {
12311264 sea = new Way(seaRelation.getOriginalId());
12321265 sea.setFakeId();
1266 } else {
1267 sea = new Way(FakeIdGenerator.makeFakeId());
12331268 }
1234 else
1235 sea = new Way(FakeIdGenerator.makeFakeId());
12361269 sea.getPoints().addAll(points);
12371270 sea.addPoint(new Coord(pEnd.getLatitude(), pStart.getLongitude()));
12381271 sea.addPoint(pStart);
12451278 } else if (extendSeaSectors) {
12461279 // create additional points at next border to prevent triangles from point 2
12471280 if (null == hStart) {
1248 hStart = getNextEdgeHit(seaBounds, pStart);
1249 w.getPoints().add(0, hStart.getPoint(seaBounds));
1281 hStart = getNextEdgeHit(tileBounds, pStart);
1282 w.getPoints().add(0, getPoint(tileBounds, hStart));
12501283 }
12511284 if (null == hEnd) {
1252 hEnd = getNextEdgeHit(seaBounds, pEnd);
1253 w.getPoints().add(hEnd.getPoint(seaBounds));
1285 hEnd = getNextEdgeHit(tileBounds, pEnd);
1286 w.getPoints().add(getPoint(tileBounds, hEnd));
12541287 }
12551288 log.debug("hits (second try): ", hStart, hEnd);
12561289 hitMap.put(hStart, w);
12591292 // show the coastline even though we can't produce
12601293 // a polygon for the land
12611294 w.addTag("natural", "coastline");
1262 if (w.hasIdenticalEndPoints() == false){
1295 if (!w.hasIdenticalEndPoints()) {
12631296 log.error("adding sea shape that is not really closed");
12641297 }
12651298 saver.addWay(w);
12661299 }
1267 } else {
1268 log.debug("hits: ", hStart, hEnd);
1269 hitMap.put(hStart, w);
1270 hitMap.put(hEnd, null);
12711300 }
12721301 }
12731302 return hitMap;
12741303 }
12751304
1276 /**
1277 * Specifies where an edge of the bounding box is hit.
1278 */
1279 private static class EdgeHit implements Comparable<EdgeHit>
1280 {
1281 private final int edge;
1282 private final double t;
1283
1284 EdgeHit(int edge, double t) {
1285 this.edge = edge;
1286 this.t = t;
1287 }
1288
1289 public int compareTo(EdgeHit o) {
1290 if (edge < o.edge)
1291 return -1;
1292 else if (edge > o.edge)
1293 return +1;
1294 else if (t > o.t)
1295 return +1;
1296 else if (t < o.t)
1297 return -1;
1298 else
1299 return 0;
1300 }
1301
1302 public boolean equals(Object o) {
1303 if (o instanceof EdgeHit) {
1304 EdgeHit h = (EdgeHit) o;
1305 return (h.edge == edge && Double.compare(h.t, t) == 0);
1306 } else
1307 return false;
1308 }
1309
1310 private Coord getPoint(Area a) {
1311 log.info("getPoint: ", this, a);
1312 switch (edge) {
1313 case 0:
1314 return new Coord(a.getMinLat(), (int) (a.getMinLong() + t * (a.getMaxLong()-a.getMinLong())));
1315
1316 case 1:
1317 return new Coord((int)(a.getMinLat() + t * (a.getMaxLat()-a.getMinLat())), a.getMaxLong());
1318
1319 case 2:
1320 return new Coord(a.getMaxLat(), (int)(a.getMaxLong() - t * (a.getMaxLong()-a.getMinLong())));
1321
1322 case 3:
1323 return new Coord((int)(a.getMaxLat() - t * (a.getMaxLat()-a.getMinLat())), a.getMinLong());
1324
1325 default:
1326 throw new MapFailedException("illegal state");
1327 }
1328 }
1329
1330 public String toString() {
1331 return "EdgeHit " + edge + "@" + t;
1332 }
1333 }
1334
1335 private EdgeHit getEdgeHit(Area a, Coord p) {
1336 return getEdgeHit(a, p, 10);
1337 }
1338
1339 private EdgeHit getEdgeHit(Area a, Coord p, int tolerance) {
1340 int lat = p.getLatitude();
1341 int lon = p.getLongitude();
1342 int minLat = a.getMinLat();
1343 int maxLat = a.getMaxLat();
1344 int minLong = a.getMinLong();
1345 int maxLong = a.getMaxLong();
1346
1347 log.info(String.format("getEdgeHit: (%d %d) (%d %d %d %d)", lat, lon, minLat, minLong, maxLat, maxLong));
1348 if (lat <= minLat+tolerance) {
1349 return new EdgeHit(0, ((double)(lon - minLong))/(maxLong-minLong));
1350 } else if (lon >= maxLong-tolerance) {
1351 return new EdgeHit(1, ((double)(lat - minLat))/(maxLat-minLat));
1352 } else if (lat >= maxLat-tolerance) {
1353 return new EdgeHit(2, ((double)(maxLong - lon))/(maxLong-minLong));
1354 } else if (lon <= minLong+tolerance) {
1355 return new EdgeHit(3, ((double)(maxLat - lat))/(maxLat-minLat));
1356 } else
1357 return null;
1305 // create the point where the shoreline hits the sea bounds
1306 private static Coord getPoint(Area a, double edgePos) {
1307 log.info("getPoint: ", a, edgePos);
1308 int aMinLongHP = a.getMinLong() << Coord.DELTA_SHIFT;
1309 int aMaxLongHP = a.getMaxLong() << Coord.DELTA_SHIFT;
1310 int aMinLatHP = a.getMinLat() << Coord.DELTA_SHIFT;
1311 int aMaxLatHP = a.getMaxLat() << Coord.DELTA_SHIFT;
1312 int platHp;
1313 int plonHp;
1314 int edge = (int) edgePos;
1315 double t = edgePos - edge;
1316 if (edge >= 4)
1317 edge -= 4;
1318 switch (edge) {
1319 case 0: // southern
1320 platHp = aMinLatHP;
1321 plonHp = (int) Math.round(aMinLongHP + t * (aMaxLongHP - aMinLongHP));
1322 break;
1323 case 1: // eastern
1324 platHp = (int) Math.round(aMinLatHP + t * (aMaxLatHP - aMinLatHP));
1325 plonHp = aMaxLongHP;
1326 break;
1327 case 2: // northern
1328 platHp = aMaxLatHP;
1329 plonHp = (int) Math.round(aMaxLongHP - t * (aMaxLongHP - aMinLongHP));
1330 break;
1331 case 3: // western
1332 platHp = (int) Math.round(aMaxLatHP - t * (aMaxLatHP - aMinLatHP));
1333 plonHp = aMinLongHP;
1334 break;
1335 default:
1336 throw new MapFailedException("illegal state");
1337 }
1338 return Coord.makeHighPrecCoord(platHp, plonHp);
1339 }
1340
1341 /**
1342 * Calculate a Double that represents the position where the given point touches
1343 * the boundary.
1344 *
1345 * @param bounds the boundary
1346 * @param p the point
1347 * @return null if the point is not touching the boundary, else a value
1348 * between 0.0 (inclusive) and 4.0 (exclusive), where 0 means the lower
1349 * left corner, 0.5 means the middle of the bottom edge, 1.5 the
1350 * middle of the right edge, 4 would be the lower left corner again
1351 */
1352 private static Double getEdgeHit(Area bounds, Coord p) {
1353 Double hit = getEdgeHit(bounds, p, 10); // 10 points in garmin units
1354 if (hit != null && hit >= 4)
1355 hit = 0.0;
1356 return hit;
1357 }
1358
1359 private static Double getEdgeHit(Area a, Coord p, int tolerance24) {
1360 final int toleranceHp = tolerance24 << Coord.DELTA_SHIFT;
1361 final int latHp = p.getHighPrecLat();
1362 final int lonHp = p.getHighPrecLon();
1363 final int minLatHp = a.getMinLat() << Coord.DELTA_SHIFT;
1364 final int maxLatHp = a.getMaxLat() << Coord.DELTA_SHIFT;
1365 final int minLongHp = a.getMinLong() << Coord.DELTA_SHIFT;
1366 final int maxLongHp = a.getMaxLong() << Coord.DELTA_SHIFT;
1367
1368 log.info(String.format("getEdgeHit: (%d %d) (%d %d %d %d)", latHp, lonHp, minLatHp, minLongHp, maxLatHp, maxLongHp));
1369 if (latHp <= minLatHp + toleranceHp) {
1370 return (double) (lonHp - minLongHp) / (maxLongHp - minLongHp);
1371 } else if (lonHp >= maxLongHp - toleranceHp) {
1372 return 1 + ((double) (latHp - minLatHp) / (maxLatHp - minLatHp));
1373 } else if (latHp >= maxLatHp - toleranceHp) {
1374 return 2 + ((double) (maxLongHp - lonHp) / (maxLongHp - minLongHp));
1375 } else if (lonHp <= minLongHp + toleranceHp) {
1376 return 3 + ((double) (maxLatHp - latHp) / (maxLatHp - minLatHp));
1377 }
1378 return null;
13581379 }
13591380
13601381 /**
13611382 * Find the nearest edge for supplied Coord p.
13621383 */
1363 private EdgeHit getNextEdgeHit(Area a, Coord p)
1364 {
1365 int lat = p.getLatitude();
1366 int lon = p.getLongitude();
1367 int minLat = a.getMinLat();
1368 int maxLat = a.getMaxLat();
1369 int minLong = a.getMinLong();
1370 int maxLong = a.getMaxLong();
1371
1372 log.info(String.format("getNextEdgeHit: (%d %d) (%d %d %d %d)", lat, lon, minLat, minLong, maxLat, maxLong));
1384 private static Double getNextEdgeHit(Area a, Coord p) {
1385 int latHp = p.getHighPrecLat();
1386 int lonHp = p.getHighPrecLon();
1387 int minLatHp = a.getMinLat() << Coord.DELTA_SHIFT;
1388 int maxLatHp = a.getMaxLat() << Coord.DELTA_SHIFT;
1389 int minLongHp = a.getMinLong() << Coord.DELTA_SHIFT;
1390 int maxLongHp = a.getMaxLong() << Coord.DELTA_SHIFT;
1391
1392 log.info(String.format("getNextEdgeHit: (%d %d) (%d %d %d %d)", latHp, lonHp, minLatHp, minLongHp, maxLatHp, maxLongHp));
13731393 // shortest distance to border (init with distance to southern border)
1374 int min = lat - minLat;
1394 int min = latHp - minLatHp;
13751395 // number of edge as used in getEdgeHit.
1376 // 0 = southern
1377 // 1 = eastern
1378 // 2 = northern
1396 // 0 = bottom
1397 // 1 = right
1398 // 2 = upper
13791399 // 3 = western edge of Area a
13801400 int i = 0;
13811401 // normalized position at border (0..1)
1382 double l = ((double)(lon - minLong))/(maxLong-minLong);
1402 double t = ((double) (lonHp - minLongHp)) / (maxLongHp - minLongHp);
13831403 // now compare distance to eastern border with already known distance
1384 if (maxLong - lon < min) {
1404 if (maxLongHp - lonHp < min) {
13851405 // update data if distance is shorter
1386 min = maxLong - lon;
1406 min = maxLongHp - lonHp;
13871407 i = 1;
1388 l = ((double)(lat - minLat))/(maxLat-minLat);
1408 t = ((double) (latHp - minLatHp)) / (maxLatHp - minLatHp);
13891409 }
13901410 // same for northern border
1391 if (maxLat - lat < min) {
1392 min = maxLat - lat;
1411 if (maxLatHp - latHp < min) {
1412 min = maxLatHp - latHp;
13931413 i = 2;
1394 l = ((double)(maxLong - lon))/(maxLong-minLong);
1414 t = ((double) (maxLongHp - lonHp)) / (maxLongHp - minLongHp);
13951415 }
13961416 // same for western border
1397 if (lon - minLong < min) {
1417 if (lonHp - minLongHp < min) {
13981418 i = 3;
1399 l = ((double)(maxLat - lat))/(maxLat-minLat);
1419 t = ((double) (maxLatHp - latHp)) / (maxLatHp - minLatHp);
14001420 }
14011421 // now created the EdgeHit for found values
1402 return new EdgeHit(i, l);
1403 }
1404
1405 private void closeGaps(List<Way> ways, Area bounds) {
1406
1407 // join up coastline segments whose end points are less than
1408 // maxCoastlineGap metres apart
1409 if (maxCoastlineGap > 0) {
1410 boolean changed = true;
1411 while (changed) {
1412 changed = false;
1413 for (Way w1 : ways) {
1414 if(w1.hasIdenticalEndPoints())
1415 continue;
1416 List<Coord> points1 = w1.getPoints();
1417 Coord w1e = w1.getLastPoint();
1418 if(bounds.onBoundary(w1e))
1419 continue;
1420 Way nearest = null;
1421 double smallestGap = Double.MAX_VALUE;
1422 for (Way w2 : ways) {
1423 if(w1 == w2 || w2.hasIdenticalEndPoints())
1424 continue;
1425 List<Coord> points2 = w2.getPoints();
1426 Coord w2s = points2.get(0);
1427 if(bounds.onBoundary(w2s))
1428 continue;
1429 double gap = w1e.distance(w2s);
1430 if(gap < smallestGap) {
1431 nearest = w2;
1432 smallestGap = gap;
1433 }
1434 }
1435 if (nearest != null && smallestGap < maxCoastlineGap) {
1436 Coord w2s = nearest.getPoints().get(0);
1437 log.warn("Bridging " + (int)smallestGap + "m gap in coastline from " + w1e.toOSMURL() + " to " + w2s.toOSMURL());
1438 Way wm;
1439 if (FakeIdGenerator.isFakeId(w1.getId())) {
1440 wm = w1;
1441 } else {
1442 wm = new Way(w1.getOriginalId());
1443 wm.setFakeId();
1444 ways.remove(w1);
1445 ways.add(wm);
1446 wm.getPoints().addAll(points1);
1447 wm.copyTags(w1);
1448 }
1449 wm.getPoints().addAll(nearest.getPoints());
1450 ways.remove(nearest);
1451 // make a line that shows the filled gap
1452 Way w = new Way(FakeIdGenerator.makeFakeId());
1453 w.addTag("natural", "mkgmap:coastline-gap");
1454 w.addPoint(w1e);
1455 w.addPoint(w2s);
1456 saver.addWay(w);
1457 changed = true;
1458 break;
1459 }
1460 }
1461 }
1462 }
1422 return i + t;
14631423 }
14641424
14651425 /**
14661426 * Helper class for threadlocal vars
1467 *
1468 *
1469 */
1470 class PrecompData {
1427 */
1428 private static class PrecompData {
14711429 /**
14721430 * The index is a grid [lon][lat]. Each element defines the content of one precompiled
14731431 * sea tile which are {@link #SEA_TYPE}, {@link #LAND_TYPE}, or {@link #MIXED_TYPE}, or 0 for unknown
14771435 private String precompSeaPrefix;
14781436 private String precompZipFileInternalPath;
14791437 private ZipFile zipFile;
1480
1481 }
1438 private File dirFile;
1439 }
1440
14821441 }
3030 * @author WanMil
3131 */
3232 public class SeaPolygonRelation extends MultiPolygonRelation {
33 private static final Logger log = Logger
34 .getLogger(SeaPolygonRelation.class);
33 private static final Logger log = Logger.getLogger(SeaPolygonRelation.class);
3534
3635 private final QuadTree landCoords;
3736 private final QuadTree seaCoords;
4443 private final DecimalFormat format = new DecimalFormat("0.0000");
4544 private Rule floodBlockerRules;
4645
47 private final String[] landTag = {"natural","land"};
46 private final String[] landTag = { "natural", "land" };
4847
4948 public SeaPolygonRelation(Relation other, Map<Long, Way> wayMap, Area bbox) {
5049 super(other, wayMap, bbox);
6059 return false;
6160 }
6261
62 @Override
6363 protected void postProcessing() {
6464 if (isFloodBlocker()) {
6565 removeFloodedAreas();
107107 // create a copy of all resulting ways - the tile way map contains only
108108 // polygons from
109109 // the sea generation
110 ArrayList<Way> polygons = new ArrayList<Way>(getMpPolygons().values());
111
112 log.info("Starting flood blocker. Polygons to check:", getMpPolygons()
113 .size());
110 ArrayList<Way> polygons = new ArrayList<>(getMpPolygons().values());
111
112 log.info("Starting flood blocker. Polygons to check:", getMpPolygons().size());
114113
115114 String baseName = GpxCreator.getGpxBaseName();
116115 if (debug) {
127126 String polyType = (sea ? "sea" : "land");
128127 String otherType = (sea ? "land" : "sea");
129128
130 List<Coord> minusCoords = badCoords.get(p.getPoints(),
131 getFloodBlockerGap());
129 List<Coord> minusCoords = badCoords.get(p.getPoints(), getFloodBlockerGap());
132130 List<Coord> positiveCoords = goodCoords.get(p.getPoints());
133131
134132 log.info(polyType,"polygon", p.getId(), "contains",
135133 minusCoords.size(), otherType,"coords and",
136134 positiveCoords.size(), polyType,"coords.");
137
138 if (minusCoords.size() > 0) {
135
136 if (!minusCoords.isEmpty()) {
139137 double area = MultiPolygonRelation.calcAreaSize(p.getPoints());
140138 double ratio = ((minusCoords.size() - positiveCoords.size()) * 100000.0d / area);
141139 String areaFMT = format.format(area);
157155 + positiveCoords.size() + "_" + ratioFMT,
158156 null, minusCoords);
159157
160 if (positiveCoords.isEmpty() == false) {
158 if (!positiveCoords.isEmpty()) {
161159 GpxCreator.createGpx(
162160 baseName + p.getId() + "_pro_"
163161 + minusCoords.size() + "_"
177175 p.deleteTag(landTag[0]);
178176 p.addTag("natural", "sea");
179177 }
180 // getMpPolygons().remove(p.getId());
181178 } else {
182179 log.info("Polygon",p.getId(), "is not blocked");
183180 }
223220 this.floodBlockerThreshold = floodBlockerThreshold;
224221 }
225222
226 public boolean isDebug() {
227 return debug;
228 }
229
230223 public void setDebug(boolean debug) {
231224 this.debug = debug;
232225 }
1515 */
1616 package uk.me.parabola.mkgmap.reader.osm;
1717
18 import java.awt.*;
18 import java.awt.Polygon;
1919 import java.util.ArrayList;
2020 import java.util.Collections;
2121 import java.util.List;
9999 }
100100
101101 public void addPointIfNotEqualToLastPoint(Coord co) {
102 if(points.isEmpty() || !co.equals(points.get(points.size() - 1)))
102 if(points.isEmpty() || !co.highPrecEquals(getLastPoint()))
103103 points.add(co);
104104 }
105105
281281 this.fullArea = fullArea;
282282 }
283283
284 public long getFullArea() { // this is unadulterated size, +ve if clockwise
285 if (this.fullArea == Long.MAX_VALUE && points.size() >= 4 && points.get(0).highPrecEquals(points.get(points.size()-1))) {
284 public long getFullArea() { // this is unadulterated size, positive if clockwise
285 if (this.fullArea == Long.MAX_VALUE && points.size() >= 4 && getFirstPoint().highPrecEquals(getLastPoint())) {
286286 this.fullArea = ShapeMergeFilter.calcAreaSizeTestVal(points);
287287 }
288288 return this.fullArea;
289289 }
290
291 public double calcLengthInMetres() {
292 double length = 0;
293 if (points.size() > 1) {
294 Coord p0 = points.get(0);
295 for (int i = 1; i < points.size(); i++) {
296 Coord p1 = points.get(i);
297 length += p0.distance(p1);
298 p0 = p1;
299 }
300 }
301 return length;
302 }
290303 }
1515 import java.io.ByteArrayInputStream;
1616 import java.io.IOException;
1717 import java.io.InputStream;
18 import java.nio.charset.StandardCharsets;
1819
1920 import uk.me.parabola.imgfmt.app.Coord;
2021 import uk.me.parabola.mkgmap.reader.osm.Element;
4849 private static final int STRING_TABLE_SIZE = 15000;
4950 private static final int MAX_STRING_PAIR_SIZE = 250 + 2;
5051 private static final String[] REL_REF_TYPES = {"node", "way", "relation", "?"};
51 private static final double FACTOR = 1d/1000000000; // used with 100*<Val>*FACTOR
52 private static final double FACTOR = 1d/1_000_000_000; // used with 100*<Val>*FACTOR
5253
5354 private BufferedInputStream fis;
5455 private InputStream is;
55 private ByteArrayInputStream bis;
5656
5757 // buffer for byte -> String conversions
5858 private byte[] cnvBuffer;
5959
6060 private byte[] ioBuf;
61 private int ioPos;
61 private int ioBufPos;
6262 // the o5m string table
6363 private String[][] stringTable;
6464 private String[] stringPair;
6666 // a counter that must be maintained by all routines that read data from the stream
6767 private int bytesToRead;
6868 // total number of bytes read from stream
69 long countBytes;
69 private long countBytes;
7070
7171 // for delta calculations
7272 private long lastNodeId;
7373 private long lastWayId;
7474 private long lastRelId;
75 private long lastRef[];
75 private long[] lastRef;
7676 private long lastTs;
7777 private long lastChangeSet;
78 private int lastLon,lastLat;
78 private int lastLon;
79 private int lastLat;
7980
8081 /**
8182 * A parser for the o5m format
82 * @param processor A mapProcessor instance
83 * @param skipArray An Array of longs that is used to hold information of file position of the first occurrence of
84 * each known 05m data type (esp. nodes, ways, and relations).
8583 */
8684 public O5mBinHandler() {
85 // nothing to do
8786 }
8887
8988 @Override
9291 }
9392
9493 /**
95 * parse the input stream
94 * Parse the input stream.
9695 */
9796 @Override
98 public void parse(InputStream stream){
97 public void parse(InputStream stream) {
9998 this.fis = new BufferedInputStream(stream);
10099 is = fis;
101100 this.cnvBuffer = new byte[4000]; // OSM data should not contain string pairs with length > 512
102101 this.ioBuf = new byte[8192];
103 this.ioPos = 0;
102 this.ioBufPos = 0;
104103 this.stringPair = new String[2];
105104 this.lastRef = new long[3];
106105 reset();
107106 try {
108107 int start = is.read();
109108 ++countBytes;
110 if (start != RESET_FLAG)
109 if (start != RESET_FLAG)
111110 throw new IOException("wrong header byte " + start);
112111 readFile();
113112 } catch (IOException e) {
113 System.err.println("exception after " + countBytes + " bytes");
114114 e.printStackTrace();
115115 }
116116 }
117117
118118 private void readFile() throws IOException{
119119 boolean done = false;
120 while(!done){
120 while(!done) {
121121 is = fis;
122122 long size = 0;
123123 int fileType = is.read();
124124 ++countBytes;
125 if (fileType >= 0 && fileType < 0xf0){
125 if (fileType >= 0 && fileType < 0xf0) {
126126 bytesToRead = 0;
127127 size = readUnsignedNum64FromStream();
128 countBytes += size - bytesToRead; // bytesToRead is negative
129 bytesToRead = (int)size;
128 countBytes += size - bytesToRead; // bytesToRead is negative
129 bytesToRead = (int) size;
130130
131 switch(fileType){
131 switch (fileType) {
132132 case NODE_DATASET:
133133 case WAY_DATASET:
134134 case REL_DATASET:
135135 case BBOX_DATASET:
136136 case TIMESTAMP_DATASET:
137137 case HEADER_DATASET:
138 if (bytesToRead > ioBuf.length){
139 ioBuf = new byte[(int)bytesToRead+100];
138 if (bytesToRead > ioBuf.length) {
139 ioBuf = new byte[bytesToRead + 100];
140140 }
141 int bytesRead = 0;
141 int bytesRead = 0;
142142 int neededBytes = bytesToRead;
143 while (neededBytes > 0){
143 while (neededBytes > 0) {
144144 bytesRead += is.read(ioBuf, bytesRead, neededBytes);
145145 neededBytes -= bytesRead;
146 }
147 ioPos = 0;
148 bis = new ByteArrayInputStream(ioBuf,0,bytesToRead);
149 is = bis;
150 break;
146 }
147 ioBufPos = 0;
148 is = new ByteArrayInputStream(ioBuf, 0, bytesToRead);
149 break;
151150 default:
152151 }
153152 }
161160 else if (fileType == EOD_FLAG) done = true;
162161 else if (fileType == RESET_FLAG) reset();
163162 else {
164 if (fileType < 0xf0 )skip(size); // skip unknown data set
165 }
166 }
167 }
168
169 /**
170 * read (and ignore) the file timestamp data set
171 */
172 private void readFileTimestamp(){
173 /*long fileTimeStamp = */readSignedNum64();
163 if (fileType < 0xf0 ) skip(size); // skip unknown data set
164 }
165 }
166 }
167
168 /**
169 * Read (and ignore) the file timestamp data set.
170 */
171 private void readFileTimestamp() {
172 /* long fileTimeStamp = */readSignedNum64();
174173 }
175174
176175 /**
178177 * @param bytes
179178 * @throws IOException
180179 */
181 private void skip(long bytes)throws IOException{
180 private void skip(long bytes) throws IOException {
182181 long toSkip = bytes;
183 while (toSkip > 0)
182 while (toSkip > 0) {
184183 toSkip -= is.skip(toSkip);
185 }
186
187 /**
188 * read the bounding box data set
189 * @throws IOException
184 }
185 }
186
187 /**
188 * Read the bounding box data set.
190189 */
191190 private void readBBox() {
192 double leftf = (double) (100L*readSignedNum32()) * FACTOR;
193 double bottomf = (double) (100L*readSignedNum32()) * FACTOR;
194 double rightf = (double) (100L*readSignedNum32()) * FACTOR;
195 double topf = (double) (100L*readSignedNum32()) * FACTOR;
191 double minlon = FACTOR * 100L * readSignedNum32();
192 double minlat = FACTOR * 100L * readSignedNum32();
193 double maxlon = FACTOR * 100L * readSignedNum32();
194 double maxlat = FACTOR * 100L * readSignedNum32();
195
196196 assert bytesToRead == 0;
197 setBBox(bottomf, leftf, topf, rightf);
198 }
199
200 /**
201 * read a node data set
202 * @throws IOException
203 */
204 private void readNode() throws IOException{
197 setBBox(minlat, minlon, maxlat, maxlon);
198 }
199
200 /**
201 * Read a node data set.
202 */
203 private void readNode() {
205204 lastNodeId += readSignedNum64();
206205 if (bytesToRead == 0)
207206 return; // only nodeId: this is a delete action, we ignore it
211210 int lon = readSignedNum32() + lastLon; lastLon = lon;
212211 int lat = readSignedNum32() + lastLat; lastLat = lat;
213212
214 double flon = (double)(100L*lon) * FACTOR;
215 double flat = (double)(100L*lat) * FACTOR;
213 double flon = FACTOR * (100L * lon);
214 double flat = FACTOR * (100L * lat);
216215 assert flat >= -90.0 && flat <= 90.0;
217216 assert flon >= -180.0 && flon <= 180.0;
218217
219218 Coord co = new Coord(flat, flon);
220219 saver.addPoint(lastNodeId, co);
221 if (bytesToRead > 0){
222 Node node = new Node(lastNodeId,co);
220 if (bytesToRead > 0) {
221 Node node = new Node(lastNodeId, co);
223222 readTags(node);
224 if (node.getTagCount() > 0){
223 if (node.getTagCount() > 0) {
225224 // If there are tags, then we save a proper node for it.
226225 saver.addNode(node);
227226 hooks.onAddNode(node);
230229 }
231230
232231 /**
233 * read a way data set
234 * @throws IOException
235 */
236 private void readWay() throws IOException{
232 * Read a way data set.
233 */
234 private void readWay() {
237235 lastWayId += readSignedNum64();
238236 if (bytesToRead == 0)
239 return; // only wayId: this is a delete action, we ignore it
237 return; // only wayId: this is a delete action, we ignore it
240238
241239 readVersionTsAuthor();
242240 if (bytesToRead == 0)
243 return; // only wayId + version: this is a delete action, we ignore it
241 return; // only wayId + version: this is a delete action, we ignore it
244242 Way way = startWay(lastWayId);
245243 long refSize = readUnsignedNum32();
246244 long stop = bytesToRead - refSize;
247
248 while(bytesToRead > stop){
245
246 while (bytesToRead > stop) {
249247 lastRef[0] += readSignedNum64();
250248 addCoordToWay(way, lastRef[0]);
251249 }
252
250
253251 readTags(way);
254252 endWay(way);
255253 }
256254
257255 /**
258 * read a relation data set
259 * @throws IOException
260 */
261 private void readRel() throws IOException{
256 * Read a relation data set.
257 */
258 private void readRel() {
262259 lastRelId += readSignedNum64();
263260 if (bytesToRead == 0)
264261 return; // only relId: this is a delete action, we ignore it
269266 GeneralRelation rel = new GeneralRelation(lastRelId);
270267 long refSize = readUnsignedNum32();
271268 long stop = bytesToRead - refSize;
272 while(bytesToRead > stop){
269 while (bytesToRead > stop) {
273270 Element el = null;
274271 long deltaRef = readSignedNum64();
275272 int refType = readRelRef();
276273 String role = stringPair[1];
277274 lastRef[refType] += deltaRef;
278275 long memId = lastRef[refType];
279 if (refType == 0){
276 if (refType == 0) {
280277 el = saver.getNode(memId);
281 if(el == null) {
278 if (el == null) {
282279 // we didn't make a node for this point earlier,
283280 // do it now (if it exists)
284281 Coord co = saver.getCoord(memId);
285 if(co != null) {
282 if (co != null) {
286283 el = new Node(memId, co);
287 saver.addNode((Node)el);
284 saver.addNode((Node) el);
288285 }
289286 }
290 }
291 else if (refType == 1){
287 } else if (refType == 1) {
292288 el = saver.getWay(memId);
293 }
294 else if (refType == 2){
289 } else if (refType == 2) {
295290 el = saver.getRelation(memId);
296291 if (el == null) {
297292 saver.deferRelation(memId, rel, role);
307302 saver.addRelation(rel);
308303 }
309304
310 private boolean readTags(Element elem) throws IOException{
305 private boolean readTags(Element elem) {
311306 boolean tagsIncomplete = false;
312 while (bytesToRead > 0){
307 while (bytesToRead > 0) {
313308 readStringPair();
314309 String key = stringPair[0];
315310 String val = stringPair[1];
321316 key = keepTag(key, val);
322317 if (key != null)
323318 elem.addTagFromRawOSM(key, val);
324 else
319 else
325320 tagsIncomplete = true;
326321 }
327322 assert bytesToRead == 0;
328323 return tagsIncomplete;
329324 }
330 /**
331 * Store a new string pair (length check must be performed by caller)
332 */
333 private void storeStringPair(){
325
326 /**
327 * Store a new string pair (length check must be performed by caller).
328 */
329 private void storeStringPair() {
334330 stringTable[0][currStringTablePos] = stringPair[0];
335331 stringTable[1][currStringTablePos] = stringPair[1];
336332 ++currStringTablePos;
339335 }
340336
341337 /**
342 * set stringPair to the values referenced by given string reference
343 * No checking is performed.
338 * set stringPair to the values referenced by given string reference No checking
339 * is performed.
340 *
344341 * @param ref valid values are 1 .. STRING_TABLE_SIZE
345342 */
346 private void setStringRefPair(int ref){
343 private void setStringRefPair(int ref) {
347344 int pos = currStringTablePos - ref;
348 if (pos < 0)
345 if (pos < 0)
349346 pos += STRING_TABLE_SIZE;
350347 stringPair[0] = stringTable[0][pos];
351348 stringPair[1] = stringTable[1][pos];
352349 }
353350
354351 /**
355 * Read version, time stamp and change set and author.
356 * We are not interested in the values, but we have to maintain the string table.
357 * @throws IOException
358 */
359
360 private void readVersionTsAuthor() throws IOException {
361 int version = readUnsignedNum32();
362 if (version != 0){
352 * Read version, time stamp and change set and author. We are not interested in
353 * the values, but we have to maintain the string table.
354 */
355 private void readVersionTsAuthor() {
356 int version = readUnsignedNum32();
357 if (version != 0) {
363358 // version info
364 long ts = readSignedNum64() + lastTs; lastTs = ts;
365 if (ts != 0){
366 long changeSet = readSignedNum32() + lastChangeSet; lastChangeSet = changeSet;
359 long ts = readSignedNum64() + lastTs;
360 lastTs = ts;
361 if (ts != 0) {
362 long changeSet = readSignedNum32() + lastChangeSet;
363 lastChangeSet = changeSet;
367364 readAuthor();
368365 }
369366 }
370367 }
371 /**
372 * Read author .
373 * @throws IOException
374 */
375 private void readAuthor() throws IOException{
368
369 /**
370 * Read author.
371 */
372 private void readAuthor() {
376373 int stringRef = readUnsignedNum32();
377 if (stringRef == 0){
374 if (stringRef == 0) {
378375 long toReadStart = bytesToRead;
379376 long uidNum = readUnsignedNum64();
380377 if (uidNum == 0)
381378 stringPair[0] = "";
382 else{
383 stringPair[0] = Long.toString(uidNum);
384 ioPos++; // skip terminating zero from uid
379 else {
380 stringPair[0] = Long.toUnsignedString(uidNum);
381 ioBufPos++; // skip terminating zero from uid
385382 --bytesToRead;
386383 }
387384 stringPair[1] = readString();
388385 long bytes = toReadStart - bytesToRead;
389386 if (bytes <= MAX_STRING_PAIR_SIZE)
390387 storeStringPair();
391 }
392 else
388 } else {
393389 setStringRefPair(stringRef);
394
395 //System.out.println(pair[0]+ "/" + pair[1]);
396 }
397
398 /**
399 * read object type ("0".."2") concatenated with role (single string)
390 }
391 }
392
393 /**
394 * Read object type ("0".."2") concatenated with role (single string) .
400395 * @return 0..3 for type (3 means unknown)
401396 */
402 private int readRelRef () throws IOException{
397 private int readRelRef () {
403398 int refType = -1;
404399 long toReadStart = bytesToRead;
405400 int stringRef = readUnsignedNum32();
406 if (stringRef == 0){
407 refType = ioBuf[ioPos++] - 0x30;
401 if (stringRef == 0) {
402 refType = ioBuf[ioBufPos++] - 0x30;
408403 --bytesToRead;
409404
410405 if (refType < 0 || refType > 2)
411406 refType = 3;
412407 stringPair[0] = REL_REF_TYPES[refType];
413
408
414409 stringPair[1] = readString();
415410 long bytes = toReadStart - bytesToRead;
416411 if (bytes <= MAX_STRING_PAIR_SIZE)
417412 storeStringPair();
418 }
419 else {
413 } else {
420414 setStringRefPair(stringRef);
421415 char c = stringPair[0].charAt(0);
422 switch (c){
416 switch (c) {
423417 case 'n': refType = 0; break;
424418 case 'w': refType = 1; break;
425419 case 'r': refType = 2; break;
430424 }
431425
432426 /**
433 * read a string pair (see o5m definition)
434 * @throws IOException
435 */
436 private void readStringPair() throws IOException{
427 * Read a string pair (see o5m definition).
428 */
429 private void readStringPair() {
437430 int stringRef = readUnsignedNum32();
438 if (stringRef == 0){
431 if (stringRef == 0) {
439432 long toReadStart = bytesToRead;
440433 int cnt = 0;
441 while (cnt < 2){
434 while (cnt < 2) {
442435 stringPair[cnt++] = readString();
443436 }
444437 long bytes = toReadStart - bytesToRead;
445438 if (bytes <= MAX_STRING_PAIR_SIZE)
446439 storeStringPair();
447 }
448 else
440 } else {
449441 setStringRefPair(stringRef);
442 }
450443 }
451444
452445 /**
453446 * Read a zero-terminated string (see o5m definition).
454447 * @throws IOException
455448 */
456 String readString() throws IOException {
457 int length = 0;
449 private String readString() {
450 int length = 0;
458451 while (true) {
459 final int b = ioBuf[ioPos++];
452 final int b = ioBuf[ioBufPos++];
460453 --bytesToRead;
461454 if (b == 0)
462 return new String(cnvBuffer, 0, length, "UTF-8");
455 return new String(cnvBuffer, 0, length, StandardCharsets.UTF_8);
463456 cnvBuffer[length++] = (byte) b;
464457 }
465458 }
466
467459
468460 /** reset the delta values and string table */
469 private void reset(){
461 private void reset() {
470462 lastNodeId = 0; lastWayId = 0; lastRelId = 0;
471463 lastRef[0] = 0; lastRef[1] = 0;lastRef[2] = 0;
472464 lastTs = 0; lastChangeSet = 0;
476468 }
477469
478470 /**
479 * read and verify o5m header (known values are o5m2 and o5c2)
480 * @throws IOException
471 * Read and verify o5m header (known values are o5m2 and o5c2).
472 * @throws IOException in case of error
481473 */
482474 private void readHeader() throws IOException {
483 if (ioBuf[0] != 'o' || ioBuf[1] != '5' || (ioBuf[2]!='c'&&ioBuf[2]!='m') ||ioBuf[3] != '2' ){
475 if (ioBuf[0] != 'o' || ioBuf[1] != '5' || (ioBuf[2] != 'c' && ioBuf[2] != 'm') || ioBuf[3] != '2') {
484476 throw new IOException("unsupported header");
485477 }
486478 }
487479
488480 /**
489 * read a varying length signed number (see o5m definition)
490 * @return the number
491 * @throws IOException
481 * Read a varying length signed number (see o5m definition).
482 * @return the number as int
492483 */
493484 private int readSignedNum32() {
494 int result;
495 int b = ioBuf[ioPos++];
485 return (int) readSignedNum64();
486 }
487
488 /**
489 * Read a varying length signed number (see o5m definition).
490 * @return the number as long
491 */
492 private long readSignedNum64() {
493 long result;
494 int b = ioBuf[ioBufPos++];
496495 --bytesToRead;
497496 result = b;
498 if ((b & 0x80) == 0){ // just one byte
497 if ((b & 0x80) == 0) { // just one byte
499498 if ((b & 0x01) == 1)
500 return -1-(result>>1);
501 else
502 return result>>1;
499 return -1 - (result >> 1);
500 return result >> 1;
501
503502 }
504503 int sign = b & 0x01;
505 result = (result & 0x7e)>>1;
506 int fac = 0x40;
507 while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
504 result = (result & 0x7e) >> 1;
505 int shift = 6;
506 while (((b = ioBuf[ioBufPos++]) & 0x80) != 0) { // more bytes will follow
508507 --bytesToRead;
509 result += fac * (b & 0x7f) ;
510 fac <<= 7;
508 result += ((long) (b & 0x7f)) << shift;
509 shift += 7;
511510 }
512511 --bytesToRead;
513 result += fac * b;
512 result += ((long) b) << shift;
514513 if (sign == 1) // negative
515 return -1-result;
516 else
517 return result;
518
519 }
520
521 /**
522 * read a varying length signed number (see o5m definition)
523 * @return the number
524 * @throws IOException
525 */
526 private long readSignedNum64() {
527 long result;
528 int b = ioBuf[ioPos++];
529 --bytesToRead;
530 result = b;
531 if ((b & 0x80) == 0){ // just one byte
532 if ((b & 0x01) == 1)
533 return -1-(result>>1);
534 else
535 return result>>1;
536 }
537 int sign = b & 0x01;
538 result = (result & 0x7e)>>1;
539 long fac = 0x40;
540 while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
541 --bytesToRead;
542 result += fac * (b & 0x7f) ;
543 fac <<= 7;
544 }
545 --bytesToRead;
546 result += fac * b;
547 if (sign == 1) // negative
548 return -1-result;
549 else
550 return result;
551
552 }
553
554 /**
555 * read a varying length unsigned number (see o5m definition)
556 * @return a long
557 * @throws IOException
558 */
559 private long readUnsignedNum64FromStream()throws IOException {
514 return -1 - result;
515 return result;
516 }
517
518 /**
519 * Read a varying length unsigned number (see o5m definition).
520 *
521 * @return the number as long
522 * @throws IOException in case of I/O error
523 */
524 private long readUnsignedNum64FromStream() throws IOException {
560525 int b = is.read();
561526 --bytesToRead;
562527 long result = b;
563 if ((b & 0x80) == 0){ // just one byte
528 if ((b & 0x80) == 0) { // just one byte
564529 return result;
565530 }
566531 result &= 0x7f;
567 long fac = 0x80;
568 while (((b = is.read()) & 0x80) != 0){ // more bytes will follow
532 int shift = 7;
533 while (((b = is.read()) & 0x80) != 0) { // more bytes will follow
569534 --bytesToRead;
570 result += fac * (b & 0x7f) ;
571 fac <<= 7;
535 result += ((long) (b & 0x7f)) << shift;
536 shift += 7;
572537 }
573538 --bytesToRead;
574 result += fac * b;
539 result += ((long) b) << shift;
575540 return result;
576541 }
577542
578
579 /**
580 * read a varying length unsigned number (see o5m definition)
581 * @return a long
582 * @throws IOException
583 */
584 private long readUnsignedNum64(){
585 int b = ioBuf[ioPos++];
543 /**
544 * Read a varying length unsigned number (see o5m definition).
545 *
546 * @return the number as long
547 */
548 private long readUnsignedNum64() {
549 int b = ioBuf[ioBufPos++];
586550 --bytesToRead;
587551 long result = b;
588 if ((b & 0x80) == 0){ // just one byte
552 if ((b & 0x80) == 0) { // just one byte
589553 return result;
590554 }
591555 result &= 0x7f;
592 long fac = 0x80;
593 while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
556 int shift = 7;
557 while (((b = ioBuf[ioBufPos++]) & 0x80) != 0) { // more bytes will follow
594558 --bytesToRead;
595 result += fac * (b & 0x7f) ;
596 fac <<= 7;
559 result += ((long) (b & 0x7f)) << shift;
560 shift += 7;
597561 }
598562 --bytesToRead;
599 result += fac * b;
563 result += ((long) b) << shift;
600564 return result;
601565 }
602566
603567 /**
604 * read a varying length unsigned number (see o5m definition)
605 * is similar to the 64 bit version.
606 * @return an int
607 * @throws IOException
608 */
609 private int readUnsignedNum32(){
610 int b = ioBuf[ioPos++];
611 --bytesToRead;
612 int result = b;
613 if ((b & 0x80) == 0){ // just one byte
614 return result;
615 }
616 result &= 0x7f;
617 long fac = 0x80;
618 while (((b = ioBuf[ioPos++]) & 0x80) != 0){ // more bytes will follow
619 --bytesToRead;
620 result += fac * (b & 0x7f) ;
621 fac <<= 7;
622 }
623 --bytesToRead;
624 result += fac * b;
625 return result;
568 * Read a varying length unsigned number (see o5m definition).
569 *
570 * @return the number as int
571 */
572 private int readUnsignedNum32() {
573 return (int) readUnsignedNum64();
626574 }
627575
628576 }
141141 * Retrieve the areas of all precompiled tiles that have to be worked out.
142142 * @return the areas of all tiles
143143 */
144 private List<uk.me.parabola.imgfmt.app.Area> getTiles() {
144 private static List<uk.me.parabola.imgfmt.app.Area> getTiles() {
145145 return getTiles(uk.me.parabola.imgfmt.app.Area.PLANET);
146146 }
147147
148 private List<uk.me.parabola.imgfmt.app.Area> getTiles(
148 private static List<uk.me.parabola.imgfmt.app.Area> getTiles(
149149 uk.me.parabola.imgfmt.app.Area wholeArea) {
150150 int minLat = wholeArea.getMinLat();
151151 int maxLat = wholeArea.getMaxLat();
152152 int minLon = wholeArea.getMinLong();
153153 int maxLon = wholeArea.getMaxLong();
154154
155 List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
155 List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<>();
156156 for (int lon = SeaGenerator.getPrecompTileStart(minLon); lon < maxLon; lon += SeaGenerator.PRECOMP_RASTER) {
157157 for (int lat = SeaGenerator.getPrecompTileStart(minLat); lat < maxLat; lat += SeaGenerator.PRECOMP_RASTER) {
158158 uk.me.parabola.imgfmt.app.Area tile = new uk.me.parabola.imgfmt.app.Area(
179179 setDaemon(true);
180180 }
181181
182 @Override
182183 public void run() {
183184 long count = 0;
184185 do {
197198 * @param geometry a polygon as {@link Geometry} object
198199 * @return the polygon converted to an {@link Area} object.
199200 */
200 private Area convertToArea(Geometry geometry) {
201 private static Area convertToArea(Geometry geometry) {
201202 Coordinate[] c = geometry.getCoordinates();
202203 List<Coord> points = new ArrayList<>(c.length);
203204 for (int n = 0; n < c.length; n++) {
218219 Collection<uk.me.parabola.imgfmt.app.Area> tiles,
219220 CountDownLatch tilesCountdown,
220221 BlockingQueue<Entry<String, List<Way>>> saveQueue) {
221 List<PrecompSeaMerger> mergers = new ArrayList<PrecompSeaMerger>();
222 List<PrecompSeaMerger> mergers = new ArrayList<>();
222223
223224 for (uk.me.parabola.imgfmt.app.Area bounds : tiles) {
224225
235236 }
236237
237238 private void createShapefileAccess() throws IOException {
238 Map<String,URL> map = new HashMap<String, URL>();
239 Map<String,URL> map = new HashMap<>();
239240 map.put("url", shapeFile.toURI().toURL());
240241 DataStore dataStore = DataStoreFinder.getDataStore(map);
241242 String typeName = dataStore.getTypeNames()[0];
275276
276277 // perform several cycles which is necessary to reduce memory
277278 // requirements
278 while (remainingTiles.isEmpty() == false) {
279 while (!remainingTiles.isEmpty()) {
279280
280281 // create a list with all tiles that are processed within this cycle
281 List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<uk.me.parabola.imgfmt.app.Area>();
282 List<uk.me.parabola.imgfmt.app.Area> tiles = new ArrayList<>();
282283 tiles.addAll(remainingTiles.subList(0,
283284 Math.min(tilesPerCycle, remainingTiles.size())));
284285 remainingTiles.subList(0,
401402 String shapeCRS = args[1];
402403 File outputDir = new File(args[2]);
403404
404 if (shapeFile.exists() == false) {
405 if (!shapeFile.exists()) {
405406 throw new FileNotFoundException("File "+shapeFile+" does not exist.");
406407 }
407408
4646 private final BlockingQueue<Entry<String, List<Way>>> saveQueue;
4747 private ExecutorService service;
4848
49 static class MergeData {
50 public final Rectangle2D bounds;
51 public final BlockingQueue<Area> toMerge;
52 public final AtomicBoolean ready = new AtomicBoolean(false);
53 public Path2D.Double tmpLandPath = new Path2D.Double();
54 public Area landArea = new Area();
49 private static class MergeData {
50 final Rectangle2D bounds;
51 final BlockingQueue<Area> toMerge;
52 final AtomicBoolean ready = new AtomicBoolean(false);
53 Path2D.Double tmpLandPath = new Path2D.Double();
54 Area landArea = new Area();
5555 private final String key;
5656
5757 public MergeData(Rectangle2D bounds, String key) {
5858 this.key = key;
5959 this.bounds = bounds;
60 toMerge = new LinkedBlockingQueue<Area>();
60 toMerge = new LinkedBlockingQueue<>();
6161 }
6262
6363 public String getKey() {
9494 return mergeData.bounds;
9595 }
9696
97 private List<Way> convertToWays(Area a, String naturalTag) {
97 private static List<Way> convertToWays(Area a, String naturalTag) {
9898 List<List<Coord>> pointLists = Java2DConverter.areaToShapes(a);
99 List<Way> ways = new ArrayList<Way>(pointLists.size());
99 List<Way> ways = new ArrayList<>(pointLists.size());
100100 for (List<Coord> points : pointLists) {
101101 Way w = new Way(FakeIdGenerator.makeFakeId(), points);
102102 w.addTag("natural", naturalTag);
137137 merge = mergeData.toMerge.poll();
138138 }
139139
140 if (mergeData.ready.get() == false
141 || mergeData.toMerge.isEmpty() == false) {
140 if (!mergeData.ready.get() || !mergeData.toMerge.isEmpty()) {
142141 // repost the merge thread
143142 service.execute(this);
144143 return;
158157 // no land in this tile => create a sea way only
159158 ways.addAll(convertToWays(new Area(mergeData.bounds), "sea"));
160159 } else {
161 Map<Long, Way> landWays = new HashMap<Long, Way>();
160 Map<Long, Way> landWays = new HashMap<>();
162161 List<List<Coord>> landParts = Java2DConverter
163162 .areaToShapes(mergeData.landArea);
164163 for (List<Coord> landPoints : landParts) {
186185 {
187186 // do not calculate the area size => it is not required and adds
188187 // a superfluous tag
188 @Override
189189 protected boolean isAreaSizeCalculated() {
190190 return false;
191191 }
202202 .getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) {
203203
204204 String tag = w.getTag("natural");
205 if ("sea".equals(tag) == false) {
205 if (!"sea".equals(tag)) {
206206 // ignore the land polygons - we already have them in our list
207207 continue;
208208 }
215215
216216 try {
217217 // forward the ways to the queue of the saver thread
218 saveQueue.put(new SimpleEntry<String, List<Way>>(
219 mergeData.getKey(), ways));
218 saveQueue.put(new SimpleEntry<String, List<Way>>(mergeData.getKey(), ways));
220219 } catch (InterruptedException exp) {
221220 exp.printStackTrace();
222221 }
1212
1313 package uk.me.parabola.mkgmap.sea.optional;
1414
15 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
16
1715 import java.io.File;
1816 import java.io.FileOutputStream;
1917 import java.io.IOException;
2018 import java.io.PrintWriter;
19 import java.nio.file.Files;
20 import java.nio.file.StandardCopyOption;
2121 import java.util.HashMap;
2222 import java.util.List;
2323 import java.util.Map;
3131 import java.util.regex.Pattern;
3232 import java.util.zip.GZIPOutputStream;
3333
34 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
35 import uk.me.parabola.imgfmt.ExitException;
3436 import uk.me.parabola.imgfmt.Utils;
3537 import uk.me.parabola.imgfmt.app.Coord;
3638 import uk.me.parabola.mkgmap.reader.osm.SeaGenerator;
5254
5355 private final File outputDir;
5456
55 private final BlockingQueue<Entry<String, List<Way>>> saveQueue = new LinkedBlockingQueue<Entry<String, List<Way>>>();
57 private final BlockingQueue<Entry<String, List<Way>>> saveQueue = new LinkedBlockingQueue<>();
5658
5759 public PrecompSeaSaver(File outputDir, boolean usePbf) {
5860 this.outputDir = outputDir;
5961 finishWait = new CountDownLatch(1);
6062 this.usePbf = usePbf;
61 idMapping = new HashMap<Integer, String>();
62 index = new TreeMap<String, String>();
63 idMapping = new HashMap<>();
64 index = new TreeMap<>();
6365 this.outputDir.mkdirs();
6466 }
6567
6971
7072 private OSMWriter createWriter(int id, String key) {
7173 String[] parts = key.split(Pattern.quote("_"));
72 int lat = Integer.valueOf(parts[0]);
73 int lon = Integer.valueOf(parts[1]);
74 uk.me.parabola.splitter.Area bounds = new uk.me.parabola.splitter.Area(
75 lat, lon, lat + SeaGenerator.PRECOMP_RASTER, lon + SeaGenerator.PRECOMP_RASTER);
74 int lat = Integer.parseInt(parts[0]);
75 int lon = Integer.parseInt(parts[1]);
76 uk.me.parabola.splitter.Area bounds = new uk.me.parabola.splitter.Area(lat, lon,
77 lat + SeaGenerator.PRECOMP_RASTER, lon + SeaGenerator.PRECOMP_RASTER);
7678 OSMWriter writer = (usePbf ? new BinaryMapWriter(bounds, outputDir, nextId, 0)
7779 : new OSMXMLWriter(bounds, outputDir, nextId, 0));
7880 idMapping.put(id, key);
8688 }
8789
8890 public void run() {
89 while (saveQueue.isEmpty() == false || finished.get() == false) {
91 while (!saveQueue.isEmpty() || !finished.get()) {
9092 Entry<String, List<Way>> tileData = null;
9193 try {
9294 tileData = saveQueue.poll(1, TimeUnit.MINUTES);
9496 exp.printStackTrace();
9597 }
9698 if (tileData != null) {
97 int id = ++nextId;
99 int fakeMapid = ++nextId;
98100
99101 if (tileData.getValue().size() == 1) {
100102 // do not write the tile because it consists of one
104106 String naturalTag = singleWay.getTag("natural");
105107 index.put(tileData.getKey(), naturalTag);
106108 } else {
107 String ext = (usePbf ? "pbf" : "gz");
108 index.put(tileData.getKey(), "sea_" + tileData.getKey()
109 + ".osm." + ext);
110
111 OSMWriter writer = createWriter(id, tileData.getKey());
112
113 Long2ObjectOpenHashMap<Long> coordIds = new Long2ObjectOpenHashMap<>();
114 Map<Long,uk.me.parabola.splitter.Way> pbfWays = new TreeMap<Long, uk.me.parabola.splitter.Way>();
115 long maxNodeId = 1;
116 for (Way w : tileData.getValue()) {
117 uk.me.parabola.splitter.Way pbfWay = new uk.me.parabola.splitter.Way();
118 pbfWay.set(w.getId());
119 for (Entry<String, String> tag : w
120 .getTagEntryIterator()) {
121 pbfWay.addTag(tag.getKey(), tag.getValue());
122 }
123 for (Coord c : w.getPoints()) {
124 Node n = new Node();
125 long key = Utils.coord2Long(c);
126 Long nodeId = coordIds.get(key);
127 if (nodeId == null) {
128 nodeId = new Long(maxNodeId++);
129 coordIds.put(key, nodeId);
130 n.set(nodeId,
131 c.getLatDegrees(),
132 c.getLonDegrees());
133 try {
134 writer.write(n);
135 } catch (IOException exp) {
136 exp.printStackTrace();
137 }
138 }
139 pbfWay.addRef(nodeId);
140 }
141 pbfWays.put(pbfWay.getId(),pbfWay);
109 try {
110 writeTile(tileData, fakeMapid);
111 } catch (IOException e) {
112 throw new ExitException(e.getLocalizedMessage());
142113 }
143 for (uk.me.parabola.splitter.Way pbfWay : pbfWays.values()) {
144 try {
145 writer.write(pbfWay);
146 } catch (IOException exp) {
147 exp.printStackTrace();
148 }
149 }
150 writer.finishWrite();
151
152 File tileFile = new File(outputDir, String.format(
153 "%08d.osm." + ext, id));
154 File precompFile = new File(outputDir, "sea_"
155 + tileData.getKey() + ".osm." + ext);
156 if (precompFile.exists()) {
157 precompFile.delete();
158 }
159
160 tileFile.renameTo(precompFile);
161114 }
162115 }
163116 }
164117
165 writeIndex();
118 try {
119 writeIndex();
120 } catch (IOException e) {
121 e.printStackTrace();
122 }
166123
167124 finishWait.countDown();
168125 }
169126
170 private void writeIndex() {
171 try {
172 PrintWriter indexWriter = new PrintWriter(
173 new GZIPOutputStream(new FileOutputStream(
174 new File(outputDir, "index.txt.gz"))));
175
127 /**
128 * Use splitter.jar to write the tile in osm format.
129 * @param tileData the tile data containing the
130 * @param fakeMapid the pseudo-mapid used for this tile
131 * @throws IOException in case of error
132 */
133 private void writeTile(Entry<String, List<Way>> tileData, int fakeMapid) throws IOException {
134 String ext = (usePbf ? "pbf" : "gz");
135 index.put(tileData.getKey(), "sea_" + tileData.getKey() + ".osm." + ext);
136
137 OSMWriter writer = createWriter(fakeMapid, tileData.getKey());
138
139 Long2ObjectOpenHashMap<Long> coordIds = new Long2ObjectOpenHashMap<>();
140 Map<Long,uk.me.parabola.splitter.Way> pbfWays = new TreeMap<>();
141 long maxNodeId = 1;
142 for (Way w : tileData.getValue()) {
143 uk.me.parabola.splitter.Way pbfWay = new uk.me.parabola.splitter.Way();
144 pbfWay.set(w.getId());
145 for (Entry<String, String> tag : w.getTagEntryIterator()) {
146 pbfWay.addTag(tag.getKey(), tag.getValue());
147 }
148 for (Coord c : w.getPoints()) {
149 Node n = new Node();
150 long key = Utils.coord2Long(c);
151 Long nodeId = coordIds.get(key);
152 if (nodeId == null) {
153 nodeId = maxNodeId++;
154 coordIds.put(key, nodeId);
155 n.set(nodeId, c.getLatDegrees(), c.getLonDegrees());
156 writer.write(n);
157 }
158 pbfWay.addRef(nodeId);
159 }
160 pbfWays.put(pbfWay.getId(), pbfWay);
161 }
162 for (uk.me.parabola.splitter.Way pbfWay : pbfWays.values()) {
163 writer.write(pbfWay);
164 }
165
166 writer.finishWrite();
167
168 File tileFile = new File(outputDir, String.format("%08d.osm.%s", fakeMapid, ext));
169 File precompFile = new File(outputDir, "sea_" + tileData.getKey() + ".osm." + ext);
170 Files.move(tileFile.toPath(), precompFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
171 }
172
173 private void writeIndex() throws IOException {
174 try (PrintWriter indexWriter = new PrintWriter(
175 new GZIPOutputStream(new FileOutputStream(new File(outputDir, "index.txt.gz"))))) {
176
176177 for (Entry<String, String> ind : index.entrySet()) {
177 indexWriter.format("%s;%s\n", ind.getKey(), ind.getValue());
178 indexWriter.format("%s;%s", ind.getKey(), ind.getValue()).append('\n');
178179 }
179
180 indexWriter.close();
181 } catch (IOException exp1) {
182 exp1.printStackTrace();
183180 }
184181 }
185182 }
2121 }
2222
2323 public boolean addAll(Collection<Coord> coordList) {
24 boolean oneAdded = false;
24 long oldCount = itemCount;
2525 for (Coord c : coordList) {
26 oneAdded = add(c) | oneAdded;
26 add(c);
2727 }
28 return oneAdded;
28 return itemCount > oldCount;
2929 }
3030
3131 public boolean add(Coord c) {
4242 }
4343
4444 public List<Coord> get(Collection<List<Coord>> polygons) {
45 return root.get(new QuadTreePolygon(polygons), new ArrayList<Coord>(
46 2000));
45 return root.get(new QuadTreePolygon(polygons), new ArrayList<Coord>(2000));
4746 }
4847
4948 public List<Coord> get(List<Coord> polygon) {
5453 if (polygon.size() < 3) {
5554 return Collections.emptyList();
5655 }
57 if (polygon.get(0).equals(polygon.get(polygon.size() - 1)) == false) {
58 return null;
56 if (!polygon.get(0).equals(polygon.get(polygon.size() - 1))) {
57 throw new IllegalArgumentException("polygon is not closed");
5958 }
60 ArrayList<Coord> points = root.get(new QuadTreePolygon(polygon),
61 new ArrayList<Coord>(2000));
59 List<Coord> points = root.get(new QuadTreePolygon(polygon), new ArrayList<Coord>(2000));
6260 if (offset > 0) {
6361 ListIterator<Coord> pointIter = points.listIterator();
6462 while (pointIter.hasNext()) {
7977 return itemCount;
8078 }
8179
82 private static boolean isCloseToPolygon(Coord point, List<Coord> polygon,
83 int gap) {
80 private static boolean isCloseToPolygon(Coord point, List<Coord> polygon, int gap) {
8481 Iterator<Coord> polyIter = polygon.iterator();
8582 Coord c2 = polyIter.next();
8683 while (polyIter.hasNext()) {
00 package uk.me.parabola.util;
11
2 import java.awt.*;
3 import java.util.ArrayList;
2 import java.awt.Rectangle;
43 import java.util.Collection;
54 import java.util.Collections;
65 import java.util.HashSet;
8988 this.points = points;
9089 split();
9190 } else {
92 this.points = new HashSet<Coord>(points);
91 this.points = new HashSet<>(points);
9392 }
9493 }
9594
101100 if (coveredBounds == null) {
102101 coveredBounds = new Area(c.getLatitude(), c.getLongitude(),
103102 c.getLatitude(), c.getLongitude());
104 } else if (coveredBounds.contains(c) == false) {
103 } else if (!coveredBounds.contains(c)) {
105104 coveredBounds = new Area(Math.min(coveredBounds.getMinLat(),
106105 c.getLatitude()), Math.min(coveredBounds.getMinLong(),
107106 c.getLongitude()), Math.max(coveredBounds.getMaxLat(),
125124
126125 public List<Coord> get(Area bbox, List<Coord> resultList) {
127126 if (isLeaf()) {
128 if (bbox.getMinLat() <= coveredBounds.getMinLat()
129 && bbox.getMaxLat() >= coveredBounds.getMaxLat()
130 && bbox.getMinLong() <= coveredBounds.getMinLong()
131 && bbox.getMaxLong() >= coveredBounds.getMaxLong()) {
132
127 if (bbox.contains(coveredBounds)) {
133128 // the bounding box is contained completely in the bbox
134129 // => add all points without further check
135130 resultList.addAll(points);
151146 return resultList;
152147 }
153148
154 public ArrayList<Coord> get(QuadTreePolygon polygon, ArrayList<Coord> resultList) {
149 public List<Coord> get(QuadTreePolygon polygon, List<Coord> resultList) {
155150 if (polygon.getBbox().intersects(getBounds())) {
156151 if (isLeaf()) {
157152 for (Coord c : points) {
175170
176171 }
177172
178 private java.awt.geom.Area createArea(Area bbox) {
179 return new java.awt.geom.Area(new Rectangle(bbox.getMinLong(),
180 bbox.getMinLat(), bbox.getWidth(), bbox.getHeight()));
173 private static java.awt.geom.Area createArea(Area bbox) {
174 return new java.awt.geom.Area(
175 new Rectangle(bbox.getMinLong(), bbox.getMinLat(), bbox.getWidth(), bbox.getHeight()));
181176 }
182177
183178 public boolean isLeaf() {
216211
217212 public void clear() {
218213 this.children = null;
219 points = new HashSet<Coord>();
214 points = new HashSet<>();
220215 coveredBounds = new Area(Integer.MAX_VALUE, Integer.MAX_VALUE,
221216 Integer.MIN_VALUE, Integer.MIN_VALUE);
222217 }