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:
parent
cfa7b2eaa5
commit
9470285d3f
4 changed files with 159 additions and 11 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in a new issue