diff --git a/DataExtractionOSM/src/net/osmand/Algoritms.java b/DataExtractionOSM/src/net/osmand/Algoritms.java index 8c5b350a81..aea642ff95 100644 --- a/DataExtractionOSM/src/net/osmand/Algoritms.java +++ b/DataExtractionOSM/src/net/osmand/Algoritms.java @@ -146,6 +146,43 @@ public class Algoritms { bytes[offset + 3] = (byte) (l & 0xff); } + + public static void writeLongInt(OutputStream stream, long l) throws IOException { + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + l >>= 8; + stream.write((int) (l & 0xff)); + } + + public static void writeInt(OutputStream stream, int l) throws IOException { + stream.write(l & 0xff); + l >>= 8; + stream.write(l & 0xff); + l >>= 8; + stream.write(l & 0xff); + l >>= 8; + stream.write(l & 0xff); + } + + + public static void writeSmallInt(OutputStream stream, int l) throws IOException { + stream.write(l & 0xff); + l >>= 8; + stream.write(l & 0xff); + l >>= 8; + } + public static int parseSmallIntFromBytes(byte[] bytes, int offset) { int s = (0xff & bytes[offset + 1]) << 8; s |= (0xff & bytes[offset + 0]); diff --git a/DataExtractionOSM/src/net/osmand/binary/BinaryIndexWriter.java b/DataExtractionOSM/src/net/osmand/binary/BinaryIndexWriter.java new file mode 100644 index 0000000000..c2a6b9cace --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/binary/BinaryIndexWriter.java @@ -0,0 +1,155 @@ +package net.osmand.binary; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Stack; + +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 { + + private final OutputStream out; + private CodedOutputStream codedOutStream; + + private static class Bounds { + public Bounds(int leftX, int rightX, int topY, int bottomY) { + super(); + this.bottomY = bottomY; + this.leftX = leftX; + this.rightX = rightX; + this.topY = topY; + } + int leftX = 0; + int rightX = 0; + int topY = 0; + int bottomY = 0; + + + } + private Stack stackBounds = new Stack(); + + // internal constants to track state of index writing + private Stack state = new Stack(); + private final static int OSMAND_STRUCTURE_INIT = 1; + 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; + codedOutStream = CodedOutputStream.newInstance(out); + codedOutStream.writeInt32(OsmandOdb.OsmAndStructure.VERSION_FIELD_NUMBER, IndexConstants.BINARY_MAP_VERSION); + state.push(OSMAND_STRUCTURE_INIT); + } +// message MapTree { +// required sint32 left = 1; // delta encoded +// required sint32 right = 2; // delta encoded +// required sint32 top = 3; // delta encoded +// required sint32 bottom = 4; // delta encoded +// +// optional StringTable stringTable = 5; +// optional uint64 baseId = 6; +// +// repeated MapTree subtrees = 7; +// repeated MapData leafs = 8; +// +// } +// /// Simple messages +// message MapData { +// required bytes coordinates = 1; // array of delta x,y uin32 could be read by codedinputstream +// repeated sint32 types = 2; +// +// required sint64 id = 3; // delta encoded +// optional uint32 stringId = 4; +// +// repeated sint64 restrictions = 5; // delta encoded 3 bytes for type and other for id +// } + + public void startWriteMapIndex() throws IOException{ + assert state.peek() == OSMAND_STRUCTURE_INIT; + state.push(MAP_INDEX_INIT); + codedOutStream.writeTag(OsmandOdb.OsmAndStructure.MAPINDEX_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType()); + // TODO write size of map index + codedOutStream.writeFixed32NoTag(0); + + } + + public void endWriteMapIndex() throws IOException{ + Integer st = state.pop(); + assert st == MAP_INDEX_INIT; + codedOutStream.writeRawVarint32(0); + } + + public void startWriteMapLevelIndex(int maxZoom, int minZoom, int leftX, int rightX, int topY, int bottomY) throws IOException{ + assert state.peek() == MAP_INDEX_INIT; + state.push(MAP_ROOT_LEVEL_INIT); + + codedOutStream.writeTag(OsmandOdb.OsmAndMapIndex.LEVELS_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType()); + // TODO write size of level map index + codedOutStream.writeFixed32NoTag(0); + + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.MAXZOOM_FIELD_NUMBER, maxZoom); + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.MINZOOM_FIELD_NUMBER, minZoom); + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.LEFT_FIELD_NUMBER, leftX); + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.RIGHT_FIELD_NUMBER, rightX); + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.TOP_FIELD_NUMBER, topY); + codedOutStream.writeInt32(OsmandOdb.MapRootLevel.BOTTOM_FIELD_NUMBER, bottomY); + + stackBounds.push(new Bounds(leftX, rightX, topY, bottomY)); + } + + public void endWriteMapLevelIndex() throws IOException{ + assert state.peek() == MAP_ROOT_LEVEL_INIT; + state.pop(); + + stackBounds.pop(); + codedOutStream.writeRawVarint32(0); + } + + public void startMapTreeElement(int leftX, int rightX, int topY, int bottomY) throws IOException{ + assert state.peek() == MAP_ROOT_LEVEL_INIT || state.peek() == MAP_TREE; + if(state.peek() == MAP_ROOT_LEVEL_INIT){ + codedOutStream.writeTag(OsmandOdb.MapRootLevel.ROOT_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType()); + } else { + codedOutStream.writeTag(OsmandOdb.MapTree.SUBTREES_FIELD_NUMBER, WireFormat.FieldType.MESSAGE.getWireType()); + } + // TODO write size of level map index + codedOutStream.writeFixed32NoTag(0); + state.push(MAP_TREE); + + + Bounds bounds = stackBounds.peek(); + codedOutStream.writeSInt32(OsmandOdb.MapTree.LEFT_FIELD_NUMBER, leftX - bounds.leftX); + codedOutStream.writeSInt32(OsmandOdb.MapTree.RIGHT_FIELD_NUMBER, rightX - bounds.rightX); + 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)); + + } + + public void endWriteMapTreeElement() throws IOException{ + assert state.peek() == MAP_TREE; + state.pop(); + + stackBounds.pop(); + } + + public void writeMapData(long id) throws IOException{ + assert state.peek() == MAP_TREE; + // TODO + codedOutStream.writeInt64NoTag(id); + } + + + + public void close() throws IOException{ + assert state.peek() == OSMAND_STRUCTURE_INIT; + codedOutStream.flush(); + out.close(); + } +} diff --git a/DataExtractionOSM/src/net/osmand/binary/OsmandOdb.java b/DataExtractionOSM/src/net/osmand/binary/OsmandOdb.java new file mode 100644 index 0000000000..9cda991866 --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/binary/OsmandOdb.java @@ -0,0 +1,2928 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: src/osmand_odb.proto + +package net.osmand.binary; + +public final class OsmandOdb { + private OsmandOdb() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public static final class OsmAndStructure extends + com.google.protobuf.GeneratedMessage { + // Use OsmAndStructure.newBuilder() to construct. + private OsmAndStructure() { + initFields(); + } + private OsmAndStructure(boolean noInit) {} + + private static final OsmAndStructure defaultInstance; + public static OsmAndStructure getDefaultInstance() { + return defaultInstance; + } + + public OsmAndStructure getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_OsmAndStructure_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_OsmAndStructure_fieldAccessorTable; + } + + // required uint32 version = 1; + public static final int VERSION_FIELD_NUMBER = 1; + private boolean hasVersion; + private int version_ = 0; + public boolean hasVersion() { return hasVersion; } + public int getVersion() { return version_; } + + // repeated .OsmAndMapIndex mapIndex = 2; + public static final int MAPINDEX_FIELD_NUMBER = 2; + private java.util.List mapIndex_ = + java.util.Collections.emptyList(); + public java.util.List getMapIndexList() { + return mapIndex_; + } + public int getMapIndexCount() { return mapIndex_.size(); } + public net.osmand.binary.OsmandOdb.OsmAndMapIndex getMapIndex(int index) { + return mapIndex_.get(index); + } + + private void initFields() { + } + public final boolean isInitialized() { + if (!hasVersion) return false; + for (net.osmand.binary.OsmandOdb.OsmAndMapIndex element : getMapIndexList()) { + if (!element.isInitialized()) return false; + } + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasVersion()) { + output.writeUInt32(1, getVersion()); + } + for (net.osmand.binary.OsmandOdb.OsmAndMapIndex element : getMapIndexList()) { + output.writeMessage(2, element); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasVersion()) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(1, getVersion()); + } + for (net.osmand.binary.OsmandOdb.OsmAndMapIndex element : getMapIndexList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, element); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndStructure parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.OsmAndStructure prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.OsmAndStructure result; + + // Construct using net.osmand.binary.OsmandOdb.OsmAndStructure.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.OsmAndStructure(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.OsmAndStructure internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.OsmAndStructure(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.OsmAndStructure.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.OsmAndStructure getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.OsmAndStructure.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.OsmAndStructure build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.OsmAndStructure buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.OsmAndStructure buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + if (result.mapIndex_ != java.util.Collections.EMPTY_LIST) { + result.mapIndex_ = + java.util.Collections.unmodifiableList(result.mapIndex_); + } + net.osmand.binary.OsmandOdb.OsmAndStructure returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.OsmAndStructure) { + return mergeFrom((net.osmand.binary.OsmandOdb.OsmAndStructure)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.OsmAndStructure other) { + if (other == net.osmand.binary.OsmandOdb.OsmAndStructure.getDefaultInstance()) return this; + if (other.hasVersion()) { + setVersion(other.getVersion()); + } + if (!other.mapIndex_.isEmpty()) { + if (result.mapIndex_.isEmpty()) { + result.mapIndex_ = new java.util.ArrayList(); + } + result.mapIndex_.addAll(other.mapIndex_); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 8: { + setVersion(input.readUInt32()); + break; + } + case 18: { + net.osmand.binary.OsmandOdb.OsmAndMapIndex.Builder subBuilder = net.osmand.binary.OsmandOdb.OsmAndMapIndex.newBuilder(); + input.readMessage(subBuilder, extensionRegistry); + addMapIndex(subBuilder.buildPartial()); + break; + } + } + } + } + + + // required uint32 version = 1; + public boolean hasVersion() { + return result.hasVersion(); + } + public int getVersion() { + return result.getVersion(); + } + public Builder setVersion(int value) { + result.hasVersion = true; + result.version_ = value; + return this; + } + public Builder clearVersion() { + result.hasVersion = false; + result.version_ = 0; + return this; + } + + // repeated .OsmAndMapIndex mapIndex = 2; + public java.util.List getMapIndexList() { + return java.util.Collections.unmodifiableList(result.mapIndex_); + } + public int getMapIndexCount() { + return result.getMapIndexCount(); + } + public net.osmand.binary.OsmandOdb.OsmAndMapIndex getMapIndex(int index) { + return result.getMapIndex(index); + } + public Builder setMapIndex(int index, net.osmand.binary.OsmandOdb.OsmAndMapIndex value) { + if (value == null) { + throw new NullPointerException(); + } + result.mapIndex_.set(index, value); + return this; + } + public Builder setMapIndex(int index, net.osmand.binary.OsmandOdb.OsmAndMapIndex.Builder builderForValue) { + result.mapIndex_.set(index, builderForValue.build()); + return this; + } + public Builder addMapIndex(net.osmand.binary.OsmandOdb.OsmAndMapIndex value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.mapIndex_.isEmpty()) { + result.mapIndex_ = new java.util.ArrayList(); + } + result.mapIndex_.add(value); + return this; + } + public Builder addMapIndex(net.osmand.binary.OsmandOdb.OsmAndMapIndex.Builder builderForValue) { + if (result.mapIndex_.isEmpty()) { + result.mapIndex_ = new java.util.ArrayList(); + } + result.mapIndex_.add(builderForValue.build()); + return this; + } + public Builder addAllMapIndex( + java.lang.Iterable values) { + if (result.mapIndex_.isEmpty()) { + result.mapIndex_ = new java.util.ArrayList(); + } + super.addAll(values, result.mapIndex_); + return this; + } + public Builder clearMapIndex() { + result.mapIndex_ = java.util.Collections.emptyList(); + return this; + } + + // @@protoc_insertion_point(builder_scope:OsmAndStructure) + } + + static { + defaultInstance = new OsmAndStructure(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAndStructure) + } + + public static final class OsmAndMapIndex extends + com.google.protobuf.GeneratedMessage { + // Use OsmAndMapIndex.newBuilder() to construct. + private OsmAndMapIndex() { + initFields(); + } + private OsmAndMapIndex(boolean noInit) {} + + private static final OsmAndMapIndex defaultInstance; + public static OsmAndMapIndex getDefaultInstance() { + return defaultInstance; + } + + public OsmAndMapIndex getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_OsmAndMapIndex_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_OsmAndMapIndex_fieldAccessorTable; + } + + // repeated .MapRootLevel levels = 1; + public static final int LEVELS_FIELD_NUMBER = 1; + private java.util.List levels_ = + java.util.Collections.emptyList(); + public java.util.List getLevelsList() { + return levels_; + } + public int getLevelsCount() { return levels_.size(); } + public net.osmand.binary.OsmandOdb.MapRootLevel getLevels(int index) { + return levels_.get(index); + } + + private void initFields() { + } + public final boolean isInitialized() { + for (net.osmand.binary.OsmandOdb.MapRootLevel element : getLevelsList()) { + if (!element.isInitialized()) return false; + } + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + for (net.osmand.binary.OsmandOdb.MapRootLevel element : getLevelsList()) { + output.writeMessage(1, element); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + for (net.osmand.binary.OsmandOdb.MapRootLevel element : getLevelsList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, element); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.OsmAndMapIndex parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.OsmAndMapIndex prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.OsmAndMapIndex result; + + // Construct using net.osmand.binary.OsmandOdb.OsmAndMapIndex.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.OsmAndMapIndex(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.OsmAndMapIndex internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.OsmAndMapIndex(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.OsmAndMapIndex.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.OsmAndMapIndex getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.OsmAndMapIndex.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.OsmAndMapIndex build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.OsmAndMapIndex buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.OsmAndMapIndex buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + if (result.levels_ != java.util.Collections.EMPTY_LIST) { + result.levels_ = + java.util.Collections.unmodifiableList(result.levels_); + } + net.osmand.binary.OsmandOdb.OsmAndMapIndex returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.OsmAndMapIndex) { + return mergeFrom((net.osmand.binary.OsmandOdb.OsmAndMapIndex)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.OsmAndMapIndex other) { + if (other == net.osmand.binary.OsmandOdb.OsmAndMapIndex.getDefaultInstance()) return this; + if (!other.levels_.isEmpty()) { + if (result.levels_.isEmpty()) { + result.levels_ = new java.util.ArrayList(); + } + result.levels_.addAll(other.levels_); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 10: { + net.osmand.binary.OsmandOdb.MapRootLevel.Builder subBuilder = net.osmand.binary.OsmandOdb.MapRootLevel.newBuilder(); + input.readMessage(subBuilder, extensionRegistry); + addLevels(subBuilder.buildPartial()); + break; + } + } + } + } + + + // repeated .MapRootLevel levels = 1; + public java.util.List getLevelsList() { + return java.util.Collections.unmodifiableList(result.levels_); + } + public int getLevelsCount() { + return result.getLevelsCount(); + } + public net.osmand.binary.OsmandOdb.MapRootLevel getLevels(int index) { + return result.getLevels(index); + } + public Builder setLevels(int index, net.osmand.binary.OsmandOdb.MapRootLevel value) { + if (value == null) { + throw new NullPointerException(); + } + result.levels_.set(index, value); + return this; + } + public Builder setLevels(int index, net.osmand.binary.OsmandOdb.MapRootLevel.Builder builderForValue) { + result.levels_.set(index, builderForValue.build()); + return this; + } + public Builder addLevels(net.osmand.binary.OsmandOdb.MapRootLevel value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.levels_.isEmpty()) { + result.levels_ = new java.util.ArrayList(); + } + result.levels_.add(value); + return this; + } + public Builder addLevels(net.osmand.binary.OsmandOdb.MapRootLevel.Builder builderForValue) { + if (result.levels_.isEmpty()) { + result.levels_ = new java.util.ArrayList(); + } + result.levels_.add(builderForValue.build()); + return this; + } + public Builder addAllLevels( + java.lang.Iterable values) { + if (result.levels_.isEmpty()) { + result.levels_ = new java.util.ArrayList(); + } + super.addAll(values, result.levels_); + return this; + } + public Builder clearLevels() { + result.levels_ = java.util.Collections.emptyList(); + return this; + } + + // @@protoc_insertion_point(builder_scope:OsmAndMapIndex) + } + + static { + defaultInstance = new OsmAndMapIndex(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:OsmAndMapIndex) + } + + public static final class MapRootLevel extends + com.google.protobuf.GeneratedMessage { + // Use MapRootLevel.newBuilder() to construct. + private MapRootLevel() { + initFields(); + } + private MapRootLevel(boolean noInit) {} + + private static final MapRootLevel defaultInstance; + public static MapRootLevel getDefaultInstance() { + return defaultInstance; + } + + public MapRootLevel getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_MapRootLevel_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_MapRootLevel_fieldAccessorTable; + } + + // required int32 maxZoom = 1; + public static final int MAXZOOM_FIELD_NUMBER = 1; + private boolean hasMaxZoom; + private int maxZoom_ = 0; + public boolean hasMaxZoom() { return hasMaxZoom; } + public int getMaxZoom() { return maxZoom_; } + + // required int32 minZoom = 2; + public static final int MINZOOM_FIELD_NUMBER = 2; + private boolean hasMinZoom; + private int minZoom_ = 0; + public boolean hasMinZoom() { return hasMinZoom; } + public int getMinZoom() { return minZoom_; } + + // required int32 left = 3; + public static final int LEFT_FIELD_NUMBER = 3; + private boolean hasLeft; + private int left_ = 0; + public boolean hasLeft() { return hasLeft; } + public int getLeft() { return left_; } + + // required int32 right = 4; + public static final int RIGHT_FIELD_NUMBER = 4; + private boolean hasRight; + private int right_ = 0; + public boolean hasRight() { return hasRight; } + public int getRight() { return right_; } + + // required int32 top = 5; + public static final int TOP_FIELD_NUMBER = 5; + private boolean hasTop; + private int top_ = 0; + public boolean hasTop() { return hasTop; } + public int getTop() { return top_; } + + // required int32 bottom = 6; + public static final int BOTTOM_FIELD_NUMBER = 6; + private boolean hasBottom; + private int bottom_ = 0; + public boolean hasBottom() { return hasBottom; } + public int getBottom() { return bottom_; } + + // required .MapTree root = 7; + public static final int ROOT_FIELD_NUMBER = 7; + private boolean hasRoot; + private net.osmand.binary.OsmandOdb.MapTree root_; + public boolean hasRoot() { return hasRoot; } + public net.osmand.binary.OsmandOdb.MapTree getRoot() { return root_; } + + private void initFields() { + root_ = net.osmand.binary.OsmandOdb.MapTree.getDefaultInstance(); + } + public final boolean isInitialized() { + if (!hasMaxZoom) return false; + if (!hasMinZoom) return false; + if (!hasLeft) return false; + if (!hasRight) return false; + if (!hasTop) return false; + if (!hasBottom) return false; + if (!hasRoot) return false; + if (!getRoot().isInitialized()) return false; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasMaxZoom()) { + output.writeInt32(1, getMaxZoom()); + } + if (hasMinZoom()) { + output.writeInt32(2, getMinZoom()); + } + if (hasLeft()) { + output.writeInt32(3, getLeft()); + } + if (hasRight()) { + output.writeInt32(4, getRight()); + } + if (hasTop()) { + output.writeInt32(5, getTop()); + } + if (hasBottom()) { + output.writeInt32(6, getBottom()); + } + if (hasRoot()) { + output.writeMessage(7, getRoot()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasMaxZoom()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, getMaxZoom()); + } + if (hasMinZoom()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, getMinZoom()); + } + if (hasLeft()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(3, getLeft()); + } + if (hasRight()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(4, getRight()); + } + if (hasTop()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(5, getTop()); + } + if (hasBottom()) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(6, getBottom()); + } + if (hasRoot()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, getRoot()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapRootLevel parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.MapRootLevel prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.MapRootLevel result; + + // Construct using net.osmand.binary.OsmandOdb.MapRootLevel.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.MapRootLevel(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.MapRootLevel internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.MapRootLevel(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.MapRootLevel.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.MapRootLevel getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.MapRootLevel.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.MapRootLevel build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.MapRootLevel buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.MapRootLevel buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + net.osmand.binary.OsmandOdb.MapRootLevel returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.MapRootLevel) { + return mergeFrom((net.osmand.binary.OsmandOdb.MapRootLevel)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.MapRootLevel other) { + if (other == net.osmand.binary.OsmandOdb.MapRootLevel.getDefaultInstance()) return this; + if (other.hasMaxZoom()) { + setMaxZoom(other.getMaxZoom()); + } + if (other.hasMinZoom()) { + setMinZoom(other.getMinZoom()); + } + if (other.hasLeft()) { + setLeft(other.getLeft()); + } + if (other.hasRight()) { + setRight(other.getRight()); + } + if (other.hasTop()) { + setTop(other.getTop()); + } + if (other.hasBottom()) { + setBottom(other.getBottom()); + } + if (other.hasRoot()) { + mergeRoot(other.getRoot()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 8: { + setMaxZoom(input.readInt32()); + break; + } + case 16: { + setMinZoom(input.readInt32()); + break; + } + case 24: { + setLeft(input.readInt32()); + break; + } + case 32: { + setRight(input.readInt32()); + break; + } + case 40: { + setTop(input.readInt32()); + break; + } + case 48: { + setBottom(input.readInt32()); + break; + } + case 58: { + net.osmand.binary.OsmandOdb.MapTree.Builder subBuilder = net.osmand.binary.OsmandOdb.MapTree.newBuilder(); + if (hasRoot()) { + subBuilder.mergeFrom(getRoot()); + } + input.readMessage(subBuilder, extensionRegistry); + setRoot(subBuilder.buildPartial()); + break; + } + } + } + } + + + // required int32 maxZoom = 1; + public boolean hasMaxZoom() { + return result.hasMaxZoom(); + } + public int getMaxZoom() { + return result.getMaxZoom(); + } + public Builder setMaxZoom(int value) { + result.hasMaxZoom = true; + result.maxZoom_ = value; + return this; + } + public Builder clearMaxZoom() { + result.hasMaxZoom = false; + result.maxZoom_ = 0; + return this; + } + + // required int32 minZoom = 2; + public boolean hasMinZoom() { + return result.hasMinZoom(); + } + public int getMinZoom() { + return result.getMinZoom(); + } + public Builder setMinZoom(int value) { + result.hasMinZoom = true; + result.minZoom_ = value; + return this; + } + public Builder clearMinZoom() { + result.hasMinZoom = false; + result.minZoom_ = 0; + return this; + } + + // required int32 left = 3; + public boolean hasLeft() { + return result.hasLeft(); + } + public int getLeft() { + return result.getLeft(); + } + public Builder setLeft(int value) { + result.hasLeft = true; + result.left_ = value; + return this; + } + public Builder clearLeft() { + result.hasLeft = false; + result.left_ = 0; + return this; + } + + // required int32 right = 4; + public boolean hasRight() { + return result.hasRight(); + } + public int getRight() { + return result.getRight(); + } + public Builder setRight(int value) { + result.hasRight = true; + result.right_ = value; + return this; + } + public Builder clearRight() { + result.hasRight = false; + result.right_ = 0; + return this; + } + + // required int32 top = 5; + public boolean hasTop() { + return result.hasTop(); + } + public int getTop() { + return result.getTop(); + } + public Builder setTop(int value) { + result.hasTop = true; + result.top_ = value; + return this; + } + public Builder clearTop() { + result.hasTop = false; + result.top_ = 0; + return this; + } + + // required int32 bottom = 6; + public boolean hasBottom() { + return result.hasBottom(); + } + public int getBottom() { + return result.getBottom(); + } + public Builder setBottom(int value) { + result.hasBottom = true; + result.bottom_ = value; + return this; + } + public Builder clearBottom() { + result.hasBottom = false; + result.bottom_ = 0; + return this; + } + + // required .MapTree root = 7; + public boolean hasRoot() { + return result.hasRoot(); + } + public net.osmand.binary.OsmandOdb.MapTree getRoot() { + return result.getRoot(); + } + public Builder setRoot(net.osmand.binary.OsmandOdb.MapTree value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasRoot = true; + result.root_ = value; + return this; + } + public Builder setRoot(net.osmand.binary.OsmandOdb.MapTree.Builder builderForValue) { + result.hasRoot = true; + result.root_ = builderForValue.build(); + return this; + } + public Builder mergeRoot(net.osmand.binary.OsmandOdb.MapTree value) { + if (result.hasRoot() && + result.root_ != net.osmand.binary.OsmandOdb.MapTree.getDefaultInstance()) { + result.root_ = + net.osmand.binary.OsmandOdb.MapTree.newBuilder(result.root_).mergeFrom(value).buildPartial(); + } else { + result.root_ = value; + } + result.hasRoot = true; + return this; + } + public Builder clearRoot() { + result.hasRoot = false; + result.root_ = net.osmand.binary.OsmandOdb.MapTree.getDefaultInstance(); + return this; + } + + // @@protoc_insertion_point(builder_scope:MapRootLevel) + } + + static { + defaultInstance = new MapRootLevel(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:MapRootLevel) + } + + public static final class MapTree extends + com.google.protobuf.GeneratedMessage { + // Use MapTree.newBuilder() to construct. + private MapTree() { + initFields(); + } + private MapTree(boolean noInit) {} + + private static final MapTree defaultInstance; + public static MapTree getDefaultInstance() { + return defaultInstance; + } + + public MapTree getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_MapTree_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_MapTree_fieldAccessorTable; + } + + // required sint32 left = 1; + public static final int LEFT_FIELD_NUMBER = 1; + private boolean hasLeft; + private int left_ = 0; + public boolean hasLeft() { return hasLeft; } + public int getLeft() { return left_; } + + // required sint32 right = 2; + public static final int RIGHT_FIELD_NUMBER = 2; + private boolean hasRight; + private int right_ = 0; + public boolean hasRight() { return hasRight; } + public int getRight() { return right_; } + + // required sint32 top = 3; + public static final int TOP_FIELD_NUMBER = 3; + private boolean hasTop; + private int top_ = 0; + public boolean hasTop() { return hasTop; } + public int getTop() { return top_; } + + // required sint32 bottom = 4; + public static final int BOTTOM_FIELD_NUMBER = 4; + private boolean hasBottom; + private int bottom_ = 0; + public boolean hasBottom() { return hasBottom; } + public int getBottom() { return bottom_; } + + // optional .StringTable stringTable = 5; + public static final int STRINGTABLE_FIELD_NUMBER = 5; + private boolean hasStringTable; + private net.osmand.binary.OsmandOdb.StringTable stringTable_; + public boolean hasStringTable() { return hasStringTable; } + public net.osmand.binary.OsmandOdb.StringTable getStringTable() { return stringTable_; } + + // optional uint64 baseId = 6; + public static final int BASEID_FIELD_NUMBER = 6; + private boolean hasBaseId; + private long baseId_ = 0L; + public boolean hasBaseId() { return hasBaseId; } + public long getBaseId() { return baseId_; } + + // repeated .MapTree subtrees = 7; + public static final int SUBTREES_FIELD_NUMBER = 7; + private java.util.List subtrees_ = + java.util.Collections.emptyList(); + public java.util.List getSubtreesList() { + return subtrees_; + } + public int getSubtreesCount() { return subtrees_.size(); } + public net.osmand.binary.OsmandOdb.MapTree getSubtrees(int index) { + return subtrees_.get(index); + } + + // repeated .MapData leafs = 8; + public static final int LEAFS_FIELD_NUMBER = 8; + private java.util.List leafs_ = + java.util.Collections.emptyList(); + public java.util.List getLeafsList() { + return leafs_; + } + public int getLeafsCount() { return leafs_.size(); } + public net.osmand.binary.OsmandOdb.MapData getLeafs(int index) { + return leafs_.get(index); + } + + private void initFields() { + stringTable_ = net.osmand.binary.OsmandOdb.StringTable.getDefaultInstance(); + } + public final boolean isInitialized() { + if (!hasLeft) return false; + if (!hasRight) return false; + if (!hasTop) return false; + if (!hasBottom) return false; + for (net.osmand.binary.OsmandOdb.MapTree element : getSubtreesList()) { + if (!element.isInitialized()) return false; + } + for (net.osmand.binary.OsmandOdb.MapData element : getLeafsList()) { + if (!element.isInitialized()) return false; + } + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasLeft()) { + output.writeSInt32(1, getLeft()); + } + if (hasRight()) { + output.writeSInt32(2, getRight()); + } + if (hasTop()) { + output.writeSInt32(3, getTop()); + } + if (hasBottom()) { + output.writeSInt32(4, getBottom()); + } + if (hasStringTable()) { + output.writeMessage(5, getStringTable()); + } + if (hasBaseId()) { + output.writeUInt64(6, getBaseId()); + } + for (net.osmand.binary.OsmandOdb.MapTree element : getSubtreesList()) { + output.writeMessage(7, element); + } + for (net.osmand.binary.OsmandOdb.MapData element : getLeafsList()) { + output.writeMessage(8, element); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasLeft()) { + size += com.google.protobuf.CodedOutputStream + .computeSInt32Size(1, getLeft()); + } + if (hasRight()) { + size += com.google.protobuf.CodedOutputStream + .computeSInt32Size(2, getRight()); + } + if (hasTop()) { + size += com.google.protobuf.CodedOutputStream + .computeSInt32Size(3, getTop()); + } + if (hasBottom()) { + size += com.google.protobuf.CodedOutputStream + .computeSInt32Size(4, getBottom()); + } + if (hasStringTable()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, getStringTable()); + } + if (hasBaseId()) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(6, getBaseId()); + } + for (net.osmand.binary.OsmandOdb.MapTree element : getSubtreesList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, element); + } + for (net.osmand.binary.OsmandOdb.MapData element : getLeafsList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(8, element); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapTree parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapTree parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.MapTree prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.MapTree result; + + // Construct using net.osmand.binary.OsmandOdb.MapTree.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.MapTree(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.MapTree internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.MapTree(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.MapTree.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.MapTree getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.MapTree.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.MapTree build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.MapTree buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.MapTree buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + if (result.subtrees_ != java.util.Collections.EMPTY_LIST) { + result.subtrees_ = + java.util.Collections.unmodifiableList(result.subtrees_); + } + if (result.leafs_ != java.util.Collections.EMPTY_LIST) { + result.leafs_ = + java.util.Collections.unmodifiableList(result.leafs_); + } + net.osmand.binary.OsmandOdb.MapTree returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.MapTree) { + return mergeFrom((net.osmand.binary.OsmandOdb.MapTree)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.MapTree other) { + if (other == net.osmand.binary.OsmandOdb.MapTree.getDefaultInstance()) return this; + if (other.hasLeft()) { + setLeft(other.getLeft()); + } + if (other.hasRight()) { + setRight(other.getRight()); + } + if (other.hasTop()) { + setTop(other.getTop()); + } + if (other.hasBottom()) { + setBottom(other.getBottom()); + } + if (other.hasStringTable()) { + mergeStringTable(other.getStringTable()); + } + if (other.hasBaseId()) { + setBaseId(other.getBaseId()); + } + if (!other.subtrees_.isEmpty()) { + if (result.subtrees_.isEmpty()) { + result.subtrees_ = new java.util.ArrayList(); + } + result.subtrees_.addAll(other.subtrees_); + } + if (!other.leafs_.isEmpty()) { + if (result.leafs_.isEmpty()) { + result.leafs_ = new java.util.ArrayList(); + } + result.leafs_.addAll(other.leafs_); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 8: { + setLeft(input.readSInt32()); + break; + } + case 16: { + setRight(input.readSInt32()); + break; + } + case 24: { + setTop(input.readSInt32()); + break; + } + case 32: { + setBottom(input.readSInt32()); + break; + } + case 42: { + net.osmand.binary.OsmandOdb.StringTable.Builder subBuilder = net.osmand.binary.OsmandOdb.StringTable.newBuilder(); + if (hasStringTable()) { + subBuilder.mergeFrom(getStringTable()); + } + input.readMessage(subBuilder, extensionRegistry); + setStringTable(subBuilder.buildPartial()); + break; + } + case 48: { + setBaseId(input.readUInt64()); + break; + } + case 58: { + net.osmand.binary.OsmandOdb.MapTree.Builder subBuilder = net.osmand.binary.OsmandOdb.MapTree.newBuilder(); + input.readMessage(subBuilder, extensionRegistry); + addSubtrees(subBuilder.buildPartial()); + break; + } + case 66: { + net.osmand.binary.OsmandOdb.MapData.Builder subBuilder = net.osmand.binary.OsmandOdb.MapData.newBuilder(); + input.readMessage(subBuilder, extensionRegistry); + addLeafs(subBuilder.buildPartial()); + break; + } + } + } + } + + + // required sint32 left = 1; + public boolean hasLeft() { + return result.hasLeft(); + } + public int getLeft() { + return result.getLeft(); + } + public Builder setLeft(int value) { + result.hasLeft = true; + result.left_ = value; + return this; + } + public Builder clearLeft() { + result.hasLeft = false; + result.left_ = 0; + return this; + } + + // required sint32 right = 2; + public boolean hasRight() { + return result.hasRight(); + } + public int getRight() { + return result.getRight(); + } + public Builder setRight(int value) { + result.hasRight = true; + result.right_ = value; + return this; + } + public Builder clearRight() { + result.hasRight = false; + result.right_ = 0; + return this; + } + + // required sint32 top = 3; + public boolean hasTop() { + return result.hasTop(); + } + public int getTop() { + return result.getTop(); + } + public Builder setTop(int value) { + result.hasTop = true; + result.top_ = value; + return this; + } + public Builder clearTop() { + result.hasTop = false; + result.top_ = 0; + return this; + } + + // required sint32 bottom = 4; + public boolean hasBottom() { + return result.hasBottom(); + } + public int getBottom() { + return result.getBottom(); + } + public Builder setBottom(int value) { + result.hasBottom = true; + result.bottom_ = value; + return this; + } + public Builder clearBottom() { + result.hasBottom = false; + result.bottom_ = 0; + return this; + } + + // optional .StringTable stringTable = 5; + public boolean hasStringTable() { + return result.hasStringTable(); + } + public net.osmand.binary.OsmandOdb.StringTable getStringTable() { + return result.getStringTable(); + } + public Builder setStringTable(net.osmand.binary.OsmandOdb.StringTable value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasStringTable = true; + result.stringTable_ = value; + return this; + } + public Builder setStringTable(net.osmand.binary.OsmandOdb.StringTable.Builder builderForValue) { + result.hasStringTable = true; + result.stringTable_ = builderForValue.build(); + return this; + } + public Builder mergeStringTable(net.osmand.binary.OsmandOdb.StringTable value) { + if (result.hasStringTable() && + result.stringTable_ != net.osmand.binary.OsmandOdb.StringTable.getDefaultInstance()) { + result.stringTable_ = + net.osmand.binary.OsmandOdb.StringTable.newBuilder(result.stringTable_).mergeFrom(value).buildPartial(); + } else { + result.stringTable_ = value; + } + result.hasStringTable = true; + return this; + } + public Builder clearStringTable() { + result.hasStringTable = false; + result.stringTable_ = net.osmand.binary.OsmandOdb.StringTable.getDefaultInstance(); + return this; + } + + // optional uint64 baseId = 6; + public boolean hasBaseId() { + return result.hasBaseId(); + } + public long getBaseId() { + return result.getBaseId(); + } + public Builder setBaseId(long value) { + result.hasBaseId = true; + result.baseId_ = value; + return this; + } + public Builder clearBaseId() { + result.hasBaseId = false; + result.baseId_ = 0L; + return this; + } + + // repeated .MapTree subtrees = 7; + public java.util.List getSubtreesList() { + return java.util.Collections.unmodifiableList(result.subtrees_); + } + public int getSubtreesCount() { + return result.getSubtreesCount(); + } + public net.osmand.binary.OsmandOdb.MapTree getSubtrees(int index) { + return result.getSubtrees(index); + } + public Builder setSubtrees(int index, net.osmand.binary.OsmandOdb.MapTree value) { + if (value == null) { + throw new NullPointerException(); + } + result.subtrees_.set(index, value); + return this; + } + public Builder setSubtrees(int index, net.osmand.binary.OsmandOdb.MapTree.Builder builderForValue) { + result.subtrees_.set(index, builderForValue.build()); + return this; + } + public Builder addSubtrees(net.osmand.binary.OsmandOdb.MapTree value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.subtrees_.isEmpty()) { + result.subtrees_ = new java.util.ArrayList(); + } + result.subtrees_.add(value); + return this; + } + public Builder addSubtrees(net.osmand.binary.OsmandOdb.MapTree.Builder builderForValue) { + if (result.subtrees_.isEmpty()) { + result.subtrees_ = new java.util.ArrayList(); + } + result.subtrees_.add(builderForValue.build()); + return this; + } + public Builder addAllSubtrees( + java.lang.Iterable values) { + if (result.subtrees_.isEmpty()) { + result.subtrees_ = new java.util.ArrayList(); + } + super.addAll(values, result.subtrees_); + return this; + } + public Builder clearSubtrees() { + result.subtrees_ = java.util.Collections.emptyList(); + return this; + } + + // repeated .MapData leafs = 8; + public java.util.List getLeafsList() { + return java.util.Collections.unmodifiableList(result.leafs_); + } + public int getLeafsCount() { + return result.getLeafsCount(); + } + public net.osmand.binary.OsmandOdb.MapData getLeafs(int index) { + return result.getLeafs(index); + } + public Builder setLeafs(int index, net.osmand.binary.OsmandOdb.MapData value) { + if (value == null) { + throw new NullPointerException(); + } + result.leafs_.set(index, value); + return this; + } + public Builder setLeafs(int index, net.osmand.binary.OsmandOdb.MapData.Builder builderForValue) { + result.leafs_.set(index, builderForValue.build()); + return this; + } + public Builder addLeafs(net.osmand.binary.OsmandOdb.MapData value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.leafs_.isEmpty()) { + result.leafs_ = new java.util.ArrayList(); + } + result.leafs_.add(value); + return this; + } + public Builder addLeafs(net.osmand.binary.OsmandOdb.MapData.Builder builderForValue) { + if (result.leafs_.isEmpty()) { + result.leafs_ = new java.util.ArrayList(); + } + result.leafs_.add(builderForValue.build()); + return this; + } + public Builder addAllLeafs( + java.lang.Iterable values) { + if (result.leafs_.isEmpty()) { + result.leafs_ = new java.util.ArrayList(); + } + super.addAll(values, result.leafs_); + return this; + } + public Builder clearLeafs() { + result.leafs_ = java.util.Collections.emptyList(); + return this; + } + + // @@protoc_insertion_point(builder_scope:MapTree) + } + + static { + defaultInstance = new MapTree(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:MapTree) + } + + public static final class StringTable extends + com.google.protobuf.GeneratedMessage { + // Use StringTable.newBuilder() to construct. + private StringTable() { + initFields(); + } + private StringTable(boolean noInit) {} + + private static final StringTable defaultInstance; + public static StringTable getDefaultInstance() { + return defaultInstance; + } + + public StringTable getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_StringTable_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_StringTable_fieldAccessorTable; + } + + // repeated string s = 1; + public static final int S_FIELD_NUMBER = 1; + private java.util.List s_ = + java.util.Collections.emptyList(); + public java.util.List getSList() { + return s_; + } + public int getSCount() { return s_.size(); } + public java.lang.String getS(int index) { + return s_.get(index); + } + + private void initFields() { + } + public final boolean isInitialized() { + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + for (java.lang.String element : getSList()) { + output.writeString(1, element); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (java.lang.String element : getSList()) { + dataSize += com.google.protobuf.CodedOutputStream + .computeStringSizeNoTag(element); + } + size += dataSize; + size += 1 * getSList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.StringTable parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.StringTable parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.StringTable prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.StringTable result; + + // Construct using net.osmand.binary.OsmandOdb.StringTable.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.StringTable(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.StringTable internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.StringTable(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.StringTable.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.StringTable getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.StringTable.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.StringTable build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.StringTable buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.StringTable buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + if (result.s_ != java.util.Collections.EMPTY_LIST) { + result.s_ = + java.util.Collections.unmodifiableList(result.s_); + } + net.osmand.binary.OsmandOdb.StringTable returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.StringTable) { + return mergeFrom((net.osmand.binary.OsmandOdb.StringTable)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.StringTable other) { + if (other == net.osmand.binary.OsmandOdb.StringTable.getDefaultInstance()) return this; + if (!other.s_.isEmpty()) { + if (result.s_.isEmpty()) { + result.s_ = new java.util.ArrayList(); + } + result.s_.addAll(other.s_); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 10: { + addS(input.readString()); + break; + } + } + } + } + + + // repeated string s = 1; + public java.util.List getSList() { + return java.util.Collections.unmodifiableList(result.s_); + } + public int getSCount() { + return result.getSCount(); + } + public java.lang.String getS(int index) { + return result.getS(index); + } + public Builder setS(int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.s_.set(index, value); + return this; + } + public Builder addS(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.s_.isEmpty()) { + result.s_ = new java.util.ArrayList(); + } + result.s_.add(value); + return this; + } + public Builder addAllS( + java.lang.Iterable values) { + if (result.s_.isEmpty()) { + result.s_ = new java.util.ArrayList(); + } + super.addAll(values, result.s_); + return this; + } + public Builder clearS() { + result.s_ = java.util.Collections.emptyList(); + return this; + } + + // @@protoc_insertion_point(builder_scope:StringTable) + } + + static { + defaultInstance = new StringTable(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:StringTable) + } + + public static final class MapData extends + com.google.protobuf.GeneratedMessage { + // Use MapData.newBuilder() to construct. + private MapData() { + initFields(); + } + private MapData(boolean noInit) {} + + private static final MapData defaultInstance; + public static MapData getDefaultInstance() { + return defaultInstance; + } + + public MapData getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return net.osmand.binary.OsmandOdb.internal_static_MapData_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return net.osmand.binary.OsmandOdb.internal_static_MapData_fieldAccessorTable; + } + + // required bytes coordinates = 1; + public static final int COORDINATES_FIELD_NUMBER = 1; + private boolean hasCoordinates; + private com.google.protobuf.ByteString coordinates_ = com.google.protobuf.ByteString.EMPTY; + public boolean hasCoordinates() { return hasCoordinates; } + public com.google.protobuf.ByteString getCoordinates() { return coordinates_; } + + // repeated sint32 types = 2; + public static final int TYPES_FIELD_NUMBER = 2; + private java.util.List types_ = + java.util.Collections.emptyList(); + public java.util.List getTypesList() { + return types_; + } + public int getTypesCount() { return types_.size(); } + public int getTypes(int index) { + return types_.get(index); + } + + // required sint64 id = 3; + public static final int ID_FIELD_NUMBER = 3; + private boolean hasId; + private long id_ = 0L; + public boolean hasId() { return hasId; } + public long getId() { return id_; } + + // optional uint32 stringId = 4; + public static final int STRINGID_FIELD_NUMBER = 4; + private boolean hasStringId; + private int stringId_ = 0; + public boolean hasStringId() { return hasStringId; } + public int getStringId() { return stringId_; } + + // repeated sint64 restrictions = 5; + public static final int RESTRICTIONS_FIELD_NUMBER = 5; + private java.util.List restrictions_ = + java.util.Collections.emptyList(); + public java.util.List getRestrictionsList() { + return restrictions_; + } + public int getRestrictionsCount() { return restrictions_.size(); } + public long getRestrictions(int index) { + return restrictions_.get(index); + } + + private void initFields() { + } + public final boolean isInitialized() { + if (!hasCoordinates) return false; + if (!hasId) return false; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasCoordinates()) { + output.writeBytes(1, getCoordinates()); + } + for (int element : getTypesList()) { + output.writeSInt32(2, element); + } + if (hasId()) { + output.writeSInt64(3, getId()); + } + if (hasStringId()) { + output.writeUInt32(4, getStringId()); + } + for (long element : getRestrictionsList()) { + output.writeSInt64(5, element); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasCoordinates()) { + 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 (hasId()) { + size += com.google.protobuf.CodedOutputStream + .computeSInt64Size(3, getId()); + } + if (hasStringId()) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, getStringId()); + } + { + int dataSize = 0; + for (long element : getRestrictionsList()) { + dataSize += com.google.protobuf.CodedOutputStream + .computeSInt64SizeNoTag(element); + } + size += dataSize; + size += 1 * getRestrictionsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapData parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static net.osmand.binary.OsmandOdb.MapData parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(net.osmand.binary.OsmandOdb.MapData prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder { + private net.osmand.binary.OsmandOdb.MapData result; + + // Construct using net.osmand.binary.OsmandOdb.MapData.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new net.osmand.binary.OsmandOdb.MapData(); + return builder; + } + + protected net.osmand.binary.OsmandOdb.MapData internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new net.osmand.binary.OsmandOdb.MapData(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return net.osmand.binary.OsmandOdb.MapData.getDescriptor(); + } + + public net.osmand.binary.OsmandOdb.MapData getDefaultInstanceForType() { + return net.osmand.binary.OsmandOdb.MapData.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public net.osmand.binary.OsmandOdb.MapData build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private net.osmand.binary.OsmandOdb.MapData buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public net.osmand.binary.OsmandOdb.MapData buildPartial() { + if (result == null) { + 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_); + } + net.osmand.binary.OsmandOdb.MapData returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof net.osmand.binary.OsmandOdb.MapData) { + return mergeFrom((net.osmand.binary.OsmandOdb.MapData)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(net.osmand.binary.OsmandOdb.MapData other) { + if (other == net.osmand.binary.OsmandOdb.MapData.getDefaultInstance()) return this; + if (other.hasCoordinates()) { + setCoordinates(other.getCoordinates()); + } + if (!other.types_.isEmpty()) { + if (result.types_.isEmpty()) { + result.types_ = new java.util.ArrayList(); + } + result.types_.addAll(other.types_); + } + if (other.hasId()) { + setId(other.getId()); + } + if (other.hasStringId()) { + setStringId(other.getStringId()); + } + if (!other.restrictions_.isEmpty()) { + if (result.restrictions_.isEmpty()) { + result.restrictions_ = new java.util.ArrayList(); + } + result.restrictions_.addAll(other.restrictions_); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + return this; + } + break; + } + case 10: { + 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); + break; + } + case 24: { + setId(input.readSInt64()); + break; + } + case 32: { + setStringId(input.readUInt32()); + break; + } + case 40: { + addRestrictions(input.readSInt64()); + break; + } + case 42: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + while (input.getBytesUntilLimit() > 0) { + addRestrictions(input.readSInt64()); + } + input.popLimit(limit); + break; + } + } + } + } + + + // required bytes coordinates = 1; + public boolean hasCoordinates() { + return result.hasCoordinates(); + } + public com.google.protobuf.ByteString getCoordinates() { + return result.getCoordinates(); + } + public Builder setCoordinates(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasCoordinates = true; + result.coordinates_ = value; + return this; + } + public Builder clearCoordinates() { + result.hasCoordinates = false; + result.coordinates_ = getDefaultInstance().getCoordinates(); + return this; + } + + // repeated sint32 types = 2; + public java.util.List getTypesList() { + return java.util.Collections.unmodifiableList(result.types_); + } + public int getTypesCount() { + return result.getTypesCount(); + } + 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(); + } + result.types_.add(value); + return this; + } + public Builder addAllTypes( + java.lang.Iterable values) { + if (result.types_.isEmpty()) { + result.types_ = new java.util.ArrayList(); + } + super.addAll(values, result.types_); + return this; + } + public Builder clearTypes() { + result.types_ = java.util.Collections.emptyList(); + return this; + } + + // required sint64 id = 3; + public boolean hasId() { + return result.hasId(); + } + public long getId() { + return result.getId(); + } + public Builder setId(long value) { + result.hasId = true; + result.id_ = value; + return this; + } + public Builder clearId() { + result.hasId = false; + result.id_ = 0L; + return this; + } + + // optional uint32 stringId = 4; + public boolean hasStringId() { + return result.hasStringId(); + } + public int getStringId() { + return result.getStringId(); + } + public Builder setStringId(int value) { + result.hasStringId = true; + result.stringId_ = value; + return this; + } + public Builder clearStringId() { + result.hasStringId = false; + result.stringId_ = 0; + return this; + } + + // repeated sint64 restrictions = 5; + public java.util.List getRestrictionsList() { + return java.util.Collections.unmodifiableList(result.restrictions_); + } + public int getRestrictionsCount() { + return result.getRestrictionsCount(); + } + public long getRestrictions(int index) { + return result.getRestrictions(index); + } + public Builder setRestrictions(int index, long value) { + result.restrictions_.set(index, value); + return this; + } + public Builder addRestrictions(long value) { + if (result.restrictions_.isEmpty()) { + result.restrictions_ = new java.util.ArrayList(); + } + result.restrictions_.add(value); + return this; + } + public Builder addAllRestrictions( + java.lang.Iterable values) { + if (result.restrictions_.isEmpty()) { + result.restrictions_ = new java.util.ArrayList(); + } + super.addAll(values, result.restrictions_); + return this; + } + public Builder clearRestrictions() { + result.restrictions_ = java.util.Collections.emptyList(); + return this; + } + + // @@protoc_insertion_point(builder_scope:MapData) + } + + static { + defaultInstance = new MapData(true); + net.osmand.binary.OsmandOdb.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:MapData) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAndStructure_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAndStructure_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_OsmAndMapIndex_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_OsmAndMapIndex_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_MapRootLevel_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_MapRootLevel_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_MapTree_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_MapTree_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_StringTable_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_StringTable_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_MapData_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_MapData_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\024src/osmand_odb.proto\"E\n\017OsmAndStructur" + + "e\022\017\n\007version\030\001 \002(\r\022!\n\010mapIndex\030\002 \003(\0132\017.O" + + "smAndMapIndex\"/\n\016OsmAndMapIndex\022\035\n\006level" + + "s\030\001 \003(\0132\r.MapRootLevel\"\202\001\n\014MapRootLevel\022" + + "\017\n\007maxZoom\030\001 \002(\005\022\017\n\007minZoom\030\002 \002(\005\022\014\n\004lef" + + "t\030\003 \002(\005\022\r\n\005right\030\004 \002(\005\022\013\n\003top\030\005 \002(\005\022\016\n\006b" + + "ottom\030\006 \002(\005\022\026\n\004root\030\007 \002(\0132\010.MapTree\"\253\001\n\007" + + "MapTree\022\014\n\004left\030\001 \002(\021\022\r\n\005right\030\002 \002(\021\022\013\n\003" + + "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" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_OsmAndStructure_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_OsmAndStructure_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAndStructure_descriptor, + new java.lang.String[] { "Version", "MapIndex", }, + net.osmand.binary.OsmandOdb.OsmAndStructure.class, + net.osmand.binary.OsmandOdb.OsmAndStructure.Builder.class); + internal_static_OsmAndMapIndex_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_OsmAndMapIndex_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_OsmAndMapIndex_descriptor, + new java.lang.String[] { "Levels", }, + net.osmand.binary.OsmandOdb.OsmAndMapIndex.class, + net.osmand.binary.OsmandOdb.OsmAndMapIndex.Builder.class); + internal_static_MapRootLevel_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_MapRootLevel_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_MapRootLevel_descriptor, + new java.lang.String[] { "MaxZoom", "MinZoom", "Left", "Right", "Top", "Bottom", "Root", }, + net.osmand.binary.OsmandOdb.MapRootLevel.class, + net.osmand.binary.OsmandOdb.MapRootLevel.Builder.class); + internal_static_MapTree_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_MapTree_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_MapTree_descriptor, + new java.lang.String[] { "Left", "Right", "Top", "Bottom", "StringTable", "BaseId", "Subtrees", "Leafs", }, + net.osmand.binary.OsmandOdb.MapTree.class, + net.osmand.binary.OsmandOdb.MapTree.Builder.class); + internal_static_StringTable_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_StringTable_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_StringTable_descriptor, + new java.lang.String[] { "S", }, + net.osmand.binary.OsmandOdb.StringTable.class, + net.osmand.binary.OsmandOdb.StringTable.Builder.class); + internal_static_MapData_descriptor = + getDescriptor().getMessageTypes().get(5); + internal_static_MapData_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_MapData_descriptor, + new java.lang.String[] { "Coordinates", "Types", "Id", "StringId", "Restrictions", }, + net.osmand.binary.OsmandOdb.MapData.class, + net.osmand.binary.OsmandOdb.MapData.Builder.class); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + public static void internalForceInit() {} + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/DataExtractionOSM/src/net/osmand/data/index/DataIndexWriter.java b/DataExtractionOSM/src/net/osmand/data/index/DataIndexWriter.java index b44358fcf5..bb46266f68 100644 --- a/DataExtractionOSM/src/net/osmand/data/index/DataIndexWriter.java +++ b/DataExtractionOSM/src/net/osmand/data/index/DataIndexWriter.java @@ -1,5 +1,6 @@ package net.osmand.data.index; +import java.io.ByteArrayOutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -19,6 +20,7 @@ import net.osmand.data.City; import net.osmand.data.TransportRoute; import net.osmand.data.TransportStop; import net.osmand.data.City.CityType; +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.IndexMapRenderObject; @@ -34,6 +36,11 @@ import net.osmand.osm.MapUtils; import net.osmand.osm.Node; import net.osmand.osm.Relation; import net.osmand.osm.Way; +import rtree.IllegalValueException; +import rtree.LeafElement; +import rtree.RTree; +import rtree.RTreeInsertException; +import rtree.Rect; @@ -185,6 +192,8 @@ public class DataIndexWriter { 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$ @@ -196,6 +205,11 @@ public class DataIndexWriter { 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)); } @@ -207,8 +221,10 @@ public class DataIndexWriter { return conn.prepareStatement(IndexConstants.generatePrepareStatementToInsert(IndexConstants.indexMapLocationsTable3, 5)); } + public static void insertMapRenderObjectIndex(Map statements, - PreparedStatement mapStat, PreparedStatement mapWayLocationsStat, /*RTree mapTree, */Entity e, String name, + PreparedStatement mapStat, PreparedStatement mapWayLocationsStat, + RTree mapTree, Entity e, String name, long id, int type, List typeUse, List restrictions, boolean writeRestrictions, boolean inversePath, boolean writeAsPoint, int batchSize) throws SQLException { assert IndexMapRenderObject.values().length == 4; @@ -270,7 +286,9 @@ public class DataIndexWriter { } } - + 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()); @@ -288,25 +306,27 @@ public class DataIndexWriter { offset += 4; Algoritms.putIntToBytes(bytes, offset, x); offset += 4; + + } } 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); + -// -// try { -// mapTree.insert(new LeafElement(new Rect(minX, minY, maxX, maxY), id)); -// } catch (RTreeInsertException e1) { -// // TODO -// e1.printStackTrace(); -// } catch (IllegalValueException e1) { -// // TODO -// e1.printStackTrace(); -// } + try { + mapTree.insert(new LeafElement(new Rect(minX, minY, maxX, maxY), id)); + } catch (RTreeInsertException e1) { + throw new IllegalArgumentException(e1); + } catch (IllegalValueException e1) { + throw new IllegalArgumentException(e1); + } mapWayLocationsStat.setLong(1, id); mapWayLocationsStat.setFloat(2, (float) minLon); diff --git a/DataExtractionOSM/src/net/osmand/data/index/IndexConstants.java b/DataExtractionOSM/src/net/osmand/data/index/IndexConstants.java index 8739ad1862..e062013fa8 100644 --- a/DataExtractionOSM/src/net/osmand/data/index/IndexConstants.java +++ b/DataExtractionOSM/src/net/osmand/data/index/IndexConstants.java @@ -8,6 +8,7 @@ public class IndexConstants { public final static int POI_TABLE_VERSION = 0; public final static int ADDRESS_TABLE_VERSION = 1; public final static int MAP_TABLE_VERSION = 0; + public final static int BINARY_MAP_VERSION = 0; public final static int VOICE_VERSION = 0; @@ -20,6 +21,7 @@ public class IndexConstants { public static final String ADDRESS_INDEX_EXT = ".addr.odb"; //$NON-NLS-1$ public static final String TRANSPORT_INDEX_EXT = ".trans.odb"; //$NON-NLS-1$ public static final String MAP_INDEX_EXT = ".map.odb"; //$NON-NLS-1$ + public static final String BINARY_MAP_INDEX_EXT = ".map.pbf"; //$NON-NLS-1$ public static final String POI_INDEX_EXT_ZIP = ".poi.zip"; //$NON-NLS-1$ public static final String ADDRESS_INDEX_EXT_ZIP = ".addr.zip"; //$NON-NLS-1$ @@ -451,4 +453,41 @@ 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$ + boolean index = false; + String type = null; + + private IndexBinaryMapRenderObject() { + } + + private IndexBinaryMapRenderObject(String type) { + this.type = type; + } + + private IndexBinaryMapRenderObject(String type, boolean index) { + this(type); + this.index = index; + } + + public static String getTable() { + return "binary_map_objects"; //$NON-NLS-1$ + } + + public String getTableName() { + return getTable(); + } + + @Override + public String getType() { + return type; + } + + @Override + public boolean isIndex() { + return index; + } + } + + } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java index 41ae936b70..f6de5d6dce 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexCreator.java @@ -4,6 +4,7 @@ import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; @@ -26,6 +27,7 @@ import java.util.Map.Entry; import net.osmand.Algoritms; import net.osmand.IProgress; +import net.osmand.binary.BinaryIndexWriter; import net.osmand.data.Amenity; import net.osmand.data.Building; import net.osmand.data.City; @@ -64,6 +66,15 @@ import org.apache.commons.logging.LogFactory; import org.apache.tools.bzip2.CBZip2InputStream; import org.xml.sax.SAXException; +import rtree.Element; +import rtree.IllegalValueException; +import rtree.LeafElement; +import rtree.NonLeafElement; +import rtree.Pack; +import rtree.RTree; +import rtree.RTreeException; +import rtree.Rect; + /** * http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing#Is_inside.2Foutside @@ -101,6 +112,7 @@ public class IndexCreator { private String poiFileName = null; private String addressFileName = null; private String mapFileName = null; + private String binaryMapFileName = null; private Long lastModifiedDate = null; @@ -139,7 +151,9 @@ public class IndexCreator { private PreparedStatement mapLocsStatLevel0; private PreparedStatement mapLocsStatLevel1; private PreparedStatement mapLocsStatLevel2; -// private RTree mapTree; + private RTree mapTree; + + private File binaryMapFile; // MEMORY map : save it in memory while that is allowed private Map> multiPolygonsWays0 = new LinkedHashMap>(); @@ -147,8 +161,6 @@ public class IndexCreator { private Map> multiPolygonsWays2 = new LinkedHashMap>(); private Map multiPolygonsNames = new LinkedHashMap(); private Map> highwayRestrictions = new LinkedHashMap>(); - private Map> lowLevelWaysSt = new LinkedHashMap>(); - private Map> lowLevelWaysEnd = new LinkedHashMap>(); // MEMORY address : choose what to use ? @@ -460,6 +472,16 @@ public class IndexCreator { return mapFileName; } + public void setBinaryMapFileName(String mapFileName) { + this.binaryMapFileName = mapFileName; + } + public String getBinaryMapFileName(){ + if(binaryMapFileName == null){ + return getRegionName() + IndexConstants.BINARY_MAP_INDEX_EXT; + } + return binaryMapFileName; + } + public String getTransportFileName() { if(transportFileName == null){ return IndexConstants.TRANSPORT_INDEX_DIR + getRegionName() + IndexConstants.TRANSPORT_INDEX_EXT; @@ -960,11 +982,9 @@ public class IndexCreator { // manipulate what kind of way to load loadEntityData(e, true); boolean inverse = "-1".equals(e.getTag(OSMTagKey.ONEWAY)); - writeEntityToMapDatabase(e, e.getId(), inverse, 0); - writeEntityToMapDatabase(e, e.getId(), false, 1); - writeEntityToMapDatabase(e, e.getId(), false, 2); -// indexLowLevelMap(e, 1); -// indexLowLevelMap(e, 2); + writeBinaryEntityToMapDatabase(e, e.getId(), inverse, 0); + writeBinaryEntityToMapDatabase(e, e.getId(), false, 1); + writeBinaryEntityToMapDatabase(e, e.getId(), false, 2); } if (indexAddress) { @@ -1191,11 +1211,8 @@ public class IndexCreator { int t = MapRenderingTypes.encodeEntityWithType(e, level, true, typeUse); int mtType = 0; if (t != 0) { - if (((t >> 1) & 3) == MapRenderingTypes.MULTY_POLYGON_TYPE) { - // last bit is used for direction - mtType = (t >> 1) & 0x7fff; - } else if (((t >> 16) & 3) == MapRenderingTypes.MULTY_POLYGON_TYPE && (t >> 16) != 0) { - mtType = t >> 16; + if ((t & 3) == MapRenderingTypes.MULTY_POLYGON_TYPE) { + mtType = t; } else { for (Integer i : typeUse) { if ((i & 3) == MapRenderingTypes.MULTY_POLYGON_TYPE) { @@ -1321,128 +1338,129 @@ public class IndexCreator { } - private void putIntoMap(Map> map, T key, R value){ - if(!map.containsKey(key)){ - map.put(key, new ArrayList()); - } - map.get(key).add(value); - } - - private void removeValueMap(Map> map, T key, R value){ - boolean remove = map.get(key).remove(value); - if(!remove){ - throw new IllegalStateException(); - } - if(map.get(key).isEmpty()){ - map.remove(key); - } - } - - // TODO do not use that method - @SuppressWarnings("unused") - private void indexLowLevelMap(Entity e, int level) throws SQLException{ + + private void writeBinaryEntityToMapDatabase(Entity e, long baseId, boolean inverse, int level) throws SQLException { int type = MapRenderingTypes.encodeEntityWithType(e, level, false, typeUse); - // TODO that is not correct because multiPolygonsWays contains types for level 0 - // TODO that method should be redesigned (!!!) to support multipolygon types and multipolygon names -// if(type == 0 && multiPolygonsWays.containsKey(e.getId())){ -// type = multiPolygonsWays.get(e.getId()).iterator().next(); -// } - if(type == 0){ - return; + Map> multiPolygonsWays; + if (level == 0) { + multiPolygonsWays = multiPolygonsWays0; + } else if (level == 1) { + multiPolygonsWays = multiPolygonsWays1; + } else if (level == 2) { + multiPolygonsWays = multiPolygonsWays2; + } else { + multiPolygonsWays = Collections.emptyMap(); } - boolean writeIntoDB = true; - boolean ring = true; - if(e instanceof Way && level > 0){ - List nodes = ((Way) e).getNodes(); - Node n = nodes.get(0); - Node l = nodes.get(nodes.size() - 1); - // ring - ring = l.getId() == n.getId(); - if (!ring) { - writeIntoDB = false; - Way start = null; - if (lowLevelWaysEnd.containsKey(n.getId())) { - for (Way w : lowLevelWaysEnd.get(n.getId())) { - int t = MapRenderingTypes.encodeEntityWithType(w, level, false, typeUse); - if (t == type && Algoritms.objectEquals(MapRenderingTypes.getEntityName(w, t), - MapRenderingTypes.getEntityName(e, t))) { - start = w; - break; - } - } - } - - if (start != null) { - ring = start.getNodeIds().get(0) == l.getId(); - if(ring){ - removeValueMap(lowLevelWaysEnd, n.getId(), start); - removeValueMap(lowLevelWaysSt, l.getId(), start); - } else { - // add nodes to start - for (int i = 1; i < nodes.size(); i++) { - start.addNode(nodes.get(i)); - } - removeValueMap(lowLevelWaysEnd, n.getId(), start); - putIntoMap(lowLevelWaysEnd, l.getId(), start); - } + boolean hasMulti = e instanceof Way && multiPolygonsWays.containsKey(e.getId()); + if (hasMulti) { + Set set = multiPolygonsWays.get(e.getId()); + boolean first = true; + for (Integer i : set) { + if (first && type == 0) { + type = i; + first = false; } else { - long tempId = (e.getId() << 2) | level; - start = new Way(tempId); - for(String t : e.getTagKeySet()){ - start.putTag(t, e.getTag(t)); - } - // add nodes to start - for (int i = 0; i < nodes.size(); i++) { - start.addNode(nodes.get(i)); - } - - putIntoMap(lowLevelWaysSt, n.getId(), start); - putIntoMap(lowLevelWaysEnd, l.getId(), start); - } - - if (!ring) { - Way end = null; - if (lowLevelWaysSt.containsKey(l.getId())) { - for (Way w : lowLevelWaysSt.get(l.getId())) { - int t = MapRenderingTypes.encodeEntityWithType(w, level, false, typeUse); - if (t == type && Algoritms.objectEquals(MapRenderingTypes.getEntityName(w, t), - MapRenderingTypes.getEntityName(e, t))) { - end = w; - break; - } - } - } - if (end != null) { - Long ll = end.getNodeIds().get(end.getNodeIds().size() - 1); - // remove end line - removeValueMap(lowLevelWaysSt, l.getId(), end); - removeValueMap(lowLevelWaysEnd, ll, end); - ring = ll == n.getId(); - - if (!ring) { - - // add nodes to start - for (int i = 1; i < end.getNodes().size(); i++) { - start.addNode(end.getNodes().get(i)); - } - - // remove end start - removeValueMap(lowLevelWaysEnd, l.getId(), start); - putIntoMap(lowLevelWaysEnd, ll, start); + // 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) { + type = i; + } else { + int ind = typeUse.indexOf(ks); + if (ind == -1) { + typeUse.add(i); + } else { + typeUse.set(ind, i); } } } } - } - - if(writeIntoDB || ring){ - writeEntityToMapDatabase(e, e.getId(), false, level); + } + + if (type == 0) { + return; + } + + 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 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); } } + - private void writeEntityToMapDatabase(Entity e, long baseId, boolean inverse, int level) throws SQLException { + /*private void writeEntityToMapDatabase(Entity e, long baseId, boolean inverse, int level) throws SQLException { int type = MapRenderingTypes.encodeEntityWithType(e, level, false, typeUse); Map> multiPolygonsWays; if(level == 0){ @@ -1569,12 +1587,69 @@ public class IndexCreator { if(eName == null ){ eName = multiPolygonsNames.get(baseId); } - DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, /*mapTree, */e, + DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, mapTree, e, eName, id, type, typeUse, restrictionsUse, useRestrictions, inverse, point, BATCH_SIZE); } } + */ + public void writeBinaryData(RTree rtree) throws IOException { + try { + long rootIndex = rtree.getFileHdr().getRootIndex(); + 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); + + writer.endWriteMapLevelIndex(); + writer.endWriteMapIndex(); + writer.close(); + } catch (RTreeException e) { + throw new IllegalStateException(e); + } + } + + public void writeBinaryMapTree(rtree.Node parent, RTree r, BinaryIndexWriter writer) throws IOException, RTreeException { + 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); + } 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); + writer.endWriteMapTreeElement(); + } + } + } + + + public Rect calcBounds(rtree.Node n) { + Rect r = null; + Element[] e = n.getAllElements(); + for (int i = 0; i < n.getTotalElements(); i++) { + Rect re = e[i].getRect(); + if (r == null) { + try { + r = new Rect(re.getMinX(), re.getMinY(), re.getMaxX(), re.getMaxY()); + } catch (IllegalValueException ex) { + } + } else { + r.expandToInclude(re); + } + } + return r; + } @@ -1585,6 +1660,15 @@ public class IndexCreator { } } + public String getRTreeMapIndexNonPackFileName(){ + return mapFile.getAbsolutePath()+".rtree"; + } + + public String getRTreeMapIndexPackFileName(){ + return mapFile.getAbsolutePath()+".prtree"; + } + + public void generateIndexes(File readFile, IProgress progress, IOsmStorageFilter addFilter) throws IOException, SAXException, SQLException { if (readFile != null && regionName == null) { @@ -1696,11 +1780,15 @@ public class IndexCreator { mapLocsStatLevel0 = DataIndexWriter.createStatementMapWaysLocationsInsert(mapConnection); mapLocsStatLevel1 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel2(mapConnection); mapLocsStatLevel2 = DataIndexWriter.createStatementMapWaysLocationsInsertLevel3(mapConnection); - // try { - // mapTree = new RTree(mapFile.getAbsolutePath()+"_ind"); - // } catch (RTreeException e) { - // e.printStackTrace(); - // } + try { + File file = new File(getRTreeMapIndexNonPackFileName()); + if(file.exists()){ + file.delete(); + } + mapTree = new RTree(getRTreeMapIndexNonPackFileName()); + } catch (RTreeException e) { + throw new IOException(e); + } pStatements.put(mapObjStat, 0); pStatements.put(mapLocsStatLevel0, 0); pStatements.put(mapLocsStatLevel1, 0); @@ -1856,19 +1944,29 @@ public class IndexCreator { } } - // 5. writing low level maps - progress.setGeneralProgress("[95 of 100]"); - progress.startTask("Indexing low levels for map ...", -1); + + // 5. writing map index if (indexMap) { - for (Long l : lowLevelWaysSt.keySet()) { - for (Way w : lowLevelWaysSt.get(l)) { - int level = (int) (w.getId() & 3); - writeEntityToMapDatabase(w, w.getId() >> 2, false, level); - } + progress.setGeneralProgress("[95 of 100]"); + progress.startTask("Serializing map data...", -1); + try { + mapTree.flush(); + } catch (RTreeException e) { + log.error("Error flushing", e); } + File file = new File(getRTreeMapIndexPackFileName()); + if (file.exists()) { + file.delete(); + } + new Pack().packTree(mapTree, getRTreeMapIndexPackFileName()); + mapTree = null; + // TODO !!! create binary output stream in order to close it properly (finally) + writeBinaryData(new RTree(getRTreeMapIndexPackFileName())); } + } catch (RTreeException e) { + throw new IOException(e); } finally { try { if (pselectNode != null) { @@ -1911,17 +2009,17 @@ public class IndexCreator { mapConnection.commit(); mapConnection.close(); mapConnection = null; - // try { - // mapTree.flush(); - // } catch (RTreeException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } - if (lastModifiedDate != null) { mapFile.setLastModified(lastModifiedDate); } } + if(mapTree != null){ + try { + mapTree.flush(); + } catch (RTreeException e) { + log.error("Error flushing", e); + } + } if (addressConnection != null) { addressConnection.commit(); @@ -1954,15 +2052,15 @@ public class IndexCreator { public static void main(String[] args) throws IOException, SAXException, SQLException { IndexCreator creator = new IndexCreator(new File("e:/Information/OSM maps/osmand/")); -// creator.setIndexMap(true); + creator.setIndexMap(true); // creator.setIndexPOI(true); - creator.setIndexTransport(true); +// creator.setIndexTransport(true); -// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb")); -// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/minsk.osm"), new ConsoleProgressImplementation(3), null); + creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/minsk.tmp.odb")); + creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/minsk.osm"), new ConsoleProgressImplementation(3), null); - creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/belarus_nodes.tmp.odb")); - creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/belarus.osm.bz2"), new ConsoleProgressImplementation(3), null); +// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/belarus_nodes.tmp.odb")); +// creator.generateIndexes(new File("e:/Information/OSM maps/belarus osm/belarus.osm.bz2"), new ConsoleProgressImplementation(3), null); // creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/ams.tmp.odb")); // creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/ams_part_map.osm"), new ConsoleProgressImplementation(3), null); @@ -1970,70 +2068,13 @@ public class IndexCreator { // creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/den_haag.tmp.odb")); // creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/den_haag.osm"), new ConsoleProgressImplementation(3), null); -// creator.setNodesDBFile(new File("e:/Information/OSM maps/osmand/netherlands.tmp.odb")); +// creator.setNodesk(new File("e:/Information/OSM maps/osmand/netherlands.tmp.odb")); // creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/netherlands.osm.bz2"), new ConsoleProgressImplementation(1), null); // creator.generateIndexes(new File("e:/Information/OSM maps/osm_map/forest_complex.osm"), new ConsoleProgressImplementation(25), null); - /*try { -// RTree rtree = new RTree("e:/Information/OSM maps/osmand/Belarus_2010_09_03.map.odb_ind"); -// new Pack().packTree(rtree, "e:/Information/OSM maps/osmand/pack.ind"); - RTree rtree = new RTree("e:/Information/OSM maps/osmand/pack.ind"); - long rootIndex = rtree.getFileHdr().getRootIndex(); - int s = calculateSize(rtree.getReadNode(rootIndex), rtree, "!-"); - System.out.println(s); - } catch (RTreeException e) { - e.printStackTrace(); - }*/ - + - - // download base - /* MapTileDownloader instance = MapTileDownloader.getInstance(); - instance.addDownloaderCallback(new MapTileDownloader.IMapDownloaderCallback() { - @Override - public void tileDownloaded(DownloadRequest request) { - System.out.println(request.url); - } - - }); - File baseDir = new File("e:/Information/OSM maps/planet_tiles"); - baseDir.mkdirs(); - TileSourceTemplate map = TileSourceManager.getMapnikSource(); - for (int zoom = 5; zoom <= 5; zoom++) { - int length = 1 << zoom; - for (int x = 0; x < length; x++) { - for (int y = 0; y < length; y++) { - String file = zoom + "/" + (x) + "/" + y + map.getTileFormat() + ".tile"; - DownloadRequest req = new DownloadRequest(map.getUrlToLoad(x, y, zoom), new File(baseDir, file), x, y, zoom); - instance.requestToDownload(req); - } - } - }*/ - } - /* - public static int calculateSize(rtree.Node n, RTree r, String level){ - Element[] e = n.getAllElements(); - int exc = 0; //20 + (169 - n.getTotalElements()) * 24; - for(int i=0; i< n.getTotalElements(); i++){ - if(e[i].getElementType() == rtree.Node.LEAF_NODE){ - exc += 1; - } else { -// exc += 1; - - long ptr = ((NonLeafElement) e[i]).getPtr(); - try { - rtree.Node ns = r.getReadNode(ptr); - System.out.println(level + " " + ns.getTotalElements()); - exc += calculateSize(ns, r, level +"-"); - } catch (RTreeException e1) { - e1.printStackTrace(); - } - } - } - return exc; - } - */ } diff --git a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java index bfd8b380af..cc8905c3f7 100644 --- a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java +++ b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java @@ -14,20 +14,19 @@ import net.osmand.osm.OSMSettings.OSMTagKey; * SOURCE : http://wiki.openstreetmap.org/wiki/Map_Features * * Describing types of polygons : - * 1. Last 3 bits define type of element : polygon, polyline, point + * 1. Last 2 bits define type of element : polygon, polyline, point */ public class MapRenderingTypes { // TODO Internet access bits for point, polygon /** standard schema : - Last bit describe whether types additional exist (it is needed only for main type, other consists only from 15 bits) - polygon : aaaaa ttttt 11 _ : 15 bits - multi : aaaaa ttttt 00 _ : 15 bits + polygon : ll aaaaa ttttt 11 : 14 bits + multi : ll aaaaa ttttt 00 : 14 bits t - object type, a - area subtype,l - layer - polyline : ll ppppp ttttt 10 _ : 15 bits + 2 bits for special info (+16) + polyline : ll ppppp ttttt 10 : 14 bits t - object type, p - polyline object type, l - layer - point : ssssssss ttttt 10 _ : 16 bits - t - object type, a - subtype + point : ssss ssss ttttt 10 : 15 bits + t - object type, s - subtype */ public final static int MULTY_POLYGON_TYPE = 0; @@ -233,12 +232,12 @@ public class MapRenderingTypes { } // if type equals 0 no need to save that point - public static int encodeEntityWithType(Entity e, int level, boolean multipolygon, List addTypes) { + public static int encodeEntityWithType(Entity e, int level, boolean multipolygon, List additionalTypes) { if (types == null) { types = new LinkedHashMap(); init(INIT_RULE_TYPES); } - addTypes.clear(); + additionalTypes.clear(); if("coastline".equals(e.getTag(OSMTagKey.NATURAL))){ //$NON-NLS-1$ multipolygon = true; } @@ -270,7 +269,7 @@ public class MapRenderingTypes { // 2. 2 iterations first for exact tag=value match, second for any tag match for (int i = 0; i < 2; i++) { - if (i == 1 && !addTypes.isEmpty()) { + if (i == 1 && !additionalTypes.isEmpty()) { break; } for (String tag : tagKeySet) { @@ -284,63 +283,47 @@ public class MapRenderingTypes { int typeVal = rType.getType(val, MASK_13) << 2; if (pr == POINT_TYPE && pointType == 0) { pointType = POINT_TYPE | typeVal; - addTypes.add(pointType); + additionalTypes.add(pointType); } else if (!point && pr == POLYLINE_TYPE) { int attr = getLayerAttributes(e) << 12; boolean prevPoint = (polylineType == 0 && polygonType == 0); polylineType = POLYLINE_TYPE | (typeVal & MASK_12) | attr; if (((polylineType >> 2) & MASK_4) == HIGHWAY || prevPoint){ - addTypes.add(0, polylineType); + additionalTypes.add(0, polylineType); } else { - addTypes.add(polylineType); + additionalTypes.add(polylineType); } } else if (polygon && (pr == POLYGON_WITH_CENTER_TYPE || pr == POLYGON_TYPE)) { boolean prevPoint = (polylineType == 0 && polygonType == 0); int attr = getLayerAttributes(e) << 12; polygonType = (multipolygon ? MULTY_POLYGON_TYPE : POLYGON_TYPE) | (typeVal & MASK_12) | attr; if (prevPoint){ - addTypes.add(0, polygonType); + additionalTypes.add(0, polygonType); } else { - addTypes.add(polygonType); + additionalTypes.add(polygonType); } if (pr == POLYGON_WITH_CENTER_TYPE) { pointType = POINT_TYPE | typeVal; - addTypes.add(pointType); + additionalTypes.add(pointType); } } else if (polygon && (pr == DEFAULT_POLYGON_BUILDING)) { if(polygonType == 0 && polylineType == 0){ - polygonType = (multipolygon ? MULTY_POLYGON_TYPE : POLYGON_TYPE) | (((SUBTYPE_BUILDING << 5) | MAN_MADE) << 3); - addTypes.add(0, polygonType); + int attr = getLayerAttributes(e) << 12; + polygonType = (multipolygon ? MULTY_POLYGON_TYPE : POLYGON_TYPE) | (((SUBTYPE_BUILDING << 5) | MAN_MADE) << 2) | attr; + additionalTypes.add(0, polygonType); } pointType = POINT_TYPE | typeVal; - addTypes.add(pointType); + additionalTypes.add(pointType); } } } } int type = 0; - if(addTypes.isEmpty()){ - return type; + if(!additionalTypes.isEmpty()){ + type = additionalTypes.get(0); + additionalTypes.remove(0); } - boolean twoBytes = true; - int first = addTypes.get(0); - addTypes.remove(0); - if(isHighwayType(first)){ - twoBytes = false; - int attr = getHighwayAttributes(e) << 16; - type = attr | (first << 1); - } else { - type = first << 1; - } - if(twoBytes && addTypes.size() > 0){ - type |= (addTypes.get(0) << 16); - addTypes.remove(0); - } - if(!addTypes.isEmpty()){ - type |= 1; - } - return type; } @@ -359,17 +342,15 @@ public class MapRenderingTypes { } // HIGHWAY special attributes : - // T/Type 5 bit - // l/layer 2 bit // o/oneway 1 bit // f/free toll 1 bit - // r/roundabout 1 bit (+ 1 bit direction) + // r/roundabout 2 bit (+ 1 bit direction) // s/max speed 3 bit [0 - 30km/h, 1 - 50km/h, 2 - 70km/h, 3 - 90km/h, 4 - 110km/h, 5 - 130 km/h, 6 >] // a/vehicle access 4 bit (height, weight?) - one bit bicycle // p/parking 1 bit // c/cycle oneway 1 bit - // ENCODING : c|p|aaaa|sss|rr|f|o|ll|TTTTT|00001|01_ - 28 bit + // ENCODING : c|p|aaaa|sss|rr|f|o - 13 bit public static int getHighwayAttributes(Entity e){ int attr = 0; @@ -497,7 +478,6 @@ public class MapRenderingTypes { } public static String getEntityName(Entity e, int mainType) { - mainType >>= 1; if (e.getTag(OSMTagKey.REF) != null && getMainObjectType(mainType) == HIGHWAY) { String ref = e.getTag(OSMTagKey.REF); if (ref.length() > 5 && ref.indexOf('_') != -1) { diff --git a/DataExtractionOSM/src/rtree/ABL.java b/DataExtractionOSM/src/rtree/ABL.java new file mode 100644 index 0000000000..0e14f3116b --- /dev/null +++ b/DataExtractionOSM/src/rtree/ABL.java @@ -0,0 +1,103 @@ +//ABL.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; +/**Active Branch List + This class will consist of the Elements and their MINDIST from the point of query. + When the array of this object is returned by the 'nearestSearch' method, + kindly type cast 'Elemen't to 'LeafElement' when necessary. + This library should be considered as an open source library. Formal GNU licensing I will include later. +*/ +public class ABL implements Cloneable +{ + /** + Please type cast it to LeafElement when used as a returned value of + the 'nearestSearch' method. + */ + public Element element; + /**By Definition - The distance of a point P in Euclidean space (E(n)) + from a rectangle R in the same space, denoted by MINDIST(P,R).
+ In English - This is the minimum distance between the query point P + and the MBR of the object. + Note:- The distance(minDist) is the square of the actual distance. + To get the actual distance, call Math.sqrt(minDist) (cast minDist to + Double). + */ + public long minDist;//MINDIST(P,this) + public ABL(Element element,long minDist) + { + this.element = element; + this.minDist = minDist; + } + //Uses Two-Way-Merge-Sort (Recursive) + //Sorts an ABL array based on minDist. Make sure there are no null values. + public void mergeSort(ABL[] arrABL) + { + twoWayMerge(arrABL,0,arrABL.length-1); + } + private void twoWayMerge(ABL[] arrABL,int start,int finish) + { + try{ + int size = finish - start+1; + if(size <= 2){ + if(size < 2) + return; + ABL temp; + if(arrABL[start].minDist > arrABL[finish].minDist){ + temp = arrABL[start]; + arrABL[start] = arrABL[finish]; + arrABL[finish] = temp; + } + return; + } + Double middle = new Double(start+finish); + middle = new Double(Math.ceil(middle.doubleValue()/2)); + twoWayMerge(arrABL,start,middle.intValue()); + twoWayMerge(arrABL,middle.intValue(),finish); + simpleMerge(arrABL,start,middle.intValue(),finish); + } + catch(Exception e){ + System.out.println("rtree.ABL.twoWayMerge: most probably a null value in array"); + } + } + + //simple merge + private void simpleMerge(ABL[] arrABL,int first,int second,int third) + throws Exception + { + int i = first; + int j = second; + int l = 0; + ABL[] temp = new ABL[third-first+1]; + while((i < second) && (j <= third)){//loop till one lasts + if(arrABL[i].minDist <= arrABL[j].minDist) + temp[l++] = arrABL[i++]; + else + temp[l++] = arrABL[j++]; + } + //copy the rest + if(i >= second)//give second section + while(j <= third) + temp[l++] = arrABL[j++]; + else + while(i < second)//give first section + temp[l++] = arrABL[i++]; + System.arraycopy(temp,0,arrABL,first,temp.length); + } + public Object clone() + { + return new ABL(element,minDist); + } + +}//class ABL + + diff --git a/DataExtractionOSM/src/rtree/CachedNodes.java b/DataExtractionOSM/src/rtree/CachedNodes.java new file mode 100644 index 0000000000..065a9b9670 --- /dev/null +++ b/DataExtractionOSM/src/rtree/CachedNodes.java @@ -0,0 +1,409 @@ +//BufferHeader.java,CachedNodes.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; +import java.util.*; +import java.io.*; +import rtree.seeded.SdNode; +/** + A circular linked list of cached nodes using hashtable ?!! +

This class will wrap a list of recently used nodes. + If the requested node is in Hashtable of the class then the node would + be returned from the Hashtable, else it would be read from the + disk. +
This will be a static object in the class RTree. Therefore no matter how + many RTree objects you create they all would have one cache for all the files + the object handles. + TODO : keep a set that keeps all the nodes that are dirty. With each node registering themselves + hara when thhey are dity, this is maageable. + @author Prachuryya Barua +*/ +class BufferHeader +{ + int recent;//the most recently inserted node + int last;//the least recently inserted node + int size;//max size of the link list + Hashtable cache; + BufferHeader(int size,Hashtable ch) + { + this.cache = ch; + this.size = size; + } + + void flush() + throws NodeWriteException + { + //if(!RTree.writeThr){ + for (Iterator it = cache.values().iterator(); it.hasNext();){ + NodeValue node = (NodeValue)it.next(); + node.node.flush(); + } // end of for (Iterator = .iterator(); .hasNext();) + //} + } + /*for a fresh key when the array is not full.This will be called when the + buffer is not fully warm*/ + void put(int key, Node node) + { + try{ + //the following two conditions happens in multithreaded programs + if(cache.containsKey(new Integer(key))){ + update(key); + return; + } + if(cache.size() == size){ + replace(key,node); + return; + } + if(cache.size() == 0){ + last = key; + cache.put(new Integer(key), new NodeValue(node,key,key)); + }else{ + //remove recent + NodeValue tmpPrev = (NodeValue)(cache.remove(new Integer(recent))); + if(last == recent){//there is only one node in cache + cache.put(new Integer(key), new NodeValue(node,tmpPrev.next,tmpPrev.next)); + cache.put(new Integer(recent), new NodeValue(tmpPrev.node,key,key)); + } + else{ + //remove next of previous + NodeValue tmpPNext = (NodeValue)(cache.remove(new Integer(tmpPrev.next))); + cache.put(new Integer(key), new NodeValue(node,tmpPrev.next,recent)); + cache.put(new Integer(tmpPrev.next), new NodeValue(tmpPNext.node,tmpPNext.next,key)); + cache.put(new Integer(recent), new NodeValue(tmpPrev.node,key,tmpPrev.prev)); + } + } + recent = key; + } + catch(Exception e){ + e.printStackTrace(); + } + } + /*a new key in a filled array*/ + void replace(int key,Node node) + throws NodeWriteException + { + try{ + if(cache.containsKey(new Integer(key))){ + update(key); + return; + } + if(cache.size() < size){ + put(key,node); + return; + } + //remove the 'last' node + NodeValue lastNode = (NodeValue)(cache.remove(new Integer(last))); + lastNode.node.flush(); + NodeValue pNode = (NodeValue)(cache.remove(new Integer(lastNode.prev))); + NodeValue nNode = (NodeValue)(cache.remove(new Integer(lastNode.next))); + //put back the three nodes + cache.put(new Integer(key), new NodeValue(node,lastNode.next, lastNode.prev)); + cache.put(new Integer(lastNode.prev), new NodeValue(pNode.node,key,pNode.prev)); + cache.put(new Integer(lastNode.next), new NodeValue(nNode.node,nNode.next,key)); + recent = key;//this is the latest node + last = lastNode.next;//set the next in chain as the new 'last' + + } + catch(Exception e){ + e.printStackTrace(); + } + } + /**make a node that is present as 'recent'*/ + void update(int key) + { + try{ + if(key != recent){ + NodeValue node,nextNode,prevNode,rcntNode,lastNode;//temp variables + node = (NodeValue)(cache.remove(new Integer(key))); + if(node == null){//will not happen + System.out.println("CachedNodes.update: unlikely flow"); + return; + } + if(key == last){ + last = node.next; + cache.put(new Integer(key), new NodeValue(node.node, node.next, node.prev)); + } + else{ + //adjust next node and the recent node + nextNode = (NodeValue)(cache.remove(new Integer(node.next))); + if(recent != node.next){//if next node is not the recent node + rcntNode = (NodeValue)(cache.remove(new Integer(recent))); + rcntNode.next = key; + cache.put(new Integer(recent), new NodeValue(rcntNode.node, rcntNode.next,rcntNode.prev)); + } + else{//next node is the recent node + nextNode.next = key; + } + cache.put(new Integer(node.next), new NodeValue(nextNode.node, nextNode.next,node.prev)); + + //adjust previous node and the last node - if unequal + prevNode = (NodeValue)(cache.remove(new Integer(node.prev))); + if(last != node.prev){//if last node is not the prev node + lastNode = (NodeValue)(cache.remove(new Integer(last))); + lastNode.prev = key; + cache.put(new Integer(last),new NodeValue(lastNode.node, lastNode.next,lastNode.prev)); + } + else{//if the last node is the prev node. + prevNode.prev = key; + } + cache.put(new Integer(node.prev), new NodeValue(prevNode.node, node.next,prevNode.prev)); + + //put the new node + cache.put(new Integer(key), new NodeValue(node.node,last,recent)); + } + //update local variables + } + recent = key; + } + catch(Exception e){ + e.printStackTrace(); + } + } + void remove(int key) + throws NodeWriteException + { + try{ + NodeValue node = (NodeValue)(cache.remove(new Integer(key))); + if((cache.size() != 0) && (node != null)){ + //if(!RTree.writeThr) + node.node.flush(); + if(cache.size() == 1){ + NodeValue oNode = (NodeValue)(cache.remove(new Integer(node.prev))); + cache.put(new Integer(node.prev), new NodeValue(oNode.node, node.prev,node.prev)); + recent = last = node.prev; + } + else{ + //if(!RTree.writeThr) + node.node.flush(); + NodeValue pNode = (NodeValue)(cache.remove(new Integer(node.prev))); + NodeValue nNode = (NodeValue)(cache.remove(new Integer(node.next))); + cache.put(new Integer(node.prev), new NodeValue(pNode.node, node.next,pNode.prev)); + cache.put(new Integer(node.next), new NodeValue(nNode.node, nNode.next,node.prev)); + if(key == recent) + recent = node.prev; + if(key == last) + last = node.next; + } + } + } + catch(Exception e){ + e.printStackTrace(); + } + } + void reset() + throws NodeWriteException + { + //if(!RTree.writeThr) + flush(); + cache.clear(); + } +} +public class CachedNodes +{ + private static final int NODE = 0; + private static final int SDNODE = 1; + Hashtable cache; + BufferHeader buffHeader; + int size = Node.CACHE_SIZE; + CachedNodes() + { + //System.out.println("CachedNodes : cache called"); + cache = new Hashtable(Node.CACHE_SIZE+1,1); + buffHeader = new BufferHeader(Node.CACHE_SIZE,cache); + size = Node.CACHE_SIZE; + } + /** + This one is still under construction. + */ + CachedNodes(int size) + { + if(size < 0) + throw new IllegalArgumentException("CachedNodes:: size is less than zero"); + cache = new Hashtable(size+1,1); + buffHeader = new BufferHeader(size, cache); + this.size = size; + } + public synchronized void setCacheSize(int size) + throws NodeWriteException + { + if(size < 0) + throw new IllegalArgumentException("CachedNodes:: size is less than zero"); + removeAll(); + cache = new Hashtable(size+1,1); + buffHeader = new BufferHeader(size, cache); + this.size = size; + } + public synchronized int getSize() + { + return cache.size(); + } + private Node getNode(RandomAccessFile file,String fileName,long lndIndex,FileHdr flHdr, int type) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + int ndIndex = (int)lndIndex; + int key = calKey(fileName,ndIndex); + NodeValue node = (NodeValue)(cache.get(new Integer(key))); + Node nNode; + if(node == null){//Node not in cache + if(type == NODE){ + nNode = new Node(file, fileName, ndIndex, flHdr); + }else{ + nNode = new SdNode(file, fileName, ndIndex, flHdr); + } + key = calKey(fileName, (int)nNode.getNodeIndex());//this is for the case where index is NOT_DEFINED + nNode.sweepSort(); + //cache not full + if(cache.size() < Node.CACHE_SIZE){ + buffHeader.put(key,nNode);//(Node)nNode.clone()); + }else if(cache.size() == Node.CACHE_SIZE){//cache Is full + buffHeader.replace(key,nNode);//(Node)nNode.clone()); + } + return nNode; + } + else{//node found in the cache + buffHeader.update(key); + node.node.sweepSort(); + return (node.node); + } + } + private Node getNode(RandomAccessFile file,String fileName,long parentIndex, int elmtType, FileHdr flHdr, + int type) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + Node nNode; + if(type == NODE){ + nNode = new Node(file,fileName,parentIndex, elmtType, flHdr); + }else{ + nNode = new SdNode(file,fileName,parentIndex, elmtType, flHdr); + } + int key = calKey(fileName, (int)nNode.getNodeIndex()); + nNode.sweepSort(); + //cache not full + if(cache.size() < Node.CACHE_SIZE) + buffHeader.put(key,nNode); + //cache Is full + else if(cache.size() == Node.CACHE_SIZE) + buffHeader.replace(key,nNode); + return nNode; + } + //-----------------------Methods for client to get Node they prefer------------ + /** + This one returns an existing SdNode + */ + public synchronized SdNode getSdNode(RandomAccessFile file,String fileName,long lndIndex,FileHdr flHdr) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + return (SdNode)getNode(file,fileName,lndIndex,flHdr, SDNODE); + } + /** + This one returns an existing SdNode. + */ + public synchronized SdNode getSdNode(RandomAccessFile file,String fileName,long parentIndex, + int elmtType, FileHdr flHdr) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + return (SdNode)getNode(file,fileName,parentIndex, elmtType, flHdr, SDNODE); + } + /** + This one returns an existing Node. + */ + public synchronized Node getNode(RandomAccessFile file,String fileName,long lndIndex,FileHdr flHdr) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + return getNode(file,fileName,lndIndex,flHdr, NODE); + } + /** + This one returns an new SdNode. + */ + public synchronized Node getNode(RandomAccessFile file,String fileName,long parentIndex, + int elmtType, FileHdr flHdr) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + return getNode(file,fileName,parentIndex, elmtType, flHdr, NODE); + } + /** + This one returns an new Node. + */ + public synchronized Node getNode(RandomAccessFile file,String fileName,long parentIndex, + int elmtType, FileHdr flHdr, Node type) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + if(type instanceof SdNode) + return getNode(file,fileName,parentIndex, elmtType, flHdr, SDNODE); + else + return getNode(file,fileName,parentIndex, elmtType, flHdr, NODE); + } + /** + This one return ReadNode a read only node. + All clients that need only to query the rtree must at all cost call this method. This method will + return a clones ReadNode, so that concurrent reads can take place (because none of the methods + of Node are synchronized. + */ + public synchronized ReadNode getReadNode(RandomAccessFile file,String fileName,long lndIndex,FileHdr flHdr) + throws IllegalValueException, NodeReadException, FileNotFoundException, IOException, NodeWriteException + { + return ReadNode.makeReadNode(getNode(file,fileName,lndIndex,flHdr)); + } + /** + Write all the diry nodes to the disc. + */ + synchronized void flush() + throws NodeWriteException + { + //if(!RTree.writeThr) + buffHeader.flush(); + } + /** + This method would be called only by those threads that need to modify the + tree. Hence this method is automatically synchronized. + */ + synchronized void remove(String fileName,long ndIndex) + throws NodeWriteException + { + int key = calKey(fileName,(int)ndIndex); + buffHeader.remove(key); + } + + + synchronized void removeAll() + throws NodeWriteException + { + buffHeader.reset(); + } + + int calKey(String fileName,int idx) + { + if(fileName != null) + return (idx + fileName.toLowerCase().hashCode()); + else{ + System.out.println("CachedNodes.calKey: fileName null"); + return 0; + } + } +} +class NodeValue +{ + Node node; + int next;//the next node's key + int prev;//the prev node's key + NodeValue(Node node,int n,int p) + { + this.node = node; + next = n; + prev = p; + } +} +/** + TODO: + 2) A way to pin an node. Obviously the client must also unpinn the node. + +*/ diff --git a/DataExtractionOSM/src/rtree/Element.java b/DataExtractionOSM/src/rtree/Element.java new file mode 100644 index 0000000000..61a71ff387 --- /dev/null +++ b/DataExtractionOSM/src/rtree/Element.java @@ -0,0 +1,58 @@ +//Element.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +/**baap of all elemetns + @author Prachuryya Barua + * + **/ +public abstract class Element implements Cloneable, java.io.Serializable +{ + Rect Rectangle; + + Element(){}; + public Element( Rect Rectangle) + { + this.Rectangle = Rectangle; + } + private void overwriteRect( Rect Rectangle) + { + this.Rectangle = Rectangle; + } + public Rect getRect() + { + return(Rectangle); + } + /** + This can be a child node pointer or a record pointer. + */ + //public abstract Object getPtr();//old + public abstract long getPtr(); + /** + Do not call this function, Node will call it. + */ + void setRect( Rect mbr) + throws IllegalValueException + { + if(mbr == null) + throw new IllegalValueException("Element.adjustMBR: Rect is null"); + overwriteRect(mbr); + } + //abstract void setPtr(Object ptr) //old + //throws IllegalValueException; + public abstract void setPtr(long ptr); + public abstract int getElementType(); + public String toString() + { + return Rectangle.toString(); + } +} diff --git a/DataExtractionOSM/src/rtree/ElementNotFoundException.java b/DataExtractionOSM/src/rtree/ElementNotFoundException.java new file mode 100644 index 0000000000..61d0105a58 --- /dev/null +++ b/DataExtractionOSM/src/rtree/ElementNotFoundException.java @@ -0,0 +1,22 @@ +//ElementNotFoundException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +/**When deleting node if the node is not found then the exception is thrown + @author Prachuryya Barua +*/ +public class ElementNotFoundException extends Exception +{ + public ElementNotFoundException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/FileHdr.java b/DataExtractionOSM/src/rtree/FileHdr.java new file mode 100644 index 0000000000..d2c05c4923 --- /dev/null +++ b/DataExtractionOSM/src/rtree/FileHdr.java @@ -0,0 +1,534 @@ +//FileHdr.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; +import java.io.*; +import java.util.Vector; +import java.util.Enumeration; +/** + This class is the handler for the file. + @author Prachuryya Barua +*/ +public class FileHdr +{ + /**------------file header - will always take 1024 bytes------------*/ + /**total no. of nodes in the file*/ + int totalNodes; + /**the index of the root*/ + long rootIndex; + + /**------------local variables--------------------------------------*/ + protected boolean writeThr = false;//whether write dirt or write through + /**Overflow limit*/ + int stkLimit; + /**The stack data. Although the indices are long but they can be easily represented as + int*/ + private int[] S; + /**Index of the top most element*/ + private int topIdx; + private RandomAccessFile file; + private boolean dirty = false;/*Tells whethet this is a dirty filehdr or not*/ + /**If any write thread is interested then increment this. This variable + results in the fact that writes will always have the preference. + Even when the JVM chooses a READ thread to run, it would have to wait + till one of all the waiting WRITE threads run. After one of the WRITE + thread runs, the situation is open for all. Again, if any of the WRITE + thread sets interested, then on next notifyAll it is + gauranteed that one of the WRITE threads will run before any other READ. + */ + private boolean interested; + /**The wait thread queue*/ + private Vector waiters; + /** + Although this 'stack' is part of the file header but it acts totally + independently of the rest of the file header. All of the file reads and + writes are handled by the 'Node' class but the free node list('stack') is + maintained by this class independently. Therefore all the 'Node' class + needs to do is call the 'push' and 'pop' method to read and write to the + file regarding the free node list.
+ Note:- This class will work well with 150 element delets at one go but + beyond that it will not maintain the list of nodes that have been + deleted. This is not fatal but the size of the file will increase and the + deleted nodes that did not register with the stack will be lost forever. + This condition can be rectified by calling Pack.packTree. + */ + FileHdr(int stkLimit,String fileName) + throws RTreeException + { + try{ + this.file = new RandomAccessFile(fileName,"rw"); + this.writeThr = false; + this.stkLimit = stkLimit; + waiters = new Vector(); + S = new int[this.stkLimit]; + topIdx = -1; + int frNode; + writeThr = false; + //no nodes present + //if(file.length() <= (Node.FILE_HDR_SIZE+1)){ + if(file.length() <= (Node.INTEGER_SIZE)){ + file.seek(0); + file.writeInt(0);//total nodes + file.writeLong(Node.NOT_DEFINED);//file.writeInt(Node.NOT_DEFINED);//original + file.writeInt(Node.NOT_DEFINED); + totalNodes = 0; + rootIndex = Node.NOT_DEFINED; + } + //read stack from the file if stack exists + else{ + file.seek(0); + byte[] data = new byte[ Node.FILE_HDR_SIZE ]; + file.read(data); + DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data)); + totalNodes = ds.readInt(); + rootIndex = ds.readLong();//rootIndex = ds.readInt(); + while((topIdx= (stkLimit-1)) + throw new StackOverflowException("FileHdr.push: Overflow but not fatal"); + //System.out.println("Push called, pushing at S["+(topIdx+1)+"]:"+val); + S[++topIdx] = val; + dirty = true; + if(writeThr){ + file.seek(( Node.INTEGER_SIZE + Node.LONG_SIZE)+( Node.INTEGER_SIZE*(topIdx))); + file.writeInt(val); + //signal end of free list + if(topIdx < ( Node.FREE_LIST_LIMIT-1)) + file.writeInt( Node.NOT_DEFINED); + } + } + synchronized int pop() + throws StackUnderflowException,IOException + { + if(topIdx < 0) + throw new StackUnderflowException("FileHdr.pop: Underflow"); + //System.out.println("Pop called, returning S["+topIdx+"]:"+S[topIdx]); + if(writeThr){ + file.seek(( Node.INTEGER_SIZE + Node.LONG_SIZE) + ( Node.INTEGER_SIZE*topIdx)); + file.writeInt( Node.NOT_DEFINED); + } + dirty = true; + return S[topIdx--]; + } + /** + returns the size of the stck of free nodes. + */ + int stackSize() + { + return topIdx + 1; + } + int peep(int index) + throws IllegalValueException + { + if((index > topIdx) || (index < 0)) + throw new IllegalValueException("FileHdr.peep: Index out of bound"); + return S[index]; + } + + private synchronized void writeFileHeader() + throws IOException + { + if(dirty){ + ByteArrayOutputStream bs = new ByteArrayOutputStream(Node.FILE_HDR_SIZE); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeInt(totalNodes); + ds.writeLong(rootIndex); + if(topIdx == -1) + ds.writeInt(Node.NOT_DEFINED); + else{//write the whole stack + for(int i=0; i <= topIdx; i++) + ds.writeInt(S[i]); + ds.writeInt(Node.NOT_DEFINED);//indicate the end of list + }//else + bs.flush(); + ds.flush(); + file.seek(0); + file.write(bs.toByteArray()); + } + dirty = false; + } + /**this function writes to file header as well as to the local variables + an atomic function.Does not concern itself with the stack info. + */ + synchronized void writeFileHeader(int totNodes,long rootIdx) + throws IOException + { + if(writeThr){ + ByteArrayOutputStream bs = new ByteArrayOutputStream(Node.INTEGER_SIZE + Node.LONG_SIZE); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeInt(totNodes); + ds.writeLong(rootIdx); + bs.flush(); + ds.flush(); + file.seek(0); + file.write(bs.toByteArray()); + dirty = false; + } + dirty = true; + //update local variables + totalNodes = totNodes; + rootIndex = rootIdx; + } + /** + This method does a file IO. Can we make another method which is not static. + @return root index for any file. + @deprecated Use the non static one. + */ + public static long getRootIndex(String fileName) + throws FileNotFoundException + { + RandomAccessFile fl = new RandomAccessFile(fileName,"r"); + try{ + if (fl.length() == 0)//new file + throw new FileNotFoundException("Node.getRootIndex : File not found"); + fl.seek( Node.INTEGER_SIZE ); + long rootIndx = fl.readLong(); + fl.close(); + return rootIndx; + } + catch(IOException e){ + System.out.println("Node.getRootIndex: Couldn't get root index"); + return Node.NOT_DEFINED; + } + } + /** + Returns the RandomAccessFile object + */ + public RandomAccessFile getFile() + { + return this.file; + } + /** + Will return the total nodes in the tree. This does not include the nodes that are deleted and are + in the stack. + */ + public int getTotalNodes() + { + if(topIdx < 0) + return totalNodes; + else + return totalNodes - topIdx; + } + public long getRootIndex() + { + return rootIndex; + } + protected void finalize() throws Throwable + { + try { + flush(); + file.close(); + }catch (Exception e) { + e.printStackTrace(); + } + } + /** + Will flush the file header if it is dirty. It will not flush the individual nodes at it it not + its responsiblity. + */ + void flush() + throws IOException + { + if(dirty && !writeThr){ + writeFileHeader(); + dirty = false; + } + } + public boolean isWriteThr() + { + return writeThr; + } + void setDirty(boolean val) + { + this.dirty = val; + } + //-------------The following code is added by Ketan ...replacing my code!!!!------------------ + + /**retuns the index of the first WRITE thread in the queue*/ + private int firstWriter() + { + Enumeration e=waiters.elements(); + + for(int index=0;e.hasMoreElements();index++) + { + ThreadInfo threadinfo = (ThreadInfo) e.nextElement(); + if(threadinfo.lockType == Node.WRITE) + return index; + } + return Integer.MAX_VALUE; + } + private int getIndex(Thread t) + { + Enumeration e=waiters.elements(); + + /** If thread is in the vector then + * return it's index + * else + * return -1 + */ + for(int index=0;e.hasMoreElements();index++) + { + ThreadInfo threadinfo = (ThreadInfo) e.nextElement(); + /** If Thread is already in the vector then + * return it's Index + */ + if(threadinfo.t == t) + { + return index; + } + } + return -1; + } + + public synchronized void lockRead() + { + ThreadInfo threadinfo; + Thread me = Thread.currentThread(); + int index = getIndex(me); + /** if index = -1 then + the thread is not in the Vector, so create a new ThreadInfo + and add it to the vector + else + thread is in the queue and get the index of the thread + */ + if(index == -1) + { + threadinfo = new ThreadInfo(me,Node.READ); + waiters.addElement(threadinfo); + } + else + { + threadinfo = (ThreadInfo) waiters.elementAt(index); + } + + /** If the currentThread has come after a Write Thread then + * make it wait() until WRITE thread is serviced + */ + while(getIndex(me) >= firstWriter()) + { + try + { + wait(); + }catch(Exception e){} + } + /** + * increase the no. of locks the threadinfo has acquired + */ + threadinfo.nAcquired++; + //System.out.println("FileHdr.lockRead : read locked for thread " + Thread.currentThread()); + //+" when "+this.toString()); + } + + public synchronized void lockWrite() throws IllegalArgumentException + { + ThreadInfo threadinfo; + Thread me= Thread.currentThread(); + int index = getIndex(me); + /** If the thread is not in the Vector then + create a new ThreadInfo with WRITE status and add it to the Vector + else + get the Index for the thread from the Vector + */ + if(index==-1) + { + threadinfo = new ThreadInfo(me,Node.WRITE); + waiters.addElement(threadinfo); + } + else + { + //System.out.println("getIndex = " +getIndex(me)); + threadinfo = (ThreadInfo) waiters.elementAt(index); + //if(threadinfo.lockType==Node.READ) + //threadinfo.lockType = Node.WRITE; + } + while(getIndex(me)!=0) + { + try + { + wait(); + }catch(Exception e){} + } + threadinfo.nAcquired++; + //System.out.println("FileHdr.lockWrite : write locked for thread " + Thread.currentThread()); + } + public synchronized void unlock() throws IllegalArgumentException + { + ThreadInfo threadinfo; + Thread me = Thread.currentThread(); + int index = getIndex(me); + + /** if the index is greater than first WRITE thread then + * lock is not held by the thread so throw Exception + else + + */ + if(index > firstWriter()) + throw new IllegalArgumentException("FileHdr.unlock: Lock not Held for the thread"); + + threadinfo = (ThreadInfo) waiters.elementAt(index); + threadinfo.nAcquired--; + + if(threadinfo.nAcquired==0) + { + waiters.removeElementAt(index); + if(waiters.size()>0){ + //System.out.println("FileHdr.unlock : notifiying"); + notifyAll(); + } + } + //System.out.println("FileHdr.unlock : unlocking for thread " + Thread.currentThread()); + } + /** + This method will return only internal varaibles. + */ + public String toString() + { + try{ + String str = new String(); + str += "\nTotal Nodes " + totalNodes; + str += "\nRoot Index " + rootIndex; + str += "\nFile length " + file.length(); + if(waiters != null){ + str += "\nWaiters : total " + waiters.size(); + for(int i=0; i"Id" of the MBR in database. + @return an Long type object + */ + // public Object getPtr() + // { + // return(new Long(recordPtr)); + // } + public long getPtr() + { + return recordPtr; + } + public int getElementType() + { + return Node.LEAF_NODE; + } + // void setPtr(Object ptr) + // throws IllegalValueException + // { + // if(!(ptr instanceof Long)) + // throw new IllegalValueException("rtree.LeafElement.setPtr: pointer shoild be Long"); + // recordPtr = ((Long)ptr).longValue(); + // } + public void setPtr(long ptr) + { + recordPtr = ptr; + } + public String toString() + { + return (super.toString()+"\n\trecPointer: "+recordPtr); + } + public Object clone() + { + try{ + return new LeafElement(new Rect(Rectangle.getMinX(), Rectangle.getMinY(), + Rectangle.getMaxX(), Rectangle.getMaxY()),recordPtr); + } + catch(Exception e){ + e.printStackTrace(); + return null; + } + } + + /** + This is a utility method that extracts record pointers(IDs) from a LeafElement vector. + This method can be called after calling amy of the spatial calls to RTree. + */ + public synchronized static List extractPtrs(List elements) + throws IllegalArgumentException + { + if(elements == null) + throw new IllegalArgumentException("RTree.LeafElement: Argument null"); + List result = new ArrayList(); + try{ + for (Iterator i = elements.iterator(); i.hasNext();) + //result.addElement(new Long(((LeafElement)i.next()).getPtr())); + result.add(new Integer((int)((LeafElement)i.next()).getPtr()));//temp + //System.out.println("LeafElement.Extractptrs : time " + (System.currentTimeMillis() - time)); + return result; + + }catch(ClassCastException e){ + throw new IllegalArgumentException("RTree.LeafElement: Type of vector is not LeafElement"); + } + } + +} diff --git a/DataExtractionOSM/src/rtree/Node.java b/DataExtractionOSM/src/rtree/Node.java new file mode 100644 index 0000000000..df282ede3f --- /dev/null +++ b/DataExtractionOSM/src/rtree/Node.java @@ -0,0 +1,1480 @@ +//Node.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Arrays; + +/** + This class will contain one node at a time in memory. + This class along with FileHdr are the only two classes that handle the + rtree file. No other class handles the rtree file. Therefore be very careful + when modifying this class, you may corrupt the file in the process. +

CHANGELOG See the projects/ChangeLog file + + @author Prachuryya Barua + @version Node.NOT_DEFINED +*/ + +public class Node implements Cloneable //can be made abstract if leaf and non leaf required +{ + /**max no. of entries in a node*/ + public final static int MAX = 169;//84;//101; //50;//testing 3 + /**min. no. of entries in a node*/ + public final static int MIN= 84;//51; //25;//testing 2 + /**The size of the cache.
+ Minimum cache size is 50% of total no. of elements (1lakh records has 597 nodes). +
Maximum cache size should be 70%, beyound that there may not be major improvements but the + overheads will increase. +
Eg: 1 lakh packed records - Total nodes in tree - 597: Height 3, 1 root,4 nonleaf, 129 leaf + and should have a cache size of 250(sufficient for normal casses) to 400(good for queries). +
Multiply the cache size by 4kbytes and you get the cache size in MBytes. +
These observations are for a packed tree only. An unpacked tree + needs a 100% buffer size - thererore don't use unpacked tree. +
For unpacked tree +
1 lakh records - Total nodes in tree - 991( Height 3: 1 root, 10 NonLeaf, 981 Leaf + + These observations shold hold good for query building as well. But it is no harm to give large caches + for query building. + */ + public final static int CACHE_SIZE = 250; + /**bytes*/ + final static int NODE_HDR_SIZE = 20;//16; + /**2 kBytes - will include the file header and the stack*/ + final static int FILE_HDR_SIZE = 4096;//2048;//1024; + /** 2 kByte*/ + final static int NODE_SIZE = 4096;//2048;//1024; + /**2048-16=2032 then 2048-20=2028 NOW 4096-20=4076*/ + final static int NODE_BODY_SIZE = 4076;//2028;//2032;//1008; + /**can be increased by increasing file header size*/ + final static int FREE_LIST_LIMIT = 1020;//509;//5102k;//2541k; + /**So that I don't forget*/ + final static int INTEGER_SIZE = 4; + /**So that I don't forget*/ + final static int LONG_SIZE = 8; + /**node elements type - LEAF*/ + public final static int LEAF_NODE = 1; + /**node elements type - NON LEAF*/ + public final static int NONLEAF_NODE = 2; + /**node elements type - NONE*/ + public final static int NOT_DEFINED = -999; + public final static long NOT_DEFINED_LONG = -999; + /**for thread which reads the tree*/ + final static int READ = 0; + /**for threads which writes the reads*/ + final static int WRITE = 1; + /**No threads reading or writing*/ + final static int NONE = 2; + + /**-------------local variables-----------------------*/ + protected RandomAccessFile file; + protected String fileName; + protected boolean dirty = false;/*This flags keeps track of the changes made*/ + /**will contain the index of the node in the file*/ + protected long nodeIndex; + /**a flag to see whether a node is empty*/ + //protected boolean isNodeEmpty; + protected boolean sorted; + /**will contain all the elements.*/ + protected Element[] elements; + /**the file header and the free nodes stack*/ + protected FileHdr fileHdr; + /**The cached Node MBR... no loops over the node Elements*/ + protected Rect nodeMBR;//remove + /**-------------------Node header and body-----------------------*/ + /**total no. of elements*/ + protected int totalElements; + /**parent index - root's parent is not defined*/ + protected long parent; + /**size of the element*/ + protected int elementSize; + /**type of the elements in the node*/ + protected int elementType; + /**---------------Element structure------------*/ + /** + *minX + *minY + *maxX + *maxY + *pointer + */ + + /**This is only for subclasses*/ + protected Node(){} + + /**for a new node + Remember if the file is new this constructor will overwrite the + parent parameter with 'NOT_DEFINED' as it will be the root node. + If the prnt parameter is given as NOT_DEFINED then it is understood + that a new root is required.The file will then have a new root. + */ + protected Node(RandomAccessFile file,String fileName, long prnt,int elmtType, FileHdr flHdr) + throws IOException, NodeWriteException + { + this.file = file; + fileHdr = flHdr; + //initialise local variables + this.fileName = fileName; + elements = new Element[MAX]; + nodeMBR = new Rect();//remove + int size;//size of the element type + /* Though there is not much difference between LeafElement and NonLeafElement but we still use + the if condition as there may sometime in the future come a case where they differ. + But again then again to incorporate such change we must make MAX dynamic with the type of the element + we have. + */ + if(elmtType == NONLEAF_NODE) + size = NonLeafElement.sizeInBytes(); + else + size = LeafElement.sizeInBytes(); + try{ + /*a new file with an empty root node*/ + //if((file.length() <= (FILE_HDR_SIZE+2))){//no nodes written + if(fileHdr.getRootIndex() == NOT_DEFINED){//no nodes written + //writing the file header + fileHdr.writeFileHeader(1,0); + //local variables + nodeIndex = 0;//this is root - though empty + //isNodeEmpty = true; + //write node header + writeNodeHeader(fileHdr.rootIndex,0,NOT_DEFINED,size,elmtType); + } + /*for an existing file with a new node*/ + else{ + //see if any free node exists + try{ + nodeIndex = fileHdr.pop(); + } + catch(StackUnderflowException e){//else + nodeIndex = fileHdr.totalNodes++;//new node index + } + //local variables + //isNodeEmpty = true; + if(prnt == NOT_DEFINED)/*new Node is the root node.*/ + fileHdr.writeFileHeader(fileHdr.totalNodes,nodeIndex); + else/*new node is any other node*/ + fileHdr.writeFileHeader(fileHdr.totalNodes,fileHdr.rootIndex); + //write the node + writeNodeHeader(nodeIndex,0,prnt,size,elmtType); + } + + return; + } + catch(IOException e){ + throw new IOException("Node.Node(new) : " + e.getMessage()); + } + } + /** + Reading existing nodes. But if this a new file then it will create the + file and make a new root node. + */ + protected Node(RandomAccessFile file,String fileName,long ndIndex,FileHdr flHdr) + throws FileNotFoundException,IOException,NodeReadException, NodeWriteException + { + //check whether file is new or old + //see whether the user must be specified or not if it is a new file + fileHdr = flHdr; + this.file = file; + this.fileName = fileName; + elements = new Element[MAX]; + nodeMBR = new Rect();//remove + //a new file with an empty root node + //if(file.length() <= (FILE_HDR_SIZE+2)){//new file with no nodes + if(fileHdr.getRootIndex() == NOT_DEFINED){//no nodes written + try{ + //write file header + fileHdr.writeFileHeader(1,0); + //local variables + nodeIndex = 0;//this is root - though empty + //isNodeEmpty = true; + //write node header + writeNodeHeader(fileHdr.rootIndex, 0, NOT_DEFINED, LeafElement.sizeInBytes(), LEAF_NODE); + } + catch(IOException e){ + throw new IOException("Node.constructor : Can't write to fileHeader and/or node " + e.getMessage()); + } + } + //if an old file with an existing node + else{ + //if out of bond index + if((FILE_HDR_SIZE+(NODE_SIZE*ndIndex)) > file.length()) + throw new NodeReadException("Node.Node.: nodeIndex is out of bound"); + //update the local variable + this.nodeIndex = ndIndex; + //read all the values into local variables from the node + refreshNode(); + } + } + + /** + A stupid internal constructor for the clone method. + */ + protected Node(RandomAccessFile file,String fileName,long nodeIndex, boolean sorted, + Element[] elmts, FileHdr fileHdr, int totalElements,long parent,int elmtSize, + int elmtType, boolean dirty, Rect nodeMBR)//remove + { + try{ + //Integer intVal; + this.file = file; + this.dirty = dirty; + this.fileName = new String(fileName.toCharArray()); + this.nodeIndex = nodeIndex; + //this.isNodeEmpty = isNodeEmpty; + this.sorted = sorted; + this.nodeMBR = new Rect(nodeMBR);//remove + this.elements = new Element[elmts.length]; + for(int i=0; i (MAX-1)) || (totalElements > index+1 )) + throw new NodeReadException("Node.readElement: Index value not correct"); + try + { + int minX,minY,maxX,maxY; + //create a buffer + byte[] data = new byte[NODE_SIZE]; + seekCurrNode(); + file.read(data); + DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data)); + //skip the header - check for error value + int skipValue = NODE_HDR_SIZE + (elementSize * (int)index); + if(ds.skipBytes(skipValue) != skipValue) + throw new NodeReadException("Can't read buffer: Header or index wrong"); + //read the points + minX = ds.readInt(); + minY = ds.readInt(); + maxX = ds.readInt(); + maxY = ds.readInt(); + Rect Rectangle = new Rect(minX,minY,maxX,maxY); + if(elementType == LEAF_NODE){ + long ptr = ds.readLong(); + return(new LeafElement(Rectangle, ptr)); + } + //if non leaf type then... + long nodePtr = ds.readLong(); + return(new NonLeafElement(Rectangle, nodePtr)); + } + catch(Exception e){ + throw new NodeReadException("Node.readElement: " +e.getMessage()); + } + } + /** + This method delets the element with the given index from the node. + It rewrites the node. + This method now also being used to write the whole node to the file. + @param index The element to delete. Give -1 if the whole node is to be flushed. + @param force Whether to force IO. As this method is also used to write the whole node, this was + required. + @return thengaa! + XXX : This is till not correct. + */ + public void deleteElement(int index, boolean force) + throws IllegalValueException, NodeWriteException + { + if((index > (totalElements-1))) + throw new IllegalValueException("Node.deleteElement: index out of bound"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + int j = -1; + try{ + nodeMBR = new Rect();//remove + ByteArrayOutputStream bs = null; + DataOutputStream ds = null; + if(fileHdr.isWriteThr() || force){ + bs = new ByteArrayOutputStream(NODE_SIZE); + ds = new DataOutputStream(bs); + if(index < 0) + ds.writeInt(totalElements); + else + ds.writeInt(totalElements - 1); + ds.writeLong(parent); + ds.writeInt(elementSize); + ds.writeInt(elementType); + } + for(int i=0; i0) + System.arraycopy(elements,j+1,elements,j,(totalElements-j)); + // else + // isNodeEmpty = true; + } + }catch(Exception e){ + System.out.println("Node.deleteElement : Error while updating " + +"local variable...reading back from file.."); + try{ + refreshNode(); + System.out.println("...successful"); + }catch(IOException ex){ + setDirty(true); + System.out.println("..node corrupted, rebuild tree ...quitting"); + throw new NodeWriteException("Node.deleteElement : Can't delete element"); + } + } + } + /**to add an element at the end + As elements are allocated to this node, each allocated + element's children node's parent are reset. This is simply because the + new node index(for elmt) would be different from the old + ones(if any). +
Note:-This again is for non leaf node only. + */ + public void insertElement(Element elmt) + throws NodeWriteException, NodeFullException + { + //check for space + if((totalElements == MAX)) + throw new NodeFullException("Node.insertElement: Node full"); + //check if it is an empty node or not + //if(!isNodeEmpty){//if not empty + if(totalElements > 0){//if not empty + if(elmt.getElementType() != elementType) + throw new NodeWriteException("Node.insertElement: Wrong element type"); + if(((totalElements+1)*elementSize) > NODE_BODY_SIZE)//no space left + throw new NodeWriteException("Node.insertElement: Node size is becoming more than allowed"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + writeLastElement(elmt); + } + else{//else set the header values depending upon the new object header + writeLastElement(elmt); + } + //update the children's parents + if( elmt.getElementType() == Node.NONLEAF_NODE ){ + try{ + Node child = null; + if(fileHdr.isWriteThr()){ + child = new Node(file, fileName, elmt.getPtr(), fileHdr); + RTree.chdNodes.remove(fileName, child.getNodeIndex()); + } + else{ + child = RTree.chdNodes.getNode(file, fileName, elmt.getPtr(), fileHdr); + } + child.setParent(nodeIndex); + } + catch(Exception e){ + throw new NodeWriteException("Node.insertElement: " + e.getMessage()); + } + } + } + /** + This func. writes the element to the last position. + It also takes care of updating the node header. + Also updates the local variables. + Also takes care whether it is the first element in the node or not. + If it is the first element then it sets the node header accordingly. + + Least error checking - use it with care. + If the node is old and the new element type is of different type then it + will change the node header to the new type - so be very very careful! + In short don't call this method to insert an element different from the + already present element type. + */ + private void writeLastElement(Element elmt) + throws NodeWriteException + { + //taking backup in case of rollback + int oldElementSize = elementSize; + int oldElementType = elementType; + int oldTotalElements = totalElements; + //boolean oldIsNodeEmpty = isNodeEmpty; + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + try{ + //setting local variables first + if(elmt instanceof LeafElement){ + //size of the element + elementSize = LeafElement.sizeInBytes(); + elementType = LEAF_NODE; + } + else{ + //size of the element + elementSize = NonLeafElement.sizeInBytes(); + elementType = NONLEAF_NODE; + } + if(fileHdr.isWriteThr()){ + //byte[] data = new byte[elementSize]; + ByteArrayOutputStream bs = new ByteArrayOutputStream(elementSize); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeInt(elmt.getRect().getMinX()); + ds.writeInt(elmt.getRect().getMinY()); + ds.writeInt(elmt.getRect().getMaxX()); + ds.writeInt(elmt.getRect().getMaxY()); + ds.writeLong(elmt.getPtr());//see [2] - replace elements with elmt + + bs.flush(); + ds.flush(); + //write to the file + seekLastElement();//uses var. + file.write(bs.toByteArray()); + setDirty(false); + }else + setDirty(true); + //write the node header + writeNodeHeader(nodeIndex,totalElements+1,parent,elementSize,elementType); + //local variables + //isNodeEmpty = false; + elements[totalElements-1] = elmt; + nodeMBR.expandToInclude(elmt.getRect());//remove + } + catch(Exception e){ + //e.printStackTrace(); + //if anything goes wrong then set 'totalElements' will not + //be set hence it remains '0' + elementSize = oldElementSize; + elementType = oldElementType; + totalElements = oldTotalElements; + //isNodeEmpty = oldIsNodeEmpty; + throw new + NodeWriteException("Node.writeLastElement: Can't write element to file"); + } + } + + /**to add more than onr element at the end. + As elements are allocated to this node, each allocated element's children node's parent are reset. + This is simply because the new node index(for elmts) would be different from the old + ones(if any). none of the element should be null. +
Note:- Giving updateChldrn true will not update the parent from + cache, but would actually update the parent on disk. + @param elmts The elements that are to be entered. None of them should be null. + @param updateChldrn Whether to update the children. When we are moving from root to leaves, + this should be false. + */ + public void insertElement(Element[] elmts, boolean updateChldrn) + throws NodeWriteException, NodeFullException + { + //check for space + if(totalElements == MAX) + throw new NodeFullException("Node.insertElement: Node full or not adequate space"); + //check if it is an empty node or not + //if(!isNodeEmpty){//if not empty + if(totalElements > 0){//if not empty + if(elmts[0].getElementType() != elementType) + throw new NodeWriteException("Node.insertElement: Wrong element type"); + if(((totalElements+elmts.length)*elementSize) > NODE_BODY_SIZE)//no space left + throw new NodeWriteException("Node.insertElement: Node size is becoming more than allowed"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + writeLastElements(elmts); + } + else{//else set the header values depending upon the new object header + writeLastElements(elmts); + } + if(!updateChldrn) + return; + //update the children's parent from the disk and not the cache. + if( elmts[0].getElementType() == Node.NONLEAF_NODE ){ + try{ + for(int i=0; iare the first element then it sets the node header accordingly. + + Least error checking - use it with care. + If the node is old and the new element type is of different type then it + will change the node header to the new type - so be very very careful! + In short don't call this method to insert an element different from the + already present element type. + */ + private void writeLastElements(Element[] elmts) + throws NodeWriteException + { + //taking backup in case of rollback + int oldElementSize = elementSize; + int oldElementType = elementType; + int oldTotalElements = totalElements; + //boolean oldIsNodeEmpty = isNodeEmpty; + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + try{ + //setting local variables first + if(elmts[0] instanceof LeafElement){ + //size of the element + elementSize = LeafElement.sizeInBytes(); + elementType = LEAF_NODE; + } + else{ + //size of the element + elementSize = NonLeafElement.sizeInBytes(); + elementType = NONLEAF_NODE; + } + ByteArrayOutputStream bs = null; + DataOutputStream ds = null; + + //write node header + + if(fileHdr.isWriteThr()){ + setDirty(false); + bs = new ByteArrayOutputStream(Node.NODE_SIZE); + ds = new DataOutputStream(bs); + writeNodeHeader(nodeIndex, totalElements+elmts.length, parent, elementSize, elementType, ds); + //write the existing elements + for(int i=0; ids. Will also update the local variables. + It is assumed that the write pointer is correctly set in the o/p stream. + */ + private void writeNodeHeader(long nodeIdx, int totElmt,long prnt,int elmtSz,int elmtTp, + DataOutputStream ds) + throws IOException, NodeWriteException + { + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + if(fileHdr.isWriteThr()){ + ds.writeInt(totElmt);//total elements + ds.writeLong(prnt);//parent + ds.writeInt(elmtSz);//element size + ds.writeInt(elmtTp);//element type + ds.flush(); + setDirty(true); + }else + setDirty(true); + //update local variables + totalElements = totElmt; + parent = prnt; + elementSize = elmtSz; + elementType = elmtTp; + } + /** + will return the index of the node. + */ + public long getNodeIndex()//for new nodes + { + return(nodeIndex); + } + private void refreshNode()//see wherever it is called from for writethr + throws IOException + { + try{ + byte[] data = new byte[NODE_SIZE]; + seekCurrNode(); + //read the whole node + file.read(data); + //get the header details into the variables + DataInputStream ds = new DataInputStream(new ByteArrayInputStream(data)); + totalElements = ds.readInt(); + parent = ds.readLong();//ds.readInt(); + elementSize = ds.readInt(); + elementType = ds.readInt(); + if(totalElements <= 0)//set local variable + return; + // else + // isNodeEmpty = false; + //get the elements if present + if(totalElements < 1) + return; + nodeMBR = new Rect();//remove + int minX,minY,maxX,maxY; + for(int i=0; i< totalElements; i++){ + //read the points + minX = ds.readInt(); + minY = ds.readInt(); + maxX = ds.readInt(); + maxY = ds.readInt(); + Rect rectangle = new Rect(minX,minY,maxX,maxY); + nodeMBR.expandToInclude(rectangle);//remove + if(elementType == LEAF_NODE){// modified see [1] + long ptr = ds.readLong(); + elements[i] = new LeafElement(rectangle,ptr); + }else if(elementType == NONLEAF_NODE){//if non leaf type then... + long nodePtr = ds.readLong(); + elements[i] = new NonLeafElement(rectangle,nodePtr); + } + } + ds.close(); + } + catch(Exception e){ + throw new IOException("Node.refreshNode : Can't read from node header " + e.getMessage()); + } + + } + Rect[] getAllRectangles() + throws IllegalValueException + { + if(totalElements == 0) + throw new IllegalValueException("Node.getAllRectangles: No elements in the node"); + Rect[] rects = new Rect[totalElements]; + for(int i=0; ielmt. + The logic assumes that the elements are not sorted. + See the documentation for least enlargement logic. + */ + public Element getLeastEnlargement(Element elmt) + throws NodeEmptyException, IllegalValueException, NodeWriteException + { + if(elmt == null) + throw new IllegalValueException("Node.getBestFitElement : Element is null"); + //if(isNodeEmpty){//if there are no elements in the node + if(totalElements <= 0){//if there are no elements in the node + throw new NodeEmptyException("Node.getBestFitElement : Node does not have any elements"); + } + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + Element retElmt;//initialize with first element + int area; + + //get area of first MBR and call it the least area + int leastArea=(elements[0].getRect().getResultingMBR(elmt.getRect())).getArea(); + leastArea -= elements[0].getRect().getArea(); + if(elementType == Node.LEAF_NODE) + //Integer intVal = (Integer)elements[0].getPtr();//the org. code + retElmt = new LeafElement(elements[0].getRect(), elements[0].getPtr() ); + else + retElmt = new NonLeafElement(elements[0].getRect(), elements[0].getPtr()); + + //now check each of the elements + for(int i=1; i < totalElements; ++i){ + //get area of the MBR of the two rects. + area=(elements[i].getRect().getResultingMBR(elmt.getRect())).getArea(); + //remove the area of the encapsulating rect. + area -= elements[i].getRect().getArea(); + //check if it is the smallest rect + if(leastArea > area){ + leastArea = area; + if(elementType == Node.LEAF_NODE) + retElmt = new LeafElement(elements[i].getRect(), elements[i].getPtr()); + else + retElmt = new NonLeafElement(elements[i].getRect(), elements[i].getPtr()); + } + else if(leastArea == area){//Resovle ties by choosing the entry with the rectangle of smallest area." + if(retElmt.getRect().getArea() >= elements[i].getRect().getArea()){ + leastArea = area; + if(elementType == Node.LEAF_NODE) + retElmt = new LeafElement(elements[i].getRect(), elements[i].getPtr()); + else + retElmt = new NonLeafElement(elements[i].getRect(),elements[i].getPtr()); + } + } + } + return(retElmt); + } + /** + @return a boolean describing whether there is space for another element + */ + boolean isInsertPossible() + { + if(totalElements >= MAX) + return false; + else + return true; + } + + /** + See ./Logic.txt + Linear split Algo. + February 1003 - Now quad split algo. + @return First node would be the original node.Second would be the new one. + @param Element The new element to be inserted + @param slotIndex The index of the slot of this tree if any, else give NOT_DEFINED. + */ + public Node[] splitNode(Element elmtM1, long slotIndex) + throws RTreeException, NodeWriteException + { + if((totalElements < MAX) || (elmtM1.getElementType() != elementType)) + throw new RTreeException("Node.splitNode: Node is not full or new element is of wrong type"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + try{ + int rem = totalElements+1;//no. of elements remaining + the new element + Element[] elmtPlusOne = new Element[rem]; + for(int i=0;i 0){ + //if A needs all to equate m then give it all the elements - see Guttman + if((Node.MIN - elmtsInA) == rem){ + for(int i=0; i < elmtsGone.length; i++){ + //check if the elmt. is already assigned + if(elmtsGone[i] == 1){ + nodeA.insertElement(elmtPlusOne[i]);//read variable + elmtsGone[i] = 0;//element now is absent + elmtsInA++; + rem--; + //find the new MBR fro A + /*Commented because not required + mbrA = Rect.getResultingMBR(mbrA,elmtPlusOne[i].getRect()); + */ + //the end of the loop and method + } + } + } + //if B needs all to equate m then give it all the elements-see Guttman + else if((Node.MIN - elmtsInB) == rem){ + for(int i=0; i < elmtsGone.length; i++){ + //check if the elmt. is already assigned + if(elmtsGone[i] == 1){ + nodeB.insertElement(elmtPlusOne[i]);//read variable + elmtsGone[i] = 0;//element now is absent + elmtsInB++; + rem--; + //find the new MBR fro B + /*Commented because not required + mbrB = Rect.getResultingMBR(mbrB,elmtPlusOne[i].getRect()); + */ + //the end of the loop and method + } + } + } + //if both are ok + else{ + int i=-1; + //loop till an unassigned element is found + try{ + while((++i newAreaB){ + nodeB.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInB++; + rem--; + mbrB = newMBRB; + } + //if equal but A is smaller + else if(mbrA.getArea() < mbrB.getArea()){ + nodeA.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInA++; + rem--; + mbrA = newMBRA; + } + //if equal but B is smaller + else if(mbrA.getArea() > mbrB.getArea()){ + nodeB.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInB++; + rem--; + mbrB = newMBRB; + } + //also equal in area elmts. in A are less + else if(elmtsInA < elmtsInB){ + nodeA.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInA++; + rem--; + mbrA = newMBRA; + } + //also equal in area elemts. in B are less + else if(elmtsInA > elmtsInB){ + nodeB.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInB++; + rem--; + mbrB = newMBRB; + } + //choose any one + else{ + nodeA.insertElement(elmtPlusOne[i]);//read local variable + elmtsGone[i] = 0;//element now is absent + elmtsInA++; + rem--; + mbrA = newMBRA; + } + } + } + /* + Adjust the parent element so that it points to the first nodeA. + */ + if(parent != slotIndex){//NOT_DEFINED){ + Node parentN = null; + if(fileHdr.isWriteThr()) + parentN = new Node(file,fileName,parent,fileHdr); + else + parentN = RTree.chdNodes.getNode(file,fileName,parent,fileHdr); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,parent); + //get the parent element of nodes[0] + int parentElmtIndex = parentN.getElementIndex(nodeIndex); + parentN.modifyElement(parentElmtIndex, nodeA.getNodeIndex()); + } + Node[] ret = new Node[2]; + ret[0] = nodeA; + ret[1] = nodeB; + deleteNode(); + return(ret); + }catch(Exception e){ + e.printStackTrace(); + throw new RTreeException("Node.nodeSplit : " + e.getMessage()); + } + } + /** + * The linear Pick Seed method from Guttman. + * Assuming that we have only 2 dimensions. + *
this method is no longer used (certainly not deprecated), instead quadPickSeeds + * is being used + * @return the two picked indexes from the node + */ + private int[] lnrPickSeeds(Element[] elmts) + throws IllegalValueException + { + if(elmts.length <= 1) + throw new IllegalValueException("Node.lnrPickSeed : PickSeed not possible as there are no elements"); + //find the MBR of the set. + Rect mbr = elmts[0].getRect(); + for(int i=1; i= hlsX){ + hlsX = elmts[i].getRect().getMinX(); + hlsIdxX = i; + } + //highest low side for Y + if(elmts[i].getRect().getMinY() >= hlsY){ + hlsY = elmts[i].getRect().getMinY(); + hlsIdxY = i; + } + //lowest high side for X + if(elmts[i].getRect().getMaxX() <= lhsX){ + lhsX = elmts[i].getRect().getMaxX(); + lhsIdxX = i; + } + //lowest high side for Y + if(elmts[i].getRect().getMaxY() <= lhsY){ + lhsY = elmts[i].getRect().getMaxY(); + lhsIdxY = i; + } + } + //"Normalize the separations" - Guttman + //divide the separations along each dimensions by the width of the MBR + int[] retIdx = new int[2]; + int Xpair = (Math.abs(lhsX - hlsX))/mbr.getWidth(); + int Ypair = (Math.abs(lhsY - hlsY))/mbr.getHeight(); + if(Xpair > Ypair){ + //if both are the same rect then choose randomly + if(hlsIdxX == lhsIdxX){ + if(hlsIdxX != 0) + hlsIdxX = 0; + else + hlsIdxX = 1; + } + retIdx[0] = hlsIdxX; + retIdx[1] = lhsIdxX; + } + else if(Xpair < Ypair){ + /*if both are the same rect then choose randomly - an accidental + discovery*/ + if(hlsIdxY == lhsIdxY){ + if(hlsIdxY != 0) + hlsIdxY = 0; + else + hlsIdxY = 1; + } + retIdx[0] = hlsIdxY; + retIdx[1] = lhsIdxY; + } + else{//if normalized values are equal + //choose the pair with the least separation(not normalized sap.) + if((Math.abs(lhsX - hlsX)) >= (Math.abs(lhsY - hlsY))){ + if(hlsIdxX == lhsIdxX){ + if(hlsIdxX != 0) + hlsIdxX = 0; + else + hlsIdxX = 1; + } + retIdx[0] = hlsIdxX; + retIdx[1] = lhsIdxX; + } + else{ + if(hlsIdxY == lhsIdxY){ + if(hlsIdxY != 0) + hlsIdxY = 0; + else + hlsIdxY = 1; + } + retIdx[0] = hlsIdxY; + retIdx[1] = lhsIdxY; + } + } + return(retIdx); + } + /** + The quadratic Pick Seed method from Guttman. + Assuming that we have only 2 dimensions. This method is slightly slower than the linear method but + it results in better splits, besides it is much easier to implement. + @return the two picked indexes from the node + */ + private int[] quadPickSeeds(Element[] elmts) + throws IllegalValueException + { + if(elmts.length <= 1) + throw new IllegalValueException("Node.quadPickSeed : PickSeed not possible as there are no elements"); + int retIdx[] = new int[2]; + int mostIneff = Integer.MIN_VALUE;//area of the most inefficient pair + for(int i=0;i mostIneff){ + retIdx[0] = i; + retIdx[1] = j; + mostIneff = arr; + } + } + } + return retIdx; + } + public long getParent() + { + return(parent); + } + /** + * returns index of the element with the pointer passed in the parameter + * @param Object Depends upon the Element type. + * @return returns NOT_DEFINED if ptr is not found + */ + public int getElementIndex(long ptr/*Object ptr*/) + { + if(totalElements < 1) + return NOT_DEFINED; + for(int i=0; i totalElements) || (index < 0) || (elmt == null)) + throw new IllegalValueException("Node.modifyElmtMBR : index out of bound or MBR is null"); + + if(elmt.getElementType() != elementType) + throw new IllegalValueException("Node.modifyElmtMBR : Element of wrong type"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + if(fileHdr.isWriteThr()){ + ByteArrayOutputStream bs = new ByteArrayOutputStream(elementSize); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeInt(elmt.getRect().getMinX()); + ds.writeInt(elmt.getRect().getMinY()); + ds.writeInt(elmt.getRect().getMaxX()); + ds.writeInt(elmt.getRect().getMaxY()); + ds.writeLong(elmt.getPtr());//see [2] + + bs.flush(); + ds.flush(); + //write to the file + seekElement(index); + file.write(bs.toByteArray()); + setDirty(false); + }else + setDirty(true); + //adjsut in the local variable + elements[index].setRect(elmt.getRect()); + elements[index].setPtr(elmt.getPtr()); + //we do not recalculate the whole mbr if we do not need to + if(elmt.getRect().contains(elements[index].getRect()))//if previous MBR was smaller... + nodeMBR.expandToInclude(elmt.getRect()); + else//i guess we need to calculate + refreshNodeMBR();//remove + } + /** + Overloaded + */ + public void modifyElement(int index,long pointer) + throws IllegalValueException,IOException, NodeWriteException + { + if((index > totalElements) || (index < 0)){ + try{ + throw new IllegalValueException("Node.modifyElmtMBR : index out of bound for node "+nodeIndex); + }catch(Exception e){ + e.printStackTrace(); + } + } + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + if(fileHdr.isWriteThr()){ + ByteArrayOutputStream bs = new ByteArrayOutputStream(LONG_SIZE); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeLong(pointer);//ds.writeInt(pointer); + bs.flush(); + ds.flush(); + //write to the file + seekElementPtr(index); + file.write(bs.toByteArray()); + setDirty(false); + } + else + setDirty(true); + //adjsut in the local variable + elements[index].setPtr(pointer); + } + /** + Overloaded + */ + public void modifyElement(int index,Rect rect) + throws IllegalValueException,IOException, NodeWriteException + { + if((index > totalElements) || (index < 0)) + throw new IllegalValueException("Node.modifyElmtMBR : index out of bound or MBR is null"); + if(fileHdr.isWriteThr()) + RTree.chdNodes.remove(fileName,nodeIndex); + if(fileHdr.isWriteThr()){ + ByteArrayOutputStream bs = new ByteArrayOutputStream(Rect.sizeInBytes()); + DataOutputStream ds = new DataOutputStream(bs); + ds.writeInt(rect.getMinX()); + ds.writeInt(rect.getMinY()); + ds.writeInt(rect.getMaxX()); + ds.writeInt(rect.getMaxY()); + bs.flush(); + ds.flush(); + //write to the file + seekElement(index); + file.write(bs.toByteArray()); + setDirty(false); + }else + setDirty(true); + //adjsut in the local variable + elements[index].setRect(rect); + //remove + //we do not recalculate the whole mbr if we do not need to + if(rect.contains(elements[index].getRect())) + nodeMBR.expandToInclude(rect); + else//i guess we need to calculate + refreshNodeMBR();//remove + } + /** + This function runs a loop on the elements to calculate the total MBR. + Therefore in case if you already have loop that runs through each of the entries, + then it is better to calculate MBR in that loop without calling this method. + @throws IllegalValueException When there are no elements in the node. + */ + public Rect getNodeMBR() + throws IllegalValueException + { + //remove + if(totalElements < 1) + throw new IllegalValueException("Node.getNodeMBR: Node empty"); + return nodeMBR; + //In case of trouble remove the above line and commission the below written lines + /* + Rect ret = elements[0].getRect(); + for(int i=1; inodeMBR for the elements + */ + private void refreshNodeMBR() + { + nodeMBR = new Rect(); + for(int i=0; iNever Use .length field With the Returned Array + . Instead use getTotalElements(). + @return An element Array. + */ + public Element[] getAllElements() + { + return elements; + } + Element getElement(int index) + throws IllegalValueException + { + if((index < 0) || (index > totalElements-1)) + throw new IllegalValueException("Node.getElement Index out of bound"); + return elements[index]; + } + /** + Adds the node to the free stack. + Be very careful with this method because once called, this node may be + given to any new node even when you have not destroyed its object. + If the node is the only node then it updates the file header as well. +
Once called, there is no turning back!. + */ + public void deleteNode() + throws NodeWriteException + { + setDirty(false);//this is intentional + RTree.chdNodes.remove(fileName,nodeIndex);//we do not check for writeThr here + try{ + fileHdr.push(nodeIndex); + }catch(StackOverflowException e){ + }catch(IOException ex){ + throw new NodeWriteException(ex.getMessage()); + } + } + /** + * This method is added to sort the elements in this node to help sweepline algorithm. + */ + void sweepSort()//check out for null elements + { + if(elements != null && elements.length > 1 && sorted == false){ + Arrays.sort(elements, 0, totalElements, new rtree.join.CompElmtX()); + sorted = true; + }//if + }//sweepSort + /** + This is a new methos that will help the phylosophy where one should write to tbe cache only when + required. + @return true if needed write and written or false (not dirty). + */ + public boolean flush() + throws NodeWriteException + { + try{ + if(dirty && !fileHdr.isWriteThr()){ + deleteElement(-1, true); + setDirty(false); + return true; + }else + return false; + }catch(Exception e){ + e.printStackTrace(); + throw new NodeWriteException(e.getMessage()); + } + } + void setDirty(boolean val) + { + if(val)//dirty + sorted = false; + dirty = val; + } + public boolean isDirty() + { + return dirty; + } + +} diff --git a/DataExtractionOSM/src/rtree/NodeEmptyException.java b/DataExtractionOSM/src/rtree/NodeEmptyException.java new file mode 100644 index 0000000000..eefac8da6e --- /dev/null +++ b/DataExtractionOSM/src/rtree/NodeEmptyException.java @@ -0,0 +1,25 @@ +//NodeEmptyException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +import java.lang.Exception; + +/**when a node is empty + @author Prachuryya Barua +*/ +public class NodeEmptyException extends Exception +{ + NodeEmptyException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/NodeFullException.java b/DataExtractionOSM/src/rtree/NodeFullException.java new file mode 100644 index 0000000000..4669e1880e --- /dev/null +++ b/DataExtractionOSM/src/rtree/NodeFullException.java @@ -0,0 +1,27 @@ +//NodeFullException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; + +import java.lang.Exception; + +/**Exception when no. of elements increase, then the limited value, in a node. + +@author Prachuryya Barua +*/ +public class NodeFullException extends Exception +{ + public NodeFullException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/NodeReadException.java b/DataExtractionOSM/src/rtree/NodeReadException.java new file mode 100644 index 0000000000..719c323387 --- /dev/null +++ b/DataExtractionOSM/src/rtree/NodeReadException.java @@ -0,0 +1,26 @@ +//NodeReadException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; + +import java.lang.Exception; + +/**When some error arises when reading a node + @author Prachuryya Barua +*/ +public class NodeReadException extends Exception +{ + public NodeReadException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/NodeWriteException.java b/DataExtractionOSM/src/rtree/NodeWriteException.java new file mode 100644 index 0000000000..74d823c6b3 --- /dev/null +++ b/DataExtractionOSM/src/rtree/NodeWriteException.java @@ -0,0 +1,26 @@ +//NodeWriteException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +//package rtree; + +import java.lang.Exception; + +/**for any error while writing to a node + @author Prachuryya Barua +*/ +public class NodeWriteException extends Exception +{ + public NodeWriteException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/NonLeafElement.java b/DataExtractionOSM/src/rtree/NonLeafElement.java new file mode 100644 index 0000000000..8fda20ac64 --- /dev/null +++ b/DataExtractionOSM/src/rtree/NonLeafElement.java @@ -0,0 +1,155 @@ +//NonLeafElement.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +/** + Anybody outside the package need not be concerned with this class. + Element that will be in a non leaf node + @author Prachuryya Barua +*/ +public class NonLeafElement extends Element +{ + /**will contain file pointer pointing to the child node*/ + long nodePtr; + public NonLeafElement( Rect nodeRect,long nodePtr) + { + super(nodeRect); + this.nodePtr = nodePtr; + } + /**if possible make this function abstract and static in the parent class + depends upon the size of the pointer + */ + public static int sizeInBytes() + { + return( Rect.sizeInBytes() + Node.LONG_SIZE); + } + /** + This can be the chile node pointer. + */ + // public Object getPtr()//this is an integer object + // { + // return(new Integer(nodePtr)); + // } + public long getPtr()//this is an integer object + { + return nodePtr; + } + + public int getElementType() + { + return Node.NONLEAF_NODE; + } + // void setPtr(Object ptr) + // throws IllegalValueException + // { + // if(!(ptr instanceof Integer)) + // throw new IllegalValueException("rtree.NonLeafElement.setPtr: pointer shoild be Integer"); + // nodePtr = ((Integer)ptr).intValue(); + // } + public void setPtr(long ptr) + { + nodePtr = ptr; + } + public String toString() + { + return (super.toString()+"\n\tnodePointer: "+nodePtr); + } + /** + A merge-sort routine for the Packing algo. + @param rect the array to sort + @param on if 0 then sort on X else on Y(i.e for 1) + */ + public static void sort( Element[] elmts,int on) + { + twoWayMerge(elmts,0,elmts.length-1,on); + } + + static void twoWayMerge(Element[] elmts,int start,int finish,int on) + { + try{ + int size = finish - start+1; + if(size <= 2){//last two elements - simple swap + if(size < 2) + return; + int midValI = getMid(elmts[start],on); + int midValJ = getMid(elmts[finish],on); + Element temp; + if(midValI > midValJ){ + temp = elmts[start]; + elmts[start] = elmts[finish]; + elmts[finish] = temp; + } + return; + } + Double middle = new Double(start+finish); + middle = new Double(Math.ceil(middle.doubleValue()/2)); + twoWayMerge(elmts,start,middle.intValue(),on); + twoWayMerge(elmts,middle.intValue(),finish,on); + simpleMerge(elmts,start,middle.intValue(),finish,on); + } + catch(Exception e){ + System.out.println("rtree.Element.twoWayMerge: probably index out of bound"); + //e.printStackTrace(); + } + } + //simple merge + private static void simpleMerge( Element[] elmts,int first,int second,int third,int on) + throws Exception + { + int i = first; + int j = second; + int l = 0; + int midValI; + int midValJ; + Element[] temp = new Element[third-first+1]; + while((i < second) && (j <= third)){//loop till one lasts + //get the mid values in the given dimension + midValI = getMid(elmts[i],on); + midValJ = getMid(elmts[j],on); + if(midValI <= midValJ) + temp[l++] = elmts[i++]; + else + temp[l++] = elmts[j++]; + } + //copy the rest + if(i >= second)//give second section + while(j <= third) + temp[l++] = elmts[j++]; + else + while(i < second)//give first section + temp[l++] = elmts[i++]; + System.arraycopy(temp,0,elmts,first,temp.length); + } + /** + A private class to calculate the mid value in given dimension + */ + private static int getMid( Element elmt,int on) + { + if(on == 0) + return ((elmt.getRect().getMaxX() + + elmt.getRect().getMinX())/2); + else + return ((elmt.getRect().getMaxY() + + elmt.getRect().getMinY())/2); + } + public Object clone() + { + try{ + return new NonLeafElement(new Rect(Rectangle.getMinX(), Rectangle.getMinY(), + Rectangle.getMaxX(), Rectangle.getMaxY()), nodePtr); + } + catch(Exception e){ + e.printStackTrace(); + return null; + } + } +} diff --git a/DataExtractionOSM/src/rtree/Pack.java b/DataExtractionOSM/src/rtree/Pack.java new file mode 100644 index 0000000000..cca3c92926 --- /dev/null +++ b/DataExtractionOSM/src/rtree/Pack.java @@ -0,0 +1,248 @@ +//Pack.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; +import java.io.*; +import java.util.*; +/** + Modified again on 9/1/2003 + This class can now be used Pack rtrees at run time i.e an rtree object can now be packed and later used + without recreating the rtree. +

Original comments + A utility class that packs a rtree. +
Pack is a special utility class. This class can also be used to maintain + a R-Tree after many insertions and deletions.(Just like defragmentation + in windows). +

Never create more than one instance of this class. +
Never run the methods of this class in any other thread except the main + thread and make sure it is the only thread running. +
Positively remember to reinitialise all the rtree objects after you + call packTree.
+ @author Prachuryya Barua +*/ +public class Pack +{ + public Pack(){}; + + /** + Added this new method that takes a list of Elements and builds a + */ + public synchronized int packTree(List elmts, String newFile) + { + try{ + if(elmts.size() <= Node.MAX){ + RTree rtree = new RTree(newFile); + for(int i=0; i**FLUSH THE RTREE BEFORE CALLING** +
Prepocess the file and sort the rectangles +
Load into file +
Recursively pack above MBRs to nodes at the next level. +
If you give the new file name same as the old one then the old would + be overwritten. One word of caution, whichever new file name you give, it + would be overwritten. + @param rtree the rtree object to pack + @param newFile the new rtree file after packing + @return 0 if successfully created a new file, +
1 if there is no need to pack the file, in this case a new + file is not created and the old file is left untouched, +
Greater than zero if all fail. + */ + public synchronized int packTree(RTree rtree,String newFile) + { + try{ + if(rtree == null) + throw new IllegalArgumentException("PackTree.packTree: rtree null"); + List elmts = rtree.getAllElements(); + //RTree.chdNodes.removeAll(); + int ret = packTree((Element[])elmts.toArray(new Element[elmts.size()]), rtree, newFile); + return ret; + }catch(Exception e){ + e.printStackTrace(); + return 2; + } + } + private int packTree(Element[] elmts, RTree rtree, String newFile) + { + try{ + //long t = System.currentTimeMillis(); + //rtree.flush(); + File tmpPckFile = File.createTempFile("pack",null); + RandomAccessFile rFile = new RandomAccessFile(tmpPckFile.getAbsolutePath(),"rw"); + + if(newFile.equalsIgnoreCase(rtree.getFileName())){//we need a write lock + rtree.getFileHdr().lockWrite(); + } + /*the following is required as we may pack an existing tree.. until we find a way to remove nodes of + a particular rtree*/ + RTree.chdNodes.removeAll(); + //rtree.getFileHdr().getFile().getFD().sync(); + if(elmts.length <= Node.MAX)//change this for the first method + return(1); + System.out.println("Pack.packTree : Size of elmts: "+ elmts.length); + + packRec(rFile,tmpPckFile,elmts,elmts.length); + + //craete the new file + File fo = new File(newFile); + //delete the new file if it exists !! + if(fo.exists()){ + fo.delete(); + fo.createNewFile(); + } + //overwrite the old rtree file with the temp file + FileInputStream fis=new FileInputStream(tmpPckFile); + FileOutputStream fos=new FileOutputStream(fo); + int i=fis.available(); + byte b[]=new byte[i]; + while((i=fis.read(b))!=-1) + fos.write(b); + fos.close(); + fis.close(); + rFile.close(); + tmpPckFile.deleteOnExit(); + //System.out.println("Pack.packTree : packing took " + (System.currentTimeMillis() - t)); + return(0); + } + catch(Exception e){ + e.printStackTrace(); + System.out.println("rtree.RTree.pack: Could not pack rtree, the destination file may be corrupted."); + return(2); + } + finally{//delete the source file header + synchronized(rtree){ + //Here we have the old and the new file as same.. so we update the header + try{ + rtree.updateHdr(); + if(newFile.equalsIgnoreCase(rtree.getFileName())){//we need a write lock + rtree.getFileHdr().unlock();//relaese this lock as this header will be lost for ever + } + }catch(Exception e){ + System.out.println("Pack.packTree : The pack tree is made but some other error hs occured. " + +"It is recomended to restart the application"); + if(newFile.equalsIgnoreCase(rtree.getFileName()))//we need a write lock + rtree.getFileHdr().unlock();//relaese this lock as this header will be lost for ever + } + }//synchronized + } + } + private void packRec(RandomAccessFile rFile,File tmpPckFile, Element[] elmts,int length) + throws Exception + { + //P the no. of leaf nodes - ceil(objects/max objects per node) + Double temp = new Double(Node.MAX);//temp + temp = new Double(Math.ceil(length/temp.doubleValue())); + //int P = temp.intValue();//leaves + //no. of vertical slices + temp = new Double(Math.ceil(Math.sqrt(temp.doubleValue()))); + int S = temp.intValue(); + //System.out.println("total slices: "+S); + Slice sls[] = new Slice[S]; + + //sort all the rectangles on X axis + NonLeafElement.twoWayMerge(elmts,0,length-1,0); + + //divide into slices + int start = 0; + int end; + for(int i=0; i1:Call flush after single or multiple inserts. In affect before the application + * shuts down, the flush method flushes all the rtrees. + *

2:Do not run more than one instance of this application. The package + * cannot handle more than one instance of the application as all the locking + * is done in the code itself(Monitors) and not on the hard-disk file. + *

3:The file name (of the rtree) is case insensitive. + *

4:The package is thread proof, i.e you can run as many threads as + * you want, not worrying about concurrent updations. The package will handle the + * situation of concurrent reads and writes. Again, it can take care of threads + * of only one process(Application) and not for more than one process of the program. + *

5:For immediate effects of tree writes, give the thread that needs + * to write to the file a high priority. This will further speed up tree writes. + *

6:Give messages like "Updating, please wait..." to the user when + * calling any of the methods that modifies the tree as the thread may have to + * wait on a lock variable. + *

7:The package maintains a queue of all threads that need to wait on some lock. + * The sequence of excecution of the threads is dependent on that queue. All the actions are fired in + * the order in which they were received.
In short the tree is perfectly concurrent. + *

8:For developers: Always obtain a lock from the lockRead or + * lockWrite method before going into a public method of the + * RTree class. Unlock by calling the unlock method. + * See any existing method to understand the mechanism. + *

9:To adjust the cache buffer size, see the Node class documentation. + * @author Prachuryya Barua + ******************************************************************************************************/ +public class RTree //the tree that would be made +{ + /**Caution: The file name (of the rtree) is case insensitive in spite + of the fact that this package was developed on a Linux(RH7.0) platform. + */ + protected String fileName; + static Map fileList;//the no. of files open + // static for the other way + protected FileHdr fileHdr; + public static CachedNodes chdNodes; + /**Inner class for the fileList vector - A List of files*/ + class Header + { + FileHdr flHdr; + String fileName; + Header(FileHdr flH,String name) + { + fileName = name; + flHdr = flH; + } + } + public RTree(String fileName) + throws RTreeException + { + try{ + this.fileName = fileName; + if(fileList == null) + fileList = new HashMap(); + synchronized(fileList){//this may give problem + if(fileList.get(fileName) != null){ + fileHdr = ((Header)fileList.get(fileName)).flHdr; + return; + } + //a new file + fileList.put(fileName, new Header(new FileHdr(Node.FREE_LIST_LIMIT, fileName),fileName)); + fileHdr = ((Header)fileList.get(fileName)).flHdr; + //the cache of nodes - one cache for all the tree files. + if(chdNodes == null) + chdNodes = new CachedNodes(); + } + } + catch(Exception e){ + throw new RTreeException("RTree.RTree: " +e.getMessage()); + } + } + /** + This method is used to ask the fileHdr to update itself. This method is package parivate used by + Pack class only. + */ + void updateHdr() + throws RTreeException, IOException, FileNotFoundException, NodeWriteException + { + Header tmp = (Header)fileList.get(fileName); + if(tmp != null){ + //chdNodes.removeAll();//XXX check this out + fileHdr.update(fileName); + } + } + + public Node getReadNode(long index) throws RTreeException + { + try{ + return chdNodes.getReadNode(fileHdr.getFile(), fileName, index, fileHdr); + }catch(Exception e){ + throw new RTreeException ("RTree.getSortedNode : " + e.getMessage()); + } + } + + public String getFileName() + { + return fileName; + } + /** + Another package private method for getting the file header + */ + public FileHdr getFileHdr() + { + return fileHdr; + } + public void flush() + throws RTreeException + { + fileHdr.lockWrite(); + try{ + fileHdr.flush(); + chdNodes.flush(); + }catch(Exception e){ + throw new RTreeException(e.getMessage()); + }finally{ + fileHdr.unlock(); + } + } + /** + * Adjust Tree from Guttman the Great. + * @param Node[] The nodes that was has the new element and also the element + * that resulted from the splt(if any).i.e N-node[0], NN-nodes[1] + * Note:- This method is functionally very much coupled with Node.spliNode() + * @param node The two new nodes caused by split. + * @param slotIndex The index of the slot of this tree if any, else give NOT_DEFINED. + * @return The new root (if it was created). If no new root was created then returns null. + */ + protected Node adjustTree(Node[] nodes, long slotIndex) + throws RTreeException + { + try{ + //if(nodes[0].getParent() == Node.NOT_DEFINED){//original + if(nodes[0].getParent() == slotIndex){ + if(nodes[1] != null){//if root is split + Node newRoot; + if(fileHdr.isWriteThr()) + newRoot = new Node(fileHdr.getFile(),fileName, slotIndex, Node.NONLEAF_NODE, + ((Header)fileList.get(fileName)).flHdr); + else + newRoot = chdNodes.getNode(fileHdr.getFile(),fileName, slotIndex, Node.NONLEAF_NODE, + ((Header)fileList.get(fileName)).flHdr, nodes[0]); + NonLeafElement branchA = new NonLeafElement(nodes[0].getNodeMBR(),nodes[0].getNodeIndex()); + NonLeafElement branchB = new NonLeafElement(nodes[1].getNodeMBR(),nodes[1].getNodeIndex()); + newRoot.insertElement(branchB); + newRoot.insertElement(branchA); + return newRoot; + } + return null; + }else{ + //where the new element is inserted + Node[] insertedNode = new Node[2]; + /* + set the parent element's MBR equal to the nodeA's MBR. + */ + //the parent of this node + Node parentN; + if(fileHdr.isWriteThr()) + parentN = new Node(fileHdr.getFile(),fileName,nodes[0].getParent(),fileHdr); + else + parentN = chdNodes.getNode(fileHdr.getFile(),fileName,nodes[0].getParent(),fileHdr); + //get the parent element of nodes[0] + //Integer intValue = new Integer(nodes[0].getNodeIndex()); + int parentElmtIndex = parentN.getElementIndex(nodes[0].getNodeIndex()/*intValue*/); + //adjust the parent element's MBR + parentN.modifyElement(parentElmtIndex,nodes[0].getNodeMBR()); + insertedNode[0] = parentN; + insertedNode[1] = null; + //if it is an split node add its entry in the parent + if(nodes[1] != null){ + NonLeafElement elmtNN = new NonLeafElement(nodes[1].getNodeMBR(),nodes[1].getNodeIndex()); + try{//if another insert is possible + parentN.insertElement(elmtNN); + insertedNode[0] = parentN; + insertedNode[1] = null; + }catch(NodeFullException e){ + insertedNode = parentN.splitNode(elmtNN, Node.NOT_DEFINED); + } + } + return adjustTree(insertedNode, slotIndex); + } + } + catch(Exception e){ + e.printStackTrace(); + throw new RTreeException("RTree.adjustTree: "+e.getMessage()); + } + } + /** + Pass a LeafElementobject. + */ + public void insert(Element elmt)//Leaf + throws RTreeInsertException + { + fileHdr.lockWrite(); + Node node = null; + try{ + //the node into which to insert + node = chooseLeaf(elmt); + //System.out.println("Returned:"+node.getNodeIndex()); + Node[] newNodes = new Node[2]; + try{ + node.insertElement(elmt);//if another insert is possible + newNodes[0] = node; + newNodes[1] = null; + } + //if another insert is not possible + catch(NodeFullException e){ + newNodes = node.splitNode(elmt, Node.NOT_DEFINED); + } + adjustTree(newNodes, Node.NOT_DEFINED); + } + catch(Exception e){ + //e.printStackTrace(); + throw new RTreeInsertException("RTree.insert: " + e.getMessage() + " for " + + Thread.currentThread()); + } + finally{ + fileHdr.unlock(); + } + } + /** + See Guttman the Great. + */ + private Node chooseLeaf(Element elmt) + throws IllegalValueException, RTreeException + { + try{ + //get the root node + long root = fileHdr.getRootIndex(); + Node node = null; + if(fileHdr.isWriteThr()) + node = new Node(fileHdr.getFile(), fileName,root,fileHdr); + else + node = chdNodes.getNode(fileHdr.getFile(), fileName,root,fileHdr); + switch (node.getElementType()){ + case Node.LEAF_NODE : + break; + case Node.NONLEAF_NODE : + //repeat till you reach a leaf node + while(true){ + //get the best fitting rect from the node + Element nextElmt = node.getLeastEnlargement(elmt); + if(nextElmt.getElementType() == Node.LEAF_NODE) + break; + if(fileHdr.isWriteThr()) + node = new Node(fileHdr.getFile(), fileName, nextElmt.getPtr(), fileHdr); + else + node = chdNodes.getNode(fileHdr.getFile(), fileName, nextElmt.getPtr(), fileHdr); + } + break; + default : + throw new IllegalValueException("RTree.chooseLeaf: Node corrupt, Illegal element type in " + +"node"); + } + return node; + } + catch( IllegalValueException e){ + throw new IllegalValueException("RTree.chooseLeaf: "+e.getMessage()); + } + catch(Exception e){ + e.printStackTrace(); + throw new RTreeException("RTree.chooseLeaf: " + e.getMessage()); + } + } + /** + given the leaf element, this method deletes the element from the tree + compairing its Rect and pointer with the similar entries in the tree. + @throws ElementNotException when the given element is not found. + */ + public void delete(LeafElement elmt) + throws RTreeException,ElementNotFoundException + { + fileHdr.lockWrite(); + long root; + if(elmt == null) + throw new RTreeException("RTree.delete: Rect is null"); + try{ + if(fileHdr.isWriteThr()) + chdNodes.removeAll(); + root = fileHdr.getRootIndex();//FileHdr.getRootIndex(fileName); + //find the leaf that contains the element + Node delNode; + if(fileHdr.isWriteThr()) + delNode = findLeaf(new Node(fileHdr.getFile(),fileName,root,fileHdr),elmt); + else + delNode = findLeaf(chdNodes.getNode(fileHdr.getFile(),fileName,root,fileHdr),elmt); + //if found... + if(delNode != null){ + Element[] elmts = delNode.getAllElements();//all the elements + int totElmts = delNode.getTotalElements();//total elements + //index of the desired element + int childIndex = Node.NOT_DEFINED; + //find the index of the element that has to be deleted + for(int i=0;imay contain the required element. + */ + private Node findLeaf(Node node,LeafElement elmt) + throws IllegalValueException,FileNotFoundException,IOException, NodeReadException, NodeWriteException + { + if((node == null) || (elmt == null)) + throw new IllegalValueException("RTree.findLeaf: Node is null"); + Node nd = null; + Element[] allElmt = node.getAllElements(); + int totElements = node.getTotalElements(); + //Integer elmtPtr = (Integer)elmt.getPtr(); + for(int i=0; iGuttman the Great. + * An vector is returned. The tree is traversed recusively in post order. + * @return If the file is empty or search rect. is out of scope then the method returns a zero size vector. + */ + public List overlaps(Rect rect) + throws RTreeException,FileNotFoundException + { + fileHdr.lockRead(); + //System.out.println("RTree.overlaps : in for thread " + Thread.currentThread().toString()); + long root; + if(rect == null) + throw new RTreeException("RTree.overlaps: Rect is null"); + root = fileHdr.getRootIndex(); + try{ + Node node = chdNodes.getReadNode(fileHdr.getFile(),fileName,root, fileHdr); + List ret = getRPostOvrlap(node, rect); + return ret; + //return(getRPostOvrlap(chdNodes.getNode(fileHdr.getFile(),fileName,root, fileHdr), rect)); + } + catch(Exception e){ + throw new RTreeException("RTree.overlaps: "+e.getMessage()); + } + finally{ + //System.out.println("RTree.overlaps : out for thread " + Thread.currentThread().toString()); + fileHdr.unlock(); + } + } + /** + Given any node it traverses a tree in a recursive post order manner + fetching all overlaping elements in the leaves. + */ + private List getRPostOvrlap(Node node, Rect rect) + throws IllegalValueException,FileNotFoundException,NodeReadException,IOException, NodeWriteException + { + if((node == null) || (rect == null)) + throw new IllegalValueException("RTree.getRPostOvrlap: Node is null"); + List list = new ArrayList(); + //System.out.println("Nodes visited:"+node.getNodeIndex()); + Element[] elmts = node.getAllElements(); + int totElements = node.getTotalElements(); + for(int i=0; ipostorder + */ + public List getAllElements() + throws RTreeException, FileNotFoundException + { + //fileHdr.enter(Node.READ); + fileHdr.lockRead(); + //System.out.println("RTree.getAllElements : in for thread " + Thread.currentThread().toString()); + long root; + root = fileHdr.getRootIndex(); + try{ + return(trvsRPost(chdNodes.getReadNode(fileHdr.getFile(),fileName,root,fileHdr),false)); + } + catch(Exception e){ + //e.printStackTrace(); + throw new RTreeException("RTree.getAllElements: " +e.getMessage()); + } + finally{ + //fileHdr.leave(); + //System.out.println("RTree.getAllElements : out for thread " + Thread.currentThread().toString()); + fileHdr.unlock(); + } + } + /** + Traverses the tree recursively in post order. + The second parameter is for the delete method. As it goes through the nodes + returning the leafelements it also deletes the nodes. + This feature is not required for any other methods hence set del as + false for all other cases. + */ + private List trvsRPost(Node node,boolean del) + throws IllegalValueException,FileNotFoundException,NodeReadException,IOException, NodeWriteException + { + if((node == null)) + throw new IllegalValueException("RTree.getRPostOvrlap: Node is null"); + List list = new ArrayList(); + Element[] elmts = node.getAllElements(); + int totElements = node.getTotalElements(); + //System.out.println("Nodes visited:"+node.getNodeIndex()) + for(int i=0; ipreorder manner. + */ + public void printTree() + throws RTreeException,FileNotFoundException + { + fileHdr.lockRead(); + long root; + root = fileHdr.getRootIndex(); + try{ + trvsRPrePrint(chdNodes.getReadNode(fileHdr.getFile(),fileName,root,fileHdr)); + } + catch(Exception e){ + throw new RTreeException("RTree.printTree: "+e.getMessage()); + } + finally{ + fileHdr.unlock(); + } + } + /** + This method will return MBR of the whole tree. + */ + public Rect getTreeMBR() + { + fileHdr.lockRead(); + long root; + try{ + root = fileHdr.getRootIndex(); + Node node = chdNodes.getReadNode(fileHdr.getFile(),fileName,root,fileHdr); + return node.getNodeMBR(); + } + catch(Exception e){ + return null; + } + finally{ + fileHdr.unlock(); + } + } + public void deleteAllElements() + throws RTreeException + { + fileHdr.lockWrite(); + try{ + chdNodes.removeAll(); + fileHdr.resetHeader(); + }catch(Exception e){ + throw new RTreeException("RTree.deleteAllElements : " + e.getMessage()); + } + finally{ + fileHdr.unlock(); + } + } + + /** + Traverses the tree recursively in post order. + */ + private void trvsRPrePrint(Node node) + throws IllegalValueException, + FileNotFoundException,NodeReadException, + IOException,NodeWriteException + { + if((node == null)) + throw new IllegalValueException("RTree.trvsRPrePrint: Node is null"); + Element[] elmts = node.getAllElements(); + int totElements = node.getTotalElements(); + System.out.println(node.toString()); + for(int i=0; iRead Me Well.
+ The Nearest Neighbour(NN) search from Roussopoulos and Cheung. +
The returned leaf elements are sorted in ascending order of their + differences from the query point.
If the no. of leaf elements found + are less then n, then the rest of the values in the returend array + are null.
Give the limit(distance) within which you want to search. + The limit is in the same unit as the coordinates of the MBRs.

There may + be some objects in the tree which come within the region but are so big + that their size makes them extend much beyond the given region. + Such objects would also be considered. + If you do not want any limit then give Long.MAX_VALUE in range. + You can also search for presence of any object at the given point by giving + range as 0. + Also required are the no. of objects that need to be fetched(N-Nearest objects). +
The value of range is actually square of the distance you want. + Therefor if you want to search in an area of 10cm, give the range as 100. + @param pt the query point. + @param range the region within which you want to search. + @param n the number of objects required. + @return the leaf elements found near the point.The length of the returned + array would be equal to n. + */ + public ABL[] nearestSearch(Point pt,long range,int n) + throws RTreeException, IllegalValueException + { + fileHdr.lockRead(); + if((pt == null) || (range < 0) || (n <= 0)) + throw new IllegalValueException("RTree.nearestSearch: Illegal arguments"); + try{ + long root = fileHdr.getRootIndex(); + ABL[] elmts = new ABL[n]; + Nearest nrstDist = new Nearest(); + nrstDist.value = range; + return INNSearch(chdNodes.getReadNode(fileHdr.getFile(),fileName,root,fileHdr),pt, elmts,nrstDist); + } + catch( IllegalValueException e){ + throw new IllegalValueException(e.getMessage()); + } + catch(Exception e){ + throw new RTreeException("RTree.nearestSearch: " +e.getMessage()); + } + finally{ + fileHdr.unlock(); + } + } + /** + Improved Nearest Neighbour Search - Cheung, theory Roussopoulos + */ + private ABL[] INNSearch(Node node, Point pt,ABL[] nrstElements,Nearest nrstDist) + throws IllegalValueException,FileNotFoundException,IOException,NodeReadException, + RTreeException,NodeWriteException + { + if((node == null)) + throw new IllegalValueException("RTree.INNSearch: Node is null"); + Element[] elmts = node.getAllElements(); + int totElements = node.getTotalElements(); + + if(totElements == 0)//no elements + return null; + //System.out.println("In Node:"+node.getNodeIndex()); + //if leaf + if(node.getElementType() == Node.LEAF_NODE){ + //at leaf level compute distance to actual objects + for(int i=0; i= 0)){ + if(arr[--i] != null){ + if((arr[i].minDist <= elmt.minDist) || + ((i == 0)&&(elmt.minDistnearestSearch method(not overloaded). This + method finds all the objects within the given range. To understand + this method please refer to the other nearestSearch method. +
When the no. of objects required is less then a few thousands, this + method would be many times slower than the above method. + If possible use the other method. + @return vector of ABL objects within the given range. + */ + public List nearestSearch(Point pt,long range) + throws RTreeException, IllegalValueException + { + fileHdr.lockRead(); + if((pt == null) || (range < 0)) + throw new IllegalValueException("RTree.nearestSearch: " + +"Point null or int less than one"); + try{ + long root = fileHdr.getRootIndex(); + List elmts = new ArrayList(); + elmts = INNSearch(chdNodes.getReadNode(fileHdr.getFile(),fileName,root,fileHdr),pt,elmts,range); + return elmts; + } + catch( IllegalValueException e){ + throw new IllegalValueException(e.getMessage()); + } + catch(Exception e){ + throw new RTreeException("RTree.nearestSearch: " + e.getMessage()); + } + finally{ + fileHdr.unlock(); + } + } + private List INNSearch(Node node, Point pt, List nrstElements,long nrstDist) + throws IllegalValueException, FileNotFoundException,IOException,NodeReadException, Exception + { + if((node == null)) + throw new IllegalValueException("RTree.INNSearch: Node is null"); + Element[] elmts = node.getAllElements(); + int totElements = node.getTotalElements(); + + if(totElements == 0)//no elements + return null; + //System.out.println("In Node:"+node.getNodeIndex()); + //if leaf + if(node.getElementType() == Node.LEAF_NODE){ + //at leaf level compute distance to actual objects + for(int i=0; ilong value. There is no way to overwrite + the value contained in the java.lang.Long wrapper class. + */ + protected class Nearest//a wrapper class for long + { + public long value; + } + //--------------------------------get height------------------------------ + /**Upto 5 lakh objectes we can have a maximum height of 3 + TODO : Calculate other levels as well. One may need to know whether the tree is packed or unpacked for + this. + `*/ + public synchronized int getHeight() + { + int totNodes = fileHdr.getTotalNodes(); + if(totNodes <= 1) + return 1; + else if(totNodes <= 170) + return 2; + else //if((totNodes > (84*84)) && (totNodes < (169*169+1))) + return 3; + // else + //return 4; + } +} +/* TODO: + Immediate Improvements + 1)Take the common code from each query methods and put them in a single method. + 2)Make a way of retuning a Integer objects other than LeafElement Objects. +*/ diff --git a/DataExtractionOSM/src/rtree/RTreeClient.java b/DataExtractionOSM/src/rtree/RTreeClient.java new file mode 100644 index 0000000000..fc5726033b --- /dev/null +++ b/DataExtractionOSM/src/rtree/RTreeClient.java @@ -0,0 +1,359 @@ +/* + PROGRAMME: + PROGRAMMER: + DATE: + PROJECT: + MODIFIED DATE: + +*/ +package rtree; + +import java.io.*; +import java.net.*; +import java.util.List; + +public class RTreeClient +{ + private Socket socket; + public RTreeClient(String host,int port) + { + try + { + socket=new Socket(host,port); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + public void insert(Element element) throws RTreeException + { + try + { + String command="insert"; + Object obj[]={element}; + sendRequest(command,obj); + } + catch(RTreeException e) + { + throw e; + } + } + public void delete(LeafElement element) throws RTreeException + { + try + { + String command="delete"; + Object obj[]={element}; + sendRequest(command,obj); + } + catch(RTreeException e) + { + throw e; + } + } + public List overlaps(Rect rect) throws RTreeException + { + try + { + String command="overlaps"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List nonDisjoint(Rect rect) throws RTreeException + { + try + { + String command="nondisjoint"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List containedBy(Rect rect) throws RTreeException + { + try + { + String command="containedby"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List equal(Rect rect) throws RTreeException + { + try + { + String command="equal"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List meet(Rect rect) throws RTreeException + { + try + { + String command="meet"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List contains(Rect rect) throws RTreeException + { + try + { + String command="contains"; + Object obj[]={rect}; + Object[] response=sendRequest(command,obj); + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public List getAllElements() throws RTreeException + { + try + { + String command="getallelements"; + Object[] response=sendRequest(command,null); + //List v=(List)response[0]; + return (List) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public Rect getTreeMBR() throws RTreeException + { + try + { + String command="gettreembr"; + Object[] response=sendRequest(command,null); + return (Rect) response[0]; + } + catch(RTreeException e) + { + throw e; + } + } + public ABL[] nearestSearch(Point pt,long ln,int in) throws RTreeException + { + try + { + String command="nearest"; + Object obj[]={pt,new Long(ln),new Integer(in)}; + Object[] response=sendRequest(command,obj); + if(response!=null) + { + ABL abl[]=new ABL[response.length]; + for(int i=0;i=total && total!=-1) + { + //System.out.println("read completed..."+bbf.length); + break; + } + } + + byte tby[]=new byte[bbf.length-10]; + System.arraycopy(bbf,10,tby,0,tby.length); + ByteArrayInputStream bin=new ByteArrayInputStream(tby); + ObjectInputStream oIn=new ObjectInputStream(bin); + Boolean bool=(Boolean) oIn.readObject(); + //System.out.println("boolean.........."+bool); + Integer count=(Integer) oIn.readObject(); + //System.out.println("count.........."+count); + if(bool.booleanValue()) + { + Object[] obj=new Object[count.intValue()]; + for(int j=0;jNever Use .length field With the Returned Array + . Instead use getTotalElements(). + @return An element Array. + */ + public Element[] getAllElements() + { + return super.getAllElements(); + } + Element getElement(int index) + throws IllegalValueException + { + return super.getElement(index); + } + /** + Adds the node to the free stack. + Be very careful with this method because once called, this node may be + given to any new node even when you have not destroyed its object. + If the node is the only node then it updates the file header as well. +
Once called, there is no turning back!. + */ + public void deleteNode() + throws NodeWriteException + { + throw new UnsupportedOperationException("operation not supported"); + } + /** + * This method is added to sort the elements in this node to help sweepline algorithm. + */ + void sweepSort()//check out for null elements + { + super.sweepSort(); + }//sweepSort + /** + This is a new methos that will help the phylosophy where one should write to tbe cache only when + required. + @return true if needed write and written or false (not dirty). + */ + public boolean flush() + throws NodeWriteException + { + throw new UnsupportedOperationException("operation not supported"); + } + void setDirty(boolean val) + { + throw new UnsupportedOperationException("operation not supported"); + } + public boolean isDirty() + { + throw new UnsupportedOperationException("operation not supported"); + } + +} + + + + + + diff --git a/DataExtractionOSM/src/rtree/Rect.java b/DataExtractionOSM/src/rtree/Rect.java new file mode 100644 index 0000000000..69c94f4785 --- /dev/null +++ b/DataExtractionOSM/src/rtree/Rect.java @@ -0,0 +1,562 @@ +//Rect.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +/** + It is very easy to extend this program to n dimensions. Here every thing is + hard coaded for 2 dim. To convert to more than 2 dim. :- +
make the point class to hold the required dimensions.(keep an array of + dimensions) +
The rect class needs the four points directly, instead of that make it to + accept Point as its argument in the constructor. +
Then on deal with the point class directly instead of the four points + directly. +

The methods of relational topology(equals,contains etc.) are from various + papers by D. Papadias and mainly from Modeling Topological Spatial + Relation: Strategies for Query Processing.- Egenhofer +
The methods are nothing but set theories. +

In GIS there can be many types of combinations of the topological relations. + The theories of these combinations are given in the above said papers. If + required this class can be improved for those conditions. + @author Prachuryya Barua +*/ +//TODO: Apply the isNull considerations. +// Take the common procedures in overloaded methods to one method. +public class Rect implements java.io.Serializable +{ + private int minX=0,minY=0,maxX=0,maxY=0; + boolean isNull = false; + public Rect() + { + initNull(); + } + + public Rect(int topX,int topY,int botX, int botY) + throws IllegalValueException + { + if((topX > botX) || (topY > botY)){ + System.out.println("\ttopX:"+topX+"\ttopY:"+topY+"\tbotX:"+botX+"\tbotY:"+botY); + throw new IllegalValueException("rtree.Rect.Rect: wrong order of params."); + } + init(topX,topY,botX,botY); + } + Rect(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.Rect: Param is null."); + if(rect.isNull()){ + initNull(); + } + else + init(rect.getMinX(), rect.getMinY(), rect.getMaxX(), rect.getMaxY()); + } + private void initNull() + { + minX = 0; + minY = 0; + maxX = -1; + maxY = -1; + isNull = true; + } + private void init(int minX, int minY, int maxX, int maxY) + { + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + isNull = false; + } + /* + If you want to make the constructor take Point, then.... + Point minP,maxP; + Rect(int minX,int minY,int botX, int botY) + throws IllegalValueException + { + if((minX > maxX) || (minY > maxY)) + throw new IllegalValueException("rtree.Rect.Rect: " + +"minP > maxP ?"); + minP = new Point(minX,minY); + maxP = new Point(maxX,maxY); + } + Rect(Point minP,Point maxP) + throws IllgalValueException + { + if((minP == null) || (maxP == null)) + throw new IllegalValueException("rtree.Rect.Rect: " + +"Either of the point are null"); + if((minP.getX() > maxP.getX()) || (minP.getY() > maxP.getY())) + throw new IllegalValueException("rtree.Rect.Rect: " + +"minP > maxP?"); + this.minP = (Point)minP.clone(); + this.maxP = (Point)maxP.clone(); + } + */ + public boolean isNull() + { + return isNull; + //if(minX == 0 && minY == 0 && maxX == -1 && maxY == -1) + //return true; + //else + //return false; + } + public static int sizeInBytes() + { + return(Node.INTEGER_SIZE*4);//depends upon the points + } + public int getArea() + { + if(isNull()) + return 0; + return((maxX-minX)*(maxY-minY)); + } + public int getWidth() + { + if(isNull()) + return 0; + return(Math.abs(maxX - minX)); + } + public int getHeight() + { + if(isNull()) + return 0; + return(Math.abs(maxY - minY)); + } + public int getMinX() + { + return(minX); + } + public int getMinY() + { + return(minY); + } + public int getMaxX() + { + return(maxX); + } + public int getMaxY() + { + return(maxY); + } + /** + Include the given Rectangle. + */ + public void expandToInclude(Rect rect) + { + if(rect == null || rect.isNull()) + return; + + if(this.isNull()){ + init(rect.getMinX(),rect.getMinY(), rect.getMaxX(), rect.getMaxY()); + return; + } + minX = Math.min(rect.getMinX(),minX);//minX + minY = Math.min(rect.getMinY(),minY);//minY + maxX = Math.max(rect.getMaxX(),maxX);//maxX + maxY = Math.max(rect.getMaxY(),maxY);//maxY + } + /** + return the minimum bounding rectangle of this rectangle and the passed + rectangle. + */ + public Rect getResultingMBR(Rect rectangle) + throws IllegalValueException + { + if(rectangle == null) + throw new IllegalValueException("rtree.Rect.getResultingMBR : Rect is null"); + if(rectangle.isNull()) + if(this.isNull()) + return new Rect(); + else + return new Rect(this); + else//rectangle is not null + if(this.isNull()) + return rectangle; + //if nobody is "isNull" + int topX,topY,botX,botY; + topX = Math.min(rectangle.getMinX(),minX);//minX + topY = Math.min(rectangle.getMinY(),minY);//minY + botX = Math.max(rectangle.getMaxX(),maxX);//maxX + botY = Math.max(rectangle.getMaxY(),maxY);//maxY + return(new Rect(topX,topY,botX,botY)); + } + /** + Overloaded type of the previous function - but static + */ + public static Rect getResultingMBR(Rect source, Rect dest) + throws IllegalValueException + { + if((dest == null) || (source == null)) + throw new IllegalValueException("rtree.Rect.getResultingMBR : Rect is null"); + return source.getResultingMBR(dest); + } + /** + Another overloaded version - but static + */ + public static Rect getResultingMBR(Rect[] rects) + throws IllegalValueException + { + if(rects.length <= 0) + throw new IllegalValueException("rtree.Rect.getResultingMBR : "+ + "Array of rectangles are empty."); + Rect result = rects[0]; + for(int i=1; iChecks the two minimal conditions from 'contains' matrix(Egenhofer.) +
Correct for Point as well. + */ + public boolean contains(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.contains: null argument"); + boolean ret = true; + //m12 = true && m22 = false + //X dim. + if((minX >= rect.getMinX()) || (maxX <= rect.getMaxX())) + return false; + //Y dim. + if((minY >= rect.getMinY()) || (maxY <= rect.getMaxY())) + return false; + return ret; + } + /** + The difference betn. this method and contains is that this method returns true + even if the covers condition if true. + @return true if this rectangle completely encloses 'rect'. + */ + + public boolean encloses(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.overlaps: null argument"); + boolean ret = true; + //X dim. + if((minX > rect.getMinX()) || (maxX < rect.getMaxX())) + return false; + //Y dim. + if((minY > rect.getMinY()) || (maxY < rect.getMaxY())) + return false; + return ret; + } + + /** + Check if this rectangle is contained by 'rect' + */ + public boolean containedBy(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.containedBy:null argument"); + boolean ret = true; + //m21 = true && m22 = false + //X dim. + if((rect.getMinX() >= minX) || (rect.getMaxX() <= maxX)) + return false; + //Y dim. + if((rect.getMinY() >= minY) || (rect.getMaxY() <= maxY)) + return false; + return ret; + } + /** + This method also gives whether one point is over another, if you do not + want that much precision then comment the line.This will improve performance. + @return true if both the rectangle overlap/intresect else false. +
Note:-This method is not precisely according to Egenhofer. + */ + public boolean overlaps(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("Rect.overlaps: null argument"); + int rectMinX = rect.getMinX(); + int rectMinY = rect.getMinY(); + int rectMaxX = rect.getMaxX(); + int rectMaxY = rect.getMaxY(); + boolean ret = false; + //if one point object is over another then..... + if((minX == rectMinX) && (minY == rectMinY) && (maxX == rectMaxX) && (maxY == rectMaxY)) + return true; + //if you do not want this much precision then comment above written line. + + //X dim. + if((minX < rectMaxX) && (maxX > rectMinX)) + ret = true; + else + return false; + //Y dim. + if((minY < rectMaxY) && (maxY > rectMinY)) + ret = true; + else + return false; + + return ret; + }//overlaps + + /** + Saperate or not(Egenhofer). +
To check if two rectangles intersect in any way then call '!disjoint()'. + */ + public boolean disjoint(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.disjoint: null argument"); + boolean ret = true; + //m12 = false && m22 = false + //X dim. + if((minX <= rect.getMaxX()) && (maxX >= rect.getMinX())) + ret = false; + else + return ret; + //Y dim. + if((minY <= rect.getMaxY()) && (maxY >= rect.getMinY())) + ret = false; + else + ret = true; + return ret; + + }//disjoint - over + /** + Checks if both the rectangles meet or not. + */ + public boolean meet(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.meet: null argument"); + boolean ret = true; + //m11 = false + if(disjoint(rect)) + return false; + //if both have common area then exit with false. + if((minX < rect.getMaxX()) && (maxX > rect.getMinX())) + if((minY < rect.getMaxY()) && (maxY > rect.getMinY())) + return false; + System.out.println("Raj!"); + //m22 = true + if((minX == rect.getMaxX()) || (maxX == rect.getMinX())) + return true; + else + ret = false; + if((minY == rect.getMaxY()) || (maxY == rect.getMinY())) + ret = true; + return ret; + + }//meet + /** + Checks if this rectangle contains 'rect'. This method is incomplete. It can + be finished if required.(Depends on query requirements) + +

+     ---------------
+     |             |
+     |      |------|
+     |      |'rect'|
+     |      |------|
+     |             |
+     ---------------
+     
+ */ + public boolean covers(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.covers: null argument"); + boolean ret = true; + //m12 = true + if((minX > rect.getMaxX()) || (maxX < rect.getMinX())) + return false; + if((minY > rect.getMaxY()) || (maxY < rect.getMinY())) + return false; + //m21 = false + if((minX < rect.getMinX()) && (maxX < rect.getMaxX())) + return false; + if((minY < rect.getMinY()) && (maxY < rect.getMaxY())) + return false; + //m22 = true + if((minX != rect.getMinX()) && (maxX != rect.getMaxX())) + return false; + if((minY != rect.getMinY()) && (maxY != rect.getMaxY())) + return false; + return ret; + } + /** + Checks if this rectangle is equal to 'rect' + */ + public boolean equals(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.equals: null argument"); + //m21=false && m23=false + if((minX != rect.getMinX()) || (maxX != rect.getMaxX())) + return false; + if((minY != rect.getMinY()) || (maxY != rect.getMaxY())) + return false; + return true; + } + + public String toString() + { + String ret; + ret = "\nThe Rectangle:-"; + ret += "\n\tminX: " + minX; + ret += "\n\tminY: " + minY; + ret += "\n\tmaxX: " + maxX; + ret += "\n\tmaxY: " + maxY; + return ret; + } + /** + Calculate the Euclidean distance between the point and the MBR. + To calculate the distance(MINDIST) betn. a Point and Rectangle in + n dimension. In our case we consider only 2 dimensions. +
Note:- The distance is the square of the actual distance. To find the actual + distance, square root the returned value. + */ + public static long minDist(Point p, Rect rect) + { + long minDist; + int ri;//see Roussopoulos for notations + int pX = p.getX(); + int pY = p.getY(); + int minX = rect.getMinX(); + int minY = rect.getMinY(); + int maxX = rect.getMaxX(); + int maxY = rect.getMaxY(); + //for X dim. + if(pX < minX) + ri = minX; + else if(pX > maxX) + ri = maxX; + else + ri = pX; + Long temp = new Long(Math.abs(pX - ri)); + minDist = (new Double(Math.pow(temp.doubleValue(),2))).longValue(); + //for Y dim. + if(pY < minY) + ri = minY; + else if(pY > maxY) + ri = maxY; + else + ri = pY; + temp = new Long(Math.abs(pY - ri)); + minDist += (new Double(Math.pow(temp.doubleValue(),2))).longValue(); + return minDist; + } + /** + To find the minimum of the maximum distances from a point to a Rectangle + (Not implemeneted yet). + For further details see Roussopoulos. + If we apply Cheung then it will not be used. + */ + public static int minMaxDist(Point p, Rect rect) + { + return(0); + } + /** + * Will return the intersection of the this and rect. + * @param rect The other Rect + */ + public Rect intersection(Rect rect) + { + if(rect == null) + throw new IllegalArgumentException("Rect.instersection : Argument Rect is null"); + int x1;// = 0 + int y1;// = 0; + int x2;// = -1; + int y2;// = -1; + //minX + if(minX < rect.minX) + x1 = rect.minX; + else + x1 = minX; + //minY + if(minY < rect.minY) + y1 = rect.minY; + else + y1 = minY; + //maxX + if(maxX > rect.maxX) + x2 = rect.maxX; + else + x2 = maxX; + //maxY + if(maxY > rect.maxY) + y2 = rect.maxY; + else + y2 = maxY; + try{ + if(x1 > x2 || y1 > y2) + return new Rect(); + else + return new Rect(x1, y1, x2, y2); + }catch(Exception e){ + e.printStackTrace(); + return new Rect(); + } + } +} +//TODO +/* + New disjunctions of topological relations can be derived from the + minimal subset algorithm(Egenhofer) +
To do so first make a method for each of the matrix element. Then + using the algo. find the conditions of the matrix to satisfy and call + the desired methods. + Although this is possible through the combinations of the eight methods + directly but it would need a lot of processing. +*/ + +/* + The diif. bet. this function and 'overlap' is that the latter returns + false if the two rects have only a side(s) in common but no area. + This method returns true if both the rects have either or both + area and side(s) common. +
returns true if ((meet=true)||(overlap=true)||(covers=true)|| + (equal=true)) or it can be said not disjoint. + @return true if this rect. touches or overlaps with 'rect' +*/ +/* + public boolean intersect(Rect rect) + throws IllegalValueException + { + if(rect == null) + throw new IllegalValueException("rtree.Rect.overlaps: null argument"); + boolean ret = true; + //X dim. + if((minX > rect.getMaxX()) || (maxX < rect.getMinX())) + return false; + //Y dim. + if((minY > rect.getMaxY()) || (maxY < rect.getMinY())) + return false; + return ret; + } + +*/ + diff --git a/DataExtractionOSM/src/rtree/StackOverflowException.java b/DataExtractionOSM/src/rtree/StackOverflowException.java new file mode 100644 index 0000000000..76ea2f9d1e --- /dev/null +++ b/DataExtractionOSM/src/rtree/StackOverflowException.java @@ -0,0 +1,24 @@ +//StackOverflowException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +/**When the stack overflows + @author Prachuryya Barua +*/ +class StackOverflowException extends Exception +{ + StackOverflowException(String msg) + { + super(msg); + } +} + diff --git a/DataExtractionOSM/src/rtree/StackUnderflowException.java b/DataExtractionOSM/src/rtree/StackUnderflowException.java new file mode 100644 index 0000000000..75a03b93e2 --- /dev/null +++ b/DataExtractionOSM/src/rtree/StackUnderflowException.java @@ -0,0 +1,24 @@ +//StackUnderflowException.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. + +package rtree; + +/**When the stack underflows + @author Prachuryya Barua +*/ +class StackUnderflowException extends Exception +{ + StackUnderflowException(String msg) + { + super(msg); + } +} diff --git a/DataExtractionOSM/src/rtree/join/CompElmtX.java b/DataExtractionOSM/src/rtree/join/CompElmtX.java new file mode 100644 index 0000000000..924d829631 --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/CompElmtX.java @@ -0,0 +1,52 @@ +//CompElmtX.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import java.util.Comparator; +import rtree.*; + +/** + An internal Comparable class to sort Element. + @author Prachuryya Barua +*/ +public class CompElmtX implements Comparator +{ + public int compare(Object o1, Object o2) + { + if(o1 instanceof Element && o2 instanceof Element){ + Rect r1 = ((Element)o1).getRect(); + Rect r2 = ((Element)o2).getRect(); + return r1.getMinX() - r2.getMinX(); + //if(r1.getMinX() <= r2.getMinX()) + //return -1; + //else if(r1.getMinX() == r2.getMinX()) + //return 0; + //else + //return 1; + } + // else if(o1 == null && o2 != null){ + // return -1; + // }else if(o1 != null && o2 == null){ + // return 1; + // }else if(o1 == null && o2 == null){ + // return Integer.MAX_VALUE; + //} + else{ + throw new ClassCastException("Rect.compareTo : wrong object(s) passed : " + +o1.getClass().getName() + " o2 " + o2.getClass().getName()); + } + } + public boolean equals(Object o) + { + return true; + } +} diff --git a/DataExtractionOSM/src/rtree/join/ContainedByPred.java b/DataExtractionOSM/src/rtree/join/ContainedByPred.java new file mode 100644 index 0000000000..618761722a --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/ContainedByPred.java @@ -0,0 +1,67 @@ +//ContainedByPred.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; +import java.util.List; + +/** + The "intersects" binary predicate. This is only for the sweepline algo. + @author Prachuryya Barua +*/ +public class ContainedByPred extends Predicate +{ + public ContainedByPred(){} + + public void relate(Element event, int from, Element[] others, List pairs, int evtSide) + { + //System.out.println("SweepLine.internalLoop : before pairs size : " + pairs.size()); + if(evtSide == Join.RIGHT){ + for(int i=from; + (i others[i].getRect().getMaxY()){ + if(evtSide == Join.LEFT) + pairs.add(p.paired(event, others[i])); + else + pairs.add(p.paired(others[i], event)); + }//if + }//for + //System.out.println("SweepLine.internalLoop : after pairs size : " + pairs.size()); + }else{ + //do nothing and see the comments in ContainsPredicate + } + } + + /** + @param side The side of elmt1. + */ + public boolean relateMismatch(Element elmt1, Element elmt2, int side) + { + try{ + if(elmt1 instanceof NonLeafElement || elmt2 instanceof NonLeafElement) + return elmt1.getRect().overlaps(elmt2.getRect()); + else{ + if(side == Join.LEFT) + return elmt1.getRect().containedBy(elmt2.getRect()); + else + return elmt2.getRect().containedBy(elmt1.getRect()); + } + }catch(Exception e){ + e.printStackTrace(); + return false; + } + } +} diff --git a/DataExtractionOSM/src/rtree/join/ContainsPred.java b/DataExtractionOSM/src/rtree/join/ContainsPred.java new file mode 100644 index 0000000000..ea55732303 --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/ContainsPred.java @@ -0,0 +1,72 @@ +//ContainsPred.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; +import java.util.List; + +/** + The "intersects" binary predicate. This is only for the sweepline algo. + @author Prachuryya Barua +*/ +public class ContainsPred extends Predicate +{ + public ContainsPred(){} + + + public void relate(Element event, int from, Element[] others, List pairs, int evtSide) + { + //System.out.println("SweepLine.internalLoop : before pairs size : " + pairs.size()); + if(evtSide == Join.LEFT){ + for(int i=from; + (i others[i].getRect().getMaxY()){//check the y coordinate + if(evtSide == Join.LEFT) + pairs.add(p.paired(event, others[i])); + else + pairs.add(p.paired(others[i], event)); + }//if + }//for + }else{ + /*do nothing as, if left contains right then left must have appeared before at all cost + .In other words, if the event took place at a right side then it is not supposed to contain anything. + We need to concern overselves with events because of left tree only. + */ + } + //System.out.println("SweepLine.internalLoop : after pairs size : " + pairs.size()); + } + + /** + @param side The side of elmt1. + */ + public boolean relateMismatch(Element elmt1, Element elmt2, int side) + { + //System.out.println("ContainsPred.relateMismatch :"); + + try{ + if(elmt1 instanceof NonLeafElement || elmt2 instanceof NonLeafElement) + return elmt1.getRect().overlaps(elmt2.getRect()); + else{ + if(side == Join.LEFT) + return elmt1.getRect().contains(elmt2.getRect()); + else + return elmt2.getRect().contains(elmt1.getRect()); + } + }catch(Exception e){ + e.printStackTrace(); + return false; + } + } +} diff --git a/DataExtractionOSM/src/rtree/join/EqualsPred.java b/DataExtractionOSM/src/rtree/join/EqualsPred.java new file mode 100644 index 0000000000..d290e14a0d --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/EqualsPred.java @@ -0,0 +1,70 @@ +//EqualsPred.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; +import java.util.List; + +/** + The "intersects" binary predicate. This is only for the sweepline algo. + @author Prachuryya Barua +*/ +public class EqualsPred extends Predicate +{ + public EqualsPred(){} + // EqualsPred(Pair p) + // { + // super(p); + // } + public void relate(Element event, int from, Element[] others, List pairs, int evtSide) + { + //System.out.println("SweepLine.internalLoop : before pairs size : " + pairs.size()); + for(int i=from; + (i others[i].getRect().getMinY()){//check the y coordinate + if(evtSide == Join.LEFT) + pairs.add(p.paired(event, others[i])); + else + pairs.add(p.paired(others[i], event)); + }//if + }//for + //System.out.println("SweepLine.internalLoop : after pairs size : " + pairs.size()); + } + // public boolean relateMismatch(Element nlElmt, Element lfElmt) + // { + // try{ + // if(nlElmt instanceof NonLeafElement || lfElmt instanceof NonLeafElement) + // return nlElmt.getRect().overlaps(lfElmt.getRect()); + // else + // return nlElmt.getRect().equals(lfElmt.getRect()); + // }catch(Exception e){ + // e.printStackTrace(); + // return false; + // } + //} + public boolean relateMismatch(Element elmt1, Element elmt2, int side) + { + try{ + if(elmt1 instanceof NonLeafElement || elmt2 instanceof NonLeafElement) + return elmt1.getRect().overlaps(elmt2.getRect()); + else{ + return elmt1.getRect().equals(elmt2.getRect()); + } + }catch(Exception e){ + e.printStackTrace(); + return false; + } + } +} diff --git a/DataExtractionOSM/src/rtree/join/IntersectPred.java b/DataExtractionOSM/src/rtree/join/IntersectPred.java new file mode 100644 index 0000000000..0191531dbb --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/IntersectPred.java @@ -0,0 +1,50 @@ +//IntersectPred.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; +import java.util.List; + +/** + The "intersects" binary predicate. This is only for the sweepline algo. + @author Prachuryya Barua +*/ +public class IntersectPred extends Predicate +{ + public IntersectPred(){} + public void relate(Element event, int from, Element[] others, List pairs, int evtSide) + { + //System.out.println("SweepLine.internalLoop : before pairs size : " + pairs.size()); + for(int i=from; + (i others[i].getRect().getMinY()){//check the y coordinate + if(evtSide == Join.LEFT) + pairs.add(p.paired(event, others[i])); + else + pairs.add(p.paired(others[i], event)); + }//if + }//for + //System.out.println("SweepLine.internalLoop : after pairs size : " + pairs.size()); + } + public boolean relateMismatch(Element ltElmt, Element rtElmt, int side) + { + try{ + return ltElmt.getRect().overlaps(rtElmt.getRect()); + }catch(Exception e){ + e.printStackTrace(); + return false; + } + } +} diff --git a/DataExtractionOSM/src/rtree/join/Join.java b/DataExtractionOSM/src/rtree/join/Join.java new file mode 100644 index 0000000000..84893d4a1c --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/Join.java @@ -0,0 +1,211 @@ +//Join.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; + +import java.util.ArrayList; +import java.util.List; + +/** + A class to join two RTrees. + TODO: + Make another buffer just for this algorithm of 512 bytes (or should you?). + It is best to have this method's own cache. Read the document well before deciding on it. + FIXME: + 1) This thing goes out of memory for large randomly generated trees. + 2) The result for point objects are not correct. The extra check done at Rect class is not done at sweep line algorithm. + 3) Better documentation + + @author Prachuryya Barua +*/ +public class Join +{ + public static final int LEFT = 0; + public static final int RIGHT = 1; + private RTree ltTree = null; + private RTree rtTree = null; + private Pair p = null; + SweepLine spLine = new SweepLine();//our sweep line always return a pair of pointers + + /** + @param left The left tree. + @param right The right tree. + */ + public Join(RTree left, RTree right, Pair p, Predicate pred) + { + if(left == null || right == null) + throw new IllegalArgumentException("Join : Argument null"); + this.ltTree = left; + this.rtTree = right; + this.p = p; + spLine.setPredicate(pred); + //this.pred = pred; + } + + public void setPairType(Pair p) + { + if(p != null) + this.p = p; + } + + /** + Will return all the record pointers of the left tree that intersects with the right tree. + At the moment I assume that the heights of the trees are same. + @return a List of Pairs of pointers that intersect. + */ + public List relate() + throws JoinException + { + try{ + //lock the files + ltTree.getFileHdr().lockRead(); + rtTree.getFileHdr().lockRead(); + List vct = new ArrayList(); + long ltRoot = ltTree.getFileHdr().getRootIndex(); + long rtRoot = rtTree.getFileHdr().getRootIndex(); + + /*We can't do anything when we do not have any mbrs in either of the trees*/ + if(ltRoot == Node.NOT_DEFINED || rtRoot == Node.NOT_DEFINED) + return vct; + + Node ltRootNd = ltTree.getReadNode(ltRoot); + Node rtRootNd = rtTree.getReadNode(rtRoot); + + relateRec(ltRootNd, rtRootNd, ltRootNd.getNodeMBR().intersection(rtRootNd.getNodeMBR()), vct); + return vct; + }catch(Exception e){ + e.printStackTrace(); + throw new JoinException("Join.intersectsInt : " + e.getMessage()); + }finally{ + ltTree.getFileHdr().lockRead(); + rtTree.getFileHdr().lockRead(); + } + } + /** + @param ltNode + @param rtNode + @param ret + @param intsect The intersection between the two Node. + @param ret A List that would be filled with the pairs that intersect. + */ + private void relateRec(Node ltNode, Node rtNode, Rect intsect, List ret) + throws Exception + { + if(ltNode == null || rtNode == null) + throw new IllegalValueException("Join.intersectRec : Argument(s) null"); + Element[] ltElmts = ltNode.getAllElements(); + Element[] rtElmts = rtNode.getAllElements(); + + if(ltNode.getElementType() == Node.NONLEAF_NODE && + rtNode.getElementType() == Node.LEAF_NODE){//both sides are of different types + ret.addAll(joinMismatch(ltElmts, rtElmts, Join.LEFT)); + }else if(ltNode.getElementType() == Node.LEAF_NODE && + rtNode.getElementType() == Node.NONLEAF_NODE){//both sides are of different types + ret.addAll(joinMismatch(rtElmts, ltElmts, Join.RIGHT)); + }else {//either both are leaf or both non-leaf + //this is where I remove elemensts which do no intersect with the intersection rectangle + ltElmts = filterRect(ltElmts, intsect); + rtElmts = filterRect(rtElmts, intsect); + List pairs = spLine.sortedIntersectionTest(ltElmts, rtElmts);//get the intersecting pairs + for(int i=0; inlElmts. (Join.LEFT or Join.RIGHT) + @return Pair of joins between leaf and non leaf elements (after window query). + */ + private List joinMismatch(Element[] nlElmts, Element[] lfElmts, int side) + throws Exception + { + List ret = new ArrayList(); + for(int i=0; (inlNode (a non-leaf Node). + * Will return a List of Pair. The pair is made accordingly side. + * @param side The side of nlNode. + */ + private List windowQuery(Node nlNode, LeafElement lfElmt, int side) + throws Exception + { + RTree nlTree = null;//the non leaf tree + if(side == Join.LEFT) + nlTree = ltTree; + else + nlTree = rtTree; + List list = new ArrayList(); + Element[] elmts = nlNode.getAllElements(); + int totElements = nlNode.getTotalElements(); + for(int i=0; ielmts that do not intersect rect. + The original elements, elmts, are not modified. + */ + private Element[] filterRect(Element[] elmts, Rect rect) + throws Exception + { + Element[] ret = new Element[elmts.length]; + int j=0; + for(int i=0; iPair and PairElmt is that the caller can get + * pairs of pointers or pairs elements from the join operations. + @author Prachuryya Barua +*/ +public class Pair +{ + protected long left; + protected long right; + private Pair(long left, long right) + { + this.left = left; + this.right = right; + } + + public Pair(){} + + public long getLtPtr() + { + return left; + } + public long getRtPtr() + { + return right; + } + /** + Returns an object this type. + */ + public Pair paired(Element ltElmt, Element rtElmt) + { + return new Pair(ltElmt.getPtr(), rtElmt.getPtr()); + } +} diff --git a/DataExtractionOSM/src/rtree/join/PairElmt.java b/DataExtractionOSM/src/rtree/join/PairElmt.java new file mode 100644 index 0000000000..307ebda271 --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/PairElmt.java @@ -0,0 +1,57 @@ +//PairEmlt.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; + +/** + * This class inherits Pair but represents the whole Element that intersect and not just the pointers. + * Basically the purpose of Pair and PairElmt is that the caller can get + * pairs of pointers or pairs elements from the join operations. + @author Prachuryya Barua +*/ +public class PairElmt extends Pair +{ + private Element ltElmt; + private Element rtElmt; + + public PairElmt(){} + + private PairElmt(Element ltElmt, Element rtElmt) + { + this.ltElmt = ltElmt; + this.rtElmt = rtElmt; + } + + public long getLtPtr() + { + return ltElmt.getPtr(); + } + public long getRtPtr() + { + return rtElmt.getPtr(); + } + public Element getLtElmt() + { + return ltElmt; + } + + public Element getRtElmt() + { + return rtElmt; + } + public Pair paired(Element ltElmt, Element rtElmt) + { + return new PairElmt(ltElmt, rtElmt); + } + +} diff --git a/DataExtractionOSM/src/rtree/join/Predicate.java b/DataExtractionOSM/src/rtree/join/Predicate.java new file mode 100644 index 0000000000..970ac979e8 --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/Predicate.java @@ -0,0 +1,62 @@ +//Predicate.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import rtree.*; +import java.util.List; + +/** + This class works with "sweepline" algo. For the actual binary predicate between MBRs, this interface + should help. We will have an implementing class for "intersects","contains","meet". + @author Prachuryya Barua +*/ +public abstract class Predicate +{ + protected Pair p = new PairElmt();//this is always PairElmt + + public Predicate(){} + + // public Predicate(Pair p) + // { + // if(p == null) + // throw new NullPointerException(" Argument null"); + // this.p = p; + // } + + /** + * Do the appropriate rtree operation. + * @param event the Element at which the event took place. + * @param from the index from which others start. + * @param others the Element[] to compare with event + * @param pairs a List value where the output pairs would put. + * @param evtSide tells whether event is from left tree or right tree. + * @param p a Pair value which specifies the kind of output required. + */ + public abstract void relate(Element event, int from, Element[] others, List pairs, int evtSide); + + /** + * This one is specifically for the case where one tree is longer then the other. + * It may be noted that both the elements can be leaf as well. + * @param nlElmt the non-leaf Element + * @param lfElmt the leaf Element + * @param side The side of nlElmt element. + * @return a boolean value + */ + public abstract boolean relateMismatch(Element nlElmt, Element lfElmt, int side); + /** + Returns the Pair which tells the type of output required. + */ + public Pair getPair() + { + return p; + } +} diff --git a/DataExtractionOSM/src/rtree/join/SweepLine.java b/DataExtractionOSM/src/rtree/join/SweepLine.java new file mode 100644 index 0000000000..b87a0e4d53 --- /dev/null +++ b/DataExtractionOSM/src/rtree/join/SweepLine.java @@ -0,0 +1,168 @@ +//SweepLine.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.join; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import rtree.*; +import java.util.Comparator; + +/** + @author Prachuryya Barua +*/ +public class SweepLine +{ + //Pair p = new Pair(); + IntersectPred intPred = new IntersectPred(); + Predicate pred = null; + public SweepLine() + { + } + + public SweepLine(Predicate pred) + { + //this.p = p; + this.pred = pred; + //intPred = new IntersectPred(); + } + + public void setPredicate(Predicate pred) + { + this.pred = pred; + } + public Predicate getPredicate() + { + return pred; + } + public void sort(Rect[] rects) + { + Arrays.sort(rects, new CompRectX()); + } + public void sort(Element[] elmts) + { + Arrays.sort(elmts, new CompElmtX()); + } + + /** + * This method will return all the pointers of elmts which intersect with + * rect. It is expected that elmts are sorted acording to minX + * @return either a List of eithers pointers or ehole elements depending upon p. + */ + public List intersects(Rect rect, Element[] elmts) + { + if(elmts == null || elmts.length < 1) + return null; + Element dummy; + if(elmts[0] instanceof LeafElement) + dummy = new LeafElement(rect, 128); + else + dummy = new NonLeafElement(rect, 128); + Element[] dummyArr = new Element[1]; + dummyArr[0] = dummy; + return sortedIntersectionTest(dummyArr, elmts); + } + /** + * This method applies the sweep line algorithm to the two given set of elements. + * It is not necessary to have the two arrays sorted (by minX). + */ + public List intersects(Element[] ltElmts,Element[] rtElmts) + { + sort(ltElmts); + sort(rtElmts); + return sortedIntersectionTest(ltElmts, rtElmts); + } + + /** + Does the sweep sort on the two sets. Assumes that both the set of elements are of the same type. + @param ltElmts The sorted elements(by minX) of the left node. + @param rtElmts The sorted elements(by minX) of the right node. + @return A List of Pair of elements + */ + public List sortedIntersectionTest(Element[] ltElmts, Element[] rtElmts) + { + int i = 0;//loop cntr for left + int j = 0;//loop cntr for right + List pairs = new ArrayList(); + while((i < ltElmts.length) && (ltElmts[i] != null) && + (j < rtElmts.length) && (rtElmts[j] != null)){ + if(ltElmts[i].getRect().getMinX() < rtElmts[j].getRect().getMinX()){//event at left + + if(ltElmts[i] instanceof NonLeafElement){ + intPred.relate(ltElmts[i], j, rtElmts, pairs, Join.LEFT); + }else{ + pred.relate(ltElmts[i], j, rtElmts, pairs, Join.LEFT); + } + //System.out.println("SweepLine.sortedIntersectionTest : total pairs " + pairs.size()); + i++; + }else{ + if(rtElmts[j] instanceof NonLeafElement){ + intPred.relate(rtElmts[j], i, ltElmts, pairs, Join.RIGHT); + }else{ + pred.relate(rtElmts[j], i, ltElmts, pairs, Join.RIGHT); + } + //System.out.println("SweepLine.sortedIntersectionTest : total pairs " + pairs.size()); + j++; + } + } + return pairs; + } + + /** + @param evtSide tells whether event is from left tree or right tree. + + private void internalLoop(Element event, int from, Element[] others, List pairs, int evtSide) + { + //System.out.println("SweepLine.internalLoop : before pairs size : " + pairs.size()); + for(int i=from; + (i others[i].getRect().getMinY()){//check the y coordinate + if(evtSide == Join.LEFT) + pairs.add(p.paired(event, others[i])); + else + pairs.add(p.paired(others[i], event)); + }//if + }//for + //System.out.println("SweepLine.internalLoop : after pairs size : " + pairs.size()); + } + */ +} + +/** + An internal Comparable class to sort Rect. +*/ +class CompRectX implements Comparator +{ + public int compare(Object o1, Object o2) + { + if(o1 instanceof Rect && o2 instanceof Rect){ + Rect r1 = (Rect)o1; + Rect r2 = (Rect)o2; + if(r1.getMinX() <= r2.getMinX()) + return -1; + else if(r1.getMinX() == r2.getMinX()) + return 0; + else + return 1; + } + else + throw new ClassCastException("Rect.compareTo : wrong object(s) passed"); + + } + public boolean equals(Object o) + { + return true; + } +} diff --git a/DataExtractionOSM/src/rtree/rTreeDemo.java b/DataExtractionOSM/src/rtree/rTreeDemo.java new file mode 100644 index 0000000000..e0491c7e0e --- /dev/null +++ b/DataExtractionOSM/src/rtree/rTreeDemo.java @@ -0,0 +1,650 @@ +//RTreeDemo.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree; + +import java.io.RandomAccessFile; +import java.util.Random; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import rtree.join.*; +import rtree.seeded.*; +import java.util.List; +import java.util.ArrayList; + +/** + One can look at this class to understand the usage of RTree. +*/ +public class rTreeDemo +{ + public static void main(String argv[]) + { + //rTreeDemo rt = new rTreeDemo(); + new TreeThread(); + } + public List tryJoin() + { + TreeThread tr = new TreeThread(); + return tr.tryJoin(); + } + public void setName(String name) + { + TreeThread.fileName = name; + } +} + +class TreeThread implements Runnable +{ + static String fileName = "c:\\temp\\temp.tree"; + static long seed = 1015395880;//1015395880431; + static int h = 15000000;//2148460;//15000000; + static int w = 6000000;//2757573;//6000000; + Thread tree; + //String tname; + TreeThread() + { + for(int i=0; i<1; i++){ + tree = new Thread(this,Integer.toString(i)); + // try{Thread.currentThread().sleep(3000);} + // catch(Exception e){System.out.println("shdb");} + tree.start(); + } + } + public void run() + { + try{ + //RTree rt = new RTree(fileName); + //rt.printTree(); + // entry(fileName); + //entryRand(fileName); + // rt.flush(); + + // HashSet set = new HashSet(list); + // System.out.println("rTreeDemo.run : size of set " + set.size()); + + //rt.printTree(); + //overlapRR(fileName); + + //Pack pck = new Pack(); + //System.out.println("rTreeDemo : rt has before " + rt.getAllElements().size()); + //pck.packTree(rt, fileName); + //System.out.println("rTreeDemo : rt has after " + rt.getAllElements().size()); + //rt.printTree(); + //pck.packTree(rt, fileName); + + //pck.packTree(new RTree(fileName+"2"), fileName+"2"); + //trySeed("/tmp/seed.dat", new RTree(fileName)); + //System.out.println("rTreeDemo : height " + rt.getHeight()); + + RTreeRead rd = new RTreeRead(fileName+"1"); + rd.readSeq(); + rd = new RTreeRead(fileName+"2"); + rd.readSeq(); + + //tryJoin(); + } + catch(Exception e){ + try{ + e.printStackTrace(); + }catch(Exception ex){ + ex.printStackTrace(); + } + } + //tryOverlap(); + //tryCvr(); + } + /** + Enter records within l - 15000000 and w - 6000000 + */ + public void entryRand(String fileName) + throws Exception + { + List vct = new ArrayList(0); + int ix,iy,xx,xy;//mIn,maX + RTree rt = new RTree(fileName); + Random rnd = new Random(seed); + long start = System.currentTimeMillis(); + Rect rect = new Rect(); + + //point data + for(int i=0;i<2000; i++){ + iy = rnd.nextInt(h);//height + ix = rnd.nextInt(w);//width + LeafElement lf = new LeafElement(new Rect(ix,iy,ix,iy),218); + rt.insert(lf); + //rect.expandToInclude(lf.getRect()); + //vct.add((LeafElement)lf.clone()); + } + + //rectangles + for(int i=0;i<30000; i++){ + iy = rnd.nextInt(h-2);//height + ix = rnd.nextInt(w-2);//width + xy = rnd.nextInt(h - iy); + xx = rnd.nextInt(w - ix); + LeafElement lf = new LeafElement(new Rect(ix,iy,ix+xx,iy+xy),218); + rt.insert(lf); + //rect.expandToInclude(lf.getRect()); + //vct.add((LeafElement)lf.clone()); + } + + for(int i=0;i<20000; i++){ + iy = rnd.nextInt(h);//height + ix = rnd.nextInt(w);//width + LeafElement lf = new LeafElement(new Rect(ix,iy,ix,iy),218); + rt.insert(lf); + //rect.expandToInclude(lf.getRect()); + //vct.add((LeafElement)lf.clone()); + } + //rectangles + for(int i=0;i<30000; i++){ + iy = rnd.nextInt(h-2);//height + ix = rnd.nextInt(w-2);//width + xy = rnd.nextInt(h - iy); + xx = rnd.nextInt(w - ix); + LeafElement lf = new LeafElement(new Rect(ix,iy,ix+xx,iy+xy),218); + rt.insert(lf); + rect.expandToInclude(lf.getRect()); + //vct.add((LeafElement)lf.clone()); + } + //for(int i=0; i maxX) + maxX = xx; + System.out.println("MaxX: "+xx); + + xy = ds.readInt(); + if(xy > maxY) + maxY = xy; + System.out.println("MaxY: "+xy); + System.out.println("Pointer: "+ds.readLong()); + } + } + catch(Exception e){ + System.out.println("Error"); + System.exit(1); + } + + } +} diff --git a/DataExtractionOSM/src/rtree/seeded/SdNode.java b/DataExtractionOSM/src/rtree/seeded/SdNode.java new file mode 100644 index 0000000000..dfe3790919 --- /dev/null +++ b/DataExtractionOSM/src/rtree/seeded/SdNode.java @@ -0,0 +1,109 @@ +//SdNode.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.seeded; + +import rtree.*; +import java.io.*; +import rtree.Node; +import rtree.IllegalValueException; +import rtree.NodeWriteException; +import java.io.IOException; + +/** + The seed node. + @author Prachuryya Barua +*/ +public class SdNode extends Node +{ + /** + For a new node. + */ + public SdNode(RandomAccessFile file,String fileName, long prnt,int elmtType, FileHdr flHdr) + throws IOException, NodeWriteException + { + super(file, fileName, prnt, elmtType, flHdr); + } + + public SdNode(RandomAccessFile file, String fileName, long ndIndex, FileHdr flHdr) + throws FileNotFoundException,IOException, NodeReadException, NodeWriteException + { + super(file, fileName, ndIndex, flHdr); + } + + SdNode(Node node) + { + + } + public int getElementIndex(long param1) + { + return super.getElementIndex(param1); + } + public void insertElement(Element[] elmts ) + throws NodeWriteException, NodeFullException + { + super.insertElement(elmts, false); + } + public void insertElement(Element elmt) + throws NodeWriteException, NodeFullException + { + super.insertElement(elmt); + } + public Element getLeastEnlargement(Element elmt) + throws NodeEmptyException, IllegalValueException, NodeWriteException + { + return super.getLeastEnlargement(elmt); + } + + /** + * Overriden so that this package can use it. + * @param param1 + * @return + * @exception RTreeException + */ + public Node[] splitNode(Element param1, long slotIndex) throws RTreeException, NodeWriteException + { + Node[] nodes = super.splitNode(param1, slotIndex); + return nodes; + } + + /** + * Overriden so that this package can use it. + */ + public void modifyElement(int index,long pointer) + throws IllegalValueException, IOException, NodeWriteException + { + super.modifyElement(index, pointer); + } + + public void deleteNode() throws NodeWriteException + { + super.deleteNode(); + } + + public void modifyElement(int param1, Rect param2) + throws IllegalValueException, IOException, NodeWriteException + { + super.modifyElement(param1, param2); + } + + public void deleteElement(int param1) throws IllegalValueException, NodeWriteException + { + super.deleteElement(param1, false); + } + + public void setParent(long param1) throws IOException, NodeWriteException + { + super.setParent(param1); + } + +} + diff --git a/DataExtractionOSM/src/rtree/seeded/SdTree.java b/DataExtractionOSM/src/rtree/seeded/SdTree.java new file mode 100644 index 0000000000..6e77e8b35b --- /dev/null +++ b/DataExtractionOSM/src/rtree/seeded/SdTree.java @@ -0,0 +1,324 @@ +//SdTree.java +// +//This library is free software; you can redistribute it and/or +//modify it under the terms of the GNU Lesser General Public +//License as published by the Free Software Foundation; either +//version 2.1 of the License, or (at your option) any later version. +// +//This library is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//Lesser General Public License for more details. +package rtree.seeded; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import rtree.Element; +import rtree.IllegalValueException; +import rtree.Node; +import rtree.NodeFullException; +import rtree.NodeReadException; +import rtree.NodeWriteException; +import rtree.NonLeafElement; +import rtree.RTree; +import rtree.RTreeException; +import rtree.Rect; + +/** + This is a seeded class is good only for joining with the seeding class and not for window + queries. + How to use: + 1) Call the constructor. + 2) For each element to be inserted call growLeaf + 3) Positively call cleanup + 4) If you want you can create another rtree object from this file then flush the seed tree. Remember if + this tree is used for query purpose and not going to be used again, there is no need to flush. + @author Prachuryya Barua +*/ +public class SdTree extends RTree +{ + private String seedName = null; + private RTree sdingTree = null; + private int slotLvl = 1; + + /** + @param fileName The rtree filr name of this seed tree. + @param sdingTree The RTree from which to start seeding. + */ + public SdTree(String fileName, RTree sdingTree) + throws RTreeException + { + super(fileName);//this method should do its own locking + try{ + System.out.println("SdTree:: sedding height is " + sdingTree.getHeight()); + fileHdr.lockWrite(); + try{ + fileHdr.setBufferPolicy(false); + if(sdingTree == null) + throw new IllegalArgumentException("SdTree: Seeding tree is null"); + this.sdingTree = sdingTree; + setSlot(); + if(slotLvl >= 1) + seed(); + //growLeaf(); + }catch(Exception e){throw new RTreeException(e.getMessage());} + }finally{ + fileHdr.unlock(); + } + } + private void setSlot() + { + int ht = sdingTree.getHeight(); + switch(ht){ + case 0 : slotLvl = Node.NOT_DEFINED; + break; + case 1 : slotLvl = Node.NOT_DEFINED; + break; + case 2 : slotLvl = Node.NOT_DEFINED; + break; + case 3 : slotLvl = 1; + break; + case 4 : slotLvl = 2; + break; + } + } + /** + Start seeding - take the root node, copy it to this tree, keep on copying until the slot level. + This method overwrites the root irrespective of its existance or nonexistence. + */ + private void seed() + throws RTreeException + { + try{ + long sdingRoot = sdingTree.getFileHdr().getRootIndex(); + //somehow remove all the nodes of this tree from the cache and since we have a write lock + //nobody can get this tree's nodes on to the buufer if we don't + + Node sdingNode = sdingTree.getReadNode(sdingRoot); + seedRec(sdingNode, chdNodes.getNode(fileHdr.getFile(), fileName, Node.NOT_DEFINED,//sd + sdingNode.getElementType(), fileHdr), 0); + }catch(Exception e){ + e.printStackTrace(); + throw new RTreeException(e.getMessage()); + } + } + /** + @param sdingNode The seeding node from which to copy (source). + @param level The height at which this node falls in the tree. + */ + private void seedRec(Node sdingNode, Node sdNode, int level)//sd + throws Exception + { + if(sdingNode.getElementType() == Node.LEAF_NODE) + throw new IllegalArgumentException("SdTree.seedRec : Cannot seed a leaf node"); + + //make the child nodes before hand so that we know their indices in file + Node[] chNodes = null;//sd + if(level != slotLvl)//we do not need to alocate new nodes if we are at slot level + chNodes = new Node[sdingNode.getTotalElements()];//sd + + Element[] elmts = sdingNode.getAllElements(); + Element[] newElmts = null;//elements for non-slot levels + + if(level != slotLvl) + newElmts = new Element[sdingNode.getTotalElements()];//non slots have multiple elements + else{ + newElmts = new Element[1];//slot has only one element + newElmts[0] = new NonLeafElement(new Rect(), Node.NOT_DEFINED);//element for slot level + } + for(int i=0; iRTree.chooseLeaf with minor modifications. + In fact there are number of changes , most important is that this method will just not get the new + Node, but also change the parent's (slot node) child pointer. + Remeber that if there are no leaf node associated with a slot selected, this method creates one + returns this new Node after doing the process described above. + but if there is a leaf node present then that node is returned just as in simple rtrees. + */ + private Node chooseLeaf(Element elmt, LongWraper slotIndex)//sd + throws RTreeException, IOException + { + /*TODO : we may also have to traverse non seed node, i.e grown nodes.*/ + try{ + //get the root node + long root = fileHdr.getRootIndex(); + int level = 0; + Node sltNode = chdNodes.getNode(fileHdr.getFile(), fileName, root, fileHdr);//sd + //repeat till you reach a slot node + while(sltNode.getElementType() != Node.LEAF_NODE){//(level != slotLvl){ + //get the best fitting rect from the node + Element nextElmt = sltNode.getLeastEnlargement(elmt); + if(level == slotLvl){ + slotIndex.val = sltNode.getNodeIndex(); + if(nextElmt.getPtr() == Node.NOT_DEFINED){//the first leaf node for this slot node + Node rtNode = chdNodes.getNode(fileHdr.getFile(), fileName, sltNode.getNodeIndex(),//sd + Node.LEAF_NODE, fileHdr); + + sltNode.modifyElement(0, rtNode.getNodeIndex()); + nextElmt.setPtr(rtNode.getNodeIndex()); + return rtNode; + } + } + //if are here then we are not at a slot that has no childs + + sltNode = chdNodes.getNode(fileHdr.getFile(), fileName, nextElmt.getPtr(), fileHdr);//sd + level++; + }//while + //if we are here then we reached a proper leaf node rather than a slot node + return sltNode; + }catch(Exception e){ + e.printStackTrace(); + throw new RTreeException(e.getMessage()); + } + } + + /** + This method will adjust the slot's only elements's child pointer. + */ + private void adjustSlot(Node node, long childIndex)//sd + throws RTreeException + { + try{ + node.modifyElement(0, childIndex); + }catch(Exception e){ + e.printStackTrace(); + throw new RTreeException(e.getMessage()); + } + } + + /** + * The clean up pahse is the last method that should be called after all the data have been grown. + * This method basically adjusts all the slot nodes after all the insertions are made + */ + public void cleanUp() + throws RTreeException + { + try{ + fileHdr.lockWrite(); + if(slotLvl == Node.NOT_DEFINED) + return; + long root = fileHdr.getRootIndex(); + Node node = chdNodes.getNode(fileHdr.getFile(), fileName, root, fileHdr);//sd + cleanUpRec(node, 0); + }catch(Exception e){ + e.printStackTrace(); + throw new RTreeException(e.getMessage()); + }finally{ + fileHdr.unlock(); + } + } + + /** + * This method adjusts all the seed node MBRs to the grown subtrees. It also delets the slot node and + * makes the root node of the underneath substree as the slot node. + */ + private Rect cleanUpRec(Node node, int level)//sd + throws NodeWriteException, FileNotFoundException, IllegalValueException, IOException, NodeReadException, + RTreeException + { + Element[] elmts = node.getAllElements(); + if(level == slotLvl){//if level is the slot + if(elmts[0].getPtr() == Node.NOT_DEFINED){//this slot was never supplied a child node + node.deleteNode(); + return new Rect();//a null rect + }else{//a slot that does have child node + //remove this slot node and make the parent element point to the child of this slot node + + Node parentNode = chdNodes.getNode(fileHdr.getFile(), fileName, node.getParent(), fileHdr);//sd + int index = parentNode.getElementIndex(node.getNodeIndex()); + parentNode.modifyElement(index, elmts[0].getPtr()); + + Node subRoot = chdNodes.getNode(fileHdr.getFile(), fileName, elmts[0].getPtr(), fileHdr);//sd + + subRoot.setParent(node.getParent()); + node.deleteNode(); + + return(subRoot.getNodeMBR()); + }//else + }else{//it is not slot node but a seed node + //remebeer we may have a situation where we do not get any Rect from down below this node...we delete + //this node as well. + Rect rect = new Rect(); + for(int i=node.getTotalElements()-1; i>-1; i--){//for each element in this seed node + Node chNode = chdNodes.getNode(fileHdr.getFile(), fileName, elmts[i].getPtr(), fileHdr);//sd + Rect chRect = cleanUpRec(chNode, level + 1); + rect.expandToInclude(chRect);//get child node's rect + if(chRect.isNull()){//situation where child node does not have grown subtrees underneath + node.deleteElement(i, false); + }else{//we do have a child Rect + node.modifyElement(i, chRect); + }//else + }//for + if(rect.isNull()){//situation where there are no grown subtrees underneath this node + node.deleteNode(); + } + return rect; + }//else + } + class LongWraper + { + long val = Node.NOT_DEFINED; + } +} +//(79 residential_1 conby 121 main_area ** select * from main_area where strName like 'andheri'**)