All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jts.geom.Envelope Maven / Gradle / Ivy

The newest version!
/*
 * The JTS Topology Suite is a collection of Java classes that
 * implement the fundamental operations required to validate a given
 * geo-spatial data set to a known topological specification.
 *
 * Copyright (C) 2001 Vivid Solutions
 *
 * 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.
 *
 * 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
 *
 * For more information, contact:
 *
 *     Vivid Solutions
 *     Suite #1A
 *     2328 Government Street
 *     Victoria BC  V8T 5G5
 *     Canada
 *
 *     (250)385-6040
 *     www.vividsolutions.com
 */
package com.vividsolutions.jts.geom;

import java.io.Serializable;

/**
 *  Defines a rectangular region of the 2D coordinate plane.
 *  It is often used to represent the bounding box of a {@link Geometry},
 *  e.g. the minimum and maximum x and y values of the {@link Coordinate}s.
 *  

* Envelopes support infinite or half-infinite regions, by using the values of * Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY. * Envelope objects may have a null value. *

* When Envelope objects are created or initialized, * the supplies extent values are automatically sorted into the correct order. * *@version 1.7 */ public class Envelope implements Comparable, Serializable { private static final long serialVersionUID = 5873921885273102420L; public int hashCode() { //Algorithm from Effective Java by Joshua Bloch [Jon Aquino] int result = 17; result = 37 * result + Coordinate.hashCode(minx); result = 37 * result + Coordinate.hashCode(maxx); result = 37 * result + Coordinate.hashCode(miny); result = 37 * result + Coordinate.hashCode(maxy); return result; } /** * Test the point q to see whether it intersects the Envelope defined by p1-p2 * @param p1 one extremal point of the envelope * @param p2 another extremal point of the envelope * @param q the point to test for intersection * @return true if q intersects the envelope p1-p2 */ public static boolean intersects(Coordinate p1, Coordinate p2, Coordinate q) { //OptimizeIt shows that Math#min and Math#max here are a bottleneck. //Replace with direct comparisons. [Jon Aquino] if (((q.x >= (p1.x < p2.x ? p1.x : p2.x)) && (q.x <= (p1.x > p2.x ? p1.x : p2.x))) && ((q.y >= (p1.y < p2.y ? p1.y : p2.y)) && (q.y <= (p1.y > p2.y ? p1.y : p2.y)))) { return true; } return false; } /** * Tests whether the envelope defined by p1-p2 * and the envelope defined by q1-q2 * intersect. * * @param p1 one extremal point of the envelope P * @param p2 another extremal point of the envelope P * @param q1 one extremal point of the envelope Q * @param q2 another extremal point of the envelope Q * @return true if Q intersects P */ public static boolean intersects(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) { double minq = Math.min(q1.x, q2.x); double maxq = Math.max(q1.x, q2.x); double minp = Math.min(p1.x, p2.x); double maxp = Math.max(p1.x, p2.x); if( minp > maxq ) return false; if( maxp < minq ) return false; minq = Math.min(q1.y, q2.y); maxq = Math.max(q1.y, q2.y); minp = Math.min(p1.y, p2.y); maxp = Math.max(p1.y, p2.y); if( minp > maxq ) return false; if( maxp < minq ) return false; return true; } /** * the minimum x-coordinate */ private double minx; /** * the maximum x-coordinate */ private double maxx; /** * the minimum y-coordinate */ private double miny; /** * the maximum y-coordinate */ private double maxy; /** * Creates a null Envelope. */ public Envelope() { init(); } /** * Creates an Envelope for a region defined by maximum and minimum values. * *@param x1 the first x-value *@param x2 the second x-value *@param y1 the first y-value *@param y2 the second y-value */ public Envelope(double x1, double x2, double y1, double y2) { init(x1, x2, y1, y2); } /** * Creates an Envelope for a region defined by two Coordinates. * *@param p1 the first Coordinate *@param p2 the second Coordinate */ public Envelope(Coordinate p1, Coordinate p2) { init(p1.x, p2.x, p1.y, p2.y); } /** * Creates an Envelope for a region defined by a single Coordinate. * *@param p the Coordinate */ public Envelope(Coordinate p) { init(p.x, p.x, p.y, p.y); } /** * Create an Envelope from an existing Envelope. * *@param env the Envelope to initialize from */ public Envelope(Envelope env) { init(env); } /** * Initialize to a null Envelope. */ public void init() { setToNull(); } /** * Initialize an Envelope for a region defined by maximum and minimum values. * *@param x1 the first x-value *@param x2 the second x-value *@param y1 the first y-value *@param y2 the second y-value */ public void init(double x1, double x2, double y1, double y2) { if (x1 < x2) { minx = x1; maxx = x2; } else { minx = x2; maxx = x1; } if (y1 < y2) { miny = y1; maxy = y2; } else { miny = y2; maxy = y1; } } /** * Initialize an Envelope to a region defined by two Coordinates. * *@param p1 the first Coordinate *@param p2 the second Coordinate */ public void init(Coordinate p1, Coordinate p2) { init(p1.x, p2.x, p1.y, p2.y); } /** * Initialize an Envelope to a region defined by a single Coordinate. * *@param p the coordinate */ public void init(Coordinate p) { init(p.x, p.x, p.y, p.y); } /** * Initialize an Envelope from an existing Envelope. * *@param env the Envelope to initialize from */ public void init(Envelope env) { this.minx = env.minx; this.maxx = env.maxx; this.miny = env.miny; this.maxy = env.maxy; } /** * Makes this Envelope a "null" envelope, that is, the envelope * of the empty geometry. */ public void setToNull() { minx = 0; maxx = -1; miny = 0; maxy = -1; } /** * Returns true if this Envelope is a "null" * envelope. * *@return true if this Envelope is uninitialized * or is the envelope of the empty geometry. */ public boolean isNull() { return maxx < minx; } /** * Returns the difference between the maximum and minimum x values. * *@return max x - min x, or 0 if this is a null Envelope */ public double getWidth() { if (isNull()) { return 0; } return maxx - minx; } /** * Returns the difference between the maximum and minimum y values. * *@return max y - min y, or 0 if this is a null Envelope */ public double getHeight() { if (isNull()) { return 0; } return maxy - miny; } /** * Returns the Envelopes minimum x-value. min x > max x * indicates that this is a null Envelope. * *@return the minimum x-coordinate */ public double getMinX() { return minx; } /** * Returns the Envelopes maximum x-value. min x > max x * indicates that this is a null Envelope. * *@return the maximum x-coordinate */ public double getMaxX() { return maxx; } /** * Returns the Envelopes minimum y-value. min y > max y * indicates that this is a null Envelope. * *@return the minimum y-coordinate */ public double getMinY() { return miny; } /** * Returns the Envelopes maximum y-value. min y > max y * indicates that this is a null Envelope. * *@return the maximum y-coordinate */ public double getMaxY() { return maxy; } /** * Gets the area of this envelope. * * @return the area of the envelope * @return 0.0 if the envelope is null */ public double getArea() { return getWidth() * getHeight(); } /** * Gets the minimum extent of this envelope across both dimensions. * * @return the minimum extent of this envelope */ public double minExtent() { if (isNull()) return 0.0; double w = getWidth(); double h = getHeight(); if (w < h) return w; return h; } /** * Gets the maximum extent of this envelope across both dimensions. * * @return the maximum extent of this envelope */ public double maxExtent() { if (isNull()) return 0.0; double w = getWidth(); double h = getHeight(); if (w > h) return w; return h; } /** * Enlarges this Envelope so that it contains * the given {@link Coordinate}. * Has no effect if the point is already on or within the envelope. * *@param p the Coordinate to expand to include */ public void expandToInclude(Coordinate p) { expandToInclude(p.x, p.y); } /** * Expands this envelope by a given distance in all directions. * Both positive and negative distances are supported. * * @param distance the distance to expand the envelope */ public void expandBy(double distance) { expandBy(distance, distance); } /** * Expands this envelope by a given distance in all directions. * Both positive and negative distances are supported. * * @param deltaX the distance to expand the envelope along the the X axis * @param deltaY the distance to expand the envelope along the the Y axis */ public void expandBy(double deltaX, double deltaY) { if (isNull()) return; minx -= deltaX; maxx += deltaX; miny -= deltaY; maxy += deltaY; // check for envelope disappearing if (minx > maxx || miny > maxy) setToNull(); } /** * Enlarges this Envelope so that it contains * the given point. * Has no effect if the point is already on or within the envelope. * *@param x the value to lower the minimum x to or to raise the maximum x to *@param y the value to lower the minimum y to or to raise the maximum y to */ public void expandToInclude(double x, double y) { if (isNull()) { minx = x; maxx = x; miny = y; maxy = y; } else { if (x < minx) { minx = x; } if (x > maxx) { maxx = x; } if (y < miny) { miny = y; } if (y > maxy) { maxy = y; } } } /** * Enlarges this Envelope so that it contains * the other Envelope. * Has no effect if other is wholly on or * within the envelope. * *@param other the Envelope to expand to include */ public void expandToInclude(Envelope other) { if (other.isNull()) { return; } if (isNull()) { minx = other.getMinX(); maxx = other.getMaxX(); miny = other.getMinY(); maxy = other.getMaxY(); } else { if (other.minx < minx) { minx = other.minx; } if (other.maxx > maxx) { maxx = other.maxx; } if (other.miny < miny) { miny = other.miny; } if (other.maxy > maxy) { maxy = other.maxy; } } } /** * Translates this envelope by given amounts in the X and Y direction. * * @param transX the amount to translate along the X axis * @param transY the amount to translate along the Y axis */ public void translate(double transX, double transY) { if (isNull()) { return; } init(getMinX() + transX, getMaxX() + transX, getMinY() + transY, getMaxY() + transY); } /** * Computes the coordinate of the centre of this envelope (as long as it is non-null * * @return the centre coordinate of this envelope * null if the envelope is null */ public Coordinate centre() { if (isNull()) return null; return new Coordinate( (getMinX() + getMaxX()) / 2.0, (getMinY() + getMaxY()) / 2.0); } /** * Computes the intersection of two {@link Envelope}s. * * @param env the envelope to intersect with * @return a new Envelope representing the intersection of the envelopes (this will be * the null envelope if either argument is null, or they do not intersect */ public Envelope intersection(Envelope env) { if (isNull() || env.isNull() || ! intersects(env)) return new Envelope(); double intMinX = minx > env.minx ? minx : env.minx; double intMinY = miny > env.miny ? miny : env.miny; double intMaxX = maxx < env.maxx ? maxx : env.maxx; double intMaxY = maxy < env.maxy ? maxy : env.maxy; return new Envelope(intMinX, intMaxX, intMinY, intMaxY); } /** * Check if the region defined by other * overlaps (intersects) the region of this Envelope. * *@param other the Envelope which this Envelope is * being checked for overlapping *@return true if the Envelopes overlap */ public boolean intersects(Envelope other) { if (isNull() || other.isNull()) { return false; } return !(other.minx > maxx || other.maxx < minx || other.miny > maxy || other.maxy < miny); } /** * @deprecated Use #intersects instead. In the future, #overlaps may be * changed to be a true overlap check; that is, whether the intersection is * two-dimensional. */ public boolean overlaps(Envelope other) { return intersects(other); } /** * Check if the point p * overlaps (lies inside) the region of this Envelope. * *@param p the Coordinate to be tested *@return true if the point overlaps this Envelope */ public boolean intersects(Coordinate p) { return intersects(p.x, p.y); } /** * @deprecated Use #intersects instead. */ public boolean overlaps(Coordinate p) { return intersects(p); } /** * Check if the point (x, y) * overlaps (lies inside) the region of this Envelope. * *@param x the x-ordinate of the point *@param y the y-ordinate of the point *@return true if the point overlaps this Envelope */ public boolean intersects(double x, double y) { if (isNull()) return false; return ! (x > maxx || x < minx || y > maxy || y < miny); } /** * @deprecated Use #intersects instead. */ public boolean overlaps(double x, double y) { return intersects(x, y); } /** * Tests if the Envelope other * lies wholely inside this Envelope (inclusive of the boundary). *

* Note that this is not the same definition as the SFS contains, * which would exclude the envelope boundary. * *@param other the Envelope to check *@return true if other is contained in this Envelope * *@see #covers(Envelope) */ public boolean contains(Envelope other) { return covers(other); } /** * Tests if the given point lies in or on the envelope. *

* Note that this is not the same definition as the SFS contains, * which would exclude the envelope boundary. * *@param p the point which this Envelope is * being checked for containing *@return true if the point lies in the interior or * on the boundary of this Envelope. * *@see #covers(Coordinate) */ public boolean contains(Coordinate p) { return covers(p); } /** * Tests if the given point lies in or on the envelope. *

* Note that this is not the same definition as the SFS contains, * which would exclude the envelope boundary. * *@param x the x-coordinate of the point which this Envelope is * being checked for containing *@param y the y-coordinate of the point which this Envelope is * being checked for containing *@return true if (x, y) lies in the interior or * on the boundary of this Envelope. * *@see #covers(double, double) */ public boolean contains(double x, double y) { return covers(x, y); } /** * Tests if the given point lies in or on the envelope. * *@param x the x-coordinate of the point which this Envelope is * being checked for containing *@param y the y-coordinate of the point which this Envelope is * being checked for containing *@return true if (x, y) lies in the interior or * on the boundary of this Envelope. */ public boolean covers(double x, double y) { if (isNull()) return false; return x >= minx && x <= maxx && y >= miny && y <= maxy; } /** * Tests if the given point lies in or on the envelope. * *@param p the point which this Envelope is * being checked for containing *@return true if the point lies in the interior or * on the boundary of this Envelope. */ public boolean covers(Coordinate p) { return covers(p.x, p.y); } /** * Tests if the Envelope other * lies wholely inside this Envelope (inclusive of the boundary). * *@param other the Envelope to check *@return true if this Envelope covers the other */ public boolean covers(Envelope other) { if (isNull() || other.isNull()) { return false; } return other.getMinX() >= minx && other.getMaxX() <= maxx && other.getMinY() >= miny && other.getMaxY() <= maxy; } /** * Computes the distance between this and another * Envelope. * The distance between overlapping Envelopes is 0. Otherwise, the * distance is the Euclidean distance between the closest points. */ public double distance(Envelope env) { if (intersects(env)) return 0; double dx = 0.0; if (maxx < env.minx) dx = env.minx - maxx; else if (minx > env.maxx) dx = minx - env.maxx; double dy = 0.0; if (maxy < env.miny) dy = env.miny - maxy; else if (miny > env.maxy) dy = miny - env.maxy; // if either is zero, the envelopes overlap either vertically or horizontally if (dx == 0.0) return dy; if (dy == 0.0) return dx; return Math.sqrt(dx * dx + dy * dy); } public boolean equals(Object other) { if (!(other instanceof Envelope)) { return false; } Envelope otherEnvelope = (Envelope) other; if (isNull()) { return otherEnvelope.isNull(); } return maxx == otherEnvelope.getMaxX() && maxy == otherEnvelope.getMaxY() && minx == otherEnvelope.getMinX() && miny == otherEnvelope.getMinY(); } public String toString() { return "Env[" + minx + " : " + maxx + ", " + miny + " : " + maxy + "]"; } /** * Compares two envelopes using lexicographic ordering. * The ordering comparison is based on the usual numerical * comparison between the sequence of ordinates. * Null envelopes are less than all non-null envelopes. * * @param o an Envelope object */ public int compareTo(Object o) { Envelope env = (Envelope) o; // compare nulls if present if (isNull()) { if (env.isNull()) return 0; return -1; } else { if (env.isNull()) return 1; } // compare based on numerical ordering of ordinates if (minx < env.minx) return -1; if (minx > env.minx) return 1; if (miny < env.miny) return -1; if (miny > env.miny) return 1; if (maxx < env.maxx) return -1; if (maxx > env.maxx) return 1; if (maxy < env.maxy) return -1; if (maxy > env.maxy) return 1; return 0; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy