//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;
}
*/