// Spatial Index Library
//
// Copyright (C) 2002 Navel Ltd.
//
// 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;
// version 2.1 of the License.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Contact information:
// Mailing address:
// Marios Hadjieleftheriou
// University of California, Riverside
// Department of Computer Science
// Surge Building, Room 310
// Riverside, CA 92521
//
// Email:
// marioh@cs.ucr.edu
package org.geotools.caching.spatialindex;
import java.io.Serializable;
public class Region implements Shape, Serializable {
/**
*
*/
private static final long serialVersionUID = 2627615073834425697L;
private double[] m_pLow = null;
private double[] m_pHigh = null;
private volatile int hashCode = 0;
public Region() {
}
public Region(final double[] pLow, final double[] pHigh) {
if (pLow.length != pHigh.length) {
throw new IllegalArgumentException(
"Region: arguments have different number of dimensions.");
}
m_pLow = new double[pLow.length];
System.arraycopy(pLow, 0, m_pLow, 0, pLow.length);
m_pHigh = new double[pHigh.length];
System.arraycopy(pHigh, 0, m_pHigh, 0, pHigh.length);
}
public Region(final Point low, final Point high) {
if (low.m_pCoords.length != high.m_pCoords.length) {
throw new IllegalArgumentException(
"Region: arguments have different number of dimensions.");
}
m_pLow = new double[low.m_pCoords.length];
System.arraycopy(low.m_pCoords, 0, m_pLow, 0, low.m_pCoords.length);
m_pHigh = new double[high.m_pCoords.length];
System.arraycopy(high.m_pCoords, 0, m_pHigh, 0, high.m_pCoords.length);
}
public Region(final Region r) {
m_pLow = new double[r.m_pLow.length];
System.arraycopy(r.m_pLow, 0, m_pLow, 0, r.m_pLow.length);
m_pHigh = new double[r.m_pHigh.length];
System.arraycopy(r.m_pHigh, 0, m_pHigh, 0, r.m_pHigh.length);
}
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof Region) {
Region r = (Region) o;
if (r.m_pLow.length != m_pLow.length) {
return false;
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if ((m_pLow[cIndex] != r.m_pLow[cIndex]) || (m_pHigh[cIndex] != r.m_pHigh[cIndex])) {
return false;
}
}
return true;
}
return false;
}
//
// Cloneable interface
//
public Object clone() {
return new Region(m_pLow, m_pHigh);
}
//
// IShape interface
//
public boolean intersects(final Shape s) {
if (s instanceof Region) {
return intersects((Region) s);
}
if (s instanceof Point) {
return contains((Point) s);
}
throw new IllegalStateException("intersects: Not implemented yet!");
}
public boolean contains(final Shape s) {
if (s instanceof Region) {
return contains((Region) s);
}
if (s instanceof Point) {
return contains((Point) s);
}
throw new IllegalStateException("contains: Not implemented yet!");
}
public boolean touches(final Shape s) {
if (s instanceof Region) {
return touches((Region) s);
}
if (s instanceof Point) {
return touches((Point) s);
}
throw new IllegalStateException("touches: Not implemented yet!");
}
public double[] getCenter() {
double[] pCoords = new double[m_pLow.length];
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
pCoords[cIndex] = (m_pLow[cIndex] + m_pHigh[cIndex]) / 2.0;
}
return pCoords;
}
public int getDimension() {
return m_pLow.length;
}
public Region getMBR() {
return new Region(m_pLow, m_pHigh);
}
public double getArea() {
double area = 1.0;
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
area *= (m_pHigh[cIndex] - m_pLow[cIndex]);
}
return area;
}
public double getMinimumDistance(final Shape s) {
if (s instanceof Region) {
return getMinimumDistance((Region) s);
}
if (s instanceof Point) {
return getMinimumDistance((Point) s);
}
throw new IllegalStateException("getMinimumDistance: Not implemented yet!");
}
public boolean intersects(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException(
"intersects: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if ((m_pLow[cIndex] > r.m_pHigh[cIndex]) || (m_pHigh[cIndex] < r.m_pLow[cIndex])) {
return false;
}
}
return true;
}
public boolean contains(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException(
"contains: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if ((m_pLow[cIndex] > r.m_pLow[cIndex]) || (m_pHigh[cIndex] < r.m_pHigh[cIndex])) {
return false;
}
}
return true;
}
public boolean touches(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException("touches: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if (((m_pLow[cIndex] > (r.m_pLow[cIndex] - SpatialIndex.EPSILON))
&& (m_pLow[cIndex] < (r.m_pLow[cIndex] + SpatialIndex.EPSILON)))
|| ((m_pHigh[cIndex] > (r.m_pHigh[cIndex] - SpatialIndex.EPSILON))
&& (m_pHigh[cIndex] < (r.m_pHigh[cIndex] + SpatialIndex.EPSILON)))) {
return true;
}
}
return false;
}
public double getMinimumDistance(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException(
"getMinimumDistance: Shape has the wrong number of dimensions.");
}
double ret = 0.0;
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
double x = 0.0;
if (r.m_pHigh[cIndex] < m_pLow[cIndex]) {
x = Math.abs(r.m_pHigh[cIndex] - m_pLow[cIndex]);
} else if (m_pHigh[cIndex] < r.m_pLow[cIndex]) {
x = Math.abs(r.m_pLow[cIndex] - m_pHigh[cIndex]);
}
ret += (x * x);
}
return Math.sqrt(ret);
}
public boolean contains(final Point p) {
if (m_pLow.length != p.m_pCoords.length) {
throw new IllegalArgumentException(
"contains: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if ((m_pLow[cIndex] > p.m_pCoords[cIndex]) || (m_pHigh[cIndex] < p.m_pCoords[cIndex])) {
return false;
}
}
return true;
}
public boolean touches(final Point p) {
if (m_pLow.length != p.m_pCoords.length) {
throw new IllegalArgumentException("touches: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if (((m_pLow[cIndex] > (p.m_pCoords[cIndex] - SpatialIndex.EPSILON))
&& (m_pLow[cIndex] < (p.m_pCoords[cIndex] + SpatialIndex.EPSILON)))
|| ((m_pHigh[cIndex] > (p.m_pCoords[cIndex] - SpatialIndex.EPSILON))
&& (m_pHigh[cIndex] < (p.m_pCoords[cIndex] + SpatialIndex.EPSILON)))) {
return true;
}
}
return false;
}
public double getMinimumDistance(final Point p) {
if (m_pLow.length != p.m_pCoords.length) {
throw new IllegalArgumentException(
"getMinimumDistance: Shape has the wrong number of dimensions.");
}
double ret = 0.0;
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if (p.m_pCoords[cIndex] < m_pLow[cIndex]) {
ret += Math.pow(m_pLow[cIndex] - p.m_pCoords[cIndex], 2.0);
} else if (p.m_pCoords[cIndex] > m_pHigh[cIndex]) {
ret += Math.pow(p.m_pCoords[cIndex] - m_pHigh[cIndex], 2.0);
}
}
return Math.sqrt(ret);
}
public double getIntersectingArea(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException(
"getIntersectingArea: Shape has the wrong number of dimensions.");
}
int cIndex;
// check for intersection.
// marioh: avoid function call since this is called billions of times.
for (cIndex = 0; cIndex < m_pLow.length; cIndex++) {
if ((m_pLow[cIndex] > r.m_pHigh[cIndex]) || (m_pHigh[cIndex] < r.m_pLow[cIndex])) {
return 0.0;
}
}
double ret = 1.0;
double f1;
double f2;
for (cIndex = 0; cIndex < m_pLow.length; cIndex++) {
f1 = Math.max(m_pLow[cIndex], r.m_pLow[cIndex]);
f2 = Math.min(m_pHigh[cIndex], r.m_pHigh[cIndex]);
ret *= (f2 - f1);
}
return ret;
}
public Region combinedRegion(final Region r) {
if (m_pLow.length != r.m_pLow.length) {
throw new IllegalArgumentException(
"combinedRegion: Shape has the wrong number of dimensions.");
}
double[] mn = new double[m_pLow.length];
double[] mx = new double[m_pLow.length];
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
mn[cIndex] = Math.min(m_pLow[cIndex], r.m_pLow[cIndex]);
mx[cIndex] = Math.max(m_pHigh[cIndex], r.m_pHigh[cIndex]);
}
return new Region(mn, mx);
}
public static Region combinedRegion(Region[] pRegions) {
double[] mn = new double[pRegions[0].m_pLow.length];
double[] mx = new double[pRegions[0].m_pLow.length];
for (int cDim = 0; cDim < pRegions[0].m_pLow.length; cDim++) {
mn[cDim] = Double.POSITIVE_INFINITY;
mx[cDim] = Double.NEGATIVE_INFINITY;
for (int cIndex = 0; cIndex < pRegions.length; cIndex++) {
mn[cDim] = Math.min(mn[cDim], pRegions[cIndex].m_pLow[cDim]);
mx[cDim] = Math.max(mx[cDim], pRegions[cIndex].m_pHigh[cDim]);
}
}
return new Region(mn, mx);
}
// Modifies the first argument to include the second.
public static void combinedRegion(Region pToModify, final Region pConst) {
if (pToModify.m_pLow.length != pConst.m_pLow.length) {
throw new IllegalArgumentException(
"combineRegion: Shape has the wrong number of dimensions.");
}
for (int cIndex = 0; cIndex < pToModify.m_pLow.length; cIndex++) {
pToModify.m_pLow[cIndex] = Math.min(pToModify.m_pLow[cIndex], pConst.m_pLow[cIndex]);
pToModify.m_pHigh[cIndex] = Math.max(pToModify.m_pHigh[cIndex], pConst.m_pHigh[cIndex]);
}
}
// Returns the margin of a region. It is calcuated as the sum of 2^(d-1) * width in each dimension.
public double getMargin() {
double mul = Math.pow(2.0, ((double) m_pLow.length) - 1.0);
double margin = 0.0;
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
margin += ((m_pHigh[cIndex] - m_pLow[cIndex]) * mul);
}
return margin;
}
public double getLow(int index) throws IndexOutOfBoundsException {
if (index >= m_pLow.length) {
throw new IndexOutOfBoundsException("" + index);
}
return m_pLow[index];
}
public double getHigh(int index) throws IndexOutOfBoundsException {
if (index >= m_pLow.length) {
throw new IndexOutOfBoundsException("" + index);
}
return m_pHigh[index];
}
public String toString() {
String s = "";
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++)
s += (m_pLow[cIndex] + " ");
s += ": ";
for (int cIndex = 0; cIndex < m_pHigh.length; cIndex++)
s += (m_pHigh[cIndex] + " ");
return s;
}
public int hashCode() {
if (hashCode == 0) {
int hash = 17;
int c;
long l;
for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) {
l = Double.doubleToLongBits(m_pLow[cIndex]);
c = (int) (l ^ (l >>> 32));
hash = (37 * hash) + c;
l = Double.doubleToLongBits(m_pHigh[cIndex]);
c = (int) (l ^ (l >>> 32));
hash = (37 * hash) + c;
}
hashCode = hash;
}
return hashCode;
}
}