/*******************************************************************************
 * Copyright (c) 2003, 2010 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
 *******************************************************************************/
package org.eclipse.draw2d.geometry;

/**
 * A Rectangle implementation using floating point values which are truncated
 * into the inherited integer fields. The use of floating point prevents
 * rounding errors from accumulating.
 * 
 * @author hudsonr Created on Apr 9, 2003
 */
public final class PrecisionRectangle extends Rectangle {

	private static final long serialVersionUID = 1L;

	/**
	 * Double value for height
	 * 
	 * @noreference
	 * @deprecated Use {@link #setPreciseHeight(double)} and
	 *             {@link #preciseHeight()} instead. This field will become
	 *             private in the future.
	 */
	public double preciseHeight;

	/**
	 * Double value for width
	 * 
	 * @noreference
	 * @deprecated Use {@link #setPreciseWidth(double)} and
	 *             {@link #preciseWidth()} instead. This field will become
	 *             private in the future.
	 */
	public double preciseWidth;

	/**
	 * Double value for X
	 * 
	 * @noreference
	 * @deprecated Use {@link #setPreciseX(double)} and {@link #preciseX()}
	 *             instead. This field will become private in the future.
	 */
	public double preciseX;

	/**
	 * Double value for Y
	 * 
	 * @noreference
	 * @deprecated Use {@link #setPreciseX(double)} and {@link #preciseY()}
	 *             instead. This field will become private in the future.
	 */
	public double preciseY;

	/**
	 * Constructs a new PrecisionRectangle with all values 0.
	 */
	public PrecisionRectangle() {
	}

	/**
	 * Constructs a PrecisionRectangle with the provided values.
	 * 
	 * @param x
	 *            X location
	 * @param y
	 *            Y location
	 * @param width
	 *            Width of the rectangle
	 * @param height
	 *            Height of the rectangle
	 * @since 3.7
	 */
	public PrecisionRectangle(double x, double y, double width, double height) {
		setPreciseLocation(x, y);
		setPreciseSize(width, height);
	}

	/**
	 * 
	 * Constructs a new PrecisionRectangle from a given Point and a Dimension
	 * 
	 * @param p
	 *            The Point to specify x and y location of the
	 *            PrecisionRectangle
	 * @param d
	 *            The Dimension to use for width and height of the
	 *            PrecisionRectangle
	 * @since 3.7
	 */
	public PrecisionRectangle(Point p, Dimension d) {
		this(p.preciseX(), p.preciseY(), d.preciseWidth(), d.preciseHeight());
	}

	/**
	 * Constructs a new PrecisionRectangle from the given integer Rectangle.
	 * 
	 * @param rect
	 *            the base rectangle
	 */
	public PrecisionRectangle(Rectangle rect) {
		this(rect.preciseX(), rect.preciseY(), rect.preciseWidth(), rect
				.preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#contains(int, int)
	 */
	public boolean contains(int x, int y) {
		return containsPrecise(x, y);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#contains(org.eclipse.draw2d.geometry.Point)
	 */
	public boolean contains(Point p) {
		return containsPrecise(p.preciseX(), p.preciseY());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#contains(org.eclipse.draw2d.geometry.Rectangle)
	 */
	public boolean contains(Rectangle rect) {
		return preciseX() <= rect.preciseX() && preciseY() <= rect.preciseY()
				&& right() >= rect.right() && bottom() >= rect.bottom();
	}

	/**
	 * Returns whether the given coordinates are within the boundaries of this
	 * Rectangle. The boundaries are inclusive of the top and left edges, but
	 * exclusive of the bottom and right edges.
	 * 
	 * @param x
	 *            X value
	 * @param y
	 *            Y value
	 * @return true if the coordinates are within this Rectangle
	 * @since 3.7
	 */
	private boolean containsPrecise(double x, double y) {
		return y >= preciseY() && y < preciseY() + preciseHeight()
				&& x >= preciseX() && x < preciseX() + preciseWidth();
	}

	/**
	 * @see Rectangle#equals(Object)
	 */
	public boolean equals(Object o) {
		if (o instanceof PrecisionRectangle) {
			PrecisionRectangle rect = (PrecisionRectangle) o;
			return super.equals(o)
					&& Math.abs(rect.preciseX() - preciseX()) < 0.000000001
					&& Math.abs(rect.preciseY() - preciseY()) < 0.000000001
					&& Math.abs(rect.preciseWidth() - preciseWidth()) < 0.000000001
					&& Math.abs(rect.preciseHeight() - preciseHeight()) < 0.00000001;
		}

		return super.equals(o);
	}

	/**
	 * Expands the horizontal and vertical sides of this Rectangle with the
	 * values provided as input, and returns this for convenience. The location
	 * of its center is kept constant.
	 * 
	 * @param h
	 *            Horizontal increment
	 * @param v
	 *            Vertical increment
	 * @return <code>this</code> for convenience
	 * @since 3.4
	 * @deprecated Use {@link #expandPrecise(double, double)} instead.
	 */
	public Rectangle expand(double h, double v) {
		return shrink(-h, -v);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#expand(org.eclipse.draw2d.geometry.Insets)
	 */
	public Rectangle expand(Insets insets) {
		if (insets == null)
			return this;
		setPreciseX(preciseX() - insets.left);
		setPreciseY(preciseY() - insets.top);
		setPreciseWidth(preciseWidth() + insets.getWidth());
		setPreciseHeight(preciseHeight() + insets.getHeight());
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#expand(int, int)
	 */
	public Rectangle expand(int h, int v) {
		return expandPrecise(h, v);
	}

	/**
	 * Expands the horizontal and vertical sides of this Rectangle with the
	 * values provided as input, and returns this for convenience. The location
	 * of its center is kept constant.
	 * 
	 * @param h
	 *            Horizontal increment
	 * @param v
	 *            Vertical increment
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle expandPrecise(double h, double v) {
		return shrinkPrecise(-h, -v);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getBottom()
	 */
	public Point getBottom() {
		return new PrecisionPoint(preciseX() + preciseWidth() / 2, bottom());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getBottomLeft()
	 */
	public Point getBottomLeft() {
		return new PrecisionPoint(preciseX(), preciseY() + preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getBottomRight()
	 */
	public Point getBottomRight() {
		return new PrecisionPoint(preciseX() + preciseWidth(), preciseY()
				+ preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getCenter()
	 */
	public Point getCenter() {
		return new PrecisionPoint(preciseX() + preciseWidth() / 2.0, preciseY()
				+ preciseHeight() / 2.0);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getCopy()
	 */
	public Rectangle getCopy() {
		return getPreciseCopy();
	}

	/**
	 * Returns a precise copy of this.
	 * 
	 * @return a precise copy
	 */
	public PrecisionRectangle getPreciseCopy() {
		return new PrecisionRectangle(preciseX(), preciseY(), preciseWidth(),
				preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getTop()
	 */
	public Point getTop() {
		return new PrecisionPoint(preciseX() + preciseWidth() / 2, preciseY());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getTopLeft()
	 */
	public Point getTopLeft() {
		return new PrecisionPoint(preciseX(), preciseY());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#getTopRight()
	 */
	public Point getTopRight() {
		return new PrecisionPoint(preciseX() + preciseWidth(), preciseY());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#intersect(org.eclipse.draw2d.geometry.Rectangle)
	 */
	public Rectangle intersect(Rectangle rect) {
		return intersectPrecise(rect);
	}

	/**
	 * Sets the size of this Rectangle to the intersection region with the
	 * Rectangle supplied as input, and returns this for convenience. The
	 * location and dimensions are set to zero if there is no intersection with
	 * the input Rectangle.
	 * 
	 * @param rect
	 *            Rectangle for the calculating intersection.
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle intersectPrecise(Rectangle rect) {
		double x1 = Math.max(preciseX(), rect.preciseX());
		double x2 = Math.min(preciseX() + preciseWidth(), rect.preciseX()
				+ rect.preciseWidth());
		double y1 = Math.max(preciseY(), rect.preciseY());
		double y2 = Math.min(preciseY() + preciseHeight(), rect.preciseY()
				+ rect.preciseHeight());
		if (((x2 - x1) < 0) || ((y2 - y1) < 0))
			return setPreciseBounds(0, 0, 0, 0); // no intersection
		else {
			return setPreciseBounds(x1, y1, x2 - x1, y2 - y1);
		}
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#performScale(double)
	 */
	public void performScale(double factor) {
		setPreciseX(preciseX() * factor);
		setPreciseY(preciseY() * factor);
		setPreciseWidth(preciseWidth() * factor);
		setPreciseHeight(preciseHeight() * factor);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#performTranslate(int, int)
	 */
	public void performTranslate(int dx, int dy) {
		setPreciseX(preciseX() + dx);
		setPreciseY(preciseY() + dy);
	}

	/**
	 * Returns the bottom coordinte in double precision.
	 * 
	 * @return the precise bottom
	 */
	public double preciseBottom() {
		return preciseHeight() + preciseY();
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#preciseHeight()
	 */
	public double preciseHeight() {
		updatePreciseHeightDouble();
		return preciseHeight;
	}

	/**
	 * Returns the right side in double precision.
	 * 
	 * @return the precise right
	 */
	public double preciseRight() {
		return preciseWidth() + preciseX();
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#preciseWidth()
	 */
	public double preciseWidth() {
		updatePreciseWidthDouble();
		return preciseWidth;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#preciseX()
	 */
	public double preciseX() {
		updatePreciseXDouble();
		return preciseX;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#preciseY()
	 */
	public double preciseY() {
		updatePreciseYDouble();
		return preciseY;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#resize(org.eclipse.draw2d.geometry.Dimension)
	 */
	public Rectangle resize(Dimension d) {
		return resizePrecise(d.preciseWidth(), d.preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#resize(int, int)
	 */
	public Rectangle resize(int w, int h) {
		return resizePrecise(w, h);
	}

	/**
	 * Resizes this Rectangle by adding the values supplied, returning this for
	 * convenience.
	 * 
	 * @param w
	 *            Amount by which width is to be resized
	 * @param h
	 *            Amount by which height is to be resized
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle resizePrecise(double w, double h) {
		setPreciseWidth(preciseWidth() + w);
		setPreciseHeight(preciseHeight() + h);
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setBounds(int, int, int, int)
	 */
	public Rectangle setBounds(int x, int y, int width, int height) {
		return setPreciseBounds(x, y, width, height);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setBounds(org.eclipse.draw2d.geometry.Point,
	 *      org.eclipse.draw2d.geometry.Dimension)
	 */
	public Rectangle setBounds(Point location, Dimension size) {
		return setPreciseBounds(location.preciseX(), location.preciseY(),
				size.preciseWidth(), size.preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setBounds(org.eclipse.draw2d.geometry.Rectangle)
	 */
	public Rectangle setBounds(Rectangle rect) {
		return setPreciseBounds(rect.preciseX(), rect.preciseY(),
				rect.preciseWidth(), rect.preciseHeight());
	}

	/**
	 * Sets the height.
	 * 
	 * @param value
	 *            the new height
	 * @deprecated Use {@link #setPreciseHeight(double)} instead.
	 */
	public void setHeight(double value) {
		setPreciseHeight(value);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setHeight(int)
	 */
	public Rectangle setHeight(int height) {
		return setPreciseHeight(height);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setLocation(int, int)
	 */
	public Rectangle setLocation(int x, int y) {
		return setPreciseLocation(x, y);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setLocation(org.eclipse.draw2d.geometry.Point)
	 */
	public Rectangle setLocation(Point loc) {
		return setPreciseLocation(loc.preciseX(), loc.preciseY());
	}

	/**
	 * Sets the preciseX, preciseY, preciseWidth, and preciseHeight values of
	 * this PrecisionRectangle to the provided values and updates the integer
	 * values of x, y, width, and height accordingly.
	 * 
	 * @param x
	 *            The new x
	 * @param y
	 *            The new y
	 * @param width
	 *            The new width
	 * @param height
	 *            The new height
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseBounds(double x, double y,
			double width, double height) {
		setPreciseLocation(x, y);
		setPreciseSize(width, height);
		return this;
	}

	/**
	 * Sets the height of this PrecisionRectangle to the specified value.
	 * 
	 * @param value
	 *            The new height.
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseHeight(double value) {
		preciseHeight = value;
		updateHeightInt();
		return this;
	}

	/**
	 * Sets the preciseX and preciseY values of this PrecisionRectangle to the
	 * provided values and updates the integer values of x and y accordingly.
	 * 
	 * @param x
	 *            The new x value
	 * @param y
	 *            The new y value
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseLocation(double x, double y) {
		setPreciseX(x);
		setPreciseY(y);
		return this;
	}

	/**
	 * Sets the precise location of this PrecisionRectangle
	 * 
	 * @param loc
	 *            The new location
	 * @return this for convenience.
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseLocation(PrecisionPoint loc) {
		return setPreciseLocation(loc.preciseX(), loc.preciseY());
	}

	/**
	 * Sets the preciseWidth and preciseHeight values of this PrecisionRectangle
	 * to the provided values and updates the integer values of width and height
	 * accordingly.
	 * 
	 * @param w
	 *            The new width
	 * @param h
	 *            The new height
	 * @return this for convenience.
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseSize(double w, double h) {
		setPreciseWidth(w);
		setPreciseHeight(h);
		return this;
	}

	/**
	 * Set the size of this PrecisionRectangle to the given dimension's width
	 * and height. Returns this for convenience.
	 * 
	 * @param size
	 *            The new size
	 * @return this for convenience.
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseSize(PrecisionDimension size) {
		return setPreciseSize(size.preciseWidth(), size.preciseHeight());
	}

	/**
	 * Sets the width of this PrecisionRectangle to the specified one.
	 * 
	 * @param value
	 *            The new width
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseWidth(double value) {
		preciseWidth = value;
		updateWidthInt();
		return this;
	}

	/**
	 * Sets the x value.
	 * 
	 * @param value
	 *            The new x value
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseX(double value) {
		preciseX = value;
		updateXInt();
		return this;
	}

	/**
	 * Sets the y value.
	 * 
	 * @param value
	 *            the new y value
	 * @return this for convenience
	 * @since 3.7
	 */
	public PrecisionRectangle setPreciseY(double value) {
		preciseY = value;
		updateYInt();
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setSize(org.eclipse.draw2d.geometry.Dimension)
	 */
	public Rectangle setSize(Dimension d) {
		return setPreciseSize(d.preciseWidth(), d.preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setSize(int, int)
	 */
	public Rectangle setSize(int w, int h) {
		return setPreciseSize(w, h);
	}

	/**
	 * Sets the width.
	 * 
	 * @param value
	 *            the new width
	 * @deprecated Use {@link #setPreciseWidth(double)} instead.
	 */
	public void setWidth(double value) {
		setPreciseWidth(value);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setWidth(int)
	 */
	public Rectangle setWidth(int width) {
		return setPreciseWidth(width);
	}

	/**
	 * Sets the x value.
	 * 
	 * @param value
	 *            the new x value
	 * @deprecated Use {@link #setPreciseX(double)} instead.
	 */
	public void setX(double value) {
		setPreciseX(value);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setX(int)
	 */
	public Rectangle setX(int value) {
		return setPreciseX(value);
	}

	/**
	 * Sets the y value.
	 * 
	 * @param value
	 *            the new y value
	 * @deprecated Use {@link #setPreciseX(double)} instead.
	 */
	public void setY(double value) {
		setPreciseY(value);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#setY(int)
	 */
	public Rectangle setY(int value) {
		return setPreciseY(value);
	}

	/**
	 * Shrinks the sides of this Rectangle by the horizontal and vertical values
	 * provided as input, and returns this Rectangle for convenience. The center
	 * of this Rectangle is kept constant.
	 * 
	 * @param h
	 *            Horizontal reduction amount
	 * @param v
	 *            Vertical reduction amount
	 * @return <code>this</code> for convenience
	 * @since 3.4
	 * @deprecated Use {@link #shrink(int, int)} or
	 *             {@link #shrinkPrecise(double, double)} instead.
	 */
	public Rectangle shrink(double h, double v) {
		return shrinkPrecise(h, v);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#shrink(org.eclipse.draw2d.geometry.Insets)
	 */
	public Rectangle shrink(Insets insets) {
		if (insets == null)
			return this;
		setPreciseX(preciseX() + insets.left);
		setPreciseY(preciseY() + insets.top);
		setPreciseWidth(preciseWidth() - insets.getWidth());
		setPreciseHeight(preciseHeight() - insets.getHeight());
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#shrink(int, int)
	 */
	public Rectangle shrink(int h, int v) {
		return shrinkPrecise(h, v);
	}

	/**
	 * Shrinks the sides of this Rectangle by the horizontal and vertical values
	 * provided as input, and returns this Rectangle for convenience. The center
	 * of this Rectangle is kept constant.
	 * 
	 * @param h
	 *            Horizontal reduction amount
	 * @param v
	 *            Vertical reduction amount
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle shrinkPrecise(double h, double v) {
		setPreciseX(preciseX() + h);
		setPreciseWidth(preciseWidth() - (h + h));
		setPreciseY(preciseY() + v);
		setPreciseHeight(preciseHeight() - (v + v));
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#touches(org.eclipse.draw2d.geometry.Rectangle)
	 */
	public boolean touches(Rectangle rect) {
		return rect.preciseX() <= preciseX() + preciseWidth()
				&& rect.preciseY() <= preciseY() + preciseHeight()
				&& rect.preciseX() + rect.preciseWidth() >= preciseX()
				&& rect.preciseY() + rect.preciseHeight() >= preciseY();
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#translate(int, int)
	 */
	public Rectangle translate(int dx, int dy) {
		return translatePrecise(dx, dy);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#translate(org.eclipse.draw2d.geometry.Point)
	 */
	public Rectangle translate(Point p) {
		return translatePrecise(p.preciseX(), p.preciseY());
	}

	/**
	 * Moves this Rectangle horizontally by dx and vertically by dy, then
	 * returns this Rectangle for convenience.
	 * 
	 * @param dx
	 *            Shift along X axis
	 * @param dy
	 *            Shift along Y axis
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle translatePrecise(double dx, double dy) {
		setPreciseX(preciseX() + dx);
		setPreciseY(preciseY() + dy);
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#transpose()
	 */
	public Rectangle transpose() {
		double temp = preciseX();
		setPreciseX(preciseY());
		setPreciseY(temp);
		temp = preciseWidth();
		setPreciseWidth(preciseHeight());
		setPreciseHeight(temp);
		return this;
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#union(int, int)
	 */
	public Rectangle union(int x, int y) {
		return unionPrecise(x, y);
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#union(org.eclipse.draw2d.geometry.Point)
	 */
	public void union(Point p) {
		unionPrecise(p.preciseX(), p.preciseY());
	}

	/**
	 * Unions the given PrecisionRectangle with this rectangle and returns
	 * <code>this</code> for convenience.
	 * 
	 * @since 3.0
	 * @param rect
	 *            the rectangle being unioned
	 * @return <code>this</code> for convenience
	 * @deprecated Use {@link #union(Rectangle)} instead
	 */
	public PrecisionRectangle union(PrecisionRectangle rect) {
		if (rect == null || rect.isEmpty()) {
			return this;
		}
		return unionPrecise(rect.preciseX(), rect.preciseY(),
				rect.preciseWidth(), rect.preciseHeight());
	}

	/**
	 * @see org.eclipse.draw2d.geometry.Rectangle#union(org.eclipse.draw2d.geometry.Rectangle)
	 */
	public Rectangle union(Rectangle rect) {
		if (rect == null || rect.isEmpty())
			return this;
		return unionPrecise(rect.preciseX(), rect.preciseY(),
				rect.preciseWidth(), rect.preciseHeight());
	}

	/**
	 * Updates this Rectangle's bounds to the minimum size which can hold both
	 * this Rectangle and the coordinate (x,y).
	 * 
	 * @return <code>this</code> for convenience
	 * @param x
	 *            X coordinate
	 * @param y
	 *            Y coordinate
	 * @since 3.7
	 */
	private PrecisionRectangle unionPrecise(double x, double y) {
		if (x < preciseX()) {
			setPreciseWidth(preciseWidth() + (preciseX() - x));
			setPreciseX(x);
		} else {
			double right = preciseX() + preciseWidth();
			if (x > right) {
				setPreciseWidth(x - preciseX());
			}
		}
		if (y < preciseY()) {
			setPreciseHeight(preciseHeight() + (preciseY() - y));
			setPreciseY(y);
		} else {
			double bottom = preciseY() + preciseHeight();
			if (y > bottom) {
				setPreciseHeight(y - preciseY());
			}
		}
		return this;
	}

	/**
	 * Updates this Rectangle's dimensions to the minimum size which can hold
	 * both this Rectangle and the rectangle (x, y, w, h).
	 * 
	 * @param x
	 *            X coordinate of desired union.
	 * @param y
	 *            Y coordinate of desired union.
	 * @param w
	 *            Width of desired union.
	 * @param h
	 *            Height of desired union.
	 * @return <code>this</code> for convenience
	 * @since 3.7
	 */
	private PrecisionRectangle unionPrecise(double x, double y, double w,
			double h) {
		double right = Math.max(preciseX() + preciseWidth(), x + w);
		double bottom = Math.max(preciseY() + preciseHeight(), y + h);
		setPreciseX(Math.min(preciseX(), x));
		setPreciseY(Math.min(preciseY(), y));
		setPreciseWidth(right - preciseX());
		setPreciseHeight(bottom - preciseY());
		return this;
	}

	/**
	 * Updates the height integer field using the value of preciseHeight.
	 */
	private final void updateHeightInt() {
		height = PrecisionGeometry.doubleToInteger(preciseHeight);
	}

	/**
	 * Updates the integer values based on the current precise values.
	 * 
	 * @deprecated This method should not be accessed by clients any more (it
	 *             will be made private in future releases). The update of
	 *             integer and precision fields is performed automatically if
	 *             {@link #preciseX}, {@link #preciseY}, {@link #preciseWidth},
	 *             and {@link #preciseHeight} field values are not manipulated
	 *             directly, but only via respective methods offered by this
	 *             class.
	 * 
	 * @since 3.0
	 */
	public void updateInts() {
		updateXInt();
		updateYInt();
		updateWidthInt();
		updateHeightInt();
	}

	/**
	 * Updates the preciseHeight double field using the value of height.
	 */
	private final void updatePreciseHeightDouble() {
		if (height != PrecisionGeometry.doubleToInteger(preciseHeight)) {
			preciseHeight = height;
		}
	}

	/**
	 * Updates the preciseWidth double field using the value of width.
	 */
	private final void updatePreciseWidthDouble() {
		if (width != PrecisionGeometry.doubleToInteger(preciseWidth)) {
			preciseWidth = width;
		}
	}

	/**
	 * Updates the preciseX double field using the value of x.
	 */
	private final void updatePreciseXDouble() {
		if (x != PrecisionGeometry.doubleToInteger(preciseX)) {
			preciseX = x;
		}
	}

	/**
	 * Updates the preciseY double field using the value of y.
	 */
	private final void updatePreciseYDouble() {
		if (y != PrecisionGeometry.doubleToInteger(preciseY)) {
			preciseY = y;
		}
	}

	/**
	 * Updates the width integer field using the value of preciseWidth.
	 */
	private final void updateWidthInt() {
		width = PrecisionGeometry.doubleToInteger(preciseWidth);
	}

	/**
	 * Updates the x integer field using the value of preciseX.
	 */
	private final void updateXInt() {
		x = PrecisionGeometry.doubleToInteger(preciseX);
	}

	/**
	 * Updates the y integer field using the value of preciseY.
	 */
	private final void updateYInt() {
		y = PrecisionGeometry.doubleToInteger(preciseY);
	}

}
