implement street search using boundaries

git-svn-id: https://osmand.googlecode.com/svn/trunk@877 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2011-01-10 00:03:40 +00:00
parent b6c9e20be2
commit 110edbef8b
5 changed files with 275 additions and 15 deletions

View file

@ -0,0 +1,142 @@
package net.osmand.data;
import java.util.ArrayList;
import java.util.List;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import net.osmand.osm.Node;
import net.osmand.osm.Way;
public class Boundary {
private long boundaryId;
private String name;
private String adminLevel;
// ? ready rings
private List<Way> outerWays = new ArrayList<Way>();
private List<Way> innerWays = new ArrayList<Way>();
public boolean containsPoint(LatLon point) {
return containsPoint(point.getLatitude(), point.getLongitude());
}
public boolean containsPoint(double latitude, double longitude) {
int intersections = 0;
for(Way w : outerWays){
for(int i=0; i<w.getNodes().size() - 1; i++){
if(ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){
intersections ++;
}
}
}
for(Way w : innerWays){
for(int i=0; i<w.getNodes().size() - 1; i++){
if(ray_intersect(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude)){
intersections ++;
}
}
}
return intersections % 2 == 1;
}
private boolean ray_intersect(Node node, Node node2, double latitude, double longitude) {
// a node below
Node a = node.getLatitude() < node2.getLatitude() ? node : node2;
// b node above
Node b = a == node2 ? node : node2;
if(latitude == a.getLatitude() || latitude == b.getLatitude()){
latitude += 0.00001d;
}
if(latitude < a.getLatitude() || latitude > b.getLatitude()){
return false;
} else {
if(longitude > Math.max(a.getLongitude(), b.getLongitude())) {
return true;
} else if(longitude < Math.min(a.getLongitude(), b.getLongitude())){
return false;
} else {
double mR;
if(a.getLongitude() != b.getLongitude()){
mR = (b.getLatitude() - a.getLatitude()) / (b.getLongitude() - a.getLongitude());
} else {
mR = Double.POSITIVE_INFINITY;
}
double mB;
if(a.getLongitude() != b.getLongitude()){
mB = (latitude - a.getLatitude()) / (longitude - a.getLongitude());
} else {
mB = Double.POSITIVE_INFINITY;
}
if(mB >= mR){
return true;
} else {
return false;
}
}
}
}
public void initializeWay(Way w) {
for (int i = 0; i < outerWays.size(); i++) {
if (outerWays.get(i).getId() == w.getId()) {
outerWays.set(i, w);
}
}
for (int i = 0; i < innerWays.size(); i++) {
if (innerWays.get(i).getId() == w.getId()) {
innerWays.set(i, w);
}
}
}
public LatLon getCenterPoint(){
List<Node> points = new ArrayList<Node>();
for(Way w : outerWays){
points.addAll(w.getNodes());
}
for(Way w : innerWays){
points.addAll(w.getNodes());
}
return MapUtils.getWeightCenterForNodes(points);
}
public List<Way> getOuterWays() {
return outerWays;
}
public List<Way> getInnerWays() {
return innerWays;
}
public long getBoundaryId() {
return boundaryId;
}
public void setBoundaryId(long boundaryId) {
this.boundaryId = boundaryId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdminLevel() {
return adminLevel;
}
public void setAdminLevel(String adminLevel) {
this.adminLevel = adminLevel;
}
}

View file

@ -4,7 +4,6 @@ import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.osmand.Algoritms;

View file

@ -34,6 +34,7 @@ import net.osmand.Algoritms;
import net.osmand.IProgress;
import net.osmand.binary.BinaryMapIndexWriter;
import net.osmand.data.Amenity;
import net.osmand.data.Boundary;
import net.osmand.data.Building;
import net.osmand.data.City;
import net.osmand.data.DataTileManager;
@ -99,7 +100,8 @@ public class IndexCreator {
public static final int STEP_CITY_NODES = 1;
public static final int STEP_ADDRESS_RELATIONS_AND_MULTYPOLYGONS = 2;
public static final int STEP_MAIN = 3;
public static final int STEP_BORDER_CITY_WAYS = 3;
public static final int STEP_MAIN = 4;
private File workingDir = null;
@ -180,6 +182,9 @@ public class IndexCreator {
private DataTileManager<City> cityVillageManager = new DataTileManager<City>(13);
private DataTileManager<City> cityManager = new DataTileManager<City>(10);
private List<Relation> postalCodeRelations = new ArrayList<Relation>();
// TODO
private Map<City, Boundary> citiBoundaries = new LinkedHashMap<City, Boundary>();
private Set<Long> visitedBoundaryWays = new HashSet<Long>();
private String[] normalizeDefaultSuffixes;
private String[] normalizeSuffixes;
@ -827,7 +832,85 @@ public class IndexCreator {
});
return r;
}
public void indexBoundariesRelation(Entity e) throws SQLException {
String adminLevel = e.getTag("admin_level");
Boundary boundary = null;
// mostly city admin_level
if ("8".equals(adminLevel)) {
if (e instanceof Relation) {
Relation i = (Relation) e;
loadEntityData(i, true);
boundary = new Boundary();
if (i.getTag(OSMTagKey.NAME) != null) {
boundary.setName(i.getTag(OSMTagKey.NAME));
}
boundary.setBoundaryId(i.getId());
Map<Entity, String> entities = i.getMemberEntities();
for (Entity es : entities.keySet()) {
if (es instanceof Way) {
boolean inner = "inner".equals(entities.get(es)); //$NON-NLS-1$
if (inner) {
boundary.getInnerWays().add((Way) es);
} else {
String wName = es.getTag(OSMTagKey.NAME);
// if name are not equal keep the way for further check (it could be different suburb)
if (Algoritms.objectEquals(wName, boundary.getName()) || wName == null) {
visitedBoundaryWays.add(es.getId());
}
boundary.getOuterWays().add((Way) es);
}
}
}
} else if (e instanceof Way) {
if (!visitedBoundaryWays.contains(e.getId())) {
boundary = new Boundary();
if (e.getTag(OSMTagKey.NAME) != null) {
boundary.setName(e.getTag(OSMTagKey.NAME));
}
boundary.setBoundaryId(e.getId());
boundary.getOuterWays().add((Way) e);
}
}
}
if(boundary != null){
LatLon point = boundary.getCenterPoint();
boolean cityFound = false;
for (City c : cityManager.getClosestObjects(point.getLatitude(), point.getLongitude(), 3)) {
if(boundary.containsPoint(c.getLocation())){
if(boundary.getName() == null || boundary.getName().equalsIgnoreCase(c.getName())) {
citiBoundaries.put(c, boundary);
cityFound = true;
}
}
}
// TODO mark all suburbs inside city as is_in tag (!) or use another solution
if (!cityFound) {
for (City c : cityVillageManager.getClosestObjects(point.getLatitude(), point.getLongitude(), 3)) {
if(boundary.containsPoint(c.getLocation())){
if(boundary.getName() == null || boundary.getName().equalsIgnoreCase(c.getName())) {
citiBoundaries.put(c, boundary);
cityFound = true;
}
}
}
}
if(!cityFound && boundary.getName() != null){
/// create new city for named boundary very rare case that's why do not proper generate id
// however it could be a problem
City nCity = new City(CityType.SUBURB);
nCity.setLocation(point.getLatitude(), point.getLongitude());
nCity.setId(-boundary.getBoundaryId());
cityVillageManager.registerObject(point.getLatitude(), point.getLongitude(), nCity);
// do not put into cities because there is no id
// cities.put(ncity.getEntityId(), nCity);
}
}
}
public void indexAddressRelation(Relation i) throws SQLException {
@ -960,6 +1043,23 @@ public class IndexCreator {
if (point == null) {
return null;
}
for (City c : cityManager.getClosestObjects(point.getLatitude(), point.getLongitude(), 3)) {
Boundary boundary = citiBoundaries.get(c);
if(boundary != null){
if(boundary.containsPoint(point)){
return c;
}
}
}
for (City c : cityVillageManager.getClosestObjects(point.getLatitude(), point.getLongitude(), 3)) {
Boundary boundary = citiBoundaries.get(c);
if(boundary != null){
if(boundary.containsPoint(point)){
return c;
}
}
}
City closest = null;
double relDist = Double.POSITIVE_INFINITY;
for (City c : cityManager.getClosestObjects(point.getLatitude(), point.getLongitude(), 3)) {
@ -1222,11 +1322,21 @@ public class IndexCreator {
}
}
}
} else if(step == STEP_BORDER_CITY_WAYS) {
if (indexAddress) {
if (e instanceof Way && "administrative".equals(e.getTag(OSMTagKey.BOUNDARY))) { //$NON-NLS-1$
indexBoundariesRelation(e);
}
}
} else if (step == STEP_ADDRESS_RELATIONS_AND_MULTYPOLYGONS) {
if (indexAddress) {
if (e instanceof Relation && "address".equals(e.getTag(OSMTagKey.TYPE))) { //$NON-NLS-1$
indexAddressRelation((Relation) e);
}
if (e instanceof Relation && "administrative".equals(e.getTag(OSMTagKey.BOUNDARY))) { //$NON-NLS-1$
indexBoundariesRelation((Relation) e);
}
}
if (indexMap && e instanceof Relation && "restriction".equals(e.getTag(OSMTagKey.TYPE))) { //$NON-NLS-1$
String val = e.getTag("restriction"); //$NON-NLS-1$
@ -2409,7 +2519,7 @@ public class IndexCreator {
// 3.2 index address relations
if (indexAddress || indexMap) {
progress.setGeneralProgress("[40 / 100]"); //$NON-NLS-1$
progress.setGeneralProgress("[30 / 100]"); //$NON-NLS-1$
progress.startTask(Messages.getString("IndexCreator.PREINDEX_ADRESS_MAP"), allRelations); //$NON-NLS-1$
allRelations = iterateOverEntities(progress, EntityType.RELATION, allRelations,
STEP_ADDRESS_RELATIONS_AND_MULTYPOLYGONS);
@ -2425,6 +2535,11 @@ public class IndexCreator {
}
mapConnection.commit();
}
if (indexAddress) {
progress.setGeneralProgress("[40 / 100]"); //$NON-NLS-1$
progress.startTask(Messages.getString("IndexCreator.PREINDEX_ADRESS_MAP"), allWays); //$NON-NLS-1$
allWays = iterateOverEntities(progress, EntityType.WAY, allWays, STEP_BORDER_CITY_WAYS);
}
}
// 3.3 MAIN iterate over all entities
@ -2833,18 +2948,20 @@ public class IndexCreator {
long time = System.currentTimeMillis();
IndexCreator creator = new IndexCreator(new File("e:/Information/OSM maps/osmand/")); //$NON-NLS-1$
creator.setIndexMap(true);
IndexCreator creator = new IndexCreator(new File("/home/victor/Projects/OsmAnd/data/osmand/")); //$NON-NLS-1$
// creator.setIndexMap(true);
creator.setIndexAddress(true);
creator.setIndexPOI(true);
creator.setIndexTransport(true);
// creator.setIndexPOI(true);
// creator.setIndexTransport(true);
creator.recreateOnlyBinaryFile = false;
creator.deleteDatabaseIndexes = true;
// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/ukraine.osm"),
// creator.generateIndexes(new File("/home/victor/Projects/OsmAnd/data/osm maps/amsteelven_part.osm"),
// new ConsoleProgressImplementation(3), null, MapZooms.getDefault(), null);
creator.generateIndexes(new File("/home/victor/Projects/OsmAnd/data/osm-maps/minsk_around.osm.bz2"),
new ConsoleProgressImplementation(3), null, MapZooms.getDefault(), null);
// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb"));
// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/minsk.osm"), new ConsoleProgressImplementation(3), null, MapZooms.getDefault(), null);
@ -2869,7 +2986,7 @@ public class IndexCreator {
// creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/new_zealand.osm.bz2"), new ConsoleProgressImplementation(3), null);
// creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/map.osm"), new ConsoleProgressImplementation(15), null);
creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/bayarea.osm"), new ConsoleProgressImplementation(15), null);
// creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/bayarea.osm"), new ConsoleProgressImplementation(15), null);
System.out.println("WHOLE GENERATION TIME : " + (System.currentTimeMillis() - time)); //$NON-NLS-1$
System.out.println("COORDINATES_SIZE " + BinaryMapIndexWriter.COORDINATES_SIZE + " count " + BinaryMapIndexWriter.COORDINATES_COUNT); //$NON-NLS-1$ //$NON-NLS-2$

View file

@ -9,6 +9,7 @@ public class OSMSettings {
// ways
HIGHWAY("highway"), //$NON-NLS-1$
BUILDING("building"), //$NON-NLS-1$
BOUNDARY("boundary"), //$NON-NLS-1$
POSTAL_CODE("postal_code"), //$NON-NLS-1$
RAILWAY("railway"), //$NON-NLS-1$
ONEWAY("oneway"), //$NON-NLS-1$

View file

@ -20,9 +20,9 @@ public class SearchStreet2ByNameActivity extends SearchByNameAbstractActivity<St
private City city;
private PostCode postcode;
private Street street1;
volatile private List<Street> initialList = new ArrayList<Street>();
private List<Street> filterList = new ArrayList<Street>();
private List<Street> initialList = new ArrayList<Street>();
private ProgressDialog progressDlg;
@Override
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = OsmandSettings.getPrefs(this);
@ -76,7 +76,6 @@ public class SearchStreet2ByNameActivity extends SearchByNameAbstractActivity<St
}
});
}
}
}
}.start();
@ -85,10 +84,12 @@ public class SearchStreet2ByNameActivity extends SearchByNameAbstractActivity<St
public List<Street> getObjects(String filter) {
int ind = 0;
filter = filter.toLowerCase();
List<Street> filterList = new ArrayList<Street>();
if(filter.length() == 0){
return initialList;
filterList.addAll(initialList);
return filterList;
}
filterList.clear();
for (Street s : initialList) {
String lowerCase = s.getName(region.useEnglishNames()).toLowerCase();
if (lowerCase.startsWith(filter)) {