Fix binary poi search

This commit is contained in:
Victor Shcherb 2011-09-22 22:12:15 +02:00
parent 2bc344fb82
commit 3b4f0ec85f
3 changed files with 215 additions and 2 deletions

View file

@ -1150,6 +1150,7 @@ public class BinaryMapIndexReader {
System.out.println(poiRegion.categories.get(i));
System.out.println(" " + poiRegion.subcategories.get(i));
}
http://www.openstreetmap.org/?lat=55.81111&lon=37.72368&zoom=16&layers=M
System.out.println("MEMORY " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); //$NON-NLS-1$
System.out.println("Time " + (System.currentTimeMillis() - time)); //$NON-NLS-1$

View file

@ -825,7 +825,7 @@ public class BinaryMapIndexWriter {
// write shift to that data
long filePointer = raf.getFilePointer();
raf.seek(fpPoiBox);
raf.writeInt((int) (startPoiData - fpPoiIndex));
raf.writeInt((int) (startPoiData - fpPoiIndex - 4));
raf.seek(filePointer);
codedOutStream.writeUInt32(OsmandOdb.OsmAndPoiBoxData.ZOOM_FIELD_NUMBER, zoom);

View file

@ -1,18 +1,33 @@
package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TIntHashSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.osmand.Algoritms;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.data.Amenity;
import net.osmand.data.AmenityType;
import net.osmand.osm.MapUtils;
import net.sf.junidecode.Junidecode;
import com.google.protobuf.CodedInputStreamRAF;
import com.google.protobuf.WireFormat;
public class BinaryMapPoiReaderAdapter {
public static final int SHIFT_BITS_CATEGORY = 7;
private static final int CATEGORY_MASK = (1 << SHIFT_BITS_CATEGORY) - 1 ;
public static class PoiRegion extends BinaryIndexPart {
List<String> categories = new ArrayList<String>();
List<AmenityType> categoriesType = new ArrayList<AmenityType>();
List<List<String>> subcategories = new ArrayList<List<String>>();
}
@ -68,7 +83,9 @@ public class BinaryMapPoiReaderAdapter {
case 0:
return;
case OsmandOdb.OsmAndCategoryTable.CATEGORY_FIELD_NUMBER :
region.categories.add(codedIS.readString());
String cat = codedIS.readString();
region.categories.add(cat);
region.categoriesType.add(AmenityType.fromString(cat));
region.subcategories.add(new ArrayList<String>());
break;
case OsmandOdb.OsmAndCategoryTable.SUBCATEGORIES_FIELD_NUMBER :
@ -81,5 +98,200 @@ public class BinaryMapPoiReaderAdapter {
}
}
protected void searchPoiIndex(int left31, int right31, int top31, int bottom31,
SearchRequest<Amenity> req, PoiRegion region) throws IOException {
int indexOffset = codedIS.getTotalBytesRead();
TIntArrayList offsets = new TIntArrayList();
while(true){
if(req.isInterrupted()){
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER :
int length = codedIS.readFixed32();
int oldLimit = codedIS.pushLimit(length);
readBoxField(left31, right31, top31, bottom31, 0, 0, 0, offsets, req);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER :
offsets.sort();
for (int j = 0; j < offsets.size(); j++) {
codedIS.seek(offsets.get(j) + indexOffset);
int len = codedIS.readFixed32();
int oldLim = codedIS.pushLimit(len);
readPoiData(left31, right31, top31, bottom31, req, region);
codedIS.popLimit(oldLim);
if(req.isInterrupted()){
return;
}
}
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return;
default:
skipUnknownField(t);
break;
}
}
}
private void readPoiData(int left31, int right31, int top31, int bottom31,
SearchRequest<Amenity> req, PoiRegion region) throws IOException {
int x = 0;
int y = 0;
int zoom = 0;
while(true){
if(req.isInterrupted()){
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndPoiBoxData.X_FIELD_NUMBER :
x = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndPoiBoxData.ZOOM_FIELD_NUMBER :
zoom = codedIS.readUInt32();
break;
case OsmandOdb.OsmAndPoiBoxData.Y_FIELD_NUMBER :
y= codedIS.readUInt32();
break;
case OsmandOdb.OsmAndPoiBoxData.POIDATA_FIELD_NUMBER:
int len = codedIS.readRawVarint32();
int oldLim = codedIS.pushLimit(len);
readPoiPoint(left31, right31, top31, bottom31, x, y, zoom, req, region);
codedIS.popLimit(oldLim);
return;
default:
skipUnknownField(t);
break;
}
}
}
private void readPoiPoint(int left31, int right31, int top31, int bottom31,
int px, int py, int zoom, SearchRequest<Amenity> req, PoiRegion region) throws IOException {
Amenity am = null;
int x = 0;
int y = 0;
while(true){
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
if(Algoritms.isEmpty(am.getEnName())){
am.setEnName(Junidecode.unidecode(am.getName()));
}
req.getSearchResults().add(am);
return;
case OsmandOdb.OsmAndPoiBoxDataAtom.DX_FIELD_NUMBER :
x = (codedIS.readSInt32() + (px << (24 - zoom))) << 7;
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.DY_FIELD_NUMBER :
y = (codedIS.readSInt32() + (py << (24 - zoom))) << 7;
if(left31 > x || right31 < x || top31 < y || bottom31 > y){
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return;
}
am = new Amenity();
am.setLocation(MapUtils.get31LatitudeY(y), MapUtils.get31LongitudeX(x));
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.CATEGORIES_FIELD_NUMBER :
// TODO add many amenities
int cat = codedIS.readUInt32();
int subcatId = cat >> SHIFT_BITS_CATEGORY;
int catId = cat & CATEGORY_MASK;
if(catId < region.categoriesType.size()){
am.setType(region.categoriesType.get(catId));
List<String> subcats = region.subcategories.get(catId);
if(subcatId < subcats.size()){
am.setSubType(subcats.get(catId));
}
} else {
am.setType(AmenityType.OTHER);
}
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.ID_FIELD_NUMBER :
am.setId(codedIS.readUInt64());
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.NAME_FIELD_NUMBER :
am.setName(codedIS.readString());
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.NAMEEN_FIELD_NUMBER :
am.setEnName(codedIS.readString());
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.OPENINGHOURS_FIELD_NUMBER :
am.setOpeningHours(codedIS.readString());
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.SITE_FIELD_NUMBER :
am.setSite(codedIS.readString());
break;
case OsmandOdb.OsmAndPoiBoxDataAtom.PHONE_FIELD_NUMBER:
am.setPhone(codedIS.readString());
break;
default:
skipUnknownField(t);
break;
}
}
}
private void readBoxField(int left31, int right31, int top31, int bottom31,
int px, int py, int pzoom, TIntArrayList offsets, SearchRequest<Amenity> req) throws IOException {
if(pzoom > 0){
int x1 = px << (31 - pzoom);
int x2 = (px + 1) << (31 - pzoom);
int y1 = py << (31 - pzoom);
int y2 = (py + 1) << (31 - pzoom);
// check intersection
if(!(left31 <= x2 && x1 <= right31 && bottom31 <= y2 && y1 <= top31)){
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
}
}
int zoom = pzoom;
int y = py;
int x = px;
while(true){
if(req.isInterrupted()){
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndPoiBox.ZOOM_FIELD_NUMBER :
zoom = codedIS.readUInt32() + pzoom;
break;
case OsmandOdb.OsmAndPoiBox.LEFT_FIELD_NUMBER :
x = codedIS.readSInt32() + px;
break;
case OsmandOdb.OsmAndPoiBox.TOP_FIELD_NUMBER:
y = codedIS.readSInt32() + py;
break;
case OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER:
int length = codedIS.readFixed32();
int oldLimit = codedIS.pushLimit(length);
readBoxField(left31, right31, top31, bottom31, x, y, zoom, offsets, req);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiBox.SHIFTTODATA_FIELD_NUMBER:
offsets.add(codedIS.readFixed32());
break;
default:
skipUnknownField(t);
break;
}
}
}
}