/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Alexander Nyßen (itemis AG) - migration to double precision
* Matthias Wienand (itemis AG) - contribution for Bugzilla #355997
*
*******************************************************************************/
package org.eclipse.gef.geometry.planar;
import java.io.Serializable;
import org.eclipse.gef.geometry.internal.utils.PrecisionUtils;
/**
* A {@link Dimension} represents a width and a height in 2-dimensional space.
* It provides various methods for manipulating the {@link Dimension} or
* creating new derived objects.
*
* @author ebordeau
* @author rhudson
* @author pshah
* @author ahunter
* @author anyssen
* @author mwienand
*
*/
public class Dimension implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
/**
* Creates a new {@link Dimension} representing the maximum of the two
* provided {@link Dimension}s.
*
* @param d1
* the first {@link Dimension}
* @param d2
* the second {@link Dimension}
* @return a new {@link Dimension} representing the maximum of the given
* {@link Dimension}s
*/
public static Dimension max(Dimension d1, Dimension d2) {
return new Dimension(Math.max(d1.width, d2.width),
Math.max(d1.height, d2.height));
}
/**
* Creates a new {@link Dimension} representing the minimum of the two
* provided {@link Dimension}s.
*
* @param d1
* the first {@link Dimension}
* @param d2
* the second {@link Dimension}
* @return a new {@link Dimension} representing the minimum of the two
* provided {@link Dimension}s
*/
public static Dimension min(Dimension d1, Dimension d2) {
return new Dimension(Math.min(d1.width, d2.width),
Math.min(d1.height, d2.height));
}
/**
* This {@link Dimension}'s width. It is the distance on the x-axis that is
* stored in this {@link Dimension}.
*/
public double width;
/**
* This {@link Dimension}'s height. It is the distance of the y-axis that is
* stored in this {@link Dimension}.
*/
public double height;
/**
* Constructs a {@link Dimension} of zero width and height.
*/
public Dimension() {
}
/**
* Constructs a {@link Dimension} with the width and height of the passed-in
* {@link Dimension}.
*
* @param d
* the {@link Dimension} supplying the initial width and height
* values
*/
public Dimension(Dimension d) {
this(d.width, d.height);
}
/**
* Constructs a {@link Dimension} with the supplied width and height values.
*
* @param w
* the width of the new {@link Dimension}
* @param h
* the height of the new {@link Dimension}
*/
public Dimension(double w, double h) {
if (Double.isNaN(w)) {
throw new IllegalArgumentException(
"width has to be differen from NaN.");
}
if (Double.isNaN(h)) {
throw new IllegalArgumentException(
"height has to be differen from NaN.");
}
width = w;
height = h;
}
@Override
public Dimension clone() {
return getCopy();
}
/**
* Checks if the given {@link Dimension} fits into this {@link Dimension}.
* In order to fit into this {@link Dimension}, the passed-in
* {@link Dimension}'s width and height have to be smaller than this
* {@link Dimension}'s width and height, within the default imprecision (see
* {@link PrecisionUtils}).
*
* @param d
* the {@link Dimension} that is checked if it fits into this
* {@link Dimension}
* @return <code>true</code> if this {@link Dimension} contains the given
* {@link Dimension}
*/
public boolean contains(Dimension d) {
return PrecisionUtils.greaterEqual(width, d.width)
&& PrecisionUtils.greaterEqual(height, d.height);
}
/**
* Returns <code>true</code> if this Dimension's width and height are equal
* to the given width and height.
*
* @param width
* the width
* @param height
* the height
* @return <code>true</code> if this dimension's width and height are equal
* to those given.
*/
public boolean equals(double width, double height) {
return PrecisionUtils.equal(this.width, width)
&& PrecisionUtils.equal(this.height, height);
}
/**
* Returns whether the input Object is equivalent to this Dimension.
* <code>true</code> if the Object is a Dimension and its width and height
* are equal to this Dimension's width and height, <code>false</code>
* otherwise.
*
* @param o
* the Object being tested for equality
* @return <code>true</code> if the given object is equal to this dimension
*/
@Override
public boolean equals(Object o) {
if (o instanceof Dimension) {
Dimension d = (Dimension) o;
return equals(d.width, d.height);
}
return false;
}
/**
* Expands the size of this Dimension by the specified amount.
*
* @param d
* the Dimension providing the expansion width and height
* @return <code>this</code> for convenience
*/
public Dimension expand(Dimension d) {
return expand(d.width, d.height);
}
/**
* Expands the size of this Dimension by the specified width and height.
*
* @param w
* Value by which the width should be increased
* @param h
* Value by which the height should be increased
* @return <code>this</code> for convenience
*/
public Dimension expand(double w, double h) {
width += w;
height += h;
return this;
}
/**
* Creates and returns a copy of this {@link Dimension}.
*
* @return a copy of this Dimension
*/
public Dimension getCopy() {
return new Dimension(this);
}
/**
* Creates and returns a {@link Dimension} representing the sum of this
* {@link Dimension} and the one specified.
*
* @param d
* the dimension providing the expansion width and height
* @return a new dimension expanded by <i>d</i>
*/
public Dimension getExpanded(Dimension d) {
return getCopy().expand(d);
}
/**
* Creates and returns a new Dimension representing the sum of this
* {@link Dimension} and the one specified.
*
* @param w
* value by which the width of this is to be expanded
* @param h
* value by which the height of this is to be expanded
* @return a new Dimension expanded by the given values
*/
public Dimension getExpanded(double w, double h) {
return getCopy().expand(w, h);
}
/**
* Returns the height of this dimension.
*
* @return The current height
*/
public double getHeight() {
return height;
}
/**
* Creates and returns a new Dimension representing the intersection of this
* Dimension and the one specified.
*
* @param d
* the Dimension to intersect with
* @return A new Dimension representing the intersection
*/
public Dimension getIntersected(Dimension d) {
return getCopy().intersect(d);
}
/**
* Creates and returns a new Dimension with negated values.
*
* @return a new Dimension with negated values
*/
public Dimension getNegated() {
return getCopy().negate();
}
/**
* Creates a new Dimension with its width and height scaled by the specified
* value.
*
* @param amount
* Value by which the width and height are scaled
* @return a new dimension with the scale applied
*/
public Dimension getScaled(double amount) {
return getCopy().scale(amount);
}
/**
* Creates a new Dimension with its width and height scaled by the specified
* values.
*
* @param widthFactor
* the value by which the width is to be scaled
* @param heightFactor
* the value by which the height is to be scaled
* @return a new dimension with the scale applied
*/
public Dimension getScaled(double widthFactor, double heightFactor) {
return getCopy().scale(widthFactor, heightFactor);
}
/**
* Creates and returns a new Dimension whose size will be reduced by the
* width and height of the given Dimension.
*
* @param d
* the dimension whose width and height values will be considered
* @return a new dimension representing the difference
*/
public Dimension getShrinked(Dimension d) {
return getCopy().shrink(d);
}
/**
* Creates and returns a new Dimension whose size will be reduced by the
* given width and height.
*
* @param w
* the value by which the width is to be reduced
* @param h
* the value by which the height is to be reduced
* @return a new dimension representing the difference
*/
public Dimension getShrinked(double w, double h) {
return getCopy().shrink(w, h);
}
/**
* Creates a new Dimension with its height and width swapped. Useful in
* orientation change calculations.
*
* @return a new Dimension with its height and width swapped
*/
public Dimension getTransposed() {
return getCopy().transpose();
}
/**
* Creates a new Dimension representing the union of this Dimension with the
* one specified. Union is defined as the max() of the values from each
* Dimension.
*
* @param d
* the Dimension to be unioned
* @return a new Dimension
*/
public Dimension getUnioned(Dimension d) {
return getCopy().union(d);
}
/**
* Returns the width of this dimension
*
* @return the current width of this dimension
*/
public double getWidth() {
return width;
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
// calculating a better hashCode is not possible, because due to the
// imprecision, equals() is no longer transitive
return 0;
}
/**
* This Dimension is intersected with the one specified. Intersection is
* performed by taking the min() of the values from each dimension.
*
* @param d
* the Dimension used to perform the min()
* @return <code>this</code> for convenience
*/
public Dimension intersect(Dimension d) {
width = Math.min(d.width, width);
height = Math.min(d.height, height);
return this;
}
/**
* Returns <code>true</code> if either dimension is less than or equal to 0.
*
* @return <code>true</code> if either dimension is less than or equal to 0.
*/
public boolean isEmpty() {
return width <= 0 || height <= 0;
}
/**
* Negates the width and height of this Dimension.
*
* @return <code>this</code> for convenience
*/
public Dimension negate() {
return scale(-1.0d);
}
/**
* Scales the width and height of this Dimension by the amount supplied, and
* returns this for convenience.
*
* @param factor
* value by which this Dimension's width and height are to be
* scaled
* @return <code>this</code> for convenience
*/
public Dimension scale(double factor) {
return scale(factor, factor);
}
/**
* Scales the width of this Dimension by <i>w</i> and scales the height of
* this Dimension by <i>h</i>. Returns this for convenience.
*
* @param widthFactor
* the value by which the width is to be scaled
* @param heightFactor
* the value by which the height is to be scaled
* @return <code>this</code> for convenience
*/
public Dimension scale(double widthFactor, double heightFactor) {
width *= widthFactor;
height *= heightFactor;
return this;
}
/**
* Sets the height of this Rectangle to the specified one.
*
* @param height
* The new height
* @return this for convenience
*/
public Dimension setHeight(double height) {
this.height = height;
return this;
}
/**
* Copies the width and height values of the input Dimension to this
* Dimension.
*
* @param d
* the dimension supplying the values
* @return <code>this</code> for convenience
*/
public Dimension setSize(Dimension d) {
width = d.width;
height = d.height;
return this;
}
/**
* Sets the size of this dimension to the specified width and height.
*
* @param w
* The new width
* @param h
* The new height
* @return <code>this</code> for convenience
*/
public Dimension setSize(double w, double h) {
width = w;
height = h;
return this;
}
/**
* Sets the width of this Rectangle to the specified one.
*
* @param width
* The new width
* @return this for convenience
*/
public Dimension setWidth(double width) {
this.width = width;
return this;
}
/**
* Shrinks the size of this Dimension by the width and height values of the
* given Dimension.
*
* @param d
* The dimension whose width and height values are to be used
* @return <code>this</code> for convenience
*/
public Dimension shrink(Dimension d) {
return shrink(d.width, d.height);
}
/**
* Reduces the width of this Dimension by <i>w</i>, and reduces the height
* of this Dimension by <i>h</i>. Returns this for convenience.
*
* @param w
* the value by which the width is to be reduced
* @param h
* the value by which the height is to be reduced
* @return <code>this</code> for convenience
*/
public Dimension shrink(double w, double h) {
width -= w;
height -= h;
return this;
}
/**
* @see Object#toString()
*/
@Override
public String toString() {
return "Dimension(" + //$NON-NLS-1$
width + ", " + //$NON-NLS-1$
height + ")"; //$NON-NLS-1$
}
/**
* Swaps the width and height of this Dimension, and returns this for
* convenience. Can be useful in orientation changes.
*
* @return <code>this</code> for convenience
*/
public Dimension transpose() {
double temp = width;
width = height;
height = temp;
return this;
}
/**
* Sets the width of this Dimension to the greater of this Dimension's width
* and <i>d</i>.width. Likewise for this Dimension's height.
*
* @param d
* the Dimension to union with this Dimension
* @return <code>this</code> for convenience
*/
public Dimension union(Dimension d) {
width = Math.max(width, d.width);
height = Math.max(height, d.height);
return this;
}
}