/* * @(#)GeoRectangle.java 11 October 1999 James Macgill * */ package uk.ac.leeds.ccg.geotools; import java.awt.*; import java.lang.Math; import java.io.*; import java.util.*; /** * A double presision rectangle.
* It is usful for describing a GeoReferanced Rectangle
* Used by GeoPolygon to return a bounding box.
*
* @version 0.50, 17 Apr 1997
* @author James Macgill
*/
public class GeoRectangle extends GeoShape implements Serializable,Cloneable {
private final static boolean DEBUG=true;
private boolean initialised = false;
public double height;
public double width;
public double x;
public double y;
public boolean equals(GeoRectangle r){
if(r==null) return false;
//System.out.println("x "+(x==r.x));
//System.out.println("y "+(y==r.y));
//System.out.println("width "+(width==r.width));
//System.out.println("height "+(height==r.height));
return(x==r.x&&y==r.y&&width==r.width&&height==r.height);
}
/**
* Initalise Rectangle to be infinatly 'inside-out', very useful for bounding box creation
*/
public GeoRectangle() {
height = 0;
width = 0;
x = Double.POSITIVE_INFINITY;
y = Double.POSITIVE_INFINITY;
initialised = false;
}
/**
* Initalise GeoRectangle with another one.
*
* @param rect Existing GeoRectangle to initalise new one
*/
public GeoRectangle(GeoRectangle rect) {
this.x = rect.x;
this.y = rect.y;
this.width = rect.width;
this.height = rect.height;
initialised = true;
}
/**
* Initalise Rectangle with a list of points
*
* @param x left most coordinate of GeoRectangle
* @param y bottom most coordinate of GeoRectangle
* @param width Width of GeoRectangle
* @param height Height of GeoRectangle
*/
public GeoRectangle(double x,double y,double width,double height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
initialised = true;
}
/**
* Initalise Rectangle with a single point
*
* @param p A GeoPoint
*/
public GeoRectangle(GeoPoint p) {
this(p.x,p.y,0d,0d);
}
/**
* Compares a point with the rectangle, if it is outside then the rectangle is expanded to
* to fit.
*
* @param px X coordinate of point to fit into GeoRectangle
* @param py Y coordinate of point to fit into GeoRectangle
*/
public void add(double px,double py) {
if(initialised){
if (px < x){
width = (x+width)-px;
x = px;
}
if (py < y){
height = height + Math.abs(py-y);
y = py;
}
if (px > x + width) width = px-x;
if (py > y + height) height = py-y;
}
else{
x=px;
y=py;
initialised = true;
}
}
/** determines if this georectangle is empty or not
*/
public boolean isEmpty(){
return(width==0||height==0);
}
/**
* Compares a point with the rectangle, if it is outside then the rectangle is expanded to
* to fit.
*
* @param p GeoPoint to fit into GeoRectangle
*/
public void add(GeoPoint p) {
add(p.x,p.y);
}
public Object clone() {
return new GeoRectangle(this);
}
/**
* Expands the rectangle so that it is large enough to hold the
* specified GeoRectangle
*
* @param rect The GeoRectangle to be inserted
*/
public void add(GeoRectangle rect) {
if(!rect.initialised)return;
//turn rectangle into points
double x1 = rect.x;
double x2 = rect.x + rect.width;
double y1 = rect.y;
double y2 = rect.y + rect.height;
//Add each point to the GeoRectangle
this.add(x1,y1);
this.add(x2,y2);
}
/**
* Gets the bounds of this georectanle which,
* by defenition is a clone of the GeoRectangle
* @return The GeoRectangle which bounds this georectangle
*/
public GeoRectangle getBounds(){
return (GeoRectangle)clone();
}
/**
* Initialise the data in GeoRectangle
*/
public void setBounds(GeoRectangle r){
setBounds(r.x,r.y,r.width,r.height);
}
/**
* Initialise the data in GeoRectangle
*/
public void setBounds(double x_new, double y_new, double width_new, double height_new) {
x=x_new;
y=y_new;
height=height_new;
width=width_new;
}
/**
* Initialise the data in GeoRectangle based on a
* Open GIS BBox format, ie
* "xmin,ymin,xmax,ymax". If the string is incorrectly formatted,
* or has invalid data, then the data is set to GeoRectangle() and
* false is returned.
* @param BBox A string of the format "xmin,ymin,xmax,ymax".
* @return Boolean specifying TRUE if the geoRectangle was created
* successfully, false otherwise.
*/
public boolean setBounds(String BBox)
{
boolean valid=false;
StringTokenizer st = new StringTokenizer(BBox,",");
if (st.countTokens()==4) {
double x1 = Double.valueOf(st.nextToken()).doubleValue();
double y1 = Double.valueOf(st.nextToken()).doubleValue();
double x2 = Double.valueOf(st.nextToken()).doubleValue();
double y2 = Double.valueOf(st.nextToken()).doubleValue();
setBounds(x1,y1,x2-x1,y2-y1);
valid=true;
}
return valid;
}
public void extendBounds(double x,double y){
add(x,y);
}
public void extendBounds(GeoPoint p){
add(p);
}
/**
* subtracts the given GeoRectangle from this one
* @author Mathieu van Loon
* the return order is left,top,right,bottom
*/
public GeoRectangle [] remainder(GeoRectangle r){
GeoRectangle [] ret = new GeoRectangle[4];
//if they don't intersect there is no remainder? or we could return r?
GeoRectangle inter = this.createIntersect(r);
System.out.println("inter "+inter);
if(inter==null) return ret;
// left hand edge
if((inter.x-this.x)>0)ret[0]=new GeoRectangle(this.x,this.y,(inter.x-this.x),this.height);
// top edge
if((inter.width)>0&&(this.y+this.height)-(inter.y+inter.height)>0)ret[1]=new GeoRectangle(inter.x,inter.y+inter.height,
(inter.width),(this.y+this.height)-(inter.y+inter.height));
// right hand edge
if((this.x+this.width)-(inter.x+inter.width)>0)ret[2]=new GeoRectangle(inter.x+inter.width,this.y,(this.x+this.width)-(inter.x+inter.width),this.height);
// bottom edge
if(inter.width>0&&(inter.y-this.y)>0)ret[3]=new GeoRectangle(inter.x,this.y, inter.width,(inter.y-this.y));
return ret;
}
/**
* this function returns true if the given rectangle is contained within this rectangle
* Creation date: (11/21/00 2:52:37 PM)
* @return boolean
* @param g uk.ac.leeds.ccg.geotools.GeoRectangle
* @author Mathieu van Loon