fix issues

improve address

git-svn-id: https://osmand.googlecode.com/svn/trunk@436 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-08-04 21:07:15 +00:00
parent c8e9f2a544
commit 92150907d8
14 changed files with 232 additions and 58 deletions

View file

@ -11,8 +11,8 @@ public class ToDoConstants {
// TODO swing
// 9. Fix issues with big files (such as netherlands) - save memory (!) - very slow due to transport index !
// Current result : for big file (1 - task 60-80% time, 90% memory) (?)
// !! 10. Improve address indexing (use relations). (?) // SLOBODSKAYA 157, 95
// use relation "a6" (to accumulate streets!), "a3" to read all cities & define boundaries for city (& define that street in city).
// !! 10. Improve address indexing (use relations). (+)
// use relation "a6" (to accumulate streets!), "a3" to read all cities & define boundaries for city (& define that street in city).
// TODO max 86
// ! 81. Add some objects to POI category (1) to add them into OSM 2) to help navigation)
@ -22,7 +22,7 @@ public class ToDoConstants {
// 85. Remove context menu on long press map ! Accumulate actions and show label.
// TODO BUGS Android
// !! 3. different screens better support
// !! 3. different screens better support (+)
// Fix map zoom by default map (in 1.5 for high density) OsmandMapTileView (+)

View file

@ -1,6 +1,7 @@
package com.osmand.data;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
@ -123,7 +124,7 @@ public class City extends MapObject {
}
public void doDataPreparation(){
for(Street s : getStreets()){
for(Street s : new ArrayList<Street>(getStreets())){
s.doDataPreparation();
}
}

View file

@ -27,10 +27,16 @@ public class Street extends MapObject {
public Street(City city) {
this.city = city;
}
public Building registerBuilding(Entity e){
return registerBuilding(e, e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER));
}
public Building registerBuilding(Entity e, String ref){
if(ref == null){
return null;
}
Building building = new Building(e);
building.setName(e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER));
building.setName(ref);
buildings.add(building);
return building;
}
@ -114,9 +120,12 @@ public class Street extends MapObject {
}
location = MapUtils.getWeightCenter(nodes);
}
if(location == null || (wayNodes.isEmpty() && buildings.isEmpty())){
city.unregisterStreet(name);
}
if (wayNodes.size() > 0) {
this.id = wayNodes.get(0).getId();
} else {
} else if(buildings.size() > 0){
this.id = buildings.get(0).getId();
}

View file

@ -106,7 +106,16 @@ public class DataExtraction {
private File workingDir = null;
// TODO : type=address
// address:a6=name_street
// address:type=a6
// is_in..., label...
// TODO <member type="relation" ref="81833" role="is_in"/>
// <member type="way" ref="25426285" role="border"/>
// <tag k="address:house" v="13"/>
// <tag k="address:type" v="house"/>
// <tag k="type" v="address"/>
public DataExtraction(boolean indexAddress, boolean indexPOI, boolean indexTransport, boolean normalizeStreets,
@ -124,15 +133,18 @@ public class DataExtraction {
protected class DataExtractionOsmFilter implements IOsmStorageFilter {
ArrayList<Node> places = new ArrayList<Node>();
ArrayList<Entity> buildings = new ArrayList<Entity>();
ArrayList<Entity> amenities = new ArrayList<Entity>();
ArrayList<Way> ways = new ArrayList<Way>();
Map<EntityId, Relation> addressRelations = new LinkedHashMap<EntityId, Relation>();
Map<EntityId, Way> ways = new LinkedHashMap<EntityId, Way>();
Map<EntityId, Entity> buildings = new LinkedHashMap<EntityId, Entity>();
ArrayList<Relation> transport = new ArrayList<Relation>();
Map<EntityId, String> postalCodes = new LinkedHashMap<EntityId, String>();
private Connection conn;
//
private boolean preloadRelationAndWaysIntoDB = false;
private boolean createWholeOsmDB = false;
@ -160,13 +172,18 @@ public class DataExtraction {
public ArrayList<Node> getPlaces() {
return places;
}
public ArrayList<Entity> getBuildings() {
public Map<EntityId, Entity> getBuildings() {
return buildings;
}
public ArrayList<Entity> getAmenities() {
return amenities;
}
public ArrayList<Way> getWays() {
public Map<EntityId, Relation> getAddressRelations() {
return addressRelations;
}
public Map<EntityId, Way> getWays() {
return ways;
}
public ArrayList<Relation> getTransport() {
@ -217,7 +234,7 @@ public class DataExtraction {
prepWays = conn.prepareStatement("insert into ways values (?, ?);");
prepRelations = conn.prepareStatement("insert into relations values (?, ?, ?, ?);");
prepTags = conn.prepareStatement("insert into tags values (?, ?, ?, ?);");
preloadRelationAndWaysIntoDB = indexTransport;
preloadRelationAndWaysIntoDB = indexTransport || indexAddress;
conn.setAutoCommit(false);
}
@ -316,16 +333,8 @@ public class DataExtraction {
}
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity e) {
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity e) {
boolean processed = false;
if (indexAddress) {
if ("yes".equals(e.getTag(OSMTagKey.BUILDING))) {
if (e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER) != null && e.getTag(OSMTagKey.ADDR_STREET) != null) {
buildings.add(e);
processed = true;
}
}
}
if (indexPOI && Amenity.isAmenity(e)) {
amenities.add(e);
processed = true;
@ -335,19 +344,31 @@ public class DataExtraction {
processed = true;
}
if (indexAddress) {
if ("yes".equals(e.getTag(OSMTagKey.BUILDING))) {
if (e.getTag(OSMTagKey.ADDR_HOUSE_NUMBER) != null/*&& e.getTag(OSMTagKey.ADDR_STREET) != null*/) {
buildings.put(entityId, e);
processed = true;
}
}
// suppose that streets are way for car
if (e instanceof Way && OSMSettings.wayForCar(e.getTag(OSMTagKey.HIGHWAY)) && e.getTag(OSMTagKey.NAME) != null) {
ways.add((Way) e);
ways.put(entityId, (Way) e);
processed = true;
}
if(e instanceof Relation){
// do not need to mark processed
if(e.getTag(OSMTagKey.POSTAL_CODE) != null){
String tag = e.getTag(OSMTagKey.POSTAL_CODE);
for(EntityId l : ((Relation)e).getMemberIds()){
postalCodes.put(l, tag);
}
}
// do not need to mark processed
if("address".equals(e.getTag(OSMTagKey.TYPE))){
addressRelations.put(entityId, (Relation) e);
processed = true;
}
}
}
if(indexTransport){
@ -398,7 +419,7 @@ public class DataExtraction {
prepRelations.setLong(2, i.getKey().getId());
prepRelations.setLong(3, i.getKey().getType().ordinal());
prepRelations.setString(4, i.getValue());
prepWays.addBatch();
prepRelations.addBatch();
}
if (currentRelationsCount >= BATCH_SIZE) {
prepRelations.executeBatch();
@ -457,11 +478,12 @@ public class DataExtraction {
DataExtractionOsmFilter filter = new DataExtractionOsmFilter(regionName);
// data to load & index
final ArrayList<Node> places = filter.getPlaces();
final ArrayList<Entity> buildings = filter.getBuildings();
final Map<EntityId, Entity> buildings = filter.getBuildings();
final Map<EntityId, Way> ways = filter.getWays();
final ArrayList<Entity> amenities = filter.getAmenities();
final ArrayList<Way> ways = filter.getWays();
final ArrayList<Relation> transport = filter.getTransport();
Map<EntityId, String> postalCodes = filter.getPostalCodes();
final Map<EntityId, Relation> addressRelations = filter.getAddressRelations();
final Map<EntityId, String> postalCodes = filter.getPostalCodes();
storage.getFilters().add(filter);
// 0. Loading osm file
@ -503,11 +525,15 @@ public class DataExtraction {
// 3. Reading cities
progress.setGeneralProgress("[65 of 100]");
progress.startTask("Indexing cities...", -1);
readingCities(places, country);
LinkedHashMap<EntityId, City> registeredCities = new LinkedHashMap<EntityId, City>();
readingCities(places, country, registeredCities);
if (indexAddress) {
// 4. Reading streets
progress.setGeneralProgress("[80 of 100]");
// 4.1 Reading address relations & remove read streets/buildings
readingAddresses(progress, addressRelations, registeredCities, ways, buildings, postalCodes, country);
// 4. Reading streets
readingStreets(progress, ways, country);
// 5. reading buildings
@ -570,10 +596,10 @@ public class DataExtraction {
}
private void readingBuildings(IProgress progress, final ArrayList<Entity> buildings, Region country, Map<EntityId, String> postalCodes) {
private void readingBuildings(IProgress progress, final Map<EntityId, Entity> buildings, Region country, Map<EntityId, String> postalCodes) {
// found buildings (index addresses)
progress.startTask("Indexing buildings...", buildings.size());
for(Entity b : buildings){
for(Entity b : buildings.values()){
LatLon center = b.getLatLon();
progress.progress(1);
// TODO first of all tag could be checked NodeUtil.getTag(e, "addr:city")
@ -584,27 +610,140 @@ public class DataExtraction {
if(city == null){
Node n = new Node(center.getLatitude(), center.getLongitude(), -1);
n.putTag(OSMTagKey.PLACE.getValue(), CityType.TOWN.name());
n.putTag(OSMTagKey.NAME.getValue(), "Uknown city");
n.putTag(OSMTagKey.NAME.getValue(), "Unknown city");
country.registerCity(n);
city = country.getClosestCity(center);
}
if (city != null) {
Building building = city.registerBuilding(b);
EntityId i = building.getEntityId();
if(postalCodes.containsKey(i) ){
building.setPostcode(postalCodes.get(i));
if (building != null) {
EntityId i = building.getEntityId();
if (postalCodes.containsKey(i)) {
building.setPostcode(postalCodes.get(i));
}
}
}
}
}
progress.finishTask();
}
private void readingAddresses(IProgress progress, Map<EntityId, Relation> addressRelations, Map<EntityId, City> cities,
Map<EntityId, Way> ways, Map<EntityId, Entity> buildings,
Map<EntityId, String> postalCodes, Region country) {
progress.startTask("Indexing addresses...", addressRelations.size());
for(Relation i : addressRelations.values()){
progress.progress(1);
String type = i.getTag(OSMTagKey.ADDRESS_TYPE);
boolean house = "house".equals(type);
boolean street = "a6".equals(type);
if(house || street){
// try to find appropriate city/street
City c = null;
Collection<Entity> members = i.getMembers("is_in");
Relation a3 = null;
Relation a6 = null;
if(!members.isEmpty()){
if(street){
a6 = i;
}
Entity in = members.iterator().next();
if(in instanceof Relation){
// go one level up for house
if(house){
a6 = (Relation) in;
members = ((Relation)in).getMembers("is_in");
if(!members.isEmpty()){
in = members.iterator().next();
if(in instanceof Relation){
a3 = (Relation) in;
}
}
} else {
a3 = (Relation) in;
}
}
}
if(a3 != null){
Collection<EntityId> memberIds = a3.getMemberIds("label");
if(!memberIds.isEmpty()){
c = cities.get(memberIds.iterator().next());
}
}
if(c != null && a6 != null){
String name = a6.getTag(OSMTagKey.NAME);
if(name != null){
Street s = c.registerStreet(name);
if(street){
for (Map.Entry<Entity, String> r : i.getMemberEntities().entrySet()) {
if ("street".equals(r.getValue())) {
if (r.getKey() instanceof Way) {
s.getWayNodes().add((Way) r.getKey());
ways.remove(EntityId.valueOf(r.getKey()));
}
} else if ("house".equals(r.getValue())) {
// will be registered further in other case
if (!(r.getKey() instanceof Relation)) {
EntityId id = EntityId.valueOf(r.getKey());
Building b = s.registerBuilding(r.getKey());
buildings.remove(id);
if (b != null) {
if (postalCodes.containsKey(id)) {
b.setPostcode(postalCodes.get(id));
}
}
}
}
}
} else {
String hno = i.getTag(OSMTagKey.ADDRESS_HOUSE);
if(hno == null){
hno = i.getTag(OSMTagKey.ADDR_HOUSE_NUMBER);
}
if(hno == null){
hno = i.getTag(OSMTagKey.NAME);
}
members = i.getMembers("border");
if(!members.isEmpty()){
Entity border = members.iterator().next();
if (border != null) {
EntityId id = EntityId.valueOf(border);
// special check that address do not contain twice in a3 - border and separate a6
if (!a6.getMemberIds().contains(id)) {
Building b = s.registerBuilding(border, hno);
if (b != null && postalCodes.containsKey(id)) {
b.setPostcode(postalCodes.get(id));
}
buildings.remove(id);
}
}
} else {
log.info("For relation " + i.getId() + " border not found");
}
}
}
}
}
}
progress.finishTask();
}
private void readingStreets(IProgress progress, final ArrayList<Way> ways, Region country) {
private void readingStreets(IProgress progress, final Map<EntityId, Way> ways, Region country) {
progress.startTask("Indexing streets...", ways.size());
DataTileManager<Way> waysManager = new DataTileManager<Way>();
for (Way w : ways) {
for (Way w : ways.values()) {
progress.progress(1);
if (w.getTag(OSMTagKey.NAME) != null) {
String street = w.getTag(OSMTagKey.NAME);
@ -783,13 +922,16 @@ public class DataExtraction {
}
public void readingCities(ArrayList<Node> places, Region country) {
public void readingCities(ArrayList<Node> places, Region country, Map<EntityId, City> citiesMap) {
for (Node s : places) {
String place = s.getTag(OSMTagKey.PLACE);
if (place == null) {
continue;
}
country.registerCity(s);
City city = country.registerCity(s);
if(city != null){
citiesMap.put(city.getEntityId(), city);
}
}
}
@ -904,7 +1046,7 @@ public class DataExtraction {
storage.getFilters().add(new IOsmStorageFilter(){
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity) {
return false;
}
});

View file

@ -29,10 +29,15 @@ public abstract class Entity {
private final EntityType type;
private final Long id;
public EntityId(EntityType type, Long id){
this.type = type;
this.id = id;
}
public static EntityId valueOf(Entity e){
return new EntityId(EntityType.valueOf(e), e.getId());
}
@Override
public int hashCode() {
@ -43,6 +48,11 @@ public abstract class Entity {
return result;
}
@Override
public String toString() {
return type + " " + id;
}
public EntityType getType() {
return type;
}

View file

@ -5,6 +5,7 @@ public class OSMSettings {
public enum OSMTagKey {
NAME("name"), //$NON-NLS-1$
NAME_EN("name:en"), //$NON-NLS-1$
// ways
HIGHWAY("highway"), //$NON-NLS-1$
BUILDING("building"), //$NON-NLS-1$
@ -20,6 +21,9 @@ public class OSMSettings {
ADDR_HOUSE_NUMBER("addr:housenumber"), //$NON-NLS-1$
ADDR_STREET("addr:street"), //$NON-NLS-1$
ADDR_POSTCODE("addr:postcode"), //$NON-NLS-1$
ADDRESS_TYPE("address:type"), //$NON-NLS-1$
ADDRESS_HOUSE("address:house"), //$NON-NLS-1$
TYPE("type"), //$NON-NLS-1$
// POI
AMENITY("amenity"), //$NON-NLS-1$

View file

@ -165,6 +165,9 @@ public class OpeningHoursParser {
try {
int i1 = stEnd[0].indexOf(':');
int i2 = stEnd[1].indexOf(':');
if(i1 == -1 || i2 == -1){
return null;
}
st = Integer.parseInt(stEnd[0].substring(0, i1).trim())* 60 + Integer.parseInt(stEnd[0].substring(i1 + 1).trim());
end = Integer.parseInt(stEnd[1].substring(0, i2).trim())* 60 + Integer.parseInt(stEnd[1].substring(i2 + 1).trim());
} catch (NumberFormatException e) {

View file

@ -1,9 +1,10 @@
package com.osmand.osm.io;
import com.osmand.osm.Entity;
import com.osmand.osm.Entity.EntityId;
public interface IOsmStorageFilter {
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity);
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity);
}

View file

@ -241,8 +241,8 @@ public class OsmBaseStorage extends DefaultHandler {
}
if (type != null) {
if(currentParsedEntity != null){
if(acceptEntityToLoad(currentParsedEntity)){
EntityId entityId = new EntityId(type, currentParsedEntity.getId());
EntityId entityId = new EntityId(type, currentParsedEntity.getId());
if(acceptEntityToLoad(entityId, currentParsedEntity)){
Entity oldEntity = entities.put(entityId, currentParsedEntity);
if(parseEntityInfo && currentParsedEntityInfo != null){
entityInfo.put(entityId, currentParsedEntityInfo);
@ -260,9 +260,9 @@ public class OsmBaseStorage extends DefaultHandler {
}
protected boolean acceptEntityToLoad(Entity entity) {
protected boolean acceptEntityToLoad(EntityId entityId, Entity entity) {
for(IOsmStorageFilter f : filters){
if(!f.acceptEntityToLoad(this, entity)){
if(!f.acceptEntityToLoad(this, entityId, entity)){
return false;
}
}

View file

@ -22,7 +22,7 @@ public class OsmBoundsFilter implements IOsmStorageFilter {
}
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity) {
if(entity instanceof Node){
double lon = ((Node) entity).getLongitude();
double lat = ((Node) entity).getLatitude();

View file

@ -227,7 +227,7 @@ public class MinskTransReader {
storage.getFilters().add(new IOsmStorageFilter(){
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
public boolean acceptEntityToLoad(OsmBaseStorage storage, EntityId entityId, Entity entity) {
if(entity.getTag("route") != null){
String route = entity.getTag("route");
if(route.equals("bus") || route.equals("tram") || route.equals("trolleybus") || route.equals("subway")){

View file

@ -192,7 +192,7 @@ public class AmenityIndexRepository extends BaseLocationIndexRepository<Amenity>
final List<Entity> amen = new ArrayList<Entity>();
st.getFilters().add(new IOsmStorageFilter(){
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity.EntityId id, Entity entity) {
if(Amenity.isAmenity(entity)){
amen.add(entity);
return true;

View file

@ -75,7 +75,7 @@ public class MainMenuActivity extends Activity {
SavingTrackHelper helper = new SavingTrackHelper(MainMenuActivity.this);
if (helper.hasDataToSave()) {
impl.startTask(getString(R.string.saving_gpx_tracks), -1);
helper.saveDataToGpx();
warnings.addAll(helper.saveDataToGpx());
}
helper.close();
showWarnings(warnings);

View file

@ -167,7 +167,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
}
public static void saveToXMLFiles(File dir, Map<String, List<List<TrkPt>>> data, Context ctx){
public static String saveToXMLFiles(File dir, Map<String, List<List<TrkPt>>> data, Context ctx){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); //$NON-NLS-1$
try {
for (String f : data.keySet()) {
@ -216,15 +216,14 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
serializer.endTag(null, "gpx"); //$NON-NLS-1$
serializer.flush();
serializer.endDocument();
}
return null;
} catch (RuntimeException e) {
log.error("Error saving gpx", e); //$NON-NLS-1$
Toast.makeText(ctx, ctx.getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_LONG).show();
return ctx.getString(R.string.error_occurred_saving_gpx);
} catch (IOException e) {
log.error("Error saving gpx", e); //$NON-NLS-1$
Toast.makeText(ctx, ctx.getString(R.string.error_occurred_saving_gpx), Toast.LENGTH_LONG).show();
return ctx.getString(R.string.error_occurred_saving_gpx);
}
}
@ -240,8 +239,9 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
return false;
}
public void saveDataToGpx(){
public List<String> saveDataToGpx(){
SQLiteDatabase db = getReadableDatabase();
List<String> warnings = new ArrayList<String>();
File file = Environment.getExternalStorageDirectory();
if(db != null && file.canWrite()){
file = new File(file, "/osmand/"+TRACKS_PATH); //$NON-NLS-1$
@ -293,7 +293,10 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
} while (query.moveToNext());
}
query.close();
saveToXMLFiles(file, data, ctx);
String w = saveToXMLFiles(file, data, ctx);
if(w != null){
warnings.add(w);
}
}
}
@ -308,6 +311,7 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
// remove all from db
db.execSQL("DELETE FROM " + TRACK_NAME+ " WHERE " + TRACK_COL_DATE + " <= ?", new Object[]{System.currentTimeMillis()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return warnings;
}
public void insertData(double lat, double lon, double alt, double speed, long time){