diff --git a/DataExtractionOSM/src/net/osmand/ToDoConstants.java b/DataExtractionOSM/src/net/osmand/ToDoConstants.java index 4d9b3150f3..5b3b8becb1 100644 --- a/DataExtractionOSM/src/net/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/net/osmand/ToDoConstants.java @@ -10,6 +10,7 @@ public class ToDoConstants { // TODO max 101 // !!! Fix progress in DataExtractionOsm + // !!! Fix files in IndexCreator (create one file!) // Outside base 0.4 release // 69. Add phone and site information to POI (enable call to POI and open site) diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java index 9fddcc1cd4..5cd88c03d3 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexReader.java @@ -13,6 +13,7 @@ import net.osmand.Algoritms; import net.osmand.LogUtil; import net.osmand.data.Building; import net.osmand.data.City; +import net.osmand.data.PostCode; import net.osmand.data.Street; import net.osmand.data.City.CityType; import net.osmand.osm.MapUtils; @@ -42,11 +43,15 @@ public class BinaryMapIndexReader { } private void init() throws IOException { + boolean initCorrectly = false; while(true){ int t = codedIS.readTag(); int tag = WireFormat.getTagFieldNumber(t); switch (tag) { case 0: + if(!initCorrectly){ + throw new IOException("Corrupted file. It should be ended as it starts with version"); //$NON-NLS-1$ + } return; case OsmandOdb.OsmAndStructure.VERSION_FIELD_NUMBER : version = codedIS.readUInt32(); @@ -60,12 +65,17 @@ public class BinaryMapIndexReader { codedIS.seek(filePointer + length); break; case OsmandOdb.OsmAndStructure.ADDRESSINDEX_FIELD_NUMBER: - length = readInt(); - filePointer = codedIS.getTotalBytesRead(); - oldLimit = codedIS.pushLimit(length); - readAddressIndex(); + AddressRegion region = new AddressRegion(); + region.length = readInt(); + region.fileOffset = codedIS.getTotalBytesRead(); + oldLimit = codedIS.pushLimit(region.length); + readAddressIndex(region); codedIS.popLimit(oldLimit); - codedIS.seek(filePointer + length); + codedIS.seek(region.fileOffset + region.length); + break; + case OsmandOdb.OsmAndStructure.VERSIONCONFIRM_FIELD_NUMBER : + int cversion = codedIS.readUInt32(); + initCorrectly = cversion == version; break; default: skipUnknownField(t); @@ -84,8 +94,7 @@ public class BinaryMapIndexReader { } } - private void readAddressIndex() throws IOException { - AddressRegion region = new AddressRegion(); + private void readAddressIndex(AddressRegion region) throws IOException { while(true){ int t = codedIS.readTag(); int tag = WireFormat.getTagFieldNumber(t); @@ -268,6 +277,34 @@ public class BinaryMapIndexReader { throw new IllegalArgumentException(name); } + public List getPostcodes(String region) throws IOException { + List postcodes = new ArrayList(); + AddressRegion r = getRegionByName(region); + if(r.postcodesOffset != -1){ + codedIS.seek(r.postcodesOffset); + int len = readInt(); + int old = codedIS.pushLimit(len); + readPostcodes(postcodes); + codedIS.popLimit(old); + } + return postcodes; + } + + public PostCode getPostcodeByName(String region, String name) throws IOException { + AddressRegion r = getRegionByName(region); + if (r.postcodesOffset != -1) { + codedIS.seek(r.postcodesOffset); + int len = readInt(); + int old = codedIS.pushLimit(len); + PostCode p = findPostcode(name); + if (p != null) { + return p; + } + codedIS.popLimit(old); + } + return null; + } + public List getCities(String region) throws IOException { List cities = new ArrayList(); AddressRegion r = getRegionByName(region); @@ -294,6 +331,51 @@ public class BinaryMapIndexReader { return cities; } + private void readPostcodes(List postcodes) throws IOException{ + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + return; + case OsmandOdb.PostcodesIndex.POSTCODES_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + int oldLimit = codedIS.pushLimit(length); + postcodes.add(readPostcode(null, offset, false, null)); + codedIS.popLimit(oldLimit); + break; + default: + skipUnknownField(t); + break; + } + } + } + + private PostCode findPostcode(String name) throws IOException{ + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + return null; + case OsmandOdb.PostcodesIndex.POSTCODES_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + int oldLimit = codedIS.pushLimit(length); + PostCode p = readPostcode(null, offset, true, name); + codedIS.popLimit(oldLimit); + if(p != null){ + return p; + } + break; + default: + skipUnknownField(t); + break; + } + } + } + private void readCities(List cities) throws IOException{ while(true){ int t = codedIS.readTag(); @@ -317,7 +399,7 @@ public class BinaryMapIndexReader { } public void preloadStreets(City c) throws IOException { - // TODO check city belongs to that address repository + checkAddressIndex(c.getFileOffset()); codedIS.seek(c.getFileOffset()); int size = codedIS.readRawVarint32(); int old = codedIS.pushLimit(size); @@ -325,15 +407,87 @@ public class BinaryMapIndexReader { codedIS.popLimit(old); } - public void preloadBuildings(Street s) throws IOException { - // TODO check street belongs to that address repository - codedIS.seek(s.getFileOffset()); + public void preloadStreets(PostCode p) throws IOException { + checkAddressIndex(p.getFileOffset()); + + codedIS.seek(p.getFileOffset()); int size = codedIS.readRawVarint32(); int old = codedIS.pushLimit(size); - readStreet(s, true, 0, 0); + readPostcode(p, p.getFileOffset(), true, null); codedIS.popLimit(old); } + private void checkAddressIndex(int offset){ + boolean ok = false; + for(AddressRegion r : addressIndexes){ + if(offset >= r.fileOffset && offset <= (r.length + r.fileOffset)){ + ok = true; + break; + } + } + if(!ok){ + throw new IllegalArgumentException("Illegal offset " + offset); //$NON-NLS-1$ + } + } + + public void preloadBuildings(Street s) throws IOException { + checkAddressIndex(s.getFileOffset()); + codedIS.seek(s.getFileOffset()); + int size = codedIS.readRawVarint32(); + int old = codedIS.pushLimit(size); + readStreet(s, true, 0, 0, null); + codedIS.popLimit(old); + } + + + private PostCode readPostcode(PostCode p, int fileOffset, boolean loadStreets, String postcodeFilter) throws IOException{ + int x = 0; + int y = 0; + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + p.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x)); + p.setFileOffset(fileOffset); + return p; + case OsmandOdb.PostcodeIndex.POSTCODE_FIELD_NUMBER : + String name = codedIS.readString(); + if(postcodeFilter != null && postcodeFilter.equalsIgnoreCase(name)){ + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return null; + } + if(p == null){ + p = new PostCode(name); + } + p.setName(name); + break; + case OsmandOdb.PostcodeIndex.X_FIELD_NUMBER : + x = codedIS.readFixed32(); + break; + case OsmandOdb.PostcodeIndex.Y_FIELD_NUMBER : + y = codedIS.readFixed32(); + break; + case OsmandOdb.PostcodeIndex.STREETS_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + if(loadStreets){ + Street s = new Street(null); + int oldLimit = codedIS.pushLimit(length); + s.setFileOffset(offset); + readStreet(s, true, x >> 7, y >> 7, p.getName()); + p.registerStreet(s, false); + codedIS.popLimit(oldLimit); + } else { + codedIS.skipRawBytes(length); + } + break; + default: + skipUnknownField(t); + break; + } + } + } private City readCity(City c, int fileOffset, boolean loadStreets) throws IOException{ @@ -375,7 +529,7 @@ public class BinaryMapIndexReader { Street s = new Street(c); int oldLimit = codedIS.pushLimit(length); s.setFileOffset(offset); - readStreet(s, false, x >> 7, y >> 7); + readStreet(s, false, x >> 7, y >> 7, null); c.registerStreet(s); codedIS.popLimit(oldLimit); } else { @@ -389,7 +543,7 @@ public class BinaryMapIndexReader { } } - private Street readStreet(Street s, boolean loadBuildings, int city24X, int city24Y) throws IOException{ + private Street readStreet(Street s, boolean loadBuildings, int city24X, int city24Y, String postcodeFilter) throws IOException{ int x = 0; int y = 0; boolean loadLocation = city24X != 0 || city24Y != 0; @@ -433,7 +587,9 @@ public class BinaryMapIndexReader { if(loadBuildings){ int oldLimit = codedIS.pushLimit(length); Building b = readBuilding(offset, x, y); - s.registerBuilding(b); + if (postcodeFilter == null || postcodeFilter.equalsIgnoreCase(b.getPostcode())) { + s.registerBuilding(b); + } codedIS.popLimit(oldLimit); } else { codedIS.skipRawBytes(length); @@ -843,16 +999,21 @@ public class BinaryMapIndexReader { String name; String enName; + int fileOffset = 0; + int length = 0; + int postcodesOffset = -1; int villagesOffset = -1; int citiesOffset = -1; } public static void main(String[] args) throws IOException { -// RandomAccessFile raf = new RandomAccessFile(new File("e:\\Information\\OSM maps\\osmand\\Minsk.map.pbf"), "r"); - RandomAccessFile raf = new RandomAccessFile(new File("e:\\Information\\OSM maps\\osmand\\Belarus.map.pbf"), "r"); + RandomAccessFile raf = new RandomAccessFile(new File("e:\\Information\\OSM maps\\osmand\\Minsk.map.pbf"), "r"); +// RandomAccessFile raf = new RandomAccessFile(new File("e:\\Information\\OSM maps\\osmand\\Belarus.map.pbf"), "r"); BinaryMapIndexReader reader = new BinaryMapIndexReader(raf); System.out.println("VERSION " + reader.getVersion()); + + // test search // int sleft = MapUtils.get31TileNumberX(27.596); // int sright = MapUtils.get31TileNumberX(27.599); // int stop = MapUtils.get31TileNumberY(53.921); @@ -864,6 +1025,8 @@ public class BinaryMapIndexReader { // System.out.println(" " + obj.getName()); // } // } + + // test address index search String reg = reader.getRegionNames().get(0); long time = System.currentTimeMillis(); List cs = reader.getCities(reg); @@ -877,8 +1040,13 @@ public class BinaryMapIndexReader { System.out.println(c.getName() + " " + c.getLocation() + " " + c.getStreets().size() + " " + buildings); } List villages = reader.getVillages(reg); - System.out.println(villages.size()); - System.out.println(System.currentTimeMillis() - time); + List postcodes = reader.getPostcodes(reg); + for(PostCode c : postcodes){ + reader.preloadStreets(c); +// System.out.println(c.getName()); + } + System.out.println("Villages " + villages.size()); + System.out.println("Time " + (System.currentTimeMillis() - time)); } } diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java index 0dc7368e88..817e44f827 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapIndexWriter.java @@ -88,6 +88,11 @@ public class BinaryMapIndexWriter { codedOutStream.writeInt32(OsmandOdb.OsmAndStructure.VERSION_FIELD_NUMBER, IndexConstants.BINARY_MAP_VERSION); state.push(OSMAND_STRUCTURE_INIT); } + + public void finishWriting(){ + + } + private void preserveInt32Size() throws IOException { codedOutStream.flush(); @@ -411,15 +416,18 @@ public class BinaryMapIndexWriter { public void writePostcode(String postcode, Collection streets) throws IOException { checkPeekState(POSTCODES_INDEX_INIT); - LatLon loc = null; + + if(streets.isEmpty()){ + return; + } + postcode = postcode.toUpperCase(); + LatLon loc = streets.iterator().next().getLocation(); PostcodeIndex.Builder post = OsmandOdb.PostcodeIndex.newBuilder(); post.setPostcode(postcode); - + post.setX(MapUtils.get31TileNumberX(loc.getLongitude())); + post.setY(MapUtils.get31TileNumberY(loc.getLatitude())); for(Street s : streets){ - if(loc == null){ - loc = s.getLocation(); - } StreetIndex streetInd = createStreetAndBuildings(s, loc, postcode); post.addStreets(streetInd); } @@ -477,8 +485,8 @@ public class BinaryMapIndexWriter { } private void checkPeekState(int... states) { - for(int i=0;i streets_ = java.util.Collections.emptyList(); public java.util.List getStreetsList() { @@ -4194,7 +4234,7 @@ public final class OsmandOdb { output.writeFixed32(6, getY()); } for (net.osmand.binary.OsmandOdb.StreetIndex element : getStreetsList()) { - output.writeMessage(7, element); + output.writeMessage(10, element); } getUnknownFields().writeTo(output); } @@ -4231,7 +4271,7 @@ public final class OsmandOdb { } for (net.osmand.binary.OsmandOdb.StreetIndex element : getStreetsList()) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(7, element); + .computeMessageSize(10, element); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; @@ -4468,7 +4508,7 @@ public final class OsmandOdb { setY(input.readFixed32()); break; } - case 58: { + case 82: { net.osmand.binary.OsmandOdb.StreetIndex.Builder subBuilder = net.osmand.binary.OsmandOdb.StreetIndex.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addStreets(subBuilder.buildPartial()); @@ -4593,7 +4633,7 @@ public final class OsmandOdb { return this; } - // repeated .StreetIndex streets = 7; + // repeated .StreetIndex streets = 10; public java.util.List getStreetsList() { return java.util.Collections.unmodifiableList(result.streets_); } @@ -4690,6 +4730,20 @@ public final class OsmandOdb { public boolean hasPostcode() { return hasPostcode; } public java.lang.String getPostcode() { return postcode_; } + // required fixed32 x = 2; + public static final int X_FIELD_NUMBER = 2; + private boolean hasX; + private int x_ = 0; + public boolean hasX() { return hasX; } + public int getX() { return x_; } + + // required fixed32 y = 3; + public static final int Y_FIELD_NUMBER = 3; + private boolean hasY; + private int y_ = 0; + public boolean hasY() { return hasY; } + public int getY() { return y_; } + // repeated .StreetIndex streets = 5; public static final int STREETS_FIELD_NUMBER = 5; private java.util.List streets_ = @@ -4706,6 +4760,8 @@ public final class OsmandOdb { } public final boolean isInitialized() { if (!hasPostcode) return false; + if (!hasX) return false; + if (!hasY) return false; for (net.osmand.binary.OsmandOdb.StreetIndex element : getStreetsList()) { if (!element.isInitialized()) return false; } @@ -4718,6 +4774,12 @@ public final class OsmandOdb { if (hasPostcode()) { output.writeString(1, getPostcode()); } + if (hasX()) { + output.writeFixed32(2, getX()); + } + if (hasY()) { + output.writeFixed32(3, getY()); + } for (net.osmand.binary.OsmandOdb.StreetIndex element : getStreetsList()) { output.writeMessage(5, element); } @@ -4734,6 +4796,14 @@ public final class OsmandOdb { size += com.google.protobuf.CodedOutputStream .computeStringSize(1, getPostcode()); } + if (hasX()) { + size += com.google.protobuf.CodedOutputStream + .computeFixed32Size(2, getX()); + } + if (hasY()) { + size += com.google.protobuf.CodedOutputStream + .computeFixed32Size(3, getY()); + } for (net.osmand.binary.OsmandOdb.StreetIndex element : getStreetsList()) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(5, element); @@ -4903,6 +4973,12 @@ public final class OsmandOdb { if (other.hasPostcode()) { setPostcode(other.getPostcode()); } + if (other.hasX()) { + setX(other.getX()); + } + if (other.hasY()) { + setY(other.getY()); + } if (!other.streets_.isEmpty()) { if (result.streets_.isEmpty()) { result.streets_ = new java.util.ArrayList(); @@ -4938,6 +5014,14 @@ public final class OsmandOdb { setPostcode(input.readString()); break; } + case 21: { + setX(input.readFixed32()); + break; + } + case 29: { + setY(input.readFixed32()); + break; + } case 42: { net.osmand.binary.OsmandOdb.StreetIndex.Builder subBuilder = net.osmand.binary.OsmandOdb.StreetIndex.newBuilder(); input.readMessage(subBuilder, extensionRegistry); @@ -4970,6 +5054,42 @@ public final class OsmandOdb { return this; } + // required fixed32 x = 2; + public boolean hasX() { + return result.hasX(); + } + public int getX() { + return result.getX(); + } + public Builder setX(int value) { + result.hasX = true; + result.x_ = value; + return this; + } + public Builder clearX() { + result.hasX = false; + result.x_ = 0; + return this; + } + + // required fixed32 y = 3; + public boolean hasY() { + return result.hasY(); + } + public int getY() { + return result.getY(); + } + public Builder setY(int value) { + result.hasY = true; + result.y_ = value; + return this; + } + public Builder clearY() { + result.hasY = false; + result.y_ = 0; + return this; + } + // repeated .StreetIndex streets = 5; public java.util.List getStreetsList() { return java.util.Collections.unmodifiableList(result.streets_); @@ -5095,8 +5215,8 @@ public final class OsmandOdb { public boolean hasY() { return hasY; } public int getY() { return y_; } - // repeated .BuildingIndex buildings = 5; - public static final int BUILDINGS_FIELD_NUMBER = 5; + // repeated .BuildingIndex buildings = 10; + public static final int BUILDINGS_FIELD_NUMBER = 10; private java.util.List buildings_ = java.util.Collections.emptyList(); public java.util.List getBuildingsList() { @@ -5134,12 +5254,12 @@ public final class OsmandOdb { if (hasY()) { output.writeSInt32(4, getY()); } - for (net.osmand.binary.OsmandOdb.BuildingIndex element : getBuildingsList()) { - output.writeMessage(5, element); - } if (hasId()) { output.writeUInt64(6, getId()); } + for (net.osmand.binary.OsmandOdb.BuildingIndex element : getBuildingsList()) { + output.writeMessage(10, element); + } getUnknownFields().writeTo(output); } @@ -5165,14 +5285,14 @@ public final class OsmandOdb { size += com.google.protobuf.CodedOutputStream .computeSInt32Size(4, getY()); } - for (net.osmand.binary.OsmandOdb.BuildingIndex element : getBuildingsList()) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(5, element); - } if (hasId()) { size += com.google.protobuf.CodedOutputStream .computeUInt64Size(6, getId()); } + for (net.osmand.binary.OsmandOdb.BuildingIndex element : getBuildingsList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(10, element); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -5397,16 +5517,16 @@ public final class OsmandOdb { setY(input.readSInt32()); break; } - case 42: { + case 48: { + setId(input.readUInt64()); + break; + } + case 82: { net.osmand.binary.OsmandOdb.BuildingIndex.Builder subBuilder = net.osmand.binary.OsmandOdb.BuildingIndex.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addBuildings(subBuilder.buildPartial()); break; } - case 48: { - setId(input.readUInt64()); - break; - } } } } @@ -5508,7 +5628,7 @@ public final class OsmandOdb { return this; } - // repeated .BuildingIndex buildings = 5; + // repeated .BuildingIndex buildings = 10; public java.util.List getBuildingsList() { return java.util.Collections.unmodifiableList(result.buildings_); } @@ -6136,39 +6256,41 @@ public final class OsmandOdb { descriptor; static { java.lang.String[] descriptorData = { - "\n\024src/osmand_odb.proto\"p\n\017OsmAndStructur" + - "e\022\017\n\007version\030\001 \002(\r\022!\n\010mapIndex\030\002 \003(\0132\017.O" + - "smAndMapIndex\022)\n\014addressIndex\030\003 \003(\0132\023.Os" + - "mAndAddressIndex\"/\n\016OsmAndMapIndex\022\035\n\006le" + - "vels\030\001 \003(\0132\r.MapRootLevel\"\202\001\n\014MapRootLev" + - "el\022\017\n\007maxZoom\030\001 \002(\005\022\017\n\007minZoom\030\002 \002(\005\022\014\n\004" + - "left\030\003 \002(\005\022\r\n\005right\030\004 \002(\005\022\013\n\003top\030\005 \002(\005\022\016" + - "\n\006bottom\030\006 \002(\005\022\026\n\004root\030\007 \003(\0132\010.MapTree\"\253" + - "\001\n\007MapTree\022\014\n\004left\030\001 \002(\021\022\r\n\005right\030\002 \002(\021\022" + - "\013\n\003top\030\003 \002(\021\022\016\n\006bottom\030\004 \002(\021\022!\n\013stringTa", - "ble\030\005 \001(\0132\014.StringTable\022\016\n\006baseId\030\006 \001(\004\022" + - "\032\n\010subtrees\030\007 \003(\0132\010.MapTree\022\027\n\005leafs\030\010 \003" + - "(\0132\010.MapData\"\030\n\013StringTable\022\t\n\001s\030\001 \003(\t\"v" + - "\n\007MapData\022\023\n\013coordinates\030\001 \002(\014\022\r\n\005types\030" + - "\002 \002(\014\022\n\n\002id\030\003 \002(\022\022\020\n\010stringId\030\004 \001(\r\022\024\n\014r" + - "estrictions\030\005 \001(\014\022\023\n\013highwayMeta\030\006 \001(\005\"\225" + - "\001\n\022OsmAndAddressIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007n" + - "ame_en\030\002 \001(\t\022\034\n\006cities\030\005 \001(\0132\014.CitiesInd" + - "ex\022\"\n\tpostcodes\030\006 \001(\0132\017.PostcodesIndex\022\036" + - "\n\010villages\030\007 \001(\0132\014.CitiesIndex\")\n\013Cities", - "Index\022\032\n\006cities\030\001 \003(\0132\n.CityIndex\"3\n\016Pos" + - "tcodesIndex\022!\n\tpostcodes\030\001 \003(\0132\016.Postcod" + - "eIndex\"~\n\tCityIndex\022\021\n\tcity_type\030\001 \002(\r\022\014" + - "\n\004name\030\002 \002(\t\022\017\n\007name_en\030\003 \001(\t\022\n\n\002id\030\004 \001(" + - "\004\022\t\n\001x\030\005 \002(\007\022\t\n\001y\030\006 \002(\007\022\035\n\007streets\030\007 \003(\013" + - "2\014.StreetIndex\"@\n\rPostcodeIndex\022\020\n\010postc" + - "ode\030\001 \002(\t\022\035\n\007streets\030\005 \003(\0132\014.StreetIndex" + - "\"q\n\013StreetIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007name_en" + - "\030\002 \001(\t\022\n\n\002id\030\006 \001(\004\022\t\n\001x\030\003 \002(\021\022\t\n\001y\030\004 \002(\021" + - "\022!\n\tbuildings\030\005 \003(\0132\016.BuildingIndex\"b\n\rB", - "uildingIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007name_en\030\002 " + - "\001(\t\022\n\n\002id\030\005 \001(\004\022\020\n\010postcode\030\006 \001(\t\022\t\n\001x\030\003" + - " \002(\021\022\t\n\001y\030\004 \002(\021B\023\n\021net.osmand.binary" + "\n\024src/osmand_odb.proto\"\210\001\n\017OsmAndStructu" + + "re\022\017\n\007version\030\001 \002(\r\022!\n\010mapIndex\030\002 \003(\0132\017." + + "OsmAndMapIndex\022)\n\014addressIndex\030\003 \003(\0132\023.O" + + "smAndAddressIndex\022\026\n\016versionConfirm\030 \002(" + + "\r\"/\n\016OsmAndMapIndex\022\035\n\006levels\030\001 \003(\0132\r.Ma" + + "pRootLevel\"\202\001\n\014MapRootLevel\022\017\n\007maxZoom\030\001" + + " \002(\005\022\017\n\007minZoom\030\002 \002(\005\022\014\n\004left\030\003 \002(\005\022\r\n\005r" + + "ight\030\004 \002(\005\022\013\n\003top\030\005 \002(\005\022\016\n\006bottom\030\006 \002(\005\022" + + "\026\n\004root\030\007 \003(\0132\010.MapTree\"\253\001\n\007MapTree\022\014\n\004l" + + "eft\030\001 \002(\021\022\r\n\005right\030\002 \002(\021\022\013\n\003top\030\003 \002(\021\022\016\n", + "\006bottom\030\004 \002(\021\022!\n\013stringTable\030\005 \001(\0132\014.Str" + + "ingTable\022\016\n\006baseId\030\006 \001(\004\022\032\n\010subtrees\030\007 \003" + + "(\0132\010.MapTree\022\027\n\005leafs\030\010 \003(\0132\010.MapData\"\030\n" + + "\013StringTable\022\t\n\001s\030\001 \003(\t\"v\n\007MapData\022\023\n\013co" + + "ordinates\030\001 \002(\014\022\r\n\005types\030\002 \002(\014\022\n\n\002id\030\003 \002" + + "(\022\022\020\n\010stringId\030\004 \001(\r\022\024\n\014restrictions\030\005 \001" + + "(\014\022\023\n\013highwayMeta\030\006 \001(\005\"\225\001\n\022OsmAndAddres" + + "sIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007name_en\030\002 \001(\t\022\034\n" + + "\006cities\030\005 \001(\0132\014.CitiesIndex\022\"\n\tpostcodes" + + "\030\006 \001(\0132\017.PostcodesIndex\022\036\n\010villages\030\007 \001(", + "\0132\014.CitiesIndex\")\n\013CitiesIndex\022\032\n\006cities" + + "\030\001 \003(\0132\n.CityIndex\"3\n\016PostcodesIndex\022!\n\t" + + "postcodes\030\001 \003(\0132\016.PostcodeIndex\"~\n\tCityI" + + "ndex\022\021\n\tcity_type\030\001 \002(\r\022\014\n\004name\030\002 \002(\t\022\017\n" + + "\007name_en\030\003 \001(\t\022\n\n\002id\030\004 \001(\004\022\t\n\001x\030\005 \002(\007\022\t\n" + + "\001y\030\006 \002(\007\022\035\n\007streets\030\n \003(\0132\014.StreetIndex\"" + + "V\n\rPostcodeIndex\022\020\n\010postcode\030\001 \002(\t\022\t\n\001x\030" + + "\002 \002(\007\022\t\n\001y\030\003 \002(\007\022\035\n\007streets\030\005 \003(\0132\014.Stre" + + "etIndex\"q\n\013StreetIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007" + + "name_en\030\002 \001(\t\022\n\n\002id\030\006 \001(\004\022\t\n\001x\030\003 \002(\021\022\t\n\001", + "y\030\004 \002(\021\022!\n\tbuildings\030\n \003(\0132\016.BuildingInd" + + "ex\"b\n\rBuildingIndex\022\014\n\004name\030\001 \002(\t\022\017\n\007nam" + + "e_en\030\002 \001(\t\022\n\n\002id\030\005 \001(\004\022\020\n\010postcode\030\006 \001(\t" + + "\022\t\n\001x\030\003 \002(\021\022\t\n\001y\030\004 \002(\021B\023\n\021net.osmand.bin" + + "ary" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -6180,7 +6302,7 @@ public final class OsmandOdb { internal_static_OsmAndStructure_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_OsmAndStructure_descriptor, - new java.lang.String[] { "Version", "MapIndex", "AddressIndex", }, + new java.lang.String[] { "Version", "MapIndex", "AddressIndex", "VersionConfirm", }, net.osmand.binary.OsmandOdb.OsmAndStructure.class, net.osmand.binary.OsmandOdb.OsmAndStructure.Builder.class); internal_static_OsmAndMapIndex_descriptor = @@ -6260,7 +6382,7 @@ public final class OsmandOdb { internal_static_PostcodeIndex_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_PostcodeIndex_descriptor, - new java.lang.String[] { "Postcode", "Streets", }, + new java.lang.String[] { "Postcode", "X", "Y", "Streets", }, net.osmand.binary.OsmandOdb.PostcodeIndex.class, net.osmand.binary.OsmandOdb.PostcodeIndex.Builder.class); internal_static_StreetIndex_descriptor = diff --git a/DataExtractionOSM/src/net/osmand/data/CityComparator.java b/DataExtractionOSM/src/net/osmand/data/MapObjectComparator.java similarity index 65% rename from DataExtractionOSM/src/net/osmand/data/CityComparator.java rename to DataExtractionOSM/src/net/osmand/data/MapObjectComparator.java index 31016a1901..a6ebe5b7ac 100644 --- a/DataExtractionOSM/src/net/osmand/data/CityComparator.java +++ b/DataExtractionOSM/src/net/osmand/data/MapObjectComparator.java @@ -3,17 +3,15 @@ package net.osmand.data; import java.text.Collator; import java.util.Comparator; -public class CityComparator implements Comparator{ +public class MapObjectComparator implements Comparator{ private final boolean en; Collator collator = Collator.getInstance(); - public CityComparator(boolean en){ + public MapObjectComparator(boolean en){ this.en = en; } - - @Override - public int compare(City o1, City o2) { + public int compare(MapObject o1, MapObject o2) { if(en){ return collator.compare(o1.getEnName(), o2.getEnName()); } else { diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java index 1ed9ef6064..c6265ec9c2 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java @@ -1518,7 +1518,7 @@ public class IndexCreator { break; } } - progress.startTask("Searilizing city addresses...", j + (cities.size() - j) / 100); + progress.startTask("Searilizing city addresses...", j + ((cities.size() - j) / 100 + 1)); Map> postcodes = new TreeMap>(); boolean writeCities = true; @@ -1600,7 +1600,6 @@ public class IndexCreator { writer.endWriteMapIndex(); - writer.close(); } catch (RTreeException e) { throw new IllegalStateException(e); } @@ -2006,6 +2005,8 @@ public class IndexCreator { addressConnection.close(); addressConnection = null; } + + writer.close(); log.info("Finish writing binary file"); } @@ -2048,15 +2049,15 @@ public class IndexCreator { } if(mapRAFile != null){ mapRAFile.close(); + if (lastModifiedDate != null && mapFile.exists()) { + mapFile.setLastModified(lastModifiedDate); + } } if (mapConnection != null) { mapConnection.commit(); mapConnection.close(); mapConnection = null; - if (lastModifiedDate != null && mapFile.exists()) { - mapFile.setLastModified(lastModifiedDate); - } File tempDBFile = new File(workingDir, getTempMapDBFileName()); if(tempDBFile.exists()){ tempDBFile.delete(); @@ -2133,7 +2134,7 @@ public class IndexCreator { creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/belarus_nodes.tmp.odb")); creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/belarus.osm.bz2"), new ConsoleProgressImplementation(3), null); -// + // creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/forest.osm"), new ConsoleProgressImplementation(3), null); diff --git a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java index 9733bf70e0..ecee0cbaeb 100644 --- a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java +++ b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java @@ -21,7 +21,6 @@ import net.osmand.osm.OSMSettings.OSMTagKey; */ public class MapRenderingTypes { - public static final int[] MAP_ZOOMS = null; // TODO Internet access bits for point, polygon /** standard schema : diff --git a/DataExtractionOSM/src/osmand_odb.proto b/DataExtractionOSM/src/osmand_odb.proto index a9d4487284..2163d9fcbb 100644 --- a/DataExtractionOSM/src/osmand_odb.proto +++ b/DataExtractionOSM/src/osmand_odb.proto @@ -14,6 +14,9 @@ message OsmAndStructure { repeated OsmAndMapIndex mapIndex = 2; // encoded as fixed32 length delimited repeated OsmAndAddressIndex addressIndex = 3; + + // last field should version again (to check consistency) + required uint32 versionConfirm = 32; } @@ -74,7 +77,6 @@ message MapData { } -/// ADDRESS INFORMATION TEST ----- message OsmAndAddressIndex { @@ -119,6 +121,8 @@ message CityIndex { message PostcodeIndex { required string postcode = 1; + required fixed32 x = 2; // x tile of 31 zoom + required fixed32 y = 3; // y tile of 31 zoom repeated StreetIndex streets = 5; } diff --git a/OsmAnd/src/net/osmand/RegionAddressRepository.java b/OsmAnd/src/net/osmand/RegionAddressRepository.java index fc7efe077b..63ade05b8b 100644 --- a/OsmAnd/src/net/osmand/RegionAddressRepository.java +++ b/OsmAnd/src/net/osmand/RegionAddressRepository.java @@ -1,53 +1,19 @@ package net.osmand; -import java.io.File; import java.text.Collator; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; import net.osmand.data.Building; import net.osmand.data.City; -import net.osmand.data.CityComparator; import net.osmand.data.MapObject; import net.osmand.data.PostCode; import net.osmand.data.Street; -import net.osmand.data.City.CityType; -import net.osmand.data.index.IndexConstants; -import net.osmand.data.index.IndexConstants.IndexBuildingTable; -import net.osmand.data.index.IndexConstants.IndexCityTable; -import net.osmand.data.index.IndexConstants.IndexStreetNodeTable; -import net.osmand.data.index.IndexConstants.IndexStreetTable; import net.osmand.osm.LatLon; import net.osmand.osm.MapUtils; -import net.osmand.osm.Node; -import net.osmand.osm.Way; - -import org.apache.commons.logging.Log; - -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -public class RegionAddressRepository { - private static final Log log = LogUtil.getLog(RegionAddressRepository.class); - private SQLiteDatabase db; - private String name; - private LinkedHashMap cities = new LinkedHashMap(); - - private Map> cityTypes = new HashMap>(); - private Map postCodes = new TreeMap(Collator.getInstance()); - - private boolean useEnglishNames = false; +public interface RegionAddressRepository { public static class MapObjectNameDistanceComparator implements Comparator { @@ -80,448 +46,43 @@ public class RegionAddressRepository { } + public String getName(); - public boolean initialize(final IProgress progress, File file) { - long start = System.currentTimeMillis(); - if(db != null){ - // close previous db - db.close(); - } - db = SQLiteDatabase.openOrCreateDatabase(file, null); - name = file.getName().substring(0, file.getName().indexOf('.')); - if(db.getVersion() != IndexConstants.ADDRESS_TABLE_VERSION){ - db.close(); - db = null; - return false; - } - - if (log.isDebugEnabled()) { - log.debug("Initializing address db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - return true; - } + public PostCode getPostcode(String name); - public void close(){ - clearCities(); - if(db != null){ - db.close(); - } - } + public City getCityById(Long id); - public String getName() { - return name; - } + public Street getStreetByName(MapObject cityOrPostcode, String name); - public void clearCities(){ - cities.clear(); - cityTypes.clear(); - postCodes.clear(); - } + public Building getBuildingByName(Street street, String name); - public boolean areCitiesPreloaded(){ - return !cities.isEmpty(); - } - public boolean arePostcodesPreloaded(){ - return !postCodes.isEmpty(); - } + public boolean useEnglishNames(); - public PostCode getPostcode(String name){ - if(name == null){ - return null; - } - preloadPostcodes(); - return postCodes.get(name.toUpperCase()); - } + public void setUseEnglishNames(boolean useEnglishNames); - public City getCityById(Long id){ - if(id == -1){ - // do not preload cities for that case - return null; - } - preloadCities(); - return cities.get(id); - } + public void fillWithSuggestedBuildings(PostCode postcode, Street street, String name, List buildingsToFill); + + public void fillWithSuggestedStreetsIntersectStreets(City city, Street st, List streetsToFill); + + public void fillWithSuggestedStreets(MapObject cityOrPostcode, String name, List streetsToFill); + + public void fillWithSuggestedCities(String name, List citiesToFill, LatLon currentLocation); + + public LatLon findStreetIntersection(Street street, Street street2); + + public boolean areCitiesPreloaded(); + + public boolean arePostcodesPreloaded(); + + public void addCityToPreloadedList(City city); - public Street getStreetByName(MapObject city, String name) { - preloadStreets(city); - if (city instanceof City) { - return ((City) city).getStreet(name); - } else { - return ((PostCode) city).getStreet(name); - } - } + public boolean isMapRepository(); - public Building getBuildingByName(Street street, String name){ - if(street.getBuildings().isEmpty()){ - preloadBuildings(street); - } - for(Building b : street.getBuildings()){ - String bName = useEnglishNames ? b.getEnName() : b.getName(); - if(bName.equals(name)){ - return b; - } - } - return null; - } + // is called on low memory + public void clearCache(); - public boolean useEnglishNames(){ - return useEnglishNames; - } + // called to close resources + public void close(); - public void setUseEnglishNames(boolean useEnglishNames) { - this.useEnglishNames = useEnglishNames; - // sort streets - for (City c : cities.values()) { - if (!c.isEmptyWithStreets()) { - ArrayList list = new ArrayList(c.getStreets()); - c.removeAllStreets(); - for (Street s : list) { - c.registerStreet(s, useEnglishNames); - } - } - } - // sort cities - ArrayList list = new ArrayList(cities.values()); - Collections.sort(list, new CityComparator(useEnglishNames)); - cities.clear(); - cityTypes.clear(); - for(City c : list){ - registerCity(c); - } - } - - public void fillWithSuggestedBuildings(PostCode postcode, Street street, String name, List buildingsToFill){ - preloadBuildings(street); - name = name.toLowerCase(); - int ind = 0; - boolean empty = name.length() == 0; - if(empty && postcode == null){ - buildingsToFill.addAll(street.getBuildings()); - return; - } - for (Building building : street.getBuildings()) { - if(postcode != null && !postcode.getName().equals(building.getPostcode())){ - continue; - } else if(empty){ - buildingsToFill.add(building); - continue; - } - String bName = useEnglishNames ? building.getEnName() : building.getName(); - String lowerCase = bName.toLowerCase(); - if (lowerCase.startsWith(name)) { - buildingsToFill.add(ind, building); - ind++; - } else if (lowerCase.contains(name)) { - buildingsToFill.add(building); - } - } - } - - public void fillWithSuggestedStreetsIntersectStreets(City city, Street st, List streetsToFill) { - if (st != null) { - Set strIds = new TreeSet(); - log.debug("Start loading instersection streets for " + city.getName()); //$NON-NLS-1$ - Cursor query = db.rawQuery("SELECT B.STREET FROM street_node A JOIN street_node B ON A.ID = B.ID WHERE A.STREET = ?", //$NON-NLS-1$ - new String[] { st.getId() + "" }); //$NON-NLS-1$ - if (query.moveToFirst()) { - do { - if (st.getId() != query.getLong(0)) { - strIds.add(query.getLong(0)); - } - } while (query.moveToNext()); - } - query.close(); - for (Street s : city.getStreets()) { - if (strIds.contains(s.getId())) { - streetsToFill.add(s); - } - } - log.debug("Loaded " + strIds.size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ - preloadWayNodes(st); - } - } - - - public void fillWithSuggestedStreets(MapObject o, String name, List streetsToFill){ - assert o instanceof PostCode || o instanceof City; - City city = (City) (o instanceof City ? o : null); - PostCode post = (PostCode) (o instanceof PostCode ? o : null); - preloadStreets(o); - name = name.toLowerCase(); - - Collection streets = post == null ? city.getStreets() : post.getStreets() ; - int ind = 0; - if(name.length() == 0){ - streetsToFill.addAll(streets); - return; - } - ind = 0; - for (Street s : streets) { - String sName = useEnglishNames ? s.getEnName() : s.getName(); - String lowerCase = sName.toLowerCase(); - if (lowerCase.startsWith(name)) { - streetsToFill.add(ind, s); - ind++; - } else if (lowerCase.contains(name)) { - streetsToFill.add(s); - } - } - } - - public void fillWithSuggestedCities(String name, List citiesToFill, LatLon currentLocation){ - preloadCities(); - // essentially index is created that cities towns are first in cities map - int ind = 0; - if (name.length() >= 2 && - Character.isDigit(name.charAt(0)) && - Character.isDigit(name.charAt(1))) { - preloadPostcodes(); - // also try to identify postcodes - String uName = name.toUpperCase(); - for (String code : postCodes.keySet()) { - if (code.startsWith(uName)) { - citiesToFill.add(ind++, postCodes.get(code)); - } else if(code.contains(uName)){ - citiesToFill.add(postCodes.get(code)); - } - } - - } - if(name.length() < 3){ - EnumSet set = EnumSet.of(CityType.CITY, CityType.TOWN); - for(CityType t : set){ - List list = cityTypes.get(t); - if(list == null){ - continue; - } - if(name.length() == 0){ - citiesToFill.addAll(list); - } else { - name = name.toLowerCase(); - for (City c : list) { - String cName = useEnglishNames ? c.getEnName() : c.getName(); - String lowerCase = cName.toLowerCase(); - if(lowerCase.startsWith(name)){ - citiesToFill.add(c); - } - } - } - } - } else { - name = name.toLowerCase(); - Collection src = cities.values(); - for (City c : src) { - String cName = useEnglishNames ? c.getEnName() : c.getName(); - String lowerCase = cName.toLowerCase(); - if (lowerCase.startsWith(name)) { - citiesToFill.add(ind, c); - ind++; - } else if (lowerCase.contains(name)) { - citiesToFill.add(c); - } - } - int initialsize = citiesToFill.size(); - log.debug("Start loading cities for " +getName() + " filter " + name); //$NON-NLS-1$ //$NON-NLS-2$ - // lower function in SQLite requires ICU extension - name = Algoritms.capitalizeFirstLetterAndLowercase(name); - int i = name.indexOf('\''); - if(i != -1){ - // SQL quotation - name = name.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ - } - StringBuilder where = new StringBuilder(80); - where. - append(IndexCityTable.CITY_TYPE.toString()).append(" not in ("). //$NON-NLS-1$ - append('\'').append(CityType.valueToString(CityType.CITY)).append('\'').append(", "). //$NON-NLS-1$ - append('\'').append(CityType.valueToString(CityType.TOWN)).append('\'').append(") and "). //$NON-NLS-1$ - append(useEnglishNames ? IndexCityTable.NAME_EN.toString() : IndexCityTable.NAME.toString()).append(" LIKE '"+name+"%'"); //$NON-NLS-1$ //$NON-NLS-2$ - Cursor query = db.query(IndexCityTable.getTable(), IndexConstants.generateColumnNames(IndexCityTable.values()), - where.toString(), null, null, null, null); - if (query.moveToFirst()) { - List hamlets = new ArrayList(); - do { - hamlets.add(parseCityFromCursor(query)); - } while (query.moveToNext()); - Collections.sort(hamlets, new MapObjectNameDistanceComparator(useEnglishNames, currentLocation)); - citiesToFill.addAll(hamlets); - } - query.close(); - - - - log.debug("Loaded citites " + (citiesToFill.size() - initialsize)); //$NON-NLS-1$ - } - } - - public void preloadWayNodes(Street street){ - if(street.getWayNodes().isEmpty()){ - Cursor query = db.query(IndexStreetNodeTable.getTable(), IndexConstants.generateColumnNames(IndexStreetNodeTable.values()), "? = street", //$NON-NLS-1$ - new String[] { street.getId() + "" }, null, null, null); //$NON-NLS-1$ - log.debug("Start loading waynodes for " + street.getName()); //$NON-NLS-1$ - Map ways = new LinkedHashMap(); - if (query.moveToFirst()) { - do { - Node n = new Node(query.getDouble(IndexStreetNodeTable.LATITUDE.ordinal()), - query.getDouble(IndexBuildingTable.LONGITUDE.ordinal()), - query.getLong(IndexStreetNodeTable.ID.ordinal())); - long way = query.getLong(IndexStreetNodeTable.WAY.ordinal()); - if(!ways.containsKey(way)){ - ways.put(way, new Way(way)); - } - ways.get(way).addNode(n); - } while (query.moveToNext()); - } - query.close(); - for(Way w : ways.values()){ - street.getWayNodes().add(w); - } - log.debug("Loaded " + ways.size() + " ways"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - } - - public void preloadPostcodes() { - if (postCodes.isEmpty()) { - // check if it possible to load postcodes - Cursor query = db.query(true, IndexBuildingTable.getTable(), new String[] { IndexBuildingTable.POSTCODE.toString() }, null, - null, null, null, null, null); - log.debug("Start loading postcodes for "); //$NON-NLS-1$ - if (query.moveToFirst()) { - do { - String postcode = query.getString(0); - if (postcode != null) { - postCodes.put(postcode, new PostCode(postcode)); - } - } while (query.moveToNext()); - } - query.close(); - log.debug("Loaded " + postCodes.size() + " postcodes "); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - public void preloadBuildings(Street street){ - if (street.getBuildings().isEmpty()) { - Cursor query = db.query(IndexBuildingTable.getTable(), IndexConstants.generateColumnNames(IndexBuildingTable.values()), "? = street", //$NON-NLS-1$ - new String[] { street.getId() + "" }, null, null, null); //$NON-NLS-1$ - log.debug("Start loading buildings for " + street.getName()); //$NON-NLS-1$ - if (query.moveToFirst()) { - do { - Building building = new Building(); - building.setId(query.getLong(IndexBuildingTable.ID.ordinal())); - building.setLocation(query.getDouble(IndexBuildingTable.LATITUDE.ordinal()), query.getDouble(IndexBuildingTable.LONGITUDE - .ordinal())); - building.setName(query.getString(IndexBuildingTable.NAME.ordinal())); - building.setEnName(query.getString(IndexBuildingTable.NAME_EN.ordinal())); - building.setPostcode(query.getString(IndexBuildingTable.POSTCODE.ordinal())); - street.registerBuilding(building); - } while (query.moveToNext()); - street.sortBuildings(); - } - query.close(); - log.debug("Loaded " + street.getBuildings().size() + " buildings"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - public void preloadStreets(MapObject o){ - assert o instanceof PostCode || o instanceof City; - City city = (City) (o instanceof City ? o : null); - PostCode post = (PostCode) (o instanceof PostCode ? o : null); - if (city != null && city.isEmptyWithStreets()) { - log.debug("Start loading streets for " + city.getName()); //$NON-NLS-1$ - Cursor query = db.query(IndexStreetTable.getTable(), IndexConstants.generateColumnNames(IndexStreetTable.values()), "? = city", //$NON-NLS-1$ - new String[] { city.getId() + "" }, null, null, null); //$NON-NLS-1$ - if (query.moveToFirst()) { - do { - Street street = new Street(city); - street.setId(query.getLong(IndexStreetTable.ID.ordinal())); - street.setLocation(query.getDouble(IndexStreetTable.LATITUDE.ordinal()), query.getDouble(IndexStreetTable.LONGITUDE.ordinal())); - street.setName(query.getString(IndexStreetTable.NAME.ordinal())); - street.setEnName(query.getString(IndexStreetTable.NAME_EN.ordinal())); - city.registerStreet(street, useEnglishNames); - } while (query.moveToNext()); - } - query.close(); - log.debug("Loaded " + city.getStreets().size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ - } else if(post != null && post.isEmptyWithStreets()){ - log.debug("Start loading streets for " + post.getName()); //$NON-NLS-1$ - Cursor query = db.rawQuery("SELECT B.CITY, B.ID,B.LATITUDE, B.LONGITUDE, B.NAME, B.NAME_EN FROM building A JOIN street B ON A.street = B.ID WHERE A.postcode = ?", //$NON-NLS-1$ - new String[] { post.getName() + "" }); //$NON-NLS-1$ - if (query.moveToFirst()) { - do { - city = getCityById(query.getLong(0)); - Street street = null; - if(city != null){ - preloadStreets(city); - street = city.getStreet(useEnglishNames ? query.getString(5) : query.getString(4)); - } - if(street == null){ - street = new Street(city); - street.setId(query.getLong(1)); - street.setLocation(query.getDouble(2), query.getDouble(3)); - street.setName(query.getString(4)); - street.setEnName(query.getString(5)); - if(city != null){ - city.registerStreet(street, useEnglishNames); - } - } - post.registerStreet(street, useEnglishNames); - } while (query.moveToNext()); - } - query.close(); - log.debug("Loaded " +post.getStreets().size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - public void registerCity(City city){ - cities.put(city.getId(), city); - - if(!cityTypes.containsKey(city.getType())){ - cityTypes.put(city.getType(), new ArrayList()); - } - cityTypes.get(city.getType()).add(city); - } - - protected City parseCityFromCursor(Cursor query){ - CityType type = CityType.valueFromString(query.getString(IndexCityTable.CITY_TYPE.ordinal())); - if (type != null) { - City city = new City(type); - city.setId(query.getLong(IndexCityTable.ID.ordinal())); - city.setLocation(query.getDouble(IndexCityTable.LATITUDE.ordinal()), - query.getDouble(IndexCityTable.LONGITUDE.ordinal())); - city.setName(query.getString(IndexCityTable.NAME.ordinal())); - city.setEnName(query.getString(IndexCityTable.NAME_EN.ordinal())); - return city; - } - return null; - } - - public void preloadCities(){ - if (cities.isEmpty()) { - log.debug("Start loading cities for " +getName()); //$NON-NLS-1$ - StringBuilder where = new StringBuilder(); - where.append(IndexCityTable.CITY_TYPE.toString()).append('='). - append('\'').append(CityType.valueToString(CityType.CITY)).append('\'').append(" or "). //$NON-NLS-1$ - append(IndexCityTable.CITY_TYPE.toString()).append('='). - append('\'').append(CityType.valueToString(CityType.TOWN)).append('\''); - Cursor query = db.query(IndexCityTable.getTable(), IndexConstants.generateColumnNames(IndexCityTable.values()), - where.toString(), null, null, null, null); - if(query.moveToFirst()){ - do { - City city = parseCityFromCursor(query); - if (city != null) { - cities.put(city.getId(), city); - - if(!cityTypes.containsKey(city.getType())){ - cityTypes.put(city.getType(), new ArrayList()); - } - cityTypes.get(city.getType()).add(city); - } - - } while(query.moveToNext()); - } - log.debug("Loaded " + cities.size() + " cities"); //$NON-NLS-1$ //$NON-NLS-2$ - query.close(); - } - } } diff --git a/OsmAnd/src/net/osmand/RegionAddressRepositoryBinary.java b/OsmAnd/src/net/osmand/RegionAddressRepositoryBinary.java new file mode 100644 index 0000000000..eee996385d --- /dev/null +++ b/OsmAnd/src/net/osmand/RegionAddressRepositoryBinary.java @@ -0,0 +1,325 @@ +package net.osmand; + +import java.io.IOException; +import java.text.Collator; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import net.osmand.binary.BinaryMapIndexReader; +import net.osmand.data.Building; +import net.osmand.data.City; +import net.osmand.data.MapObject; +import net.osmand.data.MapObjectComparator; +import net.osmand.data.PostCode; +import net.osmand.data.Street; +import net.osmand.osm.LatLon; + +import org.apache.commons.logging.Log; + + +public class RegionAddressRepositoryBinary implements RegionAddressRepository { + private static final Log log = LogUtil.getLog(RegionAddressRepositoryBinary.class); + private BinaryMapIndexReader file; + private String region; + + + private LinkedHashMap cities = new LinkedHashMap(); + private Map postCodes = new TreeMap(Collator.getInstance()); + private boolean useEnglishNames = false; + + private Comparator comparator = new MapObjectComparator(useEnglishNames); + + + public RegionAddressRepositoryBinary(BinaryMapIndexReader file, String name) { + this.file = file; + this.region = name; + } + + public void close(){ + this.file = null; + } + + @Override + public boolean isMapRepository() { + return true; + } + + @Override + public void fillWithSuggestedBuildings(PostCode postcode, Street street, String name, List buildingsToFill) { + preloadBuildings(street); + if(name.length() == 0){ + buildingsToFill.addAll(street.getBuildings()); + return; + } + name = name.toLowerCase(); + int ind = 0; + for (Building building : street.getBuildings()) { + String bName = useEnglishNames ? building.getEnName() : building.getName(); + String lowerCase = bName.toLowerCase(); + if (lowerCase.startsWith(name)) { + buildingsToFill.add(ind, building); + ind++; + } else if (lowerCase.contains(name)) { + buildingsToFill.add(building); + } + } + Collections.sort(buildingsToFill, comparator); + } + + private void preloadBuildings(Street street) { + if(street.getBuildings().isEmpty()){ + try { + file.preloadBuildings(street); + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + } + } + + + @Override + public void fillWithSuggestedStreets(MapObject o, String name, List streetsToFill) { + assert o instanceof PostCode || o instanceof City; + City city = (City) (o instanceof City ? o : null); + PostCode post = (PostCode) (o instanceof PostCode ? o : null); + preloadStreets(o); + name = name.toLowerCase(); + + Collection streets = post == null ? city.getStreets() : post.getStreets() ; + + if(name.length() == 0){ + streetsToFill.addAll(streets); + } else { + int ind = 0; + for (Street s : streets) { + String sName = useEnglishNames ? s.getEnName() : s.getName(); + String lowerCase = sName.toLowerCase(); + if (lowerCase.startsWith(name)) { + streetsToFill.add(ind, s); + ind++; + } else if (lowerCase.contains(name)) { + streetsToFill.add(s); + } + } + } + Collections.sort(streetsToFill, comparator); + + + } + + private void preloadStreets(MapObject o) { + assert o instanceof PostCode || o instanceof City; + try { + if(o instanceof PostCode){ + file.preloadStreets((PostCode) o); + } else { + file.preloadStreets((City) o); + } + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + + } + + + @Override + public void fillWithSuggestedCities(String name, List citiesToFill, LatLon currentLocation) { + preloadCities(); + try { + // essentially index is created that cities towns are first in cities map + int ind = 0; + if (name.length() >= 2 && + Character.isDigit(name.charAt(0)) && + Character.isDigit(name.charAt(1))) { + // also try to identify postcodes + String uName = name.toUpperCase(); + for (PostCode code : file.getPostcodes(region)) { + if (code.getName().startsWith(uName)) { + citiesToFill.add(ind++, code); + } else if(code.getName().contains(uName)){ + citiesToFill.add(code); + } + } + + } + if (name.length() < 3) { + if (name.length() == 0) { + citiesToFill.addAll(cities.values()); + } else { + name = name.toLowerCase(); + for (City c : cities.values()) { + String cName = useEnglishNames ? c.getEnName() : c.getName(); + String lowerCase = cName.toLowerCase(); + if (lowerCase.startsWith(name)) { + citiesToFill.add(c); + } + } + } + } else { + name = name.toLowerCase(); + Collection src = cities.values(); + for (City c : src) { + String cName = useEnglishNames ? c.getEnName() : c.getName(); + String lowerCase = cName.toLowerCase(); + if (lowerCase.startsWith(name)) { + citiesToFill.add(ind, c); + ind++; + } else if (lowerCase.contains(name)) { + citiesToFill.add(c); + } + } + int initialsize = citiesToFill.size(); + + for(City c : file.getVillages(name)){ + String cName = useEnglishNames ? c.getEnName() : c.getName(); + String lowerCase = cName.toLowerCase(); + if (lowerCase.startsWith(name)) { + citiesToFill.add(ind, c); + ind++; + } else if (lowerCase.contains(name)) { + citiesToFill.add(c); + } + } + log.debug("Loaded citites " + (citiesToFill.size() - initialsize)); //$NON-NLS-1$ + } + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + + } + + @Override + public void fillWithSuggestedStreetsIntersectStreets(City city, Street st, List streetsToFill) { + // TODO Auto-generated method stub + } + + @Override + public LatLon findStreetIntersection(Street street, Street street2) { + // TODO Auto-generated method stub + return null; + } + + + @Override + public Building getBuildingByName(Street street, String name) { + preloadBuildings(street); + for (Building b : street.getBuildings()) { + String bName = useEnglishNames ? b.getEnName() : b.getName(); + if (bName.equals(name)) { + return b; + } + } + return null; + } + + @Override + public String getName() { + return region; + } + + @Override + public boolean useEnglishNames() { + return useEnglishNames; + } + + + + @Override + public City getCityById(Long id) { + if(id == -1){ + // do not preload cities for that case + return null; + } + preloadCities(); + return cities.get(id); + } + + + private void preloadCities() { + if (cities.isEmpty()) { + try { + List cs = file.getCities(region); + for (City c : cs) { + cities.put(c.getId(), c); + } + } catch (IOException e) { + log.error("Disk operation failed", e); //$NON-NLS-1$ + } + } + } + + @Override + public PostCode getPostcode(String name) { + if(name == null){ + return null; + } + String uc = name.toUpperCase(); + if(!postCodes.containsKey(uc)){ + try { + postCodes.put(uc, file.getPostcodeByName(this.region, name)); + } catch (IOException e) { + log.error("Disk operation failed", e); //$NON-NLS-1$ + } + } + return postCodes.get(uc); + } + + + @Override + public Street getStreetByName(MapObject o, String name) { + assert o instanceof PostCode || o instanceof City; + City city = (City) (o instanceof City ? o : null); + PostCode post = (PostCode) (o instanceof PostCode ? o : null); + preloadStreets(o); + name = name.toLowerCase(); + Collection streets = post == null ? city.getStreets() : post.getStreets(); + for (Street s : streets) { + String sName = useEnglishNames ? s.getEnName() : s.getName(); + String lowerCase = sName.toLowerCase(); + if (lowerCase.equals(name)) { + return s; + } + } + return null; + } + + + + @Override + public void setUseEnglishNames(boolean useEnglishNames) { + this.useEnglishNames = useEnglishNames; + this.comparator = new MapObjectComparator(useEnglishNames); + } + + @Override + public void addCityToPreloadedList(City city) { + cities.put(city.getId(), city); + } + + @Override + public boolean areCitiesPreloaded() { + return !cities.isEmpty(); + } + + @Override + public boolean arePostcodesPreloaded() { + // postcodes are always preloaded + // do not load them into memory (just cache last used) + return true; + } + + @Override + public void clearCache() { + cities.clear(); + postCodes.clear(); + + } + + + +} diff --git a/OsmAnd/src/net/osmand/RegionAddressRepositoryOdb.java b/OsmAnd/src/net/osmand/RegionAddressRepositoryOdb.java new file mode 100644 index 0000000000..b50b2b4e5a --- /dev/null +++ b/OsmAnd/src/net/osmand/RegionAddressRepositoryOdb.java @@ -0,0 +1,524 @@ +package net.osmand; + +import java.io.File; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import net.osmand.data.Building; +import net.osmand.data.City; +import net.osmand.data.MapObject; +import net.osmand.data.MapObjectComparator; +import net.osmand.data.PostCode; +import net.osmand.data.Street; +import net.osmand.data.City.CityType; +import net.osmand.data.index.IndexConstants; +import net.osmand.data.index.IndexConstants.IndexBuildingTable; +import net.osmand.data.index.IndexConstants.IndexCityTable; +import net.osmand.data.index.IndexConstants.IndexStreetNodeTable; +import net.osmand.data.index.IndexConstants.IndexStreetTable; +import net.osmand.osm.LatLon; +import net.osmand.osm.Node; +import net.osmand.osm.Way; + +import org.apache.commons.logging.Log; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + + +public class RegionAddressRepositoryOdb implements RegionAddressRepository { + private static final Log log = LogUtil.getLog(RegionAddressRepositoryOdb.class); + private SQLiteDatabase db; + private String name; + private LinkedHashMap cities = new LinkedHashMap(); + + private Map> cityTypes = new HashMap>(); + private Map postCodes = new TreeMap(Collator.getInstance()); + + private boolean useEnglishNames = false; + + + public boolean initialize(final IProgress progress, File file) { + long start = System.currentTimeMillis(); + if(db != null){ + // close previous db + db.close(); + } + db = SQLiteDatabase.openOrCreateDatabase(file, null); + // add * as old format + name = file.getName().substring(0, file.getName().indexOf('.'))+" *"; //$NON-NLS-1$ + if(db.getVersion() != IndexConstants.ADDRESS_TABLE_VERSION){ + db.close(); + db = null; + return false; + } + + if (log.isDebugEnabled()) { + log.debug("Initializing address db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + return true; + } + + public void close(){ + clearCities(); + if(db != null){ + db.close(); + } + } + + public String getName() { + return name; + } + + public void clearCities(){ + cities.clear(); + cityTypes.clear(); + postCodes.clear(); + } + + public boolean areCitiesPreloaded(){ + return !cities.isEmpty(); + } + public boolean arePostcodesPreloaded(){ + return !postCodes.isEmpty(); + } + + public PostCode getPostcode(String name){ + if(name == null){ + return null; + } + preloadPostcodes(); + return postCodes.get(name.toUpperCase()); + } + + public City getCityById(Long id){ + if(id == -1){ + // do not preload cities for that case + return null; + } + preloadCities(); + return cities.get(id); + } + + + public Street getStreetByName(MapObject city, String name) { + preloadStreets(city); + if (city instanceof City) { + return ((City) city).getStreet(name); + } else { + return ((PostCode) city).getStreet(name); + } + } + + public Building getBuildingByName(Street street, String name){ + if(street.getBuildings().isEmpty()){ + preloadBuildings(street); + } + for(Building b : street.getBuildings()){ + String bName = useEnglishNames ? b.getEnName() : b.getName(); + if(bName.equals(name)){ + return b; + } + } + return null; + } + + public boolean useEnglishNames(){ + return useEnglishNames; + } + + public void setUseEnglishNames(boolean useEnglishNames) { + this.useEnglishNames = useEnglishNames; + // sort streets + for (City c : cities.values()) { + if (!c.isEmptyWithStreets()) { + ArrayList list = new ArrayList(c.getStreets()); + c.removeAllStreets(); + for (Street s : list) { + c.registerStreet(s, useEnglishNames); + } + } + } + // sort cities + ArrayList list = new ArrayList(cities.values()); + Collections.sort(list, new MapObjectComparator(useEnglishNames)); + cities.clear(); + cityTypes.clear(); + for(City c : list){ + addCityToPreloadedList(c); + } + } + + public void fillWithSuggestedBuildings(PostCode postcode, Street street, String name, List buildingsToFill){ + preloadBuildings(street); + name = name.toLowerCase(); + int ind = 0; + boolean empty = name.length() == 0; + if(empty && postcode == null){ + buildingsToFill.addAll(street.getBuildings()); + return; + } + for (Building building : street.getBuildings()) { + if(postcode != null && !postcode.getName().equals(building.getPostcode())){ + continue; + } else if(empty){ + buildingsToFill.add(building); + continue; + } + String bName = useEnglishNames ? building.getEnName() : building.getName(); + String lowerCase = bName.toLowerCase(); + if (lowerCase.startsWith(name)) { + buildingsToFill.add(ind, building); + ind++; + } else if (lowerCase.contains(name)) { + buildingsToFill.add(building); + } + } + } + + public void fillWithSuggestedStreetsIntersectStreets(City city, Street st, List streetsToFill) { + if (st != null) { + Set strIds = new TreeSet(); + log.debug("Start loading instersection streets for " + city.getName()); //$NON-NLS-1$ + Cursor query = db.rawQuery("SELECT B.STREET FROM street_node A JOIN street_node B ON A.ID = B.ID WHERE A.STREET = ?", //$NON-NLS-1$ + new String[] { st.getId() + "" }); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + if (st.getId() != query.getLong(0)) { + strIds.add(query.getLong(0)); + } + } while (query.moveToNext()); + } + query.close(); + for (Street s : city.getStreets()) { + if (strIds.contains(s.getId())) { + streetsToFill.add(s); + } + } + log.debug("Loaded " + strIds.size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ + preloadWayNodes(st); + } + } + + + public void fillWithSuggestedStreets(MapObject o, String name, List streetsToFill){ + assert o instanceof PostCode || o instanceof City; + City city = (City) (o instanceof City ? o : null); + PostCode post = (PostCode) (o instanceof PostCode ? o : null); + preloadStreets(o); + name = name.toLowerCase(); + + Collection streets = post == null ? city.getStreets() : post.getStreets() ; + int ind = 0; + if(name.length() == 0){ + streetsToFill.addAll(streets); + return; + } + ind = 0; + for (Street s : streets) { + String sName = useEnglishNames ? s.getEnName() : s.getName(); + String lowerCase = sName.toLowerCase(); + if (lowerCase.startsWith(name)) { + streetsToFill.add(ind, s); + ind++; + } else if (lowerCase.contains(name)) { + streetsToFill.add(s); + } + } + } + + public void fillWithSuggestedCities(String name, List citiesToFill, LatLon currentLocation){ + preloadCities(); + // essentially index is created that cities towns are first in cities map + int ind = 0; + if (name.length() >= 2 && + Character.isDigit(name.charAt(0)) && + Character.isDigit(name.charAt(1))) { + preloadPostcodes(); + // also try to identify postcodes + String uName = name.toUpperCase(); + for (String code : postCodes.keySet()) { + if (code.startsWith(uName)) { + citiesToFill.add(ind++, postCodes.get(code)); + } else if(code.contains(uName)){ + citiesToFill.add(postCodes.get(code)); + } + } + + } + if(name.length() < 3){ + EnumSet set = EnumSet.of(CityType.CITY, CityType.TOWN); + for(CityType t : set){ + List list = cityTypes.get(t); + if(list == null){ + continue; + } + if(name.length() == 0){ + citiesToFill.addAll(list); + } else { + name = name.toLowerCase(); + for (City c : list) { + String cName = useEnglishNames ? c.getEnName() : c.getName(); + String lowerCase = cName.toLowerCase(); + if(lowerCase.startsWith(name)){ + citiesToFill.add(c); + } + } + } + } + } else { + name = name.toLowerCase(); + Collection src = cities.values(); + for (City c : src) { + String cName = useEnglishNames ? c.getEnName() : c.getName(); + String lowerCase = cName.toLowerCase(); + if (lowerCase.startsWith(name)) { + citiesToFill.add(ind, c); + ind++; + } else if (lowerCase.contains(name)) { + citiesToFill.add(c); + } + } + int initialsize = citiesToFill.size(); + log.debug("Start loading cities for " +getName() + " filter " + name); //$NON-NLS-1$ //$NON-NLS-2$ + // lower function in SQLite requires ICU extension + name = Algoritms.capitalizeFirstLetterAndLowercase(name); + int i = name.indexOf('\''); + if(i != -1){ + // SQL quotation + name = name.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ + } + StringBuilder where = new StringBuilder(80); + where. + append(IndexCityTable.CITY_TYPE.toString()).append(" not in ("). //$NON-NLS-1$ + append('\'').append(CityType.valueToString(CityType.CITY)).append('\'').append(", "). //$NON-NLS-1$ + append('\'').append(CityType.valueToString(CityType.TOWN)).append('\'').append(") and "). //$NON-NLS-1$ + append(useEnglishNames ? IndexCityTable.NAME_EN.toString() : IndexCityTable.NAME.toString()).append(" LIKE '"+name+"%'"); //$NON-NLS-1$ //$NON-NLS-2$ + Cursor query = db.query(IndexCityTable.getTable(), IndexConstants.generateColumnNames(IndexCityTable.values()), + where.toString(), null, null, null, null); + if (query.moveToFirst()) { + List hamlets = new ArrayList(); + do { + hamlets.add(parseCityFromCursor(query)); + } while (query.moveToNext()); + Collections.sort(hamlets, new MapObjectNameDistanceComparator(useEnglishNames, currentLocation)); + citiesToFill.addAll(hamlets); + } + query.close(); + + + + log.debug("Loaded citites " + (citiesToFill.size() - initialsize)); //$NON-NLS-1$ + } + } + + public void preloadWayNodes(Street street){ + if(street.getWayNodes().isEmpty()){ + Cursor query = db.query(IndexStreetNodeTable.getTable(), IndexConstants.generateColumnNames(IndexStreetNodeTable.values()), "? = street", //$NON-NLS-1$ + new String[] { street.getId() + "" }, null, null, null); //$NON-NLS-1$ + log.debug("Start loading waynodes for " + street.getName()); //$NON-NLS-1$ + Map ways = new LinkedHashMap(); + if (query.moveToFirst()) { + do { + Node n = new Node(query.getDouble(IndexStreetNodeTable.LATITUDE.ordinal()), + query.getDouble(IndexBuildingTable.LONGITUDE.ordinal()), + query.getLong(IndexStreetNodeTable.ID.ordinal())); + long way = query.getLong(IndexStreetNodeTable.WAY.ordinal()); + if(!ways.containsKey(way)){ + ways.put(way, new Way(way)); + } + ways.get(way).addNode(n); + } while (query.moveToNext()); + } + query.close(); + for(Way w : ways.values()){ + street.getWayNodes().add(w); + } + log.debug("Loaded " + ways.size() + " ways"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + public void preloadPostcodes() { + if (postCodes.isEmpty()) { + // check if it possible to load postcodes + Cursor query = db.query(true, IndexBuildingTable.getTable(), new String[] { IndexBuildingTable.POSTCODE.toString() }, null, + null, null, null, null, null); + log.debug("Start loading postcodes for "); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + String postcode = query.getString(0); + if (postcode != null) { + postCodes.put(postcode, new PostCode(postcode)); + } + } while (query.moveToNext()); + } + query.close(); + log.debug("Loaded " + postCodes.size() + " postcodes "); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public void preloadBuildings(Street street){ + if (street.getBuildings().isEmpty()) { + Cursor query = db.query(IndexBuildingTable.getTable(), IndexConstants.generateColumnNames(IndexBuildingTable.values()), "? = street", //$NON-NLS-1$ + new String[] { street.getId() + "" }, null, null, null); //$NON-NLS-1$ + log.debug("Start loading buildings for " + street.getName()); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + Building building = new Building(); + building.setId(query.getLong(IndexBuildingTable.ID.ordinal())); + building.setLocation(query.getDouble(IndexBuildingTable.LATITUDE.ordinal()), query.getDouble(IndexBuildingTable.LONGITUDE + .ordinal())); + building.setName(query.getString(IndexBuildingTable.NAME.ordinal())); + building.setEnName(query.getString(IndexBuildingTable.NAME_EN.ordinal())); + building.setPostcode(query.getString(IndexBuildingTable.POSTCODE.ordinal())); + street.registerBuilding(building); + } while (query.moveToNext()); + street.sortBuildings(); + } + query.close(); + log.debug("Loaded " + street.getBuildings().size() + " buildings"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public void preloadStreets(MapObject o){ + assert o instanceof PostCode || o instanceof City; + City city = (City) (o instanceof City ? o : null); + PostCode post = (PostCode) (o instanceof PostCode ? o : null); + if (city != null && city.isEmptyWithStreets()) { + log.debug("Start loading streets for " + city.getName()); //$NON-NLS-1$ + Cursor query = db.query(IndexStreetTable.getTable(), IndexConstants.generateColumnNames(IndexStreetTable.values()), "? = city", //$NON-NLS-1$ + new String[] { city.getId() + "" }, null, null, null); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + Street street = new Street(city); + street.setId(query.getLong(IndexStreetTable.ID.ordinal())); + street.setLocation(query.getDouble(IndexStreetTable.LATITUDE.ordinal()), query.getDouble(IndexStreetTable.LONGITUDE.ordinal())); + street.setName(query.getString(IndexStreetTable.NAME.ordinal())); + street.setEnName(query.getString(IndexStreetTable.NAME_EN.ordinal())); + city.registerStreet(street, useEnglishNames); + } while (query.moveToNext()); + } + query.close(); + log.debug("Loaded " + city.getStreets().size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ + } else if(post != null && post.isEmptyWithStreets()){ + log.debug("Start loading streets for " + post.getName()); //$NON-NLS-1$ + Cursor query = db.rawQuery("SELECT B.CITY, B.ID,B.LATITUDE, B.LONGITUDE, B.NAME, B.NAME_EN FROM building A JOIN street B ON A.street = B.ID WHERE A.postcode = ?", //$NON-NLS-1$ + new String[] { post.getName() + "" }); //$NON-NLS-1$ + if (query.moveToFirst()) { + do { + city = getCityById(query.getLong(0)); + Street street = null; + if(city != null){ + preloadStreets(city); + street = city.getStreet(useEnglishNames ? query.getString(5) : query.getString(4)); + } + if(street == null){ + street = new Street(city); + street.setId(query.getLong(1)); + street.setLocation(query.getDouble(2), query.getDouble(3)); + street.setName(query.getString(4)); + street.setEnName(query.getString(5)); + if(city != null){ + city.registerStreet(street, useEnglishNames); + } + } + post.registerStreet(street, useEnglishNames); + } while (query.moveToNext()); + } + query.close(); + log.debug("Loaded " +post.getStreets().size() + " streets"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + public void addCityToPreloadedList(City city){ + cities.put(city.getId(), city); + + if(!cityTypes.containsKey(city.getType())){ + cityTypes.put(city.getType(), new ArrayList()); + } + cityTypes.get(city.getType()).add(city); + } + + protected City parseCityFromCursor(Cursor query){ + CityType type = CityType.valueFromString(query.getString(IndexCityTable.CITY_TYPE.ordinal())); + if (type != null) { + City city = new City(type); + city.setId(query.getLong(IndexCityTable.ID.ordinal())); + city.setLocation(query.getDouble(IndexCityTable.LATITUDE.ordinal()), + query.getDouble(IndexCityTable.LONGITUDE.ordinal())); + city.setName(query.getString(IndexCityTable.NAME.ordinal())); + city.setEnName(query.getString(IndexCityTable.NAME_EN.ordinal())); + return city; + } + return null; + } + + public void preloadCities(){ + if (cities.isEmpty()) { + log.debug("Start loading cities for " +getName()); //$NON-NLS-1$ + StringBuilder where = new StringBuilder(); + where.append(IndexCityTable.CITY_TYPE.toString()).append('='). + append('\'').append(CityType.valueToString(CityType.CITY)).append('\'').append(" or "). //$NON-NLS-1$ + append(IndexCityTable.CITY_TYPE.toString()).append('='). + append('\'').append(CityType.valueToString(CityType.TOWN)).append('\''); + Cursor query = db.query(IndexCityTable.getTable(), IndexConstants.generateColumnNames(IndexCityTable.values()), + where.toString(), null, null, null, null); + if(query.moveToFirst()){ + do { + City city = parseCityFromCursor(query); + if (city != null) { + cities.put(city.getId(), city); + + if(!cityTypes.containsKey(city.getType())){ + cityTypes.put(city.getType(), new ArrayList()); + } + cityTypes.get(city.getType()).add(city); + } + + } while(query.moveToNext()); + } + log.debug("Loaded " + cities.size() + " cities"); //$NON-NLS-1$ //$NON-NLS-2$ + query.close(); + } + } + + @Override + public boolean isMapRepository() { + return false; + } + + @Override + public void clearCache() { + clearCities(); + + } + + @Override + public LatLon findStreetIntersection(Street street, Street street2) { + preloadWayNodes(street2); + preloadWayNodes(street); + for(Way w : street2.getWayNodes()){ + for(Way w2 : street.getWayNodes()){ + for(Node n : w.getNodes()){ + for(Node n2 : w2.getNodes()){ + if(n.getId() == n2.getId()){ + return n.getLatLon(); + } + } + } + } + } + return null; + } +} diff --git a/OsmAnd/src/net/osmand/ResourceManager.java b/OsmAnd/src/net/osmand/ResourceManager.java index 4729db7b11..7d23f28e19 100644 --- a/OsmAnd/src/net/osmand/ResourceManager.java +++ b/OsmAnd/src/net/osmand/ResourceManager.java @@ -13,6 +13,7 @@ import java.util.Stack; import java.util.TreeMap; import net.osmand.activities.OsmandApplication; +import net.osmand.binary.BinaryMapIndexReader; import net.osmand.data.Amenity; import net.osmand.data.TransportStop; import net.osmand.data.index.IndexConstants; @@ -367,9 +368,15 @@ public class ResourceManager { if (f.getName().endsWith(IndexConstants.BINARY_MAP_INDEX_EXT)) { progress.startTask(Messages.getMessage("indexing_map") + f.getName(), -1); //$NON-NLS-1$ try { - boolean initialized = renderer.initializeNewResource(progress, f); - if (!initialized) { + BinaryMapIndexReader index = renderer.initializeNewResource(progress, f); + if (index == null) { warnings.add(MessageFormat.format(Messages.getMessage("version_index_is_not_supported"), f.getName())); //$NON-NLS-1$ + } else { + for(String rName : index.getRegionNames()) { + // skip duplicate names (don't make collision between getName() and name in the map) + RegionAddressRepositoryBinary rarb = new RegionAddressRepositoryBinary(index, rName); + addressMap.put(rName, rarb); + } } } catch (SQLiteException e) { log.error("Exception reading " + f.getAbsolutePath(), e); //$NON-NLS-1$ @@ -430,7 +437,7 @@ public class ResourceManager { public void indexingAddress(final IProgress progress, List warnings, File f) { if (f.getName().endsWith(IndexConstants.ADDRESS_INDEX_EXT)) { - RegionAddressRepository repository = new RegionAddressRepository(); + RegionAddressRepositoryOdb repository = new RegionAddressRepositoryOdb(); progress.startTask(Messages.getMessage("indexing_address") + f.getName(), -1); //$NON-NLS-1$ try { boolean initialized = repository.initialize(progress, f); @@ -630,7 +637,7 @@ public class ResourceManager { r.clearCache(); } for(RegionAddressRepository r : addressMap.values()){ - r.clearCities(); + r.clearCache(); } renderer.clearCache(); diff --git a/OsmAnd/src/net/osmand/activities/search/SearchAddressActivity.java b/OsmAnd/src/net/osmand/activities/search/SearchAddressActivity.java index f13082c601..ea8a2ecf9c 100644 --- a/OsmAnd/src/net/osmand/activities/search/SearchAddressActivity.java +++ b/OsmAnd/src/net/osmand/activities/search/SearchAddressActivity.java @@ -14,8 +14,6 @@ import net.osmand.data.MapObject; import net.osmand.data.PostCode; import net.osmand.data.Street; import net.osmand.osm.LatLon; -import net.osmand.osm.Node; -import net.osmand.osm.Way; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -179,23 +177,8 @@ public class SearchAddressActivity extends Activity { int zoom = 12; boolean en = OsmandSettings.usingEnglishNames(OsmandSettings.getPrefs(this)); if (street2 != null && street != null) { - region.preloadWayNodes(street2); - region.preloadWayNodes(street); - Node inters = null; - for(Way w : street2.getWayNodes()){ - for(Way w2 : street.getWayNodes()){ - for(Node n : w.getNodes()){ - for(Node n2 : w2.getNodes()){ - if(n.getId() == n2.getId()){ - inters = n; - break; - } - } - } - } - } - if(inters != null){ - l = inters.getLatLon(); + l = region.findStreetIntersection(street, street2); + if(l != null) { String cityName = postcode != null? postcode.getName() : city.getName(en); historyName = MessageFormat.format(getString(R.string.search_history_int_streets), street.getName(en), street2.getName(en), cityName); @@ -386,21 +369,5 @@ public class SearchAddressActivity extends Activity { } } - - @Override - protected void onPause() { - // Do not reset settings (cause it is not so necessary) -// if(building == null && OsmandSettings.getLastSearchedBuilding(this).length() > 0){ -// OsmandSettings.setLastSearchedBuilding(this, ""); -// } -// if(street == null && OsmandSettings.getLastSearchedStreet(this).length() > 0){ -// OsmandSettings.setLastSearchedStreet(this, ""); -// } -// if(city == null && OsmandSettings.getLastSearchedCity(this) != -1){ -// OsmandSettings.setLastSearchedCity(this, -1l); -// } - super.onPause(); - } - } diff --git a/OsmAnd/src/net/osmand/activities/search/SearchCityByNameActivity.java b/OsmAnd/src/net/osmand/activities/search/SearchCityByNameActivity.java index 2ac73f179c..a8ec73c964 100644 --- a/OsmAnd/src/net/osmand/activities/search/SearchCityByNameActivity.java +++ b/OsmAnd/src/net/osmand/activities/search/SearchCityByNameActivity.java @@ -52,7 +52,7 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity