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:
parent
b6c9e20be2
commit
110edbef8b
5 changed files with 275 additions and 15 deletions
142
DataExtractionOSM/src/net/osmand/data/Boundary.java
Normal file
142
DataExtractionOSM/src/net/osmand/data/Boundary.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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$
|
||||
|
|
|
@ -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$
|
||||
|
|
|
@ -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);
|
||||
|
@ -75,8 +75,7 @@ public class SearchStreet2ByNameActivity extends SearchByNameAbstractActivity<St
|
|||
setText(getFilter().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}.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)) {
|
||||
|
|
Loading…
Reference in a new issue