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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.osmand.osm.LatLon;
@ -28,6 +29,59 @@ public class Boundary {
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) {
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$
}
@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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -70,6 +71,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
private DataTileManager<City> cityManager = new DataTileManager<City>(10);
private List<Relation> postalCodeRelations = new ArrayList<Relation>();
private Map<City, Boundary> cityBoundaries = new HashMap<City, Boundary>();
private Set<Boundary> allBoundaries = new HashSet<Boundary>();
private TLongHashSet visitedBoundaryWays = new TLongHashSet();
private boolean normalizeStreets;
@ -82,6 +84,8 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
Connection mapConnection;
DBStreetDAO streetDAO;
public class DBStreetDAO
{
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()) {
// try to find same name in the middle
for (City c : citiesToSearch) {
if (boundary.containsPoint(c.getLocation())) {
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);
break;
}
@ -299,9 +304,43 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
//we can have more cities in one boundary!! (suburbs...)
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) {
int adminLevel = -1;
@ -605,12 +644,6 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
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);
}
@ -626,15 +659,23 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
Set<Long> values = new TreeSet<Long>();
for (City city : result) {
String cityPart = city.getName();
boolean found = false;
for(City subpart : result){
if(subpart != city){
Boundary subBoundary = cityBoundaries.get(subpart);
Boundary b = cityBoundaries.get(city);
if(b != null && subBoundary != null && subBoundary.getAdminLevel() > b.getAdminLevel()){
cityPart = subpart.getName();
if(b != null && subBoundary != null && subBoundary.getAdminLevel() > b.getAdminLevel()){
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);
if (foundId == null) {
long streetId = insertStreetData(addressStreetStat, name, nameEn, location.getLatitude(), location.getLongitude(), city.getId(),
@ -647,6 +688,24 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
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) {
@ -764,11 +823,12 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
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,
String name, String nameEn, double latitude,
double longitude, Long cityId, String cityPart) throws SQLException {
long streetId = streetIdSequence++;
// addressStreetStat.setLong(1, id);
addressStreetStat.setLong(1, streetId);
addressStreetStat.setString(4, name);
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,
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);
if (sameStreets == null) {
sameStreets = new ArrayList<StreetAndDistrict>(1);
@ -1137,6 +1197,12 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
city.setId(set.getLong(1));
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();
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.startTask(Messages.getString("IndexCreator.PREINDEX_ADRESS_MAP"), accessor.getAllRelations()); //$NON-NLS-1$
accessor.iterateOverEntities(progress, EntityType.RELATION, new OsmDbVisitor() {