use of uk.me.parabola.mkgmap.general.CityInfo in project mkgmap by openstreetmap.
the class HousenumberGenerator method markSimpleDuplicates.
private static void markSimpleDuplicates(String streetName, List<HousenumberMatch> housesNearCluster) {
List<HousenumberMatch> sortedHouses = new ArrayList<>(housesNearCluster);
Collections.sort(sortedHouses, new HousenumberMatchByNumComparator());
int n = sortedHouses.size();
for (int i = 1; i < n; i++) {
HousenumberMatch house1 = sortedHouses.get(i - 1);
if (house1.isIgnored())
continue;
HousenumberMatch house2 = sortedHouses.get(i);
if (house2.isIgnored())
continue;
if (house1.getHousenumber() != house2.getHousenumber())
continue;
if (house1.getRoad() == house2.getRoad()) {
if (house1.isFarDuplicate())
house2.setFarDuplicate(true);
// handled later
continue;
}
// we have two equal house numbers in different roads
// check if they should be treated alike
boolean markFarDup = false;
double dist = house1.getLocation().distance(house2.getLocation());
if (dist > MAX_DISTANCE_SAME_NUM)
markFarDup = true;
else {
CityInfo city1 = house1.getCityInfo();
CityInfo city2 = house2.getCityInfo();
if (city1 != null && city1.equals(city2) == false) {
markFarDup = true;
}
}
if (markFarDup) {
if (log.isDebugEnabled())
log.debug("keeping duplicate numbers assigned to different roads in cluster ", streetName, house1, house2);
house1.setFarDuplicate(true);
house2.setFarDuplicate(true);
continue;
}
boolean ignore2nd = false;
if (dist < 30) {
ignore2nd = true;
} else {
Coord c1s = house1.getRoad().getPoints().get(house1.getSegment());
Coord c1e = house1.getRoad().getPoints().get(house1.getSegment() + 1);
Coord c2s = house2.getRoad().getPoints().get(house2.getSegment());
Coord c2e = house2.getRoad().getPoints().get(house2.getSegment() + 1);
if (c1s == c2s || c1s == c2e || c1e == c2s || c1e == c2e) {
// roads are directly connected
ignore2nd = true;
}
}
if (ignore2nd) {
house2.setIgnored(true);
if (log.isDebugEnabled()) {
if (house1.getSign().equals(house2.getSign()))
log.debug("duplicate number is ignored", streetName, house2.getSign(), house2.toBrowseURL());
else
log.info("using", streetName, house1.getSign(), "in favor of", house2.getSign(), "as target for address search");
}
} else {
if (log.isDebugEnabled())
log.debug("keeping duplicate numbers assigned to different roads in cluster ", streetName, house1, house2);
house1.setFarDuplicate(true);
house2.setFarDuplicate(true);
}
}
}
use of uk.me.parabola.mkgmap.general.CityInfo in project mkgmap by openstreetmap.
the class HousenumberGenerator method useAddrPlaceTag.
private void useAddrPlaceTag(List<HousenumberRoad> hnrList) {
HashMap<CityInfo, MultiHashMap<String, HousenumberMatch>> cityPlaceHouseMap = new LinkedHashMap<>();
for (int i = 0; i < houseElems.size(); i++) {
HousenumberElem house = houseElems.get(i);
if (house.getRoad() == null)
continue;
if (house.getPlace() == null)
continue;
if (house instanceof HousenumberMatch) {
HousenumberMatch hm = (HousenumberMatch) house;
if (hm.getHousenumberRoad() == null)
continue;
} else
continue;
MultiHashMap<String, HousenumberMatch> subMap = cityPlaceHouseMap.get(house.getCityInfo());
if (subMap == null) {
subMap = new MultiHashMap<>();
cityPlaceHouseMap.put(house.getCityInfo(), subMap);
}
subMap.add(house.getPlace(), (HousenumberMatch) house);
}
log.info("analysing", cityPlaceHouseMap.size(), "cities with addr:place=* houses");
for (Entry<CityInfo, MultiHashMap<String, HousenumberMatch>> topEntry : cityPlaceHouseMap.entrySet()) {
CityInfo cityInfo = topEntry.getKey();
List<String> placeNames = new ArrayList<>(topEntry.getValue().keySet());
Collections.sort(placeNames);
for (String placeName : placeNames) {
List<HousenumberMatch> placeHouses = topEntry.getValue().get(placeName);
HashSet<HousenumberRoad> roads = new LinkedHashSet<>();
Int2IntOpenHashMap usedNumbers = new Int2IntOpenHashMap();
HashMap<String, Integer> usedSigns = new HashMap<>();
int dupSigns = 0;
int dupNumbers = 0;
int housesWithStreet = 0;
int housesWithMatchingStreet = 0;
int roadsWithNames = 0;
int unnamedCloseRoads = 0;
for (HousenumberMatch house : placeHouses) {
if (house.getStreet() != null) {
++housesWithStreet;
if (house.getStreet().equalsIgnoreCase(house.getRoad().getStreet())) {
++housesWithMatchingStreet;
}
} else {
if (house.getRoad().getStreet() == null)
++unnamedCloseRoads;
}
boolean added = roads.add(house.getHousenumberRoad());
if (added && house.getRoad().getStreet() != null)
++roadsWithNames;
int oldCount = usedNumbers.put(house.getHousenumber(), 1);
if (oldCount != 0) {
usedNumbers.put(house.getHousenumber(), oldCount + 1);
++dupNumbers;
}
Integer oldSignCount = usedSigns.put(house.getSign(), 1);
if (oldSignCount != null) {
usedSigns.put(house.getSign(), oldSignCount + 1);
++dupSigns;
}
}
if (log.isDebugEnabled()) {
log.debug("place", placeName, "in city", cityInfo, ":", "houses:", placeHouses.size(), ",duplicate numbers/signs:", dupNumbers + "/" + dupSigns, ",roads (named/unnamed):", roads.size(), "(" + roadsWithNames + "/" + (roads.size() - roadsWithNames) + ")", ",houses without addr:street:", placeHouses.size() - housesWithStreet, ",street = name of closest road:", housesWithMatchingStreet, ",houses without addr:street near named road:", unnamedCloseRoads);
}
if ((float) dupSigns / placeHouses.size() < 0.25) {
if (log.isDebugEnabled())
log.debug("will not use gaps in intervals for roads in", placeName);
for (HousenumberRoad hnr : roads) {
hnr.setRemoveGaps(true);
}
}
if (placeHouses.size() > housesWithStreet) {
// XXX: threshold value?
LongArrayList ids = new LongArrayList();
for (HousenumberRoad hnr : roads) {
ids.add(hnr.getRoad().getRoadDef().getId());
hnr.addPlaceName(placeName);
}
if (log.isDebugEnabled())
log.debug("detected", placeName, "as potential address name for roads", ids);
} else {
if (log.isDebugEnabled())
log.debug("will ignore addr:place for address search in", placeName, "in city", cityInfo);
}
}
}
}
use of uk.me.parabola.mkgmap.general.CityInfo 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.CityInfo in project mkgmap by openstreetmap.
the class HousenumberGenerator method parseElement.
private HousenumberElem parseElement(Element el, String sign) {
String city = el.getTag(cityTagKey);
String region = el.getTag(regionTagKey);
String country = el.getTag(countryTagKey);
CityInfo ci = getCityInfos(city, region, country);
HousenumberElem house = new HousenumberElem(el, ci);
if (house.getLocation() == null) {
// there has been a report that indicates match.getLocation() == null
// could not reproduce so far but catching it here with some additional
// information. (WanMil)
log.error("OSM element seems to have no point.");
log.error("Element: " + el.toBrowseURL() + " " + el);
log.error("Please report on the mkgmap mailing list.");
log.error("Continue creating the map. This should be possible without a problem.");
return null;
}
house.setSign(sign);
Integer hn = parseHousenumber(sign);
if (hn == null) {
if (log.isDebugEnabled())
log.debug("No housenumber (", el.toBrowseURL(), "): ", sign);
return null;
}
if (hn < 0 || hn > 1_000_000) {
log.warn("Number looks wrong, is ignored", house.getSign(), hn, "element", el.toBrowseURL());
return null;
}
house.setHousenumber(hn);
house.setStreet(getStreetname(el));
house.setPlace(el.getTag(addrPlaceTagKey));
String zipStr = el.getTag(postalCodeTagKey);
ZipCodeInfo zip = getZipInfos(zipStr);
house.setZipCode(zip);
return house;
}
use of uk.me.parabola.mkgmap.general.CityInfo in project mkgmap by openstreetmap.
the class CityZipWriter method compile.
public boolean compile(List<Numbers> numbers) {
try {
// left and right entry in zip or city table
// current num
int[] indexes = { defaultIndex, defaultIndex };
// previous num
int[] refIndexes = { defaultIndex, defaultIndex };
int lastEncodedNodeIndex = -1;
boolean needsWrite = false;
for (Numbers num : numbers) {
for (int side = 0; side < 2; side++) {
indexes[side] = defaultIndex;
boolean left = (side == 0);
switch(type) {
case "zip":
ZipCodeInfo zipInfo = num.getZipCodeInfo(left);
if (zipInfo != null) {
if (zipInfo.getImgZip() != null) {
indexes[side] = zipInfo.getImgZip().getIndex();
}
}
break;
case "city":
CityInfo cityInfo = num.getCityInfo(left);
if (cityInfo != null) {
if (cityInfo.getImgCity() != null) {
indexes[side] = cityInfo.getImgCity().getIndex();
}
}
break;
default:
break;
}
}
if (indexes[0] == refIndexes[0] && indexes[1] == refIndexes[1])
continue;
needsWrite = true;
if (num.getIndex() > 0) {
int range = num.getIndex() - 1;
if (lastEncodedNodeIndex > 0)
range -= lastEncodedNodeIndex;
encode(range, refIndexes);
}
refIndexes[0] = indexes[0];
refIndexes[1] = indexes[1];
lastEncodedNodeIndex = num.getIndex();
}
if (needsWrite) {
int lastIndexWithNumbers = numbers.get(numbers.size() - 1).getIndex();
int range = lastIndexWithNumbers - lastEncodedNodeIndex;
encode(range, indexes);
} else {
// probably not needed
buf.reset();
}
} catch (Abandon e) {
return false;
}
return true;
}
Aggregations