/******************************************************************************* * Copyright (c) 2003, 2008 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 { /** Double value for height */ public double preciseHeight; /** Double value for width */ public double preciseWidth; /** Double value for X */ public double preciseX; /** Double value for Y */ public double preciseY; /** * Constructs a new PrecisionRectangle with all values 0. */ public PrecisionRectangle() { } /** * Constructs a new PrecisionRectangle from the given integer Rectangle. * @param rect the base rectangle */ public PrecisionRectangle(Rectangle rect) { preciseX = rect.preciseX(); preciseY = rect.preciseY(); preciseWidth = rect.preciseWidth(); preciseHeight = rect.preciseHeight(); updateInts(); } /** * @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() { PrecisionRectangle result = new PrecisionRectangle(); result.preciseX = preciseX; result.preciseY = preciseY; result.preciseWidth = preciseWidth; result.preciseHeight = preciseHeight; result.updateInts(); return result; } /** * @see org.eclipse.draw2d.geometry.Rectangle#crop(org.eclipse.draw2d.geometry.Insets) */ public Rectangle crop(Insets insets) { if (insets == null) return this; setX(preciseX + insets.left); setY(preciseY + insets.top); setWidth(preciseWidth - (insets.getWidth())); setHeight(preciseHeight - (insets.getHeight())); return this; } /** * @see Rectangle#equals(Object) */ public boolean equals(Object o) { if (o instanceof PrecisionRectangle) { PrecisionRectangle pr = (PrecisionRectangle)o; return super.equals(o) && Math.abs(pr.preciseX - preciseX) < 0.000000001 && Math.abs(pr.preciseY - preciseY) < 0.000000001 && Math.abs(pr.preciseWidth - preciseWidth) < 0.000000001 && Math.abs(pr.preciseHeight - preciseHeight) < 0.00000001; } return super.equals(o); } /** * @see org.eclipse.draw2d.geometry.Rectangle#performScale(double) */ public void performScale(double factor) { preciseX *= factor; preciseY *= factor; preciseWidth *= factor; preciseHeight *= factor; updateInts(); } /** * @see org.eclipse.draw2d.geometry.Rectangle#performTranslate(int, int) */ public void performTranslate(int dx, int dy) { preciseX += dx; preciseY += dy; x += dx; y += dy; } /** * Returns the bottom coordinte in double precision. * @return the precise bottom */ public double preciseBottom() { return preciseHeight + preciseY; } /** * Returns the right side in double precision. * @return the precise right */ public double preciseRight() { return preciseWidth + preciseX; } /** * @see org.eclipse.draw2d.geometry.Rectangle#resize(org.eclipse.draw2d.geometry.Dimension) */ public Rectangle resize(Dimension sizeDelta) { preciseWidth += sizeDelta.preciseWidth(); preciseHeight += sizeDelta.preciseHeight(); updateInts(); return this; } /** * Sets the height. * @param value the new height */ public void setHeight(double value) { preciseHeight = value; height = (int)Math.floor(preciseHeight + 0.000000001); } /** * Sets the width. * @param value the new width */ public void setWidth(double value) { preciseWidth = value; width = (int)Math.floor(preciseWidth + 0.000000001); } /** * Sets the x value. * @param value the new x value */ public void setX(double value) { preciseX = value; x = (int)Math.floor(preciseX + 0.000000001); } /** * Sets the y value. * @param value the new y value */ public void setY(double value) { preciseY = value; y = (int)Math.floor(preciseY + 0.000000001); } /** * @see org.eclipse.draw2d.geometry.Rectangle#translate(org.eclipse.draw2d.geometry.Point) */ public Rectangle translate(Point p) { preciseX += p.preciseX(); preciseY += p.preciseY(); updateInts(); return this; } /** * Unions the given PrecisionRectangle with this rectangle and returns <code>this</code> * for convenience. * @since 3.0 * @param other the rectangle being unioned * @return <code>this</code> for convenience * @deprecated * Use {@link #union(Rectangle)} instead */ public PrecisionRectangle union(PrecisionRectangle other) { double newright = Math.max(preciseRight(), other.preciseRight()); double newbottom = Math.max(preciseBottom(), other.preciseBottom()); preciseX = Math.min(preciseX, other.preciseX); preciseY = Math.min(preciseY, other.preciseY); preciseWidth = newright - preciseX; preciseHeight = newbottom - preciseY; updateInts(); return this; } /** * @see org.eclipse.draw2d.geometry.Rectangle#union(org.eclipse.draw2d.geometry.Rectangle) */ public Rectangle union(Rectangle other) { double newright = Math.max(preciseRight(), other.preciseX() + other.preciseWidth()); double newbottom = Math.max(preciseBottom(), other.preciseY() + other.preciseHeight()); preciseX = Math.min(preciseX, other.preciseX()); preciseY = Math.min(preciseY, other.preciseY()); preciseWidth = newright - preciseX; preciseHeight = newbottom - preciseY; updateInts(); return this; } /** * Updates the integer values based on the current precise values. The integer values ar * the floor of the double values. This is called automatically when calling api which is * overridden in this class. * @since 3.0 */ public void updateInts() { x = (int)Math.floor(preciseX + 0.000000001); y = (int)Math.floor(preciseY + 0.000000001); width = (int)Math.floor(preciseWidth + preciseX + 0.000000001) - x; height = (int)Math.floor(preciseHeight + preciseY + 0.000000001) - y; } /** * @see org.eclipse.draw2d.geometry.Rectangle#union(org.eclipse.draw2d.geometry.Point) */ public void union(Point p) { if (p.preciseX() < preciseX) { preciseWidth += (preciseX - p.preciseX()); preciseX = p.preciseX(); } else { double right = preciseX + preciseWidth; if (p.preciseX() > right) { preciseWidth = p.preciseX() - preciseX; } } if (p.preciseY() < preciseY) { preciseHeight += (preciseY - p.preciseY()); preciseY = p.preciseY(); } else { double bottom = preciseY + preciseHeight; if (p.preciseY() > bottom) { preciseHeight = p.preciseY() - preciseY; } } updateInts(); } /** * @see org.eclipse.draw2d.geometry.Rectangle#transpose() */ public Rectangle transpose() { double temp = preciseX; preciseX = preciseY; preciseY = temp; temp = preciseWidth; preciseWidth = preciseHeight; preciseHeight = temp; super.transpose(); return this; } /** * @see org.eclipse.draw2d.geometry.Rectangle#setLocation(org.eclipse.draw2d.geometry.Point) */ public Rectangle setLocation(Point loc) { preciseX = loc.preciseX(); preciseY = loc.preciseY(); updateInts(); return this; } /** * Returns the precise geometric centre of the rectangle * * @return <code>PrecisionPoint</code> geometric center of the rectangle * @since 3.4 */ public Point getCenter() { return new PrecisionPoint(preciseX + preciseWidth / 2.0, preciseY + preciseHeight / 2.0); } /** * 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 */ public Rectangle shrink(double h, double v) { preciseX += h; preciseWidth -= (h + h); preciseY += v; preciseHeight -= (v + v); updateInts(); return this; } /** * 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 */ public Rectangle expand(double h, double v) { return shrink(-h, -v); } /** * @see org.eclipse.draw2d.geometry.Rectangle#shrink(int, int) */ public Rectangle shrink(int h, int v) { return shrink((double)h, (double)v); } /** * @see org.eclipse.draw2d.geometry.Rectangle#contains(org.eclipse.draw2d.geometry.Point) */ public boolean contains(Point p) { return preciseX <= p.preciseX() && p.preciseX() <= preciseX + preciseWidth && preciseY <= p.preciseY() && p.preciseY() <= preciseY + preciseHeight; } /** * @see org.eclipse.draw2d.geometry.Rectangle#preciseX() */ public double preciseX() { return preciseX; } /** * @see org.eclipse.draw2d.geometry.Rectangle#preciseY() */ public double preciseY() { return preciseY; } /** * @see org.eclipse.draw2d.geometry.Rectangle#preciseWidth() */ public double preciseWidth() { return preciseWidth; } /** * @see org.eclipse.draw2d.geometry.Rectangle#preciseHeight() */ public double preciseHeight() { return preciseHeight; } /** * @see org.eclipse.draw2d.geometry.Rectangle#setSize(org.eclipse.draw2d.geometry.Dimension) */ public Rectangle setSize(Dimension d) { preciseWidth = d.preciseWidth(); preciseHeight = d.preciseHeight(); return super.setSize(d); } }