### Eclipse Workspace Patch 1.0
#P org.eclipse.gef4.geometry
Index: src/org/eclipse/gef4/geometry/Angle.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/Angle.java
diff -N src/org/eclipse/gef4/geometry/Angle.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/Angle.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry;
+
+import java.io.Serializable;
+
+import org.eclipse.gef4.geometry.utils.PrecisionUtils;
+
+/**
+ * An {@link Angle} object abstracts the angle's unit. It provides a simple
+ * interface to construct it from degrees or from radians. Additionally, some
+ * useful calculations are implemented, but for sine/cosine/tangent calculations
+ * you may use the Math package.
+ *
+ * The {@link AngleUnit} enumeration is used to differentiate between degrees
+ * and radians. For the sake of simplicity, the methods that need to
+ * differentiate between the angle's unit are available twice. Expecting degrees
+ * or radians.
+ *
+ * Every {@link Angle} object is normalized. That means, you will never
+ * encounter an {@link Angle} object beyond 360°/2pi or below 0°/0.
+ *
+ * @author Matthias Wienand
+ */
+public class Angle implements Cloneable, Serializable {
+
+ /**
+ * The {@link Angle#Angle(double, AngleUnit)} constructor uses this
+ * enumeration to differentiate the unit of its first argument.
+ *
+ * @author wienand
+ */
+ public enum AngleUnit {
+ /**
+ * Specifies that the angle is given in degrees. The range of an angle
+ * in degrees is from 0° to 360°.
+ */
+ DEG,
+
+ /**
+ * Specifies that the angle is given in radians. The range of an angle
+ * in radians is from 0 to 2pi.
+ */
+ RAD,
+ }
+
+ private static final long serialVersionUID = 1L;
+ private static final double DEG_TO_RAD = Math.PI / 180d;
+ private static final double RAD_TO_DEG = 180d / Math.PI;
+ private static final double RAD_180 = Math.PI;
+ private static final double RAD_360 = 2 * Math.PI;
+
+ /**
+ * Constructs a new {@link Angle} object representing the given value. The
+ * value is interpreted as being in degrees.
+ *
+ * @param degrees
+ * The angle in degrees.
+ * @return An {@link Angle} object representing the given degrees-angle.
+ */
+ public static Angle fromDeg(double degrees) {
+ return new Angle(degrees, AngleUnit.DEG);
+ }
+
+ /**
+ * Constructs a new {@link Angle} object representing the given value. The
+ * value is interpreted as being in radians.
+ *
+ * @param radians
+ * The angle in radians.
+ * @return An {@link Angle} object representing the given radians-angle.
+ */
+ public static Angle fromRad(double radians) {
+ return new Angle(radians, AngleUnit.RAD);
+ }
+
+ private double rad = 0d;
+
+ /**
+ * Constructs a new {@link Angle} object with the given value. The
+ * {@link AngleUnit} u is used to differentiate the value's unit.
+ *
+ * @param v
+ * The angle's value.
+ * @param u
+ * The angle's unit.
+ */
+ public Angle(double v, AngleUnit u) {
+ if (u == AngleUnit.DEG) {
+ v *= DEG_TO_RAD;
+ }
+ setRad(v);
+ }
+
+ /**
+ * Overwritten with public visibility as proposed in {@link Cloneable}.
+ */
+ @Override
+ public Angle clone() {
+ return getCopy();
+ }
+
+ /**
+ * Returns the value of this {@link Angle} object in degrees.
+ *
+ * @return This {@link Angle}'s value in degrees.
+ */
+ public double deg() {
+ return rad * RAD_TO_DEG;
+ }
+
+ @Override
+ public boolean equals(Object otherObj) {
+ Angle other = (Angle) otherObj;
+ return PrecisionUtils.equal(other.rad, this.rad);
+ }
+
+ /**
+ * Returns the sum of this and the given other {@link Angle} object as a new
+ * {@link Angle} object.
+ *
+ * @param other
+ * @return The sum of this and the given other {@link Angle} object as a new
+ * {@link Angle} object.
+ */
+ public Angle getAdded(Angle other) {
+ return Angle.fromRad(this.rad + other.rad);
+ }
+
+ /**
+ * Creates and returns a copy of this {@link Angle}.
+ *
+ * @return a copy of this {@link Angle}
+ */
+ public Angle getCopy() {
+ return Angle.fromRad(this.rad);
+ }
+
+ /**
+ * Returns the opposite {@link Angle} of this {@link Angle} in a full circle
+ * as a new {@link Angle} object.
+ *
+ * @return The opposite {@link Angle} of this {@link Angle} in a full circle
+ * as a new {@link Angle} object.
+ */
+ public Angle getOppositeFull() {
+ return Angle.fromRad(RAD_360 - rad);
+ }
+
+ /**
+ * Returns the opposite {@link Angle} of this {@link Angle} in a semi-circle
+ * as a new {@link Angle} object.
+ *
+ * @return The opposite {@link Angle} of this {@link Angle} in a semi-circle
+ * as a new {@link Angle} object.
+ */
+ public Angle getOppositeSemi() {
+ return Angle.fromRad(RAD_180 - rad);
+ }
+
+ private Angle normalize() {
+ rad -= RAD_360 * Math.floor(rad / RAD_360);
+ return this;
+ }
+
+ /**
+ * Returns this {@link Angle}'s value in radians.
+ *
+ * @return This {@link Angle}'s value in radians.
+ */
+ public double rad() {
+ return rad;
+ }
+
+ /**
+ * Sets this {@link Angle}'s value to the given angle in degrees.
+ *
+ * @param degrees
+ * The angle in degrees.
+ */
+ public void setDeg(double degrees) {
+ rad = degrees * DEG_TO_RAD;
+ normalize();
+ }
+
+ /**
+ * Sets this {@link Angle}'s value to the given angle in radians.
+ *
+ * @param radians
+ * The angle value in radians.
+ */
+ public void setRad(double radians) {
+ rad = radians;
+ normalize();
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ @Override
+ public String toString() {
+ return super.toString() + ": " + Double.toString(rad) + "rad ("
+ + Double.toString(deg()) + "deg)";
+ }
+}
Index: src/org/eclipse/gef4/geometry/Dimension.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/Dimension.java,v
retrieving revision 1.3
diff -u -r1.3 Dimension.java
--- src/org/eclipse/gef4/geometry/Dimension.java 20 Oct 2011 21:01:58 -0000 1.3
+++ src/org/eclipse/gef4/geometry/Dimension.java 21 Oct 2011 12:49:29 -0000
@@ -177,6 +177,7 @@
* the Object being tested for equality
* @return true
if the given object is equal to this dimension
*/
+ @Override
public boolean equals(Object o) {
if (o instanceof Dimension) {
Dimension d = (Dimension) o;
@@ -212,7 +213,7 @@
}
/**
- * Creates and returns a copy of this Dimension.
+ * Creates and returns a copy of this {@link Dimension}.
*
* @return a copy of this Dimension
*/
@@ -221,8 +222,8 @@
}
/**
- * Creates and returns a Dimension representing the sum of this Dimension
- * and the one specified.
+ * 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
@@ -234,7 +235,7 @@
/**
* Creates and returns a new Dimension representing the sum of this
- * Dimension and the one specified.
+ * {@link Dimension} and the one specified.
*
* @param w
* value by which the width of this is to be expanded
@@ -331,6 +332,7 @@
/**
* @see java.lang.Object#hashCode()
*/
+ @Override
public int hashCode() {
return (int) (width * height) ^ (int) (width + height);
}
@@ -489,7 +491,7 @@
/**
* @see Object#toString()
*/
-
+ @Override
public String toString() {
return "Dimension(" + //$NON-NLS-1$
width + ", " + //$NON-NLS-1$
Index: src/org/eclipse/gef4/geometry/Point.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/Point.java,v
retrieving revision 1.2
diff -u -r1.2 Point.java
--- src/org/eclipse/gef4/geometry/Point.java 20 Oct 2011 21:01:58 -0000 1.2
+++ src/org/eclipse/gef4/geometry/Point.java 21 Oct 2011 12:49:29 -0000
@@ -153,6 +153,7 @@
* Object being tested for equality
* @return true if both x and y values are equal
*/
+ @Override
public boolean equals(Object o) {
if (o instanceof Point) {
Point p = (Point) o;
@@ -261,6 +262,7 @@
/**
* @see java.lang.Object#hashCode()
*/
+ @Override
public int hashCode() {
return (int) (x * y) ^ (int) (x + y);
}
@@ -354,8 +356,9 @@
}
/**
- * @return String representation.
+ * @see Object#toString()
*/
+ @Override
public String toString() {
return "Point(" + x + ", " + y + ")";//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
}
Index: src/org/eclipse/gef4/geometry/euclidean/Straight.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/euclidean/Straight.java,v
retrieving revision 1.3
diff -u -r1.3 Straight.java
--- src/org/eclipse/gef4/geometry/euclidean/Straight.java 20 Oct 2011 21:01:22 -0000 1.3
+++ src/org/eclipse/gef4/geometry/euclidean/Straight.java 21 Oct 2011 12:49:29 -0000
@@ -12,6 +12,9 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.euclidean;
+import java.io.Serializable;
+
+import org.eclipse.gef4.geometry.Angle;
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
@@ -20,7 +23,9 @@
*
* @author anyssen
*/
-public class Straight {
+public class Straight implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 1L;
/** position vector of this straight */
public Vector position;
@@ -39,8 +44,8 @@
throw new IllegalArgumentException(
"direction has to be unequal to (0,0)"); //$NON-NLS-1$
}
- this.position = position;
- this.direction = direction;
+ this.position = position.clone();
+ this.direction = direction.clone();
}
/**
@@ -55,9 +60,14 @@
this(new Vector(point1), new Vector(point1, point2));
}
+ @Override
+ public Straight clone() {
+ return new Straight(position, direction);
+ }
+
/**
- * Checks whether this Straight and the provided one have a single
- * intersection point.
+ * Checks whether this Straight and the provided one have a single point of
+ * intersection.
*
* @param other
* The Straight to use for the calculation.
@@ -111,6 +121,55 @@
}
/**
+ * Converts a given {@link Vector} into a 3-dimensional vector in
+ * homogeneous coordinates represented as an array.
+ *
+ * @param v
+ * the {@link Vector} to convert
+ * @return an array representation of the 3-dimensional homogeneous vector
+ */
+ private double[] toHomogeneousVector(Vector v) {
+ return new double[] { v.x, v.y, 1 };
+ }
+
+ /**
+ * Projects the given 3-dimensional homogeneous-coordinate vector,
+ * represented as an array, into the 2D space.
+ *
+ * @param v
+ * the array representation of a 3-dimensional
+ * homogeneous-coordinate vector to project
+ * @return the projected {@link Vector}
+ */
+ private Vector fromHomogeneousVector(double[] v) {
+ if (v[2] == 0) {
+ return null;
+ }
+ return new Vector(v[0] / v[2], v[1] / v[2]);
+ }
+
+ /**
+ * Calculates the cross product of two 3-dimensional vectors.
+ *
+ * Used in calculations based on 2D homogeneous coordinates.
+ *
+ * @param a
+ * an array representation of the first 3-dimensional input
+ * vector
+ * @param b
+ * an array representation of the second 3-deminsional input
+ * vector
+ * @return an array representation of the 3-dimensional cross product
+ */
+ private double[] getCrossProduct(double[] a, double[] b) {
+ double[] r = new double[3];
+ r[0] = a[1] * b[2] - a[2] * b[1];
+ r[1] = a[2] * b[0] - a[0] * b[2];
+ r[2] = a[0] * b[1] - a[1] * b[0];
+ return r;
+ }
+
+ /**
* Computes the intersection point of this Straight and the provided one, if
* it exists.
*
@@ -120,18 +179,16 @@
* if no intersection point exists (or the Straights are equal).
*/
public Vector getIntersection(Straight other) {
- // first check if there is a single intersection point
- if (!intersects(other)) {
- return null;
- }
- // calculate intersection point
- Vector s1 = direction.getMultiplied(other.position
- .getDotProduct(other.direction.getOrthogonalComplement()));
- Vector s2 = other.direction.getMultiplied(position
- .getDotProduct(direction.getOrthogonalComplement()));
- return s1.getSubtracted(s2).getDivided(
- direction.getDotProduct(other.direction
- .getOrthogonalComplement()));
+ // method using homogeneous coordinates
+ double[] p11 = toHomogeneousVector(position);
+ double[] p12 = toHomogeneousVector(position.getAdded(direction));
+ double[] p21 = toHomogeneousVector(other.position);
+ double[] p22 = toHomogeneousVector(other.position
+ .getAdded(other.direction));
+ double[] l1 = getCrossProduct(p11, p12);
+ double[] l2 = getCrossProduct(p21, p22);
+ double[] poi = getCrossProduct(l1, l2);
+ return fromHomogeneousVector(poi);
}
/**
@@ -139,25 +196,62 @@
*
* @param other
* The Straight to be used for the calculation.
- * @return The angle spanned between the two Straights.
+ * @return The angle spanned between the two {@link Straight}s.
*/
- public double getAngle(Straight other) {
+ public Angle getAngle(Straight other) {
return direction.getAngle(other.direction);
}
/**
- * Returns the projection of the given Vector onto this Straight, which is
- * the point on this Straight with the minimal distance to the point,
- * denoted by the provided Vector.
+ * Returns the clock-wise (CW) or negative angle spanned between the two
+ * {@link Straight}s.
+ *
+ * The returned angle is the opposite of the angle returned by the
+ * getAngleCCW(Straight other) method.
+ *
+ * @param other
+ * @return The clock-wise (CW) or negative angle spanned between the two
+ * {@link Straight}s.
+ */
+ public Angle getAngleCW(Straight other) {
+ return getAngleCCW(other).getOppositeSemi();
+ }
+
+ /**
+ * Returns the counter-clock-wise (CCW) or positive {@link Angle} spanned
+ * between the two {@link Straight}s.
+ *
+ * The returned {@link Angle} is the opposite of the {@link Angle} returned
+ * by the getAngleCCW(Straight other) method.
+ *
+ * @param other
+ * @return The counter-clock-wise (CCW) or positive angle spanned between
+ * the two {@link Straight}s.
+ */
+ public Angle getAngleCCW(Straight other) {
+ Angle angle = getAngle(other);
+ if (direction.getCrossProduct(other.direction) > 0) {
+ angle = angle.getOppositeSemi();
+ }
+ return angle;
+ }
+
+ /**
+ * Returns the projection of the given {@link Vector} onto this
+ * {@link Straight}, which is the point on this {@link Straight} with the
+ * minimal distance to the point, denoted by the provided {@link Vector}.
*
* @param vector
- * The Vector whose projection should be determined.
- * @return A new Vector representing the projection of the provided Vector
- * onto this Straight.
+ * The {@link Vector} whose projection should be determined.
+ * @return A new {@link Vector} representing the projection of the provided
+ * {@link Vector} onto this {@link Straight}.
*/
public Vector getProjection(Vector vector) {
- return getIntersection(new Straight(vector,
- direction.getOrthogonalComplement()));
+ // calculate with a normalized direction vector to prevent rounding
+ // effects
+ Vector normalized = direction.getNormalized();
+ return new Straight(position, normalized).getIntersection(new Straight(
+ vector, normalized.getOrthogonalComplement()));
}
/**
@@ -174,6 +268,88 @@
}
/**
+ * Returns the signed distance of the given {@link Vector} to this
+ * {@link Straight}.
+ *
+ * The signed distance indicates on which side of the {@link Straight} the
+ * {@link Vector} lies. If it lies on the right side of this
+ * {@link Straight}'s direction {@link Vector}, the signed distance is
+ * negative. If it is on the left side of this {@link Straight}'s direction
+ * Vector, the signed distance is positive.
+ *
+ * @param vector
+ * @return the signed distance of the given {@link Vector} to this Straight
+ */
+ public double getSignedDistanceCCW(Vector vector) {
+ Vector projected = getProjection(vector);
+ Vector d = vector.getSubtracted(projected);
+
+ double len = d.getLength();
+
+ if (!d.isNull()) {
+ Angle angleCCW = direction.getAngleCW(d);
+
+ if (angleCCW.equals(Angle.fromDeg(90))) {
+ len = -len;
+ }
+ }
+
+ return len;
+ }
+
+ /**
+ * Returns the signed distance of the given {@link Vector} to this Straight.
+ *
+ * The signed distance indicates on which side of the Straight the Vector
+ * lies. If it is on the right side of this Straight's direction Vector, the
+ * signed distance is negative. If it is on the left side of this Straight's
+ * direction Vector, the signed distance is positive.
+ *
+ * @param vector
+ * @return the signed distance of the given {@link Vector} to this Straight
+ */
+ public double getSignedDistanceCW(Vector vector) {
+ return -getSignedDistanceCCW(vector);
+ }
+
+ /**
+ * Returns this {@link Straight}'s parameter value for the given
+ * {@link Point} p.
+ *
+ * This method is the reverse of the getPointAt(double parameter) method.
+ *
+ * @param p
+ * @return this {@link Straight}'s parameter value for the given
+ * {@link Point} p
+ */
+ public double getParameterAt(Point p) {
+ if (direction.x != 0) {
+ return (p.x - position.x) / direction.x;
+ }
+ if (direction.y != 0) {
+ return (p.y - position.y) / direction.y;
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the {@link Point} on this {@link Straight} at parameter p. The
+ * {@link Point} that you get is calculated by multiplying this
+ * {@link Straight}'s direction {@link Vector} by the parameter value and
+ * translating that {@link Vector} by this {@link Straight}'s position
+ * {@link Vector}.
+ *
+ * This method is the reverse of the getPointAt(double parameter) method.
+ *
+ * @param parameter
+ * @return the {@link Point} on this {@link Straight} at parameter p
+ */
+ public Point getPointAt(double parameter) {
+ return new Point(position.x + direction.x * parameter, position.y
+ + direction.y * parameter);
+ }
+
+ /**
* Calculates whether the point indicated by the provided Vector is a point
* on this Straight.
*
Index: src/org/eclipse/gef4/geometry/euclidean/Vector.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/euclidean/Vector.java,v
retrieving revision 1.4
diff -u -r1.4 Vector.java
--- src/org/eclipse/gef4/geometry/euclidean/Vector.java 20 Oct 2011 21:01:23 -0000 1.4
+++ src/org/eclipse/gef4/geometry/euclidean/Vector.java 21 Oct 2011 12:49:29 -0000
@@ -12,6 +12,9 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.euclidean;
+import java.io.Serializable;
+
+import org.eclipse.gef4.geometry.Angle;
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
@@ -24,7 +27,9 @@
* @author ahunter
* @author anyssen
*/
-public class Vector {
+public class Vector implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 1L;
/** the X value */
public double x;
@@ -87,6 +92,14 @@
}
/**
+ * Clones the given Vector object.
+ */
+ @Override
+ public Vector clone() {
+ return new Vector(x, y);
+ }
+
+ /**
* Calculates the magnitude of the cross product of this Vector with
* another. Represents the amount by which two Vectors are directionally
* different. Parallel Vectors return a value of 0.
@@ -158,17 +171,45 @@
}
/**
- * Returns the angle (in degrees) between this Vector and the provided
- * Vector.
+ * Returns the smallest {@link Angle} between this {@link Vector} and the
+ * provided {@link Vector}.
*
* @param other
- * Vector to calculate the angle.
- * @return the angle between the two Vectors in degrees.
+ * {@link Vector} to calculate the {@link Angle}.
+ * @return the smallest {@link Angle} between the two Vectors.
*/
- public double getAngle(Vector other) {
+ public Angle getAngle(Vector other) {
double cosAlpha = getDotProduct(other)
/ (getLength() * other.getLength());
- return Math.toDegrees(Math.acos(cosAlpha));
+ return Angle.fromRad(Math.acos(cosAlpha));
+ }
+
+ /**
+ * Returns the clock-wise (mathematical negative) {@link Angle} between this
+ * {@link Vector} and the provided {@link Vector}.
+ *
+ * @param other
+ * {@link Vector} to calculate the {@link Angle}.
+ * @return the clock-wise {@link Angle} between the two Vectors.
+ */
+ public Angle getAngleCW(Vector other) {
+ return getAngleCCW(other).getOppositeFull();
+ }
+
+ /**
+ * Returns the counter-clock-wise (mathematical positive) {@link Angle}
+ * between this {@link Vector} and the provided {@link Vector}.
+ *
+ * @param other
+ * {@link Vector} to calculate the {@link Angle}.
+ * @return the counter-clock-wise {@link Angle} between the two Vectors.
+ */
+ public Angle getAngleCCW(Vector other) {
+ Angle angle = getAngle(other);
+ if (getCrossProduct(other) > 0) {
+ return angle.getOppositeFull();
+ }
+ return angle;
}
/**
@@ -218,6 +259,30 @@
}
/**
+ * Returns a fresh rotated Vector object. The rotation is clock-wise (CW) by
+ * the given angle.
+ *
+ * @param angle
+ * the rotation angle
+ * @return the new rotated Vector
+ */
+ public Vector getRotatedCW(Angle angle) {
+ return clone().rotateCW(angle);
+ }
+
+ /**
+ * Returns a fresh rotated Vector object. The rotation is counter-clock-wise
+ * (CCW) by the given angle.
+ *
+ * @param angle
+ * the rotation angle
+ * @return the new rotated Vector
+ */
+ public Vector getRotatedCCW(Angle angle) {
+ return clone().rotateCCW(angle);
+ }
+
+ /**
* Returns the length of this Vector.
*
* @return Length of this Vector
@@ -320,4 +385,42 @@
return (int) x + (int) y;
}
+ /**
+ * Rotates this {@link Vector} counter-clock-wise by the given {@link Angle}
+ * .
+ *
+ * @param angle
+ * The rotation {@link Angle}.
+ * @return This (rotated) {@link Vector} object.
+ */
+ public Vector rotateCCW(Angle angle) {
+ return rotateCW(angle.getOppositeFull());
+ }
+
+ /**
+ * Rotates this {@link Vector} clock-wise by the given {@link Angle}.
+ *
+ * @param angle
+ * The rotation {@link Angle}.
+ * @return This (rotated) {@link Vector} object.
+ */
+ public Vector rotateCW(Angle angle) {
+ double alpha = angle.rad();
+ double nx = x * Math.cos(alpha) - y * Math.sin(alpha);
+ double ny = x * Math.sin(alpha) + y * Math.cos(alpha);
+ x = nx;
+ y = ny;
+ return this;
+ }
+
+ /**
+ * Creates a new normalized {@link Vector} that has the same direction as
+ * this {@link Vector} but a length of 1.
+ *
+ * @return The normalized {@link Vector}.
+ */
+ public Vector getNormalized() {
+ return clone().getMultiplied(1 / getLength());
+ }
+
}
Index: src/org/eclipse/gef4/geometry/shapes/CubicCurve.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/CubicCurve.java,v
retrieving revision 1.3
diff -u -r1.3 CubicCurve.java
--- src/org/eclipse/gef4/geometry/shapes/CubicCurve.java 20 Oct 2011 21:04:44 -0000 1.3
+++ src/org/eclipse/gef4/geometry/shapes/CubicCurve.java 21 Oct 2011 12:49:29 -0000
@@ -11,8 +11,14 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.shapes;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.HashSet;
+
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.transform.AffineTransform;
+import org.eclipse.gef4.geometry.utils.PolynomCalculations;
+import org.eclipse.gef4.geometry.utils.PrecisionUtils;
/**
* Represents the geometric shape of a cubic Bézier curve.
@@ -20,12 +26,33 @@
* @author anyssen
*
*/
-public class CubicCurve implements Geometry {
+public class CubicCurve implements Geometry, Serializable {
private static final long serialVersionUID = 1L;
private double x1, y1, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, x2, y2;
+ /**
+ * Constructs a new {@link CubicCurve} object with the given control point
+ * coordinates.
+ *
+ * @param x1
+ * x-coordinate of the start point
+ * @param y1
+ * y-coordinate of the start point
+ * @param ctrl1X
+ * x-coordinate of the first control point
+ * @param ctrl1Y
+ * y-coordinate of the first control point
+ * @param ctrl2X
+ * x-coordinate of the second control point
+ * @param ctrl2Y
+ * y-coordinate of the second control point
+ * @param x2
+ * x-coordinate of the end point
+ * @param y2
+ * y-coordinate of the end point
+ */
public CubicCurve(double x1, double y1, double ctrl1X, double ctrl1Y,
double ctrl2X, double ctrl2Y, double x2, double y2) {
this.x1 = x1;
@@ -38,6 +65,19 @@
this.y2 = y2;
}
+ /**
+ * Constructs a new {@link CubicCurve} object with the given control
+ * {@link Point}s.
+ *
+ * @param start
+ * the start point
+ * @param ctrl1
+ * the first control point
+ * @param ctrl2
+ * the second control point
+ * @param end
+ * the end point
+ */
public CubicCurve(Point start, Point ctrl1, Point ctrl2, Point end) {
this.x1 = start.x;
this.y1 = start.y;
@@ -49,138 +89,522 @@
this.y2 = end.y;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.gef4.geometry.shapes.Geometry#contains(org.eclipse.gef4.geometry
- * .Point)
+ /**
+ * @see Geometry#contains(Point)
*/
public boolean contains(Point p) {
- // TODO Auto-generated method stub
+ // find roots of the x(t) - p.x function:
+ double D = getX1() - p.x;
+ double C = 3 * (getCtrl1X() - getX1());
+ double B = 3 * (getCtrl2X() - getCtrl1X()) - C;
+ double A = getX2() - getX1() - B - C;
+ double[] xts = PolynomCalculations.getCubicRoots(A, B, C, D);
+
+ for (double t : xts) {
+ // t = PrecisionUtils.round(t);
+ if (PrecisionUtils.greaterEqual(t, 0)
+ && PrecisionUtils.smallerEqual(t, 1)
+ && PrecisionUtils.equal(get(t).y, p.y)) {
+ return true;
+ }
+ }
return false;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.gef4.geometry.shapes.Geometry#contains(org.eclipse.gef4.geometry
- * .shapes.Rectangle)
+ /**
+ * @see Geometry#contains(Rectangle)
*/
public boolean contains(Rectangle r) {
- // TODO Auto-generated method stub
return false;
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.gef4.geometry.shapes.Geometry#getBounds()
+ @Override
+ public boolean equals(Object other) {
+ CubicCurve o = (CubicCurve) other;
+
+ Polygon myPoly = getControlPolygon();
+ Polygon otherPoly = o.getControlPolygon();
+
+ return myPoly.equals(otherPoly);
+ }
+
+ /**
+ * @see Geometry#getBounds()
*/
public Rectangle getBounds() {
- // TODO Auto-generated method stub
- return null;
+ // extremes of the x(t) and y(t) functions:
+ double[] xts;
+ try {
+ xts = PolynomCalculations.getQuadraticRoots(-3 * getX1() + 9
+ * getCtrl1X() - 9 * getCtrl2X() + 3 * getX2(), 6 * getX1()
+ - 12 * getCtrl1X() + 6 * getCtrl2X(), 3 * getCtrl1X() - 3
+ * getX1());
+ } catch (ArithmeticException x) {
+ return new Rectangle(getP1(), getP2());
+ }
+
+ double xmin = getX1(), xmax = getX1();
+ if (getX2() < xmin) {
+ xmin = getX2();
+ } else {
+ xmax = getX2();
+ }
+
+ for (double t : xts) {
+ if (t >= 0 && t <= 1) {
+ double x = get(t).x;
+ if (x < xmin) {
+ xmin = x;
+ } else if (x > xmax) {
+ xmax = x;
+ }
+ }
+ }
+
+ double[] yts;
+ try {
+ yts = PolynomCalculations.getQuadraticRoots(-3 * getY1() + 9
+ * getCtrl1Y() - 9 * getCtrl2Y() + 3 * getY2(), 6 * getY1()
+ - 12 * getCtrl1Y() + 6 * getCtrl2Y(), 3 * getCtrl1Y() - 3
+ * getY1());
+ } catch (ArithmeticException x) {
+ return new Rectangle(new Point(xmin, getP1().y), new Point(xmax,
+ getP2().y));
+ }
+
+ double ymin = getY1(), ymax = getY1();
+ if (getY2() < ymin) {
+ ymin = getY2();
+ } else {
+ ymax = getY2();
+ }
+
+ for (double t : yts) {
+ if (t >= 0 && t <= 1) {
+ double y = get(t).y;
+ if (y < ymin) {
+ ymin = y;
+ } else if (y > ymax) {
+ ymax = y;
+ }
+ }
+ }
+
+ return new Rectangle(new Point(xmin, ymin), new Point(xmax, ymax));
+ }
+
+ private Point ratioPoint(Point p, Point q, double ratio) {
+ return p.getTranslated(q.getTranslated(p.getNegated()).getScaled(ratio));
+ }
+
+ /**
+ * Subdivides this {@link CubicCurve} into two {@link CubicCurve}s on the
+ * intervals [0, t] and [t, 1] using the de-Casteljau-algorithm.
+ *
+ * @param t
+ * split point's parameter value
+ * @return the two {@link CubicCurve}s
+ */
+ public CubicCurve[] split(double t) {
+ if (t < 0 || t > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t is out of range! t = " + t + " !in_range(0,1)");
+ }
+
+ Point p10 = ratioPoint(getP1(), getCtrl1(), t);
+ Point p11 = ratioPoint(getCtrl1(), getCtrl2(), t);
+ Point p12 = ratioPoint(getCtrl2(), getP2(), t);
+ Point p20 = ratioPoint(p10, p11, t);
+ Point p21 = ratioPoint(p11, p12, t);
+ Point p30 = ratioPoint(p20, p21, t);
+
+ CubicCurve left = new CubicCurve(getP1(), p10, p20, p30);
+ CubicCurve right = new CubicCurve(p30, p21, p12, getP2());
+
+ return new CubicCurve[] { left, right };
+ }
+
+ /**
+ * Clips this {@link CubicCurve} at parameter values t1 and t2 so that the
+ * resulting {@link CubicCurve} is the section of the original
+ * {@link CubicCurve} for the parameter interval [t1, t2].
+ *
+ * @param t1
+ * @param t2
+ * @return the {@link CubicCurve} on the interval [t1, t2]
+ */
+ public CubicCurve clip(double t1, double t2) {
+ if (t1 < 0 || t1 > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t1 is out of range! t1 = " + t1
+ + " !in_range(0,1)");
+ }
+ if (t2 < 0 || t2 > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t2 is out of range! t2 = " + t2
+ + " !in_range(0,1)");
+ }
+
+ CubicCurve right = split(t1)[1];
+ double rightT2 = (t2 - t1) / (1 - t1);
+ return right.split(rightT2)[0];
+ }
+
+ private static double getArea(Polygon p) {
+ Rectangle r = p.getBounds();
+ return r.getWidth() * r.getHeight();
+ }
+
+ private Polygon getControlPolygon() {
+ return new Polygon(getP1(), getCtrl1(), getCtrl2(), getP2());
+ }
+
+ private static Point[] getIntersections(CubicCurve p, double ps, double pe,
+ Line l) {
+ // parameter convergence test
+ double pm = (ps + pe) / 2;
+
+ if (PrecisionUtils.equal(ps, pe, -2)) {
+ return new Point[] { p.get(pm) };
+ }
+
+ // no parameter convergence
+ // clip the curve
+ CubicCurve pc = p.clip(ps, pe);
+
+ // check the control polygon
+ Polygon polygon = pc.getControlPolygon();
+
+ if (polygon.intersects(l)) {
+ // area test
+ if (PrecisionUtils.equal(getArea(polygon), 0, -2)) {
+ // line/line intersection fallback for such small curves
+ Point poi = new Line(pc.getP1(), pc.getP2()).getIntersection(l);
+ if (poi != null) {
+ return new Point[] { poi };
+ }
+ return new Point[] {};
+ }
+
+ // "split" the curve to get precise intersections
+ HashSet intersections = new HashSet();
+
+ intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, l)));
+ intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, l)));
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ // no intersections
+ return new Point[] {};
+ }
+
+ private static Point[] getIntersections(CubicCurve p, double ps, double pe,
+ CubicCurve q, double qs, double qe) {
+ double pm = (ps + pe) / 2;
+ double qm = (qs + qe) / 2;
+
+ // point convergence test
+ Point pPoi = p.get(pm);
+ Point qPoi = q.get(qm);
+
+ if (pPoi != null && qPoi != null && pPoi.equals(qPoi)) {
+ return new Point[] { pPoi };
+ }
+
+ // no point convergence yet
+ // clip to parameter ranges
+ CubicCurve pc = p.clip(ps, pe);
+ CubicCurve qc = q.clip(qs, qe);
+
+ // check the control polygons
+ Polygon pPoly = pc.getControlPolygon();
+ Polygon qPoly = qc.getControlPolygon();
+
+ if (pPoly.intersects(qPoly)) {
+ // check the polygon's areas
+ double pArea = getArea(pPoly);
+ double qArea = getArea(qPoly);
+
+ if (PrecisionUtils.equal(pArea, 0, +2)
+ && PrecisionUtils.equal(qArea, 0, +2)) {
+ // return line/line intersection
+ Point poi = new Line(pc.getP1(), pc.getP2())
+ .getIntersection(new Line(qc.getP1(), qc.getP2()));
+ if (poi != null) {
+ return new Point[] { poi };
+ }
+ return new Point[] {};
+ }
+
+ // areas not small enough
+
+ // do not try to find the intersections of two equal curves
+ if (pc.equals(qc)) {
+ return new Point[] {};
+ }
+
+ // "split" the curves and do the intersection test recursively
+ HashSet intersections = new HashSet();
+
+ intersections.addAll(Arrays.asList(getIntersections(p.clip(ps, pm),
+ 0, 1, q.clip(qs, qm), 0, 1)));
+ intersections.addAll(Arrays.asList(getIntersections(p.clip(ps, pm),
+ 0, 1, q.clip(qm, qe), 0, 1)));
+ intersections.addAll(Arrays.asList(getIntersections(p.clip(pm, pe),
+ 0, 1, q.clip(qs, qm), 0, 1)));
+ intersections.addAll(Arrays.asList(getIntersections(p.clip(pm, pe),
+ 0, 1, q.clip(qm, qe), 0, 1)));
+
+ // intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
+ // qs, qm)));
+ // intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
+ // qm, qe)));
+ // intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
+ // qs, qm)));
+ // intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
+ // qm, qe)));
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ // no intersections
+ return new Point[] {};
+ }
+
+ /**
+ * Returns the points of intersection between this {@link CubicCurve} and
+ * the given other {@link CubicCurve}.
+ *
+ * @param other
+ * @return the points of intersection
+ */
+ public Point[] getIntersections(CubicCurve other) {
+ return getIntersections(this, 0, 1, other, 0, 1);
}
+ /**
+ * Returns the points of intersection between this {@link CubicCurve} and
+ * the given {@link Line} l.
+ *
+ * @param l
+ * @return the points of intersection
+ */
+ public Point[] getIntersections(Line l) {
+ return getIntersections(this, 0, 1, l);
+ }
+
+ /**
+ * Returns the first control {@link Point}.
+ *
+ * @return the first control {@link Point}.
+ */
public Point getCtrl1() {
return new Point(ctrl1X, ctrl1Y);
}
+ /**
+ * Returns the first control {@link Point}'s x-coordinate.
+ *
+ * @return the first control {@link Point}'s x-coordinate.
+ */
public double getCtrl1X() {
return ctrl1X;
}
+ /**
+ * Returns the first control {@link Point}'s y-coordinate.
+ *
+ * @return the first control {@link Point}'s y-coordinate.
+ */
public double getCtrl1Y() {
return ctrl1Y;
}
+ /**
+ * Returns the second control {@link Point}.
+ *
+ * @return the second control {@link Point}.
+ */
public Point getCtrl2() {
return new Point(ctrl2X, ctrl2Y);
}
+ /**
+ * Returns the second control {@link Point}'s x-coordinate.
+ *
+ * @return the second control {@link Point}'s x-coordinate.
+ */
public double getCtrl2X() {
return ctrl2X;
}
+ /**
+ * Returns the second control {@link Point}'s y-coordinate.
+ *
+ * @return the second control {@link Point}'s y-coordinate.
+ */
public double getCtrl2Y() {
return ctrl2Y;
}
+ /**
+ * Returns the start {@link Point}.
+ *
+ * @return the start {@link Point}.
+ */
public Point getP1() {
return new Point(x1, y1);
}
+ /**
+ * Returns the end {@link Point}.
+ *
+ * @return the end {@link Point}.
+ */
public Point getP2() {
- return new Point(x1, y1);
+ return new Point(x2, y2);
}
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.gef4.geometry.shapes.Geometry#getTransformed(org.eclipse.
- * gef4.geometry.transform.AffineTransform)
+ /**
+ * @see Geometry#getTransformed(AffineTransform)
*/
public Geometry getTransformed(AffineTransform t) {
- // TODO Auto-generated method stub
return null;
}
+ /**
+ * Returns the start {@link Point}'s x-coordinate.
+ *
+ * @return the start {@link Point}'s x-coordinate.
+ */
public double getX1() {
return x1;
}
+ /**
+ * Returns the end {@link Point}'s x-coordinate.
+ *
+ * @return the end {@link Point}'s x-coordinate.
+ */
public double getX2() {
return x2;
}
+ /**
+ * Returns the start {@link Point}'s y-coordinate.
+ *
+ * @return the start {@link Point}'s y-coordinate.
+ */
public double getY1() {
return y1;
}
+ /**
+ * Returns the end {@link Point}'s y-coordinate.
+ *
+ * @return the end {@link Point}'s y-coordinate.
+ */
public double getY2() {
return y2;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * org.eclipse.gef4.geometry.shapes.Geometry#intersects(org.eclipse.gef4
- * .geometry.shapes.Rectangle)
+ /**
+ * @see org.eclipse.gef4.geometry.shapes.Geometry#intersects(Rectangle)
*/
public boolean intersects(Rectangle r) {
- // TODO Auto-generated method stub
return false;
}
+ /**
+ * Tests if this {@link CubicCurve} intersects the given {@link Line} r.
+ *
+ * @param r
+ * @return true if they intersect, false otherwise
+ */
+ public boolean intersects(Line r) {
+ return getIntersections(r).length > 0;
+ }
+
+ /**
+ * Sets the first control {@link Point} to the given {@link Point} ctrl1.
+ *
+ * @param ctrl1
+ * the new first control {@link Point}
+ */
public void setCtrl1(Point ctrl1) {
this.ctrl1X = ctrl1.x;
this.ctrl1Y = ctrl1.y;
}
+ /**
+ * Sets the first control {@link Point}'s x-coordinate to the given
+ * x-coordinate ctrl1x.
+ *
+ * @param ctrl1x
+ * the new first control {@link Point}'s x-coordinate
+ */
public void setCtrl1X(double ctrl1x) {
ctrl1X = ctrl1x;
}
+ /**
+ * Sets the first control {@link Point}'s y-coordinate to the given
+ * y-coordinate ctrl1y.
+ *
+ * @param ctrl1y
+ * the new first control {@link Point}'s y-coordinate
+ */
public void setCtrl1Y(double ctrl1y) {
ctrl1Y = ctrl1y;
}
+ /**
+ * Sets the second control {@link Point} to the given {@link Point} ctrl2.
+ *
+ * @param ctrl2
+ * the new second control {@link Point}
+ */
public void setCtrl2(Point ctrl2) {
this.ctrl2X = ctrl2.x;
this.ctrl2Y = ctrl2.y;
}
+ /**
+ * Sets the second control {@link Point}'s x-coordinate to the given
+ * x-coordinate ctrl2x.
+ *
+ * @param ctrl2x
+ * the new second control {@link Point}'s x-coordinate
+ */
public void setCtrl2X(double ctrl2x) {
ctrl2X = ctrl2x;
}
+ /**
+ * Sets the second control {@link Point}'s y-coordinate to the given
+ * y-coordinate ctrl2y.
+ *
+ * @param ctrl2y
+ * the new second control {@link Point}'s y-coordinate
+ */
public void setCtrl2Y(double ctrl2y) {
ctrl2Y = ctrl2y;
}
+ /**
+ * Sets all control points of this {@link CubicCurve} to the given control
+ * {@link Point}s.
+ *
+ * @param p1
+ * the new start {@link Point}
+ * @param ctrl1
+ * the new first control {@link Point}
+ * @param ctrl2
+ * the new second control {@link Point}
+ * @param p2
+ * the new end {@link Point}
+ */
public void setCurve(Point p1, Point ctrl1, Point ctrl2, Point p2) {
setP1(p1);
setCtrl1(ctrl1);
@@ -188,35 +612,75 @@
setP2(p2);
}
+ /**
+ * Sets the start {@link Point} of this {@link CubicCurve} to the given
+ * {@link Point} p1.
+ *
+ * @param p1
+ * the new start {@link Point}
+ */
public void setP1(Point p1) {
this.x1 = p1.x;
this.y1 = p1.y;
}
+ /**
+ * Sets the end {@link Point} of this {@link CubicCurve} to the given
+ * {@link Point} p2.
+ *
+ * @param p2
+ * the new end {@link Point}
+ */
public void setP2(Point p2) {
this.x2 = p2.x;
this.y2 = p2.y;
}
+ /**
+ * Sets the x-coordinate of the start {@link Point} of this
+ * {@link CubicCurve} to x1.
+ *
+ * @param x1
+ * the new start {@link Point}'s x-coordinate
+ */
public void setX1(double x1) {
this.x1 = x1;
}
+ /**
+ * Sets the x-coordinate of the end {@link Point} of this {@link CubicCurve}
+ * to x2.
+ *
+ * @param x2
+ * the new end {@link Point}'s x-coordinate
+ */
public void setX2(double x2) {
this.x2 = x2;
}
+ /**
+ * Sets the y-coordinate of the start {@link Point} of this
+ * {@link CubicCurve} to y1.
+ *
+ * @param y1
+ * the new start {@link Point}'s y-coordinate
+ */
public void setY1(double y1) {
this.y1 = y1;
}
+ /**
+ * Sets the y-coordinate of the end {@link Point} of this {@link CubicCurve}
+ * to y2.
+ *
+ * @param y2
+ * the new end {@link Point}'s y-coordinate
+ */
public void setY2(double y2) {
this.y2 = y2;
}
- /*
- * (non-Javadoc)
- *
+ /**
* @see org.eclipse.gef4.geometry.shapes.Geometry#toPath()
*/
public Path toPath() {
@@ -226,4 +690,32 @@
return p;
}
+ /**
+ * Get a single {@link Point} on this CubicCurve at parameter t.
+ *
+ * @param t
+ * in range [0,1]
+ * @return the {@link Point} at parameter t
+ */
+ public Point get(double t) {
+ if (!(PrecisionUtils.greaterEqual(t, 0) && PrecisionUtils.smallerEqual(
+ t, 1))) {
+ throw new IllegalArgumentException(
+ "Paramter t is out of range! t = " + t + " !in_range(0,1)");
+ }
+
+ // compensate rounding effects
+ if (t < 0) {
+ t = 0;
+ } else if (t > 1) {
+ t = 1;
+ }
+
+ double d = 1 - t;
+ return getP1().getScaled(d * d * d)
+ .getTranslated(getCtrl1().getScaled(3 * t * d * d))
+ .getTranslated(getCtrl2().getScaled(3 * t * t * d))
+ .getTranslated(getP2().getScaled(t * t * t));
+ }
+
}
Index: src/org/eclipse/gef4/geometry/shapes/Ellipse.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/Ellipse.java,v
retrieving revision 1.11
diff -u -r1.11 Ellipse.java
--- src/org/eclipse/gef4/geometry/shapes/Ellipse.java 20 Oct 2011 21:04:44 -0000 1.11
+++ src/org/eclipse/gef4/geometry/shapes/Ellipse.java 21 Oct 2011 12:49:29 -0000
@@ -13,6 +13,8 @@
package org.eclipse.gef4.geometry.shapes;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -101,8 +103,8 @@
* @see Geometry#contains(Point)
*/
public boolean contains(Point p) {
- // point has to fulfill (x/a)^2 + (y/b)^2 = 1, where a = width/2 and b =
- // height/2, if ellipse is centered around origin, so we have to
+ // point has to fulfill (x/a)^2 + (y/b)^2 <= 1, where a = width/2 and b
+ // = height/2, if ellipse is centered around origin, so we have to
// normalize point p by subtracting the center
double normalizedX = p.x - (x + width / 2);
double normalizedY = p.y - (y + height / 2);
@@ -113,6 +115,37 @@
}
/**
+ * Tests if this {@link Ellipse} contains the given {@link Polyline}
+ * polyline.
+ *
+ * @param polyline
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(Polyline polyline) {
+ for (Line segment : polyline.getSegments()) {
+ if (!contains(segment)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests if this {@link Ellipse} contains the given {@link Polygon} polygon.
+ *
+ * @param polygon
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(Polygon polygon) {
+ for (Line segment : polygon.getSegments()) {
+ if (!contains(segment)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* @see Geometry#contains(Rectangle)
*/
public boolean contains(Rectangle r) {
@@ -305,13 +338,13 @@
double dx = x2 - x1;
// special-case the vertical line
- if (PrecisionUtils.equal(dx, 0)) {
+ if (PrecisionUtils.equal(dx, 0, +2)) {
// vertical line
if (PrecisionUtils.smallerEqual(-a, x1)
&& PrecisionUtils.smallerEqual(x1, a)) { // -a <= x1 <= a
// inside the ellipse
- double y = Math.sqrt(PrecisionUtils.round(bSq
- * (1 - x1 * x1 / aSq)));
+ double rad = bSq * (1 - x1 * x1 / aSq);
+ double y = rad < 0 ? 0 : Math.sqrt(rad);
if (PrecisionUtils.greaterEqual(y1, y)) {
if (PrecisionUtils.smallerEqual(y2, y)) {
@@ -348,16 +381,14 @@
// check if equation has at least one solution
double d = p * p / 4 - q;
- if (PrecisionUtils.smaller(d, 0)) {
- // discriminant smaller zero, so no solutions possible
- } else if (PrecisionUtils.equal(d, 0)) {
+ if (PrecisionUtils.equal(d, 0, +2)) {
// discriminant equals zero, so one possible solution
double px = -p / 2;
double py = px * m + n;
intersections.add(new Point(px, py));
- } else {
+ } else if (d > 0) {
// discriminant greater than zero, so two possible solutions
- double sqrt = Math.sqrt(PrecisionUtils.round(d));
+ double sqrt = d < 0 ? 0 : Math.sqrt(d);
// first
double px = -p / 2 + sqrt;
@@ -450,6 +481,38 @@
}
/**
+ * Tests if this {@link Ellipse} intersects the given {@link Polyline}
+ * polyline.
+ *
+ * @param polyline
+ * @return true if they intersect, false otherwise
+ */
+ public boolean intersects(Polyline polyline) {
+ for (Line segment : polyline.getSegments()) {
+ if (intersects(segment)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests if this {@link Ellipse} intersects the given {@link Polygon}
+ * polygon.
+ *
+ * @param polygon
+ * @return true if they intersect, false otherwise
+ */
+ public boolean intersects(Polygon polygon) {
+ for (Line segment : polygon.getSegments()) {
+ if (intersects(segment)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* At least one common point, which includes containment (check
* getIntersections() to check if this is a true intersection).
*
@@ -534,4 +597,86 @@
return "Ellipse: (" + x + ", " + y + ", " + //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
width + ", " + height + ")";//$NON-NLS-2$//$NON-NLS-1$
}
+
+ /**
+ * Calculates the intersections of this {@link Ellipse} with the given other
+ * {@link Ellipse}.
+ *
+ * @param e2
+ * @return points of intersection
+ */
+ public Point[] getIntersections(Ellipse e2) {
+ if (equals(e2)) {
+ return new Point[] {};
+ }
+
+ HashSet intersections = new HashSet();
+
+ for (CubicCurve seg : getBorderSegments()) {
+ intersections.addAll(Arrays.asList(e2.getIntersections(seg)));
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Calculates the points of intersection of this {@link Ellipse} and the
+ * given {@link CubicCurve}.
+ *
+ * @param curve
+ * @return points of intersection
+ */
+ public Point[] getIntersections(CubicCurve curve) {
+ HashSet intersections = new HashSet();
+
+ for (CubicCurve seg : getBorderSegments()) {
+ intersections.addAll(Arrays.asList(curve.getIntersections(seg)));
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Calculates the border segments of this {@link Ellipse}. The
+ * border-segments are approximated by {@link CubicCurve}s. These curves are
+ * generated as in the {@link Ellipse#toPath()} method.
+ *
+ * @return border-segments
+ */
+ public CubicCurve[] getBorderSegments() {
+ CubicCurve[] segs = new CubicCurve[4];
+ // see http://whizkidtech.redprince.net/bezier/circle/kappa/ for details
+ // on the approximation used here
+ final double kappa = 4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d;
+ double a = width / 2;
+ double b = height / 2;
+
+ double ox = x + a;
+ double oy = y;
+
+ segs[0] = new CubicCurve(ox, oy, x + a + kappa * a, y, x + width, y + b
+ - kappa * b, x + width, y + b);
+
+ ox = x + width;
+ oy = y + b;
+
+ segs[1] = new CubicCurve(ox, oy, x + width, y + b + kappa * b, x + a
+ + kappa * a, y + height, x + a, y + height);
+
+ ox = x + a;
+ oy = y + height;
+
+ segs[2] = new CubicCurve(ox, oy, x + width / 2 - kappa * width / 2, y
+ + height, x, y + height / 2 + kappa * height / 2, x, y + height
+ / 2);
+
+ ox = x;
+ oy = y + height / 2;
+
+ segs[3] = new CubicCurve(ox, oy, x,
+ y + height / 2 - kappa * height / 2, x + width / 2 - kappa
+ * width / 2, y, x + width / 2, y);
+
+ return segs;
+ }
}
Index: src/org/eclipse/gef4/geometry/shapes/Line.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/Line.java,v
retrieving revision 1.7
diff -u -r1.7 Line.java
--- src/org/eclipse/gef4/geometry/shapes/Line.java 20 Oct 2011 21:04:44 -0000 1.7
+++ src/org/eclipse/gef4/geometry/shapes/Line.java 21 Oct 2011 12:49:29 -0000
@@ -75,6 +75,11 @@
// TODO: optimize w.r.t object creation
Point p1 = getP1();
Point p2 = getP2();
+
+ if (p1.equals(p2)) {
+ return p.equals(p1);
+ }
+
return new Straight(p1, p2).containsWithinSegment(new Vector(p1),
new Vector(p2), new Vector(p));
}
@@ -272,9 +277,19 @@
// TODO: optimize w.r.t. object creation
Point p1 = getP1();
Point p2 = getP2();
- Straight s1 = new Straight(p1, p2);
+
+ if (p1.equals(p2)) {
+ return l.contains(p1);
+ }
+
Point lp1 = l.getP1();
Point lp2 = l.getP2();
+
+ if (lp1.equals(lp2)) {
+ return contains(lp1);
+ }
+
+ Straight s1 = new Straight(p1, p2);
Straight s2 = new Straight(lp1, lp2);
Vector v1 = new Vector(p1);
Vector v2 = new Vector(p2);
Index: src/org/eclipse/gef4/geometry/shapes/Polygon.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/Polygon.java,v
retrieving revision 1.8
diff -u -r1.8 Polygon.java
--- src/org/eclipse/gef4/geometry/shapes/Polygon.java 20 Oct 2011 21:04:44 -0000 1.8
+++ src/org/eclipse/gef4/geometry/shapes/Polygon.java 21 Oct 2011 12:49:29 -0000
@@ -11,6 +11,9 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.shapes;
+import java.util.ArrayList;
+
+import org.eclipse.gef4.geometry.Angle;
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.euclidean.Straight;
import org.eclipse.gef4.geometry.euclidean.Vector;
@@ -126,6 +129,94 @@
}
/**
+ * Returns the points of intersection between this {@link Polygon} and the
+ * given {@link Line} l.
+ *
+ * @param l
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Line l) {
+ ArrayList intersections = new ArrayList();
+
+ for (Line segment : getSegments()) {
+ Point poi = segment.getIntersection(l);
+ if (poi != null) {
+ intersections.add(poi);
+ }
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Returns the points of intersection between this {@link Polygon} and the
+ * given other {@link Polygon} polygon.
+ *
+ * @param polygon
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Polygon polygon) {
+ ArrayList intersections = new ArrayList();
+
+ for (Line segment : polygon.getSegments()) {
+ for (Point poi : getIntersections(segment)) {
+ intersections.add(poi);
+ }
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Returns the points of intersection between this {@link Polygon} and the
+ * given {@link Polyline} polyline.
+ *
+ * @param polyline
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Polyline polyline) {
+ ArrayList intersections = new ArrayList();
+
+ for (Line segment : polyline.getSegments()) {
+ for (Point poi : getIntersections(segment)) {
+ intersections.add(poi);
+ }
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Returns the points of intersection between this {@link Polygon} and the
+ * given {@link Rectangle} rect.
+ *
+ * @param rect
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Rectangle rect) {
+ ArrayList intersections = new ArrayList();
+
+ for (Line segment : rect.getSegments()) {
+ for (Point poi : getIntersections(segment)) {
+ intersections.add(poi);
+ }
+ }
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ /**
+ * Returns the points of intersection between this {@link Polygon} and the
+ * given {@link Ellipse} e.
+ *
+ * @param e
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Ellipse e) {
+ return e.getIntersections(this);
+ }
+
+ /**
* @see Geometry#contains(Point)
*/
public boolean contains(Point p) {
@@ -177,6 +268,60 @@
}
/**
+ * Tests if the given {@link QuadraticCurve} curve is contained in this
+ * {@link Polygon}.
+ *
+ * @param curve
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(QuadraticCurve curve) {
+ if (contains(curve.getP1()) && contains(curve.getP2())) {
+ for (Line seg : getSegments()) {
+ if (curve.intersects(seg)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tests if the given {@link CubicCurve} curve is contained in this
+ * {@link Polygon}.
+ *
+ * @param curve
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(CubicCurve curve) {
+ if (contains(curve.getP1()) && contains(curve.getP2())) {
+ for (Line seg : getSegments()) {
+ if (curve.intersects(seg)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Tests if the given {@link Ellipse} e is contained in this {@link Polygon}
+ * .
+ *
+ * @param e
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(Ellipse e) {
+ for (CubicCurve curve : e.getBorderSegments()) {
+ if (!contains(curve)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Checks whether the given {@link Polygon} is fully contained within this
* {@link Polygon}.
*
@@ -197,6 +342,34 @@
}
/**
+ * Tests if the given {@link Polyline} p is contained in this
+ * {@link Polygon}.
+ *
+ * @param p
+ * @return true if it is contained, false otherwise
+ */
+ public boolean contains(Polyline p) {
+ // all segments of the given polygon have to be contained
+ Line[] otherSegments = p.getSegments();
+ for (int i = 0; i < otherSegments.length; i++) {
+ if (!contains(otherSegments[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests if this {@link Polygon} intersects the given {@link Ellipse} e.
+ *
+ * @param e
+ * @return true if they intersect, false otherwise
+ */
+ public boolean intersects(Ellipse e) {
+ return e.intersects(this);
+ }
+
+ /**
* @see Geometry#contains(Rectangle)
*/
public boolean contains(Rectangle rect) {
@@ -277,6 +450,83 @@
}
/**
+ * Tests if this {@link Polygon} intersects with the given {@link Polyline}
+ * p.
+ *
+ * @param p
+ * @return true if they intersect, false otherwise
+ */
+ public boolean intersects(Polyline p) {
+ // reduce to segment intersection test
+ Line[] otherSegments = p.getSegments();
+ for (int i = 0; i < otherSegments.length; i++) {
+ if (intersects(otherSegments[i])) {
+ return true;
+ }
+ }
+ // no intersection, so we still need to check for containment
+ return contains(p);
+ }
+
+ /**
+ * Rotates this {@link Polygon} clock-wise by the given {@link Angle} alpha
+ * around the given {@link Point} center.
+ *
+ * The rotation is done by
+ *
+ * - translating this {@link Polygon} by the negated {@link Point} center
+ * - rotating each {@link Point} of this {@link Polygon} clock-wise by the
+ * given {@link Angle} angle
+ * - translating this {@link Polygon} back by the {@link Point} center
+ *
+ *
+ * @param alpha
+ * The rotation {@link Angle}.
+ * @param center
+ * The {@link Point} to rotate around.
+ * @return This (clock-wise-rotated) {@link Polygon} object.
+ */
+ public Polygon rotateCW(Angle alpha, Point center) {
+ translate(center.getNegated());
+ for (Point p : points) {
+ Point np = new Vector(p).rotateCW(alpha).toPoint();
+ p.x = np.x;
+ p.y = np.y;
+ }
+ translate(center);
+ return this;
+ }
+
+ /**
+ * Rotates this {@link Polygon} counter-clock-wise by the given
+ * {@link Angle} alpha around the given {@link Point} center.
+ *
+ * The rotation is done by
+ *
+ * - translating this {@link Polygon} by the negated {@link Point} center
+ * - rotating each {@link Point} of this {@link Polygon}
+ * counter-clock-wise by the given {@link Angle} angle
+ * - translating this {@link Polygon} back by the {@link Point} center
+ *
+ *
+ * @param alpha
+ * The rotation {@link Angle}.
+ * @param center
+ * The {@link Point} to rotate around.
+ * @return This (counter-clock-wise-rotated) {@link Polygon} object.
+ */
+ public Polygon rotateCCW(Angle alpha, Point center) {
+ translate(center.getNegated());
+ for (Point p : points) {
+ Point np = new Vector(p).rotateCCW(alpha).toPoint();
+ p.x = np.x;
+ p.y = np.y;
+ }
+ translate(center);
+ return this;
+ }
+
+ /**
* Returns a copy of the points that make up this {@link Polygon}, where a
* segment of the {@link Polygon} is represented between each two succeeding
* {@link Point}s in the sequence, and from the last back to the first.
@@ -447,6 +697,34 @@
}
/**
+ * Scales this {@link Polygon} object by the given factor from the given
+ * center {@link Point}.
+ *
+ * The scaling is done by
+ *
+ * - translating this {@link Polygon} by the negated center {@link Point}
+ * - scaling the individual {@link Polygon} {@link Point}s
+ * - translating this {@link Polygon} back
+ *
+ *
+ * @param factor
+ * The scale-factor.
+ * @param center
+ * The rotation {@link Point}.
+ * @return This (scaled) {@link Polygon} object.
+ */
+ public Polygon scale(double factor, Point center) {
+ translate(center.getNegated());
+ for (Point p : points) {
+ Point np = p.getScaled(factor);
+ p.x = np.x;
+ p.y = np.y;
+ }
+ translate(center);
+ return this;
+ }
+
+ /**
* Moves this Polygon horizontally by dx and vertically by dy, then returns
* this Rectangle for convenience.
*
Index: src/org/eclipse/gef4/geometry/shapes/QuadraticCurve.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/QuadraticCurve.java,v
retrieving revision 1.3
diff -u -r1.3 QuadraticCurve.java
--- src/org/eclipse/gef4/geometry/shapes/QuadraticCurve.java 20 Oct 2011 21:04:44 -0000 1.3
+++ src/org/eclipse/gef4/geometry/shapes/QuadraticCurve.java 21 Oct 2011 12:49:29 -0000
@@ -11,8 +11,13 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.shapes;
+import java.util.Arrays;
+import java.util.HashSet;
+
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.transform.AffineTransform;
+import org.eclipse.gef4.geometry.utils.PolynomCalculations;
+import org.eclipse.gef4.geometry.utils.PrecisionUtils;
/**
* Represents the geometric shape of a quadratic Bézier curve.
@@ -23,42 +28,90 @@
public class QuadraticCurve implements Geometry {
private static final long serialVersionUID = 1L;
-
private double x1, y1, ctrlX, ctrlY, x2, y2;
- public boolean contains(Point p) {
- // TODO Auto-generated method stub
- return false;
- }
-
- public boolean contains(Rectangle r) {
- // TODO Auto-generated method stub
- return false;
- }
-
- public Rectangle getBounds() {
- // TODO Auto-generated method stub
- return null;
- }
-
+ /**
+ * Constructs a new QuadraticCurve object from the given points.
+ *
+ * @param p1
+ * the start point
+ * @param pCtrl
+ * the control point
+ * @param p2
+ * the end point
+ */
+ public QuadraticCurve(Point p1, Point pCtrl, Point p2) {
+ setP1(p1);
+ setCtrl(pCtrl);
+ setP2(p2);
+ }
+
+ /**
+ * Constructs a new QuadraticCurve object from the given point coordinates.
+ *
+ * @param x1
+ * the start point's x-coordinate
+ * @param y1
+ * the start point's y-coordinate
+ * @param xCtrl
+ * the control point's x-coordinate
+ * @param yCtrl
+ * the control point's y-coordinate
+ * @param x2
+ * the end point's x-coordinate
+ * @param y2
+ * the end point's y-coordinate
+ */
+ public QuadraticCurve(double x1, double y1, double xCtrl, double yCtrl,
+ double x2, double y2) {
+ setP1(new Point(x1, y1));
+ setCtrl(new Point(xCtrl, yCtrl));
+ setP2(new Point(x2, y2));
+ }
+
+ /**
+ * Get the control point.
+ *
+ * @return a Point object representing the control point
+ */
public Point getCtrl() {
return new Point(ctrlX, ctrlY);
}
+ /**
+ * Get the control point's x-coordinate.
+ *
+ * @return the control point's x-coordinate
+ */
public double getCtrlX() {
return ctrlX;
}
+ /**
+ * Get the control point's y-coordinate.
+ *
+ * @return the control point's y-coordinate
+ */
public double getCtrlY() {
return ctrlY;
}
+ /**
+ * Get the curve's starting point.
+ *
+ * @return the curve's starting point
+ */
public Point getP1() {
return new Point(x1, y1);
}
+ /**
+ * Get the curve's ending point.
+ *
+ * @return the curve's ending point
+ */
public Point getP2() {
- return new Point(x1, y1);
+ return new Point(x2, y2);
}
public Geometry getTransformed(AffineTransform t) {
@@ -66,66 +119,132 @@
return null;
}
+ /**
+ * Returns the x-coordinate of the curve's starting point.
+ *
+ * @return the x-coordinate of the curve's starting point
+ */
public double getX1() {
return x1;
}
+ /**
+ * Returns the x-coordinate of the curve's ending point.
+ *
+ * @return the x-coordinate of the curve's ending point
+ */
public double getX2() {
return x2;
}
+ /**
+ * Returns the y-coordinate of the curve's starting point.
+ *
+ * @return the y-coordinate of the curve's starting point
+ */
public double getY1() {
return y1;
}
+ /**
+ * Returns the y-coordinate of the curve's ending point.
+ *
+ * @return the y-coordinate of the curve's ending point
+ */
public double getY2() {
return y2;
}
- public boolean intersects(Rectangle r) {
- // TODO Auto-generated method stub
- return false;
- }
-
+ /**
+ * Sets the curve's control point.
+ *
+ * @param ctrl
+ */
public void setCtrl(Point ctrl) {
this.ctrlX = ctrl.x;
this.ctrlY = ctrl.y;
}
+ /**
+ * Sets the x-coordinate of the curve's control point.
+ *
+ * @param ctrlX
+ */
public void setCtrlX(double ctrlX) {
this.ctrlX = ctrlX;
}
+ /**
+ * Sets the y-coordinate of the curve's control point.
+ *
+ * @param ctrlY
+ */
public void setCtrlY(double ctrlY) {
this.ctrlY = ctrlY;
}
+ /**
+ * Sets the curve's starting point.
+ *
+ * @param p1
+ */
public void setP1(Point p1) {
this.x1 = p1.x;
this.y1 = p1.y;
}
+ /**
+ * Sets the curve's ending point.
+ *
+ * @param p2
+ */
public void setP2(Point p2) {
this.x2 = p2.x;
this.y2 = p2.y;
}
+ /**
+ * Sets the x-coordinate of the curve's starting point.
+ *
+ * @param x1
+ */
public void setX1(double x1) {
this.x1 = x1;
}
+ /**
+ * Sets the x-coordinate of the curve's ending point.
+ *
+ * @param x2
+ */
public void setX2(double x2) {
this.x2 = x2;
}
+ /**
+ * Sets the y-coordinate of the curve's starting point.
+ *
+ * @param y1
+ */
public void setY1(double y1) {
this.y1 = y1;
}
+ /**
+ * Sets the y-coordinate of the curve's ending point.
+ *
+ * @param y2
+ */
public void setY2(double y2) {
this.y2 = y2;
}
+ /**
+ * Transform the QuadraticCurve object to a {@link Path} object with the
+ * same shape.
+ *
+ * @return a {@link Path} object representing the curve
+ */
public Path toPath() {
Path p = new Path();
p.moveTo(x1, y1);
@@ -133,4 +252,383 @@
return p;
}
+ /**
+ * Get a single {@link Point} on this QuadraticCurve at parameter t.
+ *
+ * @param t
+ * in range [0,1]
+ * @return the {@link Point} at parameter t
+ */
+ public Point get(double t) {
+ if (!(PrecisionUtils.greaterEqual(t, 0) && PrecisionUtils.smallerEqual(
+ t, 1))) {
+ throw new IllegalArgumentException(
+ "Paramter t is out of range! t = " + t + " !in_range(0,1)");
+ }
+
+ // compensate rounding effects
+ if (t < 0) {
+ t = 0;
+ } else if (t > 1) {
+ t = 1;
+ }
+
+ return new Point(t * (t * (getP1().x - 2 * getCtrl().x + getP2().x))
+ + 2 * (t * (getCtrl().x - getP1().x)) + getP1().x, t
+ * (t * (getP1().y - 2 * getCtrl().y + getP2().y)) + 2
+ * (t * (getCtrl().y - getP1().y)) + getP1().y);
+ }
+
+ /**
+ * Check if the given {@link Point} (approximately) lies on the curve.
+ *
+ * @param p
+ * the {@link Point} in question
+ * @return true if p lies on the curve, false otherwise
+ */
+ public boolean contains(Point p) {
+ // find roots of the x(t) - p.x function:
+ double[] xts = PolynomCalculations.getQuadraticRoots(getX1() - 2
+ * getCtrlX() + getX2(), 2 * getCtrlX() - 2 * getX1(), getX1()
+ - p.x);
+
+ for (double t : xts) {
+ // t = PrecisionUtils.round(t);
+ if (PrecisionUtils.greaterEqual(t, 0)
+ && PrecisionUtils.smallerEqual(t, 1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * How can it possibly contain a {@link Rectangle}?
+ *
+ * @param r
+ * the {@link Rectangle} in question
+ * @return always false
+ */
+ public boolean contains(Rectangle r) {
+ return false;
+ }
+
+ public boolean equals(Object other) {
+ QuadraticCurve o = (QuadraticCurve) other;
+
+ Polygon myPoly = getControlPolygon();
+ Polygon otherPoly = o.getControlPolygon();
+
+ return myPoly.equals(otherPoly);
+ }
+
+ /**
+ * Degree elevation: Returns a {@link CubicCurve} representation of this
+ * {@link QuadraticCurve}.
+ *
+ * @return A {@link CubicCurve} that represents this {@link QuadraticCurve}.
+ */
+ public CubicCurve getElevated() {
+ Point[] controlPoints = new Point[4];
+
+ // "Curves and Surfaces for Computer Aided Geometric Design" by Farin,
+ // Gerald E., Academic Press 1988
+ controlPoints[0] = getP1();
+ controlPoints[1] = getP1().getScaled(1 / 3).getTranslated(
+ getCtrl().getScaled(2 / 3));
+ controlPoints[2] = getCtrl().getScaled(2 / 3).getTranslated(
+ getP2().getScaled(1 / 3));
+ controlPoints[3] = getP2();
+
+ return new CubicCurve(controlPoints[0], controlPoints[1],
+ controlPoints[2], controlPoints[3]);
+ }
+
+ /**
+ * Returns the bounds of this QuadraticCurve. The bounds are calculated by
+ * examining the extreme points of the x(t) and y(t) function
+ * representations of this QuadraticCurve.
+ *
+ * @return the bounds {@link Rectangle}
+ */
+ public Rectangle getBounds() {
+ // extremes of the x(t) and y(t) functions:
+ double[] xts;
+ try {
+ xts = PolynomCalculations.getLinearRoots(2 * (getX1() - 2
+ * getCtrlX() + getX2()), 2 * (getCtrlX() - getX1()));
+ } catch (ArithmeticException x) {
+ return new Rectangle(getP1(), getP2());
+ }
+
+ double xmin = getX1(), xmax = getX1();
+ if (getX2() < xmin) {
+ xmin = getX2();
+ } else {
+ xmax = getX2();
+ }
+
+ for (double t : xts) {
+ if (t >= 0 && t <= 1) {
+ double x = get(t).x;
+ if (x < xmin) {
+ xmin = x;
+ } else if (x > xmax) {
+ xmax = x;
+ }
+ }
+ }
+
+ double[] yts;
+ try {
+ yts = PolynomCalculations.getLinearRoots(2 * (getY1() - 2
+ * getCtrlY() + getY2()), 2 * (getCtrlY() - getY1()));
+ } catch (ArithmeticException x) {
+ return new Rectangle(getP1(), getP2());
+ }
+
+ double ymin = getY1(), ymax = getY1();
+ if (getY2() < ymin) {
+ ymin = getY2();
+ } else {
+ ymax = getY2();
+ }
+
+ for (double t : yts) {
+ if (t >= 0 && t <= 1) {
+ double y = get(t).y;
+ if (y < ymin) {
+ ymin = y;
+ } else if (y > ymax) {
+ ymax = y;
+ }
+ }
+ }
+
+ return new Rectangle(new Point(xmin, ymin), new Point(xmax, ymax));
+ }
+
+ private Polygon getControlPolygon() {
+ return new Polygon(getP1(), getCtrl(), getP2());
+ }
+
+ /**
+ * Returns the points of intersection between this {@link QuadraticCurve}
+ * and the given {@link Line} l.
+ *
+ * @param l
+ * @return The points of intersection.
+ */
+ public Point[] getIntersections(Line l) {
+ return getIntersections(this, 0, 1, l);
+ }
+
+ private static double getArea(Polygon p) {
+ Rectangle r = p.getBounds();
+ return r.getWidth() * r.getHeight();
+ }
+
+ private static Point[] getIntersections(QuadraticCurve p, double ps,
+ double pe, Line l) {
+ // parameter convergence test
+ double pm = (ps + pe) / 2;
+
+ if (PrecisionUtils.equal(ps, pe, +2)) {
+ return new Point[] { p.get(pm) };
+ }
+
+ // no parameter convergence
+
+ // clip the curve
+ QuadraticCurve pc = p.clip(ps, pe);
+
+ // check the control polygon
+ Polygon polygon = pc.getControlPolygon();
+
+ if (polygon.intersects(l)) {
+ // area test
+ if (PrecisionUtils.equal(getArea(polygon), 0, +2)) {
+ // line/line intersection fallback for such small curves
+ Point poi = new Line(pc.getP1(), pc.getP2()).getIntersection(l);
+ if (poi != null) {
+ return new Point[] { poi };
+ }
+ return new Point[] {};
+ }
+
+ // individually test the curves left and right sides for points of
+ // intersection
+ HashSet intersections = new HashSet();
+
+ intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, l)));
+ intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, l)));
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ // no intersections
+ return new Point[] {};
+ }
+
+ private static Point[] getIntersections(QuadraticCurve p, double ps,
+ double pe, QuadraticCurve q, double qs, double qe) {
+ // parameter convergence test
+ double pm = (ps + pe) / 2;
+ double qm = (qs + qe) / 2;
+
+ if (PrecisionUtils.equal(ps, pe)) {
+ return new Point[] { p.get(pm) };
+ }
+
+ if (PrecisionUtils.equal(qs, qe)) {
+ return new Point[] { q.get(qm) };
+ }
+
+ // no parameter convergence
+
+ // clip to parameter ranges
+ QuadraticCurve pc = p.clip(ps, pe);
+ QuadraticCurve qc = q.clip(qs, qe);
+
+ // check the control polygons
+ Polygon pPoly = pc.getControlPolygon();
+ Polygon qPoly = qc.getControlPolygon();
+
+ if (pPoly.intersects(qPoly)) {
+ // check the polygon's areas
+ double pArea = getArea(pPoly);
+ double qArea = getArea(qPoly);
+
+ if (PrecisionUtils.equal(pArea, 0, -2)
+ && PrecisionUtils.equal(qArea, 0, -2)) {
+ // return line/line intersection
+ Point poi = new Line(pc.getP1(), pc.getP2())
+ .getIntersection(new Line(qc.getP1(), qc.getP2()));
+ if (poi != null) {
+ return new Point[] { poi };
+ }
+ return new Point[] {};
+ }
+
+ // areas not small enough
+
+ // individually test the left and right parts of the curves for
+ // points of intersection
+ HashSet intersections = new HashSet();
+
+ intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
+ qs, qm)));
+ intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
+ qm, qe)));
+ intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
+ qs, qm)));
+ intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
+ qm, qe)));
+
+ return intersections.toArray(new Point[] {});
+ }
+
+ // no intersections
+ return new Point[] {};
+ }
+
+ /**
+ * Calculates the intersections of two {@link QuadraticCurve}s using the
+ * subdivision algorithm.
+ *
+ * @param other
+ * @return points of intersection
+ */
+ public Point[] getIntersections(QuadraticCurve other) {
+ return getIntersections(this, 0, 1, other, 0, 1);
+ }
+
+ /**
+ * Checks if two {@link QuadraticCurve}s intersect each other. (Costly)
+ *
+ * @param other
+ * @return true if the two curves intersect. false otherwise
+ */
+ public boolean intersects(QuadraticCurve other) {
+ return getIntersections(other).length > 0;
+ }
+
+ /**
+ * Checks if this {@link QuadraticCurve} intersects with the given line.
+ * (Costly)
+ *
+ * TODO: implement a faster algorithm for this intersection-test.
+ *
+ * @param l
+ * @return true if they intersect, false otherwise.
+ */
+ public boolean intersects(Line l) {
+ return getIntersections(l).length > 0;
+ }
+
+ public boolean intersects(Rectangle r) {
+ for (Line l : r.getSegments()) {
+ if (intersects(l)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Point ratioPoint(Point p, Point q, double ratio) {
+ return p.getTranslated(q.getTranslated(p.getNegated()).getScaled(ratio));
+ }
+
+ /**
+ * Splits this QuadraticCurve using the de Casteljau algorithm at parameter
+ * t into two separate QuadraticCurve objects. The returned
+ * {@link QuadraticCurve}s are the curves for [0, t] and [t, 1].
+ *
+ * @param t
+ * in range [0,1]
+ * @return two QuadraticCurve objects constituting the original curve: 1.
+ * [0, t] 2. [t, 1]
+ */
+ public QuadraticCurve[] split(double t) {
+ if (t < 0 || t > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t is out of range! t = " + t + " !in_range(0,1)");
+ }
+
+ Point left1 = ratioPoint(getP1(), getCtrl(), t);
+ Point right1 = ratioPoint(getCtrl(), getP2(), t);
+ Point split = ratioPoint(left1, right1, t);
+
+ QuadraticCurve left = new QuadraticCurve(getP1(), left1, split);
+ QuadraticCurve right = new QuadraticCurve(split, right1, getP2());
+
+ return new QuadraticCurve[] { left, right };
+ }
+
+ /**
+ * Clips this {@link QuadraticCurve} at parameter values t1 and t2 so that
+ * the resulting {@link QuadraticCurve} is the section of the original
+ * {@link QuadraticCurve} for the parameter interval [t1, t2].
+ *
+ * @param t1
+ * @param t2
+ * @return the {@link QuadraticCurve} on the interval [t1, t2]
+ */
+ public QuadraticCurve clip(double t1, double t2) {
+ if (t1 < 0 || t1 > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t1 is out of range! t1 = " + t1
+ + " !in_range(0,1)");
+ }
+ if (t2 < 0 || t2 > 1) {
+ throw new IllegalArgumentException(
+ "Paramter t2 is out of range! t2 = " + t2
+ + " !in_range(0,1)");
+ }
+
+ QuadraticCurve right = split(t1)[1];
+ double rightT2 = (t2 - t1) / (1 - t1);
+ return right.split(rightT2)[0];
+ }
+
}
Index: src/org/eclipse/gef4/geometry/shapes/Rectangle.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/shapes/Rectangle.java,v
retrieving revision 1.10
diff -u -r1.10 Rectangle.java
--- src/org/eclipse/gef4/geometry/shapes/Rectangle.java 20 Oct 2011 21:04:44 -0000 1.10
+++ src/org/eclipse/gef4/geometry/shapes/Rectangle.java 21 Oct 2011 12:49:29 -0000
@@ -12,6 +12,7 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.shapes;
+import org.eclipse.gef4.geometry.Angle;
import org.eclipse.gef4.geometry.Dimension;
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.transform.AffineTransform;
@@ -171,9 +172,8 @@
public boolean contains(double x, double y, double width, double height) {
return PrecisionUtils.smallerEqual(this.x, x)
&& PrecisionUtils.smallerEqual(this.y, y)
- && PrecisionUtils.greaterEqual(this.x + this.width, x + width)
- && PrecisionUtils
- .greaterEqual(this.y + this.height, y + height);
+ && PrecisionUtils.greaterEqual(this.width, width)
+ && PrecisionUtils.greaterEqual(this.height, height);
}
/**
@@ -264,13 +264,13 @@
* and height of the given Insets, and returns this for convenience.
*
* @param left
- * - the amount to shrink the left side
+ * - the amount to expand the left side
* @param top
- * - the amount to shrink the top side
+ * - the amount to expand the top side
* @param right
- * - the amount to shrink the right side
+ * - the amount to expand the right side
* @param bottom
- * - the amount to shrink the bottom side
+ * - the amount to expand the bottom side
* @return this
Rectangle for convenience
*
*/
@@ -492,6 +492,42 @@
}
/**
+ * Rotates this {@link Rectangle} clock-wise by the given {@link Angle}
+ * alpha around the {@link Point} center.
+ *
+ * If the rotation {@link Angle} is not an integer multiple 90°, the
+ * resulting figure cannot be expressed as a {@link Rectangle} object.
+ * That's why this method returns a {@link Polygon} instead.
+ *
+ * @param alpha
+ * the rotation angle
+ * @param center
+ * the center point of the rotation
+ * @return the rotated rectangle ({@link Polygon})
+ */
+ public Polygon getRotatedCW(Angle alpha, Point center) {
+ return toPolygon().rotateCW(alpha, center);
+ }
+
+ /**
+ * Rotates this {@link Rectangle} counter-clock-wise by the given
+ * {@link Angle} alpha around the {@link Point} center.
+ *
+ * If the rotation {@link Angle} is not an integer multiple 90°, the
+ * resulting figure cannot be expressed as a {@link Rectangle} object.
+ * That's why this method returns a {@link Polygon} instead.
+ *
+ * @param alpha
+ * the rotation angle
+ * @param center
+ * the center point of the rotation
+ * @return the rotated rectangle ({@link Polygon})
+ */
+ public Polygon getRotatedCCW(Angle alpha, Point center) {
+ return toPolygon().rotateCCW(alpha, center);
+ }
+
+ /**
* Returns a new Rectangle, where the sides are shrinked by the horizontal
* and vertical values supplied. The center of this Rectangle is kept
* constant.
@@ -500,7 +536,7 @@
* Horizontal reduction amount
* @param v
* Vertical reduction amount
- * @return this
for convenience
+ * @return the new, shrinked {@link Rectangle}
*/
public Rectangle getShrinked(double h, double v) {
return getCopy().shrink(h, v);
Index: src/org/eclipse/gef4/geometry/utils/PolynomCalculations.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/utils/PolynomCalculations.java
diff -N src/org/eclipse/gef4/geometry/utils/PolynomCalculations.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/utils/PolynomCalculations.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry.utils;
+
+/**
+ * Utility class that implements common polynom calculations such as finding the
+ * roots of polynoms of degree 2 or 3.
+ *
+ * @author wienand
+ *
+ */
+public final class PolynomCalculations {
+ /**
+ * Solves a linear polynomial equation of the form a*x + b = 0.
+ *
+ * @param a
+ * the coefficient of x^1
+ * @param b
+ * the absolute element
+ * @return the roots of this polynom
+ */
+ public static final double[] getLinearRoots(double a, double b) {
+ if (a == 0) {
+ if (b == 0) {
+ throw new ArithmeticException(
+ "The given polynomial equation is always true.");
+ }
+ return new double[] {};
+ }
+ return new double[] { -b / a };
+ }
+
+ /**
+ * Solves a quadratic polynomial equation of the form a*x^2 + b*x + c = 0.
+ *
+ * @param a
+ * @param b
+ * @param c
+ * @return all real solutions of the given equation. An empty array in the
+ * case of no solutions.
+ */
+ public static final double[] getQuadraticRoots(double a, double b, double c) {
+ if (a == 0) {
+ return getLinearRoots(b, c);
+ }
+
+ // p-q-formula
+ double p = b / a;
+ double q = c / a;
+ double D = p * p / 4 - q;
+
+ if (PrecisionUtils.equal(D, 0, +4)) {
+ return new double[] { -p / 2 };
+ } else if (D > 0) {
+ double sqrt = Math.sqrt(D);
+ return new double[] { sqrt - p / 2, -sqrt - p / 2 };
+ } else {
+ return new double[] {};
+ }
+ }
+
+ /**
+ * Solves a cubic polynomial equation of the form Ax^3 + Bx^2 + Cx + D = 0.
+ *
+ * @param A
+ * @param B
+ * @param C
+ * @param D
+ * @return all real solutions of the given equation
+ */
+ public static final double[] getCubicRoots(double A, double B, double C,
+ double D) {
+ if (A == 0) {
+ return getQuadraticRoots(B, C, D);
+ }
+
+ double a = B / A;
+ double b = C / A;
+ double c = D / A;
+
+ // reduce to z^3 + pz + q = 0 by substituting x = z - a/3
+ // (http://en.wikipedia.org/wiki/Cubic_function#Cardano.27s_method)
+
+ double p = b - a * a / 3;
+ double q = 2 * a * a * a / 27 - a * b / 3 + c;
+
+ // short-cuts for p = 0, q = 0:
+ if (PrecisionUtils.equal(p, 0, +4)) {
+ // z^3 = -q => z = cbrt(-q) => x = cbrt(-q) - a / 3
+ return new double[] { Math.cbrt(-q) - a / 3 };
+ }
+ if (PrecisionUtils.equal(q, 0, +4)) {
+ // z^3 - pz = 0 <=> z(z^2 - p) = 0 => z = 0 v z^2 = p => z =
+ // +-sqrt(p), p >= 0 (p is not zero, because otherwise we would not
+ // be here)
+ if (p > 0) {
+ return new double[] { 0, Math.sqrt(p), -Math.sqrt(p) };
+ } else {
+ return new double[] { 0 };
+ }
+ }
+
+ double p_3 = p / 3;
+ double q_2 = q / 2;
+
+ D = q_2 * q_2 + p_3 * p_3 * p_3;
+
+ if (PrecisionUtils.equal(D, 0, +4)) {
+ // two real solutions
+ return new double[] { 3 * q / p - a / 3, -3 * q / (2 * p) - a / 3 };
+ } else if (D > 0) {
+ // one real solution
+ double u = Math.cbrt(-q_2 + Math.sqrt(D));
+ double v = Math.cbrt(-q_2 - Math.sqrt(D));
+
+ return new double[] { u + v - a / 3 };
+ } else {
+ // three real solutions
+ double r = Math.sqrt(-p_3 * p_3 * p_3);
+ double phi = Math.acos(-q / (2 * r));
+ double co = 2 * Math.cbrt(r);
+
+ // co * cos((phi + k * pi)/3) - a/3, k = 2n, n in N
+ return new double[] { co * Math.cos(phi / 3) - a / 3,
+ co * Math.cos((phi + 2 * Math.PI) / 3) - a / 3,
+ co * Math.cos((phi + 4 * Math.PI) / 3) - a / 3 };
+ }
+ }
+}
Index: src/org/eclipse/gef4/geometry/utils/PrecisionUtils.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry/src/org/eclipse/gef4/geometry/utils/PrecisionUtils.java,v
retrieving revision 1.4
diff -u -r1.4 PrecisionUtils.java
--- src/org/eclipse/gef4/geometry/utils/PrecisionUtils.java 20 Oct 2011 21:14:19 -0000 1.4
+++ src/org/eclipse/gef4/geometry/utils/PrecisionUtils.java 21 Oct 2011 12:49:31 -0000
@@ -11,8 +11,6 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.utils;
-import java.math.BigDecimal;
-
/**
* A utility class for floating point calculations and comparisons that should
* guarantee a precision of a given scale, and ignore differences beyond this
@@ -27,104 +25,152 @@
* converting to 8 digits scale, so there are no undesired rounding effects
* beyond this precision.
*/
- private static final int ROUNDING_MODE = BigDecimal.ROUND_DOWN;
- private static final int SCALE = 8;
- private static final double FRACTION = 1 / Math.pow(10, SCALE);
+ private static final int DEFAULT_SCALE = 6;
+
+ private static final double calculateFraction(int shift) {
+ return 1 / Math.pow(10, DEFAULT_SCALE + shift);
+ }
+
+ /**
+ * @see PrecisionUtils#equal(double, double, int)
+ * @param d1
+ * @param d2
+ * @return result of the comparison
+ */
+ public static final boolean equal(double d1, double d2) {
+ return equal(d1, d2, 0);
+ }
/**
* Tests whether the two values are regarded to be equal w.r.t. the given
- * scale.
+ * shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
+ * @param shift
+ * the delta shift used for this test
* @return true
in case the given two values are identical or
* differ from each other by an amount that is smaller than what is
- * recognizable by the given scale, false
otherwise
+ * recognizable by the shifted delta, false
otherwise
*/
- public static final boolean equal(double d1, double d2) {
- return round(d1) == round(d2);
+ public static final boolean equal(double d1, double d2, int shift) {
+ return Math.abs(d1 - d2) <= calculateFraction(shift);
+ }
+
+ /**
+ * @see PrecisionUtils#greater(double, double, int)
+ * @param d1
+ * @param d2
+ * @return result of the comparison
+ */
+ public static final boolean greater(double d1, double d2) {
+ return greater(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be greater than the
- * second value w.r.t. the given scale.
+ * second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
+ * @param shift
+ * the delta shift used for this test
* @return true
in case the first value is greater than the
- * second value by an amount recognizable by the given scale,
+ * second value by an amount recognizable by the shifted delta,
* false
otherwise
*/
- public static final boolean greater(double d1, double d2) {
- return round(d1) > round(d2);
+ public static final boolean greater(double d1, double d2, int shift) {
+ return d1 + calculateFraction(shift) > d2;
+ }
+
+ /**
+ * @see PrecisionUtils#greaterEqual(double, double, int)
+ * @param d1
+ * @param d2
+ * @return result of the comparison
+ */
+ public static final boolean greaterEqual(double d1, double d2) {
+ return greaterEqual(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be greater or equal
- * than the second value w.r.t. the given scale.
+ * than the second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
+ * @param shift
+ * the delta shift used for this test
* @return true
in case the first value is greater than the
* second value by an amount recognizable by the given scale or
- * differs from it by an amount not recognizable by the given scale,
- * false
otherwise
+ * differs from it by an amount not recognizable by the shifted
+ * delta, false
otherwise
*/
- public static final boolean greaterEqual(double d1, double d2) {
- return round(d1) >= round(d2);
+ public static final boolean greaterEqual(double d1, double d2, int shift) {
+ return d1 + calculateFraction(shift) >= d2;
}
/**
- * Rounds the given value w.r.t. to the given scale.
- *
- * @param d
- * the value to round
- * @return a rounded value that represents the recognizable fraction of the
- * given value w.r.t. the given scale
- */
- public static double round(double d) {
- return BigDecimal
- .valueOf(d < 0 ? d - 0.05 * FRACTION : d + 0.05 * FRACTION)
- .setScale(SCALE, ROUNDING_MODE).doubleValue();
+ * @see PrecisionUtils#smaller(double, double, int)
+ * @param d1
+ * @param d2
+ * @return result of the comparison
+ */
+ public static final boolean smaller(double d1, double d2) {
+ return smaller(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be smaller than the
- * second value w.r.t. the given scale.
+ * second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
+ * @param shift
+ * the delta shift used for this test
* @return true
in case the first value is smaller than the
- * second value by an amount recognizable by the given scale,
+ * second value by an amount recognizable by the shifted delta,
* false
otherwise
*/
- public static final boolean smaller(double d1, double d2) {
- return round(d1) < round(d2);
+ public static final boolean smaller(double d1, double d2, int shift) {
+ return d1 < d2 + calculateFraction(shift);
+ }
+
+ /**
+ * @see PrecisionUtils#smallerEqual(double, double, int)
+ * @param d1
+ * @param d2
+ * @return result of the comparison
+ */
+ public static final boolean smallerEqual(double d1, double d2) {
+ return smallerEqual(d1, d2, 0);
}
/**
* Tests whether the first given value is regarded to be smaller or equal
- * than the second value w.r.t. the given scale.
+ * than the second value w.r.t. the given shift.
*
* @param d1
* the first value to test
* @param d2
* the second value to test
+ * @param shift
+ * the delta shift used for this test
* @return true
in case the first value is smaller than the
* second value by an amount recognizable by the given scale or
- * differs from it by an amount not recognizable by the given scale,
- * false
otherwise
+ * differs from it by an amount not recognizable by the shifted
+ * delta, false
otherwise
*/
- public static final boolean smallerEqual(double d1, double d2) {
- return round(d1) <= round(d2);
+ public static final boolean smallerEqual(double d1, double d2, int shift) {
+ return d1 <= d2 + calculateFraction(shift);
}
private PrecisionUtils() {
#P org.eclipse.gef4.geometry.tests
Index: src/org/eclipse/gef4/geometry/tests/AllTests.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/AllTests.java,v
retrieving revision 1.1
diff -u -r1.1 AllTests.java
--- src/org/eclipse/gef4/geometry/tests/AllTests.java 30 Aug 2011 20:43:48 -0000 1.1
+++ src/org/eclipse/gef4/geometry/tests/AllTests.java 21 Oct 2011 12:49:32 -0000
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * itemis AG - initial API and implementation
+ * Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef4.geometry.tests;
@@ -16,10 +16,12 @@
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
-@SuiteClasses({ PrecisionUtilsTest.class, PointTests.class,
- DimensionTests.class, LineTests.class, RectangleTests.class,
- VectorTests.class, StraightTests.class, PolylineTests.class,
- PolygonTests.class, EllipseTests.class })
+@SuiteClasses({ CubicCurveTests.class, DimensionTests.class,
+ EllipseTests.class, LineTests.class, PointTests.class,
+ PolygonTests.class, PolylineTests.class,
+ PolynomCalculationsTests.class, PrecisionUtilsTest.class,
+ QuadraticCurveTests.class, RectangleTests.class, StraightTests.class,
+ VectorTests.class })
public class AllTests {
}
Index: src/org/eclipse/gef4/geometry/tests/CubicCurveTests.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/tests/CubicCurveTests.java
diff -N src/org/eclipse/gef4/geometry/tests/CubicCurveTests.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/tests/CubicCurveTests.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.gef4.geometry.Point;
+import org.eclipse.gef4.geometry.shapes.CubicCurve;
+
+public class CubicCurveTests extends TestCase {
+
+ private final Point p = new Point(-10, -10), c1 = new Point(0, -10),
+ c2 = new Point(10, 0), q = new Point(0, 10);
+
+ public void test_get() {
+ CubicCurve curve = new CubicCurve(p, c1, c2, q);
+
+ assertEquals("curve.get(0) returns the curve's start point", p,
+ curve.get(0));
+ assertEquals("curve.get(1) returns the curve's end point", q,
+ curve.get(1));
+
+ boolean thrown = false;
+ try {
+ curve.get(-0.1);
+ } catch (IllegalArgumentException x) {
+ thrown = true;
+ }
+ assertTrue("curve.get(t < 0) throws an IllegalArgumentException",
+ thrown);
+
+ thrown = false;
+ try {
+ curve.get(1.1);
+ } catch (IllegalArgumentException x) {
+ thrown = true;
+ }
+ assertTrue("curve.get(t > 1) throws an IllegalArgumentException",
+ thrown);
+ }
+
+ public void test_contains_Point() {
+ CubicCurve curve = new CubicCurve(p, c1, c2, q);
+
+ // check fix points:
+ assertEquals(true, curve.contains(p));
+ assertEquals(true, curve.contains(q));
+ assertEquals(false, curve.contains(c1)); // not always true, but for our
+ // c1 it is
+ assertEquals(false, curve.contains(c2)); // not always true, but for our
+ // c2 it is
+
+ // check 0 <= t <= 1:
+ for (double t = 0; t <= 1; t += 0.0123456789) {
+ assertEquals("curve.get(t = " + t
+ + " in range [0, 1]) lies on the curve", true,
+ curve.contains(curve.get(t)));
+ }
+ }
+
+ public void test_get_Bounds() {
+ CubicCurve curve = new CubicCurve(p, c1, c2, q);
+
+ // p is the top-left point: (y-coordinates are inverted)
+ assertEquals(curve.getBounds().getTopLeft(), p);
+ }
+
+}
Index: src/org/eclipse/gef4/geometry/tests/EllipseTests.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/EllipseTests.java,v
retrieving revision 1.3
diff -u -r1.3 EllipseTests.java
--- src/org/eclipse/gef4/geometry/tests/EllipseTests.java 31 Aug 2011 11:27:11 -0000 1.3
+++ src/org/eclipse/gef4/geometry/tests/EllipseTests.java 21 Oct 2011 12:49:32 -0000
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * itemis AG - initial API and implementation
+ * Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef4.geometry.tests;
@@ -76,4 +76,88 @@
assertTrue(e.intersects(l)); // line touches ellipse (tangent)
}
}
+
+ public void test_get_intersections_with_Ellipse() {
+ Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
+ Ellipse e1 = new Ellipse(r);
+ Ellipse e2 = new Ellipse(r);
+
+ // ellipses are identical = returns no intersections, user can check
+ // this via equals()
+ Point[] intersections = e1.getIntersections(e2);
+ assertEquals(0, intersections.length);
+
+ // if we create an x-scaled ellipse at the same position as before, they
+ // should have 3 poi (the touching point and two crossing intersections)
+ Rectangle r2 = r.getExpanded(0, 0, 100, 0);
+ e2 = new Ellipse(r2);
+ intersections = e1.getIntersections(e2);
+ assertEquals(3, intersections.length);
+
+ // if we create a y-scaled ellipse at the same position as before, they
+ // should have 3 poi (the touching point and two crossing intersections)
+ r2 = r.getExpanded(0, 0, 0, 100);
+ e2 = new Ellipse(r2);
+ intersections = e1.getIntersections(e2);
+ assertEquals(3, intersections.length);
+
+ // if we create an x-scaled ellipse at the same y-position as before,
+ // the
+ // two should touch at two positions:
+ r2 = r.getExpanded(50, 0, 50, 0);
+ e2 = new Ellipse(r2);
+ intersections = e1.getIntersections(e2);
+ assertEquals(2, intersections.length);
+
+ // the two poi are top and bottom border mid-points:
+ int equalsTop = 0;
+ int equalsBottom = 0;
+
+ Rectangle bounds = e1.getBounds();
+ for (Point poi : intersections) {
+ // we need to losen the equality test, because the points of
+ // intersection may be to unprecise
+ Point top = bounds.getTop();
+ if (top.equals(poi)) {
+ equalsTop++;
+ }
+ if (bounds.getBottom().equals(poi)) {
+ equalsBottom++;
+ }
+ }
+
+ assertEquals(
+ "The top border mid-point should be one of the two intersections.",
+ 1, equalsTop);
+ assertEquals(
+ "The bottom border mid-point should be one of the two intersections.",
+ 1, equalsBottom);
+
+ // if we create a y-scaled ellipse at the same x-position as before, the
+ // two should touch at two positions:
+ r2 = r.getExpanded(0, 50, 0, 50);
+ e2 = new Ellipse(r2);
+ intersections = e1.getIntersections(e2);
+ assertEquals(2, intersections.length);
+
+ // the two poi are left and right border mid-points:
+ int equalsLeft = 0;
+ int equalsRight = 0;
+
+ for (Point poi : intersections) {
+ if (bounds.getLeft().equals(poi)) {
+ equalsLeft++;
+ }
+ if (bounds.getRight().equals(poi)) {
+ equalsRight++;
+ }
+ }
+
+ assertEquals(
+ "The left border mid-point should be one of the two intersections.",
+ 1, equalsLeft);
+ assertEquals(
+ "The right border mid-point should be one of the two intersections.",
+ 1, equalsRight);
+ }
}
Index: src/org/eclipse/gef4/geometry/tests/PolynomCalculationsTests.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/tests/PolynomCalculationsTests.java
diff -N src/org/eclipse/gef4/geometry/tests/PolynomCalculationsTests.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/tests/PolynomCalculationsTests.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry.tests;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.eclipse.gef4.geometry.utils.PolynomCalculations;
+import org.eclipse.gef4.geometry.utils.PrecisionUtils;
+
+public class PolynomCalculationsTests extends TestCase {
+
+ public void test_get_roots_always_true() {
+ try {
+ PolynomCalculations.getLinearRoots(0, 0);
+ } catch (ArithmeticException x) {
+ assertTrue("0x + 0 = 0 throws an ArithmeticException", true);
+ }
+
+ try {
+ PolynomCalculations.getQuadraticRoots(0, 0, 0);
+ } catch (ArithmeticException x) {
+ assertTrue("0x^2 + 0x + 0 = 0 throws an ArithmeticException", true);
+ }
+
+ try {
+ PolynomCalculations.getCubicRoots(0, 0, 0, 0);
+ } catch (ArithmeticException x) {
+ assertTrue(
+ "0x^3 + 0x^2 + 0x + 0 = 0 throws an ArithmeticException",
+ true);
+ }
+ }
+
+ public void test_get_linear_roots() {
+ double[] solutions = PolynomCalculations.getLinearRoots(1, 0);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x = 0", PrecisionUtils.equal(0, solutions[0]));
+
+ solutions = PolynomCalculations.getLinearRoots(0, 1);
+ assertEquals("1 != 0", 0, solutions.length);
+
+ solutions = PolynomCalculations.getLinearRoots(1, -2);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x - 2 = 0 <=> x = 2", PrecisionUtils.equal(2, solutions[0]));
+
+ solutions = PolynomCalculations.getLinearRoots(7, -7);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("7x - 7 = 0 <=> x = 1",
+ PrecisionUtils.equal(1, solutions[0]));
+
+ solutions = PolynomCalculations.getLinearRoots(0.5, -10);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("0.5x - 10 = 0 <=> x = 20",
+ PrecisionUtils.equal(20, solutions[0]));
+
+ solutions = PolynomCalculations.getLinearRoots(5, -0.5);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("5x - 0.5 = 0 <=> x = 0.1",
+ PrecisionUtils.equal(0.1, solutions[0]));
+
+ solutions = PolynomCalculations.getLinearRoots(1, 1);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x + 1 = 0 <=> x = -1",
+ PrecisionUtils.equal(-1, solutions[0]));
+ }
+
+ public void test_get_quadratic_roots() {
+ double[] solutions = PolynomCalculations.getQuadraticRoots(1, 1, 0);
+ Arrays.sort(solutions);
+ assertEquals("two real solution", 2, solutions.length);
+ assertTrue("x^2 + x = 0 <=> x(x + 1) = 0 => x = 0 v x = -1",
+ PrecisionUtils.equal(-1, solutions[0]));
+ assertTrue("x^2 + x + 0 = 0 <=> x(x + 1) = 0 => x = 0 v x = -1",
+ PrecisionUtils.equal(0, solutions[1]));
+
+ solutions = PolynomCalculations.getQuadraticRoots(1, 0, 1);
+ assertEquals("x^2 + 1 = 0 => no real solutions", 0, solutions.length);
+
+ solutions = PolynomCalculations.getQuadraticRoots(1, 0, -1);
+ Arrays.sort(solutions);
+ assertEquals("two real solution", 2, solutions.length);
+ assertTrue("x^2 - 1 = 0 => x = +-1",
+ PrecisionUtils.equal(-1, solutions[0]));
+ assertTrue("x^2 - 1 = 0 => x = +-1",
+ PrecisionUtils.equal(1, solutions[1]));
+
+ solutions = PolynomCalculations.getQuadraticRoots(1, 0, 0);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x^2 = 0 <=> x = 0", PrecisionUtils.equal(0, solutions[0]));
+
+ solutions = PolynomCalculations.getQuadraticRoots(0, 1, 0);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x = 0", PrecisionUtils.equal(0, solutions[0]));
+
+ solutions = PolynomCalculations.getQuadraticRoots(2, 0, -8);
+ Arrays.sort(solutions);
+ assertEquals("two real solution", 2, solutions.length);
+ assertTrue("2x^2 - 8 = 0 <=> x^2 = 4 => x = +-2",
+ PrecisionUtils.equal(-2, solutions[0]));
+ assertTrue("2x^2 - 8 = 0 <=> x^2 = 4 => x = +-2",
+ PrecisionUtils.equal(2, solutions[1]));
+
+ solutions = PolynomCalculations.getQuadraticRoots(1, -3, 2);
+ Arrays.sort(solutions);
+ assertEquals("two real solution", 2, solutions.length);
+ assertTrue("x^2 - 3x + 2 = 0 <=> (x - 2)(x - 1) = 0 => x = 2 v x = 1",
+ PrecisionUtils.equal(1, solutions[0]));
+ assertTrue("x^2 - 3x + 2 = 0 <=> (x - 2)(x - 1) = 0 => x = 2 v x = 1",
+ PrecisionUtils.equal(2, solutions[1]));
+ }
+
+ public void test_get_cubic_roots() {
+ double[] solutions = PolynomCalculations.getCubicRoots(1, 1, 1, 0);
+ Arrays.sort(solutions);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x^3 + x^2 + x = 0 <=> x(x^2 + x + 1) = 0 => x = 0",
+ PrecisionUtils.equal(0, solutions[0]));
+
+ solutions = PolynomCalculations.getCubicRoots(1, -6, 12, -8);
+ assertEquals("one real solution", 1, solutions.length);
+ assertTrue("x = 2 solves the polynom",
+ PrecisionUtils.equal(2, solutions[0]));
+
+ solutions = PolynomCalculations.getCubicRoots(1, 1, -33, 63);
+ Arrays.sort(solutions);
+ assertEquals("two real solutions", 2, solutions.length);
+ assertTrue("x1 = -7", PrecisionUtils.equal(-7, solutions[0]));
+ assertTrue("x2 = 3", PrecisionUtils.equal(3, solutions[1]));
+
+ solutions = PolynomCalculations.getCubicRoots(1, 3, -6, -1);
+ Arrays.sort(solutions);
+ assertEquals("three real solutions", 3, solutions.length);
+ assertTrue("x1 = -4.33181031",
+ PrecisionUtils.equal(-4.331810310203, solutions[0]));
+ assertTrue("x2 = -0.15524041",
+ PrecisionUtils.equal(-0.15524041215, solutions[1]));
+ assertTrue("x3 = 1.48705072",
+ PrecisionUtils.equal(1.487050722353, solutions[2]));
+ }
+}
Index: src/org/eclipse/gef4/geometry/tests/PolynomTests.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/tests/PolynomTests.java
diff -N src/org/eclipse/gef4/geometry/tests/PolynomTests.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/tests/PolynomTests.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry.tests;
+
+import junit.framework.TestCase;
+
+public class PolynomTests extends TestCase {
+ public void test_getNearest() {
+ assertTrue("nyi", false);
+ }
+}
Index: src/org/eclipse/gef4/geometry/tests/PrecisionUtilsTest.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/PrecisionUtilsTest.java,v
retrieving revision 1.3
diff -u -r1.3 PrecisionUtilsTest.java
--- src/org/eclipse/gef4/geometry/tests/PrecisionUtilsTest.java 23 Sep 2011 14:44:46 -0000 1.3
+++ src/org/eclipse/gef4/geometry/tests/PrecisionUtilsTest.java 21 Oct 2011 12:49:33 -0000
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * itemis AG - initial API and implementation
+ * Alexander Nyßen (itemis AG) - initial API and implementation
*******************************************************************************/
package org.eclipse.gef4.geometry.tests;
@@ -26,6 +26,12 @@
private static final double PRECISION_FRACTION = TestUtils
.getPrecisionFraction();
+ private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ - PRECISION_FRACTION / 10;
+
+ private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ + PRECISION_FRACTION / 10;
+
/**
* Tests the precision tolerance of
* {@link PrecisionUtils#equal(double, double)}, by checking whether two
@@ -36,34 +42,79 @@
public void test_equal() {
// test equality is recognized in case we increase/decrease beyond the
// given scale
- double d1 = -9.486614173228347;
- double d2 = -34.431496062992125;
- double d3 = 41.99055118110236;
- double d4 = 25.92755905511811;
+ double d1 = -9.48661417322834712;
+ double d2 = -34.431496062992123985;
+ double d3 = 41.99055118110236626;
+ double d4 = 25.927559055118116565;
double d5 = Double.MIN_VALUE;
double d6 = 1 - d5;
- assertTrue(PrecisionUtils.equal(d1, d1 - PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d2, d2 - PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d3, d3 - PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d4, d4 - PRECISION_FRACTION / 10));
-
- assertTrue(PrecisionUtils.equal(d1, d1 + PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d2, d2 + PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d3, d3 + PRECISION_FRACTION / 10));
- assertTrue(PrecisionUtils.equal(d4, d4 + PRECISION_FRACTION / 10));
-
- assertFalse(PrecisionUtils.equal(d1, d1 - PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d2, d2 - PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d3, d3 - PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d4, d4 - PRECISION_FRACTION));
-
- assertFalse(PrecisionUtils.equal(d1, d1 + PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d2, d2 + PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d3, d3 + PRECISION_FRACTION));
- assertFalse(PrecisionUtils.equal(d4, d4 + PRECISION_FRACTION));
+ assertTrue(PrecisionUtils.equal(d1, d1 - UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d2, d2 - UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d3, d3 - UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d4, d4 - UNRECOGNIZABLE_FRACTION));
+
+ assertTrue(PrecisionUtils.equal(d1, d1 + UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d2, d2 + UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d3, d3 + UNRECOGNIZABLE_FRACTION));
+ assertTrue(PrecisionUtils.equal(d4, d4 + UNRECOGNIZABLE_FRACTION));
+
+ assertFalse(PrecisionUtils.equal(d1, d1 - RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d2, d2 - RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d3, d3 - RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d4, d4 - RECOGNIZABLE_FRACTION));
+
+ assertFalse(PrecisionUtils.equal(d1, d1 + RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d2, d2 + RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d3, d3 + RECOGNIZABLE_FRACTION));
+ assertFalse(PrecisionUtils.equal(d4, d4 + RECOGNIZABLE_FRACTION));
+ }
+
+ public void test_greater() {
+ double unrec = UNRECOGNIZABLE_FRACTION;
+
+ assertTrue(PrecisionUtils.greater(1, 0));
+ assertTrue(PrecisionUtils.greater(RECOGNIZABLE_FRACTION, 0));
+ assertTrue(PrecisionUtils.greater(unrec, 0));
+ assertTrue(PrecisionUtils.greater(0, 0));
+ assertTrue(PrecisionUtils.greater(-unrec, 0));
+ assertTrue(PrecisionUtils.greater(unrec - PRECISION_FRACTION, 0));
+ assertFalse(PrecisionUtils.greater(-1, 0));
+ assertFalse(PrecisionUtils.greater(-PRECISION_FRACTION, 0));
+ }
+
+ public void test_smaller() {
+ double unrec = UNRECOGNIZABLE_FRACTION;
+
+ assertTrue(PrecisionUtils.smaller(-1, 0));
+ assertTrue(PrecisionUtils.smaller(-PRECISION_FRACTION, 0));
+ assertTrue(PrecisionUtils.smaller(-unrec, 0));
+ assertTrue(PrecisionUtils.smaller(0, 0));
+ assertTrue(PrecisionUtils.smaller(unrec, 0));
+ assertTrue(PrecisionUtils.smaller(PRECISION_FRACTION - unrec, 0));
+ assertFalse(PrecisionUtils.smaller(1, 0));
+ assertFalse(PrecisionUtils.smaller(PRECISION_FRACTION, 0));
+ }
+
+ public void test_greaterEqual() {
+ double unrec = UNRECOGNIZABLE_FRACTION;
+
+ assertTrue(PrecisionUtils.greaterEqual(1, 0));
+ assertTrue(PrecisionUtils.greaterEqual(0, 0));
+ assertTrue(PrecisionUtils.greaterEqual(-unrec, 0));
+ assertTrue(PrecisionUtils.greaterEqual(-PRECISION_FRACTION, 0));
+ assertFalse(PrecisionUtils.greaterEqual(-1, 0));
+ assertFalse(PrecisionUtils.greaterEqual(-PRECISION_FRACTION - unrec, 0));
+ }
+
+ public void test_smallerEqual() {
+ double unrec = UNRECOGNIZABLE_FRACTION;
- assertEquals(0, PrecisionUtils.round(d5), 0);
- assertEquals(1, PrecisionUtils.round(d6), 0);
+ assertTrue(PrecisionUtils.smallerEqual(-1, 0));
+ assertTrue(PrecisionUtils.smallerEqual(0, 0));
+ assertTrue(PrecisionUtils.smallerEqual(unrec, 0));
+ assertTrue(PrecisionUtils.smallerEqual(PRECISION_FRACTION, 0));
+ assertFalse(PrecisionUtils.smallerEqual(1, 0));
+ assertFalse(PrecisionUtils.smallerEqual(PRECISION_FRACTION + unrec, 0));
}
}
Index: src/org/eclipse/gef4/geometry/tests/QuadraticCurveTests.java
===================================================================
RCS file: src/org/eclipse/gef4/geometry/tests/QuadraticCurveTests.java
diff -N src/org/eclipse/gef4/geometry/tests/QuadraticCurveTests.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/gef4/geometry/tests/QuadraticCurveTests.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Matthias Wienand (itemis AG) - initial API and implementation
+ *
+ *******************************************************************************/
+package org.eclipse.gef4.geometry.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.gef4.geometry.Point;
+import org.eclipse.gef4.geometry.shapes.QuadraticCurve;
+
+public class QuadraticCurveTests extends TestCase {
+ private final Point p = new Point(-10, -10), c = new Point(10, 0),
+ q = new Point(0, 10);
+
+ public void test_get() {
+ QuadraticCurve curve = new QuadraticCurve(p, c, q);
+
+ assertEquals("curve.get(0) returns the curve's start point", p,
+ curve.get(0));
+ assertEquals("curve.get(1) returns the curve's end point", q,
+ curve.get(1));
+
+ boolean thrown = false;
+ try {
+ curve.get(-0.1);
+ } catch (IllegalArgumentException x) {
+ thrown = true;
+ }
+ assertTrue("curve.get(t < 0) throws an IllegalArgumentException",
+ thrown);
+
+ thrown = false;
+ try {
+ curve.get(1.1);
+ } catch (IllegalArgumentException x) {
+ thrown = true;
+ }
+ assertTrue("curve.get(t > 1) throws an IllegalArgumentException",
+ thrown);
+ }
+
+ public void test_contains_Point() {
+ QuadraticCurve curve = new QuadraticCurve(p, c, q);
+
+ // check fix points:
+ assertEquals(curve.contains(p), true);
+ assertEquals(curve.contains(q), true);
+ assertEquals(curve.contains(c), false); // not always true, but for our
+ // c it is
+
+ // check 0 <= t <= 1:
+ for (double t = 0; t <= 1; t += 0.0123456789) {
+ assertEquals("curve.get(t = " + t
+ + " in range [0, 1]) lies on the curve", true,
+ curve.contains(curve.get(t)));
+ }
+ }
+
+ public void test_get_Bounds() {
+ QuadraticCurve curve = new QuadraticCurve(p, c, q);
+
+ // p is the top-left point: (y-coordinates are inverted)
+ assertEquals(curve.getBounds().getTopLeft(), p);
+ }
+
+ // public void test_get_FatLine() {
+ // QuadraticCurve curve = new QuadraticCurve(p, c, p);
+ // assertEquals(null, curve.getFatLine());
+ // }
+
+ // public void test_clip_FatLine() {
+ // QuadraticCurve curve = new QuadraticCurve(p, c, q);
+ //
+ // // FatLine L = new FatLine(new Straight(new Vector(0, -5),
+ // // new Vector(1, 0)), -10, 0);
+ // // QuadraticCurve clipped = curve.clip(L);
+ // //
+ // // assertTrue("clipped curve's endpoints lie on the FatLine",
+ // // L.contains(clipped.getP1()));
+ // // assertTrue("clipped curve's endpoints lie on the FatLine",
+ // // L.contains(clipped.getP2()));
+ // //
+ // // L = new FatLine(new Straight(new Vector(100, 100), new Vector(100,
+ // 0)),
+ // // 0, 1);
+ // // clipped = curve.clip(L);
+ // // assertEquals(null, clipped);
+ // //
+ // // L = new FatLine(
+ // // new Straight(new Vector(-100, -100), new Vector(100, 0)), -200,
+ // // 0);
+ // // clipped = curve.clip(L);
+ // // assertEquals(curve, clipped);
+ // }
+
+ public void test_intersects_Line() {
+ // TODO!
+ }
+
+ public void test_intersects_Rectangle() {
+ // TODO!
+ }
+
+ public void test_getIntersections_QuadraticCurve() {
+ // some general cases
+ Point p1 = new Point(164.0, 43.0);
+ Point p2 = new Point(169.0, 165.0);
+ Point p3 = new Point(307.0, 239.0);
+ Point q1 = new Point(100.0, 100.0);
+ Point q2 = new Point(200.0, 200.0);
+ Point q3 = new Point(300.0, 100.0);
+
+ QuadraticCurve p = new QuadraticCurve(p1, p2, p3);
+ QuadraticCurve q = new QuadraticCurve(q1, q2, q3);
+
+ Point[] intersections = q.getIntersections(p);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ p1 = new Point(200.0, 100.0);
+ p2 = new Point(304.0, 203.0);
+ p3 = new Point(300.0, 300.0);
+
+ p = new QuadraticCurve(p1, p2, p3);
+
+ intersections = q.getIntersections(p);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ p1 = new Point(144.0, 59.0);
+ p2 = new Point(358.0, 130.0);
+ p3 = new Point(300.0, 300.0);
+
+ p = new QuadraticCurve(p1, p2, p3);
+
+ intersections = q.getIntersections(p);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ p1 = new Point(151.0, 272.0);
+ p2 = new Point(101.0, 187.0);
+ p3 = new Point(205.0, 48.0);
+
+ p = new QuadraticCurve(p1, p2, p3);
+
+ intersections = q.getIntersections(p);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ p1 = new Point(184.0, 83.0);
+ p2 = new Point(400.0, 200.0);
+ p3 = new Point(300.0, 300.0);
+
+ p = new QuadraticCurve(p1, p2, p3);
+
+ intersections = p.getIntersections(q);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ p1 = new Point(196.0, 89.0);
+ p2 = new Point(335.0, 215.0);
+ p3 = new Point(300.0, 300.0);
+
+ p = new QuadraticCurve(p1, p2, p3);
+
+ intersections = q.getIntersections(p);
+ assertEquals("p and q have exactly one intersection", 1,
+ intersections.length);
+
+ for (Point poi : intersections) {
+ assertEquals("each point of intersection lies on p", true,
+ p.contains(poi));
+ assertEquals("each point of intersection lies on q", true,
+ q.contains(poi));
+ }
+
+ // special tangential cases
+ // TODO
+
+ // special
+ }
+}
Index: src/org/eclipse/gef4/geometry/tests/RectangleTests.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/RectangleTests.java,v
retrieving revision 1.2
diff -u -r1.2 RectangleTests.java
--- src/org/eclipse/gef4/geometry/tests/RectangleTests.java 31 Aug 2011 08:06:51 -0000 1.2
+++ src/org/eclipse/gef4/geometry/tests/RectangleTests.java 21 Oct 2011 12:49:34 -0000
@@ -31,6 +31,12 @@
private static final double PRECISION_FRACTION = TestUtils
.getPrecisionFraction();
+ private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ - PRECISION_FRACTION / 10;
+
+ private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ + PRECISION_FRACTION / 10;
+
public void testBorderPointsCalculation() {
Rectangle rect = new Rectangle(1, 2, 3, 4);
assertEquals(rect.getTopLeft(), new Point(1, 2));
@@ -87,49 +93,49 @@
assertTrue(preciseRect.contains(topLeft));
assertTrue(preciseRect.contains(topLeft.x, topLeft.y));
assertFalse(preciseRect.contains(topLeft.getTranslated(
- -PRECISION_FRACTION, -PRECISION_FRACTION)));
+ -RECOGNIZABLE_FRACTION, -RECOGNIZABLE_FRACTION)));
Point top = preciseRect.getTop();
assertTrue(preciseRect.contains(top));
assertTrue(preciseRect.contains(top.x, top.y));
assertFalse(preciseRect.contains(top.getTranslated(0,
- -PRECISION_FRACTION)));
+ -RECOGNIZABLE_FRACTION)));
Point topRight = preciseRect.getTopRight();
assertTrue(preciseRect.contains(topRight));
assertTrue(preciseRect.contains(topRight.x, topRight.y));
assertFalse(preciseRect.contains(topRight.getTranslated(
- PRECISION_FRACTION, -PRECISION_FRACTION)));
+ RECOGNIZABLE_FRACTION, -RECOGNIZABLE_FRACTION)));
Point left = preciseRect.getLeft();
assertTrue(preciseRect.contains(left));
assertTrue(preciseRect.contains(left.x, left.y));
assertFalse(preciseRect.contains(left.getTranslated(
- -PRECISION_FRACTION, 0)));
+ -RECOGNIZABLE_FRACTION, 0)));
Point right = preciseRect.getRight();
assertTrue(preciseRect.contains(right));
assertTrue(preciseRect.contains(right.x, right.y));
assertFalse(preciseRect.contains(right.getTranslated(
- PRECISION_FRACTION, 0)));
+ RECOGNIZABLE_FRACTION, 0)));
Point bottomLeft = preciseRect.getBottomLeft();
assertTrue(preciseRect.contains(bottomLeft));
assertTrue(preciseRect.contains(bottomLeft.x, bottomLeft.y));
assertFalse(preciseRect.contains(bottomLeft.getTranslated(
- -PRECISION_FRACTION, PRECISION_FRACTION)));
+ -RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
Point bottom = preciseRect.getBottom();
assertTrue(preciseRect.contains(bottom));
assertTrue(preciseRect.contains(bottom.x, bottom.y));
assertFalse(preciseRect.contains(bottom.getTranslated(0,
- PRECISION_FRACTION)));
+ RECOGNIZABLE_FRACTION)));
Point bottomRight = preciseRect.getBottomRight();
assertTrue(preciseRect.contains(bottomRight));
assertTrue(preciseRect.contains(bottomRight.x, bottomRight.y));
assertFalse(preciseRect.contains(bottomRight.getTranslated(
- PRECISION_FRACTION, PRECISION_FRACTION)));
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
}
public void test_contains_Rectangle() {
@@ -141,34 +147,34 @@
assertTrue(preciseRect.contains(preciseRect.getX(), preciseRect.getY(),
preciseRect.getWidth(), preciseRect.getHeight()));
assertFalse(preciseRect.contains(preciseRect.getExpanded(
- PRECISION_FRACTION, PRECISION_FRACTION)));
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
// test precision tolerance, therefore increment by an amount not
// 'recognizable'
- Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION / 10,
- PRECISION_FRACTION / 10, 0, 0);
- Rectangle shrinked = preciseRect.getShrinked(0, 0,
- PRECISION_FRACTION / 10, PRECISION_FRACTION / 10);
+
+ Rectangle unrecognizableExpanded = preciseRect.getExpanded(
+ UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION, 0, 0);
+ Rectangle unrecognizableShrinked = preciseRect.getShrinked(0, 0,
+ UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION);
+
// contains should not recognized the changes
- assertTrue(preciseRect.contains(expanded));
- assertTrue(preciseRect.contains(shrinked));
- assertTrue(expanded.contains(preciseRect));
- assertTrue(shrinked.contains(preciseRect));
- assertTrue(expanded.contains(shrinked));
- assertTrue(shrinked.contains(expanded));
+ assertTrue(preciseRect.contains(unrecognizableExpanded));
+ assertTrue(preciseRect.contains(unrecognizableShrinked));
+ assertTrue(unrecognizableExpanded.contains(preciseRect));
+ assertTrue(unrecognizableShrinked.contains(preciseRect));
+ assertTrue(unrecognizableExpanded.contains(unrecognizableShrinked));
// now increment by an amount 'recognizable'
- expanded = preciseRect.getExpanded(PRECISION_FRACTION,
- PRECISION_FRACTION, 0, 0);
- shrinked = preciseRect.getShrinked(0, 0, PRECISION_FRACTION,
- PRECISION_FRACTION);
+ Rectangle recognizableExpanded = preciseRect.getExpanded(
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION, 0, 0);
+ Rectangle recognizableShrinked = preciseRect.getShrinked(0, 0,
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
+
// contains should now recognized the changes
- assertFalse(preciseRect.contains(expanded));
- assertTrue(preciseRect.contains(shrinked));
- assertTrue(expanded.contains(preciseRect));
- assertFalse(shrinked.contains(preciseRect));
- assertTrue(expanded.contains(shrinked));
- assertFalse(shrinked.contains(expanded));
+ assertFalse(preciseRect.contains(recognizableExpanded));
+ assertTrue(recognizableExpanded.contains(preciseRect));
+ assertFalse(recognizableShrinked.contains(preciseRect));
+ assertFalse(recognizableShrinked.contains(recognizableExpanded));
}
public void test_equals() {
@@ -183,24 +189,23 @@
// test precision tolerance, therefore increment by an amount not
// 'recognizable'
- Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION / 10,
- PRECISION_FRACTION / 10, 0, 0);
- Rectangle shrinked = preciseRect.getShrinked(0, 0,
- PRECISION_FRACTION / 10, PRECISION_FRACTION / 10);
+ Rectangle unrecognizableExpanded = preciseRect.getExpanded(
+ UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION, 0, 0);
+ Rectangle unrecognizableShrinked = preciseRect.getShrinked(0, 0,
+ UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION);
// equals should not recognize the changes
- assertTrue(preciseRect.equals(expanded));
- assertTrue(preciseRect.equals(shrinked));
- assertTrue(expanded.equals(shrinked));
+ assertTrue(preciseRect.equals(unrecognizableExpanded));
+ assertTrue(preciseRect.equals(unrecognizableShrinked));
// increment by an amount 'recognizable'
- expanded = preciseRect.getExpanded(PRECISION_FRACTION,
- PRECISION_FRACTION, 0, 0);
- shrinked = preciseRect.getShrinked(0, 0, PRECISION_FRACTION,
- PRECISION_FRACTION);
+ Rectangle recognizableExpanded = preciseRect.getExpanded(
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION, 0, 0);
+ Rectangle recognizableShrinked = preciseRect.getShrinked(0, 0,
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
// equals should now recognize the changes
- assertFalse(preciseRect.equals(expanded));
- assertFalse(preciseRect.equals(shrinked));
- assertFalse(expanded.equals(shrinked));
+ assertFalse(preciseRect.equals(recognizableExpanded));
+ assertFalse(preciseRect.equals(recognizableShrinked));
+ assertFalse(recognizableExpanded.equals(recognizableShrinked));
}
public void test_scale() {
@@ -238,17 +243,19 @@
public void test_shrink_AND_expand() {
Rectangle preciseRect = new Rectangle(-9.486614173228347,
-34.431496062992125, 41.99055118110236, 25.92755905511811);
- Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION,
- PRECISION_FRACTION);
- Rectangle shrinked = preciseRect.getShrinked(PRECISION_FRACTION,
- PRECISION_FRACTION);
- assertFalse(preciseRect.equals(expanded));
- assertFalse(preciseRect.equals(shrinked));
- assertFalse(expanded.equals(shrinked));
- expanded.shrink(PRECISION_FRACTION, PRECISION_FRACTION);
- shrinked.expand(PRECISION_FRACTION, PRECISION_FRACTION);
- assertEquals(preciseRect, expanded);
- assertEquals(preciseRect, shrinked);
+ Rectangle recognizableExpanded = preciseRect.getExpanded(
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
+ Rectangle recognizableShrinked = preciseRect.getShrinked(
+ RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
+ assertFalse(preciseRect.equals(recognizableExpanded));
+ assertFalse(preciseRect.equals(recognizableShrinked));
+ assertFalse(recognizableExpanded.equals(recognizableShrinked));
+ recognizableExpanded.shrink(RECOGNIZABLE_FRACTION,
+ RECOGNIZABLE_FRACTION);
+ recognizableShrinked.expand(RECOGNIZABLE_FRACTION,
+ RECOGNIZABLE_FRACTION);
+ assertEquals(preciseRect, recognizableExpanded);
+ assertEquals(preciseRect, recognizableShrinked);
}
public void test_toSWTRectangle() {
Index: src/org/eclipse/gef4/geometry/tests/StraightTests.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/StraightTests.java,v
retrieving revision 1.1
diff -u -r1.1 StraightTests.java
--- src/org/eclipse/gef4/geometry/tests/StraightTests.java 30 Aug 2011 20:43:48 -0000 1.1
+++ src/org/eclipse/gef4/geometry/tests/StraightTests.java 21 Oct 2011 12:49:34 -0000
@@ -1,19 +1,21 @@
/*******************************************************************************
- * Copyright (c) 2010 IBM Corporation and others.
+ * Copyright (c) 2010 Research Group Software Construction,
+ * RWTH Aachen University 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:
- * Research Group Software Construction,
- * RWTH Aachen University, Germany - Contribution for Bugzilla 245182
+ * Alexander Nyßen (Research Group Software Construction,
+ * RWTH Aachen University) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef4.geometry.tests;
import junit.framework.TestCase;
+import org.eclipse.gef4.geometry.Angle;
import org.eclipse.gef4.geometry.Point;
import org.eclipse.gef4.geometry.euclidean.Straight;
import org.eclipse.gef4.geometry.euclidean.Vector;
@@ -93,11 +95,12 @@
public void test_getAngle_withStraight() {
Straight s1 = new Straight(new Vector(0, 0), new Vector(3, 3));
Straight s2 = new Straight(new Vector(0, 4), new Vector(2, 2));
- assertTrue(s1.getAngle(s2) == 0.0);
+ assertTrue(s1.getAngle(s2).equals(Angle.fromDeg(0)));
s1 = new Straight(new Vector(0, 0), new Vector(5, 5));
s2 = new Straight(new Vector(0, 5), new Vector(0, 5));
- assertTrue((float) s1.getAngle(s2) == 45.0); // rounding effects
+ assertTrue(s1.getAngle(s2).equals(Angle.fromDeg(45))); // rounding
+ // effects
}
public void test_equals() {
Index: src/org/eclipse/gef4/geometry/tests/TestUtils.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/TestUtils.java,v
retrieving revision 1.2
diff -u -r1.2 TestUtils.java
--- src/org/eclipse/gef4/geometry/tests/TestUtils.java 31 Aug 2011 08:06:51 -0000 1.2
+++ src/org/eclipse/gef4/geometry/tests/TestUtils.java 21 Oct 2011 12:49:34 -0000
@@ -11,7 +11,7 @@
*******************************************************************************/
package org.eclipse.gef4.geometry.tests;
-import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
@@ -27,16 +27,13 @@
// this class should not be instantiated by clients
}
- protected static double getPrecisionFraction() {
- return getPrecisionUtilsConstant("FRACTION");
- }
-
- private static double getPrecisionUtilsConstant(String name) {
- Field f;
+ public static double getPrecisionFraction() {
+ Method f;
try {
- f = PrecisionUtils.class.getDeclaredField(name);
+ f = PrecisionUtils.class.getDeclaredMethod("calculateFraction",
+ int.class);
f.setAccessible(true);
- return f.getDouble(PrecisionUtils.class);
+ return ((Double) f.invoke(PrecisionUtils.class, 0)).doubleValue();
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
Index: src/org/eclipse/gef4/geometry/tests/VectorTests.java
===================================================================
RCS file: /cvsroot/tools/org.eclipse.gef/GEF4/plugins/org.eclipse.gef4.geometry.tests/src/org/eclipse/gef4/geometry/tests/VectorTests.java,v
retrieving revision 1.3
diff -u -r1.3 VectorTests.java
--- src/org/eclipse/gef4/geometry/tests/VectorTests.java 31 Aug 2011 08:06:51 -0000 1.3
+++ src/org/eclipse/gef4/geometry/tests/VectorTests.java 21 Oct 2011 12:49:34 -0000
@@ -28,16 +28,21 @@
private static final double PRECISION_FRACTION = TestUtils
.getPrecisionFraction();
+ private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ - PRECISION_FRACTION / 10;
+ private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
+ + PRECISION_FRACTION / 10;
+
public void test_Equals() {
Vector a = new Vector(3, 2);
Vector b = new Vector(2, -2);
assertTrue(a.equals(a));
assertFalse(a.equals(b));
assertFalse(a.equals(new Point(3, 2)));
- assertTrue(a.equals(a.getAdded(new Vector(PRECISION_FRACTION / 10,
- PRECISION_FRACTION / 10))));
- assertFalse(a.equals(a.getAdded(new Vector(PRECISION_FRACTION,
- PRECISION_FRACTION))));
+ assertTrue(a.equals(a.getAdded(new Vector(UNRECOGNIZABLE_FRACTION / 10,
+ UNRECOGNIZABLE_FRACTION / 10))));
+ assertFalse(a.equals(a.getAdded(new Vector(RECOGNIZABLE_FRACTION,
+ RECOGNIZABLE_FRACTION))));
}
public void test_getLength() {