Bounds.java
/*
* @(#)Bounds.java
*
* Project: JHotdraw - a GUI framework for technical drawings
* http://www.jhotdraw.org
* http://jhotdraw.sourceforge.net
* Copyright: © by the original author(s) and all contributors
* License: Lesser GNU Public License (LGPL)
* http://www.opensource.org/licenses/lgpl-license.html
*/
package CH.ifa.draw.util;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
/**
* This class is a rectangle with floating point
* dimensions and location. This class provides
* many convenient geometrical methods related to
* rectangles. Basically, this class is like
* java.awt.geom.Rectangle2D with some extra
* functionality.
*
* @author WMG (28.02.1999)
* @version <$CURRENT_VERSION$>
*/
public class Bounds implements Serializable {
//_________________________________________________________VARIABLES
protected double _dX1 = 0;
protected double _dY1 = 0;
protected double _dX2 = 0;
protected double _dY2 = 0;
//______________________________________________________CONSTRUCTORS
public Bounds(double x, double y) {
_dX1 = x;
_dX2 = x;
_dY1 = y;
_dY2 = y;
}
public Bounds(double x1, double y1, double x2, double y2) {
_dX1 = Math.min(x1, x2);
_dX2 = Math.max(x1, x2);
_dY1 = Math.min(y1, y2);
_dY2 = Math.max(y1, y2);
}
public Bounds(Point2D aPoint2D) {
this(aPoint2D.getX(), aPoint2D.getY());
}
public Bounds(Point2D firstPoint2D, Point2D secondPoint2D) {
this(firstPoint2D.getX(), firstPoint2D.getY(),
secondPoint2D.getX(), secondPoint2D.getY());
}
public Bounds(Bounds aBounds) {
this(aBounds.getLesserX(), aBounds.getLesserY(),
aBounds.getGreaterX(), aBounds.getGreaterY());
}
public Bounds(Rectangle2D aRectangle2D) {
_dX1 = aRectangle2D.getMinX();
_dX2 = aRectangle2D.getMaxX();
_dY1 = aRectangle2D.getMinY();
_dY2 = aRectangle2D.getMaxY();
}
public Bounds(Point2D centerPoint2D, double dWidth, double dHeight) {
_dX1 = centerPoint2D.getX() - (dWidth / 2.0);
_dX2 = centerPoint2D.getX() + (dWidth / 2.0);
_dY1 = centerPoint2D.getY() - (dHeight / 2.0);
_dY2 = centerPoint2D.getY() + (dHeight / 2.0);
}
public Bounds(Dimension aDimension) {
this(0, 0, aDimension.width, aDimension.height);
}
protected Bounds() {
// empty constructor
}
//____________________________________________________PUBLIC METHODS
public double getLesserX() {
return _dX1;
}
public double getGreaterX() {
return _dX2;
}
public double getLesserY() {
return _dY1;
}
public double getGreaterY() {
return _dY2;
}
public double getWest() {
return _dX1;
}
public double getEast() {
return _dX2;
}
public double getSouth() {
return _dY1;
}
public double getNorth() {
return _dY2;
}
public double getWidth() {
return _dX2 - _dX1;
}
public double getHeight() {
return _dY2 - _dY1;
}
public Rectangle2D asRectangle2D() {
return new Rectangle2D.Double(getLesserX(), getLesserY(),
getWidth(), getHeight());
}
public void setCenter(Point2D centerPoint2D) {
Point2D currentCenterPoint2D = getCenter();
double dDeltaX = centerPoint2D.getX() - currentCenterPoint2D.getX();
double dDeltaY = centerPoint2D.getY() - currentCenterPoint2D.getY();
offset(dDeltaX, dDeltaY);
}
public Point2D getCenter() {
return new Point2D.Double((_dX1 + _dX2) / 2.0, (_dY1 + _dY2) / 2.0);
}
public void zoomBy(double dRatio) {
double dWidth = _dX2 - _dX1;
double dHeight = _dY2 - _dY1;
double dNewWidth = (dWidth * dRatio);
double dNewHeight = (dHeight * dRatio);
Point2D centerPoint2D = getCenter();
_dX1 = centerPoint2D.getX() - (dNewWidth / 2.0);
_dY1 = centerPoint2D.getY() - (dNewHeight / 2.0);
_dX2 = centerPoint2D.getX() + (dNewWidth / 2.0);
_dY2 = centerPoint2D.getY() + (dNewHeight / 2.0);
}
public void shiftBy(int nXPercentage, int nYPercentage) {
double dWidth = _dX2 - _dX1;
double dHeight = _dY2 - _dY1;
double dDeltaX = (dWidth * nXPercentage) / 100.0;
double dDeltaY = (dHeight * nYPercentage) / 100.0;
offset(dDeltaX, dDeltaY);
}
public void offset(double dDeltaX, double dDeltaY) {
_dX1 += dDeltaX;
_dX2 += dDeltaX;
_dY1 += dDeltaY;
_dY2 += dDeltaY;
}
/**
* This will cause the bounds to grow until the given ratio
* is satisfied. The Ration is calculated by
* <code> getWidth() / getHeight() </code>
**/
public void expandToRatio(double dRatio) {
double dCurrentRatio = getWidth() / getHeight();
if (dCurrentRatio < dRatio) {
double dNewWidth = dRatio * getHeight();
double dCenterX = (_dX1 + _dX2) / 2.0;
double dDelta = dNewWidth / 2.0;
_dX1 = dCenterX - dDelta;
_dX2 = dCenterX + dDelta;
}
if (dCurrentRatio > dRatio) {
double dNewHeight = getWidth() / dRatio;
double dCenterY = (_dY1 + _dY2) / 2.0;
double dDelta = dNewHeight / 2.0;
_dY1 = dCenterY - dDelta;
_dY2 = dCenterY + dDelta;
}
}
public void includeXCoordinate(double x) {
_dX1 = min(_dX1, _dX2, x);
_dX2 = max(_dX1, _dX2, x);
}
public void includeYCoordinate(double y) {
_dY1 = min(_dY1, _dY2, y);
_dY2 = max(_dY1, _dY2, y);
}
public void includePoint(double x, double y) {
includeXCoordinate(x);
includeYCoordinate(y);
}
public void includePoint(Point2D aPoint2D) {
includePoint(aPoint2D.getX(), aPoint2D.getY());
}
public void includeLine(double x1, double y1, double x2, double y2) {
includePoint(x1, y1);
includePoint(x2, y2);
}
public void includeLine(Point2D onePoint2D, Point2D twoPoint2D) {
includeLine(onePoint2D.getX(), onePoint2D.getY(),
twoPoint2D.getX(), twoPoint2D.getY());
}
public void includeBounds(Bounds aBounds) {
includeXCoordinate(aBounds.getLesserX());
includeXCoordinate(aBounds.getGreaterX());
includeYCoordinate(aBounds.getLesserY());
includeYCoordinate(aBounds.getGreaterY());
}
public void includeRectangle2D(Rectangle2D aRectangle2D) {
includeXCoordinate(aRectangle2D.getMinX());
includeXCoordinate(aRectangle2D.getMaxX());
includeYCoordinate(aRectangle2D.getMinY());
includeYCoordinate(aRectangle2D.getMaxY());
}
public void intersect(Bounds aBounds) {
_dX1 = Math.max(_dX1, aBounds.getLesserX());
_dY1 = Math.max(_dY1, aBounds.getLesserY());
_dX2 = Math.min(_dX2, aBounds.getGreaterX());
_dY2 = Math.min(_dY2, aBounds.getGreaterY());
if (_dX1 > _dX2) {
_dX1 = _dX2;
}
if (_dY1 > _dY2) {
_dY1 = _dY2;
}
}
public boolean intersectsPoint(double x, double y) {
return ((_dX1 <= x) && (x <= _dX2) && (_dY1 <= y) && (y <= _dY2));
}
public boolean intersectsPoint(Point2D aPoint2D) {
return intersectsPoint(aPoint2D.getX(), aPoint2D.getY());
}
public boolean intersectsLine(double x1, double y1, double x2, double y2) {
if (intersectsPoint(x1, y1)) {
return true;
}
if (intersectsPoint(x2, y2)) {
return true;
}
if ((x1 < _dX1) && (x2 < _dX1)) {
return false;
}
if ((x1 > _dX2) && (x2 > _dX2)) {
return false;
}
if ((y1 < _dY1) && (y2 < _dY1)) {
return false;
}
if ((y1 > _dY2) && (y2 > _dY2)) {
return false;
}
if (((_dX1 <= x1) && (x1 <= _dX2)) && ((_dX1 <= x2) && (x2 <= _dX2))) {
return true;
}
if (((_dY1 <= y1) && (y1 <= _dY2)) && ((_dY1 <= y2) && (y2 <= _dY2))) {
return true;
}
double dSlope = (y2-y1) / (x2-x1);
double _dYIntersectionAtX1 = dSlope * (_dX1 - x1) + y1;
double _dYIntersectionAtX2 = dSlope * (_dX2 - x1) + y1;
double _dXIntersectionAtY1 = (_dY1 - y1) / dSlope + x1;
double _dXIntersectionAtY2 = (_dY2 - y1) / dSlope + x1;
return (intersectsPoint(_dX1, _dYIntersectionAtX1)) ||
(intersectsPoint(_dX2, _dYIntersectionAtX2)) ||
(intersectsPoint(_dXIntersectionAtY1, _dY1)) ||
(intersectsPoint(_dXIntersectionAtY2, _dY2));
}
public boolean intersectsLine(Point2D onePoint2D, Point2D twoPoint2D) {
return intersectsLine(onePoint2D.getX(), onePoint2D.getY(),
twoPoint2D.getX(), twoPoint2D.getY());
}
//use K-map to simplify
public boolean intersectsBounds(Bounds aBounds) {
double dLesserX = aBounds.getLesserX();
double dGreaterX = aBounds.getGreaterX();
double dLesserY = aBounds.getLesserY();
double dGreaterY = aBounds.getGreaterY();
if (dLesserX < _dX1) {
if (dLesserY < _dY1) {
return ((dGreaterX >= _dX1) && (dGreaterY >= _dY1));
}
else {
return ((dGreaterX >= _dX1) && (dLesserY <= _dY2));
}
}
else {
if (dLesserY < _dY1) {
return ((dLesserX <= _dX2) && (dGreaterY >= _dY1));
}
else {
return ((dLesserX <= _dX2) && (dLesserY <= _dY2));
}
}
}
public boolean completelyContainsLine(double x1, double y1, double x2, double y2) {
return (_dX1 > Math.min(x1, x2)) &&
(_dX2 < Math.max(x1, x2)) &&
(_dY1 > Math.min(y1, y2)) &&
(_dY2 < Math.max(y1, y2));
}
public boolean isCompletelyInside(Bounds aBounds) {
return (_dX1 > aBounds.getLesserX()) &&
(_dX2 < aBounds.getGreaterX()) &&
(_dY1 > aBounds.getLesserY()) &&
(_dY2 < aBounds.getGreaterY());
}
public Point2D[] cropLine(double x1, double y1, double x2, double y2) {
if (!intersectsLine(x1, y1, x2, y2)) {
return null;
}
Point2D[] resultLine = new Point2D[2];
Point2D beginPoint2D = new Point2D.Double(x1, y1);
Point2D endPoint2D = new Point2D.Double(x2, y2);
if (beginPoint2D.getX() == endPoint2D.getX()) {
if (beginPoint2D.getY() > _dY2) {
beginPoint2D.setLocation(beginPoint2D.getX(), _dY2);
}
if (endPoint2D.getY() > _dY2) {
endPoint2D.setLocation(endPoint2D.getX(), _dY2);
}
if (beginPoint2D.getY() < _dY1) {
beginPoint2D.setLocation(beginPoint2D.getX(), _dY1);
}
if (endPoint2D.getY() < _dY1) {
endPoint2D.setLocation(endPoint2D.getX(), _dY1);
}
}
else if (beginPoint2D.getY() == endPoint2D.getY()) {
if (beginPoint2D.getX() > _dX2) {
beginPoint2D.setLocation(_dX2, beginPoint2D.getY());
}
if (endPoint2D.getX() > _dX2) {
endPoint2D.setLocation(_dX2, endPoint2D.getY());
}
if (beginPoint2D.getX() < _dX1) {
beginPoint2D.setLocation(_dX1, beginPoint2D.getY());
}
if (endPoint2D.getX() < _dX1) {
endPoint2D.setLocation(_dX1, endPoint2D.getY());
}
}
else {
double dSlope = (beginPoint2D.getY() - endPoint2D.getY())
/ (beginPoint2D.getX() - endPoint2D.getX());
if (!intersectsPoint(beginPoint2D)) {
if (beginPoint2D.getY() > _dY2) {
double x = ((_dY2 - beginPoint2D.getY()) / dSlope) + beginPoint2D.getX();
if ((x >= _dX1) && (x <= _dX2)) {
beginPoint2D.setLocation(x, beginPoint2D.getY());
beginPoint2D.setLocation(beginPoint2D.getX(), _dY2);
}
}
if (beginPoint2D.getY() < _dY1) {
double x = ((_dY1 - beginPoint2D.getY()) / dSlope) + beginPoint2D.getX();
if ((x >= _dX1) && (x <= _dX2)) {
beginPoint2D.setLocation(x, beginPoint2D.getY());
beginPoint2D.setLocation(beginPoint2D.getX(), _dY1);
}
}
if (beginPoint2D.getX() > _dX2) {
double y = dSlope*(_dX2 - beginPoint2D.getX()) + beginPoint2D.getY();
if ((y >= _dY1) && (y <= _dY2)) {
beginPoint2D.setLocation(_dX2, beginPoint2D.getY());
beginPoint2D.setLocation(beginPoint2D.getX(), y);
}
}
if (beginPoint2D.getX() < _dX1) {
double y = dSlope*(_dX1 - beginPoint2D.getX()) + beginPoint2D.getY();
if ((y >= _dY1) && (y <= _dY2)) {
beginPoint2D.setLocation(_dX1, beginPoint2D.getY());
beginPoint2D.setLocation(beginPoint2D.getX(), y);
}
}
}
if (!intersectsPoint(endPoint2D)) {
if (endPoint2D.getY() > _dY2) {
double x = ((_dY2 - beginPoint2D.getY()) / dSlope) + beginPoint2D.getX();
if ((x >= _dX1) && (x <= _dX2)) {
endPoint2D.setLocation(x, endPoint2D.getY());
endPoint2D.setLocation(endPoint2D.getX(), _dY2);
}
}
if (endPoint2D.getY() < _dY1) {
double x = ((_dY1 - beginPoint2D.getY()) / dSlope) + beginPoint2D.getX();
if ((x >= _dX1) && (x <= _dX2)) {
endPoint2D.setLocation(x, endPoint2D.getY());
endPoint2D.setLocation(endPoint2D.getX(), _dY1);
}
}
if (endPoint2D.getX() > _dX2) {
double y = dSlope*(_dX2 - beginPoint2D.getX()) + beginPoint2D.getY();
if ((y >= _dY1) && (y <= _dY2)) {
endPoint2D.setLocation(_dX2, endPoint2D.getY());
endPoint2D.setLocation(endPoint2D.getX(), y);
}
}
if (endPoint2D.getX() < _dX1) {
double y = dSlope*(_dX1 - beginPoint2D.getX()) + beginPoint2D.getY();
if ((y >= _dY1) && (y <= _dY2)) {
endPoint2D.setLocation(_dX1, endPoint2D.getY());
endPoint2D.setLocation(endPoint2D.getX(), y);
}
}
}
}
resultLine[0] = beginPoint2D;
resultLine[1] = endPoint2D;
return resultLine;
}
public boolean equals(Object anObject) {
if ((anObject == null) || (!(anObject instanceof Bounds))) {
return false;
}
Bounds aBounds = (Bounds) anObject;
if ((_dX1 == aBounds.getLesserX()) &&
(_dX2 == aBounds.getGreaterX()) &&
(_dY1 == aBounds.getLesserY()) &&
(_dY2 == aBounds.getGreaterY())) {
return true;
}
return false;
}
public int hashCode() {
double temp = Math.abs(_dX1 + _dX2 +_dY1 + _dY2);
while ((temp != 0) && (temp < 1)) {
temp *= 4;
}
return (int) temp;
}
public String toString() {
return Double.toString(_dX1) + " " + Double.toString(_dY1)
+ " " + Double.toString(_dX2) + " " + Double.toString(_dY2);
}
private double min( double x1, double x2, double x3 ) {
return Math.min( Math.min( x1, x2 ), x3 );
}
private double max( double x1, double x2, double x3 ) {
return Math.max( Math.max( x1, x2 ), x3 );
}
}