| /******************************************************************************* |
| * Copyright (c) 2004, 2006 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.jface.util; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Control; |
| |
| /** |
| * Contains static methods for performing simple geometric operations |
| * on the SWT geometry classes. |
| * |
| * @since 3.0 |
| */ |
| public class Geometry { |
| |
| /** |
| * Prevent this class from being instantiated. |
| * |
| * @since 3.0 |
| */ |
| private Geometry() { |
| //This is not instantiated |
| } |
| |
| /** |
| * Returns the square of the distance between two points. |
| * <p>This is preferred over the real distance when searching |
| * for the closest point, since it avoids square roots.</p> |
| * |
| * @param p1 first endpoint |
| * @param p2 second endpoint |
| * @return the square of the distance between the two points |
| * |
| * @since 3.0 |
| */ |
| public static int distanceSquared(Point p1, Point p2) { |
| int term1 = p1.x - p2.x; |
| int term2 = p1.y - p2.y; |
| return term1 * term1 + term2 * term2; |
| } |
| |
| /** |
| * Returns the magnitude of the given 2d vector (represented as a Point) |
| * |
| * @param p point representing the 2d vector whose magnitude is being computed |
| * @return the magnitude of the given 2d vector |
| * @since 3.0 |
| */ |
| public static double magnitude(Point p) { |
| return Math.sqrt(magnitudeSquared(p)); |
| } |
| |
| /** |
| * Returns the square of the magnitude of the given 2-space vector (represented |
| * using a point) |
| * |
| * @param p the point whose magnitude is being computed |
| * @return the square of the magnitude of the given vector |
| * @since 3.0 |
| */ |
| public static int magnitudeSquared(Point p) { |
| return p.x * p.x + p.y * p.y; |
| } |
| |
| /** |
| * Returns the dot product of the given vectors (expressed as Points) |
| * |
| * @param p1 the first vector |
| * @param p2 the second vector |
| * @return the dot product of the two vectors |
| * @since 3.0 |
| */ |
| public static int dotProduct(Point p1, Point p2) { |
| return p1.x * p2.x + p1.y * p2.y; |
| } |
| |
| /** |
| * Returns a new point whose coordinates are the minimum of the coordinates of the |
| * given points |
| * |
| * @param p1 a Point |
| * @param p2 a Point |
| * @return a new point whose coordinates are the minimum of the coordinates of the |
| * given points |
| * @since 3.0 |
| */ |
| public static Point min(Point p1, Point p2) { |
| return new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y)); |
| } |
| |
| /** |
| * Returns a new point whose coordinates are the maximum of the coordinates |
| * of the given points |
| * @param p1 a Point |
| * @param p2 a Point |
| * @return point a new point whose coordinates are the maximum of the coordinates |
| * @since 3.0 |
| */ |
| public static Point max(Point p1, Point p2) { |
| return new Point(Math.max(p1.x, p2.x), Math.max(p1.y, p2.y)); |
| } |
| |
| /** |
| * Returns a vector in the given direction with the given |
| * magnitude. Directions are given using SWT direction constants, and |
| * the resulting vector is in the screen's coordinate system. That is, |
| * the vector (0, 1) is down and the vector (1, 0) is right. |
| * |
| * @param distance magnitude of the vector |
| * @param direction one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT |
| * @return a point representing a vector in the given direction with the given magnitude |
| * @since 3.0 |
| */ |
| public static Point getDirectionVector(int distance, int direction) { |
| switch (direction) { |
| case SWT.TOP: |
| return new Point(0, -distance); |
| case SWT.BOTTOM: |
| return new Point(0, distance); |
| case SWT.LEFT: |
| return new Point(-distance, 0); |
| case SWT.RIGHT: |
| return new Point(distance, 0); |
| } |
| |
| return new Point(0, 0); |
| } |
| |
| /** |
| * Returns the point in the center of the given rectangle. |
| * |
| * @param rect rectangle being computed |
| * @return a Point at the center of the given rectangle. |
| * @since 3.0 |
| */ |
| public static Point centerPoint(Rectangle rect) { |
| return new Point(rect.x + rect.width / 2, rect.y + rect.height / 2); |
| } |
| |
| /** |
| * Returns a copy of the given point |
| * |
| * @param toCopy point to copy |
| * @return a copy of the given point |
| */ |
| public static Point copy(Point toCopy) { |
| return new Point(toCopy.x, toCopy.y); |
| } |
| |
| /** |
| * Sets result equal to toCopy |
| * |
| * @param result object that will be modified |
| * @param toCopy object that will be copied |
| * @since 3.1 |
| */ |
| public static void set(Point result, Point toCopy) { |
| result.x = toCopy.x; |
| result.y = toCopy.y; |
| } |
| |
| /** |
| * Sets result equal to toCopy |
| * |
| * @param result object that will be modified |
| * @param toCopy object that will be copied |
| * @since 3.1 |
| */ |
| public static void set(Rectangle result, Rectangle toCopy) { |
| result.x = toCopy.x; |
| result.y = toCopy.y; |
| result.width = toCopy.width; |
| result.height = toCopy.height; |
| } |
| |
| /** |
| * Adds two points as 2d vectors. Returns a new point whose coordinates are |
| * the sum of the original two points. |
| * |
| * @param point1 the first point (not null) |
| * @param point2 the second point (not null) |
| * @return a new point whose coordinates are the sum of the given points |
| * @since 3.0 |
| */ |
| public static Point add(Point point1, Point point2) { |
| return new Point(point1.x + point2.x, point1.y + point2.y); |
| } |
| |
| /** |
| * Divides both coordinates of the given point by the given scalar. |
| * |
| * @since 3.1 |
| * |
| * @param toDivide point to divide |
| * @param scalar denominator |
| * @return a new Point whose coordinates are equal to the original point divided by the scalar |
| */ |
| public static Point divide(Point toDivide, int scalar) { |
| return new Point(toDivide.x / scalar, toDivide.y / scalar); |
| } |
| |
| |
| /** |
| * Performs vector subtraction on two points. Returns a new point equal to |
| * (point1 - point2). |
| * |
| * @param point1 initial point |
| * @param point2 vector to subtract |
| * @return the difference (point1 - point2) |
| * @since 3.0 |
| */ |
| public static Point subtract(Point point1, Point point2) { |
| return new Point(point1.x - point2.x, point1.y - point2.y); |
| } |
| |
| /** |
| * Swaps the X and Y coordinates of the given point. |
| * |
| * @param toFlip modifies this point |
| * @since 3.1 |
| */ |
| public static void flipXY(Point toFlip) { |
| int temp = toFlip.x; |
| toFlip.x = toFlip.y; |
| toFlip.y = temp; |
| } |
| |
| /** |
| * Swaps the X and Y coordinates of the given rectangle, along with the height and width. |
| * |
| * @param toFlip modifies this rectangle |
| * @since 3.1 |
| */ |
| public static void flipXY(Rectangle toFlip) { |
| int temp = toFlip.x; |
| toFlip.x = toFlip.y; |
| toFlip.y = temp; |
| |
| temp = toFlip.width; |
| toFlip.width = toFlip.height; |
| toFlip.height = temp; |
| } |
| |
| /** |
| * Returns the height or width of the given rectangle. |
| * |
| * @param toMeasure rectangle to measure |
| * @param width returns the width if true, and the height if false |
| * @return the width or height of the given rectangle |
| * @since 3.0 |
| */ |
| public static int getDimension(Rectangle toMeasure, boolean width) { |
| if (width) { |
| return toMeasure.width; |
| } |
| return toMeasure.height; |
| } |
| |
| /** |
| * Returns the x or y coordinates of the given point. |
| * |
| * @param toMeasure point being measured |
| * @param width if true, returns x. Otherwise, returns y. |
| * @return the x or y coordinate |
| * @since 3.1 |
| */ |
| public static int getCoordinate(Point toMeasure, boolean width) { |
| return width ? toMeasure.x : toMeasure.y; |
| } |
| |
| /** |
| * Returns the x or y coordinates of the given rectangle. |
| * |
| * @param toMeasure rectangle being measured |
| * @param width if true, returns x. Otherwise, returns y. |
| * @return the x or y coordinate |
| * @since 3.1 |
| */ |
| public static int getCoordinate(Rectangle toMeasure, boolean width) { |
| return width ? toMeasure.x : toMeasure.y; |
| } |
| |
| /** |
| * Sets one dimension of the given rectangle. Modifies the given rectangle. |
| * |
| * @param toSet rectangle to modify |
| * @param width if true, the width is modified. If false, the height is modified. |
| * @param newCoordinate new value of the width or height |
| * @since 3.1 |
| */ |
| public static void setDimension(Rectangle toSet, boolean width, int newCoordinate) { |
| if (width) { |
| toSet.width = newCoordinate; |
| } else { |
| toSet.height = newCoordinate; |
| } |
| } |
| |
| /** |
| * Sets one coordinate of the given rectangle. Modifies the given rectangle. |
| * |
| * @param toSet rectangle to modify |
| * @param width if true, the x coordinate is modified. If false, the y coordinate is modified. |
| * @param newCoordinate new value of the x or y coordinates |
| * @since 3.1 |
| */ |
| public static void setCoordinate(Rectangle toSet, boolean width, int newCoordinate) { |
| if (width) { |
| toSet.x = newCoordinate; |
| } else { |
| toSet.y = newCoordinate; |
| } |
| } |
| |
| /** |
| * Sets one coordinate of the given point. Modifies the given point. |
| * |
| * @param toSet point to modify |
| * @param width if true, the x coordinate is modified. If false, the y coordinate is modified. |
| * @param newCoordinate new value of the x or y coordinates |
| * @since 3.1 |
| */ |
| public static void setCoordinate(Point toSet, boolean width, int newCoordinate) { |
| if (width) { |
| toSet.x = newCoordinate; |
| } else { |
| toSet.y = newCoordinate; |
| } |
| } |
| |
| /** |
| * Returns the distance of the given point from a particular side of the given rectangle. |
| * Returns negative values for points outside the rectangle. |
| * |
| * @param rectangle a bounding rectangle |
| * @param testPoint a point to test |
| * @param edgeOfInterest side of the rectangle to test against |
| * @return the distance of the given point from the given edge of the rectangle |
| * @since 3.0 |
| */ |
| public static int getDistanceFromEdge(Rectangle rectangle, Point testPoint, |
| int edgeOfInterest) { |
| switch (edgeOfInterest) { |
| case SWT.TOP: |
| return testPoint.y - rectangle.y; |
| case SWT.BOTTOM: |
| return rectangle.y + rectangle.height - testPoint.y; |
| case SWT.LEFT: |
| return testPoint.x - rectangle.x; |
| case SWT.RIGHT: |
| return rectangle.x + rectangle.width - testPoint.x; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Extrudes the given edge inward by the given distance. That is, if one side of the rectangle |
| * was sliced off with a given thickness, this returns the rectangle that forms the slice. Note |
| * that the returned rectangle will be inside the given rectangle if size > 0. |
| * |
| * @param toExtrude the rectangle to extrude. The resulting rectangle will share three sides |
| * with this rectangle. |
| * @param size distance to extrude. A negative size will extrude outwards (that is, the resulting |
| * rectangle will overlap the original iff this is positive). |
| * @param orientation the side to extrude. One of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM. The |
| * resulting rectangle will always share this side with the original rectangle. |
| * @return a rectangle formed by extruding the given side of the rectangle by the given distance. |
| * @since 3.0 |
| */ |
| public static Rectangle getExtrudedEdge(Rectangle toExtrude, int size, |
| int orientation) { |
| Rectangle bounds = new Rectangle(toExtrude.x, toExtrude.y, |
| toExtrude.width, toExtrude.height); |
| |
| if (!isHorizontal(orientation)) { |
| bounds.width = size; |
| } else { |
| bounds.height = size; |
| } |
| |
| switch (orientation) { |
| case SWT.RIGHT: |
| bounds.x = toExtrude.x + toExtrude.width - bounds.width; |
| break; |
| case SWT.BOTTOM: |
| bounds.y = toExtrude.y + toExtrude.height - bounds.height; |
| break; |
| } |
| |
| normalize(bounds); |
| |
| return bounds; |
| } |
| |
| /** |
| * Returns the opposite of the given direction. That is, returns SWT.LEFT if |
| * given SWT.RIGHT and visa-versa. |
| * |
| * @param swtDirectionConstant one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| * @return one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| * @since 3.0 |
| */ |
| public static int getOppositeSide(int swtDirectionConstant) { |
| switch (swtDirectionConstant) { |
| case SWT.TOP: |
| return SWT.BOTTOM; |
| case SWT.BOTTOM: |
| return SWT.TOP; |
| case SWT.LEFT: |
| return SWT.RIGHT; |
| case SWT.RIGHT: |
| return SWT.LEFT; |
| } |
| |
| return swtDirectionConstant; |
| } |
| |
| /** |
| * Converts the given boolean into an SWT orientation constant. |
| * |
| * @param horizontal if true, returns SWT.HORIZONTAL. If false, returns SWT.VERTICAL |
| * @return SWT.HORIZONTAL or SWT.VERTICAL. |
| * @since 3.0 |
| */ |
| public static int getSwtHorizontalOrVerticalConstant(boolean horizontal) { |
| if (horizontal) { |
| return SWT.HORIZONTAL; |
| } |
| return SWT.VERTICAL; |
| } |
| |
| /** |
| * Returns true iff the given SWT side constant corresponds to a horizontal side |
| * of a rectangle. That is, returns true for the top and bottom but false for the |
| * left and right. |
| * |
| * @param swtSideConstant one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT |
| * @return true iff the given side is horizontal. |
| * @since 3.0 |
| */ |
| public static boolean isHorizontal(int swtSideConstant) { |
| return !(swtSideConstant == SWT.LEFT || swtSideConstant == SWT.RIGHT); |
| } |
| |
| /** |
| * Moves the given rectangle by the given delta. |
| * |
| * @param rect rectangle to move (will be modified) |
| * @param delta direction vector to move the rectangle by |
| * @since 3.0 |
| */ |
| public static void moveRectangle(Rectangle rect, Point delta) { |
| rect.x += delta.x; |
| rect.y += delta.y; |
| } |
| |
| /** |
| * Moves each edge of the given rectangle outward by the given amount. Negative values |
| * cause the rectangle to contract. Does not allow the rectangle's width or height to be |
| * reduced below zero. |
| * |
| * @param rect normalized rectangle to modify |
| * @param left distance to move the left edge outward (negative values move the edge inward) |
| * @param right distance to move the right edge outward (negative values move the edge inward) |
| * @param top distance to move the top edge outward (negative values move the edge inward) |
| * @param bottom distance to move the bottom edge outward (negative values move the edge inward) |
| * @since 3.1 |
| */ |
| public static void expand(Rectangle rect, int left, int right, int top, int bottom) { |
| rect.x -= left; |
| rect.width = Math.max(0, rect.width + left + right); |
| rect.y -= top; |
| rect.height = Math.max(0, rect.height + top + bottom); |
| } |
| |
| /** |
| * Normalizes the given rectangle. That is, any rectangle with |
| * negative width or height becomes a rectangle with positive |
| * width or height that extends to the upper-left of the original |
| * rectangle. |
| * |
| * @param rect rectangle to modify |
| * @since 3.0 |
| */ |
| public static void normalize(Rectangle rect) { |
| if (rect.width < 0) { |
| rect.width = -rect.width; |
| rect.x -= rect.width; |
| } |
| |
| if (rect.height < 0) { |
| rect.height = -rect.height; |
| rect.y -= rect.height; |
| } |
| } |
| |
| /** |
| * Converts the given rectangle from display coordinates to the local coordinate system |
| * of the given object into display coordinates. |
| * |
| * @param coordinateSystem local coordinate system being converted to |
| * @param toConvert rectangle to convert |
| * @return a rectangle in control coordinates |
| * @since 3.0 |
| */ |
| public static Rectangle toControl(Control coordinateSystem, |
| Rectangle toConvert) { |
| return(coordinateSystem.getDisplay().map |
| (null,coordinateSystem,toConvert)); |
| } |
| |
| /** |
| * Converts the given rectangle from the local coordinate system of the given object |
| * into display coordinates. |
| * |
| * @param coordinateSystem local coordinate system being converted from |
| * @param toConvert rectangle to convert |
| * @return a rectangle in display coordinates |
| * @since 3.0 |
| */ |
| public static Rectangle toDisplay(Control coordinateSystem, |
| Rectangle toConvert) { |
| return(coordinateSystem.getDisplay().map |
| (coordinateSystem,null,toConvert)); |
| |
| } |
| |
| /** |
| * Determines where the given point lies with respect to the given rectangle. |
| * Returns a combination of SWT.LEFT, SWT.RIGHT, SWT.TOP, and SWT.BOTTOM, combined |
| * with bitwise or (for example, returns SWT.TOP | SWT.LEFT if the point is to the |
| * upper-left of the rectangle). Returns 0 if the point lies within the rectangle. |
| * Positions are in screen coordinates (ie: a point is to the upper-left of the |
| * rectangle if its x and y coordinates are smaller than any point in the rectangle) |
| * |
| * @param boundary normalized boundary rectangle |
| * @param toTest point whose relative position to the rectangle is being computed |
| * @return one of SWT.LEFT | SWT.TOP, SWT.TOP, SWT.RIGHT | SWT.TOP, SWT.LEFT, 0, |
| * SWT.RIGHT, SWT.LEFT | SWT.BOTTOM, SWT.BOTTOM, SWT.RIGHT | SWT.BOTTOM |
| * @since 3.0 |
| */ |
| public static int getRelativePosition(Rectangle boundary, Point toTest) { |
| int result = 0; |
| |
| if (toTest.x < boundary.x) { |
| result |= SWT.LEFT; |
| } else if (toTest.x >= boundary.x + boundary.width) { |
| result |= SWT.RIGHT; |
| } |
| |
| if (toTest.y < boundary.y) { |
| result |= SWT.TOP; |
| } else if (toTest.y >= boundary.y + boundary.height) { |
| result |= SWT.BOTTOM; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns the distance from the point to the nearest edge of the given |
| * rectangle. Returns negative values if the point lies outside the rectangle. |
| * |
| * @param boundary rectangle to test |
| * @param toTest point to test |
| * @return the distance between the given point and the nearest edge of the rectangle. |
| * Returns positive values for points inside the rectangle and negative values for points |
| * outside the rectangle. |
| * @since 3.1 |
| */ |
| public static int getDistanceFrom(Rectangle boundary, Point toTest) { |
| int side = getClosestSide(boundary, toTest); |
| return getDistanceFromEdge(boundary, toTest, side); |
| } |
| |
| /** |
| * Returns the edge of the given rectangle is closest to the given |
| * point. |
| * |
| * @param boundary rectangle to test |
| * @param toTest point to compare |
| * @return one of SWT.LEFT, SWT.RIGHT, SWT.TOP, or SWT.BOTTOM |
| * |
| * @since 3.0 |
| */ |
| public static int getClosestSide(Rectangle boundary, Point toTest) { |
| int[] sides = new int[] { SWT.LEFT, SWT.RIGHT, SWT.TOP, SWT.BOTTOM }; |
| |
| int closestSide = SWT.LEFT; |
| int closestDistance = Integer.MAX_VALUE; |
| |
| for (int idx = 0; idx < sides.length; idx++) { |
| int side = sides[idx]; |
| |
| int distance = getDistanceFromEdge(boundary, toTest, side); |
| |
| if (distance < closestDistance) { |
| closestDistance = distance; |
| closestSide = side; |
| } |
| } |
| |
| return closestSide; |
| } |
| |
| /** |
| * Returns a copy of the given rectangle |
| * |
| * @param toCopy rectangle to copy |
| * @return a copy of the given rectangle |
| * @since 3.0 |
| */ |
| public static Rectangle copy(Rectangle toCopy) { |
| return new Rectangle(toCopy.x, toCopy.y, toCopy.width, toCopy.height); |
| } |
| |
| /** |
| * Returns the size of the rectangle, as a Point |
| * |
| * @param rectangle rectangle whose size is being computed |
| * @return the size of the given rectangle |
| * @since 3.0 |
| */ |
| public static Point getSize(Rectangle rectangle) { |
| return new Point(rectangle.width, rectangle.height); |
| } |
| |
| /** |
| * Sets the size of the given rectangle to the given size |
| * |
| * @param rectangle rectangle to modify |
| * @param newSize new size of the rectangle |
| * @since 3.0 |
| */ |
| public static void setSize(Rectangle rectangle, Point newSize) { |
| rectangle.width = newSize.x; |
| rectangle.height = newSize.y; |
| } |
| |
| /** |
| * Sets the x,y position of the given rectangle. For a normalized |
| * rectangle (a rectangle with positive width and height), this will |
| * be the upper-left corner of the rectangle. |
| * |
| * @param rectangle rectangle to modify |
| * @param newSize new size of the rectangle |
| * |
| * @since 3.0 |
| */ |
| public static void setLocation(Rectangle rectangle, Point newSize) { |
| rectangle.width = newSize.x; |
| rectangle.height = newSize.y; |
| } |
| |
| /** |
| * Returns the x,y position of the given rectangle. For normalized rectangles |
| * (rectangles with positive width and height), this is the upper-left |
| * corner of the rectangle. |
| * |
| * @param toQuery rectangle to query |
| * @return a Point containing the x,y position of the rectangle |
| * |
| * @since 3.0 |
| */ |
| public static Point getLocation(Rectangle toQuery) { |
| return new Point(toQuery.x, toQuery.y); |
| } |
| |
| /** |
| * Returns a new rectangle with the given position and dimensions, expressed |
| * as points. |
| * |
| * @param position the (x,y) position of the rectangle |
| * @param size the size of the new rectangle, where (x,y) -> (width, height) |
| * @return a new Rectangle with the given position and size |
| * |
| * @since 3.0 |
| */ |
| public static Rectangle createRectangle(Point position, Point size) { |
| return new Rectangle(position.x, position.y, size.x, size.y); |
| } |
| |
| /** |
| * Repositions the 'inner' rectangle to lie completely within the bounds of the 'outer' |
| * rectangle if possible. One use for this is to ensure that, when setting a control's bounds, |
| * that they will always lie within its parent's client area (to avoid clipping). |
| * |
| * @param inner The 'inner' rectangle to be repositioned (should be smaller than the 'outer' rectangle) |
| * @param outer The 'outer' rectangle |
| */ |
| public static void moveInside(Rectangle inner, Rectangle outer) { |
| // adjust X |
| if (inner.x < outer.x) { |
| inner.x = outer.x; |
| } |
| if ((inner.x + inner.width) > (outer.x + outer.width)) { |
| inner.x -= (inner.x + inner.width) - (outer.x + outer.width); |
| } |
| |
| // Adjust Y |
| if (inner.y < outer.y) { |
| inner.y = outer.y; |
| } |
| if ((inner.y + inner.height) > (outer.y + outer.height)) { |
| inner.y -= (inner.y + inner.height) - (outer.y + outer.height); |
| } |
| } |
| |
| } |