implement new version of vector index

git-svn-id: https://osmand.googlecode.com/svn/trunk@592 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-10-27 10:36:07 +00:00
parent 2176d32a00
commit 45b8c23ee8
46 changed files with 11252 additions and 265 deletions

View file

@ -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]);

View file

@ -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<Bounds> stackBounds = new Stack<Bounds>();
// internal constants to track state of index writing
private Stack<Integer> state = new Stack<Integer>();
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();
}
}

File diff suppressed because it is too large Load diff

View file

@ -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<PreparedStatement, Integer> 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<Integer> typeUse, List<Long> 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);

View file

@ -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;
}
}
}

View file

@ -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<Long, Set<Integer>> multiPolygonsWays0 = new LinkedHashMap<Long, Set<Integer>>();
@ -147,8 +161,6 @@ public class IndexCreator {
private Map<Long, Set<Integer>> multiPolygonsWays2 = new LinkedHashMap<Long, Set<Integer>>();
private Map<Long, String> multiPolygonsNames = new LinkedHashMap<Long, String>();
private Map<Long, List<Long>> highwayRestrictions = new LinkedHashMap<Long, List<Long>>();
private Map<Long, List<Way>> lowLevelWaysSt = new LinkedHashMap<Long, List<Way>>();
private Map<Long, List<Way>> lowLevelWaysEnd = new LinkedHashMap<Long, List<Way>>();
// 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 <T, R> void putIntoMap(Map<T, List<R>> map, T key, R value){
if(!map.containsKey(key)){
map.put(key, new ArrayList<R>());
}
map.get(key).add(value);
}
private <T, R> void removeValueMap(Map<T, List<R>> 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<Long, Set<Integer>> multiPolygonsWays;
if (level == 0) {
multiPolygonsWays = multiPolygonsWays0;
} else if (level == 1) {
multiPolygonsWays = multiPolygonsWays1;
} else if (level == 2) {
multiPolygonsWays = multiPolygonsWays2;
} else {
multiPolygonsWays = Collections.emptyMap();
}
boolean writeIntoDB = true;
boolean ring = true;
if(e instanceof Way && level > 0){
List<Node> 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<Integer> 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<Node> nodes = ((Way) e).getNodes();
Way way = new Way(id);
for (String t : e.getTagKeySet()) {
way.putTag(t, e.getTag(t));
}
int prevX = 0;
int prevY = 0;
int len = 0;
for (int i = 0; i < nodes.size(); i++) {
// do not simplify last node it could be important node for multipolygon
if (nodes.get(i) != null) {
int r = i < nodes.size() - 1 ? 4 : 0;
int x = (int) (MapUtils.getTileNumberX(zoom, nodes.get(i).getLongitude()) * 256d);
int y = (int) (MapUtils.getTileNumberY(zoom, nodes.get(i).getLatitude()) * 256d);
int dy = Math.abs(y - prevY);
int dx = Math.abs(x - prevX);
if (dx > r || dy > r) {
way.addNode(nodes.get(i));
len += (dx + dy);
prevX = x;
prevY = y;
}
}
}
e = way;
skip = way.getNodes().size() < 2;
if (!hasMulti && len < 8) {
skip = true;
}
}
}
if (!skip) {
String eName = MapRenderingTypes.getEntityName(e, type);
if (eName == null) {
eName = multiPolygonsNames.get(baseId);
}
DataIndexWriter.insertMapRenderObjectIndex(pStatements, mapObjStat, mapLocations, mapTree, e, eName, id, type, typeUse,
restrictionsUse, useRestrictions, inverse, point, BATCH_SIZE);
}
}
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<Long, Set<Integer>> 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;
}
*/
}

View file

@ -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<Integer> addTypes) {
public static int encodeEntityWithType(Entity e, int level, boolean multipolygon, List<Integer> additionalTypes) {
if (types == null) {
types = new LinkedHashMap<String, MapRulType>();
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) {

View file

@ -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).<br>
In English - This is the minimum distance between the query point P
and the MBR of the object.
<b>Note:-</b> The distance(minDist) is the square of the actual distance.
To get the actual distance, call <b>Math.sqrt(minDist)</b> (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

View file

@ -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;
/**
<b>A circular linked list of cached nodes using hashtable ?!!</b>
<p>This class will wrap a list of recently used nodes.
If the requested node is in <tt>Hashtable</tt> of the class then the node would
be returned from the <tt>Hashtable</tt>, else it would be read from the
disk.
<br>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 <code>SdNode</code>
*/
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 <code>SdNode</code>.
*/
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 <code>Node</code>.
*/
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 <code>SdNode</code>.
*/
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 <code>Node</code>.
*/
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 <code>ReadNode</code> 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 <code>Node</code> are <code>synchronized</code>.
*/
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.
*/

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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 <code>long</code> but they can be easily represented as
<code>int</code>*/
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 <b>one</b> 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 <tt>interested</tt>, then on next <tt>notifyAll</tt> 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.<br>
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 <tt>Pack.packTree</tt>.
*/
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) &&
((frNode = ds.readInt()) != Node.NOT_DEFINED))
S[++topIdx] = frNode;
ds.close();
}
}
catch(Exception e){
throw new RTreeException("FileHdr.FileHdr: " +e.getMessage());
}
}
/**
This method at the moment is only for Pack. This one has potential!
*/
public void setBufferPolicy(boolean writeThr)
throws IOException
{
flush();
this.writeThr = writeThr;
}
/**
This method will be used by the Pack class to update this header from the file again. I assume that
the object that called this method has write lock with it.
*/
void update(String fileName)
throws RTreeException
{
try{
file.close();
this.file = new RandomAccessFile(fileName,"rw");
//file.getFD().sync();
S = new int[this.stkLimit];
topIdx = -1;
int frNode;
dirty = false;
//no nodes present
//if(file.length() <= (Node.FILE_HDR_SIZE+1)){
if(file.length() <= (Node.INTEGER_SIZE)){
file.seek(0);
file.writeInt(0);
file.writeLong(Node.NOT_DEFINED);//file.writeInt(Node.NOT_DEFINED);
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)
&& ((frNode = ds.readInt()) != Node.NOT_DEFINED))
S[++topIdx] = frNode;
ds.close();
}
}
catch(Exception e){
e.printStackTrace();
throw new RTreeException("FileHdr.FileHdr: " +e.getMessage());
}
}
/**
Will set the file header size to zero and remake the file header.
*/
void resetHeader()
throws Exception
{
S = new int[this.stkLimit];
topIdx = -1;
int frNode;
file.setLength(1);
file.seek(0);
file.writeInt(0);
file.writeLong(Node.NOT_DEFINED);
file.writeInt(Node.NOT_DEFINED);
totalNodes = 0;
rootIndex = Node.NOT_DEFINED;
dirty = false;
}
/**
Pass the index of the node that needs to be pushed in the stack
*/
synchronized void push(long lval)
throws StackOverflowException,IOException
{
int val = (int)lval;
if(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 <code>RandomAccessFile</code> 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 <b>not</b> 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<waiters.size();i++)
str += "\n" + i + " : " + waiters.get(i).toString();
}
return str;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
Vector getWaiters()
{
return waiters;
}
synchronized void setWaiters(Vector wtrs)
{
waiters = wtrs;
}
}
/**
* The class helps to store the details of a thread, like lockType
*/
class ThreadInfo
{
int lockType;
int nAcquired=0;
Thread t;
ThreadInfo(Thread t,int lockType)
{
this.t = t;
this.lockType = lockType;
}
public String toString()
{
String str = new String("\nThreadInfo");
str += "\n lockType : "+ lockType;
str += "\n nAcquired : "+ nAcquired;
str += "\n Thread : "+ t;
return str;
}
}

View file

@ -0,0 +1,27 @@
//IllegalValueException.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;
/**
@author Prachuryya Barua
*/
public class IllegalValueException extends Exception
{
public IllegalValueException (){
super ();
}
public IllegalValueException(String s){
super(s);
}
}

View file

@ -0,0 +1,109 @@
//LeafElement.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.*;
/**
This class represents database objects.
It consist of a MBR and the PID of the object.
@author Prachuryya Barua
*/
public class LeafElement extends Element
{
/**
for the time being it is 'int'.
Changed to long
*/
long recordPtr;
public LeafElement( Rect minBndRect,long recordPtr)
{
super(minBndRect);
this.recordPtr = recordPtr;
}
/**
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);
}
/**
The <tt>"Id"</tt> 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 <code>LeafElement</code> 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");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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.
<p>Original comments
A utility class that packs a rtree.
<br>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).
<p><b> Never create more than one instance of this class.
<br>Never run the methods of this class in any other thread except the main
thread and make sure it is the only thread running.
<br>Positively remember to reinitialise all the rtree objects after you
call <code>packTree</code>.</b>
@author Prachuryya Barua
*/
public class Pack
{
public Pack(){};
/**
Added this new method that takes a list of <code>Element</code>s 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<elmts.size(); i++)
rtree.insert((LeafElement)elmts.get(i));
rtree.flush();
return 0;
}
return packTree((Element[])elmts.toArray(new Element[elmts.size()]), new RTree(newFile), newFile);
}catch(Exception e){
e.printStackTrace();
return 2;
}
}
/**
Sort-Tile-Recursive(STR) packing algo. by Leutenegger.
<p><b>**FLUSH THE RTREE BEFORE CALLING**</b>
<br>Prepocess the file and sort the rectangles
<br>Load into file
<br>Recursively pack above MBRs to nodes at the next level.
<br>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 <b>0</b> if successfully created a new file,
<br><b>1</b> 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,
<br> 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; i<S; i++){
if((start + (S*Node.MAX)) <= length)
end = start+((S*Node.MAX)-1);
else
end = length - 1;
sls[i] = new Slice(start,end);
start = end+1;
}
//sort each slice on Y axis and write to file
for(int i=0; i<S; i++)
NonLeafElement.twoWayMerge(elmts,sls[i].start,sls[i].end,1);
int newLength = writePckFile(rFile,tmpPckFile,elmts,sls);
if(newLength == 1)//last insertion was a root
return;
packRec(rFile,tmpPckFile,elmts,newLength);
}
/**
Method that handles the low level details of nodes, leaves, file headers etc.
It writes the details to the rtree file.
@return the no. of new leaf elements created. The element themselves are in
the 'elmts' array.
*/
private int writePckFile(RandomAccessFile rFile,File tmpPckFile,
Element[] elmts,Slice[] sls)
throws Exception
{
FileHdr hdr = new FileHdr(Node.FREE_LIST_LIMIT,tmpPckFile.getAbsolutePath());
hdr.setBufferPolicy(true);
int length;
Double totNodes;//total nodes for the slice
int netNodes = 0;// !?!!
int l=0;//the position on to which the old elmt. would be replaced
for(int i=0; i<sls.length; i++){//for each slice
//cal. the length of this slice
length = sls[i].end - sls[i].start + 1;
//calculate the no. of new nodes for the slice
totNodes = new Double(length);
totNodes= new Double(Math.ceil(totNodes.doubleValue()/Node.MAX));
netNodes += totNodes.intValue();
//make nodes of the elements in the slice
for(int j=0; j<totNodes.intValue(); j++){//loop for each new node
Node node = new Node(rFile,tmpPckFile.getAbsolutePath(), Node.NOT_DEFINED,
elmts[sls[i].start].getElementType(), hdr);
//add elements to the node
ArrayList list = new ArrayList(Node.MAX);
for(int k=0; (k<Node.MAX) && (sls[i].start <= sls[i].end); k++){
//node.insertElement(elmts[sls[i].start++]);
list.add(elmts[sls[i].start++]);
}
node.insertElement((Element[])list.toArray(new Element[list.size()]), true);
//create the new nonleaf element - always nonleaf
NonLeafElement nlf = new NonLeafElement(node.getNodeMBR(),node.getNodeIndex());
elmts[l++] = (NonLeafElement)nlf.clone();
}
}
return netNodes;
}
/**An inner class for the packing method*/
class Slice
{
int start;
int end;
Slice(int start,int stop)
{
this.start = start;
this.end = stop;
}
}
/**A wrapper class for int*/
class Int
{
int val;
Int(int val)
{
this.val = val;
}
}
}

View file

@ -0,0 +1,23 @@
//PageFaultException.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 a page fault occurs in the CachedNodes class
@author Prachuryya Barua
*/
class PageFaultException extends Exception
{
PageFaultException(String msg)
{
super(msg);
}
}

View file

@ -0,0 +1,47 @@
//Point.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;
/**
A simple class used only in nearestNeighbour search.
@author Prachuryya Barua
*/
public class Point implements Cloneable
{
private int X=0,Y=0;
public Point(int x,int y)
{
X = x;
Y = y;
}
public int getX()
{
return X;
}
public int getY()
{
return Y;
}
public Object clone()
{
return new Point(X,Y);
}
public String toString()
{
String ret;
ret = "\nThe Point:-";
ret += "\n\tX: " + X;
ret += "\n\tY: " + Y;
return ret;
}
}

File diff suppressed because it is too large Load diff

View file

@ -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<response.length;i++)
{
abl[i]=(ABL)response[i];
}
return abl;
}
else
return null;
}
catch(RTreeException e)
{
throw e;
}
}
public List nearestSearch(Point pt,long ln) throws RTreeException
{
try
{
String command="nearestsearch";
Object obj[]={pt,new Long(ln)};
Object[] response=sendRequest(command,obj);
return (List) response[0];
}
catch(RTreeException e)
{
throw e;
}
}
private Object[] sendRequest(String command,Object[] param) throws RTreeException
{
try
{
ByteArrayOutputStream bout=new ByteArrayOutputStream ();
ObjectOutputStream out=new ObjectOutputStream (bout);
// ObjectOutputStream out=new ObjectOutputStream(socket.getOutputStream());
OutputStream fout=socket.getOutputStream ();
out.writeObject(command);
if(param!=null)
{
out.writeObject(new Integer (param.length));
for(int i=0;i<param.length;i++)
{
out.writeObject(param[i]);
}
}
else
{
out.writeObject(new Integer(0));
}
// out.flush();
out.close();
//long time = System.currentTimeMillis();
fout.write(bout.toByteArray());
fout.flush();
// InputStream in=socket.getInputStream();
/*
while(in.available()==0)
{
Thread.sleep(10);
}
int rTotal=in.available();
System.out.println("RTotal..........."+rTotal);
byte[] bb=new byte[in.available()];
in.read(bb,0,in.available());
byte ln[]=new byte[10];
System.arraycopy(bb,0,ln,0,10);
ByteArrayInputStream lin=new ByteArrayInputStream(ln);
ObjectInputStream loin=new ObjectInputStream(lin);
int total=loin.readInt();
byte bbf[]=new byte[rTotal];
System.out.println(total+"..."+bbf.length);
System.arraycopy(bb,10,bbf,0,rTotal-10);
int pos=bbf.length;
System.out.println("Postion................."+pos);
while(rTotal<total)
{
int avail=in.available();
while(avail==0)
{
avail=in.available();
}
byte temp[]=new byte[avail];
in.read(temp,0,avail);
byte temp1[]=new byte[avail+bbf.length];
System.arraycopy(bbf,0,temp1,0,bbf.length);
System.arraycopy(temp,0,temp1,bbf.length,temp.length);
bbf=temp1;
rTotal+=avail;
System.out.println(bbf.length+"______________________");
System.arraycopy(temp,0,bbf,pos,temp.length);
pos+=avail;
Thread.sleep(10);
}
*/
InputStream in=socket.getInputStream();
//System.out.println("RTreeClient.sendRequest : time to receive response "
//+ (System.currentTimeMillis() - time));
//time = System.currentTimeMillis();
byte bbf[]=new byte[100];
int i=0;
int total=-1;
while(true)
{
int val=in.read(bbf,i,1);
if(val==-1)
break;
i++;
if(i==10)
{
byte ln[]=new byte[10];
System.arraycopy(bbf,0,ln,0,10);
ByteArrayInputStream lin=new ByteArrayInputStream(ln);
ObjectInputStream loin=new ObjectInputStream(lin);
total=loin.readInt();
byte temp[]=new byte[total];
System.arraycopy(bbf,0,temp,0,bbf.length);
bbf=temp;
}
if(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;j<count.intValue();j++)
{
obj[j]=oIn.readObject();
}
// oIn.close();
//System.out.println("RTreeClient.sendRequest : time to process input data "
// + (System.currentTimeMillis() - time));
return obj;
}
else
{
throw (Exception) oIn.readObject();
}
}
catch(Exception e)
{
e.printStackTrace();
throw new RTreeException(e.getMessage());
}
}
/**
public static void main(String args[])
{
try
{
RTreeClient cln=new RTreeClient("localhost",7001);
System.out.println("Connection established1...");
Rect rect=cln.getTreeMBR();
System.out.println("........."+rect);
List v=cln.getAllElements();//contains(new Rect(0,0,1000,1000));
System.out.println(v.size());
System.out.println(v.get(0));
}
catch(Exception e)
{
e.printStackTrace();
}
} */
}

View file

@ -0,0 +1,23 @@
//RTreeException.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;
/**
for any major RTree Exception
@author Prachuryya Barua
*/
public class RTreeException extends Exception
{
public RTreeException(String msg)
{
super(msg);
}
}

View file

@ -0,0 +1,22 @@
//RTreeInsertException.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 some error arises inserting an element
@author Prachuryya Barua
*/
public class RTreeInsertException extends Exception
{
public RTreeInsertException(String msg)
{
super(msg);
}
}

View file

@ -0,0 +1,247 @@
//ReadNode.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.*;
/***********************************************************************************************************
* * *
* This is a special purpose class that is alowed read only operartion on tree. Any write operation *
* would give error. *
* This class was necessary to solve the following problem. Since none of the nodes are cloned when given *
* to the clients, they can become problematic when multiple reads on the same node is going on. *
* Because of the new buffer policy we do not clone node, it is like a single node in the whole system. *
* But the obvious problem is multiple read threads when reading nodes. *
* No though problem when writing as the whole tree is locked. What we can do is that clients themselves *
* tell the cache that they need a cloned node and that it willnot be used for write purpose. *
* This class does exactly that. *
* @author Prachuryya Barua
***********************************************************************************************************/
class ReadNode extends Node
{
ReadNode()
{
}
public static ReadNode makeReadNode(Node node)
{
ReadNode rdNode = new ReadNode();
try{
//Integer intVal;
rdNode.file = node.file;
rdNode.dirty = node.dirty;
rdNode.fileName = new String(node.fileName.toCharArray());
rdNode.nodeIndex = node.nodeIndex;
//rdNode.isNodeEmpty = node.isNodeEmpty;
rdNode.sorted = node.sorted;
rdNode.nodeMBR = new Rect(node.nodeMBR);//remove
rdNode.elements = new Element[node.elements.length];
if(node.elementType == LEAF_NODE){
for(int i=0; i<node.totalElements; i++)
rdNode.elements[i] = new LeafElement(new Rect(node.elements[i].getRect()),
node.elements[i].getPtr());
}else{
for(int i=0; i<node.totalElements; i++)
rdNode.elements[i] = new NonLeafElement(new Rect(node.elements[i].getRect()),
node.elements[i].getPtr());
}
// for(int i=0; i<node.totalElements; i++){
// if(node.elementType == LEAF_NODE)
// rdNode.elements[i] = new LeafElement(new Rect(node.elements[i].getRect()),
// node.elements[i].getPtr());
// else
// rdNode.elements[i] = new NonLeafElement(new Rect(node.elements[i].getRect()),
// node.elements[i].getPtr());
// }//if
// }//for
rdNode.fileHdr = node.fileHdr;
rdNode.totalElements = node.totalElements;
rdNode.parent = node.parent;
rdNode.elementSize = node.elementSize;
rdNode.elementType = node.elementType;
return rdNode;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
/**
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
{
throw new UnsupportedOperationException("operation not supported");
}
public void insertElement(Element elmt)
throws NodeWriteException, NodeFullException
{
throw new UnsupportedOperationException("operation not supported");
}
public void insertElement(Element[] elmts, boolean updateChldrn)
throws NodeWriteException, NodeFullException
{
throw new UnsupportedOperationException("operation not supported");
}
public int getElementType()
{
return super.getElementType();
}
public long getNodeIndex()//for new nodes
{
return super.getNodeIndex();
}
Rect[] getAllRectangles()
throws IllegalValueException
{
return super.getAllRectangles();
}
public Element getLeastEnlargement(Element elmt)
throws NodeEmptyException, IllegalValueException, NodeWriteException
{
return super.getLeastEnlargement(elmt);
}
boolean isInsertPossible()
{
return super.isInsertPossible();
}
public Node[] splitNode(Element elmtM1, long slotIndex)
throws RTreeException, NodeWriteException
{
throw new UnsupportedOperationException("operation not supported");
}
public long getParent()
{
return super.getParent();
}
public int getElementIndex(long ptr/*Object ptr*/)
{
return super.getElementIndex(ptr);
}
/**
Used to overwrite the old Element with the new one.
It modifies the element in the disk as well as in the local variables.
*/
public void modifyElement(int index,Element elmt)
throws IllegalValueException,IOException, NodeWriteException
{
throw new UnsupportedOperationException("operation not supported");
}
/**
Overloaded
*/
public void modifyElement(int index,long pointer)
throws IllegalValueException,IOException, NodeWriteException
{
throw new UnsupportedOperationException("operation not supported");
}
/**
Overloaded
*/
public void modifyElement(int index,Rect rect)
throws IllegalValueException,IOException, NodeWriteException
{
throw new UnsupportedOperationException("operation not supported");
}
/**
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
{
return super.getNodeMBR();
}
/**
No error echecking at all.
*/
public void setParent(long /*int*/ prnt)
throws IOException, NodeWriteException
{
throw new UnsupportedOperationException("operation not supported");
}
public int getTotalElements()
{
return super.getTotalElements();
}
/**
Although it returns all the elements but the total elements will not be equal to the length of
the returned array.Therefore <br><b>Never Use <code>.length</code> field With the Returned Array
</b>. Instead use <code>getTotalElements()</code>.
@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.
</br><i><b>Once called, there is no turning back!</b></i>.
*/
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");
}
}

View file

@ -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. :-
<br>make the point class to hold the required dimensions.(keep an array of
dimensions)
<br>The rect class needs the four points directly, instead of that make it to
accept Point as its argument in the constructor.
<br>Then on deal with the point class directly instead of the four points
directly.
<p>The methods of relational topology(equals,contains etc.) are from various
papers by <b>D. Papadias</b> and mainly from Modeling Topological Spatial
Relation: Strategies for Query Processing.- <b>Egenhofer</b>
<br>The methods are nothing but set theories.
<p>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; i<rects.length; ++i)
result = getResultingMBR(rects[i],result);
return result;
}
/**
Another overloaded version - but static
*/
public static Rect getResultingMBR(Rect[] rects, Rect rect)
throws IllegalValueException
{
Rect result = getResultingMBR(rects);
result = getResultingMBR(rect,result);
return result;
}
//--------------------------Topological methods---------------------------
/**
Checks if this rectangle contains 'rect'.
<br>Checks the two minimal conditions from 'contains' matrix(Egenhofer.)
<br>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 <code>contains</code> is that this method returns true
even if the <code>covers</code> 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.
<br><b>Note:-</b>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).
<br>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)
<pre>
---------------
| |
| |------|
| |'rect'|
| |------|
| |
---------------
</pre>
*/
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.
<br><b>Note:-</b> 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
<b>(Not implemeneted yet).</b>
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 <code>this</code> and <code>rect</code>.
* @param rect The other <code>Rect</code>
*/
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)
<br> 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.
<br><b>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;
}
*/

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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.length) && (others[i] != null) &&
(others[i].getRect().getMaxX() < event.getRect().getMaxX());
i++){//while others are still intersecting with the event
if(event.getRect().getMinX() < others[i].getRect().getMinX() &&//check x as well
event.getRect().getMinY() < others[i].getRect().getMinY() &&//check the y coordinate
event.getRect().getMaxY() > 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 <code>elmt1</code>.
*/
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;
}
}
}

View file

@ -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.length) && (others[i] != null) &&
(others[i].getRect().getMaxX() < event.getRect().getMaxX());
i++){//while others are still intersecting with the event
if(event.getRect().getMinY() < others[i].getRect().getMinY() &&
event.getRect().getMaxY() > 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 <code>elmt1</code>.
*/
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;
}
}
}

View file

@ -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.length) && (others[i] != null) &&
(others[i].getRect().getMinX() <= event.getRect().getMaxX());
i++){//while others are still intersecting with the event
if(event.getRect().getMinY() < others[i].getRect().getMaxY() &&
event.getRect().getMaxY() > 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;
}
}
}

View file

@ -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.length) && (others[i] != null) &&
(others[i].getRect().getMinX() <= event.getRect().getMaxX());
i++){//while others are still intersecting with the event
if(event.getRect().getMinY() < others[i].getRect().getMaxY() &&
event.getRect().getMaxY() > 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;
}
}
}

View file

@ -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 <code>List</code> of <code>Pair</code>s 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 <code>Node</code>.
@param ret A <code>List</code> 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; i<pairs.size(); i++){//for each pair
PairElmt intPair = (PairElmt)pairs.get(i);//the intersecting pair at i
if(intPair.getLtElmt() instanceof NonLeafElement &&
intPair.getRtElmt() instanceof NonLeafElement){//both are non leaf elements
Node newLtNode = ltTree.getReadNode(intPair.getLtPtr());
Node newRtNode = rtTree.getReadNode(intPair.getRtPtr());
relateRec(newLtNode, newRtNode, newLtNode.getNodeMBR().intersection(newRtNode.getNodeMBR()),
ret);
}else if(intPair.getLtElmt() instanceof LeafElement &&
intPair.getRtElmt() instanceof LeafElement){//LeafElement
ret.add(p.paired(intPair.getLtElmt(), intPair.getRtElmt()));
//System.out.println("Join.intersectRec with size of ret - leaf " + ret.size());
}
}//for
}
}
/**
Joins two nodes of different types.
@param nlElmts non-leaf elements
@param lfElmts leaf elements
@param side The side of <code>nlElmts</code>. (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; (i<nlElmts.length) && (nlElmts[i] != null); i++){//for each elmt in non-leaf
for(int j=0; (j<lfElmts.length) &&(lfElmts[j] != null); j++){
if(nlElmts[i].getRect().overlaps(lfElmts[j].getRect())){
if(side == Join.LEFT)
ret.addAll(windowQuery(ltTree.getReadNode(nlElmts[i].getPtr()),
(LeafElement)lfElmts[j], side ));
else//non leaf is the right tree
ret.addAll(windowQuery(rtTree.getReadNode(nlElmts[i].getPtr()),
(LeafElement)lfElmts[j], side ));
}//if
}//for leaf-elements - j
}//for non-leaf-elements - i
return ret;
}
/**
* This method actually performs a simple window query on <code>nlNode</code> (a non-leaf Node).
* Will return a <code>List</code> of <code>Pair</code>. The pair is made accordingly <code>side</code>.
* @param side The side of <code>nlNode</code>.
*/
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; i<totElements; i++){//for every element; we can use sweepline algorithm here
//if(elmts[i].getRect().overlaps(lfElmt.getRect())){ //select elements that overlap
if(spLine.getPredicate().relateMismatch(elmts[i], lfElmt, side)){//select elements that overlap
if(elmts[i].getElementType() == Node.NONLEAF_NODE){//non leaf
list.addAll(windowQuery( nlTree.getReadNode(elmts[i].getPtr()), lfElmt, side));
}
else{//if leaf element
if(side == Join.LEFT)//here we add another condiation of the specified predicate
list.add(p.paired(elmts[i], lfElmt));
else
list.add(p.paired(lfElmt, elmts[i]));
}
}
}
return list;
}
/**
This method removes those elements from <code>elmts</code> that do not intersect <code>rect</code>.
The original elements, <code>elmts</code>, 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; i<elmts.length && elmts[i] != null; i++)
if(rect.overlaps(elmts[i].getRect()))
//ret[j++] = (Element)elmts[i].clone();//i hope java does not remove columns
ret[j++] = elmts[i];
return ret;
}
}

View file

@ -0,0 +1,24 @@
//JoinException.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;
/**
@author Prachuryya Barua
*/
public class JoinException extends Exception
{
public JoinException(){}
public JoinException(String msg)
{
super(msg);
}
}

View file

@ -0,0 +1,42 @@
//MeetPred.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 MeetPred extends Predicate
{
public MeetPred(){}
public void relate(Element event, int from, Element[] others, List pairs, int evtSide)
{
(new IntersectPred()).relate(event, from, others, pairs, evtSide);
}
public boolean relateMismatch(Element nlElmt, Element lfElmt, int side)
{
try{
//if(nlElmt instanceof NonLeafElement)
return nlElmt.getRect().overlaps(lfElmt.getRect());
//else
//return nlElmt.getRect().meet(lfElmt.getRect());
}catch(Exception e){
e.printStackTrace();
return false;
}
}
}

View file

@ -0,0 +1,50 @@
//Pair.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 keeps a pair of intersection between two trees.
* Basically the purpose of <code>Pair</code> and <code>PairElmt</code> 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 <code>this</code> type.
*/
public Pair paired(Element ltElmt, Element rtElmt)
{
return new Pair(ltElmt.getPtr(), rtElmt.getPtr());
}
}

View file

@ -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 <code>Pair</code> and <code>PairElmt</code> 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);
}
}

View file

@ -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 <code>Element</code> at which the event took place.
* @param from the index from which <code>others</code> start.
* @param others the <code>Element[]</code> to compare with <code>event</code>
* @param pairs a <code>List</code> value where the output pairs would put.
* @param evtSide tells whether <code>event</code> is from left tree or right tree.
* @param p a <code>Pair</code> 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 <code>Element</code>
* @param lfElmt the leaf <code>Element</code>
* @param side The side of <code>nlElmt</code> element.
* @return a <code>boolean</code> value
*/
public abstract boolean relateMismatch(Element nlElmt, Element lfElmt, int side);
/**
Returns the <code>Pair</code> which tells the type of output required.
*/
public Pair getPair()
{
return p;
}
}

View file

@ -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 <code>elmts</code> which intersect with
* <code>rect</code>. It is expected that <code>elmts</code> are sorted acording to <code>minX</code>
* @return either a <code>List</code> of eithers pointers or ehole elements depending upon <code>p</code>.
*/
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 <code>List</code> of <code>Pair</code> 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 <code>event</code> 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.length) && (others[i] != null) &&
(others[i].getRect().getMinX() <= event.getRect().getMaxX());
i++){//while others are still intersecting with the event
if(event.getRect().getMinY() < others[i].getRect().getMaxY() &&
event.getRect().getMaxY() > 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;
}
}

View file

@ -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<vct.size(); i++){
//System.out.println(i);
//delete(fileName, (LeafElement)vct.get(i));
//}
// RTreeRead rd = new RTreeRead(fileName);
// rd.readSeq();
System.out.println("Entry over in ms : " +(System.currentTimeMillis()-start)
+ " for thread " + Thread.currentThread());
}
//public
public void entry(String fileName)
{
try{
//Point data
/*
RTree rtree = new RTree(fileName);
LeafElement lf1 =
new LeafElement(new Rect(4,3,4,3),218);
LeafElement lf2 =
new LeafElement(new Rect(6,5,6,5),218);
LeafElement lf3 =
new LeafElement(new Rect(5,6,5,6),218);
LeafElement lf4 =
new LeafElement(new Rect(7,2,7,2),218);
rtree.insert(lf1);
rtree.insert(lf2);
rtree.insert(lf3);
rtree.insert(lf4);
*/
//BOXES
long start = System.currentTimeMillis();
RTree rtree = new RTree(fileName);
LeafElement lf1 = new LeafElement(new Rect(3,2,4,3),3243);//keep for join
rtree.insert(lf1);
rtree.delete(lf1);
/*
//getall(fileName);
RTree rtree1 = new RTree(fileName);
LeafElement lf2 = new LeafElement(new Rect(5,4,6,5),5465);
//rtree1.insert(lf2);
RTree rtree2 = new RTree(fileName);
LeafElement lf3 = new LeafElement(new Rect(9,6,10,7),96107);
//rtree2.insert(lf3);
RTree rtree3 = new RTree(fileName);
LeafElement lf4 = new LeafElement(new Rect(6,1,7,3),6173);//keep for join
rtree3.insert(lf4);
RTree rtree4 = new RTree(fileName);
LeafElement lf5 = new LeafElement(new Rect(6,2,8,3),6283);
//rtree4.insert(lf5);
RTree rtree5 = new RTree(fileName);
LeafElement lf6 = new LeafElement(new Rect(4,4,5,6),4456);
//rtree5.insert(lf6);
RTree rtree6 = new RTree(fileName);
LeafElement lf7 = new LeafElement(new Rect(5,3,7,4),5374);
//rtree6.insert(lf7);
RTree rtree7 = new RTree(fileName);
LeafElement lf8 = new LeafElement(new Rect(9,5,10,6),95106);//keep for join
rtree2.insert(lf8);
LeafElement lf9 = new LeafElement(new Rect(1,2,2,3),1223);//keep for join
rtree2.insert(lf9);
*/
System.out.println("Time in ms:" +(System.currentTimeMillis()-start));
System.out.println("Entry over");
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
/*
Random rect queries
*/
public void overlapRR(String name)
throws Exception
{
RTree rt = new RTree(name);
int ix,iy,xx,xy;
Random rnd = new Random(System.currentTimeMillis());
for(int i=0;i<1;i++){
iy = rnd.nextInt(h-2);//height
ix = rnd.nextInt(w-2);//width
xy = rnd.nextInt(h - iy);
xx = rnd.nextInt(w - ix);
long start4 = System.currentTimeMillis();
List elmts = null;
// elmts = rt.overlaps(new Rect(ix,iy,ix+xx,iy+xy));
// System.out.println("Time in ms:" + (System.currentTimeMillis()-start4));
// System.out.println("Search result-Total elements:"+elmts.size());
System.out.println("Sweep");
start4 = System.currentTimeMillis();
elmts = rt.overlapsSweep(new Rect(ix,iy,ix+xx,iy+xy));
System.out.println("Time in ms:" + (System.currentTimeMillis()-start4));
System.out.println("Search result-Total elements:"+elmts.size());
}
}
/*
Random point queries
*/
public void overlapRP(String name)
throws Exception
{
RTree rt = new RTree(name);
int ix,iy;
Random rnd = new Random(System.currentTimeMillis());
for(int i=0;i<10;i++){
iy = rnd.nextInt(h);//height
ix = rnd.nextInt(w);//width
long start4 = System.currentTimeMillis();
List elmts = rt.overlaps(new Rect(ix,iy,ix,iy));
System.out.println("Time in ms:" +
(System.currentTimeMillis()-start4));
System.out.println("Search result-Total elements:"+elmts.size());
/*
start4 = System.currentTimeMillis();
elmts = rt.overlaps(new Rect(ix,iy,ix,iy));
System.out.println("Time in ms:" +
(System.currentTimeMillis()-start4));
System.out.println("Search result-Total elements:"+elmts.size());
*/
}
}
public void getall(String name)
{
try{
//get All elements
RTree rt = new RTree(name);
long start1 = System.currentTimeMillis();
List elmts1 = rt.getAllElements();
System.out.println("Time in ms:" +
(System.currentTimeMillis()-start1));
System.out.println("Record fetched by "+
Thread.currentThread().getName()+
": " + elmts1.size());
/*
start1 = System.currentTimeMillis();
LinkedList elmts2 = rt.testgetAllElements();
System.out.println("Time in ms:" +
(System.currentTimeMillis()-start1));
System.out.println("Record fetched: " + elmts2.size());
*/
//for(int i=0; i<elmts2.length; i++)
//System.out.println(elmts2[i].toString());
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
public void overlap(String name,Rect rect)
{
try{
//Test overlap
RTree rt = new RTree(name);
long start4 = System.currentTimeMillis();
List elmts = rt.nonDisjoint(rect);
System.out.println("Time in ms:" +
(System.currentTimeMillis()-start4));
System.out.println("overlap Search -Total elements:"+elmts.size());
//for(int i=0;i<elmts.size();i++)
//System.out.println(((LeafElement)(elmts.elementAt(i))).toString());
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
public void search(String name)
{
try{
//Search Nearest
RTree rt = new RTree(name);
int ix,iy;
Random rnd = new Random(System.currentTimeMillis());
//for(int i=0;i<10;i++){
iy = rnd.nextInt(h);//height
ix = rnd.nextInt(w);//width
Point pt =
new Point(ix,iy);
//Point pt =
//new Point(2618917,1264511);
//limited number
long start5 = System.currentTimeMillis();
ABL[] nrst = rt.nearestSearch(pt,50000000000L,10);
System.out.println("Time in ms for NNSearch(Limited):"+ (System.currentTimeMillis()-start5));
/*
for(int i=0;i<nrst.length;i++)
if(nrst[i] == null)
System.out.println("Could not find anything!!");
else
System.out.println("Result" + nrst[i].element.toString()
+"\tMINDIST:" + nrst[i].minDist);
*/
//unlimited
System.out.println("List");
start5 = System.currentTimeMillis();
List vec = rt.nearestSearch(pt,10000000000L);
System.out.println("Time in ms for NNSearch(Unlimited):"+ (System.currentTimeMillis()-start5));
System.out.println("Retrieved: "+vec.size());
//for(int i=0;i<vec.size();i++)
// System.out.println("Result" + ((ABL)(vec.elementAt(i)))
// .element.toString()
// +"\tMINDIST:" + ((ABL)(vec.elementAt(i)))
// .minDist);
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
public void delete(String name,LeafElement element)
{
try{
RTree rt = new RTree(fileName);
rt.delete(element);
//for(int i=0;i<150;i++)
//rt.delete(element);
}
catch(Exception e){
e.printStackTrace();
}
}
public void tryOverlap()
{
try{
Rect rect1 = new Rect();
//Rect rect1 = new Rect(3,2,5,4);
//Rect rect2 = new Rect(3,2,5,4);
//Rect rect2 = new Rect(4,3,4,3);//true
//Rect rect2 = new Rect(5,2,7,4);//false
//Rect rect2 = new Rect(3,4,5,5);//false
//Rect rect2 = new Rect(3,1,5,2);//false
//Rect rect2 = new Rect(3,1,5,3);//false
//Rect rect2 = new Rect(4,3,4,3);//true
//Rect rect2 = new Rect(5,3,5,3);//true
//Rect rect2 = new Rect(6,2,6,2);//false
//Rect rect2 = new Rect(2,1,6,5);//false
Rect rect2 = new Rect(4,2,5,3);
//Rect rect1 = new Rect(9,6,10,7);//true
//Rect rect2 = new Rect(8,5,11,8);//true
System.out.println(rect1.toString()+" \nand\n"+rect2.toString()
+"\noverlap? \n\tAns- "+rect2.contains(rect1));
}
catch(Exception e){
System.out.println("Exception "+e.getMessage());
}
}
public void tryIntersection()
{
try{
//Rect rect1 = new Rect(3,2,5,4);
//Rect rect2 = new Rect(3,2,5,4);//3 2 5 4
//Rect rect2 = new Rect(4,3,4,3);//4 3 4 3
//Rect rect2 = new Rect(5,2,7,4);//5 2 5 4 - not null but a single line
//Rect rect2 = new Rect(3,4,5,5);//3 4 5 4
//Rect rect2 = new Rect(3,1,5,2);//3 2 5 2
//Rect rect2 = new Rect(3,1,5,3);//3 2 5 3
//Rect rect2 = new Rect(4,3,4,3);//4 3 4 3
//Rect rect2 = new Rect(5,3,5,3);//5 3 5 3
//Rect rect2 = new Rect(6,2,6,2);//null
//Rect rect2 = new Rect(2,1,6,5);//3 2 5 4
//Rect rect2 = new Rect(4,2,5,3);//4 2 5 3
Rect rect1 = new Rect(9,6,10,7);//null
Rect rect2 = new Rect(8,5,11,8);//null - comp the two 9 6 10 7
System.out.println(rect1.toString()+" \nand\n"+rect2.toString()
+"\nIntersection \n\tAns- "+rect2.intersection(rect1));
}
catch(Exception e){
System.out.println("Exception "+e.getMessage());
}
}
public void tryCvr()
{
try{
Rect rect1 = new Rect(3,2,5,4);
Rect rect2 = new Rect(3,2,4,4);//true
//Rect rect2 = new Rect(6,2,6,2);//false
System.out.println(rect1.toString()+" \nand\n"+rect2.toString()
+"\nDoes first Eclose second? \n\tAns- "
+rect1.covers(rect2));
}
catch(Exception e){
System.out.println("Exception "+e.getMessage());
}
}
public void tryIntsct()
{
try{
Rect rect1 = new Rect(3,2,5,4);
//Rect rect2 = new Rect(3,2,3,2);//true
//Rect rect2 = new Rect(5,2,7,4);//false
//Rect rect2 = new Rect(3,2,3,2);//true
//Rect rect2 = new Rect(3,4,5,5);//false
//Rect rect2 = new Rect(3,1,5,2);//false
//Rect rect2 = new Rect(3,1,5,3);//true
//Rect rect2 = new Rect(4,3,4,3);//true - check
Rect rect2 = new Rect(3,2,3,2);//true
System.out.println(rect1.toString()+" \nand\n"+rect2.toString()
+"\nDo Both Intersect? \n\tAns- "
+rect1.meet(rect2));
}
catch(Exception e){
System.out.println("Exception "+e.getMessage());
}
}
public void trySeed(String sdTree, RTree rtree)
{
try{
//System.out.println("rTreeDemo.trySeed : height of rtree is " + rtree.getHeight());
SdTree sdt = new SdTree(sdTree, rtree);
//now grow
int ix,iy,xx,xy;//mIn,maX
Random rnd = new Random(seed);
long start = System.currentTimeMillis();
// LeafElement llf = new LeafElement(new Rect(1752, 2179, 5999888, 14999646),218);
// sdt.growLeaf(llf);
for(int i=0;i<2000000; 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);
sdt.growLeaf(lf);
}
sdt.cleanUp();
(new RTree(sdTree)).flush();
// RTreeRead rd = new RTreeRead(sdTree);
// rd.readSeq();
}catch(Exception e){
e.printStackTrace();
}
}
public List tryJoin()
{
try{
//String lt = new String("c:\\temp\temptree.dat");
//String lt = new String("/mnt/projects/data/MUM4_78.idx");
//String rt = new String("/mnt/projects/data/MUM4_118.idx");
RTree ltTree = new RTree(/*lt*/fileName+"1");
RTree rtTree = new RTree(/*rt*/fileName+"2");
//System.out.println("rTreeDemo.tryJoin : lt size " + ltTree.getAllElements().size());
Join join = new Join(ltTree, rtTree, new Pair(), new IntersectPred());
System.out.println("rTreeDemo : left tree size " + ltTree.getAllElements().size()
+"\nright tree size " + rtTree.getAllElements().size()
+"\n join size " + join.relate().size());
long t = System.currentTimeMillis();
List list = join.relate();
System.out.println("Join returned " + list.size() + " pointers in "
+ (System.currentTimeMillis() - t) + " ms" );
return list;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
class RTreeRead
{
static int nleaf;
static int leaf;
static int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE,maxX = Integer.MIN_VALUE,
maxY = Integer.MIN_VALUE;
RandomAccessFile file;
RTreeRead(String fileName)
{
nleaf = leaf = 0;
try{
file = new RandomAccessFile(fileName,"r");
}
catch(Exception e){
System.out.println("RTreeRead "+e.getMessage());
}
}
public void readSeq()
{
try{
long length = file.length();
if(length == 0)
return;
Integer ln = new Integer((new Long(file.length())).intValue());
int kbytes = (new Double(Math.floor(ln.doubleValue()/4096))).intValue();
file.seek(0);
for(int i=0;i<kbytes+1;i++)
{
byte[] data = new byte[Node.NODE_SIZE];
file.read(data);
if(i==0)
printFlHdr(data);
else
printNode(i-1,data);
}
System.out.println("Total Leaf:"+leaf+"\tNonLeaf:"+nleaf);
System.out.println("MinX:"+minX+"\tMinY:"+minY+"\tMaxX:"+maxX+"\tMaxY:"+maxY);
}
catch(Exception e){
System.out.println("RTreeRead"+e.getMessage());
}
}
public void printFlHdr(byte[] data)
{
try{
int frNode = 123;
DataInputStream ds =
new DataInputStream(new ByteArrayInputStream(data));
System.out.println("\t***The File Header***");
System.out.println("TotalNodes:(includes unused ones):"+ds.readInt());
System.out.println("RootIndex: " + ds.readLong());
System.out.println("The free nodes Stack");
for(int topIdx=0;(topIdx<Node.FREE_LIST_LIMIT)&&
((frNode = ds.readInt()) !=
Node.NOT_DEFINED); topIdx++){
System.out.println("At " + topIdx + ": "+ frNode);
}
//System.out.println(frNode);
}
catch(Exception e){
System.out.println("Error at printFlHdr");
System.exit(1);
}
}
public void printNode(int index,byte[] data)
{
int mx,my,xx,xy;
try{
DataInputStream ds =
new DataInputStream(new ByteArrayInputStream(data));
System.out.println("\t***Node at Index: "+index+"***");
System.out.println("Node Header");
int totElmt = ds.readInt();
System.out.println("TotalElements:"+totElmt);
System.out.println("Parent:"+ds.readLong());
System.out.println("Element Size:"+ds.readInt());
int elmtType = ds.readInt();
System.out.println("Element Types:"+elmtType);
if(elmtType == Node.NONLEAF_NODE)
nleaf++;
else
leaf++;
for(int i=0;i<totElmt;i++){
System.out.println("Elements...");
mx = ds.readInt();
if(mx < minX)
minX = mx;
System.out.println("MinX: "+mx);
my = ds.readInt();
if(my < minY)
minY = my;
System.out.println("MinY: "+my);
xx = ds.readInt();
if(xx > 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);
}
}
}

View file

@ -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 <description>
* @return <description>
* @exception RTreeException <description>
*/
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);
}
}

View file

@ -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 <code>growLeaf</code>
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 <code>RTree</code> 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; i<sdingNode.getTotalElements(); i++){//for each element in the seeding node
if(level != slotLvl){
newElmts[i] = (NonLeafElement)((NonLeafElement)elmts[i]).clone();//we do not seed leaf elements
chNodes[i] = chdNodes.getNode(fileHdr.getFile(), fileName, sdNode.getNodeIndex(),//sd
sdingNode.getElementType(), fileHdr);
newElmts[i].setPtr(chNodes[i].getNodeIndex());//update the child pointers for new node
seedRec(sdingTree.getReadNode(elmts[i].getPtr()), chNodes[i], level+1);
}else{//this is the slot level
/*What we do here is that we put only one element into the slot node instead of all the elements.
This would result in a single element in the node which represents all the seding node elements
with a null pointer.
*/
newElmts[0].getRect().expandToInclude(elmts[i].getRect());
}//else
}//for
sdNode.insertElement(newElmts, false);//copy the non-slot elements now //sd
}
public void growLeaf(Element elmt)
throws RTreeException
{
if(slotLvl == Node.NOT_DEFINED){
try{
insert(elmt);
}catch(Exception e){
throw new RTreeException(e.getMessage());
}
}else{
fileHdr.lockWrite();
try{
long root = fileHdr.getRootIndex();
//Long slotIndex = null;
LongWraper slotIndex = new LongWraper();
Node node = this.chooseLeaf(elmt, slotIndex);//sd
if(slotIndex == null)
throw new NullPointerException();
long nodeParent = node.getParent();
Node[] newNodes = new Node[2];
try{
node.insertElement(elmt);//if another insert is possible
newNodes[0] = node;
newNodes[1] = null;
}catch(NodeFullException e){ //if another insert is not possible
newNodes = node.splitNode(elmt, slotIndex.val);
}
Node newRoot = adjustTree(newNodes, slotIndex.val);
//if we got a new root node then we have to set the slot's child to point to this new root
if(newRoot != null){
Node slot = chdNodes.getNode(fileHdr.getFile(), fileName, newRoot.getParent(), fileHdr);//sd
slot.modifyElement(0, newRoot.getNodeIndex());
}
}catch(Exception e){
e.printStackTrace();
throw new RTreeException(e.getMessage());
}finally{
fileHdr.unlock();
}
}
}
/**
This method is a copy of <code>RTree.chooseLeaf</code> 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'**)