Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 205718 Details for
Bug 355997
[GEF4] Provide new Geometry-API
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
containment/intersection methods for the existing shapes and quadratic and cubic bézier curves with intersection methods
GEF4_additions_patch.txt (text/plain), 132.17 KB, created by
Matthias Wienand
on 2011-10-21 09:30:12 EDT
(
hide
)
Description:
containment/intersection methods for the existing shapes and quadratic and cubic bézier curves with intersection methods
Filename:
MIME Type:
Creator:
Matthias Wienand
Created:
2011-10-21 09:30:12 EDT
Size:
132.17 KB
patch
obsolete
>### 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 <code>true</code> 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<Point> intersections = new HashSet<Point>(); >+ >+ 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<Point> intersections = new HashSet<Point>(); >+ >+ 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<Point> intersections = new HashSet<Point>(); >+ >+ 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<Point> intersections = new HashSet<Point>(); >+ >+ 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<Point> intersections = new ArrayList<Point>(); >+ >+ 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<Point> intersections = new ArrayList<Point>(); >+ >+ 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<Point> intersections = new ArrayList<Point>(); >+ >+ 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<Point> intersections = new ArrayList<Point>(); >+ >+ 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 >+ * <ol> >+ * <li>translating this {@link Polygon} by the negated {@link Point} center</li> >+ * <li>rotating each {@link Point} of this {@link Polygon} clock-wise by the >+ * given {@link Angle} angle</li> >+ * <li>translating this {@link Polygon} back by the {@link Point} center</li> >+ * </ol> >+ * >+ * @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 >+ * <ol> >+ * <li>translating this {@link Polygon} by the negated {@link Point} center</li> >+ * <li>rotating each {@link Point} of this {@link Polygon} >+ * counter-clock-wise by the given {@link Angle} angle</li> >+ * <li>translating this {@link Polygon} back by the {@link Point} center</li> >+ * </ol> >+ * >+ * @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 >+ * <ol> >+ * <li>translating this {@link Polygon} by the negated center {@link Point}</li> >+ * <li>scaling the individual {@link Polygon} {@link Point}s</li> >+ * <li>translating this {@link Polygon} back</li> >+ * </ol> >+ * >+ * @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<Point> intersections = new HashSet<Point>(); >+ >+ 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<Point> intersections = new HashSet<Point>(); >+ >+ 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 <code>this</code> 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 <code>this</code> 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 <code>true</code> 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, <code>false</code> otherwise >+ * recognizable by the shifted delta, <code>false</code> 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 <code>true</code> 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, > * <code>false</code> 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 <code>true</code> 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, >- * <code>false</code> otherwise >+ * differs from it by an amount not recognizable by the shifted >+ * delta, <code>false</code> 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 <code>true</code> 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, > * <code>false</code> 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 <code>true</code> 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, >- * <code>false</code> otherwise >+ * differs from it by an amount not recognizable by the shifted >+ * delta, <code>false</code> 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() {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
nyssen
:
iplog+
Actions:
View
|
Diff
Attachments on
bug 355997
:
202484
|
202501
| 205718 |
206845
|
206852
|
207479
|
207484
|
208179
|
208923
|
212739
|
212771
|
212775
|
212776
|
213615
|
216278
|
216482
|
217706