/******************************************************************************* * Copyright (c) 2011, 2016 itemis AG 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: * Alexander Nyßen (itemis AG) - initial API and implementation * Matthias Wienand (itemis AG) - contribution for Bugzilla #355997 * *******************************************************************************/ package org.eclipse.gef.geometry.planar; /** * <p> * Abstract superclass of geometries that are defined by means of their upper * left coordinate (x, y) and a given width and height. * </p> * <p> * The type parameter <code>T</code> specifies the type of the inheriting class. * This is to be able to return the correct type, so that a type cast is * unnecessary. * </p> * <p> * The type parameter <code>S</code> specifies the result type of all rotation * short-cut methods. See {@link IRotatable} for more information. * </p> * * @param <T> * specifies the type of the inheriting class in order to avoid * otherwise necessary type casts * @param <S> * specifies the result type of all rotation short-cut methods (see * {@link IRotatable}) * * @author anyssen * @author mwienand * */ abstract class AbstractRectangleBasedGeometry<T extends AbstractRectangleBasedGeometry<?, ?>, S extends IGeometry> extends AbstractGeometry implements ITranslatable<T>, IScalable<T>, IRotatable<S> { private static final long serialVersionUID = 1L; /** * The x-coordinate of this {@link AbstractRectangleBasedGeometry}. */ double x; /** * The y-coordinate of this {@link AbstractRectangleBasedGeometry}. */ double y; /** * The width of this {@link AbstractRectangleBasedGeometry}. */ double width; /** * The height of this {@link AbstractRectangleBasedGeometry}. */ double height; /** * Constructs a new {@link AbstractRectangleBasedGeometry} with the given * position and size. If the width or height is negative, will use * <code>0</code> instead. * * @param x * The x-coordinate of this * {@link AbstractRectangleBasedGeometry} * @param y * The y-coordinate of this * {@link AbstractRectangleBasedGeometry} * @param width * the width of this {@link AbstractRectangleBasedGeometry} * @param height * the height of this {@link AbstractRectangleBasedGeometry} * * @see #setX(double) * @see #setY(double) * @see #setWidth(double) * @see #setHeight(double) */ public AbstractRectangleBasedGeometry(double x, double y, double width, double height) { setX(x); setY(y); setWidth(width); setHeight(height); } /** * Expands the horizontal and vertical sides of this * {@link AbstractRectangleBasedGeometry} with the values provided as input, * and returns <code>this</code> for convenience. The location of its center * is kept constant. * * @param h * the horizontal increment * @param v * the vertical increment * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public T expand(double h, double v) { x -= h; width += h + h; y -= v; height += v + v; return (T) this; } /** * Expands this {@link AbstractRectangleBasedGeometry} by the given amounts, * and returns this for convenience. * * @param left * the amount to expand the left side * @param top * the amount to expand the top side * @param right * the amount to expand the right side * @param bottom * the amount to expand the bottom side * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public T expand(double left, double top, double right, double bottom) { x -= left; y -= top; width += left + right; height += top + bottom; return (T) this; } @Override public Rectangle getBounds() { return new Rectangle(x, y, width, height); } /** * Returns the center {@link Point} of this * {@link AbstractRectangleBasedGeometry}. * * @return the center {@link Point} of this * {@link AbstractRectangleBasedGeometry} */ public Point getCenter() { return new Point(x + width / 2, y + height / 2); } /** * Returns a new expanded {@link AbstractRectangleBasedGeometry}, where the * sides are incremented by the horizontal and vertical values provided. The * center of the {@link AbstractRectangleBasedGeometry} is maintained * constant. * * @param h * The horizontal increment * @param v * The vertical increment * @return a new expanded {@link AbstractRectangleBasedGeometry} */ @SuppressWarnings("unchecked") public T getExpanded(double h, double v) { return (T) ((T) getCopy()).expand(h, v); } /** * Creates and returns a new {@link AbstractRectangleBasedGeometry} with the * bounds of this {@link AbstractRectangleBasedGeometry} expanded by the * given insets. * * @param left * the amount to expand the left side * @param top * the amount to expand the top side * @param right * the amount to expand the right side * @param bottom * the amount to expand the bottom side * * @return a new expanded {@link AbstractRectangleBasedGeometry} */ @SuppressWarnings("unchecked") public T getExpanded(double left, double top, double right, double bottom) { return (T) ((T) getCopy()).expand(left, top, right, bottom); } /** * Returns the height of this {@link AbstractRectangleBasedGeometry}. * * @return the height of this {@link AbstractRectangleBasedGeometry} */ public final double getHeight() { return height; } /** * Returns a {@link Point} specifying the x and y coordinates of this * {@link AbstractRectangleBasedGeometry}. * * @return a {@link Point} representing the x and y coordinates of this * {@link AbstractRectangleBasedGeometry} */ public Point getLocation() { return new Point(x, y); } @Override @SuppressWarnings("unchecked") public T getScaled(double factor) { return (T) ((T) getCopy()).scale(factor); } @Override @SuppressWarnings("unchecked") public T getScaled(double factorX, double factorY) { return (T) ((T) getCopy()).scale(factorX, factorY); } @Override @SuppressWarnings("unchecked") public T getScaled(double factor, double centerX, double centerY) { return (T) ((T) getCopy()).scale(factor, centerX, centerY); } @Override @SuppressWarnings("unchecked") public T getScaled(double factorX, double factorY, double centerX, double centerY) { return (T) ((T) getCopy()).scale(factorX, factorY, centerX, centerY); } @Override @SuppressWarnings("unchecked") public T getScaled(double factorX, double factorY, Point center) { return (T) ((T) getCopy()).scale(factorX, factorY, center); } @Override @SuppressWarnings("unchecked") public T getScaled(double factor, Point center) { return (T) ((T) getCopy()).scale(factor, center); } /** * Returns a new {@link AbstractRectangleBasedGeometry}, where the sides are * shrinked by the horizontal and vertical values supplied. The center of * this {@link AbstractRectangleBasedGeometry} is kept constant. * * @param h * horizontal reduction amount * @param v * vertical reduction amount * @return a new, shrinked {@link AbstractRectangleBasedGeometry} */ @SuppressWarnings("unchecked") public T getShrinked(double h, double v) { return (T) ((T) getCopy()).shrink(h, v); } /** * Returns a new {@link AbstractRectangleBasedGeometry} shrinked by the * specified insets. * * @param left * the amount to shrink the left side * @param top * the amount to shrink the top side * @param right * the amount to shrink the right side * @param bottom * the amount to shrink the bottom side * * @return a new, shrinked {@link AbstractRectangleBasedGeometry} */ @SuppressWarnings("unchecked") public T getShrinked(double left, double top, double right, double bottom) { return (T) ((T) getCopy()).shrink(left, top, right, bottom); } /** * Returns a {@link Dimension} that records the width and height of this * {@link AbstractRectangleBasedGeometry}. * * @return a {@link Dimension} that records the width and height of this * {@link AbstractRectangleBasedGeometry} */ public final Dimension getSize() { return new Dimension(width, height); } @Override @SuppressWarnings("unchecked") public T getTranslated(double dx, double dy) { return (T) ((T) getCopy()).translate(dx, dy); } @Override @SuppressWarnings("unchecked") public T getTranslated(Point pt) { return (T) ((T) getCopy()).translate(pt); } /** * Returns the width of this {@link AbstractRectangleBasedGeometry}. * * @return the width of this {@link AbstractRectangleBasedGeometry} */ public final double getWidth() { return width; } /** * Returns the x coordinate this {@link AbstractRectangleBasedGeometry}. * * @return the x coordinate this {@link AbstractRectangleBasedGeometry} */ public final double getX() { return x; } /** * Returns the y coordinate of this {@link AbstractRectangleBasedGeometry}. * * @return the y coordinate of this {@link AbstractRectangleBasedGeometry} */ public final double getY() { return y; } @Override public T scale(double factor) { return scale(factor, factor); } @Override public T scale(double fx, double fy) { return scale(fx, fy, getCenter()); } @Override public T scale(double factor, double cx, double cy) { return scale(factor, factor, cx, cy); } @Override @SuppressWarnings("unchecked") public T scale(double fx, double fy, double cx, double cy) { x = (x - cx) * fx + cx; y = (y - cy) * fy + cy; width *= fx; height *= fy; return (T) this; } @Override public T scale(double fx, double fy, Point center) { return scale(fx, fy, center.x, center.y); } @Override public T scale(double factor, Point center) { return scale(factor, center.x, center.y); } /** * Sets the x, y, width, and height values of this * {@link AbstractRectangleBasedGeometry} to the given values. * * @param x * the new x-coordinate * @param y * the new y-coordinate * @param w * the new width * @param h * the new height * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setBounds(double x, double y, double w, double h) { this.x = x; this.y = y; this.width = w; this.height = h; return (T) this; } /** * Sets the x, y, width, and height values of this * {@link AbstractRectangleBasedGeometry} to the respective values specified * by the passed-in {@link Point} and the passed-in {@link Dimension}. * * @param loc * the {@link Point} specifying the new x and y coordinates of * this {@link AbstractRectangleBasedGeometry} * @param size * the {@link Dimension} specifying the new width and height of * this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setBounds(Point loc, Dimension size) { setBounds(loc.x, loc.y, size.width, size.height); return (T) this; } /** * Sets the x and y coordinates and the width and height of this * {@link AbstractRectangleBasedGeometry} to the respective values of the * given {@link Rectangle}. * * @param r * the {@link Rectangle} specifying the new x, y, width, and * height values of this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setBounds(Rectangle r) { setBounds(r.x, r.y, r.width, r.height); return (T) this; } /** * Sets the height of this {@link AbstractRectangleBasedGeometry} to the * given value. * * @param height * the new height * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setHeight(double height) { if (height < 0) { height = 0; } this.height = height; return (T) this; } /** * Sets the x and y coordinates of this * {@link AbstractRectangleBasedGeometry} to the specified values. * * @param x * the new x coordinate of this * {@link AbstractRectangleBasedGeometry} * @param y * the new y coordinate of this * {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setLocation(double x, double y) { this.x = x; this.y = y; return (T) this; } /** * Sets the x and y coordinates of this * {@link AbstractRectangleBasedGeometry} to the respective values of the * given {@link Point}. * * @param p * the {@link Point} specifying the new x and y coordinates of * this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setLocation(Point p) { setLocation(p.x, p.y); return (T) this; } /** * Sets the width and height of this {@link AbstractRectangleBasedGeometry} * to the width and height of the given {@link Dimension}. * * @param d * the {@link Dimension} specifying the new width and height of * this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setSize(Dimension d) { setSize(d.width, d.height); return (T) this; } /** * Sets the width and height of this {@link AbstractRectangleBasedGeometry} * to the given values. * * @param w * the new width of this {@link AbstractRectangleBasedGeometry} * @param h * the new height of this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setSize(double w, double h) { if (w < 0) { w = 0; } if (h < 0) { h = 0; } width = w; height = h; return (T) this; } /** * Sets the width of this {@link AbstractRectangleBasedGeometry} to the * passed-in value. * * @param width * the new width of this {@link AbstractRectangleBasedGeometry} * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public final T setWidth(double width) { if (width < 0) { width = 0; } this.width = width; return (T) this; } /** * Sets the x-coordinate of this {@link AbstractRectangleBasedGeometry} to * the given value. * * @param x * The new x-coordinate. * @return <code>this</code> for convenience. */ @SuppressWarnings("unchecked") public final T setX(double x) { this.x = x; return (T) this; } /** * Sets the y-coordinate of this {@link AbstractRectangleBasedGeometry} to * the given value. * * @param y * The new y-coordinate. * @return <code>this</code> for convenience. */ @SuppressWarnings("unchecked") public final T setY(double y) { this.y = y; return (T) this; } /** * Shrinks the sides of this {@link AbstractRectangleBasedGeometry} by the * horizontal and vertical values provided as input, and returns this * {@link AbstractRectangleBasedGeometry} for convenience. The center of * this {@link AbstractRectangleBasedGeometry} is kept constant. * * @param h * horizontal reduction amount * @param v * vertical reduction amount * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public T shrink(double h, double v) { x += h; width -= h + h; y += v; height -= v + v; return (T) this; } /** * Shrinks this {@link AbstractRectangleBasedGeometry} by the specified * amounts. * * @param left * the amount to shrink the left side * @param top * the amount to shrink the top side * @param right * the amount to shrink the right side * @param bottom * the amount to shrink the bottom side * @return <code>this</code> for convenience */ @SuppressWarnings("unchecked") public T shrink(double left, double top, double right, double bottom) { x += left; y += top; width -= (left + right); height -= (top + bottom); return (T) this; } @Override @SuppressWarnings("unchecked") public T translate(double dx, double dy) { x += dx; y += dy; return (T) this; } @Override public T translate(Point p) { return translate(p.x, p.y); } }