use of uk.me.parabola.imgfmt.app.srt.IntegerSortKey in project mkgmap by openstreetmap.
the class NETFile method sortRoads.
/**
* Sort the roads by name and remove duplicates.
*
* We want a list of roads such that every entry in the list is a different road. Since in osm
* roads are frequently chopped into small pieces we have to remove the duplicates.
* This doesn't have to be perfect, it needs to be useful when searching for roads.
*
* So we have a separate entry if the road is in a different city. This would probably be enough
* except that associating streets with cities is not always very good in OSM. So I also create an
* extra entry for each subdivision. Finally there a search for disconnected roads within the subdivision
* with the same name.
*
* Performance note: The previous implementation was very, very slow when there were a large number
* of roads with the same name. Although this was an unusual situation, when it happened it appears
* that mkgmap has hung. This implementation takes a fraction of a second even for large numbers of
* same named roads.
*
* @return A sorted list of road labels that identify all the different roads.
*/
private List<LabeledRoadDef> sortRoads() {
List<SortKey<LabeledRoadDef>> sortKeys = new ArrayList<>(roads.size());
Map<Label, byte[]> cache = new HashMap<>();
for (RoadDef rd : roads) {
Label[] labels = rd.getLabels();
for (int i = 0; i < labels.length && labels[i] != null; ++i) {
Label label = labels[i];
if (label.getLength() == 0)
continue;
// Sort by name, city, region/country and subdivision number.
LabeledRoadDef lrd = new LabeledRoadDef(label, rd);
SortKey<LabeledRoadDef> nameKey = new IntegerSortKey<NETFile.LabeledRoadDef>(lrd, label.getOffset(), 0);
// If there is a city add it to the sort.
// what if we more than one?
City city = (rd.getCities().isEmpty() ? null : rd.getCities().get(0));
SortKey<LabeledRoadDef> cityKey;
if (city != null) {
int region = city.getRegionNumber();
int country = city.getCountryNumber();
cityKey = sort.createSortKey(null, city.getLabel(), (region & 0xffff) << 16 | (country & 0xffff), cache);
} else {
cityKey = sort.createSortKey(null, Label.NULL_OUT_LABEL, 0, cache);
}
SortKey<LabeledRoadDef> sortKey = new MultiSortKey<>(nameKey, cityKey, new IntegerSortKey<LabeledRoadDef>(null, rd.getStartSubdivNumber(), 0));
sortKeys.add(sortKey);
}
}
Collections.sort(sortKeys);
List<LabeledRoadDef> out = new ArrayList<>(sortKeys.size());
Label lastName = null;
City lastCity = null;
List<LabeledRoadDef> dupes = new ArrayList<>();
// The duplicates are saved to the dupes list.
for (SortKey<LabeledRoadDef> key : sortKeys) {
LabeledRoadDef lrd = key.getObject();
Label name = lrd.label;
RoadDef road = lrd.roadDef;
// what if we more than one?
City city = (road.getCities().isEmpty() ? null : road.getCities().get(0));
if (road.hasHouseNumbers() || !name.equals(lastName) || city != lastCity) {
// process any previously collected duplicate road names and reset.
addDisconnected(dupes, out);
dupes = new ArrayList<>();
lastName = name;
lastCity = city;
}
dupes.add(lrd);
}
// Finish off the final set of duplicates.
addDisconnected(dupes, out);
sortByName(out);
return out;
}
Aggregations