Trying to find better street-city binding according existing boundaries.

Removing incomplete boundaries.
Returned the algorithm to search nearest city/village for streets with
same name that are near different districts.
This commit is contained in:
Pavol Zibrita 2011-09-26 21:08:29 +02:00
parent cfa7b2eaa5
commit 9470285d3f
4 changed files with 159 additions and 11 deletions

View file

@ -1,6 +1,7 @@
package net.osmand.data; package net.osmand.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import net.osmand.osm.LatLon; import net.osmand.osm.LatLon;
@ -28,6 +29,59 @@ public class Boundary {
return closedWay; return closedWay;
} }
public boolean computeIsClosedWay()
{
//now we try to merge the ways until we have only one
int oldSize = 0;
while (getOuterWays().size() != oldSize) {
oldSize = getOuterWays().size();
mergeOuterWays();
}
//there is one way and last element is equal to the first...
return getOuterWays().size() == 1 && getOuterWays().get(0).getNodes().get(0).getId() == getOuterWays().get(0).getNodes().get(getOuterWays().get(0).getNodes().size()-1).getId();
}
private void mergeOuterWays() {
Way way = getOuterWays().get(0);
List<Node> nodes = way.getNodes();
if (!nodes.isEmpty()) {
int nodesSize = nodes.size();
Node first = nodes.get(0);
Node last = nodes.get(nodesSize-1);
int size = getOuterWays().size();
for (int i = size-1; i >= 1; i--) {
//try to find way, that matches the one ...
Way anotherWay = getOuterWays().get(i);
if (anotherWay.getNodes().isEmpty()) {
//remove empty one...
getOuterWays().remove(i);
} else {
if (anotherWay.getNodes().get(0).getId() == first.getId()) {
//reverese this way and add it to the actual
Collections.reverse(anotherWay.getNodes());
way.getNodes().addAll(0,anotherWay.getNodes());
getOuterWays().remove(i);
} else if (anotherWay.getNodes().get(0).getId() == last.getId()) {
way.getNodes().addAll(anotherWay.getNodes());
getOuterWays().remove(i);
} else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == first.getId()) {
//add at begging
way.getNodes().addAll(0,anotherWay.getNodes());
getOuterWays().remove(i);
} else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == last.getId()) {
Collections.reverse(anotherWay.getNodes());
way.getNodes().addAll(anotherWay.getNodes());
getOuterWays().remove(i);
}
}
}
} else {
//remove way with no nodes!
getOuterWays().remove(0);
}
}
public boolean containsPoint(LatLon point) { public boolean containsPoint(LatLon point) {
return containsPoint(point.getLatitude(), point.getLongitude()); return containsPoint(point.getLatitude(), point.getLongitude());
} }

View file

@ -119,4 +119,29 @@ public abstract class MapObject implements Comparable<MapObject> {
return getClass().getSimpleName() + " " + name +"("+id+")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return getClass().getSimpleName() + " " + name +"("+id+")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MapObject other = (MapObject) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
} }

View file

@ -16,6 +16,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@ -70,6 +71,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
private DataTileManager<City> cityManager = new DataTileManager<City>(10); private DataTileManager<City> cityManager = new DataTileManager<City>(10);
private List<Relation> postalCodeRelations = new ArrayList<Relation>(); private List<Relation> postalCodeRelations = new ArrayList<Relation>();
private Map<City, Boundary> cityBoundaries = new HashMap<City, Boundary>(); private Map<City, Boundary> cityBoundaries = new HashMap<City, Boundary>();
private Set<Boundary> allBoundaries = new HashSet<Boundary>();
private TLongHashSet visitedBoundaryWays = new TLongHashSet(); private TLongHashSet visitedBoundaryWays = new TLongHashSet();
private boolean normalizeStreets; private boolean normalizeStreets;
@ -82,6 +84,8 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
Connection mapConnection; Connection mapConnection;
DBStreetDAO streetDAO; DBStreetDAO streetDAO;
public class DBStreetDAO public class DBStreetDAO
{ {
protected void writeStreetWayNodes(Set<Long> streetIds, Way way) throws SQLException { protected void writeStreetWayNodes(Set<Long> streetIds, Way way) throws SQLException {
@ -267,12 +271,13 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
} }
} }
} }
//We should not look for similarities, this can be 'very' wrong....
if (cityFound.isEmpty()) { if (cityFound.isEmpty()) {
// try to find same name in the middle // try to find same name in the middle
for (City c : citiesToSearch) { for (City c : citiesToSearch) {
if (boundary.containsPoint(c.getLocation())) { if (boundary.containsPoint(c.getLocation())) {
String lower = c.getName().toLowerCase(); String lower = c.getName().toLowerCase();
if (boundaryName.startsWith(lower) || boundaryName.endsWith(lower) || boundaryName.contains(" " + lower + " ")) { if (boundaryName.startsWith(lower + " ") || boundaryName.endsWith(lower + " ") || boundaryName.contains(" " + lower + " ")) {
cityFound.add(c); cityFound.add(c);
break; break;
} }
@ -299,9 +304,43 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
//we can have more cities in one boundary!! (suburbs...) //we can have more cities in one boundary!! (suburbs...)
putCityBoundary(boundary, cityFound); putCityBoundary(boundary, cityFound);
} }
allBoundaries.add(boundary);
} }
} }
public void bindCitiesWithBoundaries() {
Iterator<Boundary> iter = allBoundaries.iterator();
while (iter.hasNext()) {
Boundary b = iter.next();
if (!b.computeIsClosedWay()) {
System.out.println("Removing not closed boundary: " + b.getName() + " alevel:" + b.getAdminLevel());
iter.remove();
}
}
//for cities without boundaries, try to find the right one
for (City c : cities.values()) {
Boundary cityB = cityBoundaries.get(c);
int smallestAdminLevel = 8; //TODO start at level 8 for now...
if (cityB == null) {
LatLon location = c.getLocation();
Boundary smallestoundary = null;
//try to found boundary
for (Boundary b : allBoundaries) {
if (b.containsPoint(location.getLatitude(), location.getLongitude())) {
//the bigger the admin level, the smaller the boundary :-)
if (b.getAdminLevel() > smallestAdminLevel) {
smallestAdminLevel = b.getAdminLevel();
smallestoundary = b;
}
}
}
if (smallestoundary != null) {
putCityBoundary(smallestoundary, Collections.singletonList(c));
}
}
}
}
private int extractBoundaryAdminLevel(Entity e) { private int extractBoundaryAdminLevel(Entity e) {
int adminLevel = -1; int adminLevel = -1;
@ -605,12 +644,6 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
result.add(city); result.add(city);
} }
} }
// for (Entry<City,Boundary> cb : cityBoundaries.entrySet()) {
// if (cb.getValue().containsPoint(location)) {
// result.add(cb.getKey());
// }
// }
return registerStreetInCities(name, nameEn, location, result); return registerStreetInCities(name, nameEn, location, result);
} }
@ -626,15 +659,23 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
Set<Long> values = new TreeSet<Long>(); Set<Long> values = new TreeSet<Long>();
for (City city : result) { for (City city : result) {
String cityPart = city.getName(); String cityPart = city.getName();
boolean found = false;
for(City subpart : result){ for(City subpart : result){
if(subpart != city){ if(subpart != city){
Boundary subBoundary = cityBoundaries.get(subpart); Boundary subBoundary = cityBoundaries.get(subpart);
Boundary b = cityBoundaries.get(city); Boundary b = cityBoundaries.get(city);
if(b != null && subBoundary != null && subBoundary.getAdminLevel() > b.getAdminLevel()){ if(b != null && subBoundary != null && subBoundary.getAdminLevel() > b.getAdminLevel()){
cityPart = subpart.getName(); cityPart = findNearestCityOrSuburb(subBoundary, location); //subpart.getName();
found = true;
} }
} }
} }
if (!found) {
Boundary b = cityBoundaries.get(city);
if (b != null) {
cityPart = findNearestCityOrSuburb(b, location);
}
}
Long foundId = streetDAO.findStreet(name, city, cityPart); Long foundId = streetDAO.findStreet(name, city, cityPart);
if (foundId == null) { if (foundId == null) {
long streetId = insertStreetData(addressStreetStat, name, nameEn, location.getLatitude(), location.getLongitude(), city.getId(), long streetId = insertStreetData(addressStreetStat, name, nameEn, location.getLatitude(), location.getLongitude(), city.getId(),
@ -647,6 +688,24 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
return values; return values;
} }
private String findNearestCityOrSuburb(Boundary greatestBoundary,
LatLon location) {
String result = greatestBoundary.getName();
List<City> nearestObjects = new ArrayList<City>();
nearestObjects.addAll(cityManager.getClosestObjects(location.getLatitude(),location.getLongitude()));
nearestObjects.addAll(cityVillageManager.getClosestObjects(location.getLatitude(),location.getLongitude()));
double dist = Double.MAX_VALUE;
for (City c : nearestObjects) {
if (greatestBoundary.containsPoint(c.getLocation())) {
double actualDistance = MapUtils.getDistance(location, c.getLocation());
if (actualDistance < dist) {
result = c.getName();
dist = actualDistance;
}
}
}
return result;
}
public City getClosestCity(LatLon point, Set<String> isInNames) { public City getClosestCity(LatLon point, Set<String> isInNames) {
@ -764,11 +823,12 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
private long streetIdSequence = 0; private long streetIdSequence = 0;
private boolean debugFullNames = false; //true to see atached cityPart and boundaries to the street names
private long insertStreetData(PreparedStatement addressStreetStat, //long id, private long insertStreetData(PreparedStatement addressStreetStat, //long id,
String name, String nameEn, double latitude, String name, String nameEn, double latitude,
double longitude, Long cityId, String cityPart) throws SQLException { double longitude, Long cityId, String cityPart) throws SQLException {
long streetId = streetIdSequence++; long streetId = streetIdSequence++;
// addressStreetStat.setLong(1, id);
addressStreetStat.setLong(1, streetId); addressStreetStat.setLong(1, streetId);
addressStreetStat.setString(4, name); addressStreetStat.setString(4, name);
addressStreetStat.setString(5, nameEn); addressStreetStat.setString(5, nameEn);
@ -1092,7 +1152,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
private String identifyBestDistrict(final Street street, final String streetName, final String district, private String identifyBestDistrict(final Street street, final String streetName, final String district,
final Map<String, List<StreetAndDistrict>> uniqueNames, Map<Street, List<Node>> streetNodes) { final Map<String, List<StreetAndDistrict>> uniqueNames, Map<Street, List<Node>> streetNodes) {
String result = ""; String result = debugFullNames ? district : ""; //TODO make it an option
List<StreetAndDistrict> sameStreets = uniqueNames.get(streetName); List<StreetAndDistrict> sameStreets = uniqueNames.get(streetName);
if (sameStreets == null) { if (sameStreets == null) {
sameStreets = new ArrayList<StreetAndDistrict>(1); sameStreets = new ArrayList<StreetAndDistrict>(1);
@ -1137,6 +1197,12 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
city.setId(set.getLong(1)); city.setId(set.getLong(1));
cities.add(city); cities.add(city);
if (debugFullNames) { //TODO make it an option...
Boundary cityB = cityBoundaries.get(city);
if (cityB != null) {
city.setName(city.getName() + " " + cityB.getAdminLevel() + ":" + cityB.getName());
}
}
} }
set.close(); set.close();
stat.close(); stat.close();

View file

@ -460,6 +460,9 @@ public class IndexCreator {
} }
}); });
//finish up the boundaries and cities
indexAddressCreator.bindCitiesWithBoundaries();
progress.setGeneralProgress("[45 / 100]"); //$NON-NLS-1$ progress.setGeneralProgress("[45 / 100]"); //$NON-NLS-1$
progress.startTask(Messages.getString("IndexCreator.PREINDEX_ADRESS_MAP"), accessor.getAllRelations()); //$NON-NLS-1$ progress.startTask(Messages.getString("IndexCreator.PREINDEX_ADRESS_MAP"), accessor.getAllRelations()); //$NON-NLS-1$
accessor.iterateOverEntities(progress, EntityType.RELATION, new OsmDbVisitor() { accessor.iterateOverEntities(progress, EntityType.RELATION, new OsmDbVisitor() {