New upstream version 0.0.0+svn4398
Bas Couwenberg
4 years ago
406 | 406 | <include name="styles/default/**"/> |
407 | 407 | <include name="styles/noname/**"/> |
408 | 408 | <include name="chars/ascii/row02.trans"/> |
409 | <include name="typ-files/**"/> | |
409 | 410 | </fileset> |
410 | 411 | </copy> |
411 | 412 |
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 |
43 | 43 | prefix2:it = "del ", "dei ", "della ", "delle ", "di " |
44 | 44 | |
45 | 45 | # 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'" | |
48 | 48 | |
49 | 49 | # spanish |
50 | 50 | prefix1:es = "Avenida", "Calle", "Paseo" |
55 | 55 | # Map three letter ISO country codes to list of used languages for road names. |
56 | 56 | # It is assumed that the style sets mkgmap:country to one of these ISO codes. |
57 | 57 | |
58 | lang:AGO = pt | |
58 | 59 | lang:AND = es, ca |
59 | 60 | lang:ARG = es |
60 | 61 | lang:BOL = es |
62 | lang:BRA = pt | |
61 | 63 | lang:CAN = en, fr |
62 | 64 | lang:CHE = de, fr, it |
63 | 65 | lang:CHL = es |
71 | 73 | lang:ESP = es, gl, eu, ca |
72 | 74 | lang:FRA = fr |
73 | 75 | lang:GBR = en |
76 | lang:GNB = pt | |
74 | 77 | lang:GTM = es |
75 | 78 | lang:GUY = en |
76 | 79 | lang:HND = es |
77 | 80 | lang:MEX = es |
81 | lang:MOZ = pt | |
78 | 82 | lang:NIC = es |
79 | 83 | lang:PAN = es |
80 | 84 | 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] |
94 | 94 | return s.trim(); |
95 | 95 | } |
96 | 96 | |
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 | */ | |
97 | 102 | public static String squashSpaces(String s) { |
98 | 103 | if(s == null || s.isEmpty()) |
99 | 104 | return null; |
13 | 13 | |
14 | 14 | import java.util.LinkedHashMap; |
15 | 15 | import java.util.Map; |
16 | ||
16 | 17 | import uk.me.parabola.mkgmap.reader.osm.Element; |
17 | 18 | import uk.me.parabola.mkgmap.reader.osm.TagDict; |
18 | 19 | |
22 | 23 | * |
23 | 24 | */ |
24 | 25 | public final class AccessTagsAndBits { |
26 | ||
27 | private AccessTagsAndBits() { | |
28 | // private constructor to hide the implicit public one | |
29 | } | |
30 | ||
25 | 31 | // constants for vehicle class |
26 | 32 | public static final byte FOOT = 0x01; |
27 | 33 | public static final byte BIKE = 0x02; |
59 | 65 | for (Map.Entry<String, Byte> entry : ACCESS_TAGS.entrySet()) { |
60 | 66 | ACCESS_TAGS_COMPILED.put(TagDict.getInstance().xlate(entry.getKey()), entry.getValue()); |
61 | 67 | } |
62 | }; | |
68 | } | |
63 | 69 | |
70 | ||
64 | 71 | public static final Map<String, Byte> ROUTE_TAGS; |
65 | 72 | static { |
66 | 73 | ROUTE_TAGS = new LinkedHashMap<>(); |
45 | 45 | |
46 | 46 | private boolean ignoreSharpAngles; |
47 | 47 | 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; | |
52 | 51 | |
53 | 52 | private int mask; |
54 | 53 | private int mrnd; |
75 | 74 | orAccessMask |= arc.getRoadDef().getAccess(); |
76 | 75 | roadDefs.add(arc.getRoadDef()); |
77 | 76 | } |
77 | ||
78 | 78 | public float getInitialHeading() { |
79 | 79 | return initialHeading; |
80 | 80 | } |
81 | ||
81 | 82 | public boolean isOneway() { |
82 | 83 | return isOneWayTrueCount == arcs.size(); |
83 | 84 | } |
85 | ||
84 | 86 | public boolean isForward() { |
85 | 87 | return isForwardTrueCount == arcs.size(); |
86 | 88 | } |
89 | ||
87 | 90 | /** |
88 | 91 | * @return |
89 | 92 | */ |
90 | 93 | public void setInitialHeading(float modIH) { |
91 | 94 | while (modIH > 180) |
92 | modIH -= 360; | |
95 | modIH -= 360; | |
93 | 96 | while (modIH < -180) |
94 | modIH += 360; | |
97 | modIH += 360; | |
95 | 98 | initialHeading = modIH; |
96 | imgHeading = calcEncodedBearing(initialHeading); | |
97 | ||
98 | for (RouteArc arc : arcs){ | |
99 | imgHeading = calcEncodedBearing(initialHeading); | |
100 | ||
101 | for (RouteArc arc : arcs) { | |
99 | 102 | arc.setInitialHeading(modIH); |
100 | 103 | } |
101 | 104 | } |
102 | ||
103 | public String toString(){ | |
105 | ||
106 | public String toString() { | |
104 | 107 | return arcs.get(0).toString(); |
105 | 108 | } |
106 | 109 | } |
107 | 110 | |
108 | 111 | |
109 | private byte calcEncodedBearing (float b) { | |
112 | private byte calcEncodedBearing(float b) { | |
110 | 113 | return (byte) ((RouteArc.directionFromDegrees(b) + mrnd) & mask); |
111 | 114 | } |
112 | ||
115 | ||
113 | 116 | public void config(EnhancedProperties props) { |
114 | 117 | // undocumented option - usually used for debugging only |
115 | 118 | ignoreSharpAngles = props.getProperty("ignore-sharp-angles", false); |
116 | 119 | 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; | |
127 | 120 | } |
128 | 121 | |
129 | 122 | public void check(Map<Integer, RouteNode> nodes) { |
182 | 175 | if (angleAttr.maskedAngle < 0) |
183 | 176 | angleAttr.maskedAngle += 256; |
184 | 177 | |
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 | |
187 | 181 | angleAttr.noAccess = true; |
188 | } else if (ag2.isOneway() && ag2.isForward() == false){ | |
189 | // the "outgoing" arc is a wrong direction oneway | |
190 | angleAttr.noAccess = true; | |
191 | 182 | } |
192 | 183 | |
193 | // if (node.getCoord().distance(test) < 2){ | |
194 | // if (angleAttr.angle == 20){ | |
195 | // angleAttr.maskedMinAngle = 0x30; | |
196 | // continue; | |
197 | // } | |
198 | // } | |
199 | 184 | int sumSpeeds = ag1.maxRoadSpeed + ag2.maxRoadSpeed; |
200 | 185 | if (sumSpeeds <= 1) |
201 | 186 | continue; |
202 | 187 | byte pathAccessMask = (byte) (ag1.orAccessMask & ag2.orAccessMask); |
203 | if (pathAccessMask == 0){ | |
188 | if (pathAccessMask == 0) { | |
204 | 189 | // no common vehicle allowed on both arcs |
205 | 190 | angleAttr.noAccess = true; |
206 | 191 | } |
289 | 274 | int modIH = ag2.imgHeading + usedIncrement; |
290 | 275 | if (modIH > 128) |
291 | 276 | modIH -= 256; |
292 | ag2.setInitialHeading(modIH * 360/256); | |
277 | ag2.setInitialHeading(modIH * 360 / 256f); | |
293 | 278 | int modAngle = Math.round(ag2.getInitialHeading() - ag1.getInitialHeading()); |
294 | 279 | if (modAngle < 0) |
295 | 280 | modAngle += 360; |
308 | 293 | int modIH = ag1.imgHeading - usedIncrement; |
309 | 294 | if (modIH < -128) |
310 | 295 | modIH += 256; |
311 | ag1.setInitialHeading(modIH * 360/256); | |
296 | ag1.setInitialHeading(modIH * 360 / 256f); | |
312 | 297 | int modAngle = Math.round(ag2.getInitialHeading() - ag1.getInitialHeading()); |
313 | 298 | if (modAngle < 0) |
314 | 299 | modAngle += 360; |
328 | 313 | log.info(sharpAngle, "don't know how to enlarge it further"); |
329 | 314 | } |
330 | 315 | } |
331 | return; | |
332 | 316 | } |
333 | 317 | |
334 | 318 | |
379 | 363 | ag.addArc(arc2); |
380 | 364 | } else{ |
381 | 365 | arc1 = arc2; |
382 | if (iter.hasNext() == false) | |
366 | if (!iter.hasNext()) | |
383 | 367 | addArc1 = true; |
384 | 368 | break; |
385 | 369 | } |
36 | 36 | private final NETHeader netHeader = new NETHeader(); |
37 | 37 | |
38 | 38 | // 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<>(); | |
40 | 40 | private List<Integer> offsets; |
41 | 41 | |
42 | 42 | private List<City> cities; |
78 | 78 | */ |
79 | 79 | public List<RoadDef> getRoads() { |
80 | 80 | 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<>(); | |
84 | 84 | int record = 0; |
85 | 85 | for (int off : offsets) { |
86 | 86 | reader.position(start + off); |
181 | 181 | initFlag >>= 5; |
182 | 182 | } |
183 | 183 | node += skip + 1; |
184 | int right = 0, left = 0; | |
184 | int right = 0; | |
185 | int left = 0; | |
185 | 186 | if (initFlag == 0) { |
186 | 187 | right = left = getCityOrZip(reader, size, endPos); |
187 | 188 | } else if ((initFlag & 0x4) != 0) { |
207 | 208 | assert false : "ERRROR overflow"; |
208 | 209 | return 0; |
209 | 210 | } |
210 | int cnum = reader.getNu(size); | |
211 | return cnum; | |
211 | return reader.getNu(size); | |
212 | 212 | } |
213 | 213 | |
214 | 214 | /** |
251 | 251 | private void readLabelOffsets() { |
252 | 252 | ImgFileReader reader = getReader(); |
253 | 253 | offsets = readOffsets(); |
254 | int start = netHeader.getRoadDefinitionsStart(); | |
254 | long start = netHeader.getRoadDefinitionsStart(); | |
255 | 255 | for (int off : offsets) { |
256 | 256 | reader.position(start + off); |
257 | 257 | 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 | |
259 | 258 | offsetLabelMap.put(off, labelOffset & 0x7fffff); |
260 | 259 | } |
261 | 260 | } |
282 | 281 | } |
283 | 282 | |
284 | 283 | // 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; | |
289 | 287 | } |
290 | 288 | |
291 | 289 | public void setCities(List<City> cities) { |
15 | 15 | */ |
16 | 16 | package uk.me.parabola.imgfmt.app.net; |
17 | 17 | |
18 | import uk.me.parabola.imgfmt.ReadFailedException; | |
19 | 18 | import uk.me.parabola.imgfmt.app.CommonHeader; |
20 | 19 | import uk.me.parabola.imgfmt.app.ImgFileReader; |
21 | 20 | import uk.me.parabola.imgfmt.app.ImgFileWriter; |
50 | 49 | * |
51 | 50 | * @param reader The header is read from here. |
52 | 51 | */ |
53 | protected void readFileHeader(ImgFileReader reader) throws ReadFailedException { | |
52 | protected void readFileHeader(ImgFileReader reader) { | |
54 | 53 | roadDefinitions.readSectionInfo(reader, false); |
55 | 54 | roadShift = reader.get1u(); |
56 | 55 |
66 | 66 | // maximal width and height of the bounding box, since |
67 | 67 | // NOD 1 coordinate offsets are at most 16 bit wide. |
68 | 68 | private static final int MAX_SIZE_UNSAFE = 1 << 16; |
69 | // private static final int MAX_SIZE = MAX_SIZE_UNSAFE / 2; | |
70 | 69 | private static final int MAX_SIZE = MAX_SIZE_UNSAFE - 0x800; |
71 | 70 | |
72 | 71 | // Table A has at most 0x100 entries |
73 | 72 | private static final int MAX_TABA_UNSAFE = 0x100; |
74 | // private static final int MAX_TABA = MAX_TABA_UNSAFE / 2; | |
75 | 73 | private static final int MAX_TABA = MAX_TABA_UNSAFE - 0x8; |
76 | 74 | |
77 | 75 | // Table B has at most 0x100 entries |
78 | 76 | private static final int MAX_TABB_UNSAFE = 0x100; |
79 | // private static final int MAX_TABB = MAX_TABB_UNSAFE / 2; | |
80 | 77 | private static final int MAX_TABB = MAX_TABB_UNSAFE - 0x2; |
81 | 78 | |
82 | 79 | // Nodes size is max 0x2000 to cope with signed 14 bit node offsets |
182 | 179 | // The area that actually has nodes. |
183 | 180 | private final BBox bboxActual = new BBox(); |
184 | 181 | |
185 | private List<RouteNode> nodes = new ArrayList<RouteNode>(); | |
182 | private List<RouteNode> nodes = new ArrayList<>(); | |
186 | 183 | private TableA tabA = new TableA(); |
187 | private Map<RouteNode,RouteNode> destNodes = new LinkedHashMap<RouteNode, RouteNode>(); | |
184 | private Map<RouteNode,RouteNode> destNodes = new LinkedHashMap<>(); | |
188 | 185 | |
189 | 186 | /** |
190 | 187 | * Create an unbounded NOD1Part. |
217 | 214 | * external arc at a deeper level of recursion. |
218 | 215 | */ |
219 | 216 | 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; | |
222 | 218 | |
223 | 219 | bboxActual.extend(node.getCoord()); |
224 | 220 | nodes.add(node); |
225 | 221 | for (RouteArc arc : node.arcsIteration()) { |
226 | 222 | tabA.addArc(arc); |
227 | 223 | RouteNode dest = arc.getDest(); |
228 | if (arc.isInternal() == false){ | |
224 | if (!arc.isInternal()) { | |
229 | 225 | 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()) { | |
232 | 227 | arc.setInternal(false); |
233 | 228 | destNodes.put(dest, dest); |
234 | 229 | } |
242 | 237 | if (arc.getSource() != node){ |
243 | 238 | tabA.addArc(arc); |
244 | 239 | RouteNode dest = arc.getDest(); |
245 | if (arc.isInternal() == false) | |
240 | if (!arc.isInternal()) | |
246 | 241 | destNodes.put(dest, dest); |
247 | 242 | else if (bbox != null && !bbox.contains(dest.getCoord()) || dest.getGroup() != node.getGroup()) { |
248 | 243 | arc.setInternal(false); |
267 | 262 | * Subdivide this part recursively until it satisfies the constraints. |
268 | 263 | */ |
269 | 264 | protected List<RouteCenter> subdivideHelper(int depth) { |
270 | List<RouteCenter> centers = new LinkedList<RouteCenter>(); | |
265 | List<RouteCenter> centers = new LinkedList<>(); | |
271 | 266 | |
272 | 267 | if (satisfiesConstraints()) { |
273 | 268 | centers.add(this.toRouteCenter()); |
17 | 17 | |
18 | 18 | import java.util.Arrays; |
19 | 19 | |
20 | import uk.me.parabola.imgfmt.ReadFailedException; | |
21 | 20 | import uk.me.parabola.imgfmt.app.CommonHeader; |
22 | 21 | import uk.me.parabola.imgfmt.app.ImgFileReader; |
23 | 22 | import uk.me.parabola.imgfmt.app.ImgFileWriter; |
60 | 59 | * |
61 | 60 | * @param reader The header is read from here. |
62 | 61 | */ |
63 | protected void readFileHeader(ImgFileReader reader) throws ReadFailedException { | |
62 | protected void readFileHeader(ImgFileReader reader) { | |
64 | 63 | nodes.readSectionInfo(reader, false); |
65 | 64 | flags = reader.get2u(); |
66 | 65 | reader.get2u(); |
91 | 90 | |
92 | 91 | // multiplier shift for road + arc length values, the smaller the shift the higher the precision and NOD size |
93 | 92 | // 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; | |
96 | 95 | protected void writeFileHeader(ImgFileWriter writer) { |
97 | 96 | nodes.setPosition(HEADER_LEN); |
98 | 97 | nodes.writeSectionInfo(writer); |
237 | 237 | /** |
238 | 238 | * The current state of the writing process. |
239 | 239 | */ |
240 | static abstract class State { | |
240 | abstract static class State { | |
241 | 241 | |
242 | 242 | protected final Side left = new Side(true); |
243 | 243 | protected final Side right = new Side(false); |
325 | 325 | } |
326 | 326 | |
327 | 327 | public Iterable<RouteArc> arcsIteration() { |
328 | return () -> arcs.iterator(); | |
328 | return arcs::iterator; | |
329 | 329 | } |
330 | 330 | |
331 | 331 | public List<RouteRestriction> getRestrictions() { |
361 | 361 | } |
362 | 362 | } |
363 | 363 | } |
364 | if (roundaboutArcs.size() > 0) { | |
364 | if (!roundaboutArcs.isEmpty()) { | |
365 | 365 | // get the coordinates of a box bounding the junctions of the roundabout |
366 | 366 | int minRoundaboutLat = coord.getHighPrecLat(); |
367 | 367 | int maxRoundaboutLat = minRoundaboutLat; |
483 | 483 | log.warn("Roundabout " + rd + " overlaps " + fb.getRoadDef() + " at " + coord.toOSMURL()); |
484 | 484 | } |
485 | 485 | } |
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()); | |
490 | 489 | } |
491 | 490 | } |
492 | 491 | } |
556 | 555 | boolean connectsToNonRoundaboutSegment = false; |
557 | 556 | RouteArc nextRoundaboutArc = null; |
558 | 557 | for (RouteArc nba : nb.arcs) { |
559 | if (nba.isDirect() == false) | |
558 | if (!nba.isDirect()) | |
560 | 559 | continue; |
561 | 560 | if (!nba.getRoadDef().isSynthesised()) { |
562 | 561 | if (nba.getRoadDef().isRoundabout()) { |
563 | 562 | if (nba.isForward()) |
564 | 563 | nextRoundaboutArc = nba; |
565 | } else | |
564 | } else { | |
566 | 565 | connectsToNonRoundaboutSegment = true; |
566 | } | |
567 | 567 | } |
568 | 568 | } |
569 | 569 | |
722 | 722 | |
723 | 723 | if (nodes.size() < 3) |
724 | 724 | return; |
725 | // System.out.println(road + " " + nodes.size() + " " + forwardArcs.size()); | |
726 | 725 | ArrayList<RouteArc> newArcs = new ArrayList<>(); |
727 | 726 | IntArrayList arcPositions = forwardArcPositions; |
728 | 727 | List<RouteArc> roadArcs = forwardArcs; |
771 | 770 | newArc.setIndirect(); |
772 | 771 | newArcs.add(newArc); |
773 | 772 | arcToStepNode = newArc; |
774 | stepNode = destNode; | |
775 | 773 | |
776 | 774 | partialArcLength = 0; |
777 | 775 | if (cl >= finalClass) |
778 | 776 | break; |
779 | 777 | } |
780 | 778 | } |
781 | if (newArcs.isEmpty() == false){ | |
782 | int directArcPos = arcPositions.getInt(i); | |
779 | if (!newArcs.isEmpty()) { | |
780 | int directArcPos = arcPositions.getInt(i); | |
783 | 781 | assert nodes.get(i).arcs.get(directArcPos).isDirect(); |
784 | 782 | assert nodes.get(i).arcs.get(directArcPos).getRoadDef() == newArcs.get(0).getRoadDef(); |
785 | 783 | assert nodes.get(i).arcs.get(directArcPos).isForward() == newArcs.get(0).isForward(); |
789 | 787 | int reverseArcPos = reverseArcPositions.get(i-1); // i-1 because first node doesn't have reverse arc |
790 | 788 | if (directArcPos < reverseArcPos) |
791 | 789 | reverseArcPositions.set(i - 1, reverseArcPos + newArcs.size()); |
792 | ||
793 | 790 | } |
794 | 791 | } |
795 | 792 | } |
37 | 37 | * @author Robert Vollmert |
38 | 38 | */ |
39 | 39 | public class RouteRestriction { |
40 | //private static final Logger log = Logger.getLogger(RouteRestriction.class); | |
41 | ||
42 | 40 | // first three bytes of the header -- might specify the type of restriction |
43 | 41 | // and when it is active |
44 | 42 | private static final byte RESTRICTION_TYPE = 0x05; // 0x07 spotted, meaning? |
62 | 60 | private final byte exceptMask; |
63 | 61 | private final byte flags; // meaning of bits 0x01 and 0x10 are not clear |
64 | 62 | |
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; | |
75 | 73 | |
76 | 74 | /** |
77 | 75 | * |
86 | 84 | RouteArc arc = arcs.get(i); |
87 | 85 | assert arc.getDest() != viaNode; |
88 | 86 | } |
89 | byte flags = 0; | |
87 | byte tmpFlags = 0; | |
90 | 88 | |
91 | 89 | if ((mkgmapExceptMask & FOOT) != 0) |
92 | flags |= F_EXCEPT_FOOT; | |
90 | tmpFlags |= F_EXCEPT_FOOT; | |
93 | 91 | if ((mkgmapExceptMask & EMERGENCY) != 0) |
94 | flags |= F_EXCEPT_EMERGENCY; | |
92 | tmpFlags |= F_EXCEPT_EMERGENCY; | |
95 | 93 | |
96 | 94 | exceptMask = translateExceptMask(mkgmapExceptMask); |
97 | 95 | if(exceptMask != 0) |
98 | flags |= F_MORE_EXCEPTIONS; | |
96 | tmpFlags |= F_MORE_EXCEPTIONS; | |
99 | 97 | |
100 | 98 | int numArcs = arcs.size(); |
101 | 99 | assert numArcs < 8; |
102 | flags |= ((numArcs) << 5); | |
103 | this.flags = flags; | |
100 | tmpFlags |= ((numArcs) << 5); | |
101 | this.flags = tmpFlags; | |
104 | 102 | } |
105 | 103 | |
106 | 104 | |
169 | 167 | offsets[pos++] = calcOffset(arc.getDest(), tableOffset); |
170 | 168 | else |
171 | 169 | offsets[pos++] = arc.getIndexB(); |
172 | if (arc.getSource() == viaNode){ | |
170 | if (!viaWritten && arc.getSource() == viaNode) { | |
173 | 171 | // 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; | |
178 | 174 | } |
179 | 175 | } |
180 | 176 |
38 | 38 | private int offset; |
39 | 39 | |
40 | 40 | // arcs for roundabouts |
41 | private final HashMap<RoadDef,Integer> roundaboutArcs = new LinkedHashMap<RoadDef,Integer>(); | |
41 | private final HashMap<RoadDef,Integer> roundaboutArcs = new LinkedHashMap<>(); | |
42 | 42 | // arcs for unpaved ways |
43 | private final HashMap<RoadDef,Integer> unpavedArcs = new LinkedHashMap<RoadDef,Integer>(); | |
43 | private final HashMap<RoadDef,Integer> unpavedArcs = new LinkedHashMap<>(); | |
44 | 44 | // arcs for ferry ways |
45 | private final HashMap<RoadDef,Integer> ferryArcs = new LinkedHashMap<RoadDef,Integer>(); | |
45 | private final HashMap<RoadDef,Integer> ferryArcs = new LinkedHashMap<>(); | |
46 | 46 | // arcs for paved ways |
47 | private final HashMap<RoadDef,Integer> pavedArcs = new LinkedHashMap<RoadDef,Integer>(); | |
47 | private final HashMap<RoadDef,Integer> pavedArcs = new LinkedHashMap<>(); | |
48 | 48 | |
49 | 49 | private static int count; |
50 | 50 |
24 | 24 | */ |
25 | 25 | public class TableB { |
26 | 26 | |
27 | private final ArrayList<RouteNode> nodes = new ArrayList<RouteNode>(); | |
27 | private final ArrayList<RouteNode> nodes = new ArrayList<>(); | |
28 | 28 | |
29 | private final static int ITEM_SIZE = 3; | |
29 | private static final int ITEM_SIZE = 3; | |
30 | 30 | |
31 | 31 | private int offset; |
32 | 32 | |
63 | 63 | public void addNode(RouteNode node) { |
64 | 64 | int i = nodes.indexOf(node); |
65 | 65 | if (i < 0) { |
66 | //i = nodes.size(); | |
67 | 66 | nodes.add(node); |
68 | 67 | } |
69 | 68 | } |
30 | 30 | |
31 | 31 | private final TableA tabA; |
32 | 32 | |
33 | private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>(); | |
33 | private final List<RouteRestriction> restrictions = new ArrayList<>(); | |
34 | 34 | |
35 | 35 | public TableC(TableA tabA) { |
36 | 36 | this.tabA = tabA; |
129 | 129 | * @param resolution The current resolution of the layer. |
130 | 130 | */ |
131 | 131 | 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); | |
138 | 133 | |
139 | 134 | PolygonSubdivSizeSplitterFilter filter = new PolygonSubdivSizeSplitterFilter(); |
140 | 135 | FilterConfig config = new FilterConfig(); |
165 | 160 | private void addLines(MapDataSource src, final int resolution) { |
166 | 161 | // Split lines for size, such that it is appropriate for the |
167 | 162 | // 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); | |
174 | 164 | |
175 | 165 | LineSizeSplitterFilter filter = new LineSizeSplitterFilter(); |
176 | 166 | FilterConfig config = new FilterConfig(); |
308 | 298 | } else { |
309 | 299 | for (MapLine l : this.lines) { |
310 | 300 | // 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) | |
312 | 302 | continue; |
313 | 303 | Area lineBounds = l.getBounds(); |
314 | 304 | int areaIndex = pickArea(mapAreas, l, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp); |
890 | 880 | * @return true if this area contains any data |
891 | 881 | */ |
892 | 882 | 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(); | |
896 | 884 | } |
897 | 885 | |
898 | 886 | @Override |
84 | 84 | param.setFamilyId(family); |
85 | 85 | if (product != -1) |
86 | 86 | param.setProductId(product); |
87 | if (cp != -1) | |
87 | if (cp != -1 && param.getCodePage() == 0) | |
88 | 88 | param.setCodePage(cp); |
89 | 89 | |
90 | 90 | File outFile = new File(filename); |
157 | 157 | private final Tags styleOptionTags; |
158 | 158 | private static final String STYLE_OPTION_PREF = "mkgmap:option:"; |
159 | 159 | private final PrefixSuffixFilter prefixSuffixFilter; |
160 | private final boolean keepBlanks; | |
160 | 161 | |
161 | 162 | private LineAdder lineAdder; |
162 | 163 | |
224 | 225 | // control calculation of extra nodes in NOD3 / NOD4 |
225 | 226 | admLevelNod3 = props.getProperty("add-boundary-nodes-at-admin-boundaries", 2); |
226 | 227 | addBoundaryNodesAtAdminBoundaries = routable && admLevelNod3 > 0; |
228 | keepBlanks = props.containsKey("keep-blanks"); | |
227 | 229 | } |
228 | 230 | |
229 | 231 | /** |
321 | 323 | roads.add(cw); |
322 | 324 | numRoads++; |
323 | 325 | 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); | |
327 | 329 | if (drivingSideIsLeft) |
328 | 330 | numDriveOnLeftRoads++; |
329 | 331 | else |
1262 | 1264 | private static final short phoneTagKey = TagDict.getInstance().xlate("mkgmap:phone"); |
1263 | 1265 | private static final short is_inTagKey = TagDict.getInstance().xlate("mkgmap:is_in"); |
1264 | 1266 | |
1265 | private static void elementSetup(MapElement ms, GType gt, Element element) { | |
1267 | private void elementSetup(MapElement ms, GType gt, Element element) { | |
1266 | 1268 | String[] labels = new String[4]; |
1267 | int noLabels = 0; | |
1269 | int numLabels = 0; | |
1268 | 1270 | for (int labelNo = 0; labelNo < 4; labelNo++) { |
1269 | 1271 | String label1 = element.getTag(labelTagKeys[labelNo]); |
1270 | String label = Label.squashSpaces(label1); | |
1272 | String label = keepBlanks ? label1 : Label.squashSpaces(label1); | |
1271 | 1273 | if (label != null) { |
1272 | labels[noLabels] = label; | |
1273 | noLabels++; | |
1274 | labels[numLabels] = label; | |
1275 | numLabels++; | |
1274 | 1276 | } |
1275 | 1277 | } |
1276 | 1278 |
17 | 17 | import java.util.Locale; |
18 | 18 | import java.util.Map.Entry; |
19 | 19 | |
20 | import uk.me.parabola.imgfmt.app.Coord; | |
21 | 20 | import uk.me.parabola.log.Logger; |
22 | 21 | import uk.me.parabola.mkgmap.reader.osm.Element; |
23 | 22 | import uk.me.parabola.mkgmap.reader.osm.Relation; |
44 | 43 | return nf.format(length); |
45 | 44 | } |
46 | 45 | |
47 | private double calcLength(Element el) { | |
46 | private static double calcLength(Element el) { | |
48 | 47 | 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(); | |
59 | 49 | } else if (el instanceof Relation) { |
60 | 50 | Relation rel = (Relation)el; |
61 | 51 | double length = 0; |
75 | 65 | } |
76 | 66 | } |
77 | 67 | |
68 | @Override | |
78 | 69 | public String getName() { |
79 | 70 | return "length"; |
80 | 71 | } |
81 | 72 | |
73 | @Override | |
82 | 74 | public boolean supportsWay() { |
83 | 75 | return true; |
84 | 76 | } |
85 | 77 | |
78 | @Override | |
86 | 79 | public boolean supportsRelation() { |
87 | 80 | return true; |
88 | 81 | } |
93 | 93 | Collection<Way> loadedCoastlines = loadFile(coastlineFile); |
94 | 94 | log.info(loadedCoastlines.size(), "coastline ways from", coastlineFile, "loaded."); |
95 | 95 | |
96 | ArrayList<Way> ways = SeaGenerator.joinWays(loadedCoastlines); | |
96 | List<Way> ways = SeaGenerator.joinWays(loadedCoastlines); | |
97 | 97 | ListIterator<Way> wayIter = ways.listIterator(); |
98 | ways = null; | |
99 | 98 | while (wayIter.hasNext()) { |
100 | 99 | Way way = wayIter.next(); |
101 | 100 | wayIter.remove(); |
12 | 12 | |
13 | 13 | package uk.me.parabola.mkgmap.reader.osm; |
14 | 14 | |
15 | import java.util.AbstractMap; | |
16 | 15 | import java.util.ArrayDeque; |
17 | 16 | import java.util.ArrayList; |
18 | 17 | import java.util.Arrays; |
19 | 18 | import java.util.Collections; |
20 | 19 | import java.util.HashSet; |
21 | 20 | import java.util.IdentityHashMap; |
22 | import java.util.LinkedHashMap; | |
23 | 21 | import java.util.LinkedHashSet; |
24 | 22 | import java.util.List; |
25 | import java.util.Map; | |
26 | import java.util.Map.Entry; | |
27 | 23 | import java.util.Queue; |
28 | 24 | import java.util.Set; |
29 | 25 | |
30 | 26 | import uk.me.parabola.imgfmt.app.Coord; |
31 | 27 | import uk.me.parabola.log.Logger; |
32 | 28 | 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; | |
34 | 30 | import uk.me.parabola.util.EnhancedProperties; |
35 | 31 | import uk.me.parabola.util.MultiHashMap; |
36 | 32 | |
37 | 33 | /** |
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) | |
42 | 38 | */ |
43 | 39 | public class LinkDestinationHook implements OsmReadingHooks { |
44 | 40 | private static final Logger log = Logger.getLogger(LinkDestinationHook.class); |
48 | 44 | /** Maps which ways can be driven from a given Coord */ |
49 | 45 | private IdentityHashMap<Coord, Set<Way>> adjacentWays = new IdentityHashMap<>(); |
50 | 46 | /** Contains all _link ways that have to be processed */ |
51 | private Map<Long, Way> destinationLinkWays = new LinkedHashMap<>(); | |
47 | private LinkedHashSet<Way> destinationLinkWays = new LinkedHashSet<>(); | |
52 | 48 | |
53 | 49 | private static final Set<String> highwayTypes = new LinkedHashSet<>(Arrays.asList( |
54 | 50 | "motorway", "trunk", "primary", "secondary", "tertiary", |
55 | 51 | "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( | |
57 | 53 | "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link")); |
58 | ||
59 | 54 | |
60 | 55 | /** Map way ids to its restriction relations so that the relations can easily be updated when the way is split. */ |
61 | 56 | private MultiHashMap<Long, RestrictionRelation> restrictions = new MultiHashMap<>(); |
67 | 62 | |
68 | 63 | private boolean processDestinations; |
69 | 64 | 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"); | |
70 | 70 | |
71 | 71 | @Override |
72 | 72 | public boolean init(ElementSaver saver, EnhancedProperties props) { |
80 | 80 | /** |
81 | 81 | * Fills the internal lists |
82 | 82 | */ |
83 | private void retrieveWays() { | |
83 | private void retrieveWaysAndRelations() { | |
84 | 84 | // collect all ways tagged with highway |
85 | 85 | for (Way w : saver.getWays().values()) { |
86 | 86 | if (w.getPoints().size() < 2) { |
87 | 87 | // ignore one-node or zero-node ways |
88 | 88 | continue; |
89 | 89 | } |
90 | String highwayTag = w.getTag("highway"); | |
90 | String highwayTag = w.getTag(TAG_KEY_HIGHWAY); | |
91 | 91 | 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); | |
172 | 93 | } |
173 | 94 | } |
174 | 95 | |
183 | 104 | } |
184 | 105 | } |
185 | 106 | |
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 | ||
187 | 183 | /** |
188 | 184 | * Registers the points of the given way for the internal data structures. |
189 | 185 | * @param w a new way |
190 | 186 | */ |
191 | 187 | private void registerPointsOfWay(Way w) { |
192 | 188 | 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); | |
199 | 190 | } |
200 | 191 | } |
201 | 192 | |
234 | 225 | for (RestrictionRelation rr : new ArrayList<>(wayRestrictions)) { |
235 | 226 | Coord lastPointNewWay = newWay.getFirstPoint(); |
236 | 227 | List<Coord> viaCoords = rr.getViaCoords(); |
237 | for (Coord via : viaCoords){ | |
228 | for (Coord via : viaCoords) { | |
238 | 229 | if (via == lastPointNewWay) { |
239 | 230 | if (rr.isToWay(oldWay.getId())) { |
240 | 231 | log.debug("Change to-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL()); |
242 | 233 | restrictions.removeMapping(oldWay.getId(), rr); |
243 | 234 | restrictions.add(newWay.getId(), rr); |
244 | 235 | |
245 | } else if (rr.isFromWay(oldWay.getId())){ | |
236 | } else if (rr.isFromWay(oldWay.getId())) { | |
246 | 237 | log.debug("Change from-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL()); |
247 | 238 | rr.replaceWay(oldWay.getId(), newWay.getId()); |
248 | 239 | restrictions.removeMapping(oldWay.getId(), rr); |
260 | 251 | * @param maxLength the cut off way is no longer than this value |
261 | 252 | * @return the cut off way or <code>null</code> if cutting not possible |
262 | 253 | */ |
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) { | |
265 | 256 | return null; |
266 | 257 | } |
267 | ||
258 | ||
268 | 259 | if (w.getPoints().size() >= 3) { |
269 | 260 | // try to use existing points - that does not deform the way |
270 | 261 | Coord firstPoint = w.getPoints().get(0); |
287 | 278 | // check and update relations so that they use the new way if appropriate |
288 | 279 | changeWayIdInRelations(w, precedingWay); |
289 | 280 | |
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); | |
292 | 282 | |
293 | 283 | // return the new way |
294 | 284 | return precedingWay; |
295 | 285 | } 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); | |
298 | 287 | } |
299 | 288 | } |
300 | 289 | |
307 | 296 | |
308 | 297 | if (startSegmentLength + segmentLength >= cutLength) { |
309 | 298 | double frac = (cutLength - startSegmentLength) / segmentLength; |
310 | // insert a new point at the minimum distance | |
299 | // insert a new point at the minimum distance | |
311 | 300 | 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; | |
340 | 305 | // 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))); | |
343 | 308 | precedingWay.setFakeId(); |
344 | 309 | precedingWay.copyTags(w); |
345 | 310 | |
353 | 318 | changeWayIdInRelations(w, precedingWay); |
354 | 319 | |
355 | 320 | // return the split way |
356 | return precedingWay; | |
321 | return precedingWay; | |
357 | 322 | } |
358 | 323 | lastC = c; |
359 | 324 | } |
363 | 328 | } |
364 | 329 | |
365 | 330 | /** |
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 | |
387 | 332 | * highway=motorway_junction and one of the tags ref, name or exit_to. |
388 | 333 | * @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> | |
391 | 335 | */ |
392 | 336 | 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 | |
431 | 343 | * a hint on Garmin GPS. This happens if the the option process-exits is set |
432 | 344 | * and the way is connected to an exit node (highway=motorway_junction) |
433 | 345 | * and/or the option process-destination is set and the destination tag is |
449 | 361 | * mkgmap:exit_hint_ref, mkgmap:exit_hint_name and/or mkgmap:exit_hint_exit_to. |
450 | 362 | */ |
451 | 363 | private void processWays() { |
364 | cleanupLinkDestWays(); | |
365 | createExitHints(); | |
366 | createDestinationHints(); | |
367 | } | |
368 | ||
369 | private void cleanupLinkDestWays() { | |
452 | 370 | // remove the adjacent links from the destinationLinkWays list |
453 | 371 | // to avoid duplicate dest_hints |
454 | Queue<Way> linksWithDestination = new ArrayDeque<>(); | |
455 | linksWithDestination.addAll(destinationLinkWays.values()); | |
372 | Queue<Way> linksWithDestination = new ArrayDeque<>(destinationLinkWays); | |
456 | 373 | log.debug(destinationLinkWays.size(),"links with destination tag"); |
457 | 374 | while (!linksWithDestination.isEmpty()) { |
458 | 375 | Way linkWay = linksWithDestination.poll(); |
459 | String destination = linkWay.getTag("mkgmap:dest_hint_work"); | |
376 | String destination = linkWay.getTag(TAG_KEY_DEST_HINT_WORK); | |
460 | 377 | if (log.isDebugEnabled()) |
461 | log.debug("Check way",linkWay.getId(),linkWay.toTagString()); | |
378 | log.debug("Check way", linkWay.getId(), linkWay.toTagString()); | |
462 | 379 | |
463 | 380 | // 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(); | |
468 | 382 | |
469 | 383 | Set<Way> nextWays = adjacentWays.get(c); |
470 | 384 | if (nextWays != null) { |
471 | 385 | for (Way connectedWay : nextWays) { |
472 | String nextDest = connectedWay.getTag("mkgmap:dest_hint_work"); | |
386 | String nextDest = connectedWay.getTag(TAG_KEY_DEST_HINT_WORK); | |
473 | 387 | |
474 | 388 | if (log.isDebugEnabled()) |
475 | 389 | log.debug("Followed by",connectedWay.getId(),connectedWay.toTagString()); |
476 | ||
390 | ||
477 | 391 | // remove the way from destination handling only if both ways are connected with start/end points |
478 | 392 | // 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") | |
482 | 399 | && destination.equals(nextDest)) { |
483 | 400 | // 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()); | |
617 | 404 | } |
618 | 405 | } |
619 | 406 | } |
620 | 407 | } |
621 | 408 | } |
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) { | |
623 | 489 | 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); | |
631 | 518 | } |
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; | |
725 | 570 | } |
726 | 571 | |
727 | 572 | /** |
731 | 576 | adjacentWays = null; |
732 | 577 | wayNodes = null; |
733 | 578 | destinationLinkWays = null; |
734 | linkTypes = null; | |
735 | 579 | saver = null; |
736 | 580 | nameFinder = null; |
737 | 581 | } |
746 | 590 | // referenced in the style file |
747 | 591 | Set<String> tags = new HashSet<>(); |
748 | 592 | tags.add("highway"); |
593 | tags.add("oneway"); | |
749 | 594 | tags.add("destination"); |
750 | 595 | tags.add("destination:lanes"); |
751 | 596 | tags.add("destination:lanes:forward"); |
753 | 598 | tags.add("destination:forward"); |
754 | 599 | tags.add("destination:backward"); |
755 | 600 | tags.add("destination:street"); |
756 | if (processExits){ | |
601 | if (processExits) { | |
757 | 602 | tags.add("exit_to"); |
758 | 603 | tags.add("ref"); |
759 | 604 | } |
764 | 609 | public void end() { |
765 | 610 | log.info("LinkDestinationHook started"); |
766 | 611 | |
767 | retrieveWays(); | |
768 | ||
769 | if (processExits || processDestinations) | |
770 | processWays(); | |
771 | ||
612 | retrieveWaysAndRelations(); | |
613 | processWays(); | |
772 | 614 | cleanup(); |
773 | 615 | |
774 | 616 | log.info("LinkDestinationHook finished"); |
779 | 621 | * @param w the way |
780 | 622 | * @return <code>true</code> way is oneway |
781 | 623 | */ |
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)) { | |
784 | 626 | return true; |
785 | 627 | } |
786 | 628 | |
787 | 629 | // 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); | |
790 | 632 | return onewayTag == null && highwayTag != null |
791 | && (highwayTag.equals("motorway") || highwayTag.equals("motorway_link")); | |
633 | && ("motorway".equals(highwayTag)|| "motorway_link".equals(highwayTag)); | |
792 | 634 | } |
793 | 635 | |
794 | 636 | /** |
796 | 638 | * @param w the way |
797 | 639 | * @return <code>true</code> way is oneway in opposite direction |
798 | 640 | */ |
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)); | |
801 | 643 | } |
802 | 644 | |
803 | 645 | /** |
805 | 647 | * @param w the way |
806 | 648 | * @return <code>true</code> way is not oneway |
807 | 649 | */ |
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 | } | |
834 | 653 | } |
42 | 42 | public class RestrictionRelation extends Relation { |
43 | 43 | private static final Logger log = Logger.getLogger(RestrictionRelation.class); |
44 | 44 | |
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; | |
52 | 52 | 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; | |
57 | 57 | |
58 | 58 | // 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( | |
64 | 64 | "no_right_turn", "no_left_turn", "no_u_turn", "no_straight_on", |
65 | 65 | "only_right_turn", "only_left_turn", "only_straight_on", |
66 | 66 | "no_entry", "no_exit" |
74 | 74 | */ |
75 | 75 | public RestrictionRelation(Relation other) { |
76 | 76 | setId(other.getId()); |
77 | messagePrefix = "Turn restriction " + toBrowseURL(); | |
77 | msgPrefix = "Turn restriction " + toBrowseURL(); | |
78 | 78 | copyTags(other); |
79 | 79 | for (Map.Entry<String, Element> pair : other.getElements()) { |
80 | 80 | addElement(pair.getKey(), pair.getValue()); |
81 | 81 | } |
82 | 82 | } |
83 | ||
83 | ||
84 | 84 | /** |
85 | 85 | * The evaluation should happen after style processing. |
86 | 86 | * Normally this is called from the {@link RelationStyleHook} |
87 | 87 | * Performs also diverse plausibility checks. |
88 | 88 | * @param bbox tile boundary |
89 | 89 | */ |
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"); | |
93 | 93 | fromWayIds.clear(); |
94 | 94 | toWayIds.clear(); |
95 | 95 | viaWayIds.clear(); |
96 | 96 | } |
97 | 97 | evalWasCalled = true; |
98 | if (getTag("type") == null){ | |
98 | if (getTag("type") == null) { | |
99 | 99 | // 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<>(); | |
108 | 108 | final String browseURL = toBrowseURL(); |
109 | 109 | valid = true; |
110 | 110 | // find out what kind of restriction we have and to which vehicles it applies |
111 | 111 | exceptMask = DEFAULT_EXCEPT_MASK; |
112 | String specifc_type = getTag("restriction"); | |
113 | int count_unknown = 0; | |
112 | String specificType = getTag("restriction"); | |
113 | int countUnknown = 0; | |
114 | 114 | Map<String, String> vehicles = getTagsWithPrefix("restriction:", true); |
115 | if (vehicles.isEmpty() == false){ | |
115 | if (!vehicles.isEmpty()) { | |
116 | 116 | exceptMask = (byte) 0xff; |
117 | 117 | Iterator<Entry<String, String>> iter = vehicles.entrySet().iterator(); |
118 | while (iter.hasNext()){ | |
118 | while (iter.hasNext()) { | |
119 | 119 | Map.Entry<String, String> entry = iter.next(); |
120 | 120 | 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"); | |
127 | 127 | valid = false; |
128 | 128 | break; |
129 | 129 | } |
130 | 130 | } |
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"); | |
133 | 133 | valid = false; |
134 | 134 | return; |
135 | 135 | } |
136 | 136 | } |
137 | if (specifc_type == null){ | |
137 | if (specificType == null) { | |
138 | 138 | // 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 = '?'; | |
153 | 153 | 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'; | |
170 | 161 | String type = getTag("type"); |
171 | if (type.startsWith("restriction:")){ | |
162 | if (type.startsWith("restriction:")) { | |
172 | 163 | exceptMask = (byte) 0xff; |
173 | 164 | 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"); | |
176 | 167 | valid = false; |
177 | 168 | return; |
178 | 169 | } |
179 | 170 | } |
180 | 171 | |
181 | 172 | 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 | |
184 | 175 | vehicle = vehicle.trim(); |
185 | 176 | setExceptMask(vehicle, true); |
186 | 177 | } |
187 | 178 | } |
188 | ||
179 | ||
189 | 180 | for (String unsupportedTag : unsupportedTags) { |
190 | 181 | if (getTag(unsupportedTag) != null) { |
191 | log.warn(messagePrefix, "ignoring unsupported '" + unsupportedTag + "' tag"); | |
182 | log.warn(msgPrefix, "ignoring unsupported '" + unsupportedTag + "' tag"); | |
192 | 183 | } |
193 | 184 | } |
194 | 185 | |
199 | 190 | |
200 | 191 | Coord location = null; |
201 | 192 | |
202 | if(viaCoord != null) | |
193 | if (viaCoord != null) | |
203 | 194 | location = viaCoord; |
204 | else if(!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty()) | |
195 | else if (!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty()) | |
205 | 196 | 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()) | |
207 | 198 | 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()) | |
209 | 200 | location = viaWays.get(0).getFirstPoint(); |
210 | 201 | |
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)) { | |
254 | 240 | // 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 | } | |
261 | 245 | |
262 | 246 | if (!valid) |
263 | 247 | 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) { | |
280 | 260 | Way fromWay = fromWays.get(0); |
281 | 261 | 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(); | |
284 | 264 | 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) { | |
288 | 268 | countSame++; |
289 | 269 | viaCoord = fp; |
290 | 270 | } |
291 | 271 | } |
292 | 272 | } |
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"); | |
295 | 276 | 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"); | |
298 | 280 | valid = false; |
299 | 281 | } 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"); | |
303 | 286 | 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"); | |
321 | 306 | valid = false; |
322 | 307 | } |
323 | 308 | if (!valid) |
325 | 310 | for (List<Way> ways : Arrays.asList(fromWays,viaWays,toWays)){ |
326 | 311 | for (Way way : ways){ |
327 | 312 | 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"); | |
329 | 314 | valid = false; |
330 | 315 | } else { |
331 | 316 | if (way.hasIdenticalEndPoints()){ |
332 | 317 | if (ways == toWays && dirIndicator != '?') |
333 | 318 | 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"); | |
335 | 320 | valid = false; |
336 | 321 | } |
337 | 322 | } |
339 | 324 | } |
340 | 325 | if (!valid) |
341 | 326 | return; |
342 | if (viaPoints.isEmpty() == false) | |
327 | if (!viaPoints.isEmpty()) | |
343 | 328 | viaCoord = viaPoints.get(0); |
344 | 329 | |
345 | 330 | if(viaCoord == null && viaWays.isEmpty()) { |
350 | 335 | viaPoints.clear(); |
351 | 336 | Coord v1 = viaCoord; |
352 | 337 | Coord v2 = viaCoord; |
353 | if (viaWays.isEmpty() == false){ | |
338 | if (!viaWays.isEmpty()) { | |
354 | 339 | v1 = viaWays.get(0).getFirstPoint(); |
355 | 340 | v2 = viaWays.get(0).getLastPoint(); |
356 | 341 | } |
357 | 342 | // 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) { | |
359 | 344 | Coord e1 = fromWay.getFirstPoint(); |
360 | 345 | Coord e2 = fromWay.getLastPoint(); |
361 | 346 | if (e1 == v1 || e2 == v1) |
363 | 348 | else if (e1 == v2 || e2 == v2) |
364 | 349 | viaCoord = v2; |
365 | 350 | 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"); | |
367 | 352 | valid = false; |
368 | } | |
353 | } | |
369 | 354 | } |
370 | 355 | if (!valid) |
371 | 356 | return; |
372 | 357 | viaPoints.add(viaCoord); |
373 | 358 | // 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++) { | |
375 | 360 | Way way = viaWays.get(i); |
376 | Coord v = viaPoints.get(viaPoints.size()-1); | |
361 | Coord v = viaPoints.get(viaPoints.size() - 1); | |
377 | 362 | if (way.getFirstPoint() == v) |
378 | 363 | v2 = way.getLastPoint(); |
379 | 364 | else if (way.getLastPoint() == v) |
380 | 365 | v2 = way.getFirstPoint(); |
381 | 366 | 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()); | |
383 | 368 | valid = false; |
384 | 369 | } |
385 | 370 | viaPoints.add(v2); |
387 | 372 | |
388 | 373 | // check if all via points are inside the bounding box |
389 | 374 | int countInside = 0; |
390 | for (Coord via: viaPoints){ | |
391 | if(bbox.contains(via)) | |
375 | for (Coord via : viaPoints) { | |
376 | if (bbox.contains(via)) | |
392 | 377 | ++countInside; |
393 | 378 | } |
394 | 379 | if (countInside == 0) |
395 | 380 | 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 | ||
401 | 386 | if (!valid) |
402 | 387 | return; |
403 | 388 | // 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) { | |
406 | 391 | Coord e1 = toWay.getFirstPoint(); |
407 | 392 | 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"); | |
410 | 395 | 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"); | |
421 | 406 | valid = false; |
422 | 407 | } |
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"); | |
425 | 410 | valid = false; |
426 | 411 | } |
427 | 412 | } |
428 | 413 | } |
429 | if (valid){ | |
430 | for (Way w: fromWays) | |
414 | if (valid) { | |
415 | for (Way w : fromWays) | |
431 | 416 | fromWayIds.add(w.getId()); |
432 | for (Way w: toWays) | |
417 | for (Way w : toWays) | |
433 | 418 | toWayIds.add(w.getId()); |
434 | for (Way w: viaWays){ | |
419 | for (Way w : viaWays) { | |
435 | 420 | w.setViaWay(true); |
436 | 421 | viaWayIds.add(w.getId()); |
437 | 422 | } |
438 | for (Coord v: viaPoints) | |
423 | for (Coord v : viaPoints) | |
439 | 424 | v.setViaNodeOfRestriction(true); |
440 | 425 | } |
441 | 426 | } |
476 | 461 | else if(vehicle.equals("foot")) |
477 | 462 | flag = AccessTagsAndBits.FOOT; |
478 | 463 | 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"); | |
480 | 465 | return false; |
481 | 466 | } |
482 | 467 | |
500 | 485 | if (viaPoints.get(i) == oldP){ |
501 | 486 | viaPoints.set(i, newP); |
502 | 487 | if (log.isDebugEnabled()){ |
503 | log.debug(messagePrefix, restriction, "'via' coord redefined from", | |
488 | log.debug(msgPrefix, restriction, "'via' coord redefined from", | |
504 | 489 | oldP.toOSMURL(), "to", newP.toOSMURL()); |
505 | 490 | } |
506 | 491 | return; |
515 | 500 | for (Coord v: viaPoints){ |
516 | 501 | CoordNode vn = nodeIdMap.get(v); |
517 | 502 | 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"); | |
519 | 504 | return; |
520 | 505 | } |
521 | 506 | viaNodes.add(vn); |
522 | 507 | } |
523 | 508 | |
524 | 509 | 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"); | |
526 | 511 | return; |
527 | 512 | } |
528 | 513 | if(restriction == null){ |
534 | 519 | if(restriction.startsWith("no_")){ |
535 | 520 | for (long fromWayId : fromWayIds){ |
536 | 521 | for (long toWayId : toWayIds){ |
537 | grr = new GeneralRouteRestriction("not", exceptMask, messagePrefix); | |
522 | grr = new GeneralRouteRestriction("not", exceptMask, msgPrefix); | |
538 | 523 | grr.setFromWayId(fromWayId); |
539 | 524 | grr.setToWayId(toWayId); |
540 | 525 | grr.setViaNodes(viaNodes); |
544 | 529 | } |
545 | 530 | } |
546 | 531 | 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"); | |
548 | 533 | } |
549 | 534 | else if(restriction.startsWith("only_")){ |
550 | grr = new GeneralRouteRestriction("only", exceptMask, messagePrefix); | |
535 | grr = new GeneralRouteRestriction("only", exceptMask, msgPrefix); | |
551 | 536 | grr.setFromWayId(fromWayIds.get(0)); |
552 | 537 | grr.setToWayId(toWayIds.get(0)); |
553 | 538 | grr.setViaNodes(viaNodes); |
555 | 540 | grr.setDirIndicator(dirIndicator); |
556 | 541 | int numAdded = collector.addRestriction(grr); |
557 | 542 | 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)); | |
559 | 544 | |
560 | 545 | } |
561 | 546 | else { |
569 | 554 | // relax |
570 | 555 | } |
571 | 556 | |
557 | @Override | |
572 | 558 | public String toString() { |
573 | 559 | String s = "[restriction id = " + getId() + "(" + restriction + ")"; |
574 | 560 | if (!fromWayIds.isEmpty() && !toWayIds.isEmpty() && viaCoord != null ) |
622 | 608 | public boolean replaceWay(long oldWayId, long newWayId) { |
623 | 609 | assert evalWasCalled; |
624 | 610 | 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) { | |
628 | 614 | ways.set(i, newWayId); |
629 | 615 | matched = true; |
630 | 616 | } |
634 | 620 | } |
635 | 621 | |
636 | 622 | /** |
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 | |
640 | 627 | */ |
641 | 628 | public boolean isValidWithoutWay(long wayId) { |
642 | 629 | assert evalWasCalled; |
643 | 630 | if (viaWayIds.contains(wayId)) |
644 | 631 | return false; |
645 | 632 | fromWayIds.remove(wayId); |
646 | if (fromWayIds.isEmpty()) | |
647 | return false; | |
648 | // else it must be a no_entry restriction which still is valid | |
649 | ||
650 | 633 | 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()); | |
655 | 635 | } |
656 | 636 | |
657 | 637 | /** |
661 | 641 | * @param nodeIndices |
662 | 642 | */ |
663 | 643 | 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())) | |
667 | 645 | return; |
668 | 646 | List<Coord> wayViaPoints = new ArrayList<>(); |
669 | 647 | for (int i : nodeIndices) { |
670 | 648 | wayViaPoints.add(way.getPoints().get(i)); |
671 | 649 | } |
672 | List<Coord> prevViaPoints = updatedViaWays.get(way.getId()); | |
673 | if(prevViaPoints != null){ | |
650 | List<Coord> prevViaPoints = updatedViaWays.get(way.getId()); | |
651 | if (prevViaPoints != null) { | |
674 | 652 | // we may get here when the style adds multiple routable ways for the |
675 | 653 | // OSM way |
676 | 654 | if (prevViaPoints.equals(wayViaPoints)) { |
677 | 655 | // already up to date |
678 | 656 | return; |
679 | 657 | } 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"); | |
681 | 659 | } |
682 | 660 | } |
683 | 661 | Coord first = wayViaPoints.get(0); |
684 | Coord last = wayViaPoints.get(wayViaPoints.size()-1); | |
662 | Coord last = wayViaPoints.get(wayViaPoints.size() - 1); | |
685 | 663 | int posFirst = -1; |
686 | 664 | int posLast = -1; |
687 | 665 | for (int i = 0; i < viaPoints.size(); i++) { |
688 | if (first == viaPoints.get(i)) | |
666 | if (first == viaPoints.get(i)) | |
689 | 667 | posFirst = i; |
690 | if (last== viaPoints.get(i)) | |
668 | if (last == viaPoints.get(i)) | |
691 | 669 | 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) { | |
694 | 672 | break; |
695 | 673 | } 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) { | |
712 | 690 | if (posLast - posFirst > 1) |
713 | viaPoints.subList(posFirst+1, posLast).clear(); | |
691 | viaPoints.subList(posFirst + 1, posLast).clear(); | |
714 | 692 | viaPoints.addAll(posFirst + 1, midPoints); |
715 | } | |
716 | else { | |
693 | } else { | |
717 | 694 | if (posFirst - posLast > 1) |
718 | 695 | viaPoints.subList(posLast + 1, posFirst).clear(); |
719 | 696 | Collections.reverse(midPoints); |
721 | 698 | } |
722 | 699 | |
723 | 700 | 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()) | |
725 | 702 | 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"); | |
734 | 711 | valid = false; |
735 | 712 | } |
736 | 713 | updatedViaWays.put(way.getId(), wayViaPoints); |
59 | 59 | public class SeaGenerator implements OsmReadingHooks { |
60 | 60 | private static final Logger log = Logger.getLogger(SeaGenerator.class); |
61 | 61 | |
62 | private String precompSea; | |
62 | 63 | private boolean generateSeaUsingMP = true; |
63 | 64 | private int maxCoastlineGap; |
64 | 65 | private boolean allowSeaSectors = true; |
72 | 73 | |
73 | 74 | private ElementSaver saver; |
74 | 75 | |
75 | private List<Way> shoreline = new ArrayList<Way>(); | |
76 | private boolean roadsReachBoundary; // todo needs setting somehow | |
76 | private List<Way> shoreline = new ArrayList<>(); | |
77 | 77 | private boolean generateSeaBackground = true; |
78 | 78 | |
79 | 79 | private String[] coastlineFilenames; |
80 | 80 | private StyleImpl fbRules; |
81 | 81 | |
82 | 82 | /** 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 | |
91 | 86 | private static final byte SEA_TILE = 's'; |
92 | 87 | private static final byte LAND_TILE = 'l'; |
93 | 88 | private static final byte MIXED_TILE = 'm'; |
94 | 89 | |
95 | private static ThreadLocal<PrecompData> precompIndex = new ThreadLocal<PrecompData>(); | |
90 | private static ThreadLocal<PrecompData> precompIndex = new ThreadLocal<>(); | |
96 | 91 | |
97 | 92 | // useful constants defining the min/max map units of the precompiled sea tiles |
98 | 93 | private static final int MIN_LAT = Utils.toMapUnit(-90.0); |
99 | 94 | private static final int MAX_LAT = Utils.toMapUnit(90.0); |
100 | 95 | private static final int MIN_LON = Utils.toMapUnit(-180.0); |
101 | 96 | 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(";")); | |
103 | 99 | |
104 | 100 | /** |
105 | 101 | * When order-by-decreasing-area we need all bit of sea to be output consistently. |
118 | 114 | * Returns true only if the option to generate the sea is active, so that |
119 | 115 | * the whole thing is omitted if not used. |
120 | 116 | */ |
117 | @Override | |
121 | 118 | public boolean init(ElementSaver saver, EnhancedProperties props) { |
122 | 119 | this.saver = saver; |
123 | 120 | |
124 | String precompSea = props.getProperty("precomp-sea", null); | |
121 | precompSea = props.getProperty("precomp-sea", null); | |
125 | 122 | 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); | |
193 | 124 | } |
194 | 125 | String gs = props.getProperty("generate-sea", null); |
195 | boolean generateSea = gs != null || precompSea != null; | |
196 | 126 | 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); | |
236 | 128 | |
237 | 129 | // init floodblocker and coastlinefile loader only |
238 | 130 | // if precompSea is not set |
239 | 131 | if (precompSea == null) { |
240 | 132 | 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(); | |
247 | 134 | } |
248 | 135 | |
249 | 136 | String coastlineFileOpt = props.getProperty("coastlinefile", null); |
250 | 137 | if (coastlineFileOpt != null) { |
251 | 138 | coastlineFilenames = coastlineFileOpt.split(","); |
252 | CoastlineFileLoader.getCoastlineLoader().setCoastlineFiles( | |
253 | coastlineFilenames); | |
139 | CoastlineFileLoader.getCoastlineLoader().setCoastlineFiles(coastlineFilenames); | |
254 | 140 | CoastlineFileLoader.getCoastlineLoader().loadCoastlines(); |
255 | 141 | log.info("Coastlines loaded"); |
256 | 142 | } else { |
259 | 145 | } |
260 | 146 | } |
261 | 147 | |
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; | |
263 | 269 | } |
264 | 270 | |
265 | 271 | /** |
266 | 272 | * Show valid generate-sea options |
267 | 273 | * @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 + "'"); | |
274 | 279 | |
275 | 280 | System.err.println("Known sea generation options " + (forPrecompSea ? "with" : "without") + " --precomp-sea are:"); |
276 | 281 | System.err.println(" multipolygon use a multipolygon (default)"); |
285 | 290 | System.err.println(" fbgap=NUM points closer to the coastline are ignored for flood blocking (default 40)"); |
286 | 291 | System.err.println(" fbthres=NUM min points contained in a polygon to be flood blocked (default 20)"); |
287 | 292 | System.err.println(" fbratio=NUM min ratio (points/area size) for flood blocking (default 0.5)"); |
288 | ||
289 | } | |
293 | } | |
294 | ||
290 | 295 | /** |
291 | 296 | * Read the index from stream and populate the index grid. |
292 | 297 | * @param fileStream already opened stream |
293 | 298 | */ |
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; | |
297 | 302 | 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)); | |
302 | 304 | String indexLine = null; |
303 | 305 | |
304 | byte[][] indexGrid = new byte[indexWidth+1][indexHeight+1]; | |
306 | byte[][] indexGrid = new byte[indexWidth + 1][indexHeight + 1]; | |
305 | 307 | boolean detectExt = true; |
306 | 308 | String prefix = null; |
307 | 309 | String ext = null; |
311 | 313 | // comment |
312 | 314 | continue; |
313 | 315 | } |
314 | String[] items = csvSplitter.split(indexLine); | |
316 | String[] items = SEMICOLON_SPLITTER.split(indexLine); | |
315 | 317 | 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); | |
318 | 319 | continue; |
319 | 320 | } |
320 | 321 | String precompKey = items[0]; |
321 | 322 | 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); | |
325 | 325 | continue; |
326 | 326 | } |
327 | if (type == MIXED_TILE){ | |
327 | if (type == MIXED_TILE) { | |
328 | 328 | // make sure that all file names are using the same name scheme |
329 | 329 | int prePos = items[1].indexOf(items[0]); |
330 | if (prePos >= 0){ | |
331 | if (detectExt){ | |
330 | if (prePos >= 0) { | |
331 | if (detectExt) { | |
332 | 332 | prefix = items[1].substring(0, prePos); |
333 | ext = items[1].substring(prePos+items[0].length()); | |
333 | ext = items[1].substring(prePos + items[0].length()); | |
334 | 334 | detectExt = false; |
335 | 335 | } 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); | |
342 | 339 | } |
343 | 340 | } |
344 | 341 | } |
353 | 350 | return pi; |
354 | 351 | } |
355 | 352 | |
356 | /** | |
353 | /** | |
357 | 354 | * Retrieves the start value of the precompiled tile. |
358 | 355 | * @param value the value for which the start value is calculated |
359 | 356 | * @return the tile start value |
385 | 382 | } |
386 | 383 | } |
387 | 384 | |
385 | @Override | |
388 | 386 | public Set<String> getUsedTags() { |
389 | HashSet<String> usedTags = new HashSet<String>(); | |
387 | HashSet<String> usedTags = new HashSet<>(); | |
390 | 388 | if (coastlineFilenames == null) { |
391 | 389 | usedTags.add("natural"); |
392 | 390 | } |
393 | 391 | if (floodblocker) { |
394 | 392 | usedTags.addAll(fbRules.getUsedTags()); |
395 | 393 | } |
396 | ||
394 | ||
397 | 395 | if (log.isDebugEnabled()) |
398 | log.debug("Sea generator used tags: "+usedTags); | |
399 | ||
396 | log.debug("Sea generator used tags: " + usedTags); | |
397 | ||
400 | 398 | return usedTags; |
401 | 399 | } |
402 | 400 | |
405 | 403 | * we save it. |
406 | 404 | * @param way The way to test. |
407 | 405 | */ |
406 | @Override | |
408 | 407 | public void onAddWay(Way way) { |
409 | 408 | 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); | |
446 | 438 | } |
447 | 439 | } |
448 | 440 | |
455 | 447 | * @param naturalVal the tag value |
456 | 448 | */ |
457 | 449 | private void splitCoastLineToLineAndShape(Way way, String naturalVal){ |
458 | if (precompSeaDir == null) | |
450 | if (precompSea == null) | |
459 | 451 | return; |
460 | 452 | if (way.hasIdenticalEndPoints()){ |
461 | 453 | // add a copy of this way to be able to draw it as a shape |
479 | 471 | * @return all ways of the tile |
480 | 472 | * @throws FileNotFoundException if the tile could not be found |
481 | 473 | */ |
482 | private Collection<Way> loadPrecompTile(InputStream is, String filename) { | |
474 | private static Collection<Way> loadPrecompTile(InputStream is, String filename) { | |
483 | 475 | OsmPrecompSeaDataSource src = new OsmPrecompSeaDataSource(); |
484 | 476 | EnhancedProperties props = new EnhancedProperties(); |
485 | 477 | props.setProperty("style", "empty"); |
502 | 494 | */ |
503 | 495 | private List<String> getPrecompKeyNames() { |
504 | 496 | Area bounds = saver.getBoundingBox(); |
505 | List<String> precompKeys = new ArrayList<String>(); | |
497 | List<String> precompKeys = new ArrayList<>(); | |
506 | 498 | for (int lat = getPrecompTileStart(bounds.getMinLat()); lat < getPrecompTileEnd(bounds |
507 | 499 | .getMaxLat()); lat += PRECOMP_RASTER) { |
508 | 500 | for (int lon = getPrecompTileStart(bounds.getMinLong()); lon < getPrecompTileEnd(bounds |
518 | 510 | * @param precompKey The key name is compiled of {@code lat+"_"+lon}. |
519 | 511 | * @return either "land" or "sea" or a file name or null |
520 | 512 | */ |
521 | private String getTileName(String precompKey){ | |
513 | private static String getTileName(String precompKey){ | |
522 | 514 | 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]); | |
526 | 518 | int latIndex = (MAX_LAT-lat) / PRECOMP_RASTER; |
527 | 519 | int lonIndex = (MAX_LON-lon) / PRECOMP_RASTER; |
528 | 520 | byte type = pi.precompIndex[lonIndex][latIndex]; |
542 | 534 | * @param indexGrid the previously allocated index grid |
543 | 535 | * @return the byte that was saved in the index grid |
544 | 536 | */ |
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); | |
547 | 539 | byte type = '?'; |
548 | 540 | 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]); | |
551 | 543 | int latIndex = (MAX_LAT - lat) / PRECOMP_RASTER; |
552 | 544 | int lonIndex = (MAX_LON - lon) / PRECOMP_RASTER; |
553 | 545 | |
572 | 564 | |
573 | 565 | // flag if all tiles contains sea or way only |
574 | 566 | // this is important for polygon processing |
575 | boolean distinctTilesOnly = true; | |
567 | boolean distinctTilesOnly; | |
576 | 568 | |
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<>(); | |
581 | 571 | |
582 | 572 | // 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 | } | |
583 | 587 | |
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 | ||
585 | 605 | PrecompData pd = precompIndex.get(); |
586 | if (precompSeaDir.getName().endsWith(".zip")){ | |
587 | zipFile = pd.zipFile; | |
588 | } | |
589 | 606 | |
590 | 607 | for (String precompKey : getPrecompKeyNames()) { |
591 | 608 | String tileName = getTileName(precompKey); |
592 | 609 | |
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."); | |
595 | 612 | continue; |
596 | 613 | } |
597 | 614 | |
598 | 615 | if ("sea".equals(tileName) || "land".equals(tileName)) { |
599 | 616 | // 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 | ||
606 | 623 | if ("sea".equals(tileName)) { |
607 | 624 | seaOnlyAreas = addWithoutCreatingHoles(seaOnlyAreas, new java.awt.geom.Area(r)); |
608 | 625 | } else { |
610 | 627 | } |
611 | 628 | } else { |
612 | 629 | 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); | |
650 | 631 | } |
651 | 632 | } |
652 | 633 | landWays.addAll(areaToWays(landOnlyAreas,"land")); |
653 | 634 | 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 | ||
691 | 677 | /** |
692 | 678 | * Try to merge an area with one or more other areas without creating holes. |
693 | 679 | * If it cannot be merged, it is added to the list. |
695 | 681 | * @param toAdd area to add |
696 | 682 | * @return new list of areas |
697 | 683 | */ |
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, | |
699 | 685 | 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<>(); | |
701 | 687 | java.awt.geom.Area toMerge = new java.awt.geom.Area(toAdd); |
702 | 688 | |
703 | for (java.awt.geom.Area area:areas ){ | |
689 | for (java.awt.geom.Area area : areas) { | |
704 | 690 | java.awt.geom.Area mergedArea = new java.awt.geom.Area(area); |
705 | 691 | mergedArea.add(toMerge); |
706 | if (mergedArea.isSingular() == false){ | |
692 | if (!mergedArea.isSingular()) { | |
707 | 693 | result.add(area); |
708 | 694 | continue; |
709 | 695 | } |
710 | 696 | toMerge = mergedArea; |
711 | 697 | } |
712 | 698 | // 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); | |
714 | 700 | boolean added = false; |
715 | for (int i = 0; i < result.size(); i++){ | |
701 | for (int i = 0; i < result.size(); i++) { | |
716 | 702 | 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); | |
719 | 705 | added = true; |
720 | 706 | break; |
721 | 707 | } |
730 | 716 | * @param type |
731 | 717 | * @return |
732 | 718 | */ |
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<>(); | |
736 | 721 | for (java.awt.geom.Area area : areas) { |
737 | 722 | List<List<Coord>> shapes = Java2DConverter.areaToShapes(area); |
738 | 723 | for (List<Coord> points : shapes) { |
739 | // uk.me.parabola.util.GpxCreator.createGpx(type + "_" + count++, points); | |
740 | 724 | Way w = new Way(FakeIdGenerator.makeFakeId(), points); |
741 | 725 | w.addTag("natural", type); |
742 | 726 | ways.add(w); |
750 | 734 | * @param segments a list of closed and unclosed ways |
751 | 735 | * @return a list of ways completely joined |
752 | 736 | */ |
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<>(); | |
756 | 740 | |
757 | 741 | for (Way w : segments) { |
758 | 742 | if (w.hasIdenticalEndPoints()) { |
759 | 743 | joined.add(w); |
760 | } else if (w.getPoints() != null && w.getPoints().size() > 1){ | |
744 | } else if (w.getPoints().size() > 1){ | |
761 | 745 | beginMap.put(w.getFirstPoint(), w); |
762 | 746 | } 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"); | |
764 | 748 | } |
765 | 749 | } |
766 | 750 | segments.clear(); |
767 | ||
768 | int merged = 1; | |
769 | while (merged > 0) { | |
770 | merged = 0; | |
751 | ||
752 | boolean merged; | |
753 | do { | |
754 | merged = false; | |
771 | 755 | 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; | |
778 | 760 | break; |
779 | 761 | } |
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."); | |
809 | 766 | joined.addAll(beginMap.values()); |
810 | 767 | return joined; |
811 | 768 | } |
812 | 769 | |
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 | ||
813 | 790 | /** |
814 | 791 | * All done, process the saved shoreline information and construct the polygons. |
815 | 792 | */ |
793 | @Override | |
816 | 794 | public void end() { |
817 | 795 | // precompiled sea has highest priority |
818 | 796 | // if it is set do not perform any other algorithm |
819 | if (precompSeaDir != null) { | |
797 | if (precompSea != null && precompIndex.get() != null) { | |
820 | 798 | addPrecompSea(); |
821 | 799 | return; |
822 | 800 | } |
823 | 801 | |
824 | final Area seaBounds = saver.getBoundingBox(); | |
802 | final Area tileBounds = saver.getBoundingBox(); | |
825 | 803 | if (coastlineFilenames == null) { |
826 | 804 | log.info("Shorelines before join", shoreline.size()); |
827 | 805 | shoreline = joinWays(shoreline); |
828 | 806 | } else { |
829 | shoreline.addAll(CoastlineFileLoader.getCoastlineLoader() | |
830 | .getCoastlines(seaBounds)); | |
807 | shoreline.addAll(CoastlineFileLoader.getCoastlineLoader().getCoastlines(tileBounds)); | |
831 | 808 | log.info("Shorelines from extra file:", shoreline.size()); |
832 | 809 | } |
833 | 810 | |
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 | ||
846 | 817 | // 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); | |
858 | 819 | |
859 | 820 | 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 | |
862 | 823 | // polygon so that the tile's background colour will |
863 | 824 | // match the land colour on the tiles that do contain |
864 | 825 | // 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 | |
869 | 827 | // only necessary to create a land polygon |
870 | saver.addWay(land); | |
828 | saver.addWay(createLandWay(tileBounds)); | |
871 | 829 | // nothing more to do |
872 | 830 | return; |
873 | 831 | } |
874 | 832 | |
875 | 833 | long multiId = FakeIdGenerator.makeFakeId(); |
876 | 834 | Relation seaRelation = null; |
877 | if(generateSeaUsingMP) { | |
878 | log.debug("Generate seabounds relation",multiId); | |
835 | if (generateSeaUsingMP) { | |
836 | log.debug("Generate seabounds relation", multiId); | |
879 | 837 | seaRelation = new GeneralRelation(multiId); |
880 | 838 | seaRelation.addTag("type", "multipolygon"); |
881 | 839 | seaRelation.addTag("natural", "sea"); |
882 | 840 | } |
883 | ||
884 | List<Way> islands = new ArrayList<Way>(); | |
841 | ||
842 | ||
843 | List<Way> islands = new ArrayList<>(); | |
885 | 844 | |
886 | 845 | // handle islands (closed shoreline components) first (they're easy) |
887 | handleIslands(shoreline, seaBounds, islands); | |
846 | handleIslands(shoreline, tileBounds, islands); | |
888 | 847 | |
889 | 848 | // the remaining shoreline segments should intersect the boundary |
890 | 849 | // 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); | |
892 | 851 | |
893 | 852 | // 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); | |
901 | 854 | |
902 | 855 | List<Way> antiIslands = removeAntiIslands(seaRelation, islands); |
903 | 856 | if (islands.isEmpty()) { |
911 | 864 | if (generateSeaBackground) { |
912 | 865 | // the background is sea so all anti-islands should be |
913 | 866 | // 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); | |
956 | 870 | |
957 | 871 | log.info("sea: ", sea); |
958 | 872 | saver.addWay(sea); |
959 | if(generateSeaUsingMP) { | |
960 | assert seaRelation != null; | |
873 | if(seaRelation != null) { | |
961 | 874 | seaRelation.addElement("outer", sea); |
962 | 875 | } |
963 | 876 | } else { |
966 | 879 | // generate a land polygon so that the tile's |
967 | 880 | // background colour will match the land colour on the |
968 | 881 | // 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); | |
972 | 883 | saver.addWay(land); |
973 | if (generateSeaUsingMP) { | |
884 | if(seaRelation != null) { | |
974 | 885 | seaRelation.addElement("inner", land); |
975 | 886 | } |
976 | 887 | } |
992 | 903 | shoreline = null; |
993 | 904 | } |
994 | 905 | |
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 | ||
995 | 962 | /** |
996 | 963 | * Clip the shoreline ways to the bounding box of the map. |
997 | 964 | * @param shoreline All the the ways making up the coast. |
998 | 965 | * @param bounds The map bounds. |
999 | 966 | */ |
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<>(); | |
1003 | 970 | for (Way segment : shoreline) { |
1004 | 971 | List<Coord> points = segment.getPoints(); |
1005 | 972 | List<List<Coord>> clipped = LineClipper.clip(bounds, points); |
1024 | 991 | * shore line list and added to the island list. |
1025 | 992 | * |
1026 | 993 | * @param shoreline The collected shore line ways. |
1027 | * @param seaBounds The map boundary. | |
994 | * @param tileBounds The map boundary. | |
1028 | 995 | * @param islands The islands are saved to this list. |
1029 | 996 | */ |
1030 | private void handleIslands(List<Way> shoreline, Area seaBounds, List<Way> islands) { | |
997 | private void handleIslands(List<Way> shoreline, Area tileBounds, List<Way> islands) { | |
1031 | 998 | Iterator<Way> it = shoreline.iterator(); |
1032 | 999 | while (it.hasNext()) { |
1033 | 1000 | Way w = it.next(); |
1038 | 1005 | } |
1039 | 1006 | } |
1040 | 1007 | |
1041 | closeGaps(shoreline, seaBounds); | |
1008 | closeGaps(shoreline, tileBounds); | |
1042 | 1009 | // there may be more islands now |
1043 | 1010 | it = shoreline.iterator(); |
1044 | 1011 | while (it.hasNext()) { |
1051 | 1018 | } |
1052 | 1019 | } |
1053 | 1020 | |
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(); | |
1057 | 1099 | while (!hits.isEmpty()) { |
1058 | long id = FakeIdGenerator.makeFakeId(); | |
1059 | Way w = new Way(id); | |
1100 | Way w = new Way(FakeIdGenerator.makeFakeId()); | |
1060 | 1101 | saver.addWay(w); |
1061 | 1102 | |
1062 | EdgeHit hit = hits.first(); | |
1063 | EdgeHit hFirst = hit; | |
1103 | Double hit = hits.first(); | |
1104 | Double hFirst = hit; | |
1064 | 1105 | do { |
1065 | 1106 | Way segment = hitMap.get(hit); |
1066 | 1107 | log.info("current hit:", hit); |
1067 | EdgeHit hNext; | |
1108 | Double hNext; | |
1068 | 1109 | if (segment != null) { |
1069 | 1110 | // add the segment and get the "ending hit" |
1070 | 1111 | 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()); | |
1074 | 1115 | } else { |
1075 | w.addPointIfNotEqualToLastPoint(hit.getPoint(seaBounds)); | |
1116 | w.addPointIfNotEqualToLastPoint(getPoint(tileBounds, hit)); | |
1076 | 1117 | hNext = hits.higher(hit); |
1077 | 1118 | if (hNext == null) |
1078 | 1119 | 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 | ||
1105 | 1122 | } |
1106 | 1123 | hits.remove(hit); |
1107 | 1124 | 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 | } | |
1111 | 1131 | w.addPoint(w.getFirstPoint()); // close shape |
1132 | } | |
1112 | 1133 | log.info("adding non-island landmass, hits.size()=" + hits.size()); |
1113 | 1134 | 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)); | |
1117 | 1152 | } |
1118 | 1153 | |
1119 | 1154 | /** |
1125 | 1160 | * @return The so-called anti-islands. |
1126 | 1161 | */ |
1127 | 1162 | 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(); | |
1131 | 1167 | 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); | |
1141 | 1169 | } |
1142 | 1170 | |
1143 | 1171 | // determine where the water is |
1147 | 1175 | // make it visible above the land) |
1148 | 1176 | w.addTag("natural", "water"); |
1149 | 1177 | antiIslands.add(w); |
1178 | iter.remove(); | |
1150 | 1179 | saver.addWay(w); |
1151 | 1180 | } else { |
1152 | 1181 | // water on the outside of the poly, it's an island |
1153 | 1182 | w.addTag(landTag[0], landTag[1]); |
1154 | 1183 | saver.addWay(w); |
1155 | if(generateSeaUsingMP) { | |
1184 | if (seaRelation != null) { | |
1156 | 1185 | // create a "inner" way for each island |
1157 | 1186 | seaRelation.addElement("inner", w); |
1158 | } | |
1159 | } | |
1160 | } | |
1161 | ||
1162 | islands.removeAll(antiIslands); | |
1187 | } | |
1188 | } | |
1189 | } | |
1163 | 1190 | 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; | |
1164 | 1207 | } |
1165 | 1208 | |
1166 | 1209 | /** |
1168 | 1211 | * map boundary. |
1169 | 1212 | * |
1170 | 1213 | * @param shoreline The remaining shore line segments. |
1171 | * @param seaBounds The map boundary. | |
1214 | * @param tileBounds The map boundary. | |
1172 | 1215 | * @param seaRelation If we are using a multi-polygon, this is it. Otherwise it will be null. |
1173 | 1216 | * @return A map of the 'hits' where the shore line intersects the boundary. |
1174 | 1217 | */ |
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<>(); | |
1179 | 1223 | 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 { | |
1188 | 1235 | /* |
1189 | 1236 | * This problem occurs usually when the shoreline is cut by osmosis (e.g. country-extracts from geofabrik) |
1190 | 1237 | * There are two possibilities to solve this problem: |
1196 | 1243 | * |
1197 | 1244 | * Usually, the first choice is appropriate if the segment is "nearly" closed. |
1198 | 1245 | */ |
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(); | |
1206 | 1248 | |
1207 | 1249 | if (nearlyClosed) { |
1208 | 1250 | // close the way |
1209 | points.add(pStart); | |
1251 | points.add(pStart); // XXX original way is modified, is that correct? | |
1210 | 1252 | |
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); | |
1221 | 1255 | } |
1222 | 1256 | w.addTag(landTag[0], landTag[1]); |
1223 | 1257 | saver.addWay(w); |
1224 | if(generateSeaUsingMP) | |
1225 | { | |
1258 | if (generateSeaUsingMP) { | |
1226 | 1259 | seaRelation.addElement("inner", w); |
1227 | 1260 | } |
1228 | 1261 | } else if(allowSeaSectors) { |
1229 | 1262 | Way sea; |
1230 | if (seaRelation != null) { | |
1263 | if (generateSeaUsingMP) { | |
1231 | 1264 | sea = new Way(seaRelation.getOriginalId()); |
1232 | 1265 | sea.setFakeId(); |
1266 | } else { | |
1267 | sea = new Way(FakeIdGenerator.makeFakeId()); | |
1233 | 1268 | } |
1234 | else | |
1235 | sea = new Way(FakeIdGenerator.makeFakeId()); | |
1236 | 1269 | sea.getPoints().addAll(points); |
1237 | 1270 | sea.addPoint(new Coord(pEnd.getLatitude(), pStart.getLongitude())); |
1238 | 1271 | sea.addPoint(pStart); |
1245 | 1278 | } else if (extendSeaSectors) { |
1246 | 1279 | // create additional points at next border to prevent triangles from point 2 |
1247 | 1280 | 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)); | |
1250 | 1283 | } |
1251 | 1284 | 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)); | |
1254 | 1287 | } |
1255 | 1288 | log.debug("hits (second try): ", hStart, hEnd); |
1256 | 1289 | hitMap.put(hStart, w); |
1259 | 1292 | // show the coastline even though we can't produce |
1260 | 1293 | // a polygon for the land |
1261 | 1294 | w.addTag("natural", "coastline"); |
1262 | if (w.hasIdenticalEndPoints() == false){ | |
1295 | if (!w.hasIdenticalEndPoints()) { | |
1263 | 1296 | log.error("adding sea shape that is not really closed"); |
1264 | 1297 | } |
1265 | 1298 | saver.addWay(w); |
1266 | 1299 | } |
1267 | } else { | |
1268 | log.debug("hits: ", hStart, hEnd); | |
1269 | hitMap.put(hStart, w); | |
1270 | hitMap.put(hEnd, null); | |
1271 | 1300 | } |
1272 | 1301 | } |
1273 | 1302 | return hitMap; |
1274 | 1303 | } |
1275 | 1304 | |
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; | |
1358 | 1379 | } |
1359 | 1380 | |
1360 | 1381 | /** |
1361 | 1382 | * Find the nearest edge for supplied Coord p. |
1362 | 1383 | */ |
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)); | |
1373 | 1393 | // shortest distance to border (init with distance to southern border) |
1374 | int min = lat - minLat; | |
1394 | int min = latHp - minLatHp; | |
1375 | 1395 | // 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 | |
1379 | 1399 | // 3 = western edge of Area a |
1380 | 1400 | int i = 0; |
1381 | 1401 | // normalized position at border (0..1) |
1382 | double l = ((double)(lon - minLong))/(maxLong-minLong); | |
1402 | double t = ((double) (lonHp - minLongHp)) / (maxLongHp - minLongHp); | |
1383 | 1403 | // now compare distance to eastern border with already known distance |
1384 | if (maxLong - lon < min) { | |
1404 | if (maxLongHp - lonHp < min) { | |
1385 | 1405 | // update data if distance is shorter |
1386 | min = maxLong - lon; | |
1406 | min = maxLongHp - lonHp; | |
1387 | 1407 | i = 1; |
1388 | l = ((double)(lat - minLat))/(maxLat-minLat); | |
1408 | t = ((double) (latHp - minLatHp)) / (maxLatHp - minLatHp); | |
1389 | 1409 | } |
1390 | 1410 | // same for northern border |
1391 | if (maxLat - lat < min) { | |
1392 | min = maxLat - lat; | |
1411 | if (maxLatHp - latHp < min) { | |
1412 | min = maxLatHp - latHp; | |
1393 | 1413 | i = 2; |
1394 | l = ((double)(maxLong - lon))/(maxLong-minLong); | |
1414 | t = ((double) (maxLongHp - lonHp)) / (maxLongHp - minLongHp); | |
1395 | 1415 | } |
1396 | 1416 | // same for western border |
1397 | if (lon - minLong < min) { | |
1417 | if (lonHp - minLongHp < min) { | |
1398 | 1418 | i = 3; |
1399 | l = ((double)(maxLat - lat))/(maxLat-minLat); | |
1419 | t = ((double) (maxLatHp - latHp)) / (maxLatHp - minLatHp); | |
1400 | 1420 | } |
1401 | 1421 | // 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; | |
1463 | 1423 | } |
1464 | 1424 | |
1465 | 1425 | /** |
1466 | 1426 | * Helper class for threadlocal vars |
1467 | * | |
1468 | * | |
1469 | */ | |
1470 | class PrecompData { | |
1427 | */ | |
1428 | private static class PrecompData { | |
1471 | 1429 | /** |
1472 | 1430 | * The index is a grid [lon][lat]. Each element defines the content of one precompiled |
1473 | 1431 | * sea tile which are {@link #SEA_TYPE}, {@link #LAND_TYPE}, or {@link #MIXED_TYPE}, or 0 for unknown |
1477 | 1435 | private String precompSeaPrefix; |
1478 | 1436 | private String precompZipFileInternalPath; |
1479 | 1437 | private ZipFile zipFile; |
1480 | ||
1481 | } | |
1438 | private File dirFile; | |
1439 | } | |
1440 | ||
1482 | 1441 | } |
30 | 30 | * @author WanMil |
31 | 31 | */ |
32 | 32 | 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); | |
35 | 34 | |
36 | 35 | private final QuadTree landCoords; |
37 | 36 | private final QuadTree seaCoords; |
44 | 43 | private final DecimalFormat format = new DecimalFormat("0.0000"); |
45 | 44 | private Rule floodBlockerRules; |
46 | 45 | |
47 | private final String[] landTag = {"natural","land"}; | |
46 | private final String[] landTag = { "natural", "land" }; | |
48 | 47 | |
49 | 48 | public SeaPolygonRelation(Relation other, Map<Long, Way> wayMap, Area bbox) { |
50 | 49 | super(other, wayMap, bbox); |
60 | 59 | return false; |
61 | 60 | } |
62 | 61 | |
62 | @Override | |
63 | 63 | protected void postProcessing() { |
64 | 64 | if (isFloodBlocker()) { |
65 | 65 | removeFloodedAreas(); |
107 | 107 | // create a copy of all resulting ways - the tile way map contains only |
108 | 108 | // polygons from |
109 | 109 | // 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()); | |
114 | 113 | |
115 | 114 | String baseName = GpxCreator.getGpxBaseName(); |
116 | 115 | if (debug) { |
127 | 126 | String polyType = (sea ? "sea" : "land"); |
128 | 127 | String otherType = (sea ? "land" : "sea"); |
129 | 128 | |
130 | List<Coord> minusCoords = badCoords.get(p.getPoints(), | |
131 | getFloodBlockerGap()); | |
129 | List<Coord> minusCoords = badCoords.get(p.getPoints(), getFloodBlockerGap()); | |
132 | 130 | List<Coord> positiveCoords = goodCoords.get(p.getPoints()); |
133 | 131 | |
134 | 132 | log.info(polyType,"polygon", p.getId(), "contains", |
135 | 133 | minusCoords.size(), otherType,"coords and", |
136 | 134 | positiveCoords.size(), polyType,"coords."); |
137 | ||
138 | if (minusCoords.size() > 0) { | |
135 | ||
136 | if (!minusCoords.isEmpty()) { | |
139 | 137 | double area = MultiPolygonRelation.calcAreaSize(p.getPoints()); |
140 | 138 | double ratio = ((minusCoords.size() - positiveCoords.size()) * 100000.0d / area); |
141 | 139 | String areaFMT = format.format(area); |
157 | 155 | + positiveCoords.size() + "_" + ratioFMT, |
158 | 156 | null, minusCoords); |
159 | 157 | |
160 | if (positiveCoords.isEmpty() == false) { | |
158 | if (!positiveCoords.isEmpty()) { | |
161 | 159 | GpxCreator.createGpx( |
162 | 160 | baseName + p.getId() + "_pro_" |
163 | 161 | + minusCoords.size() + "_" |
177 | 175 | p.deleteTag(landTag[0]); |
178 | 176 | p.addTag("natural", "sea"); |
179 | 177 | } |
180 | // getMpPolygons().remove(p.getId()); | |
181 | 178 | } else { |
182 | 179 | log.info("Polygon",p.getId(), "is not blocked"); |
183 | 180 | } |
223 | 220 | this.floodBlockerThreshold = floodBlockerThreshold; |
224 | 221 | } |
225 | 222 | |
226 | public boolean isDebug() { | |
227 | return debug; | |
228 | } | |
229 | ||
230 | 223 | public void setDebug(boolean debug) { |
231 | 224 | this.debug = debug; |
232 | 225 | } |
15 | 15 | */ |
16 | 16 | package uk.me.parabola.mkgmap.reader.osm; |
17 | 17 | |
18 | import java.awt.*; | |
18 | import java.awt.Polygon; | |
19 | 19 | import java.util.ArrayList; |
20 | 20 | import java.util.Collections; |
21 | 21 | import java.util.List; |
99 | 99 | } |
100 | 100 | |
101 | 101 | public void addPointIfNotEqualToLastPoint(Coord co) { |
102 | if(points.isEmpty() || !co.equals(points.get(points.size() - 1))) | |
102 | if(points.isEmpty() || !co.highPrecEquals(getLastPoint())) | |
103 | 103 | points.add(co); |
104 | 104 | } |
105 | 105 | |
281 | 281 | this.fullArea = fullArea; |
282 | 282 | } |
283 | 283 | |
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())) { | |
286 | 286 | this.fullArea = ShapeMergeFilter.calcAreaSizeTestVal(points); |
287 | 287 | } |
288 | 288 | return this.fullArea; |
289 | 289 | } |
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 | } | |
290 | 303 | } |
15 | 15 | import java.io.ByteArrayInputStream; |
16 | 16 | import java.io.IOException; |
17 | 17 | import java.io.InputStream; |
18 | import java.nio.charset.StandardCharsets; | |
18 | 19 | |
19 | 20 | import uk.me.parabola.imgfmt.app.Coord; |
20 | 21 | import uk.me.parabola.mkgmap.reader.osm.Element; |
48 | 49 | private static final int STRING_TABLE_SIZE = 15000; |
49 | 50 | private static final int MAX_STRING_PAIR_SIZE = 250 + 2; |
50 | 51 | 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 | |
52 | 53 | |
53 | 54 | private BufferedInputStream fis; |
54 | 55 | private InputStream is; |
55 | private ByteArrayInputStream bis; | |
56 | 56 | |
57 | 57 | // buffer for byte -> String conversions |
58 | 58 | private byte[] cnvBuffer; |
59 | 59 | |
60 | 60 | private byte[] ioBuf; |
61 | private int ioPos; | |
61 | private int ioBufPos; | |
62 | 62 | // the o5m string table |
63 | 63 | private String[][] stringTable; |
64 | 64 | private String[] stringPair; |
66 | 66 | // a counter that must be maintained by all routines that read data from the stream |
67 | 67 | private int bytesToRead; |
68 | 68 | // total number of bytes read from stream |
69 | long countBytes; | |
69 | private long countBytes; | |
70 | 70 | |
71 | 71 | // for delta calculations |
72 | 72 | private long lastNodeId; |
73 | 73 | private long lastWayId; |
74 | 74 | private long lastRelId; |
75 | private long lastRef[]; | |
75 | private long[] lastRef; | |
76 | 76 | private long lastTs; |
77 | 77 | private long lastChangeSet; |
78 | private int lastLon,lastLat; | |
78 | private int lastLon; | |
79 | private int lastLat; | |
79 | 80 | |
80 | 81 | /** |
81 | 82 | * 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). | |
85 | 83 | */ |
86 | 84 | public O5mBinHandler() { |
85 | // nothing to do | |
87 | 86 | } |
88 | 87 | |
89 | 88 | @Override |
92 | 91 | } |
93 | 92 | |
94 | 93 | /** |
95 | * parse the input stream | |
94 | * Parse the input stream. | |
96 | 95 | */ |
97 | 96 | @Override |
98 | public void parse(InputStream stream){ | |
97 | public void parse(InputStream stream) { | |
99 | 98 | this.fis = new BufferedInputStream(stream); |
100 | 99 | is = fis; |
101 | 100 | this.cnvBuffer = new byte[4000]; // OSM data should not contain string pairs with length > 512 |
102 | 101 | this.ioBuf = new byte[8192]; |
103 | this.ioPos = 0; | |
102 | this.ioBufPos = 0; | |
104 | 103 | this.stringPair = new String[2]; |
105 | 104 | this.lastRef = new long[3]; |
106 | 105 | reset(); |
107 | 106 | try { |
108 | 107 | int start = is.read(); |
109 | 108 | ++countBytes; |
110 | if (start != RESET_FLAG) | |
109 | if (start != RESET_FLAG) | |
111 | 110 | throw new IOException("wrong header byte " + start); |
112 | 111 | readFile(); |
113 | 112 | } catch (IOException e) { |
113 | System.err.println("exception after " + countBytes + " bytes"); | |
114 | 114 | e.printStackTrace(); |
115 | 115 | } |
116 | 116 | } |
117 | 117 | |
118 | 118 | private void readFile() throws IOException{ |
119 | 119 | boolean done = false; |
120 | while(!done){ | |
120 | while(!done) { | |
121 | 121 | is = fis; |
122 | 122 | long size = 0; |
123 | 123 | int fileType = is.read(); |
124 | 124 | ++countBytes; |
125 | if (fileType >= 0 && fileType < 0xf0){ | |
125 | if (fileType >= 0 && fileType < 0xf0) { | |
126 | 126 | bytesToRead = 0; |
127 | 127 | size = readUnsignedNum64FromStream(); |
128 | countBytes += size - bytesToRead; // bytesToRead is negative | |
129 | bytesToRead = (int)size; | |
128 | countBytes += size - bytesToRead; // bytesToRead is negative | |
129 | bytesToRead = (int) size; | |
130 | 130 | |
131 | switch(fileType){ | |
131 | switch (fileType) { | |
132 | 132 | case NODE_DATASET: |
133 | 133 | case WAY_DATASET: |
134 | 134 | case REL_DATASET: |
135 | 135 | case BBOX_DATASET: |
136 | 136 | case TIMESTAMP_DATASET: |
137 | 137 | 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]; | |
140 | 140 | } |
141 | int bytesRead = 0; | |
141 | int bytesRead = 0; | |
142 | 142 | int neededBytes = bytesToRead; |
143 | while (neededBytes > 0){ | |
143 | while (neededBytes > 0) { | |
144 | 144 | bytesRead += is.read(ioBuf, bytesRead, neededBytes); |
145 | 145 | 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; | |
151 | 150 | default: |
152 | 151 | } |
153 | 152 | } |
161 | 160 | else if (fileType == EOD_FLAG) done = true; |
162 | 161 | else if (fileType == RESET_FLAG) reset(); |
163 | 162 | 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(); | |
174 | 173 | } |
175 | 174 | |
176 | 175 | /** |
178 | 177 | * @param bytes |
179 | 178 | * @throws IOException |
180 | 179 | */ |
181 | private void skip(long bytes)throws IOException{ | |
180 | private void skip(long bytes) throws IOException { | |
182 | 181 | long toSkip = bytes; |
183 | while (toSkip > 0) | |
182 | while (toSkip > 0) { | |
184 | 183 | 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. | |
190 | 189 | */ |
191 | 190 | 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 | ||
196 | 196 | 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() { | |
205 | 204 | lastNodeId += readSignedNum64(); |
206 | 205 | if (bytesToRead == 0) |
207 | 206 | return; // only nodeId: this is a delete action, we ignore it |
211 | 210 | int lon = readSignedNum32() + lastLon; lastLon = lon; |
212 | 211 | int lat = readSignedNum32() + lastLat; lastLat = lat; |
213 | 212 | |
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); | |
216 | 215 | assert flat >= -90.0 && flat <= 90.0; |
217 | 216 | assert flon >= -180.0 && flon <= 180.0; |
218 | 217 | |
219 | 218 | Coord co = new Coord(flat, flon); |
220 | 219 | 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); | |
223 | 222 | readTags(node); |
224 | if (node.getTagCount() > 0){ | |
223 | if (node.getTagCount() > 0) { | |
225 | 224 | // If there are tags, then we save a proper node for it. |
226 | 225 | saver.addNode(node); |
227 | 226 | hooks.onAddNode(node); |
230 | 229 | } |
231 | 230 | |
232 | 231 | /** |
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() { | |
237 | 235 | lastWayId += readSignedNum64(); |
238 | 236 | 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 | |
240 | 238 | |
241 | 239 | readVersionTsAuthor(); |
242 | 240 | 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 | |
244 | 242 | Way way = startWay(lastWayId); |
245 | 243 | long refSize = readUnsignedNum32(); |
246 | 244 | long stop = bytesToRead - refSize; |
247 | ||
248 | while(bytesToRead > stop){ | |
245 | ||
246 | while (bytesToRead > stop) { | |
249 | 247 | lastRef[0] += readSignedNum64(); |
250 | 248 | addCoordToWay(way, lastRef[0]); |
251 | 249 | } |
252 | ||
250 | ||
253 | 251 | readTags(way); |
254 | 252 | endWay(way); |
255 | 253 | } |
256 | 254 | |
257 | 255 | /** |
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() { | |
262 | 259 | lastRelId += readSignedNum64(); |
263 | 260 | if (bytesToRead == 0) |
264 | 261 | return; // only relId: this is a delete action, we ignore it |
269 | 266 | GeneralRelation rel = new GeneralRelation(lastRelId); |
270 | 267 | long refSize = readUnsignedNum32(); |
271 | 268 | long stop = bytesToRead - refSize; |
272 | while(bytesToRead > stop){ | |
269 | while (bytesToRead > stop) { | |
273 | 270 | Element el = null; |
274 | 271 | long deltaRef = readSignedNum64(); |
275 | 272 | int refType = readRelRef(); |
276 | 273 | String role = stringPair[1]; |
277 | 274 | lastRef[refType] += deltaRef; |
278 | 275 | long memId = lastRef[refType]; |
279 | if (refType == 0){ | |
276 | if (refType == 0) { | |
280 | 277 | el = saver.getNode(memId); |
281 | if(el == null) { | |
278 | if (el == null) { | |
282 | 279 | // we didn't make a node for this point earlier, |
283 | 280 | // do it now (if it exists) |
284 | 281 | Coord co = saver.getCoord(memId); |
285 | if(co != null) { | |
282 | if (co != null) { | |
286 | 283 | el = new Node(memId, co); |
287 | saver.addNode((Node)el); | |
284 | saver.addNode((Node) el); | |
288 | 285 | } |
289 | 286 | } |
290 | } | |
291 | else if (refType == 1){ | |
287 | } else if (refType == 1) { | |
292 | 288 | el = saver.getWay(memId); |
293 | } | |
294 | else if (refType == 2){ | |
289 | } else if (refType == 2) { | |
295 | 290 | el = saver.getRelation(memId); |
296 | 291 | if (el == null) { |
297 | 292 | saver.deferRelation(memId, rel, role); |
307 | 302 | saver.addRelation(rel); |
308 | 303 | } |
309 | 304 | |
310 | private boolean readTags(Element elem) throws IOException{ | |
305 | private boolean readTags(Element elem) { | |
311 | 306 | boolean tagsIncomplete = false; |
312 | while (bytesToRead > 0){ | |
307 | while (bytesToRead > 0) { | |
313 | 308 | readStringPair(); |
314 | 309 | String key = stringPair[0]; |
315 | 310 | String val = stringPair[1]; |
321 | 316 | key = keepTag(key, val); |
322 | 317 | if (key != null) |
323 | 318 | elem.addTagFromRawOSM(key, val); |
324 | else | |
319 | else | |
325 | 320 | tagsIncomplete = true; |
326 | 321 | } |
327 | 322 | assert bytesToRead == 0; |
328 | 323 | return tagsIncomplete; |
329 | 324 | } |
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() { | |
334 | 330 | stringTable[0][currStringTablePos] = stringPair[0]; |
335 | 331 | stringTable[1][currStringTablePos] = stringPair[1]; |
336 | 332 | ++currStringTablePos; |
339 | 335 | } |
340 | 336 | |
341 | 337 | /** |
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 | * | |
344 | 341 | * @param ref valid values are 1 .. STRING_TABLE_SIZE |
345 | 342 | */ |
346 | private void setStringRefPair(int ref){ | |
343 | private void setStringRefPair(int ref) { | |
347 | 344 | int pos = currStringTablePos - ref; |
348 | if (pos < 0) | |
345 | if (pos < 0) | |
349 | 346 | pos += STRING_TABLE_SIZE; |
350 | 347 | stringPair[0] = stringTable[0][pos]; |
351 | 348 | stringPair[1] = stringTable[1][pos]; |
352 | 349 | } |
353 | 350 | |
354 | 351 | /** |
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) { | |
363 | 358 | // 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; | |
367 | 364 | readAuthor(); |
368 | 365 | } |
369 | 366 | } |
370 | 367 | } |
371 | /** | |
372 | * Read author . | |
373 | * @throws IOException | |
374 | */ | |
375 | private void readAuthor() throws IOException{ | |
368 | ||
369 | /** | |
370 | * Read author. | |
371 | */ | |
372 | private void readAuthor() { | |
376 | 373 | int stringRef = readUnsignedNum32(); |
377 | if (stringRef == 0){ | |
374 | if (stringRef == 0) { | |
378 | 375 | long toReadStart = bytesToRead; |
379 | 376 | long uidNum = readUnsignedNum64(); |
380 | 377 | if (uidNum == 0) |
381 | 378 | 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 | |
385 | 382 | --bytesToRead; |
386 | 383 | } |
387 | 384 | stringPair[1] = readString(); |
388 | 385 | long bytes = toReadStart - bytesToRead; |
389 | 386 | if (bytes <= MAX_STRING_PAIR_SIZE) |
390 | 387 | storeStringPair(); |
391 | } | |
392 | else | |
388 | } else { | |
393 | 389 | 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) . | |
400 | 395 | * @return 0..3 for type (3 means unknown) |
401 | 396 | */ |
402 | private int readRelRef () throws IOException{ | |
397 | private int readRelRef () { | |
403 | 398 | int refType = -1; |
404 | 399 | long toReadStart = bytesToRead; |
405 | 400 | int stringRef = readUnsignedNum32(); |
406 | if (stringRef == 0){ | |
407 | refType = ioBuf[ioPos++] - 0x30; | |
401 | if (stringRef == 0) { | |
402 | refType = ioBuf[ioBufPos++] - 0x30; | |
408 | 403 | --bytesToRead; |
409 | 404 | |
410 | 405 | if (refType < 0 || refType > 2) |
411 | 406 | refType = 3; |
412 | 407 | stringPair[0] = REL_REF_TYPES[refType]; |
413 | ||
408 | ||
414 | 409 | stringPair[1] = readString(); |
415 | 410 | long bytes = toReadStart - bytesToRead; |
416 | 411 | if (bytes <= MAX_STRING_PAIR_SIZE) |
417 | 412 | storeStringPair(); |
418 | } | |
419 | else { | |
413 | } else { | |
420 | 414 | setStringRefPair(stringRef); |
421 | 415 | char c = stringPair[0].charAt(0); |
422 | switch (c){ | |
416 | switch (c) { | |
423 | 417 | case 'n': refType = 0; break; |
424 | 418 | case 'w': refType = 1; break; |
425 | 419 | case 'r': refType = 2; break; |
430 | 424 | } |
431 | 425 | |
432 | 426 | /** |
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() { | |
437 | 430 | int stringRef = readUnsignedNum32(); |
438 | if (stringRef == 0){ | |
431 | if (stringRef == 0) { | |
439 | 432 | long toReadStart = bytesToRead; |
440 | 433 | int cnt = 0; |
441 | while (cnt < 2){ | |
434 | while (cnt < 2) { | |
442 | 435 | stringPair[cnt++] = readString(); |
443 | 436 | } |
444 | 437 | long bytes = toReadStart - bytesToRead; |
445 | 438 | if (bytes <= MAX_STRING_PAIR_SIZE) |
446 | 439 | storeStringPair(); |
447 | } | |
448 | else | |
440 | } else { | |
449 | 441 | setStringRefPair(stringRef); |
442 | } | |
450 | 443 | } |
451 | 444 | |
452 | 445 | /** |
453 | 446 | * Read a zero-terminated string (see o5m definition). |
454 | 447 | * @throws IOException |
455 | 448 | */ |
456 | String readString() throws IOException { | |
457 | int length = 0; | |
449 | private String readString() { | |
450 | int length = 0; | |
458 | 451 | while (true) { |
459 | final int b = ioBuf[ioPos++]; | |
452 | final int b = ioBuf[ioBufPos++]; | |
460 | 453 | --bytesToRead; |
461 | 454 | if (b == 0) |
462 | return new String(cnvBuffer, 0, length, "UTF-8"); | |
455 | return new String(cnvBuffer, 0, length, StandardCharsets.UTF_8); | |
463 | 456 | cnvBuffer[length++] = (byte) b; |
464 | 457 | } |
465 | 458 | } |
466 | ||
467 | 459 | |
468 | 460 | /** reset the delta values and string table */ |
469 | private void reset(){ | |
461 | private void reset() { | |
470 | 462 | lastNodeId = 0; lastWayId = 0; lastRelId = 0; |
471 | 463 | lastRef[0] = 0; lastRef[1] = 0;lastRef[2] = 0; |
472 | 464 | lastTs = 0; lastChangeSet = 0; |
476 | 468 | } |
477 | 469 | |
478 | 470 | /** |
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 | |
481 | 473 | */ |
482 | 474 | 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') { | |
484 | 476 | throw new IOException("unsupported header"); |
485 | 477 | } |
486 | 478 | } |
487 | 479 | |
488 | 480 | /** |
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 | |
492 | 483 | */ |
493 | 484 | 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++]; | |
496 | 495 | --bytesToRead; |
497 | 496 | result = b; |
498 | if ((b & 0x80) == 0){ // just one byte | |
497 | if ((b & 0x80) == 0) { // just one byte | |
499 | 498 | 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 | ||
503 | 502 | } |
504 | 503 | 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 | |
508 | 507 | --bytesToRead; |
509 | result += fac * (b & 0x7f) ; | |
510 | fac <<= 7; | |
508 | result += ((long) (b & 0x7f)) << shift; | |
509 | shift += 7; | |
511 | 510 | } |
512 | 511 | --bytesToRead; |
513 | result += fac * b; | |
512 | result += ((long) b) << shift; | |
514 | 513 | 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 { | |
560 | 525 | int b = is.read(); |
561 | 526 | --bytesToRead; |
562 | 527 | long result = b; |
563 | if ((b & 0x80) == 0){ // just one byte | |
528 | if ((b & 0x80) == 0) { // just one byte | |
564 | 529 | return result; |
565 | 530 | } |
566 | 531 | 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 | |
569 | 534 | --bytesToRead; |
570 | result += fac * (b & 0x7f) ; | |
571 | fac <<= 7; | |
535 | result += ((long) (b & 0x7f)) << shift; | |
536 | shift += 7; | |
572 | 537 | } |
573 | 538 | --bytesToRead; |
574 | result += fac * b; | |
539 | result += ((long) b) << shift; | |
575 | 540 | return result; |
576 | 541 | } |
577 | 542 | |
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++]; | |
586 | 550 | --bytesToRead; |
587 | 551 | long result = b; |
588 | if ((b & 0x80) == 0){ // just one byte | |
552 | if ((b & 0x80) == 0) { // just one byte | |
589 | 553 | return result; |
590 | 554 | } |
591 | 555 | 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 | |
594 | 558 | --bytesToRead; |
595 | result += fac * (b & 0x7f) ; | |
596 | fac <<= 7; | |
559 | result += ((long) (b & 0x7f)) << shift; | |
560 | shift += 7; | |
597 | 561 | } |
598 | 562 | --bytesToRead; |
599 | result += fac * b; | |
563 | result += ((long) b) << shift; | |
600 | 564 | return result; |
601 | 565 | } |
602 | 566 | |
603 | 567 | /** |
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(); | |
626 | 574 | } |
627 | 575 | |
628 | 576 | } |
141 | 141 | * Retrieve the areas of all precompiled tiles that have to be worked out. |
142 | 142 | * @return the areas of all tiles |
143 | 143 | */ |
144 | private List<uk.me.parabola.imgfmt.app.Area> getTiles() { | |
144 | private static List<uk.me.parabola.imgfmt.app.Area> getTiles() { | |
145 | 145 | return getTiles(uk.me.parabola.imgfmt.app.Area.PLANET); |
146 | 146 | } |
147 | 147 | |
148 | private List<uk.me.parabola.imgfmt.app.Area> getTiles( | |
148 | private static List<uk.me.parabola.imgfmt.app.Area> getTiles( | |
149 | 149 | uk.me.parabola.imgfmt.app.Area wholeArea) { |
150 | 150 | int minLat = wholeArea.getMinLat(); |
151 | 151 | int maxLat = wholeArea.getMaxLat(); |
152 | 152 | int minLon = wholeArea.getMinLong(); |
153 | 153 | int maxLon = wholeArea.getMaxLong(); |
154 | 154 | |
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<>(); | |
156 | 156 | for (int lon = SeaGenerator.getPrecompTileStart(minLon); lon < maxLon; lon += SeaGenerator.PRECOMP_RASTER) { |
157 | 157 | for (int lat = SeaGenerator.getPrecompTileStart(minLat); lat < maxLat; lat += SeaGenerator.PRECOMP_RASTER) { |
158 | 158 | uk.me.parabola.imgfmt.app.Area tile = new uk.me.parabola.imgfmt.app.Area( |
179 | 179 | setDaemon(true); |
180 | 180 | } |
181 | 181 | |
182 | @Override | |
182 | 183 | public void run() { |
183 | 184 | long count = 0; |
184 | 185 | do { |
197 | 198 | * @param geometry a polygon as {@link Geometry} object |
198 | 199 | * @return the polygon converted to an {@link Area} object. |
199 | 200 | */ |
200 | private Area convertToArea(Geometry geometry) { | |
201 | private static Area convertToArea(Geometry geometry) { | |
201 | 202 | Coordinate[] c = geometry.getCoordinates(); |
202 | 203 | List<Coord> points = new ArrayList<>(c.length); |
203 | 204 | for (int n = 0; n < c.length; n++) { |
218 | 219 | Collection<uk.me.parabola.imgfmt.app.Area> tiles, |
219 | 220 | CountDownLatch tilesCountdown, |
220 | 221 | BlockingQueue<Entry<String, List<Way>>> saveQueue) { |
221 | List<PrecompSeaMerger> mergers = new ArrayList<PrecompSeaMerger>(); | |
222 | List<PrecompSeaMerger> mergers = new ArrayList<>(); | |
222 | 223 | |
223 | 224 | for (uk.me.parabola.imgfmt.app.Area bounds : tiles) { |
224 | 225 | |
235 | 236 | } |
236 | 237 | |
237 | 238 | private void createShapefileAccess() throws IOException { |
238 | Map<String,URL> map = new HashMap<String, URL>(); | |
239 | Map<String,URL> map = new HashMap<>(); | |
239 | 240 | map.put("url", shapeFile.toURI().toURL()); |
240 | 241 | DataStore dataStore = DataStoreFinder.getDataStore(map); |
241 | 242 | String typeName = dataStore.getTypeNames()[0]; |
275 | 276 | |
276 | 277 | // perform several cycles which is necessary to reduce memory |
277 | 278 | // requirements |
278 | while (remainingTiles.isEmpty() == false) { | |
279 | while (!remainingTiles.isEmpty()) { | |
279 | 280 | |
280 | 281 | // 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<>(); | |
282 | 283 | tiles.addAll(remainingTiles.subList(0, |
283 | 284 | Math.min(tilesPerCycle, remainingTiles.size()))); |
284 | 285 | remainingTiles.subList(0, |
401 | 402 | String shapeCRS = args[1]; |
402 | 403 | File outputDir = new File(args[2]); |
403 | 404 | |
404 | if (shapeFile.exists() == false) { | |
405 | if (!shapeFile.exists()) { | |
405 | 406 | throw new FileNotFoundException("File "+shapeFile+" does not exist."); |
406 | 407 | } |
407 | 408 |
46 | 46 | private final BlockingQueue<Entry<String, List<Way>>> saveQueue; |
47 | 47 | private ExecutorService service; |
48 | 48 | |
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(); | |
55 | 55 | private final String key; |
56 | 56 | |
57 | 57 | public MergeData(Rectangle2D bounds, String key) { |
58 | 58 | this.key = key; |
59 | 59 | this.bounds = bounds; |
60 | toMerge = new LinkedBlockingQueue<Area>(); | |
60 | toMerge = new LinkedBlockingQueue<>(); | |
61 | 61 | } |
62 | 62 | |
63 | 63 | public String getKey() { |
94 | 94 | return mergeData.bounds; |
95 | 95 | } |
96 | 96 | |
97 | private List<Way> convertToWays(Area a, String naturalTag) { | |
97 | private static List<Way> convertToWays(Area a, String naturalTag) { | |
98 | 98 | List<List<Coord>> pointLists = Java2DConverter.areaToShapes(a); |
99 | List<Way> ways = new ArrayList<Way>(pointLists.size()); | |
99 | List<Way> ways = new ArrayList<>(pointLists.size()); | |
100 | 100 | for (List<Coord> points : pointLists) { |
101 | 101 | Way w = new Way(FakeIdGenerator.makeFakeId(), points); |
102 | 102 | w.addTag("natural", naturalTag); |
137 | 137 | merge = mergeData.toMerge.poll(); |
138 | 138 | } |
139 | 139 | |
140 | if (mergeData.ready.get() == false | |
141 | || mergeData.toMerge.isEmpty() == false) { | |
140 | if (!mergeData.ready.get() || !mergeData.toMerge.isEmpty()) { | |
142 | 141 | // repost the merge thread |
143 | 142 | service.execute(this); |
144 | 143 | return; |
158 | 157 | // no land in this tile => create a sea way only |
159 | 158 | ways.addAll(convertToWays(new Area(mergeData.bounds), "sea")); |
160 | 159 | } else { |
161 | Map<Long, Way> landWays = new HashMap<Long, Way>(); | |
160 | Map<Long, Way> landWays = new HashMap<>(); | |
162 | 161 | List<List<Coord>> landParts = Java2DConverter |
163 | 162 | .areaToShapes(mergeData.landArea); |
164 | 163 | for (List<Coord> landPoints : landParts) { |
186 | 185 | { |
187 | 186 | // do not calculate the area size => it is not required and adds |
188 | 187 | // a superfluous tag |
188 | @Override | |
189 | 189 | protected boolean isAreaSizeCalculated() { |
190 | 190 | return false; |
191 | 191 | } |
202 | 202 | .getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) { |
203 | 203 | |
204 | 204 | String tag = w.getTag("natural"); |
205 | if ("sea".equals(tag) == false) { | |
205 | if (!"sea".equals(tag)) { | |
206 | 206 | // ignore the land polygons - we already have them in our list |
207 | 207 | continue; |
208 | 208 | } |
215 | 215 | |
216 | 216 | try { |
217 | 217 | // 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)); | |
220 | 219 | } catch (InterruptedException exp) { |
221 | 220 | exp.printStackTrace(); |
222 | 221 | } |
12 | 12 | |
13 | 13 | package uk.me.parabola.mkgmap.sea.optional; |
14 | 14 | |
15 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; | |
16 | ||
17 | 15 | import java.io.File; |
18 | 16 | import java.io.FileOutputStream; |
19 | 17 | import java.io.IOException; |
20 | 18 | import java.io.PrintWriter; |
19 | import java.nio.file.Files; | |
20 | import java.nio.file.StandardCopyOption; | |
21 | 21 | import java.util.HashMap; |
22 | 22 | import java.util.List; |
23 | 23 | import java.util.Map; |
31 | 31 | import java.util.regex.Pattern; |
32 | 32 | import java.util.zip.GZIPOutputStream; |
33 | 33 | |
34 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; | |
35 | import uk.me.parabola.imgfmt.ExitException; | |
34 | 36 | import uk.me.parabola.imgfmt.Utils; |
35 | 37 | import uk.me.parabola.imgfmt.app.Coord; |
36 | 38 | import uk.me.parabola.mkgmap.reader.osm.SeaGenerator; |
52 | 54 | |
53 | 55 | private final File outputDir; |
54 | 56 | |
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<>(); | |
56 | 58 | |
57 | 59 | public PrecompSeaSaver(File outputDir, boolean usePbf) { |
58 | 60 | this.outputDir = outputDir; |
59 | 61 | finishWait = new CountDownLatch(1); |
60 | 62 | this.usePbf = usePbf; |
61 | idMapping = new HashMap<Integer, String>(); | |
62 | index = new TreeMap<String, String>(); | |
63 | idMapping = new HashMap<>(); | |
64 | index = new TreeMap<>(); | |
63 | 65 | this.outputDir.mkdirs(); |
64 | 66 | } |
65 | 67 | |
69 | 71 | |
70 | 72 | private OSMWriter createWriter(int id, String key) { |
71 | 73 | 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); | |
76 | 78 | OSMWriter writer = (usePbf ? new BinaryMapWriter(bounds, outputDir, nextId, 0) |
77 | 79 | : new OSMXMLWriter(bounds, outputDir, nextId, 0)); |
78 | 80 | idMapping.put(id, key); |
86 | 88 | } |
87 | 89 | |
88 | 90 | public void run() { |
89 | while (saveQueue.isEmpty() == false || finished.get() == false) { | |
91 | while (!saveQueue.isEmpty() || !finished.get()) { | |
90 | 92 | Entry<String, List<Way>> tileData = null; |
91 | 93 | try { |
92 | 94 | tileData = saveQueue.poll(1, TimeUnit.MINUTES); |
94 | 96 | exp.printStackTrace(); |
95 | 97 | } |
96 | 98 | if (tileData != null) { |
97 | int id = ++nextId; | |
99 | int fakeMapid = ++nextId; | |
98 | 100 | |
99 | 101 | if (tileData.getValue().size() == 1) { |
100 | 102 | // do not write the tile because it consists of one |
104 | 106 | String naturalTag = singleWay.getTag("natural"); |
105 | 107 | index.put(tileData.getKey(), naturalTag); |
106 | 108 | } 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()); | |
142 | 113 | } |
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); | |
161 | 114 | } |
162 | 115 | } |
163 | 116 | } |
164 | 117 | |
165 | writeIndex(); | |
118 | try { | |
119 | writeIndex(); | |
120 | } catch (IOException e) { | |
121 | e.printStackTrace(); | |
122 | } | |
166 | 123 | |
167 | 124 | finishWait.countDown(); |
168 | 125 | } |
169 | 126 | |
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 | ||
176 | 177 | 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'); | |
178 | 179 | } |
179 | ||
180 | indexWriter.close(); | |
181 | } catch (IOException exp1) { | |
182 | exp1.printStackTrace(); | |
183 | 180 | } |
184 | 181 | } |
185 | 182 | }⏎ |
21 | 21 | } |
22 | 22 | |
23 | 23 | public boolean addAll(Collection<Coord> coordList) { |
24 | boolean oneAdded = false; | |
24 | long oldCount = itemCount; | |
25 | 25 | for (Coord c : coordList) { |
26 | oneAdded = add(c) | oneAdded; | |
26 | add(c); | |
27 | 27 | } |
28 | return oneAdded; | |
28 | return itemCount > oldCount; | |
29 | 29 | } |
30 | 30 | |
31 | 31 | public boolean add(Coord c) { |
42 | 42 | } |
43 | 43 | |
44 | 44 | 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)); | |
47 | 46 | } |
48 | 47 | |
49 | 48 | public List<Coord> get(List<Coord> polygon) { |
54 | 53 | if (polygon.size() < 3) { |
55 | 54 | return Collections.emptyList(); |
56 | 55 | } |
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"); | |
59 | 58 | } |
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)); | |
62 | 60 | if (offset > 0) { |
63 | 61 | ListIterator<Coord> pointIter = points.listIterator(); |
64 | 62 | while (pointIter.hasNext()) { |
79 | 77 | return itemCount; |
80 | 78 | } |
81 | 79 | |
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) { | |
84 | 81 | Iterator<Coord> polyIter = polygon.iterator(); |
85 | 82 | Coord c2 = polyIter.next(); |
86 | 83 | while (polyIter.hasNext()) { |
0 | 0 | package uk.me.parabola.util; |
1 | 1 | |
2 | import java.awt.*; | |
3 | import java.util.ArrayList; | |
2 | import java.awt.Rectangle; | |
4 | 3 | import java.util.Collection; |
5 | 4 | import java.util.Collections; |
6 | 5 | import java.util.HashSet; |
89 | 88 | this.points = points; |
90 | 89 | split(); |
91 | 90 | } else { |
92 | this.points = new HashSet<Coord>(points); | |
91 | this.points = new HashSet<>(points); | |
93 | 92 | } |
94 | 93 | } |
95 | 94 | |
101 | 100 | if (coveredBounds == null) { |
102 | 101 | coveredBounds = new Area(c.getLatitude(), c.getLongitude(), |
103 | 102 | c.getLatitude(), c.getLongitude()); |
104 | } else if (coveredBounds.contains(c) == false) { | |
103 | } else if (!coveredBounds.contains(c)) { | |
105 | 104 | coveredBounds = new Area(Math.min(coveredBounds.getMinLat(), |
106 | 105 | c.getLatitude()), Math.min(coveredBounds.getMinLong(), |
107 | 106 | c.getLongitude()), Math.max(coveredBounds.getMaxLat(), |
125 | 124 | |
126 | 125 | public List<Coord> get(Area bbox, List<Coord> resultList) { |
127 | 126 | 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)) { | |
133 | 128 | // the bounding box is contained completely in the bbox |
134 | 129 | // => add all points without further check |
135 | 130 | resultList.addAll(points); |
151 | 146 | return resultList; |
152 | 147 | } |
153 | 148 | |
154 | public ArrayList<Coord> get(QuadTreePolygon polygon, ArrayList<Coord> resultList) { | |
149 | public List<Coord> get(QuadTreePolygon polygon, List<Coord> resultList) { | |
155 | 150 | if (polygon.getBbox().intersects(getBounds())) { |
156 | 151 | if (isLeaf()) { |
157 | 152 | for (Coord c : points) { |
175 | 170 | |
176 | 171 | } |
177 | 172 | |
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())); | |
181 | 176 | } |
182 | 177 | |
183 | 178 | public boolean isLeaf() { |
216 | 211 | |
217 | 212 | public void clear() { |
218 | 213 | this.children = null; |
219 | points = new HashSet<Coord>(); | |
214 | points = new HashSet<>(); | |
220 | 215 | coveredBounds = new Area(Integer.MAX_VALUE, Integer.MAX_VALUE, |
221 | 216 | Integer.MIN_VALUE, Integer.MIN_VALUE); |
222 | 217 | } |