Codebase list mkgmap / 6502969
New upstream version 0.0.0+svn4323 Bas Couwenberg 4 years ago
72 changed file(s) with 474 addition(s) and 927 deletion(s). Raw diff Collapse all Expand all
267267 <p>
268268 If the street is not given with addr:housenumber, mkgmap uses heuristics
269269 to find the best match.
270 <p>
271 Tells mkgmap to write NET data. If you specify this option, you do not need to
272 specify --net and option -no-net is ignored.
270273
271274 === Overview map options ===
272275 ;--overview-mapname=name
522525 <p>
523526 ;--net
524527 : Tells mkgmap to write NET data, which is needed for address search
525 and routing. Use this option if you want full address search, but do
526 not need a map that supports routing.
528 and routing. Use this option if you want address search, but do
529 not need a map that supports routing or house number search.
527530 <p>
528531 ;--route
529532 : Tells mkgmap to write NET and NOD data, which are needed in maps
530533 that support routing. If you specify this option, you do not need
531 to specify --net.
534 to specify --net and --no-net is ignored.
532535 <p>
533536 ;--add-boundary-nodes-at-admin-boundaries=NUM
534537 : This option controls how mkgmap calculates special routing nodes which
260260 the addr:street tag value of the house number node.
261261 If the street is not given with addr:housenumber, mkgmap uses heuristics
262262 to find the best match.
263 Tells mkgmap to write NET data. If you specify this option, you do not need
264 to specify --net and option -no-net is ignored.
263265
264266 Overview map options:
265267 --overview-mapname=name
514516 will ask you to try a value for this option.
515517
516518 --net
517 Tells mkgmap to write NET data, which is needed for address search
518 and routing. Use this option if you want full address search, but do
519 not need a map that supports routing.
519 Tells mkgmap to write NET data, which is needed for address search
520 and routing. Use this option if you want address search, but do
521 not need a map that supports routing or house number search.
520522
521523 --route
522524 Tells mkgmap to write NET and NOD data, which are needed in maps
523525 that support routing. If you specify this option, you do not need
524 to specify --net.
526 to specify --net and option -no-net is ignored.
525527
526528 --drive-on=left|right|detect|detect,left|detect,right
527529 Explicitly specify which side of the road vehicles are
0 svn.version: 4294
1 build.timestamp: 2019-09-28T07:25:58+0100
0 svn.version: 4323
1 build.timestamp: 2019-10-26T09:00:42+0100
1616 package uk.me.parabola.imgfmt.app.lbl;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
2019 import java.util.List;
2120
2221 import uk.me.parabola.imgfmt.app.ImgFileWriter;
6463 if(extraData) {
6564 writer.put1u(0);
6665 writer.put2u(region == null? 0 : region.getIndex());
67 Collections.sort(exits);
66 exits.sort(null);
6867 for(ExitPoint ep : exits) {
6968 writer.put1u(ep.index);
7069 writer.put2u(ep.div.getNumber());
3434 this.name = name;
3535 this.poiIndex = poiIndex;
3636 this.group = group;
37 this.subType = subType;
37 this.subType = subType & 0xff;
3838 }
3939
4040 void write(ImgFileWriter writer) {
1616 package uk.me.parabola.imgfmt.app.lbl;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
2019 import java.util.LinkedHashMap;
2120 import java.util.List;
2221 import java.util.Map;
9796 SortKey<POIIndex> sortKey = sort.createSortKey(index, index.getName());
9897 sorted.add(sortKey);
9998 }
100 Collections.sort(sorted);
99 sorted.sort(null);
101100
102101 for (SortKey<POIIndex> key : sorted) {
103102 key.getObject().write(writer);
341340 SortKey<Country> key = sort.createSortKey(c, c.getLabel());
342341 keys.add(key);
343342 }
344 Collections.sort(keys);
343 keys.sort(null);
345344
346345 countryList.clear();
347346 int index = 1;
361360 SortKey<Region> key = sort.createSortKey(r, r.getLabel(), r.getCountry().getIndex());
362361 keys.add(key);
363362 }
364 Collections.sort(keys);
363 keys.sort(null);
365364
366365 regionList.clear();
367366 int index = 1;
382381 sortKey = new CombinedSortKey<>(sortKey, c.getRegionNumber(), c.getCountryNumber());
383382 keys.add(sortKey);
384383 }
385 Collections.sort(keys);
384 keys.sort(null);
386385
387386 cityList.clear();
388387 int index = 1;
399398 SortKey<Zip> sortKey = sort.createSortKey(c, c.getLabel());
400399 keys.add(sortKey);
401400 }
402 Collections.sort(keys);
401 keys.sort(null);
403402
404403 zipList.clear();
405404 int index = 1;
120120 // we don't want routing info in the overview map (for now)
121121 if (!OverviewBuilder.isOverviewImg(mapName)){
122122 try {
123 if (props.containsKey("route") || props.containsKey("net") || props.containsKey("housenumbers")) {
124 addNet();
125 }
123126 if (props.containsKey("route")) {
124 addNet();
125127 addNod();
126 } else if (props.containsKey("net")) {
127 addNet();
128128 }
129129 } catch (FileExistsException e) {
130130 log.warn("Could not add NET and/or NOD sections");
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.HashMap;
1716 import java.util.List;
1817 import java.util.Map;
6564 keys.add(makeKey(list.get(i), sort, cache));
6665 }
6766 cache = null;
68 Collections.sort(keys);
67 keys.sort(null);
6968
7069 for (int i = 0; i < keys.size(); i++){
7170 SortKey<T> sk = keys.get(i);
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.LinkedHashMap;
1716 import java.util.List;
1817 import java.util.Map;
6968 if (poiGroup == null)
7069 continue;
7170
72 Collections.sort(poiGroup);
71 poiGroup.sort(null);
7372
7473 String lastName = null;
7574 int lastSub = -1;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
3433 }
3534
3635 public void writeSectData(ImgFileWriter writer) {
37 Collections.sort(regions);
36 regions.sort(null);
3837
3938 for (Mdr13Record region : regions) {
4039 putMapIndex(writer, region.getMapIndex());
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
3029 }
3130
3231 public void writeSectData(ImgFileWriter writer) {
33 Collections.sort(countries);
32 countries.sort(null);
3433
3534 for (Mdr14Record country : countries) {
3635 putMapIndex(writer, country.getMapIndex());
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
1715 import java.util.List;
1816
1917 import uk.me.parabola.imgfmt.app.ImgFileWriter;
2523 */
2624 public class Mdr19 extends MdrSection implements HasHeaderFlags {
2725 private List<Mdr11Record> pois;
28 private final List<Mdr18Record> poiTypes = new ArrayList<Mdr18Record>();
26 private final List<Mdr18Record> poiTypes = new ArrayList<>();
2927
3028 public Mdr19(MdrConfig config) {
3129 setConfig(config);
3432 /**
3533 * Sort the pois by type.
3634 */
35 @Override
3736 public void preWriteImpl() {
38 Collections.sort(pois, new Comparator<Mdr11Record>() {
39 public int compare(Mdr11Record o1, Mdr11Record o2) {
40 // For mainly historical reasons, we keep the element type in a number of different
41 // formats. Need to normalise it before sorting.
42 int t1 = MdrUtils.fullTypeToNaturalType(o1.getType());
43 int t2 = MdrUtils.fullTypeToNaturalType(o2.getType());
44
45 if (t1 == t2) return 0;
46 else if (t1 < t2) return -1;
47 else return 1;
48 }
49 });
37 // For mainly historical reasons, we keep the element type in a number
38 // of different formats. Need to normalise it before sorting.
39 pois.sort((o1, o2) -> Integer.compare(MdrUtils.fullTypeToNaturalType(o1.getType()),
40 MdrUtils.fullTypeToNaturalType(o2.getType())));
5041 }
5142
5243 /**
9182 * Release the copy of the pois. The other index is small and not worth
9283 * worrying about.
9384 */
85 @Override
9486 protected void releaseMemory() {
9587 pois = null;
9688 }
1414
1515 import java.text.Collator;
1616 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Comparator;
1917 import java.util.List;
2018
2119 /**
4947 */
5048 public void buildFromStreets(List<Mdr7Record> inStreets) {
5149 ArrayList<Mdr7Record> sorted = new ArrayList<>(inStreets);
52 Collections.sort(sorted, new Comparator<Mdr7Record>() {
53 public int compare(Mdr7Record o1, Mdr7Record o2) {
54 int d = Integer.compare(o1.getCity().getMdr20SortPos(), o2.getCity().getMdr20SortPos());
55 if (d != 0)
56 return d;
57 return Integer.compare(o1.getIndex(), o2.getIndex());
58 }
50 sorted.sort((o1, o2) -> {
51 int d = Integer.compare(o1.getCity().getMdr20SortPos(), o2.getCity().getMdr20SortPos());
52 if (d != 0)
53 return d;
54 return Integer.compare(o1.getIndex(), o2.getIndex());
5955 });
6056
6157 Collator collator = getConfig().getSort().getCollator();
9591 * Two streets are in the same group if they have the same mdr20 id.
9692 */
9793 protected boolean sameGroup(Mdr7Record street1, Mdr7Record street2) {
98 if (street2 != null && street1.getCity().getMdr20() == street2.getCity().getMdr20())
99 return true;
100 return false;
94 return street2 != null && street1.getCity().getMdr20() == street2.getCity().getMdr20();
10195 }
10296
10397 /**
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
1715 import java.util.List;
1816
1917 /**
4139 if (street.getCity() != null && street.getCity().getMdrRegion() != null)
4240 sorted.add(street);
4341 }
44 Collections.sort(sorted, new Comparator<Mdr7Record>() {
45 public int compare(Mdr7Record o1, Mdr7Record o2) {
46 int d = Integer.compare(o1.getCity().getMdr21SortPos(), o2.getCity().getMdr21SortPos());
47 if (d != 0)
48 return d;
49 return Integer.compare(o1.getIndex(), o2.getIndex());
50 }
42 sorted.sort((o1, o2) -> {
43 int d = Integer.compare(o1.getCity().getMdr21SortPos(), o2.getCity().getMdr21SortPos());
44 if (d != 0)
45 return d;
46 return Integer.compare(o1.getIndex(), o2.getIndex());
5147 });
52
5348
5449 int lastIndex = -1;
5550 int record = 0;
1414
1515 import java.util.ArrayList;
1616 import java.util.Collections;
17 import java.util.Comparator;
1817 import java.util.List;
1918
2019 /**
4948 sorted.add(street);
5049 }
5150 }
52 Collections.sort(sorted, new Comparator<Mdr7Record>() {
53 public int compare(Mdr7Record o1, Mdr7Record o2) {
54 int d = Integer.compare(o1.getCity().getMdr22SortPos(), o2.getCity().getMdr22SortPos());
55 if (d != 0)
56 return d;
57 return Integer.compare(o1.getIndex(), o2.getIndex());
58 }
51 sorted.sort((o1, o2) -> {
52 int d = Integer.compare(o1.getCity().getMdr22SortPos(), o2.getCity().getMdr22SortPos());
53 if (d != 0)
54 return d;
55 return Integer.compare(o1.getIndex(), o2.getIndex());
5956 });
60
6157
6258 int lastIndex = -1;
6359 int record = 0;
7672 lastIndex = street.getIndex();
7773 }
7874 }
79 return;
8075 }
8176
8277 protected boolean sameGroup(Mdr7Record street1, Mdr7Record street2) {
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
2524 * @author Steve Ratcliffe
2625 */
2726 public class Mdr23 extends MdrSection {
28 private final List<Mdr13Record> regions = new ArrayList<Mdr13Record>();
27 private final List<Mdr13Record> regions = new ArrayList<>();
2928
3029 public Mdr23(MdrConfig config) {
3130 setConfig(config);
3837 public void sortRegions(List<Mdr13Record> list) {
3938 Sort sort = getConfig().getSort();
4039 List<SortKey<Mdr13Record>> keys = MdrUtils.sortList(sort, list);
41 Collections.sort(keys);
4240
4341 String lastName = null;
4442 int lastMapIndex = 0;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
2524 * @author Steve Ratcliffe
2625 */
2726 public class Mdr24 extends MdrSection {
28 private final List<Mdr14Record> countries = new ArrayList<Mdr14Record>();
27 private final List<Mdr14Record> countries = new ArrayList<>();
2928
3029 public Mdr24(MdrConfig config) {
3130 setConfig(config);
3837 public void sortCountries(List<Mdr14Record> list) {
3938 Sort sort = getConfig().getSort();
4039 List<SortKey<Mdr14Record>> keys = MdrUtils.sortList(sort, list);
41
42 Collections.sort(keys);
4340
4441 String lastName = null;
4542 int lastMapIndex = 0;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
4443 keys.add(key);
4544 }
4645
47 Collections.sort(keys);
46 keys.sort(null);
4847
4948 String lastName = null;
5049 Mdr5Record lastCity = null;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
4039 SortKey<Mdr28Record> key = sort.createSortKey(mdr28, mdr28.getMdr14().getName(), ++record);
4140 sortList.add(key);
4241 }
43 Collections.sort(sortList);
42 sortList.sort(null);
4443
4544 addToIndex(sortList);
4645 }
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.ImgFileWriter;
4746 }
4847 }
4948
50 Collections.sort(keys);
49 keys.sort(null);
5150
5251 String lastName = null;
5352 int record = 0;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.HashSet;
1716 import java.util.List;
1817 import java.util.Set;
3635
3736 public void writeSectData(ImgFileWriter writer) {
3837 List<Mdr4Record> list = new ArrayList<Mdr4Record>(poiTypes);
39 Collections.sort(list);
38 list.sort(null);
4039
4140 for (Mdr4Record r : list) {
4241 writer.put1u(r.getType());
6767 sortKey = new MultiSortKey<>(sortKey, regionKey, countryKey);
6868 sortKeys.add(sortKey);
6969 }
70 Collections.sort(sortKeys);
70 sortKeys.sort(null);
7171
7272 Collator collator = getConfig().getSort().getCollator();
7373
120120 sortKey = new MultiSortKey<>(sortKey, regionKey, countryKey);
121121 sortKeys.add(sortKey);
122122 }
123 Collections.sort(sortKeys);
123 sortKeys.sort(null);
124124
125125 SortKey<Mdr5Record> lastKey = null;
126126 int pos = 0;
146146 // Sort by region name.
147147 sortKeys.add(sort.createSortKey(m, m.getRegionName()));
148148 }
149 Collections.sort(sortKeys);
149 sortKeys.sort(null);
150150
151151 SortKey<Mdr5Record> lastKey = null;
152152 int pos = 0;
174174 SortKey<Mdr5Record> countryKey = sort.createSortKey(m, m.getCountryName());
175175 sortKeys.add(countryKey);
176176 }
177 Collections.sort(sortKeys);
177 sortKeys.sort(null);
178178
179179 SortKey<Mdr5Record> lastKey = null;
180180 int pos = 0;
247247 // This sometimes presents search results in the wrong order. The partial sort fields allow to
248248 // tell the right order.
249249
250 // LargeListSorter<Mdr7Record> initalPartSorter = new LargeListSorter<Mdr7Record>(sort) {
251 // @Override
252 // protected SortKey<Mdr7Record> makeKey(Mdr7Record r, Sort sort, Map<String, byte[]> cache) {
253 // return sort.createSortKey(r, r.getInitialPart(), r.getMapIndex(), cache);
254 // }
255 // };
256 // LargeListSorter<Mdr7Record> suffixSorter = new LargeListSorter<Mdr7Record>(sort) {
257 // @Override
258 // protected SortKey<Mdr7Record> makeKey(Mdr7Record r, Sort sort, Map<String, byte[]> cache) {
259 // return sort.createSortKey(r, r.getSuffix(), r.getMapIndex(), cache);
260 // }
261 // };
262250 LargeListSorter<Mdr7Record> fullNameSorter = new LargeListSorter<Mdr7Record>(sort) {
263251 @Override
264252 protected SortKey<Mdr7Record> makeKey(Mdr7Record r, Sort sort, Map<String, byte[]> cache) {
267255 };
268256
269257
270 // List<Mdr7Record> sortedByInitial = new ArrayList<>(samePartial);
271 // List<Mdr7Record> sortedBySuffix = new ArrayList<>(samePartial);
272 // initalPartSorter.sort(sortedByInitial);
273 // suffixSorter.sort(sortedBySuffix);
274
275 // Mdr7Record last = null;
276 // for (int i = 0; i < samePartial.size(); i++) {
277 // Mdr7Record r = samePartial.get(i);
278 // if (i > 0) {
279 // int repeat = r.checkRepeat(last, collator);
280 // int b = 0;
281 // if (repeat == 0) {
282 // } else if (repeat == 3)
283 // b = last.getB();
284 // else if (repeat == 1) {
285 // b = last.getB() + 1;
286 // }
287 // if (b != 0) {
288 // if (b > maxPrefixCount)
289 // maxPrefixCount = b;
290 // r.setB(b);
291 // }
292 // }
293 // last = r;
294 // }
295 // suffixSorter.sort(samePartial);
296 // last = null;
297 // int s = 0;
298 // for (int i = 0; i < samePartial.size(); i++) {
299 // Mdr7Record r = samePartial.get(i);
300 // if (i > 0) {
301 // int cmp = collator.compare(last.getSuffix(), r.getSuffix());
302 // if (cmp == 0)
303 // s = last.getS();
304 // else
305 // s = last.getS() + 1;
306 // if (s != 0) {
307 // if (s > maxSuffixCount)
308 // maxSuffixCount = s;
309 // r.setB(s);
310 // }
311 // }
312 // last = r;
313 // }
314 //
315 //
316258 fullNameSorter.sort(samePartial);
317259 Mdr7Record last = null;
318260 int recordNumber = streets.size();
319261
320262 // list is now sorted by partial name, name, and map index
321 // // De-duplicate the street names so that there is only one entry
322 // // per map for the same name.
263 // De-duplicate the street names so that there is only one entry
264 // per map for the same name.
323265 for (int i = 0; i < samePartial.size(); i++) {
324266 Mdr7Record r = samePartial.get(i);
325267 if (last != null && r.getMapIndex() == last.getMapIndex() && r.getName().equals(last.getName())) {
342284 boolean hasStrings = hasFlag(MDR7_HAS_STRING);
343285 boolean hasNameOffset = hasFlag(MDR7_HAS_NAME_OFFSET);
344286 Collator collator = sort.getCollator();
345 // int partialBShift = ((getExtraValue() >> 9) & 0xf);
346287 collator.setStrength(Collator.SECONDARY);
347288 Mdr7Record last = null;
348289 for (Mdr7Record s : streets) {
363304 writer.put1u(s.getOutNameOffset());
364305 if (partialInfoSize > 0) {
365306 int trailingFlags = ((rr & 1) == 0) ? 1 : 0;
366 // trailingFlags |= s.getB() << 1;
367 // trailingFlags |= s.getS() << (1 + partialBShift);
368307 writer.putNu(partialInfoSize, trailingFlags);
369308 }
370309 last = s;
1212 package uk.me.parabola.imgfmt.app.mdr;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.app.srt.Sort;
8584 }
8685
8786 /**
88 * Sort records that are sorted by a name. They appropriate sort order will be used.
87 * Sort records that are to be sorted by a name. The appropriate sort order will be used.
8988 * @param sort The sort to be applied.
9089 * @param list The list to be sorted.
9190 * @param <T> One of the Mdr?Record types that need to be sorted on a text field, eg street name.
9392 * by calling getObject().
9493 */
9594 public static <T extends NamedRecord> List<SortKey<T>> sortList(Sort sort, List<T> list) {
96 List<SortKey<T>> toSort = new ArrayList<SortKey<T>>(list.size());
95 List<SortKey<T>> toSort = new ArrayList<>(list.size());
9796 for (T m : list) {
9897 SortKey<T> sortKey = sort.createSortKey(m, m.getName(), m.getMapIndex());
9998 toSort.add(sortKey);
10099 }
101 Collections.sort(toSort);
100 toSort.sort(null);
102101 return toSort;
103102 }
104103
1212 package uk.me.parabola.imgfmt.app.net;
1313
1414 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
1715 import java.util.HashSet;
1816 import java.util.Iterator;
1917 import java.util.List;
149147 if (n <= 1)
150148 return;
151149 // sort the arcs by initial heading
152 Collections.sort(arcGroups, new Comparator<ArcGroup>() {
153 public int compare(ArcGroup ag1, ArcGroup ag2) {
154 if (ag1.initialHeading < ag2.initialHeading)
155 return -1;
156 if (ag1.initialHeading > ag2.initialHeading)
157 return 1;
158 return 0;
159 }
160 });
150 arcGroups.sort((ag1, ag2) -> Float.compare(ag1.initialHeading, ag2.initialHeading));
161151
162152 class AngleAttr {
163153 int angle;
359349 return arcGroups; // should not happen
360350
361351 // sort the arcs by initial heading
362 Collections.sort(directArcs, new Comparator<RouteArc>() {
363 public int compare(RouteArc ra1, RouteArc ra2) {
364 if (ra1.getInitialHeading() < ra2.getInitialHeading())
365 return -1;
366 if (ra1.getInitialHeading() > ra2.getInitialHeading())
367 return 1;
368 int d = Integer.compare(ra1.getPointsHash(), ra2.getPointsHash());
369 if (d != 0)
370 return d;
371 d = Long.compare(ra1.getRoadDef().getId() , ra2.getRoadDef().getId());
372 if (d != 0)
373 return d;
374 return d;
375 }
376 });
377
352 directArcs.sort((ra1,ra2) -> {
353 int d = Float.compare(ra1.getInitialHeading(), ra2.getInitialHeading());
354 if (d != 0)
355 return d;
356 d = Integer.compare(ra1.getPointsHash(), ra2.getPointsHash());
357 if (d != 0)
358 return d;
359 d = Long.compare(ra1.getRoadDef().getId() , ra2.getRoadDef().getId());
360 if (d != 0)
361 return d;
362 return d;
363 });
364
378365 Iterator<RouteArc> iter = directArcs.listIterator();
379366 RouteArc arc1 = iter.next();
380367 boolean addArc1 = false;
1616 package uk.me.parabola.imgfmt.app.net;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
2119 import java.util.HashMap;
2220 import java.util.List;
2321 import java.util.Map;
125123
126124 // Sort by name, city, region/country and subdivision number.
127125 LabeledRoadDef lrd = new LabeledRoadDef(label, rd);
128 SortKey<LabeledRoadDef> nameKey = new IntegerSortKey<NETFile.LabeledRoadDef>(lrd, label.getOffset(), 0);
126 SortKey<LabeledRoadDef> nameKey = new IntegerSortKey<>(lrd, label.getOffset(), 0);
129127 // If there is a city add it to the sort.
130128 City city = (rd.getCities().isEmpty() ? null : rd.getCities().get(0)); // what if we more than one?
131129 SortKey<LabeledRoadDef> cityKey;
144142 }
145143 }
146144
147 Collections.sort(sortKeys);
145 sortKeys.sort(null);
148146
149147 List<LabeledRoadDef> out = new ArrayList<>(sortKeys.size());
150148
193191 SortKey<LabeledRoadDef> sk2 = sort.createSortKey(null, lrd.label, 0, cacheFull);
194192 sortKeys.add(new DoubleSortKey<>(sk1, sk2));
195193 }
196 Collections.sort(sortKeys);
194 sortKeys.sort(null);
197195 roads.clear();
198196 for (SortKey<LabeledRoadDef> key : sortKeys) {
199197 roads.add(key.getObject());
278276 * @param out List to add the discovered groups.
279277 */
280278 private void addDisconnectedLarge(List<LabeledRoadDef> in, List<LabeledRoadDef> out) {
281 Collections.sort(in, new Comparator<LabeledRoadDef>() {
282 public int compare(LabeledRoadDef o1, LabeledRoadDef o2) {
283 Integer i1 = o1.roadDef.getStartSubdivNumber();
284 Integer i2 = o2.roadDef.getStartSubdivNumber();
285 return i1.compareTo(i2);
286 }
287 });
279 in.sort((o1, o2) -> Integer.compare(o1.roadDef.getStartSubdivNumber(), o2.roadDef.getStartSubdivNumber()));
288280
289281 int lastDiv = 0;
290282 List<LabeledRoadDef> dupes = new ArrayList<>();
1111 */
1212 package uk.me.parabola.imgfmt.app.net;
1313
14 import it.unimi.dsi.fastutil.ints.IntArrayList;
15
1614 import java.util.ArrayList;
17 import java.util.Collections;
1815 import java.util.HashMap;
1916 import java.util.HashSet;
2017 import java.util.List;
2118 import java.util.Map;
2219 import java.util.Set;
2320
21 import it.unimi.dsi.fastutil.ints.IntArrayList;
2422 import uk.me.parabola.imgfmt.Utils;
2523 import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
2624 import uk.me.parabola.imgfmt.app.ImgFile;
286284 // Sort in address order in the hope of speeding up reading.
287285 List<Integer> offsets = new ArrayList<>(allOffsets);
288286 allOffsets = null;
289 Collections.sort(offsets);
287 offsets.sort(null);
290288 return offsets;
291289 }
292290
1616 package uk.me.parabola.imgfmt.app.net;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
2119 import java.util.LinkedHashMap;
2220 import java.util.LinkedList;
2321 import java.util.List;
328326 * be a legal RouteCenter.
329327 */
330328 private RouteCenter toRouteCenter() {
331 Collections.sort(nodes, new Comparator<RouteNode>() {
332 public int compare(RouteNode n1, RouteNode n2) {
333 return n1.getCoord().compareTo(n2.getCoord());
334 }
335 });
329 nodes.sort((n1, n2) -> n1.getCoord().compareTo(n2.getCoord()));
336330 TableB tabB = new TableB();
337331 for (RouteNode rn : destNodes.keySet())
338332 tabB.addNode(rn);
1616 package uk.me.parabola.imgfmt.app.net;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
2019 import java.util.List;
2120
2221 import uk.me.parabola.imgfmt.app.BufferedImgFileReader;
134133 private void writeBoundary() {
135134 log.info("writeBoundary");
136135
137 Collections.sort(boundary);
136 boundary.sort(null);
138137
139138 ImgFileWriter writer = new SectionWriter(getWriter(), nodHeader.getBoundarySection());
140139
155154 */
156155 private void writeHighClassBoundary() {
157156 log.info("writeBoundary");
158
159 // Collections.sort(boundary); // already sorted for NOD3
160157
161158 Section section = nodHeader.getHighClassBoundary();
162159 int pos = section.getPosition();
2828 import uk.me.parabola.imgfmt.MapFailedException;
2929 import uk.me.parabola.imgfmt.Utils;
3030 import uk.me.parabola.imgfmt.app.BitWriter;
31 import uk.me.parabola.imgfmt.app.Coord;
3231 import uk.me.parabola.imgfmt.app.ImgFileWriter;
3332 import uk.me.parabola.imgfmt.app.Label;
3433 import uk.me.parabola.imgfmt.app.lbl.City;
617617 return added;
618618 }
619619
620 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) {
621 RouteNode node = nodes.get(junctionNodeId);
622 assert node != null : "Can't find node with id " + junctionNodeId;
623
624 node.addThroughRoute(roadIdA, roadIdB);
625 }
626
627620 /**
628621 * Calculate the "angle" between to arcs. The arcs may not be connected.
629622 * We do this by "virtually" moving the toArc so that its source
6464 private final CoordNode coord;
6565 private int latOff;
6666 private int lonOff;
67 private List<RouteArc[]> throughRoutes;
6867
6968 // contains the maximum of roads this node is on, written with the flags
7069 // field. It is also used for the calculation of the destination class on
673672 }
674673 }
675674 }
676 }
677
678 public void addThroughRoute(long roadIdA, long roadIdB) {
679 if(throughRoutes == null)
680 throughRoutes = new ArrayList<>();
681 boolean success = false;
682 for(RouteArc arc1 : arcs) {
683 if(arc1.getRoadDef().getId() == roadIdA) {
684 for(RouteArc arc2 : arcs) {
685 if(arc2.getRoadDef().getId() == roadIdB) {
686 throughRoutes.add(new RouteArc[] { arc1.getReverseArc(), arc2 });
687 success = true;
688 break;
689 }
690 }
691 }
692 else if(arc1.getRoadDef().getId() == roadIdB) {
693 for(RouteArc arc2 : arcs) {
694 if(arc2.getRoadDef().getId() == roadIdA) {
695 throughRoutes.add(new RouteArc[] { arc1.getReverseArc(), arc2 });
696 success = true;
697 break;
698 }
699 }
700 }
701 }
702 /*
703 for(RouteArc arc1 : incomingArcs) {
704 if(arc1.getRoadDef().getId() == roadIdA) {
705 for(RouteArc arc2 : arcs) {
706 if(arc2.getRoadDef().getId() == roadIdB) {
707 throughRoutes.add(new RouteArc[] { arc1, arc2 });
708 success = true;
709 break;
710 }
711 }
712 }
713 else if(arc1.getRoadDef().getId() == roadIdB) {
714 for(RouteArc arc2 : arcs) {
715 if(arc2.getRoadDef().getId() == roadIdA) {
716 throughRoutes.add(new RouteArc[] { arc1, arc2 });
717 success = true;
718 break;
719 }
720 }
721 }
722 }
723 */
724 if(success)
725 log.info("Added through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL());
726 else
727 log.warn("Failed to add through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL() + " - perhaps they don't meet here?");
728675 }
729676
730677 /**
1818 import java.text.DecimalFormat;
1919 import java.text.ParsePosition;
2020 import java.util.ArrayList;
21 import java.util.Collections;
2221 import java.util.List;
2322 import java.util.Map;
2423
410409 break;
411410 }
412411 // sort the lights by increasing sector start angle
413 Collections.sort(lights);
412 lights.sort(null);
414413 // generate the descriptor string - each light is
415414 // specified as color,range,sectorStartAngle
416415 String light = null;
1616 package uk.me.parabola.imgfmt.app.trergn;
1717
1818 import java.util.ArrayList;
19 import java.util.Collections;
2019 import java.util.Iterator;
2120 import java.util.List;
2221
225224 header.setPointPos(position());
226225
227226 // Point overview section
228 Collections.sort(pointOverviews);
227 pointOverviews.sort(null);
229228 for (Overview ov : pointOverviews) {
230229 if(!ov.hasExtType()) {
231230 ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
236235
237236 // Line overview section.
238237 header.setPolylinePos(position());
239 Collections.sort(polylineOverviews);
238 polylineOverviews.sort(null);
240239 for (Overview ov : polylineOverviews) {
241240 if(!ov.hasExtType()) {
242241 ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
247246
248247 // Polygon overview section
249248 header.setPolygonPos(position());
250 Collections.sort(polygonOverviews);
249 polygonOverviews.sort(null);
251250 for (Overview ov : polygonOverviews) {
252251 if(!ov.hasExtType()) {
253252 ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
2121 import java.nio.charset.CharacterCodingException;
2222 import java.nio.charset.CharsetEncoder;
2323 import java.util.ArrayList;
24 import java.util.Collections;
2524 import java.util.List;
2625 import java.util.Map;
2726 import java.util.TreeMap;
10099 keys.add(key);
101100 }
102101 }
103 Collections.sort(keys);
102 keys.sort(null);
104103
105104 // Offset 0 is reserved to mean no label.
106105 writer.put1u(0);
159158 private void writeSection(ImgFileWriter writer, Section dataSection, Section indexSection,
160159 List<? extends TypElement> elementData)
161160 {
162 Collections.sort(elementData);
161 elementData.sort(null);
163162
164163 SectionWriter subWriter = dataSection.makeSectionWriter(writer);
165164 CharsetEncoder encoder = data.getEncoder();
2020 import java.nio.channels.FileChannel;
2121 import java.nio.channels.WritableByteChannel;
2222 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
2523 import java.util.List;
2624
2725 /**
3634 private final char familyId;
3735 private final char productId;
3836
39 private final List<MapInfo> maps = new ArrayList<MapInfo>();
37 private final List<MapInfo> maps = new ArrayList<>();
4038
4139 /**
4240 * Create with default family and product ids.
9896
9997 private void writeBody(WritableByteChannel chan, ByteBuffer buf) throws IOException {
10098 // Sort the maps by the hex number.
101 Collections.sort(maps, new Comparator<MapInfo>() {
102 public int compare(MapInfo o1, MapInfo o2) {
103 if (o1.getHexMapname() == o2.getHexMapname())
104 return 0;
105 else if (o1.getHexMapname() < o2.getHexMapname())
106 return -1;
107 else
108 return 1;
109 }
110 });
99 maps.sort((o1, o2) -> Integer.compare(o1.getHexMapname(), o2.getHexMapname()));
111100
112101 for (MapInfo info : maps) {
113102 // Although its not necessarily wrong for them to be zero, it probably
2323 import java.util.ArrayList;
2424 import java.util.Arrays;
2525 import java.util.Collections;
26 import java.util.Comparator;
2726 import java.util.HashMap;
2827 import java.util.IdentityHashMap;
2928 import java.util.List;
3029 import java.util.Set;
3130 import java.util.function.UnaryOperator;
3231
32 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
3333 import uk.me.parabola.imgfmt.ExitException;
3434 import uk.me.parabola.imgfmt.MapFailedException;
3535 import uk.me.parabola.imgfmt.Utils;
103103 import uk.me.parabola.util.Configurable;
104104 import uk.me.parabola.util.EnhancedProperties;
105105 import uk.me.parabola.util.Java2DConverter;
106 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
107106
108107 /**
109108 * This is the core of the code to translate from the general representation
12251224
12261225 if (orderByDecreasingArea && shapes.size() > 1) {
12271226 // sort so that the shape with the largest area is processed first
1228 Collections.sort(shapes, new Comparator<MapShape>() {
1229 public int compare(MapShape s1, MapShape s2) {
1230 return Long.compare(Math.abs(s2.getFullArea()), Math.abs(s1.getFullArea()));
1231 }
1232 });
1227 shapes.sort((s1,s2) -> Long.compare(Math.abs(s2.getFullArea()), Math.abs(s1.getFullArea())));
12331228 }
12341229
12351230 preserveHorizontalAndVerticalLines(res, shapes);
7575 * @param exceptMask For exceptions eg. no-left-turn except for buses.
7676 */
7777 public int addRestriction(GeneralRouteRestriction grr);
78 }
7879
79 /**
80 * Add a through route to the map.
81 *
82 */
83 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB);
84 }
129129 return roadNetwork.addRestriction(grr);
130130 }
131131
132 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) {
133 roadNetwork.addThroughRoute(junctionNodeId, roadIdA, roadIdB);
134 }
135
136132 /**
137133 * Add the given point to the total bounds for the map.
138134 *
2727 import java.time.Instant;
2828 import java.util.ArrayList;
2929 import java.util.Arrays;
30 import java.util.Comparator;
3130 import java.util.Date;
3231 import java.util.HashMap;
3332 import java.util.HashSet;
603602 for (Combiner c : combiners)
604603 c.init(args);
605604
606 filenames.sort(new Comparator<FilenameTask>() {
607 public int compare(FilenameTask o1, FilenameTask o2) {
608 if (!o1.getFilename().endsWith(".img") || !o2.getFilename().endsWith(".img"))
609 return o1.getFilename().compareTo(o2.getFilename());
610
611 // Both end in .img
612 try {
613 int id1 = FileInfo.getFileInfo(o1.getFilename()).getHexname();
614 int id2 = FileInfo.getFileInfo(o2.getFilename()).getHexname();
615 if (id1 == id2)
616 return 0;
617 else if (id1 < id2)
618 return -1;
619 else
620 return 1;
621 } catch (FileNotFoundException ignored) {
622 }
623 return 0;
624 }
625
605 filenames.sort((o1, o2) -> {
606 if (!o1.getFilename().endsWith(".img") || !o2.getFilename().endsWith(".img"))
607 return o1.getFilename().compareTo(o2.getFilename());
608
609 // Both end in .img
610 try {
611 return Integer.compare(FileInfo.getFileInfo(o1.getFilename()).getHexname(),
612 FileInfo.getFileInfo(o2.getFilename()).getHexname());
613 } catch (FileNotFoundException ignored) {
614 }
615 return 0;
626616 });
627617
628618 // will contain img files for which an additional ovm file was found
3535 import javax.xml.parsers.ParserConfigurationException;
3636 import javax.xml.parsers.SAXParser;
3737 import javax.xml.parsers.SAXParserFactory;
38
39 import org.xml.sax.SAXException;
3840
3941 import uk.me.parabola.imgfmt.FormatException;
4042 import uk.me.parabola.imgfmt.Utils;
7880 import uk.me.parabola.mkgmap.scan.TokenScanner;
7981 import uk.me.parabola.util.EnhancedProperties;
8082
81 import org.xml.sax.SAXException;
82
8383
8484 /**
8585 * Test style rules by converting to a text format, rather than a .img file.
391391 */
392392 private static List<String> formatResults(String prefix, List<MapElement> lines) {
393393 List<String> result = new ArrayList<>();
394 int i = 0;
395394 for (MapElement el : lines) {
396395 String s;
397396 // So we can run against versions that do not have toString() methods
838837 public int addRestriction(GeneralRouteRestriction grr) {
839838 return 0;
840839 }
841
842 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) {
843 }
844840 }
845841
846842 /**
882878 return 0;
883879 }
884880
885 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) {
886 }
887
888881 public long getStart() {
889882 return start;
890883 }
1818 import java.util.ArrayList;
1919 import java.util.Arrays;
2020 import java.util.Collections;
21 import java.util.Comparator;
2221 import java.util.HashMap;
2322 import java.util.HashSet;
2423 import java.util.LinkedHashSet;
313312 * @param strings
314313 */
315314 private void sortByLength(List<String> strings) {
316 strings.sort(new Comparator<String>() {
317 @Override
318 public int compare(String o1, String o2) {
319 return Integer.compare(o2.length(), o1.length());
320 }
321 });
315 strings.sort((o1, o2) -> Integer.compare(o2.length(), o1.length()));
322316 }
323317 }
1515 import java.util.ArrayList;
1616 import java.util.Arrays;
1717 import java.util.Collections;
18 import java.util.Comparator;
1918 import java.util.HashSet;
2019 import java.util.IdentityHashMap;
2120 import java.util.List;
2726 import uk.me.parabola.imgfmt.app.Coord;
2827 import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits;
2928 import uk.me.parabola.log.Logger;
30 import uk.me.parabola.mkgmap.reader.osm.Element;
3129 import uk.me.parabola.mkgmap.reader.osm.GType;
32 import uk.me.parabola.mkgmap.reader.osm.Node;
33 import uk.me.parabola.mkgmap.reader.osm.Relation;
3430 import uk.me.parabola.mkgmap.reader.osm.RestrictionRelation;
3531 import uk.me.parabola.mkgmap.reader.osm.Way;
3632 import uk.me.parabola.util.MultiIdentityHashMap;
5753 /**
5854 * For these tags two ways need to have an equal value so that their roads can be merged.
5955 */
60 private final static Set<String> mergeTagsEqualValue = new HashSet<>(Arrays.asList(
56 private static final Set<String> mergeTagsEqualValue = new HashSet<>(Arrays.asList(
6157 "mkgmap:label:1",
6258 "mkgmap:label:2",
6359 "mkgmap:label:3",
109105 }
110106 }
111107
112 private void workoutThroughRoutes(List<Relation> throughRouteRelations) {
113 for (Relation relation : throughRouteRelations) {
114 Node node = null;
115 Way w1 = null;
116 Way w2 = null;
117 for (Map.Entry<String, Element> member : relation.getElements()) {
118 if (member.getValue() instanceof Node) {
119 if (node == null)
120 node = (Node) member.getValue();
121 else
122 log.warn("Through route relation "
123 + relation.toBrowseURL()
124 + " has more than 1 node");
125 } else if (member.getValue() instanceof Way) {
126 Way w = (Way) member.getValue();
127 if (w1 == null)
128 w1 = w;
129 else if (w2 == null)
130 w2 = w;
131 else
132 log.warn("Through route relation "
133 + relation.toBrowseURL()
134 + " has more than 2 ways");
135 }
136 }
137
138 if (node == null)
139 log.warn("Through route relation " + relation.toBrowseURL()
140 + " is missing the junction node");
141
142 if (w1 == null || w2 == null)
143 log.warn("Through route relation "
144 + relation.toBrowseURL()
145 + " should reference 2 ways that meet at the junction node");
146
147 if (node != null && w1 != null && w2 != null) {
148 restrictions.add(node.getLocation(), w1.getId());
149 restrictions.add(node.getLocation(), w2.getId());
150 }
151 }
152 }
153
154108 private boolean hasRestriction(Coord c, Way w) {
155109 if (w.isViaWay())
156110 return true;
170124 private void mergeRoads(ConvertedWay road1, ConvertedWay road2) {
171125 // Removes the second line,
172126 // Merges the points in the first one
173 List<Coord> points1 = road1.getWay().getPoints();
174127 List<Coord> points2 = road2.getWay().getPoints();
175
176128 Coord mergePoint = points2.get(0);
177129 Coord endPoint= points2.get(points2.size()-1);
178130
180132 endPoints.removeMapping(endPoint, road2);
181133 endPoints.removeMapping(mergePoint, road1);
182134
183 points1.addAll(points2.subList(1, points2.size()));
135 road1.getPoints().addAll(points2.subList(1, points2.size()));
184136 endPoints.add(endPoint, road1);
185137
186138 // merge the POI info
187139 String wayPOI2 = road2.getWay().getTag(StyledConverter.WAY_POI_NODE_IDS);
188140 if (wayPOI2 != null){
189 String WayPOI1 = road1.getWay().getTag(StyledConverter.WAY_POI_NODE_IDS);
190 if (wayPOI2.equals(WayPOI1) == false){
191 if (WayPOI1 == null)
192 WayPOI1 = "";
141 String wayPOI1 = road1.getWay().getTag(StyledConverter.WAY_POI_NODE_IDS);
142 if (!wayPOI2.equals(wayPOI1)){
143 if (wayPOI1 == null)
144 wayPOI1 = "";
193145 // store combination of both ways. This might contain
194146 // duplicates, but that is not a problem.
195 road1.getWay().addTag(StyledConverter.WAY_POI_NODE_IDS, WayPOI1 + wayPOI2);
196 }
197 }
198
199 // // the mergePoint is now used by one highway less
147 road1.getWay().addTag(StyledConverter.WAY_POI_NODE_IDS, wayPOI1 + wayPOI2);
148 }
149 }
150
151 // the mergePoint is now used by one highway less
200152 mergePoint.decHighwayCount();
201153
202154 // road2 is removed - it must not be part of a restriction
203 assert (restrictions.get(endPoint).contains(road2.getWay().getId()) == false);
155 assert !restrictions.get(endPoint).contains(road2.getWay().getId());
204156
205157 }
206158
210162 * @param resultingGTypes list for the merged (and not mergeable) GTypes
211163 */
212164 public List<ConvertedWay> merge(List<ConvertedWay> convertedWays,
213 List<RestrictionRelation> restrictions,
214 List<Relation> throughRouteRelations) {
165 List<RestrictionRelation> restrictions) {
215166 List<ConvertedWay> result = new ArrayList<>();
216167 List<ConvertedWay> roadsToMerge = new ArrayList<>(convertedWays.size());
217168 for (int i = 0; i < convertedWays.size(); i++) {
221172 }
222173
223174 int noRoadsBeforeMerge = roadsToMerge.size();
224 int noMerges = 0;
175 int numMerges = 0;
225176
226177 List<Coord> mergePoints = new ArrayList<>();
227178
228179 // first add all roads with their start and end points to the
229180 // start/endpoint lists
230181 for (ConvertedWay road : roadsToMerge) {
231 List<Coord> points = road.getWay().getPoints();
232 Coord start = points.get(0);
233 Coord end = points.get(points.size() - 1);
182 Coord start = road.getWay().getFirstPoint();
183 Coord end = road.getWay().getLastPoint();
234184
235185 if (start == end) {
236186 // do not merge closed roads
244194 endPoints.add(end, road);
245195 }
246196 workoutRestrictionRelations(restrictions);
247 workoutThroughRoutes(throughRouteRelations);
248197
249198 // a set of all points where no more merging is possible
250199 Set<Coord> mergeCompletedPoints = Collections.newSetFromMap(new IdentityHashMap<Coord, Boolean>());
280229 continue;
281230 }
282231
283 List<Coord> points1 = road1.getWay().getPoints();
232 List<Coord> points1 = road1.getPoints();
284233
285234 // go through all candidates to merge
286235 for (ConvertedWay road2 : startRoads) {
287 if (hasRestriction(mergePoint, road2.getWay())) {
288 continue;
289 }
290 List<Coord> points2 = road2.getWay().getPoints();
291236
292237 // the second road is merged into the first road
293238 // so only the id of the first road is kept
294239 // This also means that the second road must not have a restriction on
295240 // both start and end point
296 if (hasRestriction(points2.get(points2.size()-1), road2.getWay())) {
241 if (hasRestriction(mergePoint, road2.getWay())
242 || hasRestriction(road2.getWay().getLastPoint(), road2.getWay())) {
297243 continue;
298244 }
299245
302248 // yes they might be merged
303249 // calculate the angle between them
304250 // if there is more then one road to merge the one with the lowest angle is merged
305 double angle = Math.abs(Utils.getAngle(points1.get(points1.size()-2), mergePoint, points2.get(1)));
251 double angle = Math.abs(Utils.getAngle(points1.get(points1.size()-2), mergePoint, road2.getPoints().get(1)));
306252 log.debug("Road",road1.getWay().getId(),"and road",road2.getWay().getId(),"are mergeable with angle",angle);
307253 if (angle < bestAngle) {
308254 mergeRoad1 = road1;
318264 // yes!! => merge them
319265 log.debug("Merge",mergeRoad1.getWay().getId(),"and",mergeRoad2.getWay().getId(),"with angle",bestAngle);
320266 mergeRoads(mergeRoad1, mergeRoad2);
321 noMerges++;
267 numMerges++;
322268 } else {
323 // no => do not check again this point again
269 // no => do not check this point again
324270 mergeCompletedPoints.add(mergePoint);
325271 }
326272 }
331277 }
332278
333279 // sort the roads to ensure that the order of roads is constant for two runs
334 Collections.sort(result, new Comparator<ConvertedWay>() {
335 public int compare(ConvertedWay o1, ConvertedWay o2) {
336 return Integer.compare(o1.getIndex(), o2.getIndex());
337 }
338 });
280 result.sort((o1, o2) -> Integer.compare(o1.getIndex(), o2.getIndex()));
339281
340282 // print out some statistics
341283 int noRoadsAfterMerge = result.size();
343285 noRoadsAfterMerge);
344286 int percentage = (int) Math.round((noRoadsBeforeMerge - noRoadsAfterMerge) * 100.0d
345287 / noRoadsBeforeMerge);
346 log.info("Road network reduced by", percentage, "%",noMerges,"merges");
288 log.info("Road network reduced by", percentage, "%",numMerges,"merges");
347289 return result;
348290 }
349291
358300 */
359301 private static boolean isMergeable(Coord mergePoint, ConvertedWay road1, ConvertedWay road2) {
360302 // check if basic road attributes match
361 if (road1.getRoadClass() != road2.getRoadClass())
362 return false;
363 if (road1.getRoadSpeed() != road2.getRoadSpeed())
364 return false;
303 if (road1.getRoadClass() != road2.getRoadClass() || road1.getRoadSpeed() != road2.getRoadSpeed()) {
304 return false;
305 }
365306 Way way1 = road1.getWay();
366307 Way way2 = road2.getWay();
367308
380321 return false;
381322 }
382323
324 if (!checkGeometry(mergePoint, road1, road2))
325 return false;
326
327 if (!isGTypeMergeable(road1.getGType(), road2.getGType())) {
328 return false;
329 }
330
331 if (!isWayTagsMergeable(way1, way2))
332 return false;
333
334 return isAngleOK(mergePoint, way1, way2);
335 }
336
337
338 /**
339 * Check if roads meet at the given point and don't form a loop or a bad oneway combination
340 * @param mergePoint the mergePoint
341 * @param road1 first road
342 * @param road2 second road
343 * @return true if roads can be merged, else false
344 */
345 private static boolean checkGeometry(Coord mergePoint, ConvertedWay road1, ConvertedWay road2) {
346 Way way1 = road1.getWay();
347 Way way2 = road2.getWay();
383348 // now check if this road starts or stops at the mergePoint
384 Coord cStart = road1.getWay().getPoints().get(0);
385 Coord cEnd = road1.getWay().getPoints().get(road1.getWay().getPoints().size() - 1);
349 Coord cStart = way1.getFirstPoint();
350 Coord cEnd = way1.getLastPoint();
386351 if (cStart != mergePoint && cEnd != mergePoint) {
387352 // it doesn't => roads not mergeable at mergePoint
388353 return false;
389354 }
390355
391356 // do the same check for the otherRoad
392 Coord cOtherStart = way2.getPoints().get(0);
393 Coord cOtherEnd = way2.getPoints()
394 .get(way2.getPoints().size() - 1);
357 Coord cOtherStart = way2.getFirstPoint();
358 Coord cOtherEnd = way2.getLastPoint();
395359 if (cOtherStart != mergePoint && cOtherEnd != mergePoint) {
396360 // otherRoad does not start or stop at mergePoint =>
397361 // roads not mergeable at mergePoint
401365 // check if merging would create a closed way - which should not
402366 // be done (why? WanMil)
403367 if (cStart == cOtherEnd) {
404 return false;
405 }
406
407 // check if certain fields in the GType objects are the same
408 if (isGTypeMergeable(road1.getGType(), road2.getGType()) == false) {
409368 return false;
410369 }
411370
419378 return false;
420379 }
421380 }
422
423 // checks if the tag values of both ways match so that the ways
424 // can be merged
425 if (isWayMergeable(mergePoint, way1, way2) == false)
426 return false;
427
428
429 // check if the angle between the two ways is not too sharp
430 if (isAngleOK(mergePoint, way1, way2) == false)
431 return false;
432
433381 return true;
434382 }
435383
465413 * objects do not match and must not be merged
466414 */
467415 private static boolean isGTypeMergeable(GType type1, GType type2) {
468 if (type1.getType() != type2.getType()) {
469 return false;
470 }
471 if (type1.getMinResolution() != type2.getMinResolution()) {
472 return false;
473 }
474 if (type1.getMaxResolution() != type2.getMaxResolution()) {
475 return false;
476 }
477 if (type1.getMinLevel() != type2.getMinLevel()) {
478 return false;
479 }
480 if (type1.getMaxLevel() != type2.getMaxLevel()) {
481 return false;
482 }
416 return type1.getType() == type2.getType()
417 && type1.getMinResolution() == type2.getMinResolution()
418 && type1.getMaxResolution() == type2.getMaxResolution()
419 && type1.getMinLevel() == type2.getMinLevel()
420 && type1.getMaxLevel() == type2.getMaxLevel();
483421 // roadClass and roadSpeed are taken from the ConvertedWay objects
484 //
485 //default name is applied before the RoadMerger starts
486 //so they needn't be equal
487 // if (stringEquals(gtype.getDefaultName(),
488 // otherGType.getDefaultName()) == false) {
489 // return false;
490 // }
491
492 // log.info("Matches");
493 return true;
494422 }
495423
496424 /**
497425 * Checks if the tag values of the {@link Way} objects of both roads
498426 * match so that both roads can be merged.
499 * @param mergePoint the coord where both roads should be merged
500427 * @param way1 1st way
501428 * @param way2 2nd way
502429 * @return {@code true} tag values match so that both roads might be merged;
503430 * {@code false} tag values differ so that road must not be merged
504431 */
505 private static boolean isWayMergeable(Coord mergePoint, Way way1, Way way2) {
432 private static boolean isWayTagsMergeable(Way way1, Way way2) {
506433 // tags that need to have an equal value
507434 for (String tagname : mergeTagsEqualValue) {
508435 String tag1 = way1.getTag(tagname);
509436 String tag2 = way2.getTag(tagname);
510 if (stringEquals(tag1, tag2) == false) {
437 if (!stringEquals(tag1, tag2)) {
511438 if (log.isDebugEnabled()){
512439 log.debug(tagname, "does not match", way1.getId(), "("
513440 + tag1 + ")", way2.getId(), "(" + tag2
531458 private static boolean isAngleOK(Coord mergePoint, Way way1, Way way2) {
532459 // Check the angle of the two ways
533460 Coord cOnWay1;
534 if (way1.getPoints().get(0) == mergePoint) {
461 if (way1.getFirstPoint() == mergePoint) {
535462 cOnWay1 = way1.getPoints().get(1);
536463 } else {
537464 cOnWay1 = way1.getPoints().get(way1.getPoints().size() - 2);
538465 }
539466 Coord cOnWay2;
540 if (way2.getPoints().get(0) == mergePoint) {
467 if (way2.getFirstPoint() == mergePoint) {
541468 cOnWay2 = way2.getPoints().get(1);
542469 } else {
543 cOnWay2 = way2.getPoints().get(
544 way2.getPoints().size() - 2);
470 cOnWay2 = way2.getPoints().get(way2.getPoints().size() - 2);
545471 }
546472
547473 double angle = Math.abs(Utils.getAngle(cOnWay1, mergePoint, cOnWay2));
101101
102102 private Map<Node, List<Way>> poiRestrictions = new LinkedHashMap<>();
103103
104 private final List<Relation> throughRouteRelations = new ArrayList<>();
105
106104 // limit line length to avoid problems with portions of really
107105 // long lines being assigned to the wrong subdivision
108106 private static final int MAX_LINE_LENGTH = 40000;
340338 rules = polygonRules;
341339 else {
342340 if (way.isClosedInOSM() && !way.isComplete() && !way.hasIdenticalEndPoints())
343 way.getPoints().add(way.getPoints().get(0));
341 way.getPoints().add(way.getFirstPoint());
344342
345 if (way.hasIdenticalEndPoints() == false || way.getPoints().size() < 4)
343 if (!way.hasIdenticalEndPoints() || way.getPoints().size() < 4)
346344 rules = lineRules;
347345 else
348346 rules = wayRules;
457455 }
458456 if (cw.isRoundabout()) {
459457 if (wasReversed)
460 log.warn("Roundabout", way.getId(), "has reverse oneway tag (" + way.getPoints().get(0).toOSMURL() + ")");
458 log.warn("Roundabout", way.getId(), "has reverse oneway tag (" + way.getFirstPoint().toOSMURL() + ")");
461459 }
462460 lastRoadId = way.getId();
463461 }
655653 continue;
656654
657655 // the bounding box of the road intersects with one or more bounding boxes of borders
658 Coord pw1 = way.getPoints().get(0);
656 Coord pw1 = way.getFirstPoint();
659657 int pos = 1;
660658 while (pos < way.getPoints().size()) {
661659 boolean changed = false;
748746 }
749747
750748 RoadMerger merger = new RoadMerger();
751 roads = merger.merge(roads, restrictions, throughRouteRelations);
749 roads = merger.merge(roads, restrictions);
752750 }
753751
754752 public void end() {
824822 rr.addRestriction(collector, nodeIdMap);
825823 }
826824 }
825 // return memory to GC
827826 roads = null;
828 if (routable){
829 for(Relation relation : throughRouteRelations) {
830 Node node = null;
831 Way w1 = null;
832 Way w2 = null;
833 for(Map.Entry<String,Element> member : relation.getElements()) {
834 if(member.getValue() instanceof Node) {
835 if(node == null)
836 node = (Node)member.getValue();
837 else
838 log.warn("Through route relation", relation.toBrowseURL(), "has more than 1 node");
839 }
840 else if(member.getValue() instanceof Way) {
841 Way w = (Way)member.getValue();
842 if(w1 == null)
843 w1 = w;
844 else if(w2 == null)
845 w2 = w;
846 else
847 log.warn("Through route relation", relation.toBrowseURL(), "has more than 2 ways");
848 }
849 }
850
851 CoordNode coordNode = null;
852 if(node == null)
853 log.warn("Through route relation", relation.toBrowseURL(), "is missing the junction node");
854 else {
855 Coord junctionPoint = node.getLocation();
856 if(bbox != null && !bbox.contains(junctionPoint)) {
857 // junction is outside of the tile - ignore it
858 continue;
859 }
860 coordNode = nodeIdMap.get(junctionPoint);
861 if(coordNode == null)
862 log.warn("Through route relation", relation.toBrowseURL(), "junction node at", junctionPoint.toOSMURL(), "is not a routing node");
863 }
864
865 if(w1 == null || w2 == null)
866 log.warn("Through route relation", relation.toBrowseURL(), "should reference 2 ways that meet at the junction node");
867
868 if(coordNode != null && w1 != null && w2 != null)
869 collector.addThroughRoute(coordNode.getId(), w1.getId(), w2.getId());
870 }
871 }
872 // return memory to GC
873827 nodeIdMap = null;
874 throughRouteRelations.clear();
875828 restrictions.clear();
876
877829 }
878830
879831 /**
11151067 for (long id : rr.getWayIds())
11161068 wayRelMap.add(id, rr);
11171069 }
1118 }
1119 else if("through_route".equals(relation.getTag("type"))) {
1120 throughRouteRelations.add(relation);
11211070 } else if (addBoundaryNodesAtAdminBoundaries) {
11221071 if (relation instanceof MultiPolygonRelation || "boundary".equals(relation.getTag("type"))) {
11231072 if (isNod3Border(relation)) {
14191368 String roadClass = node.getTag("mkgmap:road-class");
14201369 String roadSpeed = node.getTag("mkgmap:road-speed");
14211370 if(roadClass != null || roadSpeed != null) {
1422 // find good split point after POI
1423 Coord splitPoint;
1424 double segmentLength = 0;
1425 int splitPos = i+1;
1426 while( splitPos+1 < points.size()){
1427 splitPoint = points.get(splitPos);
1428 segmentLength += splitPoint.distance(points.get(splitPos - 1));
1429 if (splitPoint.getHighwayCount() > 1
1430 || segmentLength > stubSegmentLength - 5)
1431 break;
1432 splitPos++;
1433 }
1434 if (segmentLength > stubSegmentLength + 10){
1435 // insert a new point after the POI to
1436 // make a short stub segment
1437 splitPoint = points.get(splitPos);
1438 Coord prev = points.get(splitPos-1);
1439 double dist = splitPoint.distance(prev);
1440 double neededLength = stubSegmentLength - (segmentLength - dist);
1441
1442 splitPoint = prev.makeBetweenPoint(splitPoint, neededLength / dist);
1443 double newDist = splitPoint.distance(prev);
1444 segmentLength += newDist - dist;
1445 splitPoint.incHighwayCount();
1446 points.add(splitPos, splitPoint);
1447 }
1448 if((splitPos + 1) < points.size() && way.isViaWay() == false &&
1449 safeToSplitWay(points, splitPos, i, points.size() - 1)) {
1450 Way tail = splitWayAt(way, splitPos);
1451 // recursively process tail of way
1452 addRoad(new ConvertedWay(cw, tail));
1371 if (!way.isViaWay()) {
1372 // find good split point after POI
1373 Coord splitPoint;
1374 double segmentLength = 0;
1375 int splitPos = i + 1;
1376 while (splitPos + 1 < points.size()) {
1377 splitPoint = points.get(splitPos);
1378 segmentLength += splitPoint.distance(points.get(splitPos - 1));
1379 if (splitPoint.getHighwayCount() > 1 || segmentLength > stubSegmentLength - 5)
1380 break;
1381 splitPos++;
1382 }
1383 if (segmentLength > stubSegmentLength + 10) {
1384 // insert a new point after the POI to
1385 // make a short stub segment
1386 splitPoint = points.get(splitPos);
1387 Coord prev = points.get(splitPos - 1);
1388 double dist = splitPoint.distance(prev);
1389 double neededLength = stubSegmentLength - (segmentLength - dist);
1390
1391 splitPoint = prev.makeBetweenPoint(splitPoint, neededLength / dist);
1392 double newDist = splitPoint.distance(prev);
1393 segmentLength += newDist - dist;
1394 splitPoint.incHighwayCount();
1395 points.add(splitPos, splitPoint);
1396 }
1397 if ((splitPos + 1) < points.size()
1398 && safeToSplitWay(points, splitPos, i, points.size() - 1)) {
1399 Way tail = splitWayAt(way, splitPos);
1400 // recursively process tail of way
1401 addRoad(new ConvertedWay(cw, tail));
1402 }
14531403 }
14541404 boolean classChanged = cw.recalcRoadClass(node);
14551405 if (classChanged && log.isInfoEnabled()){
14671417 // and the next point modifies the way's speed/class,
14681418 // split the way at this point to limit the size of
14691419 // the affected region
1470 if (i + 1 < points.size()
1420 if (!way.isViaWay() && i + 1 < points.size()
14711421 && points.get(i + 1) instanceof CoordPOI) {
14721422 CoordPOI cp = (CoordPOI) points.get(i + 1);
14731423 Node node = cp.getNode();
15541504 private void addRoadAfterSplittingLoops(ConvertedWay cw) {
15551505 Way way = cw.getWay();
15561506 // make sure the way has nodes at each end
1557 way.getPoints().get(0).incHighwayCount();
1558 way.getPoints().get(way.getPoints().size() - 1).incHighwayCount();
1507 way.getFirstPoint().incHighwayCount();
1508 way.getLastPoint().incHighwayCount();
15591509
15601510 // check if the way is a loop or intersects with itself
15611511
19511901 * @return true if fixme flag was found
19521902 */
19531903 private static boolean checkFixmeCoords(Way way) {
1954 if (way.getPoints().get(0).isFixme())
1955 return true;
1956 if (way.getPoints().get(way.getPoints().size()-1).isFixme())
1957 return true;
1958 return false;
1904 return way.getFirstPoint().isFixme() || way.getLastPoint().isFixme();
19591905 }
19601906
19611907 /**
19651911 * @param index the split position.
19661912 * @return the trailing part of the way
19671913 */
1968 private static Way splitWayAt(Way way, int index) {
1914 private Way splitWayAt(Way way, int index) {
19691915 if (way.isViaWay()){
1970 log.warn("via way of restriction is split, restriction will be ignored",way);
1916 removeRestrictionsWithWay(Level.WARNING, way, "is split, restriction will be ignored");
19711917 }
19721918 Way trailingWay = new Way(way.getId());
19731919 List<Coord> wayPoints = way.getPoints();
14861486 if (way.equals(lastWay))
14871487 continue;
14881488 lastWay = way;
1489 List<Coord> points = way.getPoints();
1490 points.get(0).setEndOfWay(true);
1491 points.get(points.size()-1).setEndOfWay(true);
1489 way.getFirstPoint().setEndOfWay(true);
1490 way.getLastPoint().setEndOfWay(true);
14921491 }
14931492 }
14941493
556556 List<HousenumberMatch> testOrder = new ArrayList<>();
557557 testOrder.add(house1);
558558 testOrder.add(house2);
559 Collections.sort(testOrder, new HousenumberMatchByPosComparator());
559 testOrder.sort(new HousenumberMatchByPosComparator());
560560 if (testOrder.get(0) != house1){
561561 log.info("order indicates random case or missing road!",this);
562562 housenumberRoad.setRandom(true);
10531053 HousenumberGenerator.findClosestRoadSegment(house, getRoad(), startInRoad, endInRoad);
10541054 }
10551055 if (houses.size() > 1)
1056 Collections.sort(houses, new HousenumberMatchByPosComparator());
1056 houses.sort(new HousenumberMatchByPosComparator());
10571057 }
10581058
10591059
14561456 from.housenumberRoad.getHouses().remove(bestMoveOrig);
14571457 fromHouses.remove(bestMoveOrig);
14581458 toHouses.add(bestMoveOrig);
1459 Collections.sort(toHouses, new HousenumberMatchByPosComparator());
1459 toHouses.sort(new HousenumberMatchByPosComparator());
14601460 en1.reset();
14611461 en2.reset();
14621462 en1.setNumbers(houses1, en1.startInRoad, en1.endInRoad, left1);
825825 for (Entry<CityInfo, MultiHashMap<String, HousenumberMatch>> topEntry : cityPlaceHouseMap.entrySet()){
826826 CityInfo cityInfo = topEntry.getKey();
827827 List<String> placeNames = new ArrayList<>(topEntry.getValue().keySet());
828 Collections.sort(placeNames);
828 placeNames.sort(null);
829829 for (String placeName : placeNames){
830830 List<HousenumberMatch> placeHouses = topEntry.getValue().get(placeName);
831831 HashSet<HousenumberRoad> roads = new LinkedHashSet<>();
12321232 List<HousenumberRoad> roadsInCluster) {
12331233 if (houses.isEmpty())
12341234 return;
1235 Collections.sort(houses, new HousenumberMatchByNumComparator());
1235 houses.sort(new HousenumberMatchByNumComparator());
12361236
12371237 HousenumberMatch prev = null;
12381238 for (HousenumberMatch house : houses) {
12671267 // multiple roads, we assume that the closest is the best
12681268 // but we may have to check the alternatives as well
12691269
1270 Collections.sort(matches, new HousenumberGenerator.HousenumberMatchByDistComparator());
1270 matches.sort(new HousenumberGenerator.HousenumberMatchByDistComparator());
12711271 closest = matches.get(0);
12721272 best = checkAngle(closest, matches);
12731273 }
13061306
13071307 private static void markSimpleDuplicates(String streetName, List<HousenumberMatch> housesNearCluster) {
13081308 List<HousenumberMatch> sortedHouses = new ArrayList<>(housesNearCluster);
1309 Collections.sort(sortedHouses, new HousenumberMatchByNumComparator());
1309 sortedHouses.sort(new HousenumberMatchByNumComparator());
13101310 int n = sortedHouses.size();
13111311 for (int i = 1; i < n; i++){
13121312 HousenumberMatch house1 = sortedHouses.get(i-1);
14721472 if (o1 == o2) {
14731473 return 0;
14741474 }
1475 if (o1.getRoad() == null || o2.getRoad() == null){
1476 log.error("road is null in sort comparator",o1,o2);
1477 throw new MapFailedException("internal error in housenumber processing");
1475 if (o1.getRoad() == null || o2.getRoad() == null) {
1476 log.error("road is null in sort comparator", o1, o2);
1477 throw new MapFailedException("internal error in housenumber processing");
14781478 }
14791479 if (o1.getRoad() != o2.getRoad()) {
14801480 // should not happen
15271527 }
15281528 }
15291529 /**
1530 * Sorts house numbers by distance. If eqaul, compare segment and road to produce
1530 * Sorts house numbers by distance. If equal, compare segment and road to produce
15311531 * predictable results.
15321532 * @author Gerd Petermann
15331533 */
17791779 }
17801780
17811781 public List<RoadPoint> getCLoseRoadPoints(HousenumberElem house){
1782 Set<RoadPoint> closeRoadPoints = kdTree.findNextPoint(house, kdSearchRange);
1782 Set<RoadPoint> closeRoadPoints = kdTree.findClosePoints(house, kdSearchRange);
17831783 List<RoadPoint> result = new ArrayList<>();
17841784 for (RoadPoint rp : closeRoadPoints){
17851785 int id = rp.p.getId();
18011801 List<RoadPoint> closeRoadPoints = getCLoseRoadPoints(house);
18021802 if (closeRoadPoints.isEmpty())
18031803 return closest;
1804 Collections.sort(closeRoadPoints, new Comparator<RoadPoint>() {
1805 // sort by distance (smallest first)
1806 public int compare(RoadPoint o1, RoadPoint o2) {
1804 closeRoadPoints.sort((o1,o2)-> {
18071805 if (o1 == o2)
18081806 return 0;
18091807 int d = Integer.compare(o1.r.getRoadId(), o2.r.getRoadId());
18141812 return d;
18151813 return Integer.compare(o1.partOfSeg, o2.partOfSeg);
18161814 }
1817 });
1815 );
18181816
18191817 List<HousenumberMatch> matches = new ArrayList<>(40);
18201818 BitSet testedSegments = new BitSet();
18551853 if (matches.isEmpty())
18561854 return closest; // closest has not yet a road
18571855
1858 Collections.sort(matches, new HousenumberGenerator.HousenumberMatchByDistComparator());
1856 matches.sort(new HousenumberGenerator.HousenumberMatchByDistComparator());
18591857 closest = matches.get(0);
18601858 closest = checkAngle(closest, matches);
18611859 closest.calcRoadSide();
7676 }
7777
7878 public void buildIntervals() {
79 Collections.sort(houseNumbers, new HousenumberMatchByNumComparator());
79 houseNumbers.sort(new HousenumberMatchByNumComparator());
8080 if (log.isInfoEnabled())
8181 log.info("Initial housenumbers for",road,"in",road.getCity(),houseNumbers);
8282
101101 }
102102 }
103103 detectGroups(leftNumbers, rightNumbers);
104 Collections.sort(leftNumbers, new HousenumberMatchByPosComparator());
105 Collections.sort(rightNumbers, new HousenumberMatchByPosComparator());
104 leftNumbers.sort(new HousenumberMatchByPosComparator());
105 rightNumbers.sort(new HousenumberMatchByPosComparator());
106106
107107
108108 int currNodePos = 0;
306306 return "http://www.openstreetmap.org/" + kind() + "/" + id;
307307 }
308308
309 /**
310 * Create a copy of the element.
311 * @return
312 */
309313 public Element copy() {
310314 // Can be implemented in subclasses
311315 throw new UnsupportedOperationException("unsupported element copy");
1212 package uk.me.parabola.mkgmap.reader.osm;
1313
1414 import java.util.AbstractMap;
15 import java.util.ArrayList;
1615 import java.util.HashMap;
16 import java.util.Iterator;
1717 import java.util.LinkedHashMap;
18 import java.util.Iterator;
1918 import java.util.List;
2019 import java.util.Map;
20
2121 import uk.me.parabola.imgfmt.Utils;
2222 import uk.me.parabola.imgfmt.app.Area;
2323 import uk.me.parabola.imgfmt.app.Coord;
2424 import uk.me.parabola.log.Logger;
2525 import uk.me.parabola.mkgmap.general.LineClipper;
2626 import uk.me.parabola.util.EnhancedProperties;
27 import uk.me.parabola.util.MultiHashMap;
2728
2829 /**
2930 * This is where we save the elements read from any of the file formats that
4546 public class ElementSaver {
4647 private static final Logger log = Logger.getLogger(ElementSaver.class);
4748
48 protected OSMId2ObjectMap<Coord> coordMap = new OSMId2ObjectMap<Coord>();
49 protected OSMId2ObjectMap<Coord> coordMap = new OSMId2ObjectMap<>();
4950
5051 protected Map<Long, Node> nodeMap;
5152 protected Map<Long, Way> wayMap;
5253 protected Map<Long, Relation> relationMap;
5354
54 protected final Map<Long, List<Map.Entry<String,Relation>>> deferredRelationMap = new HashMap<Long, List<Map.Entry<String,Relation>>>();
55 protected final MultiHashMap<Long, Map.Entry<String, Relation>> deferredRelationMap = new MultiHashMap<>();
5556
5657 // This is an explicitly given bounding box from the input file command line etc.
5758 private Area boundingBox;
7071
7172 public ElementSaver(EnhancedProperties args) {
7273 if (args.getProperty("preserve-element-order", false)) {
73 nodeMap = new LinkedHashMap<Long, Node>(5000);
74 wayMap = new LinkedHashMap<Long, Way>(5000);
75 relationMap = new LinkedHashMap<Long, Relation>();
74 nodeMap = new LinkedHashMap<>(5000);
75 wayMap = new LinkedHashMap<>(5000);
76 relationMap = new LinkedHashMap<>();
7677 } else {
77 nodeMap = new HashMap<Long, Node>();
78 wayMap = new HashMap<Long, Way>();
79 relationMap = new HashMap<Long, Relation>();
80 }
81
82 ignoreTurnRestrictions = args.getProperty("ignore-turn-restrictions", false);
78 nodeMap = new HashMap<>();
79 wayMap = new HashMap<>();
80 relationMap = new HashMap<>();
81 }
82
83 ignoreTurnRestrictions = args.getProperty("ignore-turn-restrictions", false) || !args.containsKey("route");
8384 }
8485
8586 /**
139140 public void addRelation(Relation rel) {
140141 String type = rel.getTag("type");
141142 if (type == null) {
143 // maybe set rel to null?
142144 } else if ("multipolygon".equals(type) || "boundary".equals(type)) {
143145 rel = createMultiPolyRelation(rel);
144146 } else if("restriction".equals(type) || type.startsWith("restriction:")) {
145147 if (ignoreTurnRestrictions)
146148 rel = null;
147 else if (rel.getTag("restriction") == null && rel.getTagsWithPrefix("restriction:", false).isEmpty())
149 else if (rel.getTag("restriction") == null && rel.getTagsWithPrefix("restriction:", false).isEmpty()) {
148150 log.warn("ignoring unspecified/unsupported restriction " + rel.toBrowseURL());
149 else
151 } else {
150152 rel = new RestrictionRelation(rel);
153 }
151154 }
152155
153156 if(rel != null) {
156159
157160 rel.processElements();
158161
159 List<Map.Entry<String,Relation>> entries = deferredRelationMap.remove(id);
160 if (entries != null)
161 for (Map.Entry<String,Relation> entry : entries)
162 List<Map.Entry<String, Relation>> entries = deferredRelationMap.remove(id);
163 if (entries != null) {
164 for (Map.Entry<String, Relation> entry : entries) {
162165 entry.getValue().addElement(entry.getKey(), rel);
166 }
167 }
163168 }
164169 }
165170
273278 // insert boundary point before the second point
274279 points.add(i, clippedPair[1]);
275280 ++numBoundaryNodesAdded;
276 } else if(clippedPair[1].getOnBoundary())
281 } else if (clippedPair[1].getOnBoundary()) {
277282 ++numBoundaryNodesDetected;
278
283 }
279284
280285 if (clippedPair[0] != points.get(i - 1)) {
281286 // the first point in the segment is outside
284289 // insert boundary point after the first point
285290 points.add(i, clippedPair[0]);
286291 ++numBoundaryNodesAdded;
287 } else if (clippedPair[0].getOnBoundary())
292 } else if (clippedPair[0].getOnBoundary()) {
288293 ++numBoundaryNodesDetected;
294 }
289295 }
290296 }
291297 }
335341 }
336342 }
337343
338 public void deferRelation(long id, Relation rel, String role) {
339 // The relation may be defined later in the input.
340 // Defer the lookup.
341 Map.Entry<String,Relation> entry =
342 new AbstractMap.SimpleEntry<String,Relation>(role, rel);
343
344 List<Map.Entry<String,Relation>> entries = deferredRelationMap.get(id);
345 if (entries == null) {
346 entries = new ArrayList<Map.Entry<String,Relation>>();
347 deferredRelationMap.put(id, entries);
348 }
349
350 entries.add(entry);
344 /**
345 * Handle the case that a relation refers to another relation which was not yet found in the input.
346 * The relation may be defined later in the input. Defer the lookup.
347 * @param id the id of the not yet known relation
348 * @param parentRel the parent relation
349 * @param role the role of the not yet known relation in the parent relation
350 */
351 public void deferRelation(long id, Relation parentRel, String role) {
352 deferredRelationMap.add(id, new AbstractMap.SimpleEntry<>(role, parentRel));
351353 }
352354 }
224224 if (wayRestrictions.isEmpty()) {
225225 return;
226226 }
227 if (oldWay.isViaWay())
228 newWay.setViaWay(true);
227 if (oldWay.isViaWay()) {
228 log.error("internal error: via way is split in", this.getClass().getSimpleName());
229 }
229230 // create a copy because original list may be modified within the loop
230231 for (RestrictionRelation rr : new ArrayList<>(wayRestrictions)) {
231 Coord lastPointNewWay = newWay.getPoints().get(0);
232 Coord lastPointNewWay = newWay.getFirstPoint();
232233 List<Coord> viaCoords = rr.getViaCoords();
233234 for (Coord via : viaCoords){
234235 if (via == lastPointNewWay) {
296297
297298 double startSegmentLength = 0;
298299
299 Coord lastC = w.getPoints().get(0);
300 Coord lastC = w.getFirstPoint();
300301 for (int i = 1; i < w.getPoints().size(); i++) {
301302 Coord c = w.getPoints().get(i);
302303 double segmentLength = lastC.distance(c);
461462 log.debug("Check way",linkWay.getId(),linkWay.toTagString());
462463
463464 // Retrieve all adjacent ways of the current link
464 Coord c = linkWay.getPoints().get(linkWay.getPoints().size()-1);
465 Coord c = linkWay.getLastPoint();
465466 if (isOnewayOppositeDirection(linkWay)) {
466 c = linkWay.getPoints().get(0);
467 c = linkWay.getFirstPoint();
467468 }
468469
469470 Set<Way> nextWays = adjacentWays.get(c);
476477
477478 // remove the way from destination handling only if both ways are connected with start/end points
478479 // otherwise it is a crossroads and therefore both ways need to be handled
479 boolean startEndConnection = connectedWay.getPoints().isEmpty()==false && connectedWay.getPoints().get(0).equals(c);
480 boolean startEndConnection = connectedWay.getPoints().isEmpty()==false && connectedWay.getFirstPoint().equals(c);
480481 if (startEndConnection && connectedWay.equals(linkWay) == false
481482 && connectedWay.getTag("highway").endsWith("_link")
482483 && destination.equals(nextDest)) {
181181 int middle = way.getPoints().size() / 2;
182182 Coord midPoint;
183183 if (way.getPoints().size() == 2) {
184 midPoint = way.getPoints().get(0).makeBetweenPoint(way.getPoints().get(1), 0.5);
184 midPoint = way.getFirstPoint().makeBetweenPoint(way.getLastPoint(), 0.5);
185185 } else {
186186 midPoint = way.getPoints().get(middle);
187187 }
188188 tags = search(midPoint);
189189 if (tags == null){
190190 // try 1st point next
191 tags = search(way.getPoints().get(0));
191 tags = search(way.getFirstPoint());
192192 }
193193 if (tags == null){
194194 // try last point next
195 tags = search(way.getPoints().get(way.getPoints().size()-1));
195 tags = search(way.getLastPoint());
196196 }
197197 if (tags == null){
198198 // still not found, try rest
199199 for (int i = 1; i < way.getPoints().size()-1; i++){
200 if (i == middle)
201 continue;
202 tags = search(way.getPoints().get(i));
203 if (tags != null)
204 break;
200 if (i != middle) {
201 tags = search(way.getPoints().get(i));
202 if (tags != null)
203 break;
204 }
205205 }
206206 }
207207 if (tags == null)
292292 CutPoint edgeCutPoint = new CutPoint(axis, outerBounds);
293293
294294 // go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the start
295 Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
295 innerStart.sort(axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START);
296296 for (Area anInnerStart : innerStart) {
297297 if (axis.getStartHighPrec(anInnerStart) <= axis.getStartHighPrec(outerBounds)) {
298298 // found a touching area
306306 return edgeCutPoint;
307307 }
308308
309 Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP: COMP_LAT_STOP));
309 innerStart.sort(axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP: COMP_LAT_STOP);
310310 // go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the stop
311311 for (Area anInnerStart : innerStart) {
312312 if (axis.getStopHighPrec(anInnerStart) >= axis.getStopHighPrec(outerBounds)) {
328328 CutPoint bestCutPoint = new CutPoint(axis, outerBounds);
329329 CutPoint currentCutPoint = new CutPoint(axis, outerBounds);
330330
331 Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
331 innerStart.sort(axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START);
332332
333333 for (Area anInnerStart : innerStart) {
334334 currentCutPoint.addArea(anInnerStart);
550550 }
551551
552552 areas.add(area);
553 Collections.sort(areas, comparator);
553 areas.sort(comparator);
554554 startPoinHp = axis.getStartHighPrec(Collections.max(areas,
555555 (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START
556556 : COMP_LAT_START)));
185185 boolean joinable = false;
186186
187187 // use == or equals as comparator??
188 if (joinWay.getPoints().get(0) == tempWay.getPoints().get(0)) {
188 if (joinWay.getFirstPoint() == tempWay.getFirstPoint()) {
189189 insIdx = 0;
190190 reverseTempWay = true;
191191 firstTmpIdx = 1;
192192 joinable = true;
193 } else if (joinWay.getPoints().get(joinWay.getPoints().size() - 1) == tempWay
194 .getPoints().get(0)) {
193 } else if (joinWay.getLastPoint() == tempWay.getFirstPoint()) {
195194 insIdx = joinWay.getPoints().size();
196195 reverseTempWay = false;
197196 firstTmpIdx = 1;
198197 joinable = true;
199 } else if (joinWay.getPoints().get(0) == tempWay.getPoints().get(
200 tempWay.getPoints().size() - 1)) {
198 } else if (joinWay.getFirstPoint() == tempWay.getLastPoint()) {
201199 insIdx = 0;
202200 reverseTempWay = false;
203201 firstTmpIdx = 0;
204202 joinable = true;
205 } else if (joinWay.getPoints().get(joinWay.getPoints().size() - 1) == tempWay
206 .getPoints().get(tempWay.getPoints().size() - 1)) {
203 } else if (joinWay.getLastPoint() == tempWay.getLastPoint()) {
207204 insIdx = joinWay.getPoints().size();
208205 reverseTempWay = true;
209206 firstTmpIdx = 0;
383380 if (way.hasIdenticalEndPoints() || way.getPoints().size() < 3) {
384381 continue;
385382 }
386 Coord p1 = way.getPoints().get(0);
387 Coord p2 = way.getPoints().get(way.getPoints().size() - 1);
383 Coord p1 = way.getFirstPoint();
384 Coord p2 = way.getLastPoint();
388385
389386 if (tileBounds.insideBoundary(p1) == false
390387 && tileBounds.insideBoundary(p2) == false) {
437434 boolean doClose = true;
438435 if (maxCloseDist > 0) {
439436 // calc the distance to close
440 double closeDist = way.getPoints().get(0).distance(way.getPoints().get(way.getPoints().size()-1));
437 double closeDist = way.getFirstPoint().distance(way.getLastPoint());
441438 doClose = closeDist < maxCloseDist;
442439 }
443440 if (doClose) {
444 log.info("Closing way", way);
445 log.info("from", way.getPoints().get(0).toOSMURL());
446 log.info("to", way.getPoints().get(way.getPoints().size() - 1)
447 .toOSMURL());
441 if (log.isInfoEnabled()) {
442 log.info("Closing way", way);
443 log.info("from", way.getFirstPoint().toOSMURL());
444 log.info("to", way.getLastPoint().toOSMURL());
445 }
448446 // mark this ways as artificially closed
449447 way.closeWayArtificially();
450448 }
482480
483481 // check all ways for endpoints outside or on the bbox
484482 for (JoinedWay w : unclosed) {
485 Coord c1 = w.getPoints().get(0);
486 Coord c2 = w.getPoints().get(w.getPoints().size()-1);
483 Coord c1 = w.getFirstPoint();
484 Coord c2 = w.getLastPoint();
487485 if (tileBounds.insideBoundary(c1)==false) {
488486 log.debug("Point",c1,"of way",w.getId(),"outside bbox");
489487 outOfBboxPoints.put(c1, w);
548546 } else {
549547 // retrieve the connection with the minimum distance
550548 ConnectionData minCon = Collections.min(coordPairs,
551 new Comparator<ConnectionData>() {
552 public int compare(ConnectionData o1,
553 ConnectionData o2) {
554 return Double.compare(o1.distance, o2.distance);
555 }
556 });
549 (o1, o2) -> Double.compare(o1.distance, o2.distance));
557550
558551 if (minCon.w1 == minCon.w2) {
559552 log.debug("Close a gap in way",minCon.w1);
563556 } else {
564557 log.debug("Connect", minCon.w1, "with", minCon.w2);
565558
566 if (minCon.w1.getPoints().get(0) == minCon.c1) {
559 if (minCon.w1.getFirstPoint() == minCon.c1) {
567560 Collections.reverse(minCon.w1.getPoints());
568561 }
569 if (minCon.w2.getPoints().get(0) != minCon.c2) {
562 if (minCon.w2.getFirstPoint() != minCon.c2) {
570563 Collections.reverse(minCon.w2.getPoints());
571564 }
572565
727720 // sort by role and then by number of points, this improves performance
728721 // in the routines which add the polygons to areas
729722 if (polygonStatusList.size() > 2){
730 Collections.sort(polygonStatusList, new Comparator<PolygonStatus>() {
731 public int compare(PolygonStatus o1, PolygonStatus o2) {
732 if (o1.outer != o2.outer)
733 return (o1.outer) ? -1 : 1;
734 return o1.polygon.getPoints().size() - o2.polygon.getPoints().size();
735 }
723 polygonStatusList.sort((o1, o2) -> {
724 if (o1.outer != o2.outer)
725 return (o1.outer) ? -1 : 1;
726 return o1.polygon.getPoints().size() - o2.polygon.getPoints().size();
736727 });
737728 }
738729 return polygonStatusList;
18451836
18461837 for (Way orgWay : fakeWay.getOriginalWays()) {
18471838 log.log(logLevel, " Way",orgWay.getId(),"is composed of other artificial ways. Details:");
1848 log.log(logLevel, " Start:",orgWay.getPoints().get(0).toOSMURL());
1839 log.log(logLevel, " Start:",orgWay.getFirstPoint().toOSMURL());
18491840 if (orgWay.hasEqualEndPoints()) {
18501841 // the way is closed so start and end are equal - log the point in the middle of the way
18511842 int mid = orgWay.getPoints().size()/2;
18521843 log.log(logLevel, " Mid: ",orgWay.getPoints().get(mid).toOSMURL());
18531844 } else {
1854 log.log(logLevel, " End: ",orgWay.getPoints().get(orgWay.getPoints().size()-1).toOSMURL());
1845 log.log(logLevel, " End: ",orgWay.getLastPoint().toOSMURL());
18551846 }
18561847 }
18571848 }
20252016 addWay(originalWay);
20262017
20272018 // we have to initialize the min/max values
2028 Coord c0 = originalWay.getPoints().get(0);
2019 Coord c0 = originalWay.getFirstPoint();
20292020 minLat = maxLat = c0.getLatitude();
20302021 minLon = maxLon = c0.getLongitude();
20312022
286286 prevC = c;
287287 }
288288
289 Node startNode = createPOI(line, line.getPoints().get(0), LINE2POI_TAG, sumDist);
289 Node startNode = createPOI(line, line.getFirstPoint(), LINE2POI_TAG, sumDist);
290290 startNode.addTag(LINE2POI_TYPE_TAG,"start");
291291 saver.addNode(startNode);
292292
293 Node endNode = createPOI(line, line.getPoints().get(line.getPoints().size()-1), LINE2POI_TAG, sumDist);
293 Node endNode = createPOI(line, line.getLastPoint(), LINE2POI_TAG, sumDist);
294294 endNode.addTag(LINE2POI_TYPE_TAG,"end");
295295 saver.addNode(endNode);
296296
297297 int noPOIs = 2;
298 Coord lastPoint = line.getPoints().get(0);
298 Coord lastPoint = line.getFirstPoint();
299299 if (line.getPoints().size() > 2) {
300300 for (Coord inPoint : line.getPoints().subList(1, line.getPoints().size()-1)) {
301301 if (inPoint.equals(lastPoint)){
202202 if(viaCoord != null)
203203 location = viaCoord;
204204 else if(!fromWays.isEmpty() && !fromWays.get(0).getPoints().isEmpty())
205 location = fromWays.get(0).getPoints().get(0);
205 location = fromWays.get(0).getFirstPoint();
206206 else if(!toWays.isEmpty() && !toWays.get(0).getPoints().isEmpty())
207 location = toWays.get(0).getPoints().get(0);
207 location = toWays.get(0).getFirstPoint();
208208 else if(!viaWays.isEmpty() && !viaWays.get(0).getPoints().isEmpty())
209 location = viaWays.get(0).getPoints().get(0);
209 location = viaWays.get(0).getFirstPoint();
210210
211211 if(location != null)
212212 messagePrefix = "Turn restriction (" + restriction + ") " + browseURL + " (at " + location.toOSMURL() + ")";
328328 log.warn(messagePrefix,"way",way.toBrowseURL(),"has less than 2 points, restriction is ignored");
329329 valid = false;
330330 } else {
331 if (way.getPoints().get(0) == way.getPoints().get(way.getPoints().size()-1)){
331 if (way.hasIdenticalEndPoints()){
332332 if (ways == toWays && dirIndicator != '?')
333333 continue; // we try to determine the correct part in RoadNetwork
334334 log.warn(messagePrefix, "way", way.toBrowseURL(), "starts and ends at same node, don't know which one to use");
351351 Coord v1 = viaCoord;
352352 Coord v2 = viaCoord;
353353 if (viaWays.isEmpty() == false){
354 v1 = viaWays.get(0).getPoints().get(0);
355 v2 = viaWays.get(0).getPoints().get(viaWays.get(0).getPoints().size()-1);
354 v1 = viaWays.get(0).getFirstPoint();
355 v2 = viaWays.get(0).getLastPoint();
356356 }
357357 // check if all from ways are connected at the given via point or with the given via ways
358358 for (Way fromWay : fromWays){
359 Coord e1 = fromWay.getPoints().get(0);
360 Coord e2 = fromWay.getPoints().get(fromWay.getPoints().size() - 1);
359 Coord e1 = fromWay.getFirstPoint();
360 Coord e2 = fromWay.getLastPoint();
361361 if (e1 == v1 || e2 == v1)
362362 viaCoord = v1;
363363 else if (e1 == v2 || e2 == v2)
374374 for (int i = 0; i < viaWays.size();i++){
375375 Way way = viaWays.get(i);
376376 Coord v = viaPoints.get(viaPoints.size()-1);
377 if (way.getPoints().get(0) == v)
378 v2 = way.getPoints().get(way.getPoints().size()-1);
379 else if (way.getPoints().get(way.getPoints().size()-1) == v)
380 v2 = way.getPoints().get(0);
377 if (way.getFirstPoint() == v)
378 v2 = way.getLastPoint();
379 else if (way.getLastPoint() == v)
380 v2 = way.getFirstPoint();
381381 else {
382382 log.warn(messagePrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at",v.toDegreeString());
383383 valid = false;
403403 // check if all to ways are connected to via point or last via way
404404 Coord lastVia = viaPoints.get(viaPoints.size()-1);
405405 for (Way toWay : toWays){
406 Coord e1 = toWay.getPoints().get(0);
407 Coord e2 = toWay.getPoints().get(toWay.getPoints().size() - 1);
406 Coord e1 = toWay.getFirstPoint();
407 Coord e2 = toWay.getLastPoint();
408408 if(e1 != lastVia && e2 != lastVia) {
409409 log.warn(messagePrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
410410 valid = false;
758758 if (w.hasIdenticalEndPoints()) {
759759 joined.add(w);
760760 } else if (w.getPoints() != null && w.getPoints().size() > 1){
761 List<Coord> points = w.getPoints();
762 beginMap.put(points.get(0), w);
761 beginMap.put(w.getFirstPoint(), w);
763762 } else {
764763 log.info("Discard coastline way",w.getId(),"because consists of less than 2 points");
765764 }
800799
801800 if (wm.hasIdenticalEndPoints()) {
802801 joined.add(wm);
803 beginMap.remove(wm.getPoints().get(0));
802 beginMap.remove(wm.getFirstPoint());
804803 }
805804 break;
806805 }
932931 assert seaRelation != null;
933932 seaRelation.addElement("inner", ai);
934933 }
935 log.warn("Converting anti-island starting at", ai.getPoints().get(0).toOSMURL() , "into an island as it is surrounded by water");
934 log.warn("Converting anti-island starting at", ai.getFirstPoint().toOSMURL() , "into an island as it is surrounded by water");
936935 }
937936 }
938937
951950 se.getLongitude() + 1));
952951 sea.addPoint(new Coord(ne.getLatitude() - 1,
953952 ne.getLongitude() + 1));
954 sea.addPoint(sea.getPoints().get(0)); // close shape
953 sea.addPoint(sea.getFirstPoint()); // close shape
955954 sea.addTag("natural", "sea");
956955 sea.setFullArea(SEA_SIZE);
957956
10711070 log.info("adding:", segment);
10721071 for(Coord p : segment.getPoints())
10731072 w.addPointIfNotEqualToLastPoint(p);
1074 hNext = getEdgeHit(seaBounds, segment.getPoints().get(segment.getPoints().size()-1));
1073 hNext = getEdgeHit(seaBounds, segment.getLastPoint());
10751074 } else {
10761075 w.addPointIfNotEqualToLastPoint(hit.getPoint(seaBounds));
10771076 hNext = hits.higher(hit);
11091108 } while (!hits.isEmpty() && !hit.equals(hFirst));
11101109
11111110 if (!w.hasIdenticalEndPoints())
1112 w.addPoint(w.getPoints().get(0)); // close shape
1111 w.addPoint(w.getFirstPoint()); // close shape
11131112 log.info("adding non-island landmass, hits.size()=" + hits.size());
11141113 islands.add(w);
11151114 shorelineReachesBoundary = true;
14151414 if(w1.hasIdenticalEndPoints())
14161415 continue;
14171416 List<Coord> points1 = w1.getPoints();
1418 Coord w1e = points1.get(points1.size() - 1);
1417 Coord w1e = w1.getLastPoint();
14191418 if(bounds.onBoundary(w1e))
14201419 continue;
14211420 Way nearest = null;
4949 private boolean isViaWay;
5050
5151 public Way(long id) {
52 points = new ArrayList<Coord>(5);
52 points = new ArrayList<>(5);
5353 setId(id);
5454 }
5555
5656 public Way(long id, List<Coord> points) {
57 this.points = new ArrayList<Coord>(points);
57 this.points = new ArrayList<>(points);
5858 setId(id);
5959 }
6060
61 @Override
6162 public Way copy() {
6263 Way dup = new Way(getId(), points);
6364 dup.copyIds(this);
7778 */
7879 public List<Coord> getPoints() {
7980 return points;
81 }
82
83 /**
84 * @return first point or null if points is empty
85 */
86 public Coord getFirstPoint() {
87 return points.isEmpty() ? null:points.get(0);
88 }
89
90 /**
91 * @return last point or null if points is empty
92 */
93 public Coord getLastPoint() {
94 return points.isEmpty() ? null:points.get(points.size() - 1);
8095 }
8196
8297 public void addPoint(Coord co) {
206221 return Coord.makeHighPrecCoord((int)Math.round(lat), (int)Math.round(lon));
207222 }
208223
224 @Override
209225 public String kind() {
210226 return "way";
211227 }
271287 }
272288 return this.fullArea;
273289 }
274
275290 }
8080 if (b1.size() == 0 && b2.size() == 0)
8181 return;
8282
83 Collections.sort(b1);
84 Collections.sort(b2);
83 b1.sort(null);
84 b2.sort(null);
8585
8686 Queue<String> bounds1 = new LinkedList<>(b1);
8787 Queue<String> bounds2 = new LinkedList<>(b2);
1717 import java.io.IOException;
1818 import java.nio.channels.FileChannel;
1919 import java.util.ArrayList;
20 import java.util.Collections;
2120 import java.util.List;
2221 import java.util.ListIterator;
2322
5352 List<String> fl1 = BoundaryUtil.getBoundaryDirContent(dir1.getAbsolutePath());
5453 List<String> fl2 = BoundaryUtil.getBoundaryDirContent(dir2.getAbsolutePath());
5554
56 Collections.sort(fl1);
57 Collections.sort(fl2);
55 fl1.sort(null);
56 fl2.sort(null);
5857
5958 ListIterator<String> fl1Iter = fl1.listIterator();
6059 ListIterator<String> fl2Iter = fl2.listIterator();
270270 private void sortBoundaryTagsMap(){
271271 // make sure that the merged LinkedHashMap is sorted as mergeBoundaries() needs it
272272 ArrayList<String> ids = new ArrayList<>(boundaryTags.keySet());
273 Collections.sort(ids, new AdminLevelCollator());
274 Collections.reverse(ids);
273 ids.sort(new AdminLevelCollator().reversed());
275274 HashMap<String,Tags> tmp = new LinkedHashMap<>(boundaryTags);
276275 boundaryTags.clear();
277276 for (String id: ids){
1414 import java.util.ArrayList;
1515 import java.util.BitSet;
1616 import java.util.Collections;
17 import java.util.Comparator;
1817 import java.util.HashMap;
1918 import java.util.HashSet;
2019 import java.util.IdentityHashMap;
323322
324323 // check all ways for endpoints outside or on the bbox
325324 for (JoinedWay w : unclosed) {
326 Coord c1 = w.getPoints().get(0);
327 Coord c2 = w.getPoints().get(w.getPoints().size() - 1);
325 Coord c1 = w.getFirstPoint();
326 Coord c2 = w.getLastPoint();
328327 outOfBboxPoints.put(c1, w);
329328 outOfBboxPoints.put(c2, w);
330329 }
355354 } else {
356355 // retrieve the connection with the minimum distance
357356 ConnectionData minCon = Collections.min(coordPairs,
358 new Comparator<ConnectionData>() {
359 public int compare(ConnectionData o1,
360 ConnectionData o2) {
361 return Double.compare(o1.distance, o2.distance);
362 }
363 });
357 (o1, o2) -> Double.compare(o1.distance, o2.distance));
364358
365359 if (minCon.distance < getMaxCloseDist()) {
366360
371365 minCon.w1.closeWayArtificially();
372366 } else {
373367 log.debug("Connect", minCon.w1, "with", minCon.w2);
374 if (minCon.w1.getPoints().get(0) == minCon.c1) {
368 if (minCon.w1.getFirstPoint() == minCon.c1) {
375369 Collections.reverse(minCon.w1.getPoints());
376370 }
377 if (minCon.w2.getPoints().get(0) != minCon.c2) {
371 if (minCon.w2.getFirstPoint() != minCon.c2) {
378372 Collections.reverse(minCon.w2.getPoints());
379373 }
380374
408402 ListIterator<JoinedWay> pIter = polygons.listIterator();
409403 while (pIter.hasNext()) {
410404 JoinedWay w = pIter.next();
411 Coord first = w.getPoints().get(0);
412 Coord last = w.getPoints().get(w.getPoints().size() - 1);
405 Coord first = w.getFirstPoint();
406 Coord last = w.getLastPoint();
413407 if (first != last) {
414408 // the way is not closed
415409 // check if one of start/endpoint is out of the bounding box
416410 // in this case it is too risky to close it
417 if (getTileBounds().contains(first) == false || getTileBounds().contains(last) == false) {
411 if (!getTileBounds().contains(first) || !getTileBounds().contains(last)) {
418412 pIter.remove();
419413 }
420414 }
1111 */
1212 package uk.me.parabola.mkgmap.reader.osm.boundary;
1313
14 import it.unimi.dsi.fastutil.ints.IntArrayList;
1514 import java.awt.Shape;
1615 import java.awt.geom.PathIterator;
1716 import java.io.BufferedOutputStream;
2221 import java.io.IOException;
2322 import java.io.OutputStream;
2423 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Comparator;
2724 import java.util.HashMap;
2825 import java.util.HashSet;
2926 import java.util.Iterator;
3229 import java.util.Map.Entry;
3330 import java.util.regex.Pattern;
3431
32 import it.unimi.dsi.fastutil.ints.IntArrayList;
3533 import uk.me.parabola.log.Logger;
3634 import uk.me.parabola.mkgmap.Version;
3735 import uk.me.parabola.mkgmap.reader.osm.Tags;
176174 return;
177175 }
178176
179 Collections.sort(openStreams, new Comparator<StreamInfo>() {
180
181 public int compare(StreamInfo o1, StreamInfo o2) {
182 return o1.lastAccessNo - o2.lastAccessNo;
183 }
184 });
177 openStreams.sort((o1, o2) -> o1.lastAccessNo - o2.lastAccessNo);
185178
186179 log.debug(openStreams.size(), "open streams.");
187180 List<StreamInfo> closingStreams = openStreams.subList(0,
171171 seaWay.addPoint(new Coord(90.0d, -180.0d));
172172 seaWay.addPoint(new Coord(90.0d, 180.0d));
173173 seaWay.addPoint(new Coord(-90.0d, 180.0d));
174 seaWay.addPoint(seaWay.getPoints().get(0)); // close shape
174 seaWay.addPoint(seaWay.getFirstPoint()); // close shape
175175 seaWay.setClosedInOSM(true);
176176 landWays.put(seaWay.getId(), seaWay);
177177
1414
1515 import java.util.LinkedHashSet;
1616 import java.util.Set;
17
1718 import uk.me.parabola.imgfmt.app.Coord;
1819
1920
6162
6263
6364 /**
64 * Start the add action with the root
65 * Add a point to the tree.
6566 * @param toAdd
6667 */
6768 public void add(T toAdd) {
8687 }
8788
8889 /**
89 * Recursive routine to find the right place for inserting
90 * into the tree.
91 * @param toAdd the point
90 * Recursive routine to find the right place for inserting a point into the tree.
91 * @param toAdd the point to add
9292 * @param tree the subtree root node where to add (maybe <code>null</code>)
9393 * @param useLongitude <code>true</code> the tree node uses longitude for comparison;
9494 * <code>false</code> the tree node uses latitude for comparison
9595 * @return the subtree root node after insertion
9696 */
97 private KdNode add( T toAdd, KdNode tree, boolean useLongitude){
98 if( tree == null ) {
99 tree = new KdNode( toAdd );
100 } else {
101 if(isSmaller(useLongitude, toAdd.getLocation(), tree.point.getLocation())) {
102 tree.left = add(toAdd, tree.left, !useLongitude);
103 } else {
104 tree.right = add(toAdd, tree.right, !useLongitude);
105 }
106 }
107 return tree;
108 }
97 private KdNode add(T toAdd, KdNode tree, boolean useLongitude) {
98 if (tree == null) {
99 tree = new KdNode(toAdd);
100 } else {
101 if (isSmaller(useLongitude, toAdd.getLocation(), tree.point.getLocation())) {
102 tree.left = add(toAdd, tree.left, !useLongitude);
103 } else {
104 tree.right = add(toAdd, tree.right, !useLongitude);
105 }
106 }
107 return tree;
108 }
109109
110110 /**
111111 * Searches for the point that has smallest distance to the given point.
112 * @param p the point to search for
112 * @param p the given point
113113 * @return the point with shortest distance to <var>p</var>
114114 */
115115 public T findNextPoint(Locatable p) {
116116 // reset
117117 minDist = Double.MAX_VALUE;
118 maxDist = -1;
118 maxDist = -1;
119119 set = null;
120120 nextPoint = null;
121121
122122 // false => first node is a latitude level
123 return findNextPoint(p, root, ROOT_NODE_USES_LONGITUDE);
123 return findNextPoint(p.getLocation(), root, ROOT_NODE_USES_LONGITUDE);
124124 }
125125
126126 /**
127 * Searches for the point that has smallest distance to the given point.
128 * @param p the point to search for
129 * @return the point with shortest distance to <var>p</var>
127 * Searches for the points that have <var>maxDist</var> distance to the given point.
128 * @param p the given point
129 * @param maxDist the allowed distance
130 * @return the points within distance <var>maxDist</var> to <var>p</var>
130131 */
131 public Set<T> findNextPoint(Locatable p, double maxDist) {
132 public Set<T> findClosePoints(Locatable p, double maxDist) {
132133 // reset
133134 minDist = Double.MAX_VALUE;
134135 this.maxDist = Math.pow(maxDist * 360 / Coord.U, 2); // convert maxDist in meter to distanceInDegreesSquared
135136 nextPoint = null;
136 this.set = new LinkedHashSet<>();
137 set = new LinkedHashSet<>();
137138 // false => first node is a latitude level
138 findNextPoint(p, root, ROOT_NODE_USES_LONGITUDE);
139 findNextPoint(p.getLocation(), root, ROOT_NODE_USES_LONGITUDE);
139140 return set;
140141 }
141142
142 private T findNextPoint(Locatable p, KdNode tree, boolean useLongitude) {
143 boolean continueWithLeft = false;
143 /**
144 * Recursive routine to find the closest point. If set is not null, all
145 * elements within the range given by maxDist are collected.
146 *
147 * @param p the location of the given point
148 * @param tree the sub tree
149 * @param useLongitude gives the dimension to search in
150 * @return the closest point
151 */
152 private T findNextPoint(Coord p, KdNode tree, boolean useLongitude) {
144153 if (tree == null)
145154 return nextPoint;
146155
147 if (tree.left == null && tree.right == null){
148 double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
149 if (dist <= maxDist && set != null){
150 set.add(tree.point);
151 }
152 if (dist < minDist){
153 nextPoint = tree.point;
154 if (dist < maxDist)
155 minDist = maxDist;
156 else
157 minDist = dist;
158 }
156 boolean smaller;
157
158 if (tree.left == null && tree.right == null) {
159 processNode(tree, p);
159160 return nextPoint;
160161 }
161 else {
162 if (isSmaller(useLongitude, p.getLocation(), tree.point.getLocation())){
163 continueWithLeft = false;
164 nextPoint = findNextPoint(p, tree.left, !useLongitude);
165 }
166 else {
167 continueWithLeft = true;
168 nextPoint = findNextPoint(p, tree.right, !useLongitude);
169 }
170 }
171
172 double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
173 if (dist <= maxDist && set != null)
174 set.add(tree.point);
175 if (dist < minDist){
176 nextPoint = tree.point;
177 minDist = dist;
178 if (dist < maxDist)
179 minDist = maxDist;
180 else
181 minDist = dist;
182 }
162 smaller = isSmaller(useLongitude, p, tree.point.getLocation());
163 nextPoint = findNextPoint(p, smaller ? tree.left : tree.right, !useLongitude);
164
165 processNode(tree, p);
183166 // do we have to search the other part of the tree?
184 Coord test;
185 if (useLongitude)
186 test = Coord.makeHighPrecCoord(p.getLocation().getHighPrecLat(), tree.point.getLocation().getHighPrecLon());
187 else
188 test = Coord.makeHighPrecCoord(tree.point.getLocation().getHighPrecLat(), p.getLocation().getHighPrecLon());
189 if (test.distanceInDegreesSquared(p.getLocation()) < minDist){
190 if (continueWithLeft)
191 nextPoint = findNextPoint(p, tree.left, !useLongitude);
192 else
193 nextPoint = findNextPoint(p, tree.right, !useLongitude);
167 int testLat = useLongitude ? p.getHighPrecLat() : tree.point.getLocation().getHighPrecLat();
168 int testLon = useLongitude ? tree.point.getLocation().getHighPrecLon() : p.getHighPrecLon();
169 Coord test = Coord.makeHighPrecCoord(testLat, testLon);
170 if (test.distanceInDegreesSquared(p) < minDist) {
171 nextPoint = findNextPoint(p, smaller ? tree.right : tree.left, !useLongitude);
194172 }
195173 return nextPoint;
196174 }
175
176 private void processNode(KdNode node, Coord p) {
177 double dist = node.point.getLocation().distanceInDegreesSquared(p);
178 if (dist <= maxDist && set != null) {
179 // node is within wanted range
180 set.add(node.point);
181 }
182 if (dist < minDist) {
183 nextPoint = node.point;
184 minDist = dist < maxDist ? maxDist : dist;
185 }
186 }
197187 }
1212
1313 package uk.me.parabola.util;
1414
15 import java.util.ArrayList;
1615 import java.util.Collections;
1716 import java.util.HashMap;
1817 import java.util.LinkedList;
2221 public class MultiHashMap<K,V> extends HashMap<K,List<V>> {
2322
2423 /**
25 * the empty list to be returned when there is key without values.
26 */
27 private final List<V> emptyList = Collections.unmodifiableList(new ArrayList<V>(0));
28
29 /**
3024 * Returns the list of values associated with the given key.
3125 *
3226 * @param key the key to get the values for.
3327 * @return a list of values for the given keys or the empty list of no such
3428 * value exist.
3529 */
30 @Override
3631 public List<V> get(Object key) {
3732 List<V> result = super.get(key);
38 return result == null ? emptyList : result;
33 return result == null ? Collections.emptyList() : result;
3934 }
4035
41
36 /**
37 * Add mapping for the given key and value.
38 * If the key already exists, the value is added to the end of the existing list.
39 *
40 * @param key the key
41 * @param value the value
42 * @return the value
43 */
4244 public V add(K key, V value ) {
43 List<V> values = super.get(key);
44 if (values == null ) {
45 values = new LinkedList<V>();
46 super.put( key, values );
47 }
48
49 boolean results = values.add(value);
50
51 return ( results ? value : null );
45 super.computeIfAbsent(key, k -> new LinkedList<>()).add(value);
46 return value;
5247 }
5348
5449 public V removeMapping(K key, V value) {
55 List<V> values = super.get(key);
56 if (values == null )
50 List<V> values = super.get(key);
51 if (values == null)
5752 return null;
5853
59 values.remove(value);
60
54 values.remove(value);
55
6156 if (values.isEmpty())
6257 super.remove(key);
6358
+0
-63
src/uk/me/parabola/util/MultiHashSet.java less more
0 /*
1 * Copyright (C) 2015 Gerd Petermann
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 3 or
5 * version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 */
12 package uk.me.parabola.util;
13
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.LinkedHashSet;
17 import java.util.Set;
18
19
20 public class MultiHashSet<K,V> extends HashMap<K,Set<V>> {
21
22 /**
23 * the empty set to be returned when there is key without values.
24 */
25 private final Set<V> emptyList = Collections.emptySet();
26
27 /**
28 * Returns the list of values associated with the given key.
29 *
30 * @param key the key to get the values for.
31 * @return a list of values for the given keys or the empty list of no such
32 * value exist.
33 */
34 public Set<V> get(Object key) {
35 Set<V> result = super.get(key);
36 return result == null ? emptyList : result;
37 }
38
39
40 public boolean add(K key, V value ) {
41 Set<V> values = super.get(key);
42 if (values == null ) {
43 values = new LinkedHashSet<V>();
44 super.put( key, values );
45 }
46 return values.add(value);
47 }
48
49 public boolean removeMapping(K key, V value) {
50 Set<V> values = super.get(key);
51 if (values == null )
52 return false;
53
54 boolean existed = values.remove(value);
55
56 if (values.isEmpty())
57 super.remove(key);
58
59 return existed;
60 }
61 }
62
173173 SortKey<String> key = sort.createSortKey(s, s);
174174 keys.add(key);
175175 }
176 Collections.sort(keys);
176 keys.sort(null);
177177
178178 long end = System.currentTimeMillis();
179179
189189 private List<String> sortWithCollator(List<String> list) {
190190 long start = System.currentTimeMillis();
191191 List<String> ret = new ArrayList<>(list);
192 Collections.sort(ret, sort.getCollator());
192 ret.sort(sort.getCollator());
193193 System.out.println("time coll: " + (System.currentTimeMillis() - start) + "ms");
194194 return ret;
195195 }
209209 CollationKey key = jcol.getCollationKey(s);
210210 keys.add(key);
211211 }
212 Collections.sort(keys);
212 keys.sort(null);
213213
214214 long end = System.currentTimeMillis();
215215
235235 return null;
236236 }
237237
238 Collections.sort(out, jcol);
238 out.sort(jcol);
239239
240240 System.out.println("time J collator: " + (System.currentTimeMillis() - start) + "ms");
241241 return out;
12051205 el.addPoint(new Coord(2000,2000));
12061206 el.addPoint(new Coord(2000,1000));
12071207 if (closed)
1208 el.addPoint(el.getPoints().get(0));
1208 el.addPoint(el.getFirstPoint());
12091209 el.setComplete(complete);
12101210 el.setClosedInOSM(true);
12111211 return el;
268268 return 0;
269269 }
270270
271 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) { }
272271 };
273272
274273 return new StyledConverter(style, coll, new EnhancedProperties());
1515 */
1616 package uk.me.parabola.mkgmap.reader.osm;
1717
18 import static org.junit.Assert.assertArrayEquals;
19 import static org.junit.Assert.assertEquals;
20
1821 import java.util.ArrayList;
19 import java.util.Collections;
2022 import java.util.List;
2123 import java.util.Map;
2224
2325 import org.junit.Test;
24
25 import static org.junit.Assert.*;
2626
2727
2828 public class ElementTest {
4242 values.add(ent.getValue());
4343 }
4444
45 Collections.sort(keys);
46 Collections.sort(values);
45 keys.sort(null);
46 values.sort(null);
4747
4848 assertArrayEquals("list of keys",
4949 new String[] {"a", "b", "c"},
1212 package uk.me.parabola.util;
1313
1414 import static org.junit.Assert.assertFalse;
15
1516 import org.junit.Test;
1617
1718 import uk.me.parabola.imgfmt.app.Coord;
1819 import uk.me.parabola.mkgmap.general.MapPoint;
19 import uk.me.parabola.util.KdTree;
2020
2121 public class KdTreeTest {
2222
2323 @Test
24 public void TestFindNextPoint(){
24 public void findNextPointTest(){
2525 KdTree<MapPoint> t = new KdTree<>( );
2626
2727 int [][]test = {{70,20}, {50,40}, {90,60}, {20,30}, {40,70}, {80,10}, {-10,20}, {-30,-40} } ;
4848 }
4949 }
5050 toFind.setLocation(co);
51 MapPoint next = (MapPoint) t.findNextPoint(toFind);
51 MapPoint next = t.findNextPoint(toFind);
5252 double dist = next.getLocation().distanceInDegreesSquared(co);
5353 double delta = Math.abs(dist - minDist);
5454 // if this test fails because