use of uk.me.parabola.imgfmt.app.net.Numbers in project mkgmap by openstreetmap.
the class ExtNumbers method checkIntervals.
/**
* Check if two intervals are overlapping (all combinations of left + right)
* @param streetName
* @param en1
* @param en2
* @return true if something was changed
*/
public static int checkIntervals(String streetName, ExtNumbers en1, ExtNumbers en2) {
if (en1.getRoad() != en2.getRoad()) {
Coord cs1 = en1.getRoad().getPoints().get(en1.startInRoad);
Coord ce1 = en1.getRoad().getPoints().get(en1.endInRoad);
Coord ce2 = en2.getRoad().getPoints().get(en2.endInRoad);
if (ce2 == cs1 || ce2 == ce1) {
ExtNumbers help = en1;
en1 = en2;
en2 = help;
}
}
boolean allOK = true;
Numbers ivl1 = en1.getNumbers();
Numbers ivl2 = en2.getNumbers();
for (int i = 0; i < 2; i++) {
boolean left1 = i == 0;
NumberStyle style1 = ivl1.getNumberStyle(left1);
if (style1 == NumberStyle.NONE)
continue;
int s1 = ivl1.getStart(left1);
int e1 = ivl1.getEnd(left1);
for (int j = 0; j < 2; j++) {
boolean left2 = (j == 0);
NumberStyle style2 = ivl2.getNumberStyle(left2);
if (style2 == NumberStyle.NONE)
continue;
int s2 = ivl2.getStart(left2);
int e2 = ivl2.getEnd(left2);
boolean ok = true;
if (style1 == style2 || style1 == NumberStyle.BOTH || style2 == NumberStyle.BOTH)
ok = checkIntervalBoundaries(s1, e1, s2, e2, left1 == left2 && en1.getRoad() == en2.getRoad());
if (ok)
continue;
if (en1.getRoad() != en2.getRoad() && en1.hasGaps == false && en2.hasGaps == false) {
allOK = false;
continue;
}
if (s1 == e1) {
if (en1.getHouses(left1).get(0).isFarDuplicate()) {
allOK = false;
continue;
}
}
if (s2 == e2) {
if (en2.getHouses(left2).get(0).isFarDuplicate()) {
allOK = false;
continue;
}
}
List<HousenumberMatch> houses1 = en1.getHouses(left1);
List<HousenumberMatch> houses2 = en2.getHouses(left2);
if (log.isInfoEnabled()) {
log.info("detected unplausible combination of intervals in", streetName, s1 + ".." + e1, "and", s2 + ".." + e2, "houses:", (left1 ? "left:" : "right"), houses1, (left2 ? "left:" : "right"), houses2, (en1.getRoad() == en2.getRoad() ? "in road " + en1.getRoad() : "road id(s):" + en1.getRoad().getRoadDef().getId() + ", " + en2.getRoad().getRoadDef().getId()));
}
double smallestDelta = Double.POSITIVE_INFINITY;
HousenumberMatch bestMoveOrig = null;
HousenumberMatch bestMoveMod = null;
ExtNumbers bestRemove = null;
List<HousenumberMatch> possibleRemoves1 = new ArrayList<>();
List<HousenumberMatch> possibleRemoves2 = new ArrayList<>();
if (en1.housenumberRoad.isRandom() == false && en2.housenumberRoad.isRandom() == false) {
// check if we can move a house from en1 to en2
for (HousenumberMatch house : houses1) {
if (house.getGroup() != null)
continue;
int n = house.getHousenumber();
if (countOccurence(houses1, n) > 1)
continue;
if (n == s1 || n == e1) {
Numbers modNumbers = en1.simulateRemovalOfHouseNumber(n, left1).getNumbers();
int s1Mod = modNumbers.getStart(left1);
int e1Mod = modNumbers.getEnd(left1);
NumberStyle modStyle = modNumbers.getNumberStyle(left1);
boolean ok2 = true;
if (modStyle == style2 || modStyle == NumberStyle.BOTH || style2 == NumberStyle.BOTH)
ok2 = checkIntervalBoundaries(s1Mod, e1Mod, s2, e2, left1 == left2 && en1.getRoad() == en2.getRoad());
if (ok2) {
// the intervals don't overlap if house is removed from en1
if (houses1.size() > 1)
possibleRemoves1.add(house);
// check if it fits into en2
HousenumberMatch test = checkMoveTo(house, en2, left2);
if (test.getRoad() != null) {
double deltaDist = test.getDistance() - house.getDistance();
if (deltaDist < smallestDelta) {
bestMoveMod = test;
bestMoveOrig = house;
smallestDelta = deltaDist;
bestRemove = en1;
}
}
}
}
}
for (HousenumberMatch house : houses2) {
if (house.getGroup() != null)
continue;
int n = house.getHousenumber();
if (countOccurence(houses2, n) > 1)
continue;
if (n == s2 || n == e2) {
Numbers modNumbers = en2.simulateRemovalOfHouseNumber(n, left2).getNumbers();
int s2Mod = modNumbers.getStart(left2);
int e2Mod = modNumbers.getEnd(left2);
NumberStyle modStyle = modNumbers.getNumberStyle(left2);
boolean ok2 = true;
if (modStyle == style1 || modStyle == NumberStyle.BOTH || style1 == NumberStyle.BOTH)
ok2 = checkIntervalBoundaries(s1, e1, s2Mod, e2Mod, left1 == left2 && en1.getRoad() == en2.getRoad());
if (ok2) {
// the intervals don't overlap if house is removed from en2
if (houses2.size() > 1)
possibleRemoves2.add(house);
// check if it fits into en1
HousenumberMatch test = checkMoveTo(house, en1, left1);
if (test.getRoad() != null) {
double deltaDist = test.getDistance() - house.getDistance();
if (deltaDist < smallestDelta) {
bestMoveMod = test;
bestMoveOrig = house;
smallestDelta = deltaDist;
bestRemove = en2;
}
}
}
}
}
if (bestMoveMod != null) {
if (bestMoveOrig.isDuplicate()) {
log.warn("duplicate number causes problems", streetName, bestMoveOrig.getSign(), bestMoveOrig.toBrowseURL());
}
List<HousenumberMatch> fromHouses, toHouses;
ExtNumbers from, to;
if (bestRemove == en1) {
from = en1;
to = en2;
fromHouses = houses1;
toHouses = houses2;
bestMoveOrig.setLeft(left2);
} else {
from = en2;
to = en1;
fromHouses = houses2;
toHouses = houses1;
bestMoveOrig.setLeft(left1);
}
if (bestMoveOrig.getMoved() >= 3) {
bestMoveMod = null;
bestMoveOrig = null;
bestRemove.housenumberRoad.setRandom(true);
} else {
if (log.isInfoEnabled()) {
if (to.getRoad() == from.getRoad())
log.info("moving", streetName, bestMoveOrig.getSign(), bestMoveOrig.getElement().toBrowseURL(), "from", fromHouses, "to", toHouses, "in road", to.getRoad());
else
log.info("moving", streetName, bestMoveOrig.getSign(), bestMoveOrig.getElement().toBrowseURL(), "from", fromHouses, "in road", from.getRoad(), "to", toHouses, "in road", to.getRoad());
}
bestMoveOrig.incMoved();
bestMoveOrig.setRoad(to.getRoad());
bestMoveOrig.setHousenumberRoad(to.housenumberRoad);
bestMoveOrig.setSegment(bestMoveMod.getSegment());
bestMoveOrig.setDistance(bestMoveMod.getDistance());
bestMoveOrig.setSegmentFrac(bestMoveMod.getSegmentFrac());
from.housenumberRoad.getHouses().remove(bestMoveOrig);
fromHouses.remove(bestMoveOrig);
toHouses.add(bestMoveOrig);
Collections.sort(toHouses, new HousenumberMatchByPosComparator());
en1.reset();
en2.reset();
en1.setNumbers(houses1, en1.startInRoad, en1.endInRoad, left1);
en2.setNumbers(houses2, en2.startInRoad, en2.endInRoad, left2);
return OK_AFTER_CHANGES;
}
}
}
ExtNumbers toSplit = null;
int splitNum = -1;
int delta1 = Math.abs(e1 - s1);
int delta2 = Math.abs(e2 - s2);
if (delta1 > 0 && delta2 > 0) {
if (en1.hasGaps != en2.hasGaps) {
if (en1.hasGaps) {
if (possibleRemoves1.isEmpty() == false)
splitNum = possibleRemoves1.get(0).getHousenumber();
toSplit = en1;
} else {
if (possibleRemoves2.isEmpty() == false)
splitNum = possibleRemoves2.get(0).getHousenumber();
toSplit = en2;
}
} else if (possibleRemoves1.size() == 1) {
splitNum = possibleRemoves1.get(0).getHousenumber();
toSplit = en1;
} else if (possibleRemoves2.size() == 1) {
splitNum = possibleRemoves2.get(0).getHousenumber();
toSplit = en2;
} else if (possibleRemoves1.size() > 0) {
splitNum = possibleRemoves1.get(0).getHousenumber();
toSplit = en1;
} else if (possibleRemoves2.size() > 0) {
splitNum = possibleRemoves2.get(0).getHousenumber();
toSplit = en2;
} else {
// intervals are overlapping, a single remove doesn't help
if (ivl1.isContained(s2, left1) && ivl1.isContained(e2, left1)) {
// en2 is completely in en1
toSplit = en1;
splitNum = s2;
} else if (ivl2.isContained(s1, left2) && ivl2.isContained(e1, left2)) {
// en1 is completely in en2
toSplit = en2;
splitNum = s1;
} else {
if (ivl1.isContained(s2, left1)) {
toSplit = en1;
splitNum = s2;
} else if (ivl1.isContained(e2, left1)) {
toSplit = en1;
splitNum = e2;
} else if (ivl2.isContained(s1, left2)) {
toSplit = en2;
splitNum = s1;
} else if (ivl2.isContained(e1, left2)) {
toSplit = en2;
splitNum = e1;
} else if (style1 == NumberStyle.BOTH) {
toSplit = en1;
} else if (style2 == NumberStyle.BOTH) {
toSplit = en2;
} else {
toSplit = (delta1 >= delta2) ? en1 : en2;
}
}
}
} else if (delta1 == 0 && delta2 > 0 && countOccurence(houses2, s1) == 0) {
toSplit = en2;
splitNum = s1;
} else if (delta2 == 0 && delta1 > 0 && countOccurence(houses1, s2) == 0) {
toSplit = en1;
splitNum = s2;
}
if (toSplit != null) {
toSplit.worstHouse = null;
toSplit.badNum = splitNum;
toSplit.setNeedsSplit(true);
return NOT_OK_TRY_SPLIT;
}
allOK = false;
}
}
if (allOK)
return OK_NO_CHANGES;
return NOT_OK_KEEP;
}
use of uk.me.parabola.imgfmt.app.net.Numbers in project mkgmap by openstreetmap.
the class ExtNumbers method checkMoveTo.
private static HousenumberMatch checkMoveTo(HousenumberMatch house, ExtNumbers other, boolean otherLeft) {
HousenumberMatch test = new HousenumberMatch(house);
Numbers otherIvl = other.getNumbers();
int oStart = otherIvl.getStart(otherLeft);
int oEnd = otherIvl.getEnd(otherLeft);
// check if it fits into en2
if (house.getHousenumber() <= Math.min(oStart, oEnd) || house.getHousenumber() >= Math.max(oStart, oEnd))
return test;
boolean even = house.getHousenumber() % 2 == 0;
NumberStyle oStyle = otherIvl.getNumberStyle(otherLeft);
if (oStyle == NumberStyle.EVEN && !even || oStyle == NumberStyle.ODD && even)
return test;
HousenumberGenerator.findClosestRoadSegment(test, other.getRoad(), other.startInRoad, other.endInRoad);
if (test.getDistance() <= HousenumberGenerator.MAX_DISTANCE_TO_ROAD) {
Coord c1 = other.getRoad().getPoints().get(test.getSegment());
Coord c2 = other.getRoad().getPoints().get(test.getSegment() + 1);
if (c1.highPrecEquals(c2) || otherLeft == HousenumberGenerator.isLeft(c1, c2, house.getLocation())) {
test.setLeft(otherLeft);
return test;
}
}
test.setRoad(null);
return test;
}
use of uk.me.parabola.imgfmt.app.net.Numbers 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);
}
}
Aggregations