diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryMapAddressReaderAdapter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryMapAddressReaderAdapter.java index 8500c8a7d5..7b1734c12b 100644 --- a/DataExtractionOSM/src/net/osmand/binary/BinaryMapAddressReaderAdapter.java +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryMapAddressReaderAdapter.java @@ -1,505 +1,505 @@ -package net.osmand.binary; - -import java.io.IOException; -import java.util.List; - -import net.osmand.StringMatcher; -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.LatLon; -import net.osmand.osm.MapUtils; -import net.sf.junidecode.Junidecode; - -import com.google.protobuf.CodedInputStreamRAF; -import com.google.protobuf.WireFormat; - -public class BinaryMapAddressReaderAdapter { - - public static class AddressRegion extends BinaryIndexPart { - String enName; - - int postcodesOffset = -1; - int villagesOffset = -1; - int citiesOffset = -1; - } - - private CodedInputStreamRAF codedIS; - private final BinaryMapIndexReader map; - - protected BinaryMapAddressReaderAdapter(BinaryMapIndexReader map){ - this.codedIS = map.codedIS; - this.map = map; - } - - private void skipUnknownField(int t) throws IOException { - map.skipUnknownField(t); - } - - private int readInt() throws IOException { - return map.readInt(); - } - - - protected void readAddressIndex(AddressRegion region) throws IOException { - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - if(region.enName == null || region.enName.length() == 0){ - region.enName = Junidecode.unidecode(region.name); - } - return; - case OsmandOdb.OsmAndAddressIndex.NAME_FIELD_NUMBER : - region.name = codedIS.readString(); - break; - case OsmandOdb.OsmAndAddressIndex.NAME_EN_FIELD_NUMBER : - region.enName = codedIS.readString(); - break; - case OsmandOdb.OsmAndAddressIndex.CITIES_FIELD_NUMBER : - region.citiesOffset = codedIS.getTotalBytesRead(); - int length = readInt(); - codedIS.seek(region.citiesOffset + length + 4); - break; - case OsmandOdb.OsmAndAddressIndex.VILLAGES_FIELD_NUMBER : - region.villagesOffset = codedIS.getTotalBytesRead(); - length = readInt(); - codedIS.seek(region.villagesOffset + length + 4); - break; - case OsmandOdb.OsmAndAddressIndex.POSTCODES_FIELD_NUMBER : - region.postcodesOffset = codedIS.getTotalBytesRead(); - length = readInt(); - codedIS.seek(region.postcodesOffset + length + 4); - break; - default: - skipUnknownField(t); - break; - } - } - } - - protected void readCities(List cities, StringMatcher matcher, boolean useEn) throws IOException { - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - return; - case OsmandOdb.CitiesIndex.CITIES_FIELD_NUMBER : - int offset = codedIS.getTotalBytesRead(); - int length = codedIS.readRawVarint32(); - - int oldLimit = codedIS.pushLimit(length); - City c = readCity(null, offset, false, matcher, useEn); - if(c != null){ - cities.add(c); - } - codedIS.popLimit(oldLimit); - break; - default: - skipUnknownField(t); - break; - } - } - } - - - protected 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; - } - } - } - - - protected City readCity(City c, int fileOffset, boolean loadStreets, StringMatcher nameMatcher, boolean useEn) throws IOException{ - int x = 0; - int y = 0; - int streetInd = 0; - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - boolean englishNameMatched = false; - switch (tag) { - case 0: - c.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x)); - if(c.getEnName().length() == 0){ - c.setEnName(Junidecode.unidecode(c.getName())); - } - return c; - case OsmandOdb.CityIndex.CITY_TYPE_FIELD_NUMBER : - int type = codedIS.readUInt32(); - if(c == null){ - c = new City(CityType.values()[type]); - c.setFileOffset(fileOffset); - } - break; - case OsmandOdb.CityIndex.ID_FIELD_NUMBER : - c.setId(codedIS.readUInt64()); - if(nameMatcher != null && useEn && !englishNameMatched){ - codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); - return null; - } - break; - case OsmandOdb.CityIndex.NAME_EN_FIELD_NUMBER : - String enName = codedIS.readString(); - if (nameMatcher != null && enName.length() > 0) { - if(!nameMatcher.matches(enName)){ - codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); - return null; - } else { - englishNameMatched = true; - } - } - c.setEnName(enName); - break; - case OsmandOdb.CityIndex.NAME_FIELD_NUMBER : - String name = codedIS.readString(); - c.setName(name); - if(nameMatcher != null){ - if(!useEn){ - if(!nameMatcher.matches(name)) { - codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); - return null; - } - } else { - if(nameMatcher.matches(Junidecode.unidecode(name))){ - englishNameMatched = true; - } - } - } - break; - case OsmandOdb.CityIndex.X_FIELD_NUMBER : - x = codedIS.readFixed32(); - break; - case OsmandOdb.CityIndex.Y_FIELD_NUMBER : - y = codedIS.readFixed32(); - break; - case OsmandOdb.CityIndex.INTERSECTIONS_FIELD_NUMBER : - codedIS.skipRawBytes(codedIS.readRawVarint32()); - break; - case OsmandOdb.CityIndex.STREETS_FIELD_NUMBER : - int offset = codedIS.getTotalBytesRead(); - int length = codedIS.readRawVarint32(); - if(loadStreets){ - Street s = new Street(c); - int oldLimit = codedIS.pushLimit(length); - s.setFileOffset(offset); - s.setIndexInCity(streetInd++); - readStreet(s, false, x >> 7, y >> 7, null); - c.registerStreet(s); - codedIS.popLimit(oldLimit); - } else { - codedIS.skipRawBytes(length); - } - break; - default: - skipUnknownField(t); - break; - } - } - } - - protected 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; - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - if(loadLocation){ - s.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); - } - if(s.getEnName().length() == 0){ - s.setEnName(Junidecode.unidecode(s.getName())); - } - return s; - case OsmandOdb.StreetIndex.ID_FIELD_NUMBER : - s.setId(codedIS.readUInt64()); - break; - case OsmandOdb.StreetIndex.NAME_EN_FIELD_NUMBER : - s.setEnName(codedIS.readString()); - break; - case OsmandOdb.StreetIndex.NAME_FIELD_NUMBER : - s.setName(codedIS.readString()); - break; - case OsmandOdb.StreetIndex.X_FIELD_NUMBER : - int sx = codedIS.readSInt32(); - if(loadLocation){ - x = sx + city24X; - } else { - x = (int) MapUtils.getTileNumberX(24, s.getLocation().getLongitude()); - } - break; - case OsmandOdb.StreetIndex.Y_FIELD_NUMBER : - int sy = codedIS.readSInt32(); - if(loadLocation){ - y = sy + city24Y; - } else { - y = (int) MapUtils.getTileNumberY(24, s.getLocation().getLatitude()); - } - break; - case OsmandOdb.StreetIndex.BUILDINGS_FIELD_NUMBER : - int offset = codedIS.getTotalBytesRead(); - int length = codedIS.readRawVarint32(); - if(loadBuildings){ - int oldLimit = codedIS.pushLimit(length); - Building b = readBuilding(offset, x, y); - if (postcodeFilter == null || postcodeFilter.equalsIgnoreCase(b.getPostcode())) { - s.registerBuilding(b); - } - codedIS.popLimit(oldLimit); - } else { - codedIS.skipRawBytes(length); - } - break; - default: - skipUnknownField(t); - break; - } - } - } - - protected Building readBuilding(int fileOffset, int street24X, int street24Y) throws IOException{ - int x = 0; - int y = 0; - Building b = new Building(); - b.setFileOffset(fileOffset); - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - b.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); - if(b.getEnName().length() == 0){ - b.setEnName(Junidecode.unidecode(b.getName())); - } - return b; - case OsmandOdb.BuildingIndex.ID_FIELD_NUMBER : - b.setId(codedIS.readUInt64()); - break; - case OsmandOdb.BuildingIndex.NAME_EN_FIELD_NUMBER : - b.setEnName(codedIS.readString()); - break; - case OsmandOdb.BuildingIndex.NAME_FIELD_NUMBER : - b.setName(codedIS.readString()); - break; - case OsmandOdb.BuildingIndex.X_FIELD_NUMBER : - x = codedIS.readSInt32() + street24X; - break; - case OsmandOdb.BuildingIndex.Y_FIELD_NUMBER : - y = codedIS.readSInt32() + street24Y; - break; - case OsmandOdb.BuildingIndex.POSTCODE_FIELD_NUMBER : - b.setPostcode(codedIS.readString()); - break; - default: - skipUnknownField(t); - break; - } - } - } - - // 2 different quires : s2 == null -> fill possible streets, s2 != null return LatLon intersection - private LatLon readIntersectedStreets(Street[] cityStreets, Street s, Street s2, LatLon parent, List streets) throws IOException { - int size = codedIS.readRawVarint32(); - int old = codedIS.pushLimit(size); - boolean e = false; - while(!e){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - e = true; - break; - case OsmandOdb.InteresectedStreets.INTERSECTIONS_FIELD_NUMBER: - int nsize = codedIS.readRawVarint32(); - int nold = codedIS.pushLimit(nsize); - int st1 = -1; - int st2 = -1; - int cx = 0; - int cy = 0; - boolean end = false; - while (!end) { - int nt = codedIS.readTag(); - int ntag = WireFormat.getTagFieldNumber(nt); - switch (ntag) { - case 0: - end = true; - break; - case OsmandOdb.StreetIntersection.INTERSECTEDSTREET1_FIELD_NUMBER: - st1 = codedIS.readUInt32(); - break; - case OsmandOdb.StreetIntersection.INTERSECTEDSTREET2_FIELD_NUMBER: - st2 = codedIS.readUInt32(); - break; - case OsmandOdb.StreetIntersection.INTERSECTEDX_FIELD_NUMBER: - cx = codedIS.readSInt32(); - break; - case OsmandOdb.StreetIntersection.INTERSECTEDY_FIELD_NUMBER: - cy = codedIS.readSInt32(); - break; - default: - skipUnknownField(nt); - } - } - codedIS.popLimit(nold); - if (s2 == null) { - // find all intersections - if (st1 == s.getIndexInCity() && st2 != -1 && st2 < cityStreets.length && cityStreets[st2] != null) { - streets.add(cityStreets[st2]); - } else if (st2 == s.getIndexInCity() && st1 != -1 && st1 < cityStreets.length && cityStreets[st1] != null) { - streets.add(cityStreets[st1]); - } - } else { - if((st1 == s.getIndexInCity() && st2 == s2.getIndexInCity() ) || - (st2 == s.getIndexInCity() && st1 == s2.getIndexInCity())) { - int x = (int) (MapUtils.getTileNumberX(24, parent.getLongitude()) + cx); - int y = (int) (MapUtils.getTileNumberY(24, parent.getLatitude()) + cy); - codedIS.popLimit(old); - return new LatLon(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); - } - } - - break; - default: - skipUnknownField(t); - } - } - codedIS.popLimit(old); - return null; - } - - // do not preload streets in city - protected LatLon findIntersectedStreets(City c, Street s, Street s2, List streets) throws IOException { - if(s.getIndexInCity() == -1){ - return null; - } - codedIS.seek(c.getFileOffset()); - int size = codedIS.readRawVarint32(); - int old = codedIS.pushLimit(size); - while(true){ - int t = codedIS.readTag(); - int tag = WireFormat.getTagFieldNumber(t); - switch (tag) { - case 0: - codedIS.popLimit(old); - return null; - case OsmandOdb.CityIndex.INTERSECTIONS_FIELD_NUMBER : - Street[] cityStreets = new Street[c.getStreets().size()]; - for(Street st : c.getStreets()){ - if(st.getIndexInCity() >= 0 && st.getIndexInCity() < cityStreets.length){ - cityStreets[st.getIndexInCity()] = st; - } - } - LatLon ret = readIntersectedStreets(cityStreets, s, s2, c.getLocation(), streets); - codedIS.popLimit(old); - return ret; - default: - skipUnknownField(t); - } - } - - } - - - - void readPostcodes(List postcodes, StringMatcher nameMatcher) 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); - final PostCode postCode = readPostcode(null, offset, false, null); - //TODO support getEnName?? - if (nameMatcher == null || nameMatcher.matches(postCode.getName())) { - postcodes.add(postCode); - } - codedIS.popLimit(oldLimit); - break; - default: - skipUnknownField(t); - break; - } - } - } - - 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; - } - } - } - - - -} +package net.osmand.binary; + +import java.io.IOException; +import java.util.List; + +import net.osmand.StringMatcher; +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.LatLon; +import net.osmand.osm.MapUtils; +import net.sf.junidecode.Junidecode; + +import com.google.protobuf.CodedInputStreamRAF; +import com.google.protobuf.WireFormat; + +public class BinaryMapAddressReaderAdapter { + + public static class AddressRegion extends BinaryIndexPart { + String enName; + + int postcodesOffset = -1; + int villagesOffset = -1; + int citiesOffset = -1; + } + + private CodedInputStreamRAF codedIS; + private final BinaryMapIndexReader map; + + protected BinaryMapAddressReaderAdapter(BinaryMapIndexReader map){ + this.codedIS = map.codedIS; + this.map = map; + } + + private void skipUnknownField(int t) throws IOException { + map.skipUnknownField(t); + } + + private int readInt() throws IOException { + return map.readInt(); + } + + + protected void readAddressIndex(AddressRegion region) throws IOException { + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + if(region.enName == null || region.enName.length() == 0){ + region.enName = Junidecode.unidecode(region.name); + } + return; + case OsmandOdb.OsmAndAddressIndex.NAME_FIELD_NUMBER : + region.name = codedIS.readString(); + break; + case OsmandOdb.OsmAndAddressIndex.NAME_EN_FIELD_NUMBER : + region.enName = codedIS.readString(); + break; + case OsmandOdb.OsmAndAddressIndex.CITIES_FIELD_NUMBER : + region.citiesOffset = codedIS.getTotalBytesRead(); + int length = readInt(); + codedIS.seek(region.citiesOffset + length + 4); + break; + case OsmandOdb.OsmAndAddressIndex.VILLAGES_FIELD_NUMBER : + region.villagesOffset = codedIS.getTotalBytesRead(); + length = readInt(); + codedIS.seek(region.villagesOffset + length + 4); + break; + case OsmandOdb.OsmAndAddressIndex.POSTCODES_FIELD_NUMBER : + region.postcodesOffset = codedIS.getTotalBytesRead(); + length = readInt(); + codedIS.seek(region.postcodesOffset + length + 4); + break; + default: + skipUnknownField(t); + break; + } + } + } + + protected void readCities(List cities, StringMatcher matcher, boolean useEn) throws IOException { + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + return; + case OsmandOdb.CitiesIndex.CITIES_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + + int oldLimit = codedIS.pushLimit(length); + City c = readCity(null, offset, false, matcher, useEn); + if(c != null){ + cities.add(c); + } + codedIS.popLimit(oldLimit); + break; + default: + skipUnknownField(t); + break; + } + } + } + + + protected 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; + } + } + } + + + protected City readCity(City c, int fileOffset, boolean loadStreets, StringMatcher nameMatcher, boolean useEn) throws IOException{ + int x = 0; + int y = 0; + int streetInd = 0; + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + boolean englishNameMatched = false; + switch (tag) { + case 0: + c.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x)); + if(c.getEnName().length() == 0){ + c.setEnName(Junidecode.unidecode(c.getName())); + } + return c; + case OsmandOdb.CityIndex.CITY_TYPE_FIELD_NUMBER : + int type = codedIS.readUInt32(); + if(c == null){ + c = new City(CityType.values()[type]); + c.setFileOffset(fileOffset); + } + break; + case OsmandOdb.CityIndex.ID_FIELD_NUMBER : + c.setId(codedIS.readUInt64()); + if(nameMatcher != null && useEn && !englishNameMatched){ + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return null; + } + break; + case OsmandOdb.CityIndex.NAME_EN_FIELD_NUMBER : + String enName = codedIS.readString(); + if (nameMatcher != null && enName.length() > 0) { + if(!nameMatcher.matches(enName)){ + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return null; + } else { + englishNameMatched = true; + } + } + c.setEnName(enName); + break; + case OsmandOdb.CityIndex.NAME_FIELD_NUMBER : + String name = codedIS.readString(); + c.setName(name); + if(nameMatcher != null){ + if(!useEn){ + if(!nameMatcher.matches(name)) { + codedIS.skipRawBytes(codedIS.getBytesUntilLimit()); + return null; + } + } else { + if(nameMatcher.matches(Junidecode.unidecode(name))){ + englishNameMatched = true; + } + } + } + break; + case OsmandOdb.CityIndex.X_FIELD_NUMBER : + x = codedIS.readFixed32(); + break; + case OsmandOdb.CityIndex.Y_FIELD_NUMBER : + y = codedIS.readFixed32(); + break; + case OsmandOdb.CityIndex.INTERSECTIONS_FIELD_NUMBER : + codedIS.skipRawBytes(codedIS.readRawVarint32()); + break; + case OsmandOdb.CityIndex.STREETS_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + if(loadStreets){ + Street s = new Street(c); + int oldLimit = codedIS.pushLimit(length); + s.setFileOffset(offset); + s.setIndexInCity(streetInd++); + readStreet(s, false, x >> 7, y >> 7, null); + c.registerStreet(s); + codedIS.popLimit(oldLimit); + } else { + codedIS.skipRawBytes(length); + } + break; + default: + skipUnknownField(t); + break; + } + } + } + + protected 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; + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + if(loadLocation){ + s.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); + } + if(s.getEnName().length() == 0){ + s.setEnName(Junidecode.unidecode(s.getName())); + } + return s; + case OsmandOdb.StreetIndex.ID_FIELD_NUMBER : + s.setId(codedIS.readUInt64()); + break; + case OsmandOdb.StreetIndex.NAME_EN_FIELD_NUMBER : + s.setEnName(codedIS.readString()); + break; + case OsmandOdb.StreetIndex.NAME_FIELD_NUMBER : + s.setName(codedIS.readString()); + break; + case OsmandOdb.StreetIndex.X_FIELD_NUMBER : + int sx = codedIS.readSInt32(); + if(loadLocation){ + x = sx + city24X; + } else { + x = (int) MapUtils.getTileNumberX(24, s.getLocation().getLongitude()); + } + break; + case OsmandOdb.StreetIndex.Y_FIELD_NUMBER : + int sy = codedIS.readSInt32(); + if(loadLocation){ + y = sy + city24Y; + } else { + y = (int) MapUtils.getTileNumberY(24, s.getLocation().getLatitude()); + } + break; + case OsmandOdb.StreetIndex.BUILDINGS_FIELD_NUMBER : + int offset = codedIS.getTotalBytesRead(); + int length = codedIS.readRawVarint32(); + if(loadBuildings){ + int oldLimit = codedIS.pushLimit(length); + Building b = readBuilding(offset, x, y); + if (postcodeFilter == null || postcodeFilter.equalsIgnoreCase(b.getPostcode())) { + s.registerBuilding(b); + } + codedIS.popLimit(oldLimit); + } else { + codedIS.skipRawBytes(length); + } + break; + default: + skipUnknownField(t); + break; + } + } + } + + protected Building readBuilding(int fileOffset, int street24X, int street24Y) throws IOException{ + int x = 0; + int y = 0; + Building b = new Building(); + b.setFileOffset(fileOffset); + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + b.setLocation(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); + if(b.getEnName().length() == 0){ + b.setEnName(Junidecode.unidecode(b.getName())); + } + return b; + case OsmandOdb.BuildingIndex.ID_FIELD_NUMBER : + b.setId(codedIS.readUInt64()); + break; + case OsmandOdb.BuildingIndex.NAME_EN_FIELD_NUMBER : + b.setEnName(codedIS.readString()); + break; + case OsmandOdb.BuildingIndex.NAME_FIELD_NUMBER : + b.setName(codedIS.readString()); + break; + case OsmandOdb.BuildingIndex.X_FIELD_NUMBER : + x = codedIS.readSInt32() + street24X; + break; + case OsmandOdb.BuildingIndex.Y_FIELD_NUMBER : + y = codedIS.readSInt32() + street24Y; + break; + case OsmandOdb.BuildingIndex.POSTCODE_FIELD_NUMBER : + b.setPostcode(codedIS.readString()); + break; + default: + skipUnknownField(t); + break; + } + } + } + + // 2 different quires : s2 == null -> fill possible streets, s2 != null return LatLon intersection + private LatLon readIntersectedStreets(Street[] cityStreets, Street s, Street s2, LatLon parent, List streets) throws IOException { + int size = codedIS.readRawVarint32(); + int old = codedIS.pushLimit(size); + boolean e = false; + while(!e){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + e = true; + break; + case OsmandOdb.InteresectedStreets.INTERSECTIONS_FIELD_NUMBER: + int nsize = codedIS.readRawVarint32(); + int nold = codedIS.pushLimit(nsize); + int st1 = -1; + int st2 = -1; + int cx = 0; + int cy = 0; + boolean end = false; + while (!end) { + int nt = codedIS.readTag(); + int ntag = WireFormat.getTagFieldNumber(nt); + switch (ntag) { + case 0: + end = true; + break; + case OsmandOdb.StreetIntersection.INTERSECTEDSTREET1_FIELD_NUMBER: + st1 = codedIS.readUInt32(); + break; + case OsmandOdb.StreetIntersection.INTERSECTEDSTREET2_FIELD_NUMBER: + st2 = codedIS.readUInt32(); + break; + case OsmandOdb.StreetIntersection.INTERSECTEDX_FIELD_NUMBER: + cx = codedIS.readSInt32(); + break; + case OsmandOdb.StreetIntersection.INTERSECTEDY_FIELD_NUMBER: + cy = codedIS.readSInt32(); + break; + default: + skipUnknownField(nt); + } + } + codedIS.popLimit(nold); + if (s2 == null) { + // find all intersections + if (st1 == s.getIndexInCity() && st2 != -1 && st2 < cityStreets.length && cityStreets[st2] != null) { + streets.add(cityStreets[st2]); + } else if (st2 == s.getIndexInCity() && st1 != -1 && st1 < cityStreets.length && cityStreets[st1] != null) { + streets.add(cityStreets[st1]); + } + } else { + if((st1 == s.getIndexInCity() && st2 == s2.getIndexInCity() ) || + (st2 == s.getIndexInCity() && st1 == s2.getIndexInCity())) { + int x = (int) (MapUtils.getTileNumberX(24, parent.getLongitude()) + cx); + int y = (int) (MapUtils.getTileNumberY(24, parent.getLatitude()) + cy); + codedIS.popLimit(old); + return new LatLon(MapUtils.getLatitudeFromTile(24, y), MapUtils.getLongitudeFromTile(24, x)); + } + } + + break; + default: + skipUnknownField(t); + } + } + codedIS.popLimit(old); + return null; + } + + // do not preload streets in city + protected LatLon findIntersectedStreets(City c, Street s, Street s2, List streets) throws IOException { + if(s.getIndexInCity() == -1){ + return null; + } + codedIS.seek(c.getFileOffset()); + int size = codedIS.readRawVarint32(); + int old = codedIS.pushLimit(size); + while(true){ + int t = codedIS.readTag(); + int tag = WireFormat.getTagFieldNumber(t); + switch (tag) { + case 0: + codedIS.popLimit(old); + return null; + case OsmandOdb.CityIndex.INTERSECTIONS_FIELD_NUMBER : + Street[] cityStreets = new Street[c.getStreets().size()]; + for(Street st : c.getStreets()){ + if(st.getIndexInCity() >= 0 && st.getIndexInCity() < cityStreets.length){ + cityStreets[st.getIndexInCity()] = st; + } + } + LatLon ret = readIntersectedStreets(cityStreets, s, s2, c.getLocation(), streets); + codedIS.popLimit(old); + return ret; + default: + skipUnknownField(t); + } + } + + } + + + + void readPostcodes(List postcodes, StringMatcher nameMatcher) 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); + final PostCode postCode = readPostcode(null, offset, false, null); + //TODO support getEnName?? + if (nameMatcher == null || nameMatcher.matches(postCode.getName())) { + postcodes.add(postCode); + } + codedIS.popLimit(oldLimit); + break; + default: + skipUnknownField(t); + break; + } + } + } + + 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; + } + } + } + + + +} diff --git a/OsmAnd/src/net/osmand/plus/RegionAddressRepositoryBinary.java b/OsmAnd/src/net/osmand/plus/RegionAddressRepositoryBinary.java index 5e0d7282d4..dc5993068b 100644 --- a/OsmAnd/src/net/osmand/plus/RegionAddressRepositoryBinary.java +++ b/OsmAnd/src/net/osmand/plus/RegionAddressRepositoryBinary.java @@ -1,337 +1,337 @@ -package net.osmand.plus; - -import static net.osmand.plus.CollatorStringMatcher.ccontains; -import static net.osmand.plus.CollatorStringMatcher.cstartsWith; - -import java.io.IOException; -import java.text.Collator; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import net.osmand.Algoritms; -import net.osmand.LogUtil; -import net.osmand.binary.BinaryMapIndexReader; -import net.osmand.data.Building; -import net.osmand.data.City; -import net.osmand.data.MapObject; -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 final LinkedHashMap cities = new LinkedHashMap(); - private final Map postCodes; - private boolean useEnglishNames = false; - private final Collator collator; - - public RegionAddressRepositoryBinary(BinaryMapIndexReader file, String name) { - this.file = file; - this.region = name; - this.collator = Collator.getInstance(); - this.collator.setStrength(Collator.PRIMARY); //ignores also case - this.postCodes = new TreeMap(collator); - } - - 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(); //lower case not needed, collator ensures that - if (cstartsWith(collator,bName,name)) { - buildingsToFill.add(ind, building); - ind++; - } else if (ccontains(collator,name,bName)) { - buildingsToFill.add(building); - } - } - } - - - private void preloadBuildings(Street street) { - if(street.getBuildings().isEmpty()){ - try { - file.preloadBuildings(street); - street.sortBuildings(); - } catch (IOException e) { - log.error("Disk operation failed" , e); //$NON-NLS-1$ - } - } - } - - - @Override - public void fillWithSuggestedStreets(MapObject o, List streetsToFill, String... names) { - 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); - Collection streets = post == null ? city.getStreets() : post.getStreets() ; - - if(names.length == 0){ - streetsToFill.addAll(streets); - return; - } - - int ind = 0; - for (Street s : streets) { - String sName = useEnglishNames ? s.getEnName() : s.getName(); //lower case not needed, collator ensures that - for (String name : names) { - if (cstartsWith(collator,sName,name)) { - streetsToFill.add(ind, s); - ind++; - } else if (ccontains(collator,name,sName) || ccontains(collator,sName,name)) { - streetsToFill.add(s); - } - } - } - } - - private void preloadStreets(MapObject o) { - assert o instanceof PostCode || o instanceof City; - Collection streets = o instanceof PostCode ? ((PostCode) o).getStreets() : ((City) o).getStreets(); - if(!streets.isEmpty()){ - return; - } - 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 && Algoritms.containsDigit(name)) { - // also try to identify postcodes - String uName = name.toUpperCase(); - for (PostCode code : file.getPostcodes(region,new ContainsStringMatcher(uName,collator))) { - if (cstartsWith(collator,code.getName(),uName)) { - citiesToFill.add(ind++, code); - } else if(ccontains(collator,code.getName(),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(); //lower case not needed, collator ensures that - if (cstartsWith(collator,cName,name)) { - citiesToFill.add(c); - } - } - } - } else { - name = name.toLowerCase(); - Collection src = cities.values(); - for (City c : src) { - String cName = useEnglishNames ? c.getEnName() : c.getName(); //lower case not needed, collator ensures that - if (cstartsWith(collator,cName,name)) { - citiesToFill.add(ind, c); - ind++; - } else if (ccontains(collator,name,cName)) { - citiesToFill.add(c); - } - } - int initialsize = citiesToFill.size(); - - for(City c : file.getVillages(region, new ContainsStringMatcher(name,collator), useEnglishNames )){ - String cName = c.getName(useEnglishNames); //lower case not needed, collator ensures that - if (cstartsWith(collator,cName,name)) { - citiesToFill.add(ind, c); - ind++; - } else if (ccontains(collator,name, cName)) { - 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) { - if(city != null){ - preloadStreets(city); - try { - file.findIntersectedStreets(city, st, streetsToFill); - } catch (IOException e) { - log.error("Disk operation failed" , e); //$NON-NLS-1$ - } - } - } - - @Override - public LatLon findStreetIntersection(Street street, Street street2) { - City city = street.getCity(); - if(city != null){ - preloadStreets(city); - try { - return file.findStreetIntersection(city, street, street2); - } catch (IOException e) { - log.error("Disk operation failed" , e); //$NON-NLS-1$ - } - } - 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); - name = name.toLowerCase(); - preloadStreets(o); - Collection streets = post == null ? city.getStreets() : post.getStreets(); - for (Street s : streets) { - String sName = useEnglishNames ? s.getEnName() : s.getName(); //lower case not needed, collator ensures that - if (collator.equals(sName,name)) { - return s; - } - } - return null; - } - - - - @Override - public void setUseEnglishNames(boolean useEnglishNames) { - this.useEnglishNames = 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(); - - } - - - -} +package net.osmand.plus; + +import static net.osmand.plus.CollatorStringMatcher.ccontains; +import static net.osmand.plus.CollatorStringMatcher.cstartsWith; + +import java.io.IOException; +import java.text.Collator; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import net.osmand.Algoritms; +import net.osmand.LogUtil; +import net.osmand.binary.BinaryMapIndexReader; +import net.osmand.data.Building; +import net.osmand.data.City; +import net.osmand.data.MapObject; +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 final LinkedHashMap cities = new LinkedHashMap(); + private final Map postCodes; + private boolean useEnglishNames = false; + private final Collator collator; + + public RegionAddressRepositoryBinary(BinaryMapIndexReader file, String name) { + this.file = file; + this.region = name; + this.collator = Collator.getInstance(); + this.collator.setStrength(Collator.PRIMARY); //ignores also case + this.postCodes = new TreeMap(collator); + } + + 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(); //lower case not needed, collator ensures that + if (cstartsWith(collator,bName,name)) { + buildingsToFill.add(ind, building); + ind++; + } else if (ccontains(collator,name,bName)) { + buildingsToFill.add(building); + } + } + } + + + private void preloadBuildings(Street street) { + if(street.getBuildings().isEmpty()){ + try { + file.preloadBuildings(street); + street.sortBuildings(); + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + } + } + + + @Override + public void fillWithSuggestedStreets(MapObject o, List streetsToFill, String... names) { + 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); + Collection streets = post == null ? city.getStreets() : post.getStreets() ; + + if(names.length == 0){ + streetsToFill.addAll(streets); + return; + } + + int ind = 0; + for (Street s : streets) { + String sName = useEnglishNames ? s.getEnName() : s.getName(); //lower case not needed, collator ensures that + for (String name : names) { + if (cstartsWith(collator,sName,name)) { + streetsToFill.add(ind, s); + ind++; + } else if (ccontains(collator,name,sName) || ccontains(collator,sName,name)) { + streetsToFill.add(s); + } + } + } + } + + private void preloadStreets(MapObject o) { + assert o instanceof PostCode || o instanceof City; + Collection streets = o instanceof PostCode ? ((PostCode) o).getStreets() : ((City) o).getStreets(); + if(!streets.isEmpty()){ + return; + } + 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 && Algoritms.containsDigit(name)) { + // also try to identify postcodes + String uName = name.toUpperCase(); + for (PostCode code : file.getPostcodes(region,new ContainsStringMatcher(uName,collator))) { + if (cstartsWith(collator,code.getName(),uName)) { + citiesToFill.add(ind++, code); + } else if(ccontains(collator,code.getName(),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(); //lower case not needed, collator ensures that + if (cstartsWith(collator,cName,name)) { + citiesToFill.add(c); + } + } + } + } else { + name = name.toLowerCase(); + Collection src = cities.values(); + for (City c : src) { + String cName = useEnglishNames ? c.getEnName() : c.getName(); //lower case not needed, collator ensures that + if (cstartsWith(collator,cName,name)) { + citiesToFill.add(ind, c); + ind++; + } else if (ccontains(collator,name,cName)) { + citiesToFill.add(c); + } + } + int initialsize = citiesToFill.size(); + + for(City c : file.getVillages(region, new ContainsStringMatcher(name,collator), useEnglishNames )){ + String cName = c.getName(useEnglishNames); //lower case not needed, collator ensures that + if (cstartsWith(collator,cName,name)) { + citiesToFill.add(ind, c); + ind++; + } else if (ccontains(collator,name, cName)) { + 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) { + if(city != null){ + preloadStreets(city); + try { + file.findIntersectedStreets(city, st, streetsToFill); + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + } + } + + @Override + public LatLon findStreetIntersection(Street street, Street street2) { + City city = street.getCity(); + if(city != null){ + preloadStreets(city); + try { + return file.findStreetIntersection(city, street, street2); + } catch (IOException e) { + log.error("Disk operation failed" , e); //$NON-NLS-1$ + } + } + 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); + name = name.toLowerCase(); + preloadStreets(o); + Collection streets = post == null ? city.getStreets() : post.getStreets(); + for (Street s : streets) { + String sName = useEnglishNames ? s.getEnName() : s.getName(); //lower case not needed, collator ensures that + if (collator.equals(sName,name)) { + return s; + } + } + return null; + } + + + + @Override + public void setUseEnglishNames(boolean useEnglishNames) { + this.useEnglishNames = 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(); + + } + + + +}