implement new binary format

git-svn-id: https://osmand.googlecode.com/svn/trunk@593 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-10-27 15:18:28 +00:00
parent 45b8c23ee8
commit e1f4daa59c
8 changed files with 553 additions and 396 deletions

View file

@ -2,13 +2,15 @@ package net.osmand.binary;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
import net.osmand.Algoritms;
import net.osmand.data.index.IndexConstants;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.WireFormat;
import com.google.protobuf.WireFormat.JavaType;
public class BinaryIndexWriter {
@ -31,6 +33,9 @@ public class BinaryIndexWriter {
}
private Stack<Bounds> stackBounds = new Stack<Bounds>();
// needed for map tree
private Stack<Long> stackBaseIds = new Stack<Long>();
private Stack<Map<String, Integer>> stackStringTable = new Stack<Map<String, Integer>>();
// internal constants to track state of index writing
private Stack<Integer> state = new Stack<Integer>();
@ -38,7 +43,6 @@ public class BinaryIndexWriter {
private final static int MAP_INDEX_INIT = 2;
private final static int MAP_ROOT_LEVEL_INIT = 3;
private final static int MAP_TREE = 4;
private final static int MAP_DATA = 5;
public BinaryIndexWriter(OutputStream out) throws IOException{
this.out = out;
@ -62,12 +66,13 @@ public class BinaryIndexWriter {
// /// Simple messages
// message MapData {
// required bytes coordinates = 1; // array of delta x,y uin32 could be read by codedinputstream
// repeated sint32 types = 2;
// required bytes types = 2; // array of fixed int16
//
// required sint64 id = 3; // delta encoded
// optional uint32 stringId = 4;
//
// repeated sint64 restrictions = 5; // delta encoded 3 bytes for type and other for id
// repeated sint64 restrictions = 5; // delta encoded 3 bytes for type and other for id
// optional int32 highwayMeta = 6;
// }
public void startWriteMapIndex() throws IOException{
@ -129,7 +134,8 @@ public class BinaryIndexWriter {
codedOutStream.writeSInt32(OsmandOdb.MapTree.TOP_FIELD_NUMBER, topY - bounds.topY);
codedOutStream.writeSInt32(OsmandOdb.MapTree.BOTTOM_FIELD_NUMBER, bottomY - bounds.bottomY);
stackBounds.push(new Bounds(leftX, rightX, topY, bottomY));
stackBaseIds.push(0L);
stackStringTable.push(null);
}
public void endWriteMapTreeElement() throws IOException{
@ -137,15 +143,93 @@ public class BinaryIndexWriter {
state.pop();
stackBounds.pop();
Long l = stackBaseIds.pop();
if(l != 0){
codedOutStream.writeTag(OsmandOdb.MapTree.BASEID_FIELD_NUMBER, WireFormat.FieldType.UINT64.getWireType());
codedOutStream.writeUInt64NoTag(l);
}
Map<String, Integer> map = stackStringTable.peek();
if(map != null){
codedOutStream.writeTag(OsmandOdb.MapTree.STRINGTABLE_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType());
// TODO write size
codedOutStream.writeFixed32NoTag(0);
int i = 0;
for(String s : map.keySet()){
Integer integer = map.get(s);
if(integer != i){
throw new IllegalStateException();
}
i++;
codedOutStream.writeTag(OsmandOdb.StringTable.S_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType());
codedOutStream.writeStringNoTag(s);
}
}
}
public void writeMapData(long id) throws IOException{
public void writeMapData(long id, byte[] nodes, byte[] types, String name, int highwayAttributes, byte[] restrictions) throws IOException{
assert state.peek() == MAP_TREE;
// TODO
codedOutStream.writeInt64NoTag(id);
codedOutStream.writeTag(OsmandOdb.MapTree.LEAFS_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType());
// TODO write size of map data !!! here
Bounds bounds = stackBounds.peek();
codedOutStream.writeTag(OsmandOdb.MapData.COORDINATES_FIELD_NUMBER, WireFormat.FieldType.BYTES.getWireType());
int size = 0;
for(int i=0; i< nodes.length / 8; i++){
int x = Algoritms.parseIntFromBytes(nodes, i*8) - bounds.leftX;
int y = Algoritms.parseIntFromBytes(nodes, i*8 + 4) - bounds.topY;
size += CodedOutputStream.computeInt32SizeNoTag(x);
size += CodedOutputStream.computeInt32SizeNoTag(y);
}
codedOutStream.writeRawVarint32(size);
for(int i=0; i< nodes.length / 8; i++){
int x = Algoritms.parseIntFromBytes(nodes, i*8) - bounds.leftX;
int y = Algoritms.parseIntFromBytes(nodes, i*8 + 4) - bounds.topY;
codedOutStream.writeInt32NoTag(x);
codedOutStream.writeInt32NoTag(y);
}
codedOutStream.writeTag(OsmandOdb.MapData.TYPES_FIELD_NUMBER, WireFormat.FieldType.BYTES.getWireType());
codedOutStream.writeRawVarint32(types.length);
codedOutStream.writeRawBytes(types);
if(stackBaseIds.peek() == 0){
stackBaseIds.pop();
stackBaseIds.push(id);
}
codedOutStream.writeTag(OsmandOdb.MapData.ID_FIELD_NUMBER, WireFormat.FieldType.SINT64.getWireType());
codedOutStream.writeSInt64NoTag(id - stackBaseIds.peek());
if(name != null){
if(stackStringTable.peek() == null) {
stackStringTable.pop();
stackStringTable.push(new LinkedHashMap<String, Integer>());
}
Map<String, Integer> map = stackStringTable.peek();
int s;
if(map.containsKey(name)) {
s = map.get(name);
} else {
s = map.size();
map.put(name, s);
}
codedOutStream.writeTag(OsmandOdb.MapData.STRINGID_FIELD_NUMBER, WireFormat.FieldType.UINT32.getWireType());
codedOutStream.writeUInt32NoTag(s);
}
if(restrictions.length > 0){
// TODO restrictions delta?
codedOutStream.writeTag(OsmandOdb.MapData.RESTRICTIONS_FIELD_NUMBER, WireFormat.FieldType.BYTES.getWireType());
codedOutStream.writeRawVarint32(restrictions.length);
codedOutStream.writeRawBytes(restrictions);
}
if(highwayAttributes != 0){
codedOutStream.writeTag(OsmandOdb.MapData.HIGHWAYMETA_FIELD_NUMBER, WireFormat.FieldType.UINT32.getWireType());
codedOutStream.writeRawVarint32(highwayAttributes);
}
}
public void close() throws IOException{
assert state.peek() == OSMAND_STRUCTURE_INIT;

View file

@ -2310,17 +2310,12 @@ public final class OsmandOdb {
public boolean hasCoordinates() { return hasCoordinates; }
public com.google.protobuf.ByteString getCoordinates() { return coordinates_; }
// repeated sint32 types = 2;
// required bytes types = 2;
public static final int TYPES_FIELD_NUMBER = 2;
private java.util.List<java.lang.Integer> types_ =
java.util.Collections.emptyList();
public java.util.List<java.lang.Integer> getTypesList() {
return types_;
}
public int getTypesCount() { return types_.size(); }
public int getTypes(int index) {
return types_.get(index);
}
private boolean hasTypes;
private com.google.protobuf.ByteString types_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasTypes() { return hasTypes; }
public com.google.protobuf.ByteString getTypes() { return types_; }
// required sint64 id = 3;
public static final int ID_FIELD_NUMBER = 3;
@ -2348,10 +2343,18 @@ public final class OsmandOdb {
return restrictions_.get(index);
}
// optional int32 highwayMeta = 6;
public static final int HIGHWAYMETA_FIELD_NUMBER = 6;
private boolean hasHighwayMeta;
private int highwayMeta_ = 0;
public boolean hasHighwayMeta() { return hasHighwayMeta; }
public int getHighwayMeta() { return highwayMeta_; }
private void initFields() {
}
public final boolean isInitialized() {
if (!hasCoordinates) return false;
if (!hasTypes) return false;
if (!hasId) return false;
return true;
}
@ -2362,8 +2365,8 @@ public final class OsmandOdb {
if (hasCoordinates()) {
output.writeBytes(1, getCoordinates());
}
for (int element : getTypesList()) {
output.writeSInt32(2, element);
if (hasTypes()) {
output.writeBytes(2, getTypes());
}
if (hasId()) {
output.writeSInt64(3, getId());
@ -2374,6 +2377,9 @@ public final class OsmandOdb {
for (long element : getRestrictionsList()) {
output.writeSInt64(5, element);
}
if (hasHighwayMeta()) {
output.writeInt32(6, getHighwayMeta());
}
getUnknownFields().writeTo(output);
}
@ -2387,14 +2393,9 @@ public final class OsmandOdb {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, getCoordinates());
}
{
int dataSize = 0;
for (int element : getTypesList()) {
dataSize += com.google.protobuf.CodedOutputStream
.computeSInt32SizeNoTag(element);
}
size += dataSize;
size += 1 * getTypesList().size();
if (hasTypes()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(2, getTypes());
}
if (hasId()) {
size += com.google.protobuf.CodedOutputStream
@ -2413,6 +2414,10 @@ public final class OsmandOdb {
size += dataSize;
size += 1 * getRestrictionsList().size();
}
if (hasHighwayMeta()) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(6, getHighwayMeta());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@ -2555,10 +2560,6 @@ public final class OsmandOdb {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
if (result.types_ != java.util.Collections.EMPTY_LIST) {
result.types_ =
java.util.Collections.unmodifiableList(result.types_);
}
if (result.restrictions_ != java.util.Collections.EMPTY_LIST) {
result.restrictions_ =
java.util.Collections.unmodifiableList(result.restrictions_);
@ -2582,11 +2583,8 @@ public final class OsmandOdb {
if (other.hasCoordinates()) {
setCoordinates(other.getCoordinates());
}
if (!other.types_.isEmpty()) {
if (result.types_.isEmpty()) {
result.types_ = new java.util.ArrayList<java.lang.Integer>();
}
result.types_.addAll(other.types_);
if (other.hasTypes()) {
setTypes(other.getTypes());
}
if (other.hasId()) {
setId(other.getId());
@ -2600,6 +2598,9 @@ public final class OsmandOdb {
}
result.restrictions_.addAll(other.restrictions_);
}
if (other.hasHighwayMeta()) {
setHighwayMeta(other.getHighwayMeta());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@ -2629,17 +2630,8 @@ public final class OsmandOdb {
setCoordinates(input.readBytes());
break;
}
case 16: {
addTypes(input.readSInt32());
break;
}
case 18: {
int length = input.readRawVarint32();
int limit = input.pushLimit(length);
while (input.getBytesUntilLimit() > 0) {
addTypes(input.readSInt32());
}
input.popLimit(limit);
setTypes(input.readBytes());
break;
}
case 24: {
@ -2663,6 +2655,10 @@ public final class OsmandOdb {
input.popLimit(limit);
break;
}
case 48: {
setHighwayMeta(input.readInt32());
break;
}
}
}
}
@ -2689,37 +2685,24 @@ public final class OsmandOdb {
return this;
}
// repeated sint32 types = 2;
public java.util.List<java.lang.Integer> getTypesList() {
return java.util.Collections.unmodifiableList(result.types_);
// required bytes types = 2;
public boolean hasTypes() {
return result.hasTypes();
}
public int getTypesCount() {
return result.getTypesCount();
public com.google.protobuf.ByteString getTypes() {
return result.getTypes();
}
public int getTypes(int index) {
return result.getTypes(index);
}
public Builder setTypes(int index, int value) {
result.types_.set(index, value);
return this;
}
public Builder addTypes(int value) {
if (result.types_.isEmpty()) {
result.types_ = new java.util.ArrayList<java.lang.Integer>();
}
result.types_.add(value);
return this;
}
public Builder addAllTypes(
java.lang.Iterable<? extends java.lang.Integer> values) {
if (result.types_.isEmpty()) {
result.types_ = new java.util.ArrayList<java.lang.Integer>();
}
super.addAll(values, result.types_);
public Builder setTypes(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasTypes = true;
result.types_ = value;
return this;
}
public Builder clearTypes() {
result.types_ = java.util.Collections.emptyList();
result.hasTypes = false;
result.types_ = getDefaultInstance().getTypes();
return this;
}
@ -2793,6 +2776,24 @@ public final class OsmandOdb {
return this;
}
// optional int32 highwayMeta = 6;
public boolean hasHighwayMeta() {
return result.hasHighwayMeta();
}
public int getHighwayMeta() {
return result.getHighwayMeta();
}
public Builder setHighwayMeta(int value) {
result.hasHighwayMeta = true;
result.highwayMeta_ = value;
return this;
}
public Builder clearHighwayMeta() {
result.hasHighwayMeta = false;
result.highwayMeta_ = 0;
return this;
}
// @@protoc_insertion_point(builder_scope:MapData)
}
@ -2855,10 +2856,11 @@ public final class OsmandOdb {
"top\030\003 \002(\021\022\016\n\006bottom\030\004 \002(\021\022!\n\013stringTable" +
"\030\005 \001(\0132\014.StringTable\022\016\n\006baseId\030\006 \001(\004\022\032\n\010",
"subtrees\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\"a\n\007M" +
"apData\022\023\n\013coordinates\030\001 \002(\014\022\r\n\005types\030\002 \003" +
"(\021\022\n\n\002id\030\003 \002(\022\022\020\n\010stringId\030\004 \001(\r\022\024\n\014rest" +
"rictions\030\005 \003(\022B\023\n\021net.osmand.binary"
"\010.MapData\"\030\n\013StringTable\022\t\n\001s\030\001 \003(\t\"v\n\007M" +
"apData\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\014rest" +
"rictions\030\005 \003(\022\022\023\n\013highwayMeta\030\006 \001(\005B\023\n\021n" +
"et.osmand.binary"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@ -2910,7 +2912,7 @@ public final class OsmandOdb {
internal_static_MapData_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_MapData_descriptor,
new java.lang.String[] { "Coordinates", "Types", "Id", "StringId", "Restrictions", },
new java.lang.String[] { "Coordinates", "Types", "Id", "StringId", "Restrictions", "HighwayMeta", },
net.osmand.binary.OsmandOdb.MapData.class,
net.osmand.binary.OsmandOdb.MapData.Builder.class);
return null;

View file

@ -1,6 +1,7 @@
package net.osmand.data.index;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@ -190,44 +191,23 @@ public class DataIndexWriter {
public static void createMapIndexStructure(Connection conn) throws SQLException{
Statement stat = conn.createStatement();
stat.execute(IndexConstants.generateCreateSQL(IndexMapRenderObject.values()));
stat.execute(IndexConstants.generateCreateIndexSQL(IndexMapRenderObject.values()));
stat.execute(IndexConstants.generateCreateSQL(IndexBinaryMapRenderObject.values()));
stat.execute(IndexConstants.generateCreateIndexSQL(IndexBinaryMapRenderObject.values()));
stat.execute("CREATE VIRTUAL TABLE "+IndexConstants.indexMapLocationsTable+" USING rtree (id, minLon, maxLon, minLat, maxLat);"); //$NON-NLS-1$ //$NON-NLS-2$
stat.execute("CREATE VIRTUAL TABLE "+IndexConstants.indexMapLocationsTable2+" USING rtree (id, minLon, maxLon, minLat, maxLat);"); //$NON-NLS-1$ //$NON-NLS-2$
stat.execute("CREATE VIRTUAL TABLE "+IndexConstants.indexMapLocationsTable3+" USING rtree (id, minLon, maxLon, minLat, maxLat);"); //$NON-NLS-1$ //$NON-NLS-2$
stat.execute("PRAGMA user_version = " + IndexConstants.MAP_TABLE_VERSION); //$NON-NLS-1$
stat.close();
}
public static PreparedStatement createStatementMapWaysInsert(Connection conn) throws SQLException{
assert IndexMapRenderObject.values().length == 4;
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexMapRenderObject.getTable(), 4));
}
public static PreparedStatement createStatementMapBinaryInsert(Connection conn) throws SQLException{
assert IndexBinaryMapRenderObject.values().length == 5;
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexBinaryMapRenderObject.getTable(), 5));
}
public static PreparedStatement createStatementMapWaysLocationsInsert(Connection conn) throws SQLException{
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexConstants.indexMapLocationsTable, 5));
}
public static PreparedStatement createStatementMapWaysLocationsInsertLevel2(Connection conn) throws SQLException{
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexConstants.indexMapLocationsTable2, 5));
}
public static PreparedStatement createStatementMapWaysLocationsInsertLevel3(Connection conn) throws SQLException{
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexConstants.indexMapLocationsTable3, 5));
assert IndexBinaryMapRenderObject.values().length == 6;
return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexBinaryMapRenderObject.getTable(), 6));
}
public static void insertMapRenderObjectIndex(Map<PreparedStatement, Integer> statements,
PreparedStatement mapStat, PreparedStatement mapWayLocationsStat,
RTree mapTree, Entity e, String name,
long id, int type, List<Integer> typeUse, List<Long> restrictions, boolean writeRestrictions,
public static void insertBinaryMapRenderObjectIndex(Map<PreparedStatement, Integer> statements,
PreparedStatement mapBinaryStat, RTree mapTree, Entity e, String name,
long id, int type, List<Integer> typeUse, int highwayAttributes, List<Long> restrictions,
boolean inversePath, boolean writeAsPoint, int batchSize) throws SQLException {
assert IndexMapRenderObject.values().length == 4;
assert IndexBinaryMapRenderObject.values().length == 6;
if(e instanceof Relation){
throw new IllegalArgumentException();
}
@ -236,10 +216,6 @@ public class DataIndexWriter {
int maxX = 0;
int minY = Integer.MAX_VALUE;
int maxY = 0;
double minLat = 180;
double maxLat = -180;
double minLon = 360;
double maxLon = -360;
Collection<Node> nodes;
if (e instanceof Way) {
if (writeAsPoint) {
@ -256,68 +232,43 @@ public class DataIndexWriter {
Collections.reverse((List<?>) nodes);
}
byte[] bytes;
int offset = 0;
boolean multiType = (type & 1) == 1;
int len = nodes.size() * 8;
if(multiType){
len += typeUse.size() * 2 + 1;
}
if(writeRestrictions){
len += restrictions.size() * 8 + 1;
}
bytes = new byte[len];
if(multiType){
bytes[offset++] = (byte) typeUse.size();
}
if(writeRestrictions){
bytes[offset++] = (byte) restrictions.size();
}
if(multiType){
for(Integer i : typeUse){
Algoritms.putSmallIntBytes(bytes, offset, i);
offset += 2;
}
}
if(writeRestrictions){
for(Long i : restrictions){
Algoritms.putLongToBytes(bytes, offset, i);
offset += 8;
}
}
ByteArrayOutputStream bnodes = new ByteArrayOutputStream();
ByteArrayOutputStream btypes = new ByteArrayOutputStream();
ByteArrayOutputStream brestrictions = new ByteArrayOutputStream();
for (Node n : nodes) {
if (n != null) {
int y = MapUtils.get31TileNumberY(n.getLatitude());
int x = MapUtils.get31TileNumberX(n.getLongitude());
minLat = Math.min(minLat, n.getLatitude());
maxLat = Math.max(maxLat, n.getLatitude());
minLon = Math.min(minLon, n.getLongitude());
maxLon = Math.max(maxLon, n.getLongitude());
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
init = true;
Algoritms.putIntToBytes(bytes, offset, y);
offset += 4;
Algoritms.putIntToBytes(bytes, offset, x);
offset += 4;
try {
Algoritms.writeSmallInt(btypes, type);
for (Integer i : typeUse) {
Algoritms.writeSmallInt(btypes, i);
}
for (Long i : restrictions) {
Algoritms.writeLongInt(brestrictions, i);
}
for (Node n : nodes) {
if (n != null) {
int y = MapUtils.get31TileNumberY(n.getLatitude());
int x = MapUtils.get31TileNumberX(n.getLongitude());
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
init = true;
Algoritms.writeInt(bnodes, x);
Algoritms.writeInt(bnodes, y);
}
}
} catch (IOException es) {
throw new IllegalStateException(es);
}
if (init) {
mapStat.setLong(IndexMapRenderObject.ID.ordinal() + 1, id);
mapStat.setInt(IndexMapRenderObject.TYPE.ordinal() + 1, type);
mapStat.setString(IndexMapRenderObject.NAME.ordinal() + 1, name);
mapStat.setBytes(IndexMapRenderObject.NODES.ordinal() + 1, bytes);
addBatch(statements, mapStat);
mapBinaryStat.setLong(IndexBinaryMapRenderObject.ID.ordinal() + 1, id);
mapBinaryStat.setBytes(IndexBinaryMapRenderObject.TYPES.ordinal() + 1, btypes.toByteArray());
mapBinaryStat.setBytes(IndexBinaryMapRenderObject.RESTRICTIONS.ordinal() + 1, brestrictions.toByteArray());
mapBinaryStat.setBytes(IndexBinaryMapRenderObject.NODES.ordinal() + 1, bnodes.toByteArray());
mapBinaryStat.setInt(IndexBinaryMapRenderObject.HIGHWAY.ordinal() + 1, highwayAttributes);
mapBinaryStat.setString(IndexBinaryMapRenderObject.NAME.ordinal() + 1, name);
addBatch(statements, mapBinaryStat);
try {
@ -327,17 +278,6 @@ public class DataIndexWriter {
} catch (IllegalValueException e1) {
throw new IllegalArgumentException(e1);
}
mapWayLocationsStat.setLong(1, id);
mapWayLocationsStat.setFloat(2, (float) minLon);
mapWayLocationsStat.setFloat(3, (float) maxLon);
mapWayLocationsStat.setFloat(4, (float) minLat);
mapWayLocationsStat.setFloat(5, (float) maxLat);
// mapWayLocationsStat.setInt(2, minX);
// mapWayLocationsStat.setInt(3, maxX);
// mapWayLocationsStat.setInt(4, minY);
// mapWayLocationsStat.setInt(5, maxY);
addBatch(statements, mapWayLocationsStat);
}
}
private static void addBatch(Map<PreparedStatement, Integer> count, PreparedStatement p) throws SQLException{

View file

@ -454,7 +454,7 @@ public class IndexConstants {
}
public enum IndexBinaryMapRenderObject implements IndexColumn {
ID("long", true), NAME, TYPES("BLOB"), RESTRICTIONS("BLOB"), NODES("BLOB"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
ID("long", true), NAME, TYPES("BLOB"), RESTRICTIONS("BLOB"), NODES("BLOB"), HIGHWAY("INT"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
boolean index = false;
String type = null;

View file

@ -7,6 +7,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
@ -38,6 +39,7 @@ import net.osmand.data.TransportStop;
import net.osmand.data.City.CityType;
import net.osmand.data.index.DataIndexWriter;
import net.osmand.data.index.IndexConstants;
import net.osmand.data.index.IndexConstants.IndexBinaryMapRenderObject;
import net.osmand.data.index.IndexConstants.IndexBuildingTable;
import net.osmand.data.index.IndexConstants.IndexCityTable;
import net.osmand.data.index.IndexConstants.IndexStreetNodeTable;
@ -147,11 +149,9 @@ public class IndexCreator {
private File mapFile;
private Connection mapConnection;
private PreparedStatement mapObjStat;
private PreparedStatement mapLocsStatLevel0;
private PreparedStatement mapLocsStatLevel1;
private PreparedStatement mapLocsStatLevel2;
private RTree mapTree;
private PreparedStatement mapBinaryStat;
private static final int[] MAP_ZOOMS = new int[]{6, 9, 14, 22};
private RTree[] mapTree = null;
private File binaryMapFile;
@ -982,9 +982,10 @@ public class IndexCreator {
// manipulate what kind of way to load
loadEntityData(e, true);
boolean inverse = "-1".equals(e.getTag(OSMTagKey.ONEWAY));
writeBinaryEntityToMapDatabase(e, e.getId(), inverse, 0);
writeBinaryEntityToMapDatabase(e, e.getId(), false, 1);
writeBinaryEntityToMapDatabase(e, e.getId(), false, 2);
for (int i = 0; i < MAP_ZOOMS.length - 1; i++) {
writeBinaryEntityToMapDatabase(e, e.getId(), i == 0 ? inverse : false, i);
}
}
if (indexAddress) {
@ -1382,10 +1383,8 @@ public class IndexCreator {
return;
}
boolean useRestrictions = false;
restrictionsUse.clear();
if (MapRenderingTypes.isHighwayType(type >> 1)) {
useRestrictions = true;
if (MapRenderingTypes.isHighwayType(type)) {
// try to find restrictions only for max zoom level
if (level == 0 && highwayRestrictions.containsKey(baseId)) {
restrictionsUse.addAll(highwayRestrictions.get(baseId));
@ -1393,22 +1392,12 @@ public class IndexCreator {
}
boolean point = ((type >> 1) & 3) == MapRenderingTypes.POINT_TYPE;
PreparedStatement mapLocations;
boolean point = (type & 3) == MapRenderingTypes.POINT_TYPE;
RTree rtree = null;
int zoom;
long id = baseId << 3;
if (level == 1) {
id |= 2;
mapLocations = mapLocsStatLevel1;
zoom = 12;
} else if (level == 2) {
id |= 4;
zoom = 7;
mapLocations = mapLocsStatLevel2;
} else {
zoom = 18;
mapLocations = mapLocsStatLevel0;
}
long id = (baseId << 3) | ((level & 3) << 1);
rtree = mapTree[level];
zoom = MAP_ZOOMS[MAP_ZOOMS.length - level - 1] - 2;
boolean skip = false;
if (e instanceof Way) {
id |= 1;
@ -1448,166 +1437,45 @@ public class IndexCreator {
}
if (!skip) {
int highwayAttributes = 0;
if(MapRenderingTypes.isHighwayType(type)){
highwayAttributes = MapRenderingTypes.getHighwayAttributes(e);
}
String eName = MapRenderingTypes.getEntityName(e, type);
if (eName == null) {
eName = multiPolygonsNames.get(baseId);
}
DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, mapTree, e, eName, id, type, typeUse,
restrictionsUse, useRestrictions, inverse, point, BATCH_SIZE);
DataIndexWriter.insertBinaryMapRenderObjectIndex(pStatements, mapBinaryStat, rtree, e, eName, id,
type, typeUse, highwayAttributes, restrictionsUse, inverse, point, BATCH_SIZE);
}
}
/*private void writeEntityToMapDatabase(Entity e, long baseId, boolean inverse, int level) throws SQLException {
int type = MapRenderingTypes.encodeEntityWithType(e, level, false, typeUse);
Map<Long, Set<Integer>> multiPolygonsWays;
if(level == 0){
multiPolygonsWays = multiPolygonsWays0;
} else if(level == 1){
multiPolygonsWays = multiPolygonsWays1;
} else if(level == 2){
multiPolygonsWays = multiPolygonsWays2;
} else {
multiPolygonsWays = Collections.emptyMap();
}
boolean hasMulti = e instanceof Way && multiPolygonsWays.containsKey(e.getId());
if(type == 0){
if(hasMulti){
Set<Integer> set = multiPolygonsWays.get(e.getId());
boolean first = true;
for(Integer i : set){
if(first){
type = i << 1;
first = false;
} else {
typeUse.add(i);
}
}
} else {
return;
}
} else if(hasMulti){
Set<Integer> set = multiPolygonsWays.get(e.getId());
for(Integer i : set){
// do not compare direction
int k = i & 0x7fff;
int ks = k | MapRenderingTypes.POLYGON_TYPE;
// turn of polygon type 3 ^ (suppose polygon = multipolygon)
if(ks == ((type >> 1) & 0xffff)){
type = ((type >> 16) << 16) | (i << 1);
} else if(ks == type >> 16){
type = (type & 0xffff) | (i << 16);
} else {
int ind = typeUse.indexOf(ks);
if (ind == -1) {
typeUse.add(i);
} else {
typeUse.set(ind, i);
}
}
}
}
// be sure about last segments
if(!typeUse.isEmpty()){
type |= 1;
}
boolean useRestrictions = false;
restrictionsUse.clear();
if(MapRenderingTypes.isHighwayType(type >> 1)){
useRestrictions = true;
// try to find restrictions only for max zoom level
if(level == 0 && highwayRestrictions.containsKey(baseId)){
restrictionsUse.addAll(highwayRestrictions.get(baseId));
}
}
boolean point = ((type >> 1) & 3) == MapRenderingTypes.POINT_TYPE;
PreparedStatement mapLocations;
int zoom;
long id = baseId << 3;
if (level == 1) {
id |= 2;
mapLocations = mapLocsStatLevel1;
zoom = 12;
} else if (level == 2) {
id |= 4;
zoom = 7;
mapLocations = mapLocsStatLevel2;
} else {
zoom = 18;
mapLocations = mapLocsStatLevel0;
}
boolean skip = false;
if (e instanceof Way) {
id |= 1;
// simplify route
if (level > 0) {
List<Node> nodes = ((Way) e).getNodes();
Way way = new Way(id);
for(String t : e.getTagKeySet()){
way.putTag(t, e.getTag(t));
}
int prevX = 0;
int prevY = 0;
int len = 0;
for (int i = 0; i < nodes.size(); i++) {
// do not simplify last node it could be important node for multipolygon
if (nodes.get(i) != null) {
int r = i < nodes.size() - 1 ? 4 : 0;
int x = (int) (MapUtils.getTileNumberX(zoom, nodes.get(i).getLongitude()) * 256d);
int y = (int) (MapUtils.getTileNumberY(zoom, nodes.get(i).getLatitude()) * 256d);
int dy = Math.abs(y - prevY);
int dx = Math.abs(x - prevX);
if (dx > r || dy > r) {
way.addNode(nodes.get(i));
len += (dx + dy);
prevX = x;
prevY = y;
}
}
}
e = way;
skip = way.getNodes().size() < 2;
if(!hasMulti && len < 8){
skip = true;
}
}
}
if (!skip) {
String eName = MapRenderingTypes.getEntityName(e, type);
if(eName == null ){
eName = multiPolygonsNames.get(baseId);
}
DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, mapTree, e,
eName, id, type, typeUse, restrictionsUse, useRestrictions,
inverse, point, BATCH_SIZE);
}
}
*/
public void writeBinaryData(RTree rtree) throws IOException {
public void writeBinaryData() throws IOException, SQLException {
try {
long rootIndex = rtree.getFileHdr().getRootIndex();
assert IndexConstants.IndexBinaryMapRenderObject.values().length == 6;
PreparedStatement selectData = mapConnection.prepareStatement("SELECT * FROM " + IndexBinaryMapRenderObject.getTable() + " WHERE id = ?");
binaryMapFile = new File(workingDir, getBinaryMapFileName());
FileOutputStream fout = new FileOutputStream(binaryMapFile);
BinaryIndexWriter writer = new BinaryIndexWriter(fout);
writer.startWriteMapIndex();
rtree.Node root = rtree.getReadNode(rootIndex);
Rect rootBounds = calcBounds(root);
writer.startWriteMapLevelIndex(6, 17, rootBounds.getMinX(), rootBounds.getMaxX(), rootBounds.getMinY(), rootBounds.getMaxY());
writeBinaryMapTree(root, rtree, writer);
for (int i = 0; i < MAP_ZOOMS.length - 1; i++) {
RTree rtree = mapTree[i];
long rootIndex = rtree.getFileHdr().getRootIndex();
rtree.Node root = rtree.getReadNode(rootIndex);
Rect rootBounds = calcBounds(root);
writer.startWriteMapLevelIndex(MAP_ZOOMS[MAP_ZOOMS.length - i - 2] + 1,
MAP_ZOOMS[MAP_ZOOMS.length - i - 1], rootBounds.getMinX(),
rootBounds.getMaxX(), rootBounds.getMinY(), rootBounds.getMaxY());
writeBinaryMapTree(root, rtree, writer, selectData);
writer.endWriteMapLevelIndex();
}
writer.endWriteMapLevelIndex();
writer.endWriteMapIndex();
writer.close();
} catch (RTreeException e) {
@ -1615,19 +1483,26 @@ public class IndexCreator {
}
}
public void writeBinaryMapTree(rtree.Node parent, RTree r, BinaryIndexWriter writer) throws IOException, RTreeException {
public void writeBinaryMapTree(rtree.Node parent, RTree r, BinaryIndexWriter writer, PreparedStatement selectData) throws IOException, RTreeException, SQLException {
Element[] e = parent.getAllElements();
for (int i = 0; i < parent.getTotalElements(); i++) {
Rect re = e[i].getRect();
if(e[i].getElementType() == rtree.Node.LEAF_NODE){
// TODO
long ptr = ((LeafElement) e[i]).getPtr();
writer.writeMapData(ptr);
long id = ((LeafElement) e[i]).getPtr();
selectData.setLong(1, id);
ResultSet rs = selectData.executeQuery();
if(rs.next()){
writer.writeMapData(id, rs.getBytes(IndexBinaryMapRenderObject.NODES.ordinal()+ 1),
rs.getBytes(IndexBinaryMapRenderObject.TYPES.ordinal()+ 1), rs.getString(IndexBinaryMapRenderObject.NAME.ordinal()+ 1),
rs.getInt(IndexBinaryMapRenderObject.HIGHWAY.ordinal()+ 1), rs.getBytes(IndexBinaryMapRenderObject.RESTRICTIONS.ordinal()+ 1));
} else {
log.error("Something goes wrong with id = " + id);
}
} else {
long ptr = ((NonLeafElement) e[i]).getPtr();
writer.startMapTreeElement(re.getMinX(), re.getMaxX(), re.getMinY(), re.getMaxY());
rtree.Node ns = r.getReadNode(ptr);
writeBinaryMapTree(ns, r, writer);
writeBinaryMapTree(ns, r, writer, selectData);
writer.endWriteMapTreeElement();
}
}
@ -1776,23 +1651,22 @@ public class IndexCreator {
mapConnection = DriverManager.getConnection("jdbc:sqlite:" + mapFile.getAbsolutePath());
DataIndexWriter.createMapIndexStructure(mapConnection);
mapObjStat = DataIndexWriter.createStatementMapWaysInsert(mapConnection);
mapLocsStatLevel0 = DataIndexWriter.createStatementMapWaysLocationsInsert(mapConnection);
mapLocsStatLevel1 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel2(mapConnection);
mapLocsStatLevel2 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel3(mapConnection);
mapBinaryStat = DataIndexWriter.createStatementMapBinaryInsert(mapConnection);
try {
File file = new File(getRTreeMapIndexNonPackFileName());
if(file.exists()){
file.delete();
}
mapTree = new RTree(getRTreeMapIndexNonPackFileName());
mapTree = new RTree[MAP_ZOOMS.length - 1];
for (int i = 0; i < MAP_ZOOMS.length - 1; i++) {
File file = new File(getRTreeMapIndexNonPackFileName() + i);
if (file.exists()) {
file.delete();
}
mapTree[i] = new RTree(getRTreeMapIndexNonPackFileName() + i);
// very slow
//mapTree[i].getFileHdr().setBufferPolicy(true);
}
} catch (RTreeException e) {
throw new IOException(e);
}
pStatements.put(mapObjStat, 0);
pStatements.put(mapLocsStatLevel0, 0);
pStatements.put(mapLocsStatLevel1, 0);
pStatements.put(mapLocsStatLevel2, 0);
pStatements.put(mapBinaryStat, 0);
mapConnection.setAutoCommit(false);
}
@ -1950,23 +1824,33 @@ public class IndexCreator {
progress.setGeneralProgress("[95 of 100]");
progress.startTask("Serializing map data...", -1);
try {
mapTree.flush();
for (int i = 0; i < MAP_ZOOMS.length-1; i++) {
mapTree[i].flush();
File file = new File(getRTreeMapIndexPackFileName() + i);
if (file.exists()) {
file.delete();
}
new Pack().packTree(mapTree[i], getRTreeMapIndexPackFileName() + i);
mapTree[i].getFileHdr().getFile().close();
file = new File(getRTreeMapIndexNonPackFileName() + i);
file.delete();
mapTree[i] = new RTree(getRTreeMapIndexPackFileName() + i);
}
} catch (RTreeException e) {
log.error("Error flushing", e);
throw new IOException(e);
}
File file = new File(getRTreeMapIndexPackFileName());
if (file.exists()) {
file.delete();
}
new Pack().packTree(mapTree, getRTreeMapIndexPackFileName());
mapTree = null;
// update map connection
mapBinaryStat.executeBatch();
pStatements.remove(mapBinaryStat);
mapConnection.commit();
// TODO !!! create binary output stream in order to close it properly (finally)
writeBinaryData(new RTree(getRTreeMapIndexPackFileName()));
writeBinaryData();
}
} catch (RTreeException e) {
throw new IOException(e);
} finally {
try {
if (pselectNode != null) {
@ -2013,14 +1897,7 @@ public class IndexCreator {
mapFile.setLastModified(lastModifiedDate);
}
}
if(mapTree != null){
try {
mapTree.flush();
} catch (RTreeException e) {
log.error("Error flushing", e);
}
}
if (addressConnection != null) {
addressConnection.commit();
addressConnection.close();
@ -2029,6 +1906,25 @@ public class IndexCreator {
addressIndexFile.setLastModified(lastModifiedDate);
}
}
for (int i = 0; i < mapTree.length; i++) {
if (mapTree[i] != null) {
RandomAccessFile file = mapTree[i].getFileHdr().getFile();
file.close();
}
}
for (int i = 0; i < mapTree.length; i++) {
File f = new File(getRTreeMapIndexNonPackFileName() + i);
if (f.exists()) {
f.delete();
}
f = new File(getRTreeMapIndexPackFileName() + i);
if (f.exists()) {
f.delete();
}
}
dbConn.close();
} catch (SQLException e) {
}

View file

@ -0,0 +1,238 @@
package net.osmand.osm;
import net.osmand.Algoritms;
public class BinaryMapRenderObject {
private String name = null;
private int type;
private byte[] data = null;
private long id;
private float order = -1;
private boolean multitype = false;
private boolean highwayType = false;
public BinaryMapRenderObject(long id){
this.id = id;
}
public void setData(byte[] data) {
this.data = data;
}
public void setName(String name) {
this.name = name;
}
public void setType(int type) {
this.type = type;
multitype = (type & 1) > 0;
highwayType = isHighwayType();
order = -1;
}
public int getWholeType() {
return type;
}
public long getId() {
return id;
}
public boolean isMultitype() {
return multitype;
}
public byte getMultiTypes(){
return multitype ? data[0] : 0;
}
public byte getRestrictions(){
if(!highwayType){
return 0;
}
if(multitype){
return data[1];
}
return data[0];
}
public int getAdditionalType(int k){
return Algoritms.parseSmallIntFromBytes(data, highwayType ? k * 2 + 2 : k * 2 + 1);
}
// do not cut type to 15 bits (16 bits needed for multipolygon)
public int getMainType(){
return (type >> 1);
}
private boolean isHighwayType(){
int pr = type >> 1;
return (pr & 3) == MapRenderingTypes.POLYLINE_TYPE && MapRenderingTypes.getMainObjectType(pr) == MapRenderingTypes.HIGHWAY;
}
public int getSecondType(){
if(isHighwayType()){
return 0;
}
return type >> 16;
}
public byte getRestrictionType(int k){
int offset = multitype ? data[0] * 2 + 2 : 1;
long l = Algoritms.parseLongFromBytes(data, offset);
return (byte) (l & 7);
}
public long getRestriction(int k){
int offset = multitype ? data[0] * 2 + 2 : 1;
long l = Algoritms.parseLongFromBytes(data, offset);
return (l & ~7l) | (id & 7l);
}
public int getPointsLength() {
if (data == null || data.length == 0) {
return 0;
}
return (data.length - getShiftCoordinates()) / 8;
}
public String getName() {
return name;
}
private int getShiftCoordinates(){
int shift = 0;
if(multitype){
shift = data[0] * 2 + 1;
if(highwayType){
shift += data[1] * 8 + 1;
}
} else if(highwayType){
shift = data[0] * 8 + 1;
}
return shift;
}
public int getPoint31YTile(int ind) {
return Algoritms.parseIntFromBytes(data, ind * 8 + getShiftCoordinates());
}
public int getPoint31XTile(int ind) {
return Algoritms.parseIntFromBytes(data, ind * 8 + 4 + getShiftCoordinates());
}
public float getMapOrder(){
if (order == -1) {
order = getOrder(getMainType());
}
return order;
}
public static float getOrder(int wholeType) {
float order = 0;
int t = wholeType & 3;
int oType = MapRenderingTypes.getMainObjectType(wholeType);
int sType = MapRenderingTypes.getObjectSubType(wholeType);
int layer = MapRenderingTypes.getWayLayer(wholeType);
if (t == MapRenderingTypes.MULTY_POLYGON_TYPE || t == MapRenderingTypes.POLYGON_TYPE) {
// 1 - 9
if (oType == MapRenderingTypes.MAN_MADE && sType == MapRenderingTypes.SUBTYPE_BUILDING) {
// draw over lines
if(layer != 1){
order = 64;
} else {
order = 2;
}
} else {
if(layer == 1){
order = 0.5f;
} else if(layer == 2){
// over lines
order = 64;
} else if (oType == MapRenderingTypes.LANDUSE) {
switch (sType) {
case 5:
case 6:
case 15:
case 18:
case 20:
case 23:
order = 1;
break;
case 22:
order = 5;
break;
default:
order = 1f;
break;
}
} else if (oType == MapRenderingTypes.LEISURE) {
switch (sType) {
case 3:
case 10:
case 13:
order = 2;
break;
case 6:
order = 4;
default:
order = 2;
break;
}
} else if (oType == MapRenderingTypes.POWER) {
order = 4;
} else if (oType == MapRenderingTypes.NATURAL) {
if (order == 5) {
// coastline
order = 0.5f;
} else if (order == 21) {
// water
order = 5;
} else {
order = 1;
}
} else if (oType == MapRenderingTypes.WATERWAY) {
// water 5
order = 5;
} else {
order = 1;
}
}
} else if (t == MapRenderingTypes.POLYLINE_TYPE) {
// 10 - 68
if(layer == 1 && oType != MapRenderingTypes.RAILWAY){
// not subway especially
order = 10;
} else if(layer == 2) {
order = 67; // over buildings
} else if (oType == MapRenderingTypes.HIGHWAY) {
order = 32 - sType + 24;
if(sType == MapRenderingTypes.PL_HW_MOTORWAY){
// TODO ? that was done only to have good overlay
// but really it should be motorway_link have -= 10
order -= 2;
}
} else if (oType == MapRenderingTypes.RAILWAY) {
order = 58;
} else if (oType == MapRenderingTypes.AERIALWAY) {
order = 68; // over buildings
} else if (oType == MapRenderingTypes.POWER) {
order = 68; // over buildings
} else if (oType == MapRenderingTypes.ADMINISTRATIVE) {
order = 62;
} else if (oType == MapRenderingTypes.WATERWAY) {
order = 18;
} else {
order = 10;
}
} else {
order = 128;
}
return order;
}
}

View file

@ -29,10 +29,6 @@ public class MapRenderObject {
order = -1;
}
public int getWholeType() {
return type;
}
public long getId() {
return id;
}

View file

@ -382,9 +382,10 @@ public class CachedNodes
int calKey(String fileName,int idx)
{
if(fileName != null)
return (idx + fileName.toLowerCase().hashCode());
else{
if(fileName != null) {
// System.out.println(idx + " " + fileName + " " + ((idx << 5)+ fileName.toLowerCase().hashCode() % 32));
return ((idx << 5)+ fileName.toLowerCase().hashCode() % 32);
} else{
System.out.println("CachedNodes.calKey: fileName null");
return 0;
}