use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.
the class LineSizeSplitterFilter method doFilter.
/**
* Keep track of the max dimensions of a line and split when they get too
* big.
*
* @param element A map element.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
// We do not deal with shapes.
assert !(element instanceof MapShape) && element instanceof MapLine;
MapLine line = (MapLine) element;
if (line.getBounds().getMaxDimension() < maxSize) {
next.doFilter(element);
return;
}
if (line instanceof MapRoad) {
MapRoad road = ((MapRoad) line);
log.error("Way " + road.getRoadDef() + " has a max dimension of " + line.getBounds().getMaxDimension() + " and is about to be split (routing will be broken)");
}
// ensure that all single lines do not exceed the maximum size
// use a slightly decreased max size (-10) to get better results
// in the subdivision creation
List<Coord> points = splitLinesToMaxSize(line.getPoints(), maxSize - 10);
log.debug("line bbox too big, splitting");
MapLine l = line.copy();
List<Coord> coords = new ArrayList<Coord>();
boolean first = true;
/**
* Class to keep track of the dimensions.
*/
class Dim {
private int minLat;
private int minLong;
private int maxLat;
private int maxLong;
Dim() {
reset();
}
private void reset() {
minLat = Integer.MAX_VALUE;
minLong = Integer.MAX_VALUE;
maxLat = Integer.MIN_VALUE;
maxLong = Integer.MIN_VALUE;
}
private void addToBounds(Coord co) {
int lat = co.getLatitude();
if (lat < minLat)
minLat = lat;
if (lat > maxLat)
maxLat = lat;
int lon = co.getLongitude();
if (lon < minLong)
minLong = lon;
if (lon > maxLong)
maxLong = lon;
}
private int getMaxDim() {
int dx = maxLong - minLong;
int dy = maxLat - minLat;
return Math.max(dx, dy);
}
}
Dim dim = new Dim();
Coord prev = null;
// Add points while not too big and then start again with a fresh line.
for (Coord co : points) {
dim.addToBounds(co);
if (dim.getMaxDim() > maxSize) {
if (first)
log.debug("bigness saving first part");
else
log.debug("bigness saving next part");
l.setPoints(coords);
next.doFilter(l);
l = line.copy();
first = false;
dim.reset();
coords = new ArrayList<Coord>();
coords.add(prev);
dim.addToBounds(prev);
dim.addToBounds(co);
}
coords.add(co);
prev = co;
}
assert coords.size() > 1;
if (coords.size() > 1) {
log.debug("bigness saving a final part");
l.setPoints(coords);
next.doFilter(l);
}
}
use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.
the class HousenumberGenerator method generate.
/**
* @param adder
* @param naxNodeId the highest nodeId used before
*/
public void generate(LineAdder adder, int naxNodeId) {
if (numbersEnabled) {
MultiHashMap<MapRoad, HousenumberMatch> initialHousesForRoads = findClosestRoadsToHouse();
identifyServiceRoads();
handleInterpolationWays(initialHousesForRoads);
List<HousenumberRoad> hnrList = createHousenumberRoads(initialHousesForRoads);
initialHousesForRoads = null;
log.info("found", hnrList.size(), "road candidates for address search");
useAddrPlaceTag(hnrList);
Map<MapRoad, HousenumberRoad> road2HousenumberRoadMap = new HashMap<>();
for (HousenumberRoad hnr : hnrList) {
road2HousenumberRoadMap.put(hnr.getRoad(), hnr);
}
Int2ObjectOpenHashMap<HashSet<MapRoad>> nodeId2RoadLists = new Int2ObjectOpenHashMap<>();
for (MapRoad road : allRoads) {
for (Coord co : road.getPoints()) {
if (co.getId() == 0)
continue;
HashSet<MapRoad> connectedRoads = nodeId2RoadLists.get(co.getId());
if (connectedRoads == null) {
connectedRoads = new HashSet<>();
nodeId2RoadLists.put(co.getId(), connectedRoads);
}
connectedRoads.add(road);
}
}
List<HousenumberRoad> addedRoads = new ArrayList<>();
Iterator<HousenumberRoad> iter = hnrList.iterator();
while (iter.hasNext()) {
HousenumberRoad hnr = iter.next();
List<HousenumberMatch> lostHouses = hnr.checkStreetName(road2HousenumberRoadMap, nodeId2RoadLists);
for (HousenumberMatch house : lostHouses) {
MapRoad r = house.getRoad();
if (r != null) {
HousenumberRoad hnr2 = road2HousenumberRoadMap.get(r);
if (hnr2 == null) {
CityInfo ci = getCityInfos(r.getCity(), r.getRegion(), r.getCountry());
hnr2 = new HousenumberRoad(r, ci, Arrays.asList(house));
if (r.getZip() != null)
hnr2.setZipCodeInfo(getZipInfos(r.getZip()));
road2HousenumberRoadMap.put(r, hnr2);
addedRoads.add(hnr2);
} else {
hnr2.addHouse(house);
}
}
}
if (hnr.getName() == null) {
iter.remove();
for (HousenumberMatch house : hnr.getHouses()) {
log.warn("found no plausible road name for address", house.toBrowseURL(), ", closest road id:", house.getRoad());
}
}
}
hnrList.addAll(addedRoads);
// TODO: interpolate addr:interpolation houses
removeDupsGroupedByCityAndName(hnrList);
// group by street name and city
TreeMap<String, TreeMap<CityInfo, List<HousenumberRoad>>> streetnameCityRoadMap = new TreeMap<>();
for (HousenumberRoad hnr : hnrList) {
TreeMap<CityInfo, List<HousenumberRoad>> cluster = streetnameCityRoadMap.get(hnr.getName());
if (cluster == null) {
cluster = new TreeMap<>();
streetnameCityRoadMap.put(hnr.getName(), cluster);
}
List<HousenumberRoad> roadsInCluster = cluster.get(hnr.getRoadCityInfo());
if (roadsInCluster == null) {
roadsInCluster = new ArrayList<>();
cluster.put(hnr.getRoadCityInfo(), roadsInCluster);
}
roadsInCluster.add(hnr);
}
for (Entry<String, TreeMap<CityInfo, List<HousenumberRoad>>> streetNameEntry : streetnameCityRoadMap.entrySet()) {
String streetName = streetNameEntry.getKey();
for (Entry<CityInfo, List<HousenumberRoad>> clusterEntry : streetNameEntry.getValue().entrySet()) {
useInterpolationInfo(streetName, clusterEntry.getValue(), road2HousenumberRoadMap);
}
for (Entry<CityInfo, List<HousenumberRoad>> clusterEntry : streetNameEntry.getValue().entrySet()) {
List<HousenumberRoad> roadsInCluster = clusterEntry.getValue();
if (log.isDebugEnabled()) {
log.debug("processing road(s) with name", streetName, "in", clusterEntry.getKey());
}
for (HousenumberRoad hnr : roadsInCluster) {
hnr.buildIntervals();
}
boolean optimized = false;
for (int loop = 0; loop < 10; loop++) {
for (HousenumberRoad hnr : roadsInCluster) {
hnr.checkIntervals();
}
checkWrongRoadAssignmments(roadsInCluster);
boolean changed = hasChanges(roadsInCluster);
if (!optimized && !changed) {
for (HousenumberRoad hnr : roadsInCluster) {
hnr.improveSearchResults();
}
changed = hasChanges(roadsInCluster);
optimized = true;
}
if (!changed)
break;
}
for (HousenumberRoad hnr : roadsInCluster) {
hnr.setNumbers();
}
}
}
}
if (log.isInfoEnabled()) {
for (HousenumberElem house : houseElems) {
if (house.getRoad() == null) {
if (house.getStreet() != null)
log.info("found no plausible road for house number element", house.toBrowseURL(), house.getStreet(), house.getSign());
else
log.info("found no plausible road for house number element", house.toBrowseURL());
}
}
}
for (MapRoad r : allRoads) {
if (log.isDebugEnabled()) {
List<Numbers> finalNumbers = r.getRoadDef().getNumbersList();
if (finalNumbers != null) {
log.info("id:" + r.getRoadDef().getId(), ", final numbers,", r, "in", r.getCity());
for (Numbers cn : finalNumbers) {
if (cn.isEmpty())
continue;
log.info("id:" + r.getRoadDef().getId(), ", Left: ", cn.getLeftNumberStyle(), cn.getIndex(), "Start:", cn.getLeftStart(), "End:", cn.getLeftEnd());
log.info("id:" + r.getRoadDef().getId(), ", Right:", cn.getRightNumberStyle(), cn.getIndex(), "Start:", cn.getRightStart(), "End:", cn.getRightEnd());
}
}
}
adder.add(r);
}
}
use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.
the class HousenumberGenerator method findRoadForInterpolatedHouses.
private static void findRoadForInterpolatedHouses(String streetName, List<HousenumberMatch> houses, List<HousenumberRoad> roadsInCluster) {
if (houses.isEmpty())
return;
Collections.sort(houses, new HousenumberMatchByNumComparator());
HousenumberMatch prev = null;
for (HousenumberMatch house : houses) {
if (house.isIgnored())
continue;
// make sure that we don't use an old match
house.setDistance(Double.POSITIVE_INFINITY);
house.setRoad(null);
List<HousenumberMatch> matches = new ArrayList<>();
for (HousenumberRoad hnr : roadsInCluster) {
MapRoad r = hnr.getRoad();
// make sure that we use the street info if available
if (house.getPlace() != null) {
if (house.getStreet() != null && r.getStreet() != null && house.getStreet().equals(r.getStreet()) == false)
continue;
}
HousenumberMatch test = new HousenumberMatch(house);
findClosestRoadSegment(test, r);
if (test.getRoad() != null && test.getGroup() != null || test.getDistance() < MAX_DISTANCE_TO_ROAD) {
matches.add(test);
}
}
if (matches.isEmpty()) {
house.setIgnored(true);
continue;
}
HousenumberMatch closest, best;
best = closest = matches.get(0);
if (matches.size() > 1) {
// multiple roads, we assume that the closest is the best
// but we may have to check the alternatives as well
Collections.sort(matches, new HousenumberGenerator.HousenumberMatchByDistComparator());
closest = matches.get(0);
best = checkAngle(closest, matches);
}
house.setDistance(best.getDistance());
house.setSegmentFrac(best.getSegmentFrac());
house.setRoad(best.getRoad());
house.setSegment(best.getSegment());
for (HousenumberMatch altHouse : matches) {
if (altHouse.getRoad() != best.getRoad() && altHouse.getDistance() < MAX_DISTANCE_TO_ROAD)
house.addAlternativeRoad(altHouse.getRoad());
}
if (house.getRoad() == null) {
house.setIgnored(true);
} else {
house.calcRoadSide();
}
// plausibility check for duplicate house numbers
if (prev != null && prev.getHousenumber() == house.getHousenumber()) {
// duplicate number (e.g. 10 and 10 or 10 and 10A or 10A and 10B)
if (prev.getSign().equals(house.getSign())) {
prev.setDuplicate(true);
house.setDuplicate(true);
}
}
if (house.getRoad() == null) {
if (house.isIgnored() == false)
log.warn("found no plausible road for house number element", house.toBrowseURL(), "(", streetName, house.getSign(), ")");
}
if (!house.isIgnored())
prev = house;
}
}
use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.
the class LineSplitterFilter method doFilter.
/**
* If the line is short enough then we just pass it on straight away.
* Otherwise we cut it into pieces that are short enough and hand them
* on.
*
* @param element A map element.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
// We do not deal with shapes.
assert !(element instanceof MapShape) && element instanceof MapLine;
MapLine line = (MapLine) element;
List<Coord> points = line.getPoints();
int npoints = points.size();
if (npoints <= MAX_POINTS_IN_LINE) {
next.doFilter(element);
return;
}
log.debug("line has too many points, splitting");
if (line.isRoad() && level == 0 && isRoutable && log.isDebugEnabled()) {
log.debug("Way " + ((MapRoad) line).getRoadDef() + " has more than " + MAX_POINTS_IN_LINE + " points and is about to be split");
}
boolean last = false;
int wantedSize = (npoints < 2 * MAX_POINTS_IN_LINE) ? npoints / 2 + 1 : MAX_POINTS_IN_LINE;
int pos = 0;
while (true) {
if (pos == 0)
log.debug("saving first part");
else if (!last)
log.debug("saving next part");
else
log.debug("saving final part");
MapLine l = line.copy();
l.setPoints(new ArrayList<>(points.subList(pos, pos + wantedSize)));
if (wantedSize < MAX_POINTS_IN_LINE / 2)
log.error("size?", npoints, pos, wantedSize);
if (!last && line instanceof MapRoad)
((MapRoad) l).setSegmentsFollowing(true);
next.doFilter(l);
if (last)
break;
// we start with the last point of previous part
pos += wantedSize - 1;
int remaining = npoints - pos;
// make sure that the last parts have enough points
if (remaining <= MAX_POINTS_IN_LINE) {
last = true;
wantedSize = remaining;
} else if (remaining < 2 * MAX_POINTS_IN_LINE)
wantedSize = remaining / 2 + 1;
}
}
use of uk.me.parabola.mkgmap.general.MapRoad in project mkgmap by openstreetmap.
the class HousenumberIvl method checkRoads2.
private boolean checkRoads2() {
for (int i = 0; i < 2; i++) {
if (knownHouses[i] == null) {
log.error("internal error: housenumber matches not properly set", this);
return false;
}
if (knownHouses[i].getRoad() == null || knownHouses[i].getDistance() > 100) {
log.warn("cannot find any reasonable road for both nodes, ignoring them", streetName, this);
return false;
}
}
if (knownHouses[0].getRoad().getRoadDef().getId() == knownHouses[1].getRoad().getRoadDef().getId()) {
if (knownHouses[0].getRoad() != knownHouses[1].getRoad()) {
// special case: interval goes along clipped road, data is probably OK
hasMultipleRoads = true;
return true;
}
for (MapRoad r : knownHouses[0].getAlternativeRoads()) {
if (r.getRoadDef().getId() == knownHouses[0].getRoad().getRoadDef().getId()) {
// special case: interval may go along clipped road, data is probably OK
hasMultipleRoads = true;
return true;
}
}
}
MapRoad bestRoad = null;
// make sure that the closest road is one with a matching name
for (int i = 0; i < 2; i++) {
while (streetName.equals(knownHouses[i].getRoad().getStreet()) == false && knownHouses[i].hasAlternativeRoad()) {
HousenumberMatch testx = new HousenumberMatch(knownHouses[i]);
MapRoad r = knownHouses[i].getAlternativeRoads().remove(0);
if (streetName.equals(r.getStreet())) {
HousenumberGenerator.findClosestRoadSegment(testx, r);
if (testx.getDistance() < MAX_INTERPOLATION_DISTANCE_TO_ROAD) {
copyRoadData(testx, knownHouses[i]);
}
}
}
}
List<MapRoad> toTest = new ArrayList<>();
toTest.add(knownHouses[0].getRoad());
toTest.add(knownHouses[1].getRoad());
for (MapRoad r : knownHouses[0].getAlternativeRoads()) {
if (knownHouses[1].getAlternativeRoads().contains(r))
toTest.add(r);
}
HousenumberMatch[] test = new HousenumberMatch[2];
HousenumberMatch[] closest = new HousenumberMatch[2];
boolean foundSingleRoad = false;
for (MapRoad r : toTest) {
if (streetName.equals(r.getStreet()) == false)
continue;
foundSingleRoad = true;
for (int i = 0; i < 2; i++) {
test[i] = knownHouses[i];
if (test[i].getRoad() != r) {
test[i] = new HousenumberMatch(knownHouses[i]);
HousenumberGenerator.findClosestRoadSegment(test[i], r);
test[i].calcRoadSide();
}
if (test[i].getRoad() == null || test[i].getDistance() > MAX_INTERPOLATION_DISTANCE_TO_ROAD) {
foundSingleRoad = false;
break;
}
}
if (foundSingleRoad) {
if (test[0].isLeft() != test[1].isLeft()) {
foundSingleRoad = false;
continue;
}
int s0 = test[0].getSegment();
int s1 = test[1].getSegment();
// check if the road and the addr:interpolation way are nearly parallel lines
double angle1 = Utils.getAngle(test[0].getClosestPointOnRoad(), points.get(0), points.get(1));
if (Math.abs(angle1) < 30) {
foundSingleRoad = false;
HousenumberMatch testx = new HousenumberMatch(test[0]);
for (int s = Math.min(s0, s1); s <= Math.max(s0, s1); s++) {
if (s != test[0].getSegment()) {
HousenumberGenerator.findClosestRoadSegment(testx, r, s, s + 1);
angle1 = Utils.getAngle(testx.getClosestPointOnRoad(), points.get(0), points.get(1));
if (Math.abs(angle1) >= 30 && testx.getDistance() < 2 * test[0].getDistance()) {
test[0] = testx;
foundSingleRoad = true;
break;
}
}
}
}
double angle2 = Utils.getAngle(points.get(points.size() - 2), points.get(points.size() - 1), test[1].getClosestPointOnRoad());
if (Math.abs(angle2) < 30) {
foundSingleRoad = false;
HousenumberMatch testx = new HousenumberMatch(test[1]);
for (int s = Math.min(s0, s1); s <= Math.max(s0, s1); s++) {
if (s != test[1].getSegment()) {
HousenumberGenerator.findClosestRoadSegment(testx, r, s, s + 1);
angle2 = Utils.getAngle(points.get(points.size() - 2), points.get(points.size() - 1), testx.getClosestPointOnRoad());
if (Math.abs(angle2) >= 30 && testx.getDistance() < 2 * test[1].getDistance()) {
test[1] = testx;
foundSingleRoad = true;
break;
}
}
}
}
}
if (foundSingleRoad) {
if (r.isNamedByHousenumberProcessing() == false)
break;
// the closest road was originally unnamed , try to find one that is named in OSM
if (bestRoad == null) {
bestRoad = r;
closest[0] = test[0];
closest[1] = test[1];
}
}
}
if (!foundSingleRoad && bestRoad != null) {
// not matching road name in original OSM data, use the closest
foundSingleRoad = true;
test[0] = closest[0];
test[1] = closest[1];
}
if (!foundSingleRoad) {
if (streetName.equals(knownHouses[0].getRoad().getStreet()) == false || streetName.equals(knownHouses[1].getRoad().getStreet()) == false) {
log.warn("cannot find reasonable road for both nodes", streetName, this);
return false;
}
hasMultipleRoads = true;
return true;
}
// we found the road that should be used for interpolation
roadForInterpolatedHouses = test[0].getRoad();
// we found a single plausible road, make sure that both nodes are using it
for (int i = 0; i < 2; i++) {
if (knownHouses[i].getRoad() != test[i].getRoad() || knownHouses[i].getSegment() != test[i].getSegment()) {
copyRoadData(test[i], knownHouses[i]);
knownHouses[i].forgetAlternativeRoads();
}
if (knownHouses[i].getSegmentFrac() < 0 || knownHouses[i].getSegmentFrac() > 1) {
hasMultipleRoads = true;
}
}
if (knownHouses[0].isLeft() != knownHouses[1].isLeft()) {
log.warn("addr:interpolation way crosses road", streetName, this);
return false;
}
return true;
}
Aggregations