Write poi data

This commit is contained in:
Victor Shcherb 2011-09-22 01:06:09 +02:00
parent bbcf0e344c
commit bfdf307975
6 changed files with 1492 additions and 164 deletions

View file

@ -1,10 +1,10 @@
<!-- build JAR libraty -->
<project name="OsmPDB" default="build" basedir=".">
<target name="build" >
<exec dir="." executable="protoc">
<arg value="src/osmand_odb.proto"/>
<arg value="--java_out=./src/"/>
</exec>
<target name="build">
<exec dir="." executable="/usr/bin/protoc">
<arg value="src/osmand_odb.proto" />
<arg value="--java_out=./src/" />
</exec>
</target>
</project>

View file

@ -1,5 +1,7 @@
package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
@ -15,6 +17,7 @@ import net.osmand.Algoritms;
import net.osmand.binary.OsmandOdb.CityIndex;
import net.osmand.binary.OsmandOdb.InteresectedStreets;
import net.osmand.binary.OsmandOdb.MapEncodingRule;
import net.osmand.binary.OsmandOdb.OsmAndPoiBoxDataAtom;
import net.osmand.binary.OsmandOdb.OsmAndTransportIndex;
import net.osmand.binary.OsmandOdb.PostcodeIndex;
import net.osmand.binary.OsmandOdb.StreetIndex;
@ -37,6 +40,7 @@ import net.sf.junidecode.Junidecode;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.WireFormat;
import com.google.protobuf.WireFormat.FieldType;
import com.sun.org.apache.bcel.internal.generic.ALOAD;
public class BinaryMapIndexWriter {
@ -85,6 +89,7 @@ public class BinaryMapIndexWriter {
private final static int POI_INDEX_INIT = 12;
private final static int POI_BOX = 13;
private final static int POI_DATA = 14;
public BinaryMapIndexWriter(final RandomAccessFile raf) throws IOException{
this.raf = raf;
@ -114,10 +119,12 @@ public class BinaryMapIndexWriter {
}
private void preserveInt32Size() throws IOException {
private long preserveInt32Size() throws IOException {
codedOutStream.flush();
stackSizes.push(raf.getFilePointer());
long filePointer = raf.getFilePointer();
stackSizes.push(filePointer);
codedOutStream.writeFixed32NoTag(0);
return filePointer + 4;
}
private int writeInt32Size() throws IOException{
@ -737,14 +744,22 @@ public class BinaryMapIndexWriter {
codedOutStream.writeMessage(OsmAndTransportIndex.STRINGTABLE_FIELD_NUMBER, st.build());
}
public void startWritePOIIndex(String name) throws IOException {
public long startWritePOIIndex(String name) throws IOException {
pushState(POI_INDEX_INIT, OSMAND_STRUCTURE_INIT);
codedOutStream.writeTag(OsmandOdb.OsmAndStructure.POIINDEX_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
stackBounds.push(new Bounds(0, 0, 0, 0)); // for poi index tree
preserveInt32Size();
long startPoiIndex = preserveInt32Size();
if(name != null){
codedOutStream.writeString(OsmandOdb.OsmAndTransportIndex.NAME_FIELD_NUMBER, name);
codedOutStream.writeString(OsmandOdb.OsmAndPoiIndex.NAME_FIELD_NUMBER, name);
}
return startPoiIndex;
}
public void endWritePOIIndex() throws IOException {
popState(POI_INDEX_INIT);
int len = writeInt32Size();
stackBounds.pop();
System.out.println("POI INDEX SIZE : " + len);
}
public Map<String, Integer> writePOICategoriesTable(Map<String, Map<String, Integer>> categories)
@ -771,23 +786,95 @@ public class BinaryMapIndexWriter {
return catIndexes;
}
public void writePoiDataAtom(long id, int x24shift, int y24shift, String nameEn, String name, TIntArrayList types, String openingHours,
String site, String phone) throws IOException {
checkPeekState(POI_DATA);
OsmAndPoiBoxDataAtom.Builder builder = OsmandOdb.OsmAndPoiBoxDataAtom.newBuilder();
builder.setDx(x24shift);
builder.setDy(y24shift);
for(int i=0; i < types.size(); i++){
int j = types.get(i);
builder.addCategories(j);
}
if(!Algoritms.isEmpty(name)){
builder.setName(name);
}
if(!Algoritms.isEmpty(nameEn)){
builder.setNameEn(nameEn);
}
builder.setId(id);
if(!Algoritms.isEmpty(openingHours)){
builder.setOpeningHours(openingHours);
}
if(!Algoritms.isEmpty(site)){
builder.setSite(site);
}
if(!Algoritms.isEmpty(phone)){
builder.setPhone(phone);
}
codedOutStream.writeMessage(OsmandOdb.OsmAndPoiBoxData.POIDATA_FIELD_NUMBER, builder.build());
}
public void startWritePoiBox(int zoom) throws IOException {
pushState(POI_BOX, POI_INDEX_INIT);
codedOutStream.writeTag(OsmandOdb.OsmAndTransportIndex.ROUTES_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
public void startWritePoiData(int zoom, int x, int y, long fpPoiIndex, long fpPoiBox) throws IOException {
pushState(POI_DATA, POI_INDEX_INIT);
codedOutStream.writeTag(OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
long startPoiData = preserveInt32Size();
// write shift to that data
long filePointer = raf.getFilePointer();
raf.seek(fpPoiBox);
raf.writeInt((int) (startPoiData - fpPoiIndex));
raf.seek(filePointer);
codedOutStream.writeUInt32(OsmandOdb.OsmAndPoiBoxData.ZOOM_FIELD_NUMBER, zoom);
codedOutStream.writeUInt32(OsmandOdb.OsmAndPoiBoxData.X_FIELD_NUMBER, x);
codedOutStream.writeUInt32(OsmandOdb.OsmAndPoiBoxData.Y_FIELD_NUMBER, y);
}
public void endWritePoiData() throws IOException {
popState(POI_DATA);
writeInt32Size();
}
public long startWritePoiBox(int zoom, int tileX, int tileY) throws IOException {
checkPeekState(POI_INDEX_INIT, POI_BOX);
if(state.peek() == POI_INDEX_INIT){
codedOutStream.writeTag(OsmandOdb.OsmAndPoiIndex.BOXES_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
} else {
codedOutStream.writeTag(OsmandOdb.OsmAndPoiBox.SUBBOXES_FIELD_NUMBER, WireFormat.WIRETYPE_FIXED32_LENGTH_DELIMITED);
}
state.push(POI_BOX);
preserveInt32Size();
Bounds bounds = stackBounds.peek();
int parentZoom = bounds.rightX;
int parentTileX = bounds.leftX;
int parentTileY = bounds.topY;
int pTileX = parentTileX << (zoom - parentZoom);
int pTileY = parentTileY << (zoom - parentZoom);
codedOutStream.writeSInt32(OsmandOdb.OsmAndPoiBox.LEFT_FIELD_NUMBER, tileX - pTileX);
codedOutStream.writeSInt32(OsmandOdb.OsmAndPoiBox.TOP_FIELD_NUMBER, tileY - pTileY);
codedOutStream.writeUInt32(OsmandOdb.OsmAndPoiBox.ZOOM_FIELD_NUMBER, (zoom - parentZoom));
stackBounds.push(new Bounds(tileX, zoom, tileY, 0 ));
codedOutStream.writeFixed32(OsmandOdb.OsmAndPoiBox.SHIFTTODATA_FIELD_NUMBER, 0);
codedOutStream.flush();
long filePointer = raf.getFilePointer() - 4;
return filePointer;
}
public void endWritePoiBox() throws IOException {
popState(POI_BOX);
writeInt32Size();
}
public void endWritePOIIndex() throws IOException {
popState(POI_INDEX_INIT);
int len = writeInt32Size();
stackBounds.pop();
System.out.println("POI INDEX SIZE : " + len);
}
@ -827,4 +914,5 @@ public class BinaryMapIndexWriter {
}

File diff suppressed because it is too large Load diff

View file

@ -542,7 +542,8 @@ public class IndexCreator {
if (indexPOI) {
progress.setGeneralProgress("[95 of 100]");
progress.startTask("Writing poi index to binary file...", -1);
indexPoiCreator.writeBinaryPoiIndex(writer, regionName, progress);
// TODO uncomment
// indexPoiCreator.writeBinaryPoiIndex(writer, regionName, progress);
}
if (indexTransport) {

View file

@ -1,5 +1,7 @@
package net.osmand.data.preparation;
import gnu.trove.list.array.TIntArrayList;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -15,8 +17,6 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import net.osmand.Algoritms;
import net.osmand.IProgress;
@ -33,21 +33,22 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class IndexPoiCreator extends AbstractIndexPartCreator {
private static final Log log = LogFactory.getLog(IndexPoiCreator.class);
private Connection poiConnection;
private File poiIndexFile;
private PreparedStatement poiPreparedStatement;
private static final int ZOOM_TO_SAVE_END = 14;
private static final int ZOOM_TO_SAVE_END = 15;
private static final int ZOOM_TO_SAVE_START = 6;
private static final int SHIFT_BYTES_CATEGORY = 7;
private List<Amenity> tempAmenityList = new ArrayList<Amenity>();
public IndexPoiCreator(){
public IndexPoiCreator() {
}
public void iterateEntity(Entity e, OsmDbAccessorContext ctx) throws SQLException{
public void iterateEntity(Entity e, OsmDbAccessorContext ctx) throws SQLException {
tempAmenityList.clear();
tempAmenityList = Amenity.parseAmenities(e, tempAmenityList);
if (!tempAmenityList.isEmpty() && poiPreparedStatement != null) {
@ -66,7 +67,7 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
}
}
}
public void commitAndClosePoiFile(Long lastModifiedDate) throws SQLException {
closeAllPreparedStatements();
if (poiConnection != null) {
@ -78,10 +79,10 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
}
}
}
private void checkEntity(Entity e){
private void checkEntity(Entity e) {
String name = e.getTag(OSMTagKey.NAME);
if (name == null){
if (name == null) {
String msg = "";
Collection<String> keys = e.getTagKeySet();
int cnt = 0;
@ -101,10 +102,10 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
}
}
}
private void insertAmenityIntoPoi(Amenity amenity) throws SQLException {
assert IndexConstants.POI_TABLE != null : "use constants here to show table usage "; //$NON-NLS-1$
poiPreparedStatement.setLong(1, amenity.getId());
poiPreparedStatement.setInt(2, MapUtils.get31TileNumberX(amenity.getLocation().getLongitude()));
poiPreparedStatement.setInt(3, MapUtils.get31TileNumberY(amenity.getLocation().getLatitude()));
@ -117,7 +118,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
poiPreparedStatement.setString(10, amenity.getPhone());
addBatch(poiPreparedStatement);
}
public void createDatabaseStructure(File poiIndexFile) throws SQLException {
this.poiIndexFile = poiIndexFile;
@ -128,31 +128,57 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
poiIndexFile.getParentFile().mkdirs();
// creating connection
poiConnection = (Connection) DBDialect.SQLITE.getDatabaseConnection(poiIndexFile.getAbsolutePath(), log);
// create database structure
Statement stat = poiConnection.createStatement();
stat.executeUpdate("create table " + IndexConstants.POI_TABLE + //$NON-NLS-1$
"(id bigint, x int, y int, name_en varchar(1024), name varchar(1024), " +
"type varchar(1024), subtype varchar(1024), opening_hours varchar(1024), phone varchar(1024), site varchar(1024)," +
"primary key(id, type, subtype))");
stat.executeUpdate("create index poi_loc on poi (x, y, type, subtype)");
stat.executeUpdate("create index poi_id on poi (id, type, subtype)");
stat.execute("PRAGMA user_version = " + IndexConstants.POI_TABLE_VERSION); //$NON-NLS-1$
stat.close();
// create prepared statment
stat.executeUpdate("create table " + IndexConstants.POI_TABLE + //$NON-NLS-1$
"(id bigint, x int, y int, name_en varchar(1024), name varchar(1024), "
+ "type varchar(1024), subtype varchar(1024), opening_hours varchar(1024), phone varchar(1024), site varchar(1024),"
+ "primary key(id, type, subtype))");
stat.executeUpdate("create index poi_loc on poi (x, y, type, subtype)");
stat.executeUpdate("create index poi_id on poi (id, type, subtype)");
stat.execute("PRAGMA user_version = " + IndexConstants.POI_TABLE_VERSION); //$NON-NLS-1$
stat.close();
// create prepared statment
poiPreparedStatement = poiConnection
.prepareStatement("INSERT INTO " + IndexConstants.POI_TABLE + "(id, x, y, name_en, name, type, subtype, opening_hours, site, phone) " + //$NON-NLS-1$//$NON-NLS-2$
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
pStatements.put(poiPreparedStatement, 0);
poiConnection.setAutoCommit(false);
}
private void buildTypeIds(String category, String subcategory, Map<String, Map<String, Integer>> categories,
Map<String, Integer> catIndexes, TIntArrayList types) {
types.clear();
Map<String, Integer> map = categories.get(category);
if (map == null) {
throw new IllegalArgumentException("Unknown category " + category);
}
int catInd = catIndexes.get(category);
if (subcategory.contains(";") || subcategory.contains(",")) {
String[] split = subcategory.split(",|;");
for (String sub : split) {
sub = sub.trim();
Integer subcatInd = map.get(sub);
if (subcatInd == null) {
throw new IllegalArgumentException("Unknown subcategory " + sub + " category " + category);
}
types.add((subcatInd << SHIFT_BYTES_CATEGORY) | catInd);
}
} else {
subcategory = subcategory.trim();
Integer subcatInd = map.get(subcategory);
if (subcatInd == null) {
throw new IllegalArgumentException("Unknown subcategory " + subcategory + " category " + category);
}
types.add((subcatInd << SHIFT_BYTES_CATEGORY) | catInd);
}
}
public void writeBinaryPoiIndex(BinaryMapIndexWriter writer, String regionName, IProgress progress) throws SQLException, IOException {
if(poiPreparedStatement != null){
if (poiPreparedStatement != null) {
closePreparedStatements(poiPreparedStatement);
}
poiConnection.commit();
@ -177,61 +203,204 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
Statement stat = rs.getStatement();
rs.close();
stat.close();
// 1. write header
writer.startWritePOIIndex(regionName);
long startFpPoiIndex = writer.startWritePOIIndex(regionName);
// 2. write categories table
Map<String, Integer> catIndexes = writer.writePOICategoriesTable(categories);
// 3. write boxes
String selectZm = (31 - ZOOM_TO_SAVE_END) +"";
rs = poiConnection.createStatement().executeQuery("SELECT DISTINCT x>>"+selectZm +", y>>"+selectZm + " from poi");
Set<Long>[] zooms = new Set[ZOOM_TO_SAVE_END + 1];
String selectZm = (31 - ZOOM_TO_SAVE_END) + "";
rs = poiConnection.createStatement().executeQuery("SELECT DISTINCT x>>" + selectZm + ", y>>" + selectZm + " from poi");
Tree<Long> rootZoomsTree = new Tree<Long>();
int zoomToStart = ZOOM_TO_SAVE_START;
for(int i=zoomToStart; i<=ZOOM_TO_SAVE_END; i++){
zooms[i] = new TreeSet<Long>();
}
while(rs.next()){
while (rs.next()) {
int x = rs.getInt(1);
int y = rs.getInt(2);
for(int i=zoomToStart; i<=ZOOM_TO_SAVE_END; i++){
Tree<Long> prevTree = rootZoomsTree;
for (int i = zoomToStart; i <= ZOOM_TO_SAVE_END; i++) {
int shift = ZOOM_TO_SAVE_END - i;
long l = (((long)x >> shift) << 31) | ((long)y >> shift);
zooms[i].add(l);
long l = (((long) x >> shift) << 31) | ((long) y >> shift);
Tree<Long> subtree = prevTree.getSubtreeByNode(l);
if (subtree == null) {
subtree = new Tree<Long>();
subtree.setNode(l);
prevTree.addSubTree(subtree);
}
prevTree = subtree;
}
}
for (int i = zoomToStart; i < ZOOM_TO_SAVE_END; i++) {
if (zooms[i].size() > 4) {
int level = 0;
for (; level < (ZOOM_TO_SAVE_END - zoomToStart); level++) {
int subtrees = rootZoomsTree.getSubTreesOnLevel(level);
if (subtrees > 8) {
level--;
break;
}
zoomToStart = i;
}
for (int i = zoomToStart; i <= ZOOM_TO_SAVE_END; i++) {
System.out.println(i + " " + zooms[i].size());
if (level > 0) {
rootZoomsTree.extractChildrenFromLevel(level);
zoomToStart = zoomToStart + level;
}
// write tree using stack
Map<Long, Long> fpToWriteSeeks = new LinkedHashMap<Long, Long>();
for (Tree<Long> subs : rootZoomsTree.getSubtrees()) {
writePoiBoxes(writer, subs, zoomToStart, fpToWriteSeeks);
}
stat = rs.getStatement();
rs.close();
stat.close();
// 4. write poi data
PreparedStatement prepareStatement = poiConnection
.prepareStatement("SELECT id, x, y, name_en, name, type, subtype, opening_hours, site, phone from poi "
+ "where x >= ? AND x < ? AND y >= ? AND y < ?");
TIntArrayList types = new TIntArrayList();
for (Map.Entry<Long, Long> entry : fpToWriteSeeks.entrySet()) {
long l = entry.getKey();
int z = ZOOM_TO_SAVE_END;
int x = (int) (l >> 31);
int y = (int) (l & ((1 << 31) - 1));
writer.startWritePoiData(z, x, y, startFpPoiIndex, entry.getValue());
prepareStatement.setInt(1, x << (31 - z));
prepareStatement.setInt(2, (x + 1) << (31 - z));
prepareStatement.setInt(3, y << (31 - z));
prepareStatement.setInt(4, (y + 1) << (31 - z));
rs = prepareStatement.executeQuery();
while (rs.next()) {
long id = rs.getLong(1);
int x31 = rs.getInt(2);
int y31 = rs.getInt(3);
int x24shift = (x31 >> 7) - (x << (24 - z));
int y24shift = (y31 >> 7) - (y << (24 - z));
String nameEn = rs.getString(4);
String name = rs.getString(5);
String type = rs.getString(6);
String subtype = rs.getString(7);
buildTypeIds(type, subtype, categories, catIndexes, types);
String openingHours = rs.getString(8);
String site = rs.getString(9);
String phone = rs.getString(10);
writer.writePoiDataAtom(id, x24shift, y24shift, nameEn, name, types, openingHours, site, phone);
}
writer.endWritePoiData();
rs.close();
}
prepareStatement.close();
writer.endWritePOIIndex();
}
private void writePoiBoxes(BinaryMapIndexWriter writer, Tree<Long> tree, int zoom, Map<Long, Long> fpToWriteSeeks) throws IOException {
long l = tree.getNode();
int x = (int) (l >> 31);
int y = (int) (l & ((1 << 31) - 1));
long fp = writer.startWritePoiBox(zoom, x, y);
if (zoom < ZOOM_TO_SAVE_END) {
for (Tree<Long> subTree : tree.getSubtrees()) {
writePoiBoxes(writer, subTree, zoom + 1, fpToWriteSeeks);
}
} else {
fpToWriteSeeks.put(l, fp);
}
writer.endWritePoiBox();
}
private static class Tree<T> {
private T node;
private List<Tree<T>> subtrees = null;
public List<Tree<T>> getSubtrees() {
if (subtrees == null) {
subtrees = new ArrayList<Tree<T>>();
}
return subtrees;
}
public void addSubTree(Tree<T> t) {
getSubtrees().add(t);
}
public T getNode() {
return node;
}
public void setNode(T node) {
this.node = node;
}
public void extractChildrenFromLevel(int level) {
List<Tree<T>> list = new ArrayList<Tree<T>>();
collectChildrenFromLevel(list, level);
subtrees = list;
}
public void collectChildrenFromLevel(List<Tree<T>> list, int level) {
if (level == 0) {
if (subtrees != null) {
list.addAll(subtrees);
}
} else if (subtrees != null) {
for (Tree<T> sub : subtrees) {
sub.collectChildrenFromLevel(list, level - 1);
}
}
}
public int getSubTreesOnLevel(int level) {
if (level == 0) {
if (subtrees == null) {
return 0;
} else {
return subtrees.size();
}
} else {
int sum = 0;
for (Tree<T> t : subtrees) {
sum += t.getSubTreesOnLevel(level - 1);
}
return sum;
}
}
public Tree<T> getSubtreeByNode(T node) {
if (subtrees == null) {
return null;
}
for (Tree<T> s : subtrees) {
if (node.equals(s.getNode())) {
return s;
}
}
return null;
}
}
public static void main(String[] args) throws SQLException, FileNotFoundException, IOException {
long time = System.currentTimeMillis();
IndexPoiCreator poiCreator = new IndexPoiCreator();
poiCreator.poiConnection = (Connection) DBDialect.SQLITE.getDatabaseConnection("/home/victor/projects/OsmAnd/data/osm-gen/POI/Ru-mow.poi.odb", log);
BinaryMapIndexWriter writer = new BinaryMapIndexWriter(new RandomAccessFile("/home/victor/projects/OsmAnd/data/osm-gen/POI/Test-Ru.poi.obf", "rw"));
poiCreator.poiConnection = (Connection) DBDialect.SQLITE.getDatabaseConnection(
"/home/victor/projects/OsmAnd/data/osm-gen/POI/Ru-mow.poi.odb", log);
BinaryMapIndexWriter writer = new BinaryMapIndexWriter(new RandomAccessFile(
"/home/victor/projects/OsmAnd/data/osm-gen/POI/Test-Ru.poi.obf", "rw"));
poiCreator.poiConnection.setAutoCommit(false);
poiCreator.writeBinaryPoiIndex(writer, "Ru-mow", new ConsoleProgressImplementation());
writer.close();
System.out.println("TIME " + (System.currentTimeMillis() - time));
}
}

View file

@ -28,8 +28,7 @@ message OsmAndStructure {
*/
message StringTable {
repeated string s = 1;
}
}
message OsmAndMapIndex {
// encoded as fixed32 length delimited
@ -271,12 +270,23 @@ message OsmAndPoiIndex {
repeated OsmAndPoiBox boxes = 6; // children
// encoded as fixed32 length delimited
repeated OsmAndPoiBoxData poiData = 7;
repeated OsmAndPoiBoxData poiData = 9;
}
message OsmAndCategoryTable {
message IndexedStringTable {
// common prefix for all strings inside
optional string prefix = 1;
repeated string s = 3;
// subtables are supposed to make search faster
// instead of searching through all strings
// it's enought to read prefix in the header
repeated IndexedStringTable subtables = 6;
}
message OsmAndCategoryTable {
required string category = 1;
repeated string subcategories = 3;
}
@ -289,18 +299,15 @@ message OsmAndPoiBox {
optional OsmAndPoiCategories categories = 4;
optional StringTable includeNamesList = 5;
optional IndexedStringTable includeNamesList = 5;
optional StringTable excludeNamesList = 6;
optional IndexedStringTable excludeNamesList = 6;
// encoded as fixed32 length delimited
repeated OsmAndPoiBox subBoxes = 10;
optional uint32 shiftToData = 14; // shift to OsmAndPoiBoxDataAtom
// TODO
// TransportStop.Message.start - sizeof(TransportStop.Message.length) - routes[i]
// = TransportRoute.Message.start - sizeof(TransportRoute.Message.length)
// message is started when body is started
optional fixed32 shiftToData = 14; // shift to OsmAndPoiBoxData message from OsmAndPoiIndex.start
// message is started when body is started
}
message OsmAndPoiCategories {
@ -309,9 +316,26 @@ message OsmAndPoiCategories {
}
message OsmAndPoiBoxData {
repeated OsmAndPoiBoxDataAtom poiData = 3;
optional uint32 zoom = 1; // zoom level
optional uint32 x = 2; // x tile
optional uint32 y = 3; // y tile
repeated OsmAndPoiBoxDataAtom poiData = 5;
}
message OsmAndPoiBoxDataAtom {
required sint32 dx = 2; // delta encoded to OsmAndPoiBox on 24 zoom
required sint32 dy = 3; // delta encoded to OsmAndPoiBox on 24 zoom
optional uint64 id = 4;
optional string name = 5;
optional string nameEn = 6;
repeated uint32 categories = 7;
optional string openingHours = 10;
optional string site = 11;
optional string phone = 12;
optional string note = 13;
}