View | Details | Raw Unified | Return to bug 355997 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/gef4/geometry/Angle.java (+214 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *     
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry;
13
14
import java.io.Serializable;
15
16
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
17
18
/**
19
 * An {@link Angle} object abstracts the angle's unit. It provides a simple
20
 * interface to construct it from degrees or from radians. Additionally, some
21
 * useful calculations are implemented, but for sine/cosine/tangent calculations
22
 * you may use the Math package.
23
 * 
24
 * The {@link AngleUnit} enumeration is used to differentiate between degrees
25
 * and radians. For the sake of simplicity, the methods that need to
26
 * differentiate between the angle's unit are available twice. Expecting degrees
27
 * or radians.
28
 * 
29
 * Every {@link Angle} object is normalized. That means, you will never
30
 * encounter an {@link Angle} object beyond 360°/2pi or below 0°/0.
31
 * 
32
 * @author Matthias Wienand
33
 */
34
public class Angle implements Cloneable, Serializable {
35
36
	/**
37
	 * The {@link Angle#Angle(double, AngleUnit)} constructor uses this
38
	 * enumeration to differentiate the unit of its first argument.
39
	 * 
40
	 * @author wienand
41
	 */
42
	public enum AngleUnit {
43
		/**
44
		 * Specifies that the angle is given in degrees. The range of an angle
45
		 * in degrees is from 0° to 360°.
46
		 */
47
		DEG,
48
49
		/**
50
		 * Specifies that the angle is given in radians. The range of an angle
51
		 * in radians is from 0 to 2pi.
52
		 */
53
		RAD,
54
	}
55
56
	private static final long serialVersionUID = 1L;
57
	private static final double DEG_TO_RAD = Math.PI / 180d;
58
	private static final double RAD_TO_DEG = 180d / Math.PI;
59
	private static final double RAD_180 = Math.PI;
60
	private static final double RAD_360 = 2 * Math.PI;
61
62
	/**
63
	 * Constructs a new {@link Angle} object representing the given value. The
64
	 * value is interpreted as being in degrees.
65
	 * 
66
	 * @param degrees
67
	 *            The angle in degrees.
68
	 * @return An {@link Angle} object representing the given degrees-angle.
69
	 */
70
	public static Angle fromDeg(double degrees) {
71
		return new Angle(degrees, AngleUnit.DEG);
72
	}
73
74
	/**
75
	 * Constructs a new {@link Angle} object representing the given value. The
76
	 * value is interpreted as being in radians.
77
	 * 
78
	 * @param radians
79
	 *            The angle in radians.
80
	 * @return An {@link Angle} object representing the given radians-angle.
81
	 */
82
	public static Angle fromRad(double radians) {
83
		return new Angle(radians, AngleUnit.RAD);
84
	}
85
86
	private double rad = 0d;
87
88
	/**
89
	 * Constructs a new {@link Angle} object with the given value. The
90
	 * {@link AngleUnit} u is used to differentiate the value's unit.
91
	 * 
92
	 * @param v
93
	 *            The angle's value.
94
	 * @param u
95
	 *            The angle's unit.
96
	 */
97
	public Angle(double v, AngleUnit u) {
98
		if (u == AngleUnit.DEG) {
99
			v *= DEG_TO_RAD;
100
		}
101
		setRad(v);
102
	}
103
104
	/**
105
	 * Overwritten with public visibility as proposed in {@link Cloneable}.
106
	 */
107
	@Override
108
	public Angle clone() {
109
		return getCopy();
110
	}
111
112
	/**
113
	 * Returns the value of this {@link Angle} object in degrees.
114
	 * 
115
	 * @return This {@link Angle}'s value in degrees.
116
	 */
117
	public double deg() {
118
		return rad * RAD_TO_DEG;
119
	}
120
121
	@Override
122
	public boolean equals(Object otherObj) {
123
		Angle other = (Angle) otherObj;
124
		return PrecisionUtils.equal(other.rad, this.rad);
125
	}
126
127
	/**
128
	 * Returns the sum of this and the given other {@link Angle} object as a new
129
	 * {@link Angle} object.
130
	 * 
131
	 * @param other
132
	 * @return The sum of this and the given other {@link Angle} object as a new
133
	 *         {@link Angle} object.
134
	 */
135
	public Angle getAdded(Angle other) {
136
		return Angle.fromRad(this.rad + other.rad);
137
	}
138
139
	/**
140
	 * Creates and returns a copy of this {@link Angle}.
141
	 * 
142
	 * @return a copy of this {@link Angle}
143
	 */
144
	public Angle getCopy() {
145
		return Angle.fromRad(this.rad);
146
	}
147
148
	/**
149
	 * Returns the opposite {@link Angle} of this {@link Angle} in a full circle
150
	 * as a new {@link Angle} object.
151
	 * 
152
	 * @return The opposite {@link Angle} of this {@link Angle} in a full circle
153
	 *         as a new {@link Angle} object.
154
	 */
155
	public Angle getOppositeFull() {
156
		return Angle.fromRad(RAD_360 - rad);
157
	}
158
159
	/**
160
	 * Returns the opposite {@link Angle} of this {@link Angle} in a semi-circle
161
	 * as a new {@link Angle} object.
162
	 * 
163
	 * @return The opposite {@link Angle} of this {@link Angle} in a semi-circle
164
	 *         as a new {@link Angle} object.
165
	 */
166
	public Angle getOppositeSemi() {
167
		return Angle.fromRad(RAD_180 - rad);
168
	}
169
170
	private Angle normalize() {
171
		rad -= RAD_360 * Math.floor(rad / RAD_360);
172
		return this;
173
	}
174
175
	/**
176
	 * Returns this {@link Angle}'s value in radians.
177
	 * 
178
	 * @return This {@link Angle}'s value in radians.
179
	 */
180
	public double rad() {
181
		return rad;
182
	}
183
184
	/**
185
	 * Sets this {@link Angle}'s value to the given angle in degrees.
186
	 * 
187
	 * @param degrees
188
	 *            The angle in degrees.
189
	 */
190
	public void setDeg(double degrees) {
191
		rad = degrees * DEG_TO_RAD;
192
		normalize();
193
	}
194
195
	/**
196
	 * Sets this {@link Angle}'s value to the given angle in radians.
197
	 * 
198
	 * @param radians
199
	 *            The angle value in radians.
200
	 */
201
	public void setRad(double radians) {
202
		rad = radians;
203
		normalize();
204
	}
205
206
	/**
207
	 * @see Object#toString()
208
	 */
209
	@Override
210
	public String toString() {
211
		return super.toString() + ": " + Double.toString(rad) + "rad ("
212
				+ Double.toString(deg()) + "deg)";
213
	}
214
}
(-)src/org/eclipse/gef4/geometry/Dimension.java (-5 / +7 lines)
Lines 177-182 Link Here
177
	 *            the Object being tested for equality
177
	 *            the Object being tested for equality
178
	 * @return <code>true</code> if the given object is equal to this dimension
178
	 * @return <code>true</code> if the given object is equal to this dimension
179
	 */
179
	 */
180
	@Override
180
	public boolean equals(Object o) {
181
	public boolean equals(Object o) {
181
		if (o instanceof Dimension) {
182
		if (o instanceof Dimension) {
182
			Dimension d = (Dimension) o;
183
			Dimension d = (Dimension) o;
Lines 212-218 Link Here
212
	}
213
	}
213
214
214
	/**
215
	/**
215
	 * Creates and returns a copy of this Dimension.
216
	 * Creates and returns a copy of this {@link Dimension}.
216
	 * 
217
	 * 
217
	 * @return a copy of this Dimension
218
	 * @return a copy of this Dimension
218
	 */
219
	 */
Lines 221-228 Link Here
221
	}
222
	}
222
223
223
	/**
224
	/**
224
	 * Creates and returns a Dimension representing the sum of this Dimension
225
	 * Creates and returns a {@link Dimension} representing the sum of this
225
	 * and the one specified.
226
	 * {@link Dimension} and the one specified.
226
	 * 
227
	 * 
227
	 * @param d
228
	 * @param d
228
	 *            the dimension providing the expansion width and height
229
	 *            the dimension providing the expansion width and height
Lines 234-240 Link Here
234
235
235
	/**
236
	/**
236
	 * Creates and returns a new Dimension representing the sum of this
237
	 * Creates and returns a new Dimension representing the sum of this
237
	 * Dimension and the one specified.
238
	 * {@link Dimension} and the one specified.
238
	 * 
239
	 * 
239
	 * @param w
240
	 * @param w
240
	 *            value by which the width of this is to be expanded
241
	 *            value by which the width of this is to be expanded
Lines 331-336 Link Here
331
	/**
332
	/**
332
	 * @see java.lang.Object#hashCode()
333
	 * @see java.lang.Object#hashCode()
333
	 */
334
	 */
335
	@Override
334
	public int hashCode() {
336
	public int hashCode() {
335
		return (int) (width * height) ^ (int) (width + height);
337
		return (int) (width * height) ^ (int) (width + height);
336
	}
338
	}
Lines 489-495 Link Here
489
	/**
491
	/**
490
	 * @see Object#toString()
492
	 * @see Object#toString()
491
	 */
493
	 */
492
494
	@Override
493
	public String toString() {
495
	public String toString() {
494
		return "Dimension(" + //$NON-NLS-1$
496
		return "Dimension(" + //$NON-NLS-1$
495
				width + ", " + //$NON-NLS-1$
497
				width + ", " + //$NON-NLS-1$
(-)src/org/eclipse/gef4/geometry/Point.java (-1 / +4 lines)
Lines 153-158 Link Here
153
	 *            Object being tested for equality
153
	 *            Object being tested for equality
154
	 * @return true if both x and y values are equal
154
	 * @return true if both x and y values are equal
155
	 */
155
	 */
156
	@Override
156
	public boolean equals(Object o) {
157
	public boolean equals(Object o) {
157
		if (o instanceof Point) {
158
		if (o instanceof Point) {
158
			Point p = (Point) o;
159
			Point p = (Point) o;
Lines 261-266 Link Here
261
	/**
262
	/**
262
	 * @see java.lang.Object#hashCode()
263
	 * @see java.lang.Object#hashCode()
263
	 */
264
	 */
265
	@Override
264
	public int hashCode() {
266
	public int hashCode() {
265
		return (int) (x * y) ^ (int) (x + y);
267
		return (int) (x * y) ^ (int) (x + y);
266
	}
268
	}
Lines 354-361 Link Here
354
	}
356
	}
355
357
356
	/**
358
	/**
357
	 * @return String representation.
359
	 * @see Object#toString()
358
	 */
360
	 */
361
	@Override
359
	public String toString() {
362
	public String toString() {
360
		return "Point(" + x + ", " + y + ")";//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
363
		return "Point(" + x + ", " + y + ")";//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
361
	}
364
	}
(-)src/org/eclipse/gef4/geometry/euclidean/Straight.java (-27 / +203 lines)
Lines 12-17 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.gef4.geometry.euclidean;
13
package org.eclipse.gef4.geometry.euclidean;
14
14
15
import java.io.Serializable;
16
17
import org.eclipse.gef4.geometry.Angle;
15
import org.eclipse.gef4.geometry.Point;
18
import org.eclipse.gef4.geometry.Point;
16
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
19
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
17
20
Lines 20-26 Link Here
20
 * 
23
 * 
21
 * @author anyssen
24
 * @author anyssen
22
 */
25
 */
23
public class Straight {
26
public class Straight implements Cloneable, Serializable {
27
28
	private static final long serialVersionUID = 1L;
24
29
25
	/** position vector of this straight */
30
	/** position vector of this straight */
26
	public Vector position;
31
	public Vector position;
Lines 39-46 Link Here
39
			throw new IllegalArgumentException(
44
			throw new IllegalArgumentException(
40
					"direction has to be unequal to (0,0)"); //$NON-NLS-1$
45
					"direction has to be unequal to (0,0)"); //$NON-NLS-1$
41
		}
46
		}
42
		this.position = position;
47
		this.position = position.clone();
43
		this.direction = direction;
48
		this.direction = direction.clone();
44
	}
49
	}
45
50
46
	/**
51
	/**
Lines 55-63 Link Here
55
		this(new Vector(point1), new Vector(point1, point2));
60
		this(new Vector(point1), new Vector(point1, point2));
56
	}
61
	}
57
62
63
	@Override
64
	public Straight clone() {
65
		return new Straight(position, direction);
66
	}
67
58
	/**
68
	/**
59
	 * Checks whether this Straight and the provided one have a single
69
	 * Checks whether this Straight and the provided one have a single point of
60
	 * intersection point.
70
	 * intersection.
61
	 * 
71
	 * 
62
	 * @param other
72
	 * @param other
63
	 *            The Straight to use for the calculation.
73
	 *            The Straight to use for the calculation.
Lines 111-116 Link Here
111
	}
121
	}
112
122
113
	/**
123
	/**
124
	 * Converts a given {@link Vector} into a 3-dimensional vector in
125
	 * homogeneous coordinates represented as an array.
126
	 * 
127
	 * @param v
128
	 *            the {@link Vector} to convert
129
	 * @return an array representation of the 3-dimensional homogeneous vector
130
	 */
131
	private double[] toHomogeneousVector(Vector v) {
132
		return new double[] { v.x, v.y, 1 };
133
	}
134
135
	/**
136
	 * Projects the given 3-dimensional homogeneous-coordinate vector,
137
	 * represented as an array, into the 2D space.
138
	 * 
139
	 * @param v
140
	 *            the array representation of a 3-dimensional
141
	 *            homogeneous-coordinate vector to project
142
	 * @return the projected {@link Vector}
143
	 */
144
	private Vector fromHomogeneousVector(double[] v) {
145
		if (v[2] == 0) {
146
			return null;
147
		}
148
		return new Vector(v[0] / v[2], v[1] / v[2]);
149
	}
150
151
	/**
152
	 * Calculates the cross product of two 3-dimensional vectors.
153
	 * 
154
	 * Used in calculations based on 2D homogeneous coordinates.
155
	 * 
156
	 * @param a
157
	 *            an array representation of the first 3-dimensional input
158
	 *            vector
159
	 * @param b
160
	 *            an array representation of the second 3-deminsional input
161
	 *            vector
162
	 * @return an array representation of the 3-dimensional cross product
163
	 */
164
	private double[] getCrossProduct(double[] a, double[] b) {
165
		double[] r = new double[3];
166
		r[0] = a[1] * b[2] - a[2] * b[1];
167
		r[1] = a[2] * b[0] - a[0] * b[2];
168
		r[2] = a[0] * b[1] - a[1] * b[0];
169
		return r;
170
	}
171
172
	/**
114
	 * Computes the intersection point of this Straight and the provided one, if
173
	 * Computes the intersection point of this Straight and the provided one, if
115
	 * it exists.
174
	 * it exists.
116
	 * 
175
	 * 
Lines 120-137 Link Here
120
	 *         if no intersection point exists (or the Straights are equal).
179
	 *         if no intersection point exists (or the Straights are equal).
121
	 */
180
	 */
122
	public Vector getIntersection(Straight other) {
181
	public Vector getIntersection(Straight other) {
123
		// first check if there is a single intersection point
182
		// method using homogeneous coordinates
124
		if (!intersects(other)) {
183
		double[] p11 = toHomogeneousVector(position);
125
			return null;
184
		double[] p12 = toHomogeneousVector(position.getAdded(direction));
126
		}
185
		double[] p21 = toHomogeneousVector(other.position);
127
		// calculate intersection point
186
		double[] p22 = toHomogeneousVector(other.position
128
		Vector s1 = direction.getMultiplied(other.position
187
				.getAdded(other.direction));
129
				.getDotProduct(other.direction.getOrthogonalComplement()));
188
		double[] l1 = getCrossProduct(p11, p12);
130
		Vector s2 = other.direction.getMultiplied(position
189
		double[] l2 = getCrossProduct(p21, p22);
131
				.getDotProduct(direction.getOrthogonalComplement()));
190
		double[] poi = getCrossProduct(l1, l2);
132
		return s1.getSubtracted(s2).getDivided(
191
		return fromHomogeneousVector(poi);
133
				direction.getDotProduct(other.direction
134
						.getOrthogonalComplement()));
135
	}
192
	}
136
193
137
	/**
194
	/**
Lines 139-163 Link Here
139
	 * 
196
	 * 
140
	 * @param other
197
	 * @param other
141
	 *            The Straight to be used for the calculation.
198
	 *            The Straight to be used for the calculation.
142
	 * @return The angle spanned between the two Straights.
199
	 * @return The angle spanned between the two {@link Straight}s.
143
	 */
200
	 */
144
	public double getAngle(Straight other) {
201
	public Angle getAngle(Straight other) {
145
		return direction.getAngle(other.direction);
202
		return direction.getAngle(other.direction);
146
	}
203
	}
147
204
148
	/**
205
	/**
149
	 * Returns the projection of the given Vector onto this Straight, which is
206
	 * Returns the clock-wise (CW) or negative angle spanned between the two
150
	 * the point on this Straight with the minimal distance to the point,
207
	 * {@link Straight}s.
151
	 * denoted by the provided Vector.
208
	 * 
209
	 * The returned angle is the opposite of the angle returned by the
210
	 * getAngleCCW(Straight other) method.
211
	 * 
212
	 * @param other
213
	 * @return The clock-wise (CW) or negative angle spanned between the two
214
	 *         {@link Straight}s.
215
	 */
216
	public Angle getAngleCW(Straight other) {
217
		return getAngleCCW(other).getOppositeSemi();
218
	}
219
220
	/**
221
	 * Returns the counter-clock-wise (CCW) or positive {@link Angle} spanned
222
	 * between the two {@link Straight}s.
223
	 * 
224
	 * The returned {@link Angle} is the opposite of the {@link Angle} returned
225
	 * by the getAngleCCW(Straight other) method.
226
	 * 
227
	 * @param other
228
	 * @return The counter-clock-wise (CCW) or positive angle spanned between
229
	 *         the two {@link Straight}s.
230
	 */
231
	public Angle getAngleCCW(Straight other) {
232
		Angle angle = getAngle(other);
233
		if (direction.getCrossProduct(other.direction) > 0) {
234
			angle = angle.getOppositeSemi();
235
		}
236
		return angle;
237
	}
238
239
	/**
240
	 * Returns the projection of the given {@link Vector} onto this
241
	 * {@link Straight}, which is the point on this {@link Straight} with the
242
	 * minimal distance to the point, denoted by the provided {@link Vector}.
152
	 * 
243
	 * 
153
	 * @param vector
244
	 * @param vector
154
	 *            The Vector whose projection should be determined.
245
	 *            The {@link Vector} whose projection should be determined.
155
	 * @return A new Vector representing the projection of the provided Vector
246
	 * @return A new {@link Vector} representing the projection of the provided
156
	 *         onto this Straight.
247
	 *         {@link Vector} onto this {@link Straight}.
157
	 */
248
	 */
158
	public Vector getProjection(Vector vector) {
249
	public Vector getProjection(Vector vector) {
159
		return getIntersection(new Straight(vector,
250
		// calculate with a normalized direction vector to prevent rounding
160
				direction.getOrthogonalComplement()));
251
		// effects
252
		Vector normalized = direction.getNormalized();
253
		return new Straight(position, normalized).getIntersection(new Straight(
254
				vector, normalized.getOrthogonalComplement()));
161
	}
255
	}
162
256
163
	/**
257
	/**
Lines 174-179 Link Here
174
	}
268
	}
175
269
176
	/**
270
	/**
271
	 * Returns the signed distance of the given {@link Vector} to this
272
	 * {@link Straight}.
273
	 * 
274
	 * The signed distance indicates on which side of the {@link Straight} the
275
	 * {@link Vector} lies. If it lies on the right side of this
276
	 * {@link Straight}'s direction {@link Vector}, the signed distance is
277
	 * negative. If it is on the left side of this {@link Straight}'s direction
278
	 * Vector, the signed distance is positive.
279
	 * 
280
	 * @param vector
281
	 * @return the signed distance of the given {@link Vector} to this Straight
282
	 */
283
	public double getSignedDistanceCCW(Vector vector) {
284
		Vector projected = getProjection(vector);
285
		Vector d = vector.getSubtracted(projected);
286
287
		double len = d.getLength();
288
289
		if (!d.isNull()) {
290
			Angle angleCCW = direction.getAngleCW(d);
291
292
			if (angleCCW.equals(Angle.fromDeg(90))) {
293
				len = -len;
294
			}
295
		}
296
297
		return len;
298
	}
299
300
	/**
301
	 * Returns the signed distance of the given {@link Vector} to this Straight.
302
	 * 
303
	 * The signed distance indicates on which side of the Straight the Vector
304
	 * lies. If it is on the right side of this Straight's direction Vector, the
305
	 * signed distance is negative. If it is on the left side of this Straight's
306
	 * direction Vector, the signed distance is positive.
307
	 * 
308
	 * @param vector
309
	 * @return the signed distance of the given {@link Vector} to this Straight
310
	 */
311
	public double getSignedDistanceCW(Vector vector) {
312
		return -getSignedDistanceCCW(vector);
313
	}
314
315
	/**
316
	 * Returns this {@link Straight}'s parameter value for the given
317
	 * {@link Point} p.
318
	 * 
319
	 * This method is the reverse of the getPointAt(double parameter) method.
320
	 * 
321
	 * @param p
322
	 * @return this {@link Straight}'s parameter value for the given
323
	 *         {@link Point} p
324
	 */
325
	public double getParameterAt(Point p) {
326
		if (direction.x != 0) {
327
			return (p.x - position.x) / direction.x;
328
		}
329
		if (direction.y != 0) {
330
			return (p.y - position.y) / direction.y;
331
		}
332
		return 0;
333
	}
334
335
	/**
336
	 * Returns the {@link Point} on this {@link Straight} at parameter p. The
337
	 * {@link Point} that you get is calculated by multiplying this
338
	 * {@link Straight}'s direction {@link Vector} by the parameter value and
339
	 * translating that {@link Vector} by this {@link Straight}'s position
340
	 * {@link Vector}.
341
	 * 
342
	 * This method is the reverse of the getPointAt(double parameter) method.
343
	 * 
344
	 * @param parameter
345
	 * @return the {@link Point} on this {@link Straight} at parameter p
346
	 */
347
	public Point getPointAt(double parameter) {
348
		return new Point(position.x + direction.x * parameter, position.y
349
				+ direction.y * parameter);
350
	}
351
352
	/**
177
	 * Calculates whether the point indicated by the provided Vector is a point
353
	 * Calculates whether the point indicated by the provided Vector is a point
178
	 * on this Straight.
354
	 * on this Straight.
179
	 * 
355
	 * 
(-)src/org/eclipse/gef4/geometry/euclidean/Vector.java (-7 / +110 lines)
Lines 12-17 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.gef4.geometry.euclidean;
13
package org.eclipse.gef4.geometry.euclidean;
14
14
15
import java.io.Serializable;
16
17
import org.eclipse.gef4.geometry.Angle;
15
import org.eclipse.gef4.geometry.Point;
18
import org.eclipse.gef4.geometry.Point;
16
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
19
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
17
20
Lines 24-30 Link Here
24
 * @author ahunter
27
 * @author ahunter
25
 * @author anyssen
28
 * @author anyssen
26
 */
29
 */
27
public class Vector {
30
public class Vector implements Cloneable, Serializable {
31
32
	private static final long serialVersionUID = 1L;
28
33
29
	/** the X value */
34
	/** the X value */
30
	public double x;
35
	public double x;
Lines 87-92 Link Here
87
	}
92
	}
88
93
89
	/**
94
	/**
95
	 * Clones the given Vector object.
96
	 */
97
	@Override
98
	public Vector clone() {
99
		return new Vector(x, y);
100
	}
101
102
	/**
90
	 * Calculates the magnitude of the cross product of this Vector with
103
	 * Calculates the magnitude of the cross product of this Vector with
91
	 * another. Represents the amount by which two Vectors are directionally
104
	 * another. Represents the amount by which two Vectors are directionally
92
	 * different. Parallel Vectors return a value of 0.
105
	 * different. Parallel Vectors return a value of 0.
Lines 158-174 Link Here
158
	}
171
	}
159
172
160
	/**
173
	/**
161
	 * Returns the angle (in degrees) between this Vector and the provided
174
	 * Returns the smallest {@link Angle} between this {@link Vector} and the
162
	 * Vector.
175
	 * provided {@link Vector}.
163
	 * 
176
	 * 
164
	 * @param other
177
	 * @param other
165
	 *            Vector to calculate the angle.
178
	 *            {@link Vector} to calculate the {@link Angle}.
166
	 * @return the angle between the two Vectors in degrees.
179
	 * @return the smallest {@link Angle} between the two Vectors.
167
	 */
180
	 */
168
	public double getAngle(Vector other) {
181
	public Angle getAngle(Vector other) {
169
		double cosAlpha = getDotProduct(other)
182
		double cosAlpha = getDotProduct(other)
170
				/ (getLength() * other.getLength());
183
				/ (getLength() * other.getLength());
171
		return Math.toDegrees(Math.acos(cosAlpha));
184
		return Angle.fromRad(Math.acos(cosAlpha));
185
	}
186
187
	/**
188
	 * Returns the clock-wise (mathematical negative) {@link Angle} between this
189
	 * {@link Vector} and the provided {@link Vector}.
190
	 * 
191
	 * @param other
192
	 *            {@link Vector} to calculate the {@link Angle}.
193
	 * @return the clock-wise {@link Angle} between the two Vectors.
194
	 */
195
	public Angle getAngleCW(Vector other) {
196
		return getAngleCCW(other).getOppositeFull();
197
	}
198
199
	/**
200
	 * Returns the counter-clock-wise (mathematical positive) {@link Angle}
201
	 * between this {@link Vector} and the provided {@link Vector}.
202
	 * 
203
	 * @param other
204
	 *            {@link Vector} to calculate the {@link Angle}.
205
	 * @return the counter-clock-wise {@link Angle} between the two Vectors.
206
	 */
207
	public Angle getAngleCCW(Vector other) {
208
		Angle angle = getAngle(other);
209
		if (getCrossProduct(other) > 0) {
210
			return angle.getOppositeFull();
211
		}
212
		return angle;
172
	}
213
	}
173
214
174
	/**
215
	/**
Lines 218-223 Link Here
218
	}
259
	}
219
260
220
	/**
261
	/**
262
	 * Returns a fresh rotated Vector object. The rotation is clock-wise (CW) by
263
	 * the given angle.
264
	 * 
265
	 * @param angle
266
	 *            the rotation angle
267
	 * @return the new rotated Vector
268
	 */
269
	public Vector getRotatedCW(Angle angle) {
270
		return clone().rotateCW(angle);
271
	}
272
273
	/**
274
	 * Returns a fresh rotated Vector object. The rotation is counter-clock-wise
275
	 * (CCW) by the given angle.
276
	 * 
277
	 * @param angle
278
	 *            the rotation angle
279
	 * @return the new rotated Vector
280
	 */
281
	public Vector getRotatedCCW(Angle angle) {
282
		return clone().rotateCCW(angle);
283
	}
284
285
	/**
221
	 * Returns the length of this Vector.
286
	 * Returns the length of this Vector.
222
	 * 
287
	 * 
223
	 * @return Length of this Vector
288
	 * @return Length of this Vector
Lines 320-323 Link Here
320
		return (int) x + (int) y;
385
		return (int) x + (int) y;
321
	}
386
	}
322
387
388
	/**
389
	 * Rotates this {@link Vector} counter-clock-wise by the given {@link Angle}
390
	 * .
391
	 * 
392
	 * @param angle
393
	 *            The rotation {@link Angle}.
394
	 * @return This (rotated) {@link Vector} object.
395
	 */
396
	public Vector rotateCCW(Angle angle) {
397
		return rotateCW(angle.getOppositeFull());
398
	}
399
400
	/**
401
	 * Rotates this {@link Vector} clock-wise by the given {@link Angle}.
402
	 * 
403
	 * @param angle
404
	 *            The rotation {@link Angle}.
405
	 * @return This (rotated) {@link Vector} object.
406
	 */
407
	public Vector rotateCW(Angle angle) {
408
		double alpha = angle.rad();
409
		double nx = x * Math.cos(alpha) - y * Math.sin(alpha);
410
		double ny = x * Math.sin(alpha) + y * Math.cos(alpha);
411
		x = nx;
412
		y = ny;
413
		return this;
414
	}
415
416
	/**
417
	 * Creates a new normalized {@link Vector} that has the same direction as
418
	 * this {@link Vector} but a length of 1.
419
	 * 
420
	 * @return The normalized {@link Vector}.
421
	 */
422
	public Vector getNormalized() {
423
		return clone().getMultiplied(1 / getLength());
424
	}
425
323
}
426
}
(-)src/org/eclipse/gef4/geometry/shapes/CubicCurve.java (-39 / +531 lines)
Lines 11-18 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.shapes;
12
package org.eclipse.gef4.geometry.shapes;
13
13
14
import java.io.Serializable;
15
import java.util.Arrays;
16
import java.util.HashSet;
17
14
import org.eclipse.gef4.geometry.Point;
18
import org.eclipse.gef4.geometry.Point;
15
import org.eclipse.gef4.geometry.transform.AffineTransform;
19
import org.eclipse.gef4.geometry.transform.AffineTransform;
20
import org.eclipse.gef4.geometry.utils.PolynomCalculations;
21
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
16
22
17
/**
23
/**
18
 * Represents the geometric shape of a cubic Bézier curve.
24
 * Represents the geometric shape of a cubic Bézier curve.
Lines 20-31 Link Here
20
 * @author anyssen
26
 * @author anyssen
21
 * 
27
 * 
22
 */
28
 */
23
public class CubicCurve implements Geometry {
29
public class CubicCurve implements Geometry, Serializable {
24
30
25
	private static final long serialVersionUID = 1L;
31
	private static final long serialVersionUID = 1L;
26
32
27
	private double x1, y1, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, x2, y2;
33
	private double x1, y1, ctrl1X, ctrl1Y, ctrl2X, ctrl2Y, x2, y2;
28
34
35
	/**
36
	 * Constructs a new {@link CubicCurve} object with the given control point
37
	 * coordinates.
38
	 * 
39
	 * @param x1
40
	 *            x-coordinate of the start point
41
	 * @param y1
42
	 *            y-coordinate of the start point
43
	 * @param ctrl1X
44
	 *            x-coordinate of the first control point
45
	 * @param ctrl1Y
46
	 *            y-coordinate of the first control point
47
	 * @param ctrl2X
48
	 *            x-coordinate of the second control point
49
	 * @param ctrl2Y
50
	 *            y-coordinate of the second control point
51
	 * @param x2
52
	 *            x-coordinate of the end point
53
	 * @param y2
54
	 *            y-coordinate of the end point
55
	 */
29
	public CubicCurve(double x1, double y1, double ctrl1X, double ctrl1Y,
56
	public CubicCurve(double x1, double y1, double ctrl1X, double ctrl1Y,
30
			double ctrl2X, double ctrl2Y, double x2, double y2) {
57
			double ctrl2X, double ctrl2Y, double x2, double y2) {
31
		this.x1 = x1;
58
		this.x1 = x1;
Lines 38-43 Link Here
38
		this.y2 = y2;
65
		this.y2 = y2;
39
	}
66
	}
40
67
68
	/**
69
	 * Constructs a new {@link CubicCurve} object with the given control
70
	 * {@link Point}s.
71
	 * 
72
	 * @param start
73
	 *            the start point
74
	 * @param ctrl1
75
	 *            the first control point
76
	 * @param ctrl2
77
	 *            the second control point
78
	 * @param end
79
	 *            the end point
80
	 */
41
	public CubicCurve(Point start, Point ctrl1, Point ctrl2, Point end) {
81
	public CubicCurve(Point start, Point ctrl1, Point ctrl2, Point end) {
42
		this.x1 = start.x;
82
		this.x1 = start.x;
43
		this.y1 = start.y;
83
		this.y1 = start.y;
Lines 49-186 Link Here
49
		this.y2 = end.y;
89
		this.y2 = end.y;
50
	}
90
	}
51
91
52
	/*
92
	/**
53
	 * (non-Javadoc)
93
	 * @see Geometry#contains(Point)
54
	 * 
55
	 * @see
56
	 * org.eclipse.gef4.geometry.shapes.Geometry#contains(org.eclipse.gef4.geometry
57
	 * .Point)
58
	 */
94
	 */
59
	public boolean contains(Point p) {
95
	public boolean contains(Point p) {
60
		// TODO Auto-generated method stub
96
		// find roots of the x(t) - p.x function:
97
		double D = getX1() - p.x;
98
		double C = 3 * (getCtrl1X() - getX1());
99
		double B = 3 * (getCtrl2X() - getCtrl1X()) - C;
100
		double A = getX2() - getX1() - B - C;
101
		double[] xts = PolynomCalculations.getCubicRoots(A, B, C, D);
102
103
		for (double t : xts) {
104
			// t = PrecisionUtils.round(t);
105
			if (PrecisionUtils.greaterEqual(t, 0)
106
					&& PrecisionUtils.smallerEqual(t, 1)
107
					&& PrecisionUtils.equal(get(t).y, p.y)) {
108
				return true;
109
			}
110
		}
61
		return false;
111
		return false;
62
	}
112
	}
63
113
64
	/*
114
	/**
65
	 * (non-Javadoc)
115
	 * @see Geometry#contains(Rectangle)
66
	 * 
67
	 * @see
68
	 * org.eclipse.gef4.geometry.shapes.Geometry#contains(org.eclipse.gef4.geometry
69
	 * .shapes.Rectangle)
70
	 */
116
	 */
71
	public boolean contains(Rectangle r) {
117
	public boolean contains(Rectangle r) {
72
		// TODO Auto-generated method stub
73
		return false;
118
		return false;
74
	}
119
	}
75
120
76
	/*
121
	@Override
77
	 * (non-Javadoc)
122
	public boolean equals(Object other) {
78
	 * 
123
		CubicCurve o = (CubicCurve) other;
79
	 * @see org.eclipse.gef4.geometry.shapes.Geometry#getBounds()
124
125
		Polygon myPoly = getControlPolygon();
126
		Polygon otherPoly = o.getControlPolygon();
127
128
		return myPoly.equals(otherPoly);
129
	}
130
131
	/**
132
	 * @see Geometry#getBounds()
80
	 */
133
	 */
81
	public Rectangle getBounds() {
134
	public Rectangle getBounds() {
82
		// TODO Auto-generated method stub
135
		// extremes of the x(t) and y(t) functions:
83
		return null;
136
		double[] xts;
137
		try {
138
			xts = PolynomCalculations.getQuadraticRoots(-3 * getX1() + 9
139
					* getCtrl1X() - 9 * getCtrl2X() + 3 * getX2(), 6 * getX1()
140
					- 12 * getCtrl1X() + 6 * getCtrl2X(), 3 * getCtrl1X() - 3
141
					* getX1());
142
		} catch (ArithmeticException x) {
143
			return new Rectangle(getP1(), getP2());
144
		}
145
146
		double xmin = getX1(), xmax = getX1();
147
		if (getX2() < xmin) {
148
			xmin = getX2();
149
		} else {
150
			xmax = getX2();
151
		}
152
153
		for (double t : xts) {
154
			if (t >= 0 && t <= 1) {
155
				double x = get(t).x;
156
				if (x < xmin) {
157
					xmin = x;
158
				} else if (x > xmax) {
159
					xmax = x;
160
				}
161
			}
162
		}
163
164
		double[] yts;
165
		try {
166
			yts = PolynomCalculations.getQuadraticRoots(-3 * getY1() + 9
167
					* getCtrl1Y() - 9 * getCtrl2Y() + 3 * getY2(), 6 * getY1()
168
					- 12 * getCtrl1Y() + 6 * getCtrl2Y(), 3 * getCtrl1Y() - 3
169
					* getY1());
170
		} catch (ArithmeticException x) {
171
			return new Rectangle(new Point(xmin, getP1().y), new Point(xmax,
172
					getP2().y));
173
		}
174
175
		double ymin = getY1(), ymax = getY1();
176
		if (getY2() < ymin) {
177
			ymin = getY2();
178
		} else {
179
			ymax = getY2();
180
		}
181
182
		for (double t : yts) {
183
			if (t >= 0 && t <= 1) {
184
				double y = get(t).y;
185
				if (y < ymin) {
186
					ymin = y;
187
				} else if (y > ymax) {
188
					ymax = y;
189
				}
190
			}
191
		}
192
193
		return new Rectangle(new Point(xmin, ymin), new Point(xmax, ymax));
194
	}
195
196
	private Point ratioPoint(Point p, Point q, double ratio) {
197
		return p.getTranslated(q.getTranslated(p.getNegated()).getScaled(ratio));
198
	}
199
200
	/**
201
	 * Subdivides this {@link CubicCurve} into two {@link CubicCurve}s on the
202
	 * intervals [0, t] and [t, 1] using the de-Casteljau-algorithm.
203
	 * 
204
	 * @param t
205
	 *            split point's parameter value
206
	 * @return the two {@link CubicCurve}s
207
	 */
208
	public CubicCurve[] split(double t) {
209
		if (t < 0 || t > 1) {
210
			throw new IllegalArgumentException(
211
					"Paramter t is out of range! t = " + t + " !in_range(0,1)");
212
		}
213
214
		Point p10 = ratioPoint(getP1(), getCtrl1(), t);
215
		Point p11 = ratioPoint(getCtrl1(), getCtrl2(), t);
216
		Point p12 = ratioPoint(getCtrl2(), getP2(), t);
217
		Point p20 = ratioPoint(p10, p11, t);
218
		Point p21 = ratioPoint(p11, p12, t);
219
		Point p30 = ratioPoint(p20, p21, t);
220
221
		CubicCurve left = new CubicCurve(getP1(), p10, p20, p30);
222
		CubicCurve right = new CubicCurve(p30, p21, p12, getP2());
223
224
		return new CubicCurve[] { left, right };
225
	}
226
227
	/**
228
	 * Clips this {@link CubicCurve} at parameter values t1 and t2 so that the
229
	 * resulting {@link CubicCurve} is the section of the original
230
	 * {@link CubicCurve} for the parameter interval [t1, t2].
231
	 * 
232
	 * @param t1
233
	 * @param t2
234
	 * @return the {@link CubicCurve} on the interval [t1, t2]
235
	 */
236
	public CubicCurve clip(double t1, double t2) {
237
		if (t1 < 0 || t1 > 1) {
238
			throw new IllegalArgumentException(
239
					"Paramter t1 is out of range! t1 = " + t1
240
							+ " !in_range(0,1)");
241
		}
242
		if (t2 < 0 || t2 > 1) {
243
			throw new IllegalArgumentException(
244
					"Paramter t2 is out of range! t2 = " + t2
245
							+ " !in_range(0,1)");
246
		}
247
248
		CubicCurve right = split(t1)[1];
249
		double rightT2 = (t2 - t1) / (1 - t1);
250
		return right.split(rightT2)[0];
251
	}
252
253
	private static double getArea(Polygon p) {
254
		Rectangle r = p.getBounds();
255
		return r.getWidth() * r.getHeight();
256
	}
257
258
	private Polygon getControlPolygon() {
259
		return new Polygon(getP1(), getCtrl1(), getCtrl2(), getP2());
260
	}
261
262
	private static Point[] getIntersections(CubicCurve p, double ps, double pe,
263
			Line l) {
264
		// parameter convergence test
265
		double pm = (ps + pe) / 2;
266
267
		if (PrecisionUtils.equal(ps, pe, -2)) {
268
			return new Point[] { p.get(pm) };
269
		}
270
271
		// no parameter convergence
272
		// clip the curve
273
		CubicCurve pc = p.clip(ps, pe);
274
275
		// check the control polygon
276
		Polygon polygon = pc.getControlPolygon();
277
278
		if (polygon.intersects(l)) {
279
			// area test
280
			if (PrecisionUtils.equal(getArea(polygon), 0, -2)) {
281
				// line/line intersection fallback for such small curves
282
				Point poi = new Line(pc.getP1(), pc.getP2()).getIntersection(l);
283
				if (poi != null) {
284
					return new Point[] { poi };
285
				}
286
				return new Point[] {};
287
			}
288
289
			// "split" the curve to get precise intersections
290
			HashSet<Point> intersections = new HashSet<Point>();
291
292
			intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, l)));
293
			intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, l)));
294
295
			return intersections.toArray(new Point[] {});
296
		}
297
298
		// no intersections
299
		return new Point[] {};
300
	}
301
302
	private static Point[] getIntersections(CubicCurve p, double ps, double pe,
303
			CubicCurve q, double qs, double qe) {
304
		double pm = (ps + pe) / 2;
305
		double qm = (qs + qe) / 2;
306
307
		// point convergence test
308
		Point pPoi = p.get(pm);
309
		Point qPoi = q.get(qm);
310
311
		if (pPoi != null && qPoi != null && pPoi.equals(qPoi)) {
312
			return new Point[] { pPoi };
313
		}
314
315
		// no point convergence yet
316
		// clip to parameter ranges
317
		CubicCurve pc = p.clip(ps, pe);
318
		CubicCurve qc = q.clip(qs, qe);
319
320
		// check the control polygons
321
		Polygon pPoly = pc.getControlPolygon();
322
		Polygon qPoly = qc.getControlPolygon();
323
324
		if (pPoly.intersects(qPoly)) {
325
			// check the polygon's areas
326
			double pArea = getArea(pPoly);
327
			double qArea = getArea(qPoly);
328
329
			if (PrecisionUtils.equal(pArea, 0, +2)
330
					&& PrecisionUtils.equal(qArea, 0, +2)) {
331
				// return line/line intersection
332
				Point poi = new Line(pc.getP1(), pc.getP2())
333
						.getIntersection(new Line(qc.getP1(), qc.getP2()));
334
				if (poi != null) {
335
					return new Point[] { poi };
336
				}
337
				return new Point[] {};
338
			}
339
340
			// areas not small enough
341
342
			// do not try to find the intersections of two equal curves
343
			if (pc.equals(qc)) {
344
				return new Point[] {};
345
			}
346
347
			// "split" the curves and do the intersection test recursively
348
			HashSet<Point> intersections = new HashSet<Point>();
349
350
			intersections.addAll(Arrays.asList(getIntersections(p.clip(ps, pm),
351
					0, 1, q.clip(qs, qm), 0, 1)));
352
			intersections.addAll(Arrays.asList(getIntersections(p.clip(ps, pm),
353
					0, 1, q.clip(qm, qe), 0, 1)));
354
			intersections.addAll(Arrays.asList(getIntersections(p.clip(pm, pe),
355
					0, 1, q.clip(qs, qm), 0, 1)));
356
			intersections.addAll(Arrays.asList(getIntersections(p.clip(pm, pe),
357
					0, 1, q.clip(qm, qe), 0, 1)));
358
359
			// intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
360
			// qs, qm)));
361
			// intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
362
			// qm, qe)));
363
			// intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
364
			// qs, qm)));
365
			// intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
366
			// qm, qe)));
367
368
			return intersections.toArray(new Point[] {});
369
		}
370
371
		// no intersections
372
		return new Point[] {};
373
	}
374
375
	/**
376
	 * Returns the points of intersection between this {@link CubicCurve} and
377
	 * the given other {@link CubicCurve}.
378
	 * 
379
	 * @param other
380
	 * @return the points of intersection
381
	 */
382
	public Point[] getIntersections(CubicCurve other) {
383
		return getIntersections(this, 0, 1, other, 0, 1);
84
	}
384
	}
85
385
386
	/**
387
	 * Returns the points of intersection between this {@link CubicCurve} and
388
	 * the given {@link Line} l.
389
	 * 
390
	 * @param l
391
	 * @return the points of intersection
392
	 */
393
	public Point[] getIntersections(Line l) {
394
		return getIntersections(this, 0, 1, l);
395
	}
396
397
	/**
398
	 * Returns the first control {@link Point}.
399
	 * 
400
	 * @return the first control {@link Point}.
401
	 */
86
	public Point getCtrl1() {
402
	public Point getCtrl1() {
87
		return new Point(ctrl1X, ctrl1Y);
403
		return new Point(ctrl1X, ctrl1Y);
88
	}
404
	}
89
405
406
	/**
407
	 * Returns the first control {@link Point}'s x-coordinate.
408
	 * 
409
	 * @return the first control {@link Point}'s x-coordinate.
410
	 */
90
	public double getCtrl1X() {
411
	public double getCtrl1X() {
91
		return ctrl1X;
412
		return ctrl1X;
92
	}
413
	}
93
414
415
	/**
416
	 * Returns the first control {@link Point}'s y-coordinate.
417
	 * 
418
	 * @return the first control {@link Point}'s y-coordinate.
419
	 */
94
	public double getCtrl1Y() {
420
	public double getCtrl1Y() {
95
		return ctrl1Y;
421
		return ctrl1Y;
96
	}
422
	}
97
423
424
	/**
425
	 * Returns the second control {@link Point}.
426
	 * 
427
	 * @return the second control {@link Point}.
428
	 */
98
	public Point getCtrl2() {
429
	public Point getCtrl2() {
99
		return new Point(ctrl2X, ctrl2Y);
430
		return new Point(ctrl2X, ctrl2Y);
100
	}
431
	}
101
432
433
	/**
434
	 * Returns the second control {@link Point}'s x-coordinate.
435
	 * 
436
	 * @return the second control {@link Point}'s x-coordinate.
437
	 */
102
	public double getCtrl2X() {
438
	public double getCtrl2X() {
103
		return ctrl2X;
439
		return ctrl2X;
104
	}
440
	}
105
441
442
	/**
443
	 * Returns the second control {@link Point}'s y-coordinate.
444
	 * 
445
	 * @return the second control {@link Point}'s y-coordinate.
446
	 */
106
	public double getCtrl2Y() {
447
	public double getCtrl2Y() {
107
		return ctrl2Y;
448
		return ctrl2Y;
108
	}
449
	}
109
450
451
	/**
452
	 * Returns the start {@link Point}.
453
	 * 
454
	 * @return the start {@link Point}.
455
	 */
110
	public Point getP1() {
456
	public Point getP1() {
111
		return new Point(x1, y1);
457
		return new Point(x1, y1);
112
	}
458
	}
113
459
460
	/**
461
	 * Returns the end {@link Point}.
462
	 * 
463
	 * @return the end {@link Point}.
464
	 */
114
	public Point getP2() {
465
	public Point getP2() {
115
		return new Point(x1, y1);
466
		return new Point(x2, y2);
116
	}
467
	}
117
468
118
	/*
469
	/**
119
	 * (non-Javadoc)
470
	 * @see Geometry#getTransformed(AffineTransform)
120
	 * 
121
	 * @see
122
	 * org.eclipse.gef4.geometry.shapes.Geometry#getTransformed(org.eclipse.
123
	 * gef4.geometry.transform.AffineTransform)
124
	 */
471
	 */
125
	public Geometry getTransformed(AffineTransform t) {
472
	public Geometry getTransformed(AffineTransform t) {
126
		// TODO Auto-generated method stub
127
		return null;
473
		return null;
128
	}
474
	}
129
475
476
	/**
477
	 * Returns the start {@link Point}'s x-coordinate.
478
	 * 
479
	 * @return the start {@link Point}'s x-coordinate.
480
	 */
130
	public double getX1() {
481
	public double getX1() {
131
		return x1;
482
		return x1;
132
	}
483
	}
133
484
485
	/**
486
	 * Returns the end {@link Point}'s x-coordinate.
487
	 * 
488
	 * @return the end {@link Point}'s x-coordinate.
489
	 */
134
	public double getX2() {
490
	public double getX2() {
135
		return x2;
491
		return x2;
136
	}
492
	}
137
493
494
	/**
495
	 * Returns the start {@link Point}'s y-coordinate.
496
	 * 
497
	 * @return the start {@link Point}'s y-coordinate.
498
	 */
138
	public double getY1() {
499
	public double getY1() {
139
		return y1;
500
		return y1;
140
	}
501
	}
141
502
503
	/**
504
	 * Returns the end {@link Point}'s y-coordinate.
505
	 * 
506
	 * @return the end {@link Point}'s y-coordinate.
507
	 */
142
	public double getY2() {
508
	public double getY2() {
143
		return y2;
509
		return y2;
144
	}
510
	}
145
511
146
	/*
512
	/**
147
	 * (non-Javadoc)
513
	 * @see org.eclipse.gef4.geometry.shapes.Geometry#intersects(Rectangle)
148
	 * 
149
	 * @see
150
	 * org.eclipse.gef4.geometry.shapes.Geometry#intersects(org.eclipse.gef4
151
	 * .geometry.shapes.Rectangle)
152
	 */
514
	 */
153
	public boolean intersects(Rectangle r) {
515
	public boolean intersects(Rectangle r) {
154
		// TODO Auto-generated method stub
155
		return false;
516
		return false;
156
	}
517
	}
157
518
519
	/**
520
	 * Tests if this {@link CubicCurve} intersects the given {@link Line} r.
521
	 * 
522
	 * @param r
523
	 * @return true if they intersect, false otherwise
524
	 */
525
	public boolean intersects(Line r) {
526
		return getIntersections(r).length > 0;
527
	}
528
529
	/**
530
	 * Sets the first control {@link Point} to the given {@link Point} ctrl1.
531
	 * 
532
	 * @param ctrl1
533
	 *            the new first control {@link Point}
534
	 */
158
	public void setCtrl1(Point ctrl1) {
535
	public void setCtrl1(Point ctrl1) {
159
		this.ctrl1X = ctrl1.x;
536
		this.ctrl1X = ctrl1.x;
160
		this.ctrl1Y = ctrl1.y;
537
		this.ctrl1Y = ctrl1.y;
161
	}
538
	}
162
539
540
	/**
541
	 * Sets the first control {@link Point}'s x-coordinate to the given
542
	 * x-coordinate ctrl1x.
543
	 * 
544
	 * @param ctrl1x
545
	 *            the new first control {@link Point}'s x-coordinate
546
	 */
163
	public void setCtrl1X(double ctrl1x) {
547
	public void setCtrl1X(double ctrl1x) {
164
		ctrl1X = ctrl1x;
548
		ctrl1X = ctrl1x;
165
	}
549
	}
166
550
551
	/**
552
	 * Sets the first control {@link Point}'s y-coordinate to the given
553
	 * y-coordinate ctrl1y.
554
	 * 
555
	 * @param ctrl1y
556
	 *            the new first control {@link Point}'s y-coordinate
557
	 */
167
	public void setCtrl1Y(double ctrl1y) {
558
	public void setCtrl1Y(double ctrl1y) {
168
		ctrl1Y = ctrl1y;
559
		ctrl1Y = ctrl1y;
169
	}
560
	}
170
561
562
	/**
563
	 * Sets the second control {@link Point} to the given {@link Point} ctrl2.
564
	 * 
565
	 * @param ctrl2
566
	 *            the new second control {@link Point}
567
	 */
171
	public void setCtrl2(Point ctrl2) {
568
	public void setCtrl2(Point ctrl2) {
172
		this.ctrl2X = ctrl2.x;
569
		this.ctrl2X = ctrl2.x;
173
		this.ctrl2Y = ctrl2.y;
570
		this.ctrl2Y = ctrl2.y;
174
	}
571
	}
175
572
573
	/**
574
	 * Sets the second control {@link Point}'s x-coordinate to the given
575
	 * x-coordinate ctrl2x.
576
	 * 
577
	 * @param ctrl2x
578
	 *            the new second control {@link Point}'s x-coordinate
579
	 */
176
	public void setCtrl2X(double ctrl2x) {
580
	public void setCtrl2X(double ctrl2x) {
177
		ctrl2X = ctrl2x;
581
		ctrl2X = ctrl2x;
178
	}
582
	}
179
583
584
	/**
585
	 * Sets the second control {@link Point}'s y-coordinate to the given
586
	 * y-coordinate ctrl2y.
587
	 * 
588
	 * @param ctrl2y
589
	 *            the new second control {@link Point}'s y-coordinate
590
	 */
180
	public void setCtrl2Y(double ctrl2y) {
591
	public void setCtrl2Y(double ctrl2y) {
181
		ctrl2Y = ctrl2y;
592
		ctrl2Y = ctrl2y;
182
	}
593
	}
183
594
595
	/**
596
	 * Sets all control points of this {@link CubicCurve} to the given control
597
	 * {@link Point}s.
598
	 * 
599
	 * @param p1
600
	 *            the new start {@link Point}
601
	 * @param ctrl1
602
	 *            the new first control {@link Point}
603
	 * @param ctrl2
604
	 *            the new second control {@link Point}
605
	 * @param p2
606
	 *            the new end {@link Point}
607
	 */
184
	public void setCurve(Point p1, Point ctrl1, Point ctrl2, Point p2) {
608
	public void setCurve(Point p1, Point ctrl1, Point ctrl2, Point p2) {
185
		setP1(p1);
609
		setP1(p1);
186
		setCtrl1(ctrl1);
610
		setCtrl1(ctrl1);
Lines 188-222 Link Here
188
		setP2(p2);
612
		setP2(p2);
189
	}
613
	}
190
614
615
	/**
616
	 * Sets the start {@link Point} of this {@link CubicCurve} to the given
617
	 * {@link Point} p1.
618
	 * 
619
	 * @param p1
620
	 *            the new start {@link Point}
621
	 */
191
	public void setP1(Point p1) {
622
	public void setP1(Point p1) {
192
		this.x1 = p1.x;
623
		this.x1 = p1.x;
193
		this.y1 = p1.y;
624
		this.y1 = p1.y;
194
	}
625
	}
195
626
627
	/**
628
	 * Sets the end {@link Point} of this {@link CubicCurve} to the given
629
	 * {@link Point} p2.
630
	 * 
631
	 * @param p2
632
	 *            the new end {@link Point}
633
	 */
196
	public void setP2(Point p2) {
634
	public void setP2(Point p2) {
197
		this.x2 = p2.x;
635
		this.x2 = p2.x;
198
		this.y2 = p2.y;
636
		this.y2 = p2.y;
199
	}
637
	}
200
638
639
	/**
640
	 * Sets the x-coordinate of the start {@link Point} of this
641
	 * {@link CubicCurve} to x1.
642
	 * 
643
	 * @param x1
644
	 *            the new start {@link Point}'s x-coordinate
645
	 */
201
	public void setX1(double x1) {
646
	public void setX1(double x1) {
202
		this.x1 = x1;
647
		this.x1 = x1;
203
	}
648
	}
204
649
650
	/**
651
	 * Sets the x-coordinate of the end {@link Point} of this {@link CubicCurve}
652
	 * to x2.
653
	 * 
654
	 * @param x2
655
	 *            the new end {@link Point}'s x-coordinate
656
	 */
205
	public void setX2(double x2) {
657
	public void setX2(double x2) {
206
		this.x2 = x2;
658
		this.x2 = x2;
207
	}
659
	}
208
660
661
	/**
662
	 * Sets the y-coordinate of the start {@link Point} of this
663
	 * {@link CubicCurve} to y1.
664
	 * 
665
	 * @param y1
666
	 *            the new start {@link Point}'s y-coordinate
667
	 */
209
	public void setY1(double y1) {
668
	public void setY1(double y1) {
210
		this.y1 = y1;
669
		this.y1 = y1;
211
	}
670
	}
212
671
672
	/**
673
	 * Sets the y-coordinate of the end {@link Point} of this {@link CubicCurve}
674
	 * to y2.
675
	 * 
676
	 * @param y2
677
	 *            the new end {@link Point}'s y-coordinate
678
	 */
213
	public void setY2(double y2) {
679
	public void setY2(double y2) {
214
		this.y2 = y2;
680
		this.y2 = y2;
215
	}
681
	}
216
682
217
	/*
683
	/**
218
	 * (non-Javadoc)
219
	 * 
220
	 * @see org.eclipse.gef4.geometry.shapes.Geometry#toPath()
684
	 * @see org.eclipse.gef4.geometry.shapes.Geometry#toPath()
221
	 */
685
	 */
222
	public Path toPath() {
686
	public Path toPath() {
Lines 226-229 Link Here
226
		return p;
690
		return p;
227
	}
691
	}
228
692
693
	/**
694
	 * Get a single {@link Point} on this CubicCurve at parameter t.
695
	 * 
696
	 * @param t
697
	 *            in range [0,1]
698
	 * @return the {@link Point} at parameter t
699
	 */
700
	public Point get(double t) {
701
		if (!(PrecisionUtils.greaterEqual(t, 0) && PrecisionUtils.smallerEqual(
702
				t, 1))) {
703
			throw new IllegalArgumentException(
704
					"Paramter t is out of range! t = " + t + " !in_range(0,1)");
705
		}
706
707
		// compensate rounding effects
708
		if (t < 0) {
709
			t = 0;
710
		} else if (t > 1) {
711
			t = 1;
712
		}
713
714
		double d = 1 - t;
715
		return getP1().getScaled(d * d * d)
716
				.getTranslated(getCtrl1().getScaled(3 * t * d * d))
717
				.getTranslated(getCtrl2().getScaled(3 * t * t * d))
718
				.getTranslated(getP2().getScaled(t * t * t));
719
	}
720
229
}
721
}
(-)src/org/eclipse/gef4/geometry/shapes/Ellipse.java (-10 / +155 lines)
Lines 13-18 Link Here
13
package org.eclipse.gef4.geometry.shapes;
13
package org.eclipse.gef4.geometry.shapes;
14
14
15
import java.util.ArrayList;
15
import java.util.ArrayList;
16
import java.util.Arrays;
17
import java.util.HashSet;
16
import java.util.Iterator;
18
import java.util.Iterator;
17
import java.util.List;
19
import java.util.List;
18
20
Lines 101-108 Link Here
101
	 * @see Geometry#contains(Point)
103
	 * @see Geometry#contains(Point)
102
	 */
104
	 */
103
	public boolean contains(Point p) {
105
	public boolean contains(Point p) {
104
		// point has to fulfill (x/a)^2 + (y/b)^2 = 1, where a = width/2 and b =
106
		// point has to fulfill (x/a)^2 + (y/b)^2 <= 1, where a = width/2 and b
105
		// height/2, if ellipse is centered around origin, so we have to
107
		// = height/2, if ellipse is centered around origin, so we have to
106
		// normalize point p by subtracting the center
108
		// normalize point p by subtracting the center
107
		double normalizedX = p.x - (x + width / 2);
109
		double normalizedX = p.x - (x + width / 2);
108
		double normalizedY = p.y - (y + height / 2);
110
		double normalizedY = p.y - (y + height / 2);
Lines 113-118 Link Here
113
	}
115
	}
114
116
115
	/**
117
	/**
118
	 * Tests if this {@link Ellipse} contains the given {@link Polyline}
119
	 * polyline.
120
	 * 
121
	 * @param polyline
122
	 * @return true if it is contained, false otherwise
123
	 */
124
	public boolean contains(Polyline polyline) {
125
		for (Line segment : polyline.getSegments()) {
126
			if (!contains(segment)) {
127
				return false;
128
			}
129
		}
130
		return true;
131
	}
132
133
	/**
134
	 * Tests if this {@link Ellipse} contains the given {@link Polygon} polygon.
135
	 * 
136
	 * @param polygon
137
	 * @return true if it is contained, false otherwise
138
	 */
139
	public boolean contains(Polygon polygon) {
140
		for (Line segment : polygon.getSegments()) {
141
			if (!contains(segment)) {
142
				return false;
143
			}
144
		}
145
		return true;
146
	}
147
148
	/**
116
	 * @see Geometry#contains(Rectangle)
149
	 * @see Geometry#contains(Rectangle)
117
	 */
150
	 */
118
	public boolean contains(Rectangle r) {
151
	public boolean contains(Rectangle r) {
Lines 305-317 Link Here
305
		double dx = x2 - x1;
338
		double dx = x2 - x1;
306
339
307
		// special-case the vertical line
340
		// special-case the vertical line
308
		if (PrecisionUtils.equal(dx, 0)) {
341
		if (PrecisionUtils.equal(dx, 0, +2)) {
309
			// vertical line
342
			// vertical line
310
			if (PrecisionUtils.smallerEqual(-a, x1)
343
			if (PrecisionUtils.smallerEqual(-a, x1)
311
					&& PrecisionUtils.smallerEqual(x1, a)) { // -a <= x1 <= a
344
					&& PrecisionUtils.smallerEqual(x1, a)) { // -a <= x1 <= a
312
				// inside the ellipse
345
				// inside the ellipse
313
				double y = Math.sqrt(PrecisionUtils.round(bSq
346
				double rad = bSq * (1 - x1 * x1 / aSq);
314
						* (1 - x1 * x1 / aSq)));
347
				double y = rad < 0 ? 0 : Math.sqrt(rad);
315
348
316
				if (PrecisionUtils.greaterEqual(y1, y)) {
349
				if (PrecisionUtils.greaterEqual(y1, y)) {
317
					if (PrecisionUtils.smallerEqual(y2, y)) {
350
					if (PrecisionUtils.smallerEqual(y2, y)) {
Lines 348-363 Link Here
348
381
349
			// check if equation has at least one solution
382
			// check if equation has at least one solution
350
			double d = p * p / 4 - q;
383
			double d = p * p / 4 - q;
351
			if (PrecisionUtils.smaller(d, 0)) {
384
			if (PrecisionUtils.equal(d, 0, +2)) {
352
				// discriminant smaller zero, so no solutions possible
353
			} else if (PrecisionUtils.equal(d, 0)) {
354
				// discriminant equals zero, so one possible solution
385
				// discriminant equals zero, so one possible solution
355
				double px = -p / 2;
386
				double px = -p / 2;
356
				double py = px * m + n;
387
				double py = px * m + n;
357
				intersections.add(new Point(px, py));
388
				intersections.add(new Point(px, py));
358
			} else {
389
			} else if (d > 0) {
359
				// discriminant greater than zero, so two possible solutions
390
				// discriminant greater than zero, so two possible solutions
360
				double sqrt = Math.sqrt(PrecisionUtils.round(d));
391
				double sqrt = d < 0 ? 0 : Math.sqrt(d);
361
392
362
				// first
393
				// first
363
				double px = -p / 2 + sqrt;
394
				double px = -p / 2 + sqrt;
Lines 450-455 Link Here
450
	}
481
	}
451
482
452
	/**
483
	/**
484
	 * Tests if this {@link Ellipse} intersects the given {@link Polyline}
485
	 * polyline.
486
	 * 
487
	 * @param polyline
488
	 * @return true if they intersect, false otherwise
489
	 */
490
	public boolean intersects(Polyline polyline) {
491
		for (Line segment : polyline.getSegments()) {
492
			if (intersects(segment)) {
493
				return true;
494
			}
495
		}
496
		return false;
497
	}
498
499
	/**
500
	 * Tests if this {@link Ellipse} intersects the given {@link Polygon}
501
	 * polygon.
502
	 * 
503
	 * @param polygon
504
	 * @return true if they intersect, false otherwise
505
	 */
506
	public boolean intersects(Polygon polygon) {
507
		for (Line segment : polygon.getSegments()) {
508
			if (intersects(segment)) {
509
				return true;
510
			}
511
		}
512
		return false;
513
	}
514
515
	/**
453
	 * At least one common point, which includes containment (check
516
	 * At least one common point, which includes containment (check
454
	 * getIntersections() to check if this is a true intersection).
517
	 * getIntersections() to check if this is a true intersection).
455
	 * 
518
	 * 
Lines 534-537 Link Here
534
		return "Ellipse: (" + x + ", " + y + ", " + //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
597
		return "Ellipse: (" + x + ", " + y + ", " + //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
535
				width + ", " + height + ")";//$NON-NLS-2$//$NON-NLS-1$
598
				width + ", " + height + ")";//$NON-NLS-2$//$NON-NLS-1$
536
	}
599
	}
600
601
	/**
602
	 * Calculates the intersections of this {@link Ellipse} with the given other
603
	 * {@link Ellipse}.
604
	 * 
605
	 * @param e2
606
	 * @return points of intersection
607
	 */
608
	public Point[] getIntersections(Ellipse e2) {
609
		if (equals(e2)) {
610
			return new Point[] {};
611
		}
612
613
		HashSet<Point> intersections = new HashSet<Point>();
614
615
		for (CubicCurve seg : getBorderSegments()) {
616
			intersections.addAll(Arrays.asList(e2.getIntersections(seg)));
617
		}
618
619
		return intersections.toArray(new Point[] {});
620
	}
621
622
	/**
623
	 * Calculates the points of intersection of this {@link Ellipse} and the
624
	 * given {@link CubicCurve}.
625
	 * 
626
	 * @param curve
627
	 * @return points of intersection
628
	 */
629
	public Point[] getIntersections(CubicCurve curve) {
630
		HashSet<Point> intersections = new HashSet<Point>();
631
632
		for (CubicCurve seg : getBorderSegments()) {
633
			intersections.addAll(Arrays.asList(curve.getIntersections(seg)));
634
		}
635
636
		return intersections.toArray(new Point[] {});
637
	}
638
639
	/**
640
	 * Calculates the border segments of this {@link Ellipse}. The
641
	 * border-segments are approximated by {@link CubicCurve}s. These curves are
642
	 * generated as in the {@link Ellipse#toPath()} method.
643
	 * 
644
	 * @return border-segments
645
	 */
646
	public CubicCurve[] getBorderSegments() {
647
		CubicCurve[] segs = new CubicCurve[4];
648
		// see http://whizkidtech.redprince.net/bezier/circle/kappa/ for details
649
		// on the approximation used here
650
		final double kappa = 4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d;
651
		double a = width / 2;
652
		double b = height / 2;
653
654
		double ox = x + a;
655
		double oy = y;
656
657
		segs[0] = new CubicCurve(ox, oy, x + a + kappa * a, y, x + width, y + b
658
				- kappa * b, x + width, y + b);
659
660
		ox = x + width;
661
		oy = y + b;
662
663
		segs[1] = new CubicCurve(ox, oy, x + width, y + b + kappa * b, x + a
664
				+ kappa * a, y + height, x + a, y + height);
665
666
		ox = x + a;
667
		oy = y + height;
668
669
		segs[2] = new CubicCurve(ox, oy, x + width / 2 - kappa * width / 2, y
670
				+ height, x, y + height / 2 + kappa * height / 2, x, y + height
671
				/ 2);
672
673
		ox = x;
674
		oy = y + height / 2;
675
676
		segs[3] = new CubicCurve(ox, oy, x,
677
				y + height / 2 - kappa * height / 2, x + width / 2 - kappa
678
						* width / 2, y, x + width / 2, y);
679
680
		return segs;
681
	}
537
}
682
}
(-)src/org/eclipse/gef4/geometry/shapes/Line.java (-1 / +16 lines)
Lines 75-80 Link Here
75
		// TODO: optimize w.r.t object creation
75
		// TODO: optimize w.r.t object creation
76
		Point p1 = getP1();
76
		Point p1 = getP1();
77
		Point p2 = getP2();
77
		Point p2 = getP2();
78
79
		if (p1.equals(p2)) {
80
			return p.equals(p1);
81
		}
82
78
		return new Straight(p1, p2).containsWithinSegment(new Vector(p1),
83
		return new Straight(p1, p2).containsWithinSegment(new Vector(p1),
79
				new Vector(p2), new Vector(p));
84
				new Vector(p2), new Vector(p));
80
	}
85
	}
Lines 272-280 Link Here
272
		// TODO: optimize w.r.t. object creation
277
		// TODO: optimize w.r.t. object creation
273
		Point p1 = getP1();
278
		Point p1 = getP1();
274
		Point p2 = getP2();
279
		Point p2 = getP2();
275
		Straight s1 = new Straight(p1, p2);
280
281
		if (p1.equals(p2)) {
282
			return l.contains(p1);
283
		}
284
276
		Point lp1 = l.getP1();
285
		Point lp1 = l.getP1();
277
		Point lp2 = l.getP2();
286
		Point lp2 = l.getP2();
287
288
		if (lp1.equals(lp2)) {
289
			return contains(lp1);
290
		}
291
292
		Straight s1 = new Straight(p1, p2);
278
		Straight s2 = new Straight(lp1, lp2);
293
		Straight s2 = new Straight(lp1, lp2);
279
		Vector v1 = new Vector(p1);
294
		Vector v1 = new Vector(p1);
280
		Vector v2 = new Vector(p2);
295
		Vector v2 = new Vector(p2);
(-)src/org/eclipse/gef4/geometry/shapes/Polygon.java (+278 lines)
Lines 11-16 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.shapes;
12
package org.eclipse.gef4.geometry.shapes;
13
13
14
import java.util.ArrayList;
15
16
import org.eclipse.gef4.geometry.Angle;
14
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.Point;
15
import org.eclipse.gef4.geometry.euclidean.Straight;
18
import org.eclipse.gef4.geometry.euclidean.Straight;
16
import org.eclipse.gef4.geometry.euclidean.Vector;
19
import org.eclipse.gef4.geometry.euclidean.Vector;
Lines 126-131 Link Here
126
	}
129
	}
127
130
128
	/**
131
	/**
132
	 * Returns the points of intersection between this {@link Polygon} and the
133
	 * given {@link Line} l.
134
	 * 
135
	 * @param l
136
	 * @return The points of intersection.
137
	 */
138
	public Point[] getIntersections(Line l) {
139
		ArrayList<Point> intersections = new ArrayList<Point>();
140
141
		for (Line segment : getSegments()) {
142
			Point poi = segment.getIntersection(l);
143
			if (poi != null) {
144
				intersections.add(poi);
145
			}
146
		}
147
148
		return intersections.toArray(new Point[] {});
149
	}
150
151
	/**
152
	 * Returns the points of intersection between this {@link Polygon} and the
153
	 * given other {@link Polygon} polygon.
154
	 * 
155
	 * @param polygon
156
	 * @return The points of intersection.
157
	 */
158
	public Point[] getIntersections(Polygon polygon) {
159
		ArrayList<Point> intersections = new ArrayList<Point>();
160
161
		for (Line segment : polygon.getSegments()) {
162
			for (Point poi : getIntersections(segment)) {
163
				intersections.add(poi);
164
			}
165
		}
166
167
		return intersections.toArray(new Point[] {});
168
	}
169
170
	/**
171
	 * Returns the points of intersection between this {@link Polygon} and the
172
	 * given {@link Polyline} polyline.
173
	 * 
174
	 * @param polyline
175
	 * @return The points of intersection.
176
	 */
177
	public Point[] getIntersections(Polyline polyline) {
178
		ArrayList<Point> intersections = new ArrayList<Point>();
179
180
		for (Line segment : polyline.getSegments()) {
181
			for (Point poi : getIntersections(segment)) {
182
				intersections.add(poi);
183
			}
184
		}
185
186
		return intersections.toArray(new Point[] {});
187
	}
188
189
	/**
190
	 * Returns the points of intersection between this {@link Polygon} and the
191
	 * given {@link Rectangle} rect.
192
	 * 
193
	 * @param rect
194
	 * @return The points of intersection.
195
	 */
196
	public Point[] getIntersections(Rectangle rect) {
197
		ArrayList<Point> intersections = new ArrayList<Point>();
198
199
		for (Line segment : rect.getSegments()) {
200
			for (Point poi : getIntersections(segment)) {
201
				intersections.add(poi);
202
			}
203
		}
204
205
		return intersections.toArray(new Point[] {});
206
	}
207
208
	/**
209
	 * Returns the points of intersection between this {@link Polygon} and the
210
	 * given {@link Ellipse} e.
211
	 * 
212
	 * @param e
213
	 * @return The points of intersection.
214
	 */
215
	public Point[] getIntersections(Ellipse e) {
216
		return e.getIntersections(this);
217
	}
218
219
	/**
129
	 * @see Geometry#contains(Point)
220
	 * @see Geometry#contains(Point)
130
	 */
221
	 */
131
	public boolean contains(Point p) {
222
	public boolean contains(Point p) {
Lines 177-182 Link Here
177
	}
268
	}
178
269
179
	/**
270
	/**
271
	 * Tests if the given {@link QuadraticCurve} curve is contained in this
272
	 * {@link Polygon}.
273
	 * 
274
	 * @param curve
275
	 * @return true if it is contained, false otherwise
276
	 */
277
	public boolean contains(QuadraticCurve curve) {
278
		if (contains(curve.getP1()) && contains(curve.getP2())) {
279
			for (Line seg : getSegments()) {
280
				if (curve.intersects(seg)) {
281
					return false;
282
				}
283
			}
284
			return true;
285
		}
286
		return false;
287
	}
288
289
	/**
290
	 * Tests if the given {@link CubicCurve} curve is contained in this
291
	 * {@link Polygon}.
292
	 * 
293
	 * @param curve
294
	 * @return true if it is contained, false otherwise
295
	 */
296
	public boolean contains(CubicCurve curve) {
297
		if (contains(curve.getP1()) && contains(curve.getP2())) {
298
			for (Line seg : getSegments()) {
299
				if (curve.intersects(seg)) {
300
					return false;
301
				}
302
			}
303
			return true;
304
		}
305
		return false;
306
	}
307
308
	/**
309
	 * Tests if the given {@link Ellipse} e is contained in this {@link Polygon}
310
	 * .
311
	 * 
312
	 * @param e
313
	 * @return true if it is contained, false otherwise
314
	 */
315
	public boolean contains(Ellipse e) {
316
		for (CubicCurve curve : e.getBorderSegments()) {
317
			if (!contains(curve)) {
318
				return false;
319
			}
320
		}
321
		return true;
322
	}
323
324
	/**
180
	 * Checks whether the given {@link Polygon} is fully contained within this
325
	 * Checks whether the given {@link Polygon} is fully contained within this
181
	 * {@link Polygon}.
326
	 * {@link Polygon}.
182
	 * 
327
	 * 
Lines 197-202 Link Here
197
	}
342
	}
198
343
199
	/**
344
	/**
345
	 * Tests if the given {@link Polyline} p is contained in this
346
	 * {@link Polygon}.
347
	 * 
348
	 * @param p
349
	 * @return true if it is contained, false otherwise
350
	 */
351
	public boolean contains(Polyline p) {
352
		// all segments of the given polygon have to be contained
353
		Line[] otherSegments = p.getSegments();
354
		for (int i = 0; i < otherSegments.length; i++) {
355
			if (!contains(otherSegments[i])) {
356
				return false;
357
			}
358
		}
359
		return true;
360
	}
361
362
	/**
363
	 * Tests if this {@link Polygon} intersects the given {@link Ellipse} e.
364
	 * 
365
	 * @param e
366
	 * @return true if they intersect, false otherwise
367
	 */
368
	public boolean intersects(Ellipse e) {
369
		return e.intersects(this);
370
	}
371
372
	/**
200
	 * @see Geometry#contains(Rectangle)
373
	 * @see Geometry#contains(Rectangle)
201
	 */
374
	 */
202
	public boolean contains(Rectangle rect) {
375
	public boolean contains(Rectangle rect) {
Lines 277-282 Link Here
277
	}
450
	}
278
451
279
	/**
452
	/**
453
	 * Tests if this {@link Polygon} intersects with the given {@link Polyline}
454
	 * p.
455
	 * 
456
	 * @param p
457
	 * @return true if they intersect, false otherwise
458
	 */
459
	public boolean intersects(Polyline p) {
460
		// reduce to segment intersection test
461
		Line[] otherSegments = p.getSegments();
462
		for (int i = 0; i < otherSegments.length; i++) {
463
			if (intersects(otherSegments[i])) {
464
				return true;
465
			}
466
		}
467
		// no intersection, so we still need to check for containment
468
		return contains(p);
469
	}
470
471
	/**
472
	 * Rotates this {@link Polygon} clock-wise by the given {@link Angle} alpha
473
	 * around the given {@link Point} center.
474
	 * 
475
	 * The rotation is done by
476
	 * <ol>
477
	 * <li>translating this {@link Polygon} by the negated {@link Point} center</li>
478
	 * <li>rotating each {@link Point} of this {@link Polygon} clock-wise by the
479
	 * given {@link Angle} angle</li>
480
	 * <li>translating this {@link Polygon} back by the {@link Point} center</li>
481
	 * </ol>
482
	 * 
483
	 * @param alpha
484
	 *            The rotation {@link Angle}.
485
	 * @param center
486
	 *            The {@link Point} to rotate around.
487
	 * @return This (clock-wise-rotated) {@link Polygon} object.
488
	 */
489
	public Polygon rotateCW(Angle alpha, Point center) {
490
		translate(center.getNegated());
491
		for (Point p : points) {
492
			Point np = new Vector(p).rotateCW(alpha).toPoint();
493
			p.x = np.x;
494
			p.y = np.y;
495
		}
496
		translate(center);
497
		return this;
498
	}
499
500
	/**
501
	 * Rotates this {@link Polygon} counter-clock-wise by the given
502
	 * {@link Angle} alpha around the given {@link Point} center.
503
	 * 
504
	 * The rotation is done by
505
	 * <ol>
506
	 * <li>translating this {@link Polygon} by the negated {@link Point} center</li>
507
	 * <li>rotating each {@link Point} of this {@link Polygon}
508
	 * counter-clock-wise by the given {@link Angle} angle</li>
509
	 * <li>translating this {@link Polygon} back by the {@link Point} center</li>
510
	 * </ol>
511
	 * 
512
	 * @param alpha
513
	 *            The rotation {@link Angle}.
514
	 * @param center
515
	 *            The {@link Point} to rotate around.
516
	 * @return This (counter-clock-wise-rotated) {@link Polygon} object.
517
	 */
518
	public Polygon rotateCCW(Angle alpha, Point center) {
519
		translate(center.getNegated());
520
		for (Point p : points) {
521
			Point np = new Vector(p).rotateCCW(alpha).toPoint();
522
			p.x = np.x;
523
			p.y = np.y;
524
		}
525
		translate(center);
526
		return this;
527
	}
528
529
	/**
280
	 * Returns a copy of the points that make up this {@link Polygon}, where a
530
	 * Returns a copy of the points that make up this {@link Polygon}, where a
281
	 * segment of the {@link Polygon} is represented between each two succeeding
531
	 * segment of the {@link Polygon} is represented between each two succeeding
282
	 * {@link Point}s in the sequence, and from the last back to the first.
532
	 * {@link Point}s in the sequence, and from the last back to the first.
Lines 447-452 Link Here
447
	}
697
	}
448
698
449
	/**
699
	/**
700
	 * Scales this {@link Polygon} object by the given factor from the given
701
	 * center {@link Point}.
702
	 * 
703
	 * The scaling is done by
704
	 * <ol>
705
	 * <li>translating this {@link Polygon} by the negated center {@link Point}</li>
706
	 * <li>scaling the individual {@link Polygon} {@link Point}s</li>
707
	 * <li>translating this {@link Polygon} back</li>
708
	 * </ol>
709
	 * 
710
	 * @param factor
711
	 *            The scale-factor.
712
	 * @param center
713
	 *            The rotation {@link Point}.
714
	 * @return This (scaled) {@link Polygon} object.
715
	 */
716
	public Polygon scale(double factor, Point center) {
717
		translate(center.getNegated());
718
		for (Point p : points) {
719
			Point np = p.getScaled(factor);
720
			p.x = np.x;
721
			p.y = np.y;
722
		}
723
		translate(center);
724
		return this;
725
	}
726
727
	/**
450
	 * Moves this Polygon horizontally by dx and vertically by dy, then returns
728
	 * Moves this Polygon horizontally by dx and vertically by dy, then returns
451
	 * this Rectangle for convenience.
729
	 * this Rectangle for convenience.
452
	 * 
730
	 * 
(-)src/org/eclipse/gef4/geometry/shapes/QuadraticCurve.java (-22 / +520 lines)
Lines 11-18 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.shapes;
12
package org.eclipse.gef4.geometry.shapes;
13
13
14
import java.util.Arrays;
15
import java.util.HashSet;
16
14
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.Point;
15
import org.eclipse.gef4.geometry.transform.AffineTransform;
18
import org.eclipse.gef4.geometry.transform.AffineTransform;
19
import org.eclipse.gef4.geometry.utils.PolynomCalculations;
20
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
16
21
17
/**
22
/**
18
 * Represents the geometric shape of a quadratic Bézier curve.
23
 * Represents the geometric shape of a quadratic Bézier curve.
Lines 23-64 Link Here
23
public class QuadraticCurve implements Geometry {
28
public class QuadraticCurve implements Geometry {
24
29
25
	private static final long serialVersionUID = 1L;
30
	private static final long serialVersionUID = 1L;
26
27
	private double x1, y1, ctrlX, ctrlY, x2, y2;
31
	private double x1, y1, ctrlX, ctrlY, x2, y2;
28
32
29
	public boolean contains(Point p) {
33
	/**
30
		// TODO Auto-generated method stub
34
	 * Constructs a new QuadraticCurve object from the given points.
31
		return false;
35
	 * 
32
	}
36
	 * @param p1
33
37
	 *            the start point
34
	public boolean contains(Rectangle r) {
38
	 * @param pCtrl
35
		// TODO Auto-generated method stub
39
	 *            the control point
36
		return false;
40
	 * @param p2
37
	}
41
	 *            the end point
38
42
	 */
39
	public Rectangle getBounds() {
43
	public QuadraticCurve(Point p1, Point pCtrl, Point p2) {
40
		// TODO Auto-generated method stub
44
		setP1(p1);
41
		return null;
45
		setCtrl(pCtrl);
42
	}
46
		setP2(p2);
43
47
	}
48
49
	/**
50
	 * Constructs a new QuadraticCurve object from the given point coordinates.
51
	 * 
52
	 * @param x1
53
	 *            the start point's x-coordinate
54
	 * @param y1
55
	 *            the start point's y-coordinate
56
	 * @param xCtrl
57
	 *            the control point's x-coordinate
58
	 * @param yCtrl
59
	 *            the control point's y-coordinate
60
	 * @param x2
61
	 *            the end point's x-coordinate
62
	 * @param y2
63
	 *            the end point's y-coordinate
64
	 */
65
	public QuadraticCurve(double x1, double y1, double xCtrl, double yCtrl,
66
			double x2, double y2) {
67
		setP1(new Point(x1, y1));
68
		setCtrl(new Point(xCtrl, yCtrl));
69
		setP2(new Point(x2, y2));
70
	}
71
72
	/**
73
	 * Get the control point.
74
	 * 
75
	 * @return a Point object representing the control point
76
	 */
44
	public Point getCtrl() {
77
	public Point getCtrl() {
45
		return new Point(ctrlX, ctrlY);
78
		return new Point(ctrlX, ctrlY);
46
	}
79
	}
47
80
81
	/**
82
	 * Get the control point's x-coordinate.
83
	 * 
84
	 * @return the control point's x-coordinate
85
	 */
48
	public double getCtrlX() {
86
	public double getCtrlX() {
49
		return ctrlX;
87
		return ctrlX;
50
	}
88
	}
51
89
90
	/**
91
	 * Get the control point's y-coordinate.
92
	 * 
93
	 * @return the control point's y-coordinate
94
	 */
52
	public double getCtrlY() {
95
	public double getCtrlY() {
53
		return ctrlY;
96
		return ctrlY;
54
	}
97
	}
55
98
99
	/**
100
	 * Get the curve's starting point.
101
	 * 
102
	 * @return the curve's starting point
103
	 */
56
	public Point getP1() {
104
	public Point getP1() {
57
		return new Point(x1, y1);
105
		return new Point(x1, y1);
58
	}
106
	}
59
107
108
	/**
109
	 * Get the curve's ending point.
110
	 * 
111
	 * @return the curve's ending point
112
	 */
60
	public Point getP2() {
113
	public Point getP2() {
61
		return new Point(x1, y1);
114
		return new Point(x2, y2);
62
	}
115
	}
63
116
64
	public Geometry getTransformed(AffineTransform t) {
117
	public Geometry getTransformed(AffineTransform t) {
Lines 66-131 Link Here
66
		return null;
119
		return null;
67
	}
120
	}
68
121
122
	/**
123
	 * Returns the x-coordinate of the curve's starting point.
124
	 * 
125
	 * @return the x-coordinate of the curve's starting point
126
	 */
69
	public double getX1() {
127
	public double getX1() {
70
		return x1;
128
		return x1;
71
	}
129
	}
72
130
131
	/**
132
	 * Returns the x-coordinate of the curve's ending point.
133
	 * 
134
	 * @return the x-coordinate of the curve's ending point
135
	 */
73
	public double getX2() {
136
	public double getX2() {
74
		return x2;
137
		return x2;
75
	}
138
	}
76
139
140
	/**
141
	 * Returns the y-coordinate of the curve's starting point.
142
	 * 
143
	 * @return the y-coordinate of the curve's starting point
144
	 */
77
	public double getY1() {
145
	public double getY1() {
78
		return y1;
146
		return y1;
79
	}
147
	}
80
148
149
	/**
150
	 * Returns the y-coordinate of the curve's ending point.
151
	 * 
152
	 * @return the y-coordinate of the curve's ending point
153
	 */
81
	public double getY2() {
154
	public double getY2() {
82
		return y2;
155
		return y2;
83
	}
156
	}
84
157
85
	public boolean intersects(Rectangle r) {
158
	/**
86
		// TODO Auto-generated method stub
159
	 * Sets the curve's control point.
87
		return false;
160
	 * 
88
	}
161
	 * @param ctrl
89
162
	 */
90
	public void setCtrl(Point ctrl) {
163
	public void setCtrl(Point ctrl) {
91
		this.ctrlX = ctrl.x;
164
		this.ctrlX = ctrl.x;
92
		this.ctrlY = ctrl.y;
165
		this.ctrlY = ctrl.y;
93
	}
166
	}
94
167
168
	/**
169
	 * Sets the x-coordinate of the curve's control point.
170
	 * 
171
	 * @param ctrlX
172
	 */
95
	public void setCtrlX(double ctrlX) {
173
	public void setCtrlX(double ctrlX) {
96
		this.ctrlX = ctrlX;
174
		this.ctrlX = ctrlX;
97
	}
175
	}
98
176
177
	/**
178
	 * Sets the y-coordinate of the curve's control point.
179
	 * 
180
	 * @param ctrlY
181
	 */
99
	public void setCtrlY(double ctrlY) {
182
	public void setCtrlY(double ctrlY) {
100
		this.ctrlY = ctrlY;
183
		this.ctrlY = ctrlY;
101
	}
184
	}
102
185
186
	/**
187
	 * Sets the curve's starting point.
188
	 * 
189
	 * @param p1
190
	 */
103
	public void setP1(Point p1) {
191
	public void setP1(Point p1) {
104
		this.x1 = p1.x;
192
		this.x1 = p1.x;
105
		this.y1 = p1.y;
193
		this.y1 = p1.y;
106
	}
194
	}
107
195
196
	/**
197
	 * Sets the curve's ending point.
198
	 * 
199
	 * @param p2
200
	 */
108
	public void setP2(Point p2) {
201
	public void setP2(Point p2) {
109
		this.x2 = p2.x;
202
		this.x2 = p2.x;
110
		this.y2 = p2.y;
203
		this.y2 = p2.y;
111
	}
204
	}
112
205
206
	/**
207
	 * Sets the x-coordinate of the curve's starting point.
208
	 * 
209
	 * @param x1
210
	 */
113
	public void setX1(double x1) {
211
	public void setX1(double x1) {
114
		this.x1 = x1;
212
		this.x1 = x1;
115
	}
213
	}
116
214
215
	/**
216
	 * Sets the x-coordinate of the curve's ending point.
217
	 * 
218
	 * @param x2
219
	 */
117
	public void setX2(double x2) {
220
	public void setX2(double x2) {
118
		this.x2 = x2;
221
		this.x2 = x2;
119
	}
222
	}
120
223
224
	/**
225
	 * Sets the y-coordinate of the curve's starting point.
226
	 * 
227
	 * @param y1
228
	 */
121
	public void setY1(double y1) {
229
	public void setY1(double y1) {
122
		this.y1 = y1;
230
		this.y1 = y1;
123
	}
231
	}
124
232
233
	/**
234
	 * Sets the y-coordinate of the curve's ending point.
235
	 * 
236
	 * @param y2
237
	 */
125
	public void setY2(double y2) {
238
	public void setY2(double y2) {
126
		this.y2 = y2;
239
		this.y2 = y2;
127
	}
240
	}
128
241
242
	/**
243
	 * Transform the QuadraticCurve object to a {@link Path} object with the
244
	 * same shape.
245
	 * 
246
	 * @return a {@link Path} object representing the curve
247
	 */
129
	public Path toPath() {
248
	public Path toPath() {
130
		Path p = new Path();
249
		Path p = new Path();
131
		p.moveTo(x1, y1);
250
		p.moveTo(x1, y1);
Lines 133-136 Link Here
133
		return p;
252
		return p;
134
	}
253
	}
135
254
255
	/**
256
	 * Get a single {@link Point} on this QuadraticCurve at parameter t.
257
	 * 
258
	 * @param t
259
	 *            in range [0,1]
260
	 * @return the {@link Point} at parameter t
261
	 */
262
	public Point get(double t) {
263
		if (!(PrecisionUtils.greaterEqual(t, 0) && PrecisionUtils.smallerEqual(
264
				t, 1))) {
265
			throw new IllegalArgumentException(
266
					"Paramter t is out of range! t = " + t + " !in_range(0,1)");
267
		}
268
269
		// compensate rounding effects
270
		if (t < 0) {
271
			t = 0;
272
		} else if (t > 1) {
273
			t = 1;
274
		}
275
276
		return new Point(t * (t * (getP1().x - 2 * getCtrl().x + getP2().x))
277
				+ 2 * (t * (getCtrl().x - getP1().x)) + getP1().x, t
278
				* (t * (getP1().y - 2 * getCtrl().y + getP2().y)) + 2
279
				* (t * (getCtrl().y - getP1().y)) + getP1().y);
280
	}
281
282
	/**
283
	 * Check if the given {@link Point} (approximately) lies on the curve.
284
	 * 
285
	 * @param p
286
	 *            the {@link Point} in question
287
	 * @return true if p lies on the curve, false otherwise
288
	 */
289
	public boolean contains(Point p) {
290
		// find roots of the x(t) - p.x function:
291
		double[] xts = PolynomCalculations.getQuadraticRoots(getX1() - 2
292
				* getCtrlX() + getX2(), 2 * getCtrlX() - 2 * getX1(), getX1()
293
				- p.x);
294
295
		for (double t : xts) {
296
			// t = PrecisionUtils.round(t);
297
			if (PrecisionUtils.greaterEqual(t, 0)
298
					&& PrecisionUtils.smallerEqual(t, 1)) {
299
				return true;
300
			}
301
		}
302
		return false;
303
	}
304
305
	/**
306
	 * How can it possibly contain a {@link Rectangle}?
307
	 * 
308
	 * @param r
309
	 *            the {@link Rectangle} in question
310
	 * @return always false
311
	 */
312
	public boolean contains(Rectangle r) {
313
		return false;
314
	}
315
316
	public boolean equals(Object other) {
317
		QuadraticCurve o = (QuadraticCurve) other;
318
319
		Polygon myPoly = getControlPolygon();
320
		Polygon otherPoly = o.getControlPolygon();
321
322
		return myPoly.equals(otherPoly);
323
	}
324
325
	/**
326
	 * Degree elevation: Returns a {@link CubicCurve} representation of this
327
	 * {@link QuadraticCurve}.
328
	 * 
329
	 * @return A {@link CubicCurve} that represents this {@link QuadraticCurve}.
330
	 */
331
	public CubicCurve getElevated() {
332
		Point[] controlPoints = new Point[4];
333
334
		// "Curves and Surfaces for Computer Aided Geometric Design" by Farin,
335
		// Gerald E., Academic Press 1988
336
		controlPoints[0] = getP1();
337
		controlPoints[1] = getP1().getScaled(1 / 3).getTranslated(
338
				getCtrl().getScaled(2 / 3));
339
		controlPoints[2] = getCtrl().getScaled(2 / 3).getTranslated(
340
				getP2().getScaled(1 / 3));
341
		controlPoints[3] = getP2();
342
343
		return new CubicCurve(controlPoints[0], controlPoints[1],
344
				controlPoints[2], controlPoints[3]);
345
	}
346
347
	/**
348
	 * Returns the bounds of this QuadraticCurve. The bounds are calculated by
349
	 * examining the extreme points of the x(t) and y(t) function
350
	 * representations of this QuadraticCurve.
351
	 * 
352
	 * @return the bounds {@link Rectangle}
353
	 */
354
	public Rectangle getBounds() {
355
		// extremes of the x(t) and y(t) functions:
356
		double[] xts;
357
		try {
358
			xts = PolynomCalculations.getLinearRoots(2 * (getX1() - 2
359
					* getCtrlX() + getX2()), 2 * (getCtrlX() - getX1()));
360
		} catch (ArithmeticException x) {
361
			return new Rectangle(getP1(), getP2());
362
		}
363
364
		double xmin = getX1(), xmax = getX1();
365
		if (getX2() < xmin) {
366
			xmin = getX2();
367
		} else {
368
			xmax = getX2();
369
		}
370
371
		for (double t : xts) {
372
			if (t >= 0 && t <= 1) {
373
				double x = get(t).x;
374
				if (x < xmin) {
375
					xmin = x;
376
				} else if (x > xmax) {
377
					xmax = x;
378
				}
379
			}
380
		}
381
382
		double[] yts;
383
		try {
384
			yts = PolynomCalculations.getLinearRoots(2 * (getY1() - 2
385
					* getCtrlY() + getY2()), 2 * (getCtrlY() - getY1()));
386
		} catch (ArithmeticException x) {
387
			return new Rectangle(getP1(), getP2());
388
		}
389
390
		double ymin = getY1(), ymax = getY1();
391
		if (getY2() < ymin) {
392
			ymin = getY2();
393
		} else {
394
			ymax = getY2();
395
		}
396
397
		for (double t : yts) {
398
			if (t >= 0 && t <= 1) {
399
				double y = get(t).y;
400
				if (y < ymin) {
401
					ymin = y;
402
				} else if (y > ymax) {
403
					ymax = y;
404
				}
405
			}
406
		}
407
408
		return new Rectangle(new Point(xmin, ymin), new Point(xmax, ymax));
409
	}
410
411
	private Polygon getControlPolygon() {
412
		return new Polygon(getP1(), getCtrl(), getP2());
413
	}
414
415
	/**
416
	 * Returns the points of intersection between this {@link QuadraticCurve}
417
	 * and the given {@link Line} l.
418
	 * 
419
	 * @param l
420
	 * @return The points of intersection.
421
	 */
422
	public Point[] getIntersections(Line l) {
423
		return getIntersections(this, 0, 1, l);
424
	}
425
426
	private static double getArea(Polygon p) {
427
		Rectangle r = p.getBounds();
428
		return r.getWidth() * r.getHeight();
429
	}
430
431
	private static Point[] getIntersections(QuadraticCurve p, double ps,
432
			double pe, Line l) {
433
		// parameter convergence test
434
		double pm = (ps + pe) / 2;
435
436
		if (PrecisionUtils.equal(ps, pe, +2)) {
437
			return new Point[] { p.get(pm) };
438
		}
439
440
		// no parameter convergence
441
442
		// clip the curve
443
		QuadraticCurve pc = p.clip(ps, pe);
444
445
		// check the control polygon
446
		Polygon polygon = pc.getControlPolygon();
447
448
		if (polygon.intersects(l)) {
449
			// area test
450
			if (PrecisionUtils.equal(getArea(polygon), 0, +2)) {
451
				// line/line intersection fallback for such small curves
452
				Point poi = new Line(pc.getP1(), pc.getP2()).getIntersection(l);
453
				if (poi != null) {
454
					return new Point[] { poi };
455
				}
456
				return new Point[] {};
457
			}
458
459
			// individually test the curves left and right sides for points of
460
			// intersection
461
			HashSet<Point> intersections = new HashSet<Point>();
462
463
			intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, l)));
464
			intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, l)));
465
466
			return intersections.toArray(new Point[] {});
467
		}
468
469
		// no intersections
470
		return new Point[] {};
471
	}
472
473
	private static Point[] getIntersections(QuadraticCurve p, double ps,
474
			double pe, QuadraticCurve q, double qs, double qe) {
475
		// parameter convergence test
476
		double pm = (ps + pe) / 2;
477
		double qm = (qs + qe) / 2;
478
479
		if (PrecisionUtils.equal(ps, pe)) {
480
			return new Point[] { p.get(pm) };
481
		}
482
483
		if (PrecisionUtils.equal(qs, qe)) {
484
			return new Point[] { q.get(qm) };
485
		}
486
487
		// no parameter convergence
488
489
		// clip to parameter ranges
490
		QuadraticCurve pc = p.clip(ps, pe);
491
		QuadraticCurve qc = q.clip(qs, qe);
492
493
		// check the control polygons
494
		Polygon pPoly = pc.getControlPolygon();
495
		Polygon qPoly = qc.getControlPolygon();
496
497
		if (pPoly.intersects(qPoly)) {
498
			// check the polygon's areas
499
			double pArea = getArea(pPoly);
500
			double qArea = getArea(qPoly);
501
502
			if (PrecisionUtils.equal(pArea, 0, -2)
503
					&& PrecisionUtils.equal(qArea, 0, -2)) {
504
				// return line/line intersection
505
				Point poi = new Line(pc.getP1(), pc.getP2())
506
						.getIntersection(new Line(qc.getP1(), qc.getP2()));
507
				if (poi != null) {
508
					return new Point[] { poi };
509
				}
510
				return new Point[] {};
511
			}
512
513
			// areas not small enough
514
515
			// individually test the left and right parts of the curves for
516
			// points of intersection
517
			HashSet<Point> intersections = new HashSet<Point>();
518
519
			intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
520
					qs, qm)));
521
			intersections.addAll(Arrays.asList(getIntersections(p, ps, pm, q,
522
					qm, qe)));
523
			intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
524
					qs, qm)));
525
			intersections.addAll(Arrays.asList(getIntersections(p, pm, pe, q,
526
					qm, qe)));
527
528
			return intersections.toArray(new Point[] {});
529
		}
530
531
		// no intersections
532
		return new Point[] {};
533
	}
534
535
	/**
536
	 * Calculates the intersections of two {@link QuadraticCurve}s using the
537
	 * subdivision algorithm.
538
	 * 
539
	 * @param other
540
	 * @return points of intersection
541
	 */
542
	public Point[] getIntersections(QuadraticCurve other) {
543
		return getIntersections(this, 0, 1, other, 0, 1);
544
	}
545
546
	/**
547
	 * Checks if two {@link QuadraticCurve}s intersect each other. (Costly)
548
	 * 
549
	 * @param other
550
	 * @return true if the two curves intersect. false otherwise
551
	 */
552
	public boolean intersects(QuadraticCurve other) {
553
		return getIntersections(other).length > 0;
554
	}
555
556
	/**
557
	 * Checks if this {@link QuadraticCurve} intersects with the given line.
558
	 * (Costly)
559
	 * 
560
	 * TODO: implement a faster algorithm for this intersection-test.
561
	 * 
562
	 * @param l
563
	 * @return true if they intersect, false otherwise.
564
	 */
565
	public boolean intersects(Line l) {
566
		return getIntersections(l).length > 0;
567
	}
568
569
	public boolean intersects(Rectangle r) {
570
		for (Line l : r.getSegments()) {
571
			if (intersects(l)) {
572
				return true;
573
			}
574
		}
575
		return false;
576
	}
577
578
	private Point ratioPoint(Point p, Point q, double ratio) {
579
		return p.getTranslated(q.getTranslated(p.getNegated()).getScaled(ratio));
580
	}
581
582
	/**
583
	 * Splits this QuadraticCurve using the de Casteljau algorithm at parameter
584
	 * t into two separate QuadraticCurve objects. The returned
585
	 * {@link QuadraticCurve}s are the curves for [0, t] and [t, 1].
586
	 * 
587
	 * @param t
588
	 *            in range [0,1]
589
	 * @return two QuadraticCurve objects constituting the original curve: 1.
590
	 *         [0, t] 2. [t, 1]
591
	 */
592
	public QuadraticCurve[] split(double t) {
593
		if (t < 0 || t > 1) {
594
			throw new IllegalArgumentException(
595
					"Paramter t is out of range! t = " + t + " !in_range(0,1)");
596
		}
597
598
		Point left1 = ratioPoint(getP1(), getCtrl(), t);
599
		Point right1 = ratioPoint(getCtrl(), getP2(), t);
600
		Point split = ratioPoint(left1, right1, t);
601
602
		QuadraticCurve left = new QuadraticCurve(getP1(), left1, split);
603
		QuadraticCurve right = new QuadraticCurve(split, right1, getP2());
604
605
		return new QuadraticCurve[] { left, right };
606
	}
607
608
	/**
609
	 * Clips this {@link QuadraticCurve} at parameter values t1 and t2 so that
610
	 * the resulting {@link QuadraticCurve} is the section of the original
611
	 * {@link QuadraticCurve} for the parameter interval [t1, t2].
612
	 * 
613
	 * @param t1
614
	 * @param t2
615
	 * @return the {@link QuadraticCurve} on the interval [t1, t2]
616
	 */
617
	public QuadraticCurve clip(double t1, double t2) {
618
		if (t1 < 0 || t1 > 1) {
619
			throw new IllegalArgumentException(
620
					"Paramter t1 is out of range! t1 = " + t1
621
							+ " !in_range(0,1)");
622
		}
623
		if (t2 < 0 || t2 > 1) {
624
			throw new IllegalArgumentException(
625
					"Paramter t2 is out of range! t2 = " + t2
626
							+ " !in_range(0,1)");
627
		}
628
629
		QuadraticCurve right = split(t1)[1];
630
		double rightT2 = (t2 - t1) / (1 - t1);
631
		return right.split(rightT2)[0];
632
	}
633
136
}
634
}
(-)src/org/eclipse/gef4/geometry/shapes/Rectangle.java (-8 / +44 lines)
Lines 12-17 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.gef4.geometry.shapes;
13
package org.eclipse.gef4.geometry.shapes;
14
14
15
import org.eclipse.gef4.geometry.Angle;
15
import org.eclipse.gef4.geometry.Dimension;
16
import org.eclipse.gef4.geometry.Dimension;
16
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.transform.AffineTransform;
18
import org.eclipse.gef4.geometry.transform.AffineTransform;
Lines 171-179 Link Here
171
	public boolean contains(double x, double y, double width, double height) {
172
	public boolean contains(double x, double y, double width, double height) {
172
		return PrecisionUtils.smallerEqual(this.x, x)
173
		return PrecisionUtils.smallerEqual(this.x, x)
173
				&& PrecisionUtils.smallerEqual(this.y, y)
174
				&& PrecisionUtils.smallerEqual(this.y, y)
174
				&& PrecisionUtils.greaterEqual(this.x + this.width, x + width)
175
				&& PrecisionUtils.greaterEqual(this.width, width)
175
				&& PrecisionUtils
176
				&& PrecisionUtils.greaterEqual(this.height, height);
176
						.greaterEqual(this.y + this.height, y + height);
177
	}
177
	}
178
178
179
	/**
179
	/**
Lines 264-276 Link Here
264
	 * and height of the given Insets, and returns this for convenience.
264
	 * and height of the given Insets, and returns this for convenience.
265
	 * 
265
	 * 
266
	 * @param left
266
	 * @param left
267
	 *            - the amount to shrink the left side
267
	 *            - the amount to expand the left side
268
	 * @param top
268
	 * @param top
269
	 *            - the amount to shrink the top side
269
	 *            - the amount to expand the top side
270
	 * @param right
270
	 * @param right
271
	 *            - the amount to shrink the right side
271
	 *            - the amount to expand the right side
272
	 * @param bottom
272
	 * @param bottom
273
	 *            - the amount to shrink the bottom side
273
	 *            - the amount to expand the bottom side
274
	 * @return <code>this</code> Rectangle for convenience
274
	 * @return <code>this</code> Rectangle for convenience
275
	 * 
275
	 * 
276
	 */
276
	 */
Lines 492-497 Link Here
492
	}
492
	}
493
493
494
	/**
494
	/**
495
	 * Rotates this {@link Rectangle} clock-wise by the given {@link Angle}
496
	 * alpha around the {@link Point} center.
497
	 * 
498
	 * If the rotation {@link Angle} is not an integer multiple 90°, the
499
	 * resulting figure cannot be expressed as a {@link Rectangle} object.
500
	 * That's why this method returns a {@link Polygon} instead.
501
	 * 
502
	 * @param alpha
503
	 *            the rotation angle
504
	 * @param center
505
	 *            the center point of the rotation
506
	 * @return the rotated rectangle ({@link Polygon})
507
	 */
508
	public Polygon getRotatedCW(Angle alpha, Point center) {
509
		return toPolygon().rotateCW(alpha, center);
510
	}
511
512
	/**
513
	 * Rotates this {@link Rectangle} counter-clock-wise by the given
514
	 * {@link Angle} alpha around the {@link Point} center.
515
	 * 
516
	 * If the rotation {@link Angle} is not an integer multiple 90°, the
517
	 * resulting figure cannot be expressed as a {@link Rectangle} object.
518
	 * That's why this method returns a {@link Polygon} instead.
519
	 * 
520
	 * @param alpha
521
	 *            the rotation angle
522
	 * @param center
523
	 *            the center point of the rotation
524
	 * @return the rotated rectangle ({@link Polygon})
525
	 */
526
	public Polygon getRotatedCCW(Angle alpha, Point center) {
527
		return toPolygon().rotateCCW(alpha, center);
528
	}
529
530
	/**
495
	 * Returns a new Rectangle, where the sides are shrinked by the horizontal
531
	 * Returns a new Rectangle, where the sides are shrinked by the horizontal
496
	 * and vertical values supplied. The center of this Rectangle is kept
532
	 * and vertical values supplied. The center of this Rectangle is kept
497
	 * constant.
533
	 * constant.
Lines 500-506 Link Here
500
	 *            Horizontal reduction amount
536
	 *            Horizontal reduction amount
501
	 * @param v
537
	 * @param v
502
	 *            Vertical reduction amount
538
	 *            Vertical reduction amount
503
	 * @return <code>this</code> for convenience
539
	 * @return the new, shrinked {@link Rectangle}
504
	 */
540
	 */
505
	public Rectangle getShrinked(double h, double v) {
541
	public Rectangle getShrinked(double h, double v) {
506
		return getCopy().shrink(h, v);
542
		return getCopy().shrink(h, v);
(-)src/org/eclipse/gef4/geometry/utils/PolynomCalculations.java (+138 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *     
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.utils;
13
14
/**
15
 * Utility class that implements common polynom calculations such as finding the
16
 * roots of polynoms of degree 2 or 3.
17
 * 
18
 * @author wienand
19
 * 
20
 */
21
public final class PolynomCalculations {
22
	/**
23
	 * Solves a linear polynomial equation of the form a*x + b = 0.
24
	 * 
25
	 * @param a
26
	 *            the coefficient of x^1
27
	 * @param b
28
	 *            the absolute element
29
	 * @return the roots of this polynom
30
	 */
31
	public static final double[] getLinearRoots(double a, double b) {
32
		if (a == 0) {
33
			if (b == 0) {
34
				throw new ArithmeticException(
35
						"The given polynomial equation is always true.");
36
			}
37
			return new double[] {};
38
		}
39
		return new double[] { -b / a };
40
	}
41
42
	/**
43
	 * Solves a quadratic polynomial equation of the form a*x^2 + b*x + c = 0.
44
	 * 
45
	 * @param a
46
	 * @param b
47
	 * @param c
48
	 * @return all real solutions of the given equation. An empty array in the
49
	 *         case of no solutions.
50
	 */
51
	public static final double[] getQuadraticRoots(double a, double b, double c) {
52
		if (a == 0) {
53
			return getLinearRoots(b, c);
54
		}
55
56
		// p-q-formula
57
		double p = b / a;
58
		double q = c / a;
59
		double D = p * p / 4 - q;
60
61
		if (PrecisionUtils.equal(D, 0, +4)) {
62
			return new double[] { -p / 2 };
63
		} else if (D > 0) {
64
			double sqrt = Math.sqrt(D);
65
			return new double[] { sqrt - p / 2, -sqrt - p / 2 };
66
		} else {
67
			return new double[] {};
68
		}
69
	}
70
71
	/**
72
	 * Solves a cubic polynomial equation of the form Ax^3 + Bx^2 + Cx + D = 0.
73
	 * 
74
	 * @param A
75
	 * @param B
76
	 * @param C
77
	 * @param D
78
	 * @return all real solutions of the given equation
79
	 */
80
	public static final double[] getCubicRoots(double A, double B, double C,
81
			double D) {
82
		if (A == 0) {
83
			return getQuadraticRoots(B, C, D);
84
		}
85
86
		double a = B / A;
87
		double b = C / A;
88
		double c = D / A;
89
90
		// reduce to z^3 + pz + q = 0 by substituting x = z - a/3
91
		// (http://en.wikipedia.org/wiki/Cubic_function#Cardano.27s_method)
92
93
		double p = b - a * a / 3;
94
		double q = 2 * a * a * a / 27 - a * b / 3 + c;
95
96
		// short-cuts for p = 0, q = 0:
97
		if (PrecisionUtils.equal(p, 0, +4)) {
98
			// z^3 = -q => z = cbrt(-q) => x = cbrt(-q) - a / 3
99
			return new double[] { Math.cbrt(-q) - a / 3 };
100
		}
101
		if (PrecisionUtils.equal(q, 0, +4)) {
102
			// z^3 - pz = 0 <=> z(z^2 - p) = 0 => z = 0 v z^2 = p => z =
103
			// +-sqrt(p), p >= 0 (p is not zero, because otherwise we would not
104
			// be here)
105
			if (p > 0) {
106
				return new double[] { 0, Math.sqrt(p), -Math.sqrt(p) };
107
			} else {
108
				return new double[] { 0 };
109
			}
110
		}
111
112
		double p_3 = p / 3;
113
		double q_2 = q / 2;
114
115
		D = q_2 * q_2 + p_3 * p_3 * p_3;
116
117
		if (PrecisionUtils.equal(D, 0, +4)) {
118
			// two real solutions
119
			return new double[] { 3 * q / p - a / 3, -3 * q / (2 * p) - a / 3 };
120
		} else if (D > 0) {
121
			// one real solution
122
			double u = Math.cbrt(-q_2 + Math.sqrt(D));
123
			double v = Math.cbrt(-q_2 - Math.sqrt(D));
124
125
			return new double[] { u + v - a / 3 };
126
		} else {
127
			// three real solutions
128
			double r = Math.sqrt(-p_3 * p_3 * p_3);
129
			double phi = Math.acos(-q / (2 * r));
130
			double co = 2 * Math.cbrt(r);
131
132
			// co * cos((phi + k * pi)/3) - a/3, k = 2n, n in N
133
			return new double[] { co * Math.cos(phi / 3) - a / 3,
134
					co * Math.cos((phi + 2 * Math.PI) / 3) - a / 3,
135
					co * Math.cos((phi + 4 * Math.PI) / 3) - a / 3 };
136
		}
137
	}
138
}
(-)src/org/eclipse/gef4/geometry/utils/PrecisionUtils.java (-38 / +84 lines)
Lines 11-18 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.utils;
12
package org.eclipse.gef4.geometry.utils;
13
13
14
import java.math.BigDecimal;
15
16
/**
14
/**
17
 * A utility class for floating point calculations and comparisons that should
15
 * A utility class for floating point calculations and comparisons that should
18
 * guarantee a precision of a given scale, and ignore differences beyond this
16
 * guarantee a precision of a given scale, and ignore differences beyond this
Lines 27-130 Link Here
27
	 * converting to 8 digits scale, so there are no undesired rounding effects
25
	 * converting to 8 digits scale, so there are no undesired rounding effects
28
	 * beyond this precision.
26
	 * beyond this precision.
29
	 */
27
	 */
30
	private static final int ROUNDING_MODE = BigDecimal.ROUND_DOWN;
28
	private static final int DEFAULT_SCALE = 6;
31
	private static final int SCALE = 8;
29
32
	private static final double FRACTION = 1 / Math.pow(10, SCALE);
30
	private static final double calculateFraction(int shift) {
31
		return 1 / Math.pow(10, DEFAULT_SCALE + shift);
32
	}
33
34
	/**
35
	 * @see PrecisionUtils#equal(double, double, int)
36
	 * @param d1
37
	 * @param d2
38
	 * @return result of the comparison
39
	 */
40
	public static final boolean equal(double d1, double d2) {
41
		return equal(d1, d2, 0);
42
	}
33
43
34
	/**
44
	/**
35
	 * Tests whether the two values are regarded to be equal w.r.t. the given
45
	 * Tests whether the two values are regarded to be equal w.r.t. the given
36
	 * scale.
46
	 * shift.
37
	 * 
47
	 * 
38
	 * @param d1
48
	 * @param d1
39
	 *            the first value to test
49
	 *            the first value to test
40
	 * @param d2
50
	 * @param d2
41
	 *            the second value to test
51
	 *            the second value to test
52
	 * @param shift
53
	 *            the delta shift used for this test
42
	 * @return <code>true</code> in case the given two values are identical or
54
	 * @return <code>true</code> in case the given two values are identical or
43
	 *         differ from each other by an amount that is smaller than what is
55
	 *         differ from each other by an amount that is smaller than what is
44
	 *         recognizable by the given scale, <code>false</code> otherwise
56
	 *         recognizable by the shifted delta, <code>false</code> otherwise
45
	 */
57
	 */
46
	public static final boolean equal(double d1, double d2) {
58
	public static final boolean equal(double d1, double d2, int shift) {
47
		return round(d1) == round(d2);
59
		return Math.abs(d1 - d2) <= calculateFraction(shift);
60
	}
61
62
	/**
63
	 * @see PrecisionUtils#greater(double, double, int)
64
	 * @param d1
65
	 * @param d2
66
	 * @return result of the comparison
67
	 */
68
	public static final boolean greater(double d1, double d2) {
69
		return greater(d1, d2, 0);
48
	}
70
	}
49
71
50
	/**
72
	/**
51
	 * Tests whether the first given value is regarded to be greater than the
73
	 * Tests whether the first given value is regarded to be greater than the
52
	 * second value w.r.t. the given scale.
74
	 * second value w.r.t. the given shift.
53
	 * 
75
	 * 
54
	 * @param d1
76
	 * @param d1
55
	 *            the first value to test
77
	 *            the first value to test
56
	 * @param d2
78
	 * @param d2
57
	 *            the second value to test
79
	 *            the second value to test
80
	 * @param shift
81
	 *            the delta shift used for this test
58
	 * @return <code>true</code> in case the first value is greater than the
82
	 * @return <code>true</code> in case the first value is greater than the
59
	 *         second value by an amount recognizable by the given scale,
83
	 *         second value by an amount recognizable by the shifted delta,
60
	 *         <code>false</code> otherwise
84
	 *         <code>false</code> otherwise
61
	 */
85
	 */
62
	public static final boolean greater(double d1, double d2) {
86
	public static final boolean greater(double d1, double d2, int shift) {
63
		return round(d1) > round(d2);
87
		return d1 + calculateFraction(shift) > d2;
88
	}
89
90
	/**
91
	 * @see PrecisionUtils#greaterEqual(double, double, int)
92
	 * @param d1
93
	 * @param d2
94
	 * @return result of the comparison
95
	 */
96
	public static final boolean greaterEqual(double d1, double d2) {
97
		return greaterEqual(d1, d2, 0);
64
	}
98
	}
65
99
66
	/**
100
	/**
67
	 * Tests whether the first given value is regarded to be greater or equal
101
	 * Tests whether the first given value is regarded to be greater or equal
68
	 * than the second value w.r.t. the given scale.
102
	 * than the second value w.r.t. the given shift.
69
	 * 
103
	 * 
70
	 * @param d1
104
	 * @param d1
71
	 *            the first value to test
105
	 *            the first value to test
72
	 * @param d2
106
	 * @param d2
73
	 *            the second value to test
107
	 *            the second value to test
108
	 * @param shift
109
	 *            the delta shift used for this test
74
	 * @return <code>true</code> in case the first value is greater than the
110
	 * @return <code>true</code> in case the first value is greater than the
75
	 *         second value by an amount recognizable by the given scale or
111
	 *         second value by an amount recognizable by the given scale or
76
	 *         differs from it by an amount not recognizable by the given scale,
112
	 *         differs from it by an amount not recognizable by the shifted
77
	 *         <code>false</code> otherwise
113
	 *         delta, <code>false</code> otherwise
78
	 */
114
	 */
79
	public static final boolean greaterEqual(double d1, double d2) {
115
	public static final boolean greaterEqual(double d1, double d2, int shift) {
80
		return round(d1) >= round(d2);
116
		return d1 + calculateFraction(shift) >= d2;
81
	}
117
	}
82
118
83
	/**
119
	/**
84
	 * Rounds the given value w.r.t. to the given scale.
120
	 * @see PrecisionUtils#smaller(double, double, int)
85
	 * 
121
	 * @param d1
86
	 * @param d
122
	 * @param d2
87
	 *            the value to round
123
	 * @return result of the comparison
88
	 * @return a rounded value that represents the recognizable fraction of the
124
	 */
89
	 *         given value w.r.t. the given scale
125
	public static final boolean smaller(double d1, double d2) {
90
	 */
126
		return smaller(d1, d2, 0);
91
	public static double round(double d) {
92
		return BigDecimal
93
				.valueOf(d < 0 ? d - 0.05 * FRACTION : d + 0.05 * FRACTION)
94
				.setScale(SCALE, ROUNDING_MODE).doubleValue();
95
	}
127
	}
96
128
97
	/**
129
	/**
98
	 * Tests whether the first given value is regarded to be smaller than the
130
	 * Tests whether the first given value is regarded to be smaller than the
99
	 * second value w.r.t. the given scale.
131
	 * second value w.r.t. the given shift.
100
	 * 
132
	 * 
101
	 * @param d1
133
	 * @param d1
102
	 *            the first value to test
134
	 *            the first value to test
103
	 * @param d2
135
	 * @param d2
104
	 *            the second value to test
136
	 *            the second value to test
137
	 * @param shift
138
	 *            the delta shift used for this test
105
	 * @return <code>true</code> in case the first value is smaller than the
139
	 * @return <code>true</code> in case the first value is smaller than the
106
	 *         second value by an amount recognizable by the given scale,
140
	 *         second value by an amount recognizable by the shifted delta,
107
	 *         <code>false</code> otherwise
141
	 *         <code>false</code> otherwise
108
	 */
142
	 */
109
	public static final boolean smaller(double d1, double d2) {
143
	public static final boolean smaller(double d1, double d2, int shift) {
110
		return round(d1) < round(d2);
144
		return d1 < d2 + calculateFraction(shift);
145
	}
146
147
	/**
148
	 * @see PrecisionUtils#smallerEqual(double, double, int)
149
	 * @param d1
150
	 * @param d2
151
	 * @return result of the comparison
152
	 */
153
	public static final boolean smallerEqual(double d1, double d2) {
154
		return smallerEqual(d1, d2, 0);
111
	}
155
	}
112
156
113
	/**
157
	/**
114
	 * Tests whether the first given value is regarded to be smaller or equal
158
	 * Tests whether the first given value is regarded to be smaller or equal
115
	 * than the second value w.r.t. the given scale.
159
	 * than the second value w.r.t. the given shift.
116
	 * 
160
	 * 
117
	 * @param d1
161
	 * @param d1
118
	 *            the first value to test
162
	 *            the first value to test
119
	 * @param d2
163
	 * @param d2
120
	 *            the second value to test
164
	 *            the second value to test
165
	 * @param shift
166
	 *            the delta shift used for this test
121
	 * @return <code>true</code> in case the first value is smaller than the
167
	 * @return <code>true</code> in case the first value is smaller than the
122
	 *         second value by an amount recognizable by the given scale or
168
	 *         second value by an amount recognizable by the given scale or
123
	 *         differs from it by an amount not recognizable by the given scale,
169
	 *         differs from it by an amount not recognizable by the shifted
124
	 *         <code>false</code> otherwise
170
	 *         delta, <code>false</code> otherwise
125
	 */
171
	 */
126
	public static final boolean smallerEqual(double d1, double d2) {
172
	public static final boolean smallerEqual(double d1, double d2, int shift) {
127
		return round(d1) <= round(d2);
173
		return d1 <= d2 + calculateFraction(shift);
128
	}
174
	}
129
175
130
	private PrecisionUtils() {
176
	private PrecisionUtils() {
(-)src/org/eclipse/gef4/geometry/tests/AllTests.java (-5 / +7 lines)
Lines 6-12 Link Here
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     itemis AG - initial API and implementation
9
 *     Alexander Nyßen (itemis AG) - initial API and implementation
10
 *     
10
 *     
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
12
package org.eclipse.gef4.geometry.tests;
Lines 16-25 Link Here
16
import org.junit.runners.Suite.SuiteClasses;
16
import org.junit.runners.Suite.SuiteClasses;
17
17
18
@RunWith(Suite.class)
18
@RunWith(Suite.class)
19
@SuiteClasses({ PrecisionUtilsTest.class, PointTests.class,
19
@SuiteClasses({ CubicCurveTests.class, DimensionTests.class,
20
		DimensionTests.class, LineTests.class, RectangleTests.class,
20
		EllipseTests.class, LineTests.class, PointTests.class,
21
		VectorTests.class, StraightTests.class, PolylineTests.class,
21
		PolygonTests.class, PolylineTests.class,
22
		PolygonTests.class, EllipseTests.class })
22
		PolynomCalculationsTests.class, PrecisionUtilsTest.class,
23
		QuadraticCurveTests.class, RectangleTests.class, StraightTests.class,
24
		VectorTests.class })
23
public class AllTests {
25
public class AllTests {
24
26
25
}
27
}
(-)src/org/eclipse/gef4/geometry/tests/CubicCurveTests.java (+77 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *          
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
13
14
import junit.framework.TestCase;
15
16
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.shapes.CubicCurve;
18
19
public class CubicCurveTests extends TestCase {
20
21
	private final Point p = new Point(-10, -10), c1 = new Point(0, -10),
22
			c2 = new Point(10, 0), q = new Point(0, 10);
23
24
	public void test_get() {
25
		CubicCurve curve = new CubicCurve(p, c1, c2, q);
26
27
		assertEquals("curve.get(0) returns the curve's start point", p,
28
				curve.get(0));
29
		assertEquals("curve.get(1) returns the curve's end point", q,
30
				curve.get(1));
31
32
		boolean thrown = false;
33
		try {
34
			curve.get(-0.1);
35
		} catch (IllegalArgumentException x) {
36
			thrown = true;
37
		}
38
		assertTrue("curve.get(t < 0) throws an IllegalArgumentException",
39
				thrown);
40
41
		thrown = false;
42
		try {
43
			curve.get(1.1);
44
		} catch (IllegalArgumentException x) {
45
			thrown = true;
46
		}
47
		assertTrue("curve.get(t > 1) throws an IllegalArgumentException",
48
				thrown);
49
	}
50
51
	public void test_contains_Point() {
52
		CubicCurve curve = new CubicCurve(p, c1, c2, q);
53
54
		// check fix points:
55
		assertEquals(true, curve.contains(p));
56
		assertEquals(true, curve.contains(q));
57
		assertEquals(false, curve.contains(c1)); // not always true, but for our
58
													// c1 it is
59
		assertEquals(false, curve.contains(c2)); // not always true, but for our
60
													// c2 it is
61
62
		// check 0 <= t <= 1:
63
		for (double t = 0; t <= 1; t += 0.0123456789) {
64
			assertEquals("curve.get(t = " + t
65
					+ " in range [0, 1]) lies on the curve", true,
66
					curve.contains(curve.get(t)));
67
		}
68
	}
69
70
	public void test_get_Bounds() {
71
		CubicCurve curve = new CubicCurve(p, c1, c2, q);
72
73
		// p is the top-left point: (y-coordinates are inverted)
74
		assertEquals(curve.getBounds().getTopLeft(), p);
75
	}
76
77
}
(-)src/org/eclipse/gef4/geometry/tests/EllipseTests.java (-1 / +85 lines)
Lines 6-12 Link Here
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     itemis AG - initial API and implementation
9
 *     Alexander Nyßen (itemis AG) - initial API and implementation
10
 *     
10
 *     
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
12
package org.eclipse.gef4.geometry.tests;
Lines 76-79 Link Here
76
			assertTrue(e.intersects(l)); // line touches ellipse (tangent)
76
			assertTrue(e.intersects(l)); // line touches ellipse (tangent)
77
		}
77
		}
78
	}
78
	}
79
80
	public void test_get_intersections_with_Ellipse() {
81
		Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
82
		Ellipse e1 = new Ellipse(r);
83
		Ellipse e2 = new Ellipse(r);
84
85
		// ellipses are identical = returns no intersections, user can check
86
		// this via equals()
87
		Point[] intersections = e1.getIntersections(e2);
88
		assertEquals(0, intersections.length);
89
90
		// if we create an x-scaled ellipse at the same position as before, they
91
		// should have 3 poi (the touching point and two crossing intersections)
92
		Rectangle r2 = r.getExpanded(0, 0, 100, 0);
93
		e2 = new Ellipse(r2);
94
		intersections = e1.getIntersections(e2);
95
		assertEquals(3, intersections.length);
96
97
		// if we create a y-scaled ellipse at the same position as before, they
98
		// should have 3 poi (the touching point and two crossing intersections)
99
		r2 = r.getExpanded(0, 0, 0, 100);
100
		e2 = new Ellipse(r2);
101
		intersections = e1.getIntersections(e2);
102
		assertEquals(3, intersections.length);
103
104
		// if we create an x-scaled ellipse at the same y-position as before,
105
		// the
106
		// two should touch at two positions:
107
		r2 = r.getExpanded(50, 0, 50, 0);
108
		e2 = new Ellipse(r2);
109
		intersections = e1.getIntersections(e2);
110
		assertEquals(2, intersections.length);
111
112
		// the two poi are top and bottom border mid-points:
113
		int equalsTop = 0;
114
		int equalsBottom = 0;
115
116
		Rectangle bounds = e1.getBounds();
117
		for (Point poi : intersections) {
118
			// we need to losen the equality test, because the points of
119
			// intersection may be to unprecise
120
			Point top = bounds.getTop();
121
			if (top.equals(poi)) {
122
				equalsTop++;
123
			}
124
			if (bounds.getBottom().equals(poi)) {
125
				equalsBottom++;
126
			}
127
		}
128
129
		assertEquals(
130
				"The top border mid-point should be one of the two intersections.",
131
				1, equalsTop);
132
		assertEquals(
133
				"The bottom border mid-point should be one of the two intersections.",
134
				1, equalsBottom);
135
136
		// if we create a y-scaled ellipse at the same x-position as before, the
137
		// two should touch at two positions:
138
		r2 = r.getExpanded(0, 50, 0, 50);
139
		e2 = new Ellipse(r2);
140
		intersections = e1.getIntersections(e2);
141
		assertEquals(2, intersections.length);
142
143
		// the two poi are left and right border mid-points:
144
		int equalsLeft = 0;
145
		int equalsRight = 0;
146
147
		for (Point poi : intersections) {
148
			if (bounds.getLeft().equals(poi)) {
149
				equalsLeft++;
150
			}
151
			if (bounds.getRight().equals(poi)) {
152
				equalsRight++;
153
			}
154
		}
155
156
		assertEquals(
157
				"The left border mid-point should be one of the two intersections.",
158
				1, equalsLeft);
159
		assertEquals(
160
				"The right border mid-point should be one of the two intersections.",
161
				1, equalsRight);
162
	}
79
}
163
}
(-)src/org/eclipse/gef4/geometry/tests/PolynomCalculationsTests.java (+151 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *     
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
13
14
import java.util.Arrays;
15
16
import junit.framework.TestCase;
17
18
import org.eclipse.gef4.geometry.utils.PolynomCalculations;
19
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
20
21
public class PolynomCalculationsTests extends TestCase {
22
23
	public void test_get_roots_always_true() {
24
		try {
25
			PolynomCalculations.getLinearRoots(0, 0);
26
		} catch (ArithmeticException x) {
27
			assertTrue("0x + 0 = 0  throws an ArithmeticException", true);
28
		}
29
30
		try {
31
			PolynomCalculations.getQuadraticRoots(0, 0, 0);
32
		} catch (ArithmeticException x) {
33
			assertTrue("0x^2 + 0x + 0 = 0  throws an ArithmeticException", true);
34
		}
35
36
		try {
37
			PolynomCalculations.getCubicRoots(0, 0, 0, 0);
38
		} catch (ArithmeticException x) {
39
			assertTrue(
40
					"0x^3 + 0x^2 + 0x + 0 = 0  throws an ArithmeticException",
41
					true);
42
		}
43
	}
44
45
	public void test_get_linear_roots() {
46
		double[] solutions = PolynomCalculations.getLinearRoots(1, 0);
47
		assertEquals("one real solution", 1, solutions.length);
48
		assertTrue("x = 0", PrecisionUtils.equal(0, solutions[0]));
49
50
		solutions = PolynomCalculations.getLinearRoots(0, 1);
51
		assertEquals("1 != 0", 0, solutions.length);
52
53
		solutions = PolynomCalculations.getLinearRoots(1, -2);
54
		assertEquals("one real solution", 1, solutions.length);
55
		assertTrue("x - 2 = 0 <=> x = 2", PrecisionUtils.equal(2, solutions[0]));
56
57
		solutions = PolynomCalculations.getLinearRoots(7, -7);
58
		assertEquals("one real solution", 1, solutions.length);
59
		assertTrue("7x - 7 = 0 <=> x = 1",
60
				PrecisionUtils.equal(1, solutions[0]));
61
62
		solutions = PolynomCalculations.getLinearRoots(0.5, -10);
63
		assertEquals("one real solution", 1, solutions.length);
64
		assertTrue("0.5x - 10 = 0 <=> x = 20",
65
				PrecisionUtils.equal(20, solutions[0]));
66
67
		solutions = PolynomCalculations.getLinearRoots(5, -0.5);
68
		assertEquals("one real solution", 1, solutions.length);
69
		assertTrue("5x - 0.5 = 0 <=> x = 0.1",
70
				PrecisionUtils.equal(0.1, solutions[0]));
71
72
		solutions = PolynomCalculations.getLinearRoots(1, 1);
73
		assertEquals("one real solution", 1, solutions.length);
74
		assertTrue("x + 1 = 0 <=> x = -1",
75
				PrecisionUtils.equal(-1, solutions[0]));
76
	}
77
78
	public void test_get_quadratic_roots() {
79
		double[] solutions = PolynomCalculations.getQuadraticRoots(1, 1, 0);
80
		Arrays.sort(solutions);
81
		assertEquals("two real solution", 2, solutions.length);
82
		assertTrue("x^2 + x = 0 <=> x(x + 1) = 0 => x = 0 v x = -1",
83
				PrecisionUtils.equal(-1, solutions[0]));
84
		assertTrue("x^2 + x + 0 = 0 <=> x(x + 1) = 0 => x = 0 v x = -1",
85
				PrecisionUtils.equal(0, solutions[1]));
86
87
		solutions = PolynomCalculations.getQuadraticRoots(1, 0, 1);
88
		assertEquals("x^2 + 1 = 0 => no real solutions", 0, solutions.length);
89
90
		solutions = PolynomCalculations.getQuadraticRoots(1, 0, -1);
91
		Arrays.sort(solutions);
92
		assertEquals("two real solution", 2, solutions.length);
93
		assertTrue("x^2 - 1 = 0 => x = +-1",
94
				PrecisionUtils.equal(-1, solutions[0]));
95
		assertTrue("x^2 - 1 = 0 => x = +-1",
96
				PrecisionUtils.equal(1, solutions[1]));
97
98
		solutions = PolynomCalculations.getQuadraticRoots(1, 0, 0);
99
		assertEquals("one real solution", 1, solutions.length);
100
		assertTrue("x^2 = 0 <=> x = 0", PrecisionUtils.equal(0, solutions[0]));
101
102
		solutions = PolynomCalculations.getQuadraticRoots(0, 1, 0);
103
		assertEquals("one real solution", 1, solutions.length);
104
		assertTrue("x = 0", PrecisionUtils.equal(0, solutions[0]));
105
106
		solutions = PolynomCalculations.getQuadraticRoots(2, 0, -8);
107
		Arrays.sort(solutions);
108
		assertEquals("two real solution", 2, solutions.length);
109
		assertTrue("2x^2 - 8 = 0 <=> x^2 = 4 => x = +-2",
110
				PrecisionUtils.equal(-2, solutions[0]));
111
		assertTrue("2x^2 - 8 = 0 <=> x^2 = 4 => x = +-2",
112
				PrecisionUtils.equal(2, solutions[1]));
113
114
		solutions = PolynomCalculations.getQuadraticRoots(1, -3, 2);
115
		Arrays.sort(solutions);
116
		assertEquals("two real solution", 2, solutions.length);
117
		assertTrue("x^2 - 3x + 2 = 0 <=> (x - 2)(x - 1) = 0 => x = 2 v x = 1",
118
				PrecisionUtils.equal(1, solutions[0]));
119
		assertTrue("x^2 - 3x + 2 = 0 <=> (x - 2)(x - 1) = 0 => x = 2 v x = 1",
120
				PrecisionUtils.equal(2, solutions[1]));
121
	}
122
123
	public void test_get_cubic_roots() {
124
		double[] solutions = PolynomCalculations.getCubicRoots(1, 1, 1, 0);
125
		Arrays.sort(solutions);
126
		assertEquals("one real solution", 1, solutions.length);
127
		assertTrue("x^3 + x^2 + x = 0 <=> x(x^2 + x + 1) = 0 => x = 0",
128
				PrecisionUtils.equal(0, solutions[0]));
129
130
		solutions = PolynomCalculations.getCubicRoots(1, -6, 12, -8);
131
		assertEquals("one real solution", 1, solutions.length);
132
		assertTrue("x = 2 solves the polynom",
133
				PrecisionUtils.equal(2, solutions[0]));
134
135
		solutions = PolynomCalculations.getCubicRoots(1, 1, -33, 63);
136
		Arrays.sort(solutions);
137
		assertEquals("two real solutions", 2, solutions.length);
138
		assertTrue("x1 = -7", PrecisionUtils.equal(-7, solutions[0]));
139
		assertTrue("x2 = 3", PrecisionUtils.equal(3, solutions[1]));
140
141
		solutions = PolynomCalculations.getCubicRoots(1, 3, -6, -1);
142
		Arrays.sort(solutions);
143
		assertEquals("three real solutions", 3, solutions.length);
144
		assertTrue("x1 = -4.33181031",
145
				PrecisionUtils.equal(-4.331810310203, solutions[0]));
146
		assertTrue("x2 = -0.15524041",
147
				PrecisionUtils.equal(-0.15524041215, solutions[1]));
148
		assertTrue("x3 = 1.48705072",
149
				PrecisionUtils.equal(1.487050722353, solutions[2]));
150
	}
151
}
(-)src/org/eclipse/gef4/geometry/tests/PolynomTests.java (+20 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *     
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
13
14
import junit.framework.TestCase;
15
16
public class PolynomTests extends TestCase {
17
	public void test_getNearest() {
18
		assertTrue("nyi", false);
19
	}
20
}
(-)src/org/eclipse/gef4/geometry/tests/PrecisionUtilsTest.java (-26 / +77 lines)
Lines 6-12 Link Here
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     itemis AG - initial API and implementation
9
 *     Alexander Nyßen (itemis AG) - initial API and implementation
10
 *******************************************************************************/
10
 *******************************************************************************/
11
11
12
package org.eclipse.gef4.geometry.tests;
12
package org.eclipse.gef4.geometry.tests;
Lines 26-31 Link Here
26
	private static final double PRECISION_FRACTION = TestUtils
26
	private static final double PRECISION_FRACTION = TestUtils
27
			.getPrecisionFraction();
27
			.getPrecisionFraction();
28
28
29
	private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
30
			- PRECISION_FRACTION / 10;
31
32
	private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
33
			+ PRECISION_FRACTION / 10;
34
29
	/**
35
	/**
30
	 * Tests the precision tolerance of
36
	 * Tests the precision tolerance of
31
	 * {@link PrecisionUtils#equal(double, double)}, by checking whether two
37
	 * {@link PrecisionUtils#equal(double, double)}, by checking whether two
Lines 36-69 Link Here
36
	public void test_equal() {
42
	public void test_equal() {
37
		// test equality is recognized in case we increase/decrease beyond the
43
		// test equality is recognized in case we increase/decrease beyond the
38
		// given scale
44
		// given scale
39
		double d1 = -9.486614173228347;
45
		double d1 = -9.48661417322834712;
40
		double d2 = -34.431496062992125;
46
		double d2 = -34.431496062992123985;
41
		double d3 = 41.99055118110236;
47
		double d3 = 41.99055118110236626;
42
		double d4 = 25.92755905511811;
48
		double d4 = 25.927559055118116565;
43
		double d5 = Double.MIN_VALUE;
49
		double d5 = Double.MIN_VALUE;
44
		double d6 = 1 - d5;
50
		double d6 = 1 - d5;
45
51
46
		assertTrue(PrecisionUtils.equal(d1, d1 - PRECISION_FRACTION / 10));
52
		assertTrue(PrecisionUtils.equal(d1, d1 - UNRECOGNIZABLE_FRACTION));
47
		assertTrue(PrecisionUtils.equal(d2, d2 - PRECISION_FRACTION / 10));
53
		assertTrue(PrecisionUtils.equal(d2, d2 - UNRECOGNIZABLE_FRACTION));
48
		assertTrue(PrecisionUtils.equal(d3, d3 - PRECISION_FRACTION / 10));
54
		assertTrue(PrecisionUtils.equal(d3, d3 - UNRECOGNIZABLE_FRACTION));
49
		assertTrue(PrecisionUtils.equal(d4, d4 - PRECISION_FRACTION / 10));
55
		assertTrue(PrecisionUtils.equal(d4, d4 - UNRECOGNIZABLE_FRACTION));
50
56
51
		assertTrue(PrecisionUtils.equal(d1, d1 + PRECISION_FRACTION / 10));
57
		assertTrue(PrecisionUtils.equal(d1, d1 + UNRECOGNIZABLE_FRACTION));
52
		assertTrue(PrecisionUtils.equal(d2, d2 + PRECISION_FRACTION / 10));
58
		assertTrue(PrecisionUtils.equal(d2, d2 + UNRECOGNIZABLE_FRACTION));
53
		assertTrue(PrecisionUtils.equal(d3, d3 + PRECISION_FRACTION / 10));
59
		assertTrue(PrecisionUtils.equal(d3, d3 + UNRECOGNIZABLE_FRACTION));
54
		assertTrue(PrecisionUtils.equal(d4, d4 + PRECISION_FRACTION / 10));
60
		assertTrue(PrecisionUtils.equal(d4, d4 + UNRECOGNIZABLE_FRACTION));
55
61
56
		assertFalse(PrecisionUtils.equal(d1, d1 - PRECISION_FRACTION));
62
		assertFalse(PrecisionUtils.equal(d1, d1 - RECOGNIZABLE_FRACTION));
57
		assertFalse(PrecisionUtils.equal(d2, d2 - PRECISION_FRACTION));
63
		assertFalse(PrecisionUtils.equal(d2, d2 - RECOGNIZABLE_FRACTION));
58
		assertFalse(PrecisionUtils.equal(d3, d3 - PRECISION_FRACTION));
64
		assertFalse(PrecisionUtils.equal(d3, d3 - RECOGNIZABLE_FRACTION));
59
		assertFalse(PrecisionUtils.equal(d4, d4 - PRECISION_FRACTION));
65
		assertFalse(PrecisionUtils.equal(d4, d4 - RECOGNIZABLE_FRACTION));
60
66
61
		assertFalse(PrecisionUtils.equal(d1, d1 + PRECISION_FRACTION));
67
		assertFalse(PrecisionUtils.equal(d1, d1 + RECOGNIZABLE_FRACTION));
62
		assertFalse(PrecisionUtils.equal(d2, d2 + PRECISION_FRACTION));
68
		assertFalse(PrecisionUtils.equal(d2, d2 + RECOGNIZABLE_FRACTION));
63
		assertFalse(PrecisionUtils.equal(d3, d3 + PRECISION_FRACTION));
69
		assertFalse(PrecisionUtils.equal(d3, d3 + RECOGNIZABLE_FRACTION));
64
		assertFalse(PrecisionUtils.equal(d4, d4 + PRECISION_FRACTION));
70
		assertFalse(PrecisionUtils.equal(d4, d4 + RECOGNIZABLE_FRACTION));
71
	}
72
73
	public void test_greater() {
74
		double unrec = UNRECOGNIZABLE_FRACTION;
75
76
		assertTrue(PrecisionUtils.greater(1, 0));
77
		assertTrue(PrecisionUtils.greater(RECOGNIZABLE_FRACTION, 0));
78
		assertTrue(PrecisionUtils.greater(unrec, 0));
79
		assertTrue(PrecisionUtils.greater(0, 0));
80
		assertTrue(PrecisionUtils.greater(-unrec, 0));
81
		assertTrue(PrecisionUtils.greater(unrec - PRECISION_FRACTION, 0));
82
		assertFalse(PrecisionUtils.greater(-1, 0));
83
		assertFalse(PrecisionUtils.greater(-PRECISION_FRACTION, 0));
84
	}
85
86
	public void test_smaller() {
87
		double unrec = UNRECOGNIZABLE_FRACTION;
88
89
		assertTrue(PrecisionUtils.smaller(-1, 0));
90
		assertTrue(PrecisionUtils.smaller(-PRECISION_FRACTION, 0));
91
		assertTrue(PrecisionUtils.smaller(-unrec, 0));
92
		assertTrue(PrecisionUtils.smaller(0, 0));
93
		assertTrue(PrecisionUtils.smaller(unrec, 0));
94
		assertTrue(PrecisionUtils.smaller(PRECISION_FRACTION - unrec, 0));
95
		assertFalse(PrecisionUtils.smaller(1, 0));
96
		assertFalse(PrecisionUtils.smaller(PRECISION_FRACTION, 0));
97
	}
98
99
	public void test_greaterEqual() {
100
		double unrec = UNRECOGNIZABLE_FRACTION;
101
102
		assertTrue(PrecisionUtils.greaterEqual(1, 0));
103
		assertTrue(PrecisionUtils.greaterEqual(0, 0));
104
		assertTrue(PrecisionUtils.greaterEqual(-unrec, 0));
105
		assertTrue(PrecisionUtils.greaterEqual(-PRECISION_FRACTION, 0));
106
		assertFalse(PrecisionUtils.greaterEqual(-1, 0));
107
		assertFalse(PrecisionUtils.greaterEqual(-PRECISION_FRACTION - unrec, 0));
108
	}
109
110
	public void test_smallerEqual() {
111
		double unrec = UNRECOGNIZABLE_FRACTION;
65
112
66
		assertEquals(0, PrecisionUtils.round(d5), 0);
113
		assertTrue(PrecisionUtils.smallerEqual(-1, 0));
67
		assertEquals(1, PrecisionUtils.round(d6), 0);
114
		assertTrue(PrecisionUtils.smallerEqual(0, 0));
115
		assertTrue(PrecisionUtils.smallerEqual(unrec, 0));
116
		assertTrue(PrecisionUtils.smallerEqual(PRECISION_FRACTION, 0));
117
		assertFalse(PrecisionUtils.smallerEqual(1, 0));
118
		assertFalse(PrecisionUtils.smallerEqual(PRECISION_FRACTION + unrec, 0));
68
	}
119
	}
69
}
120
}
(-)src/org/eclipse/gef4/geometry/tests/QuadraticCurveTests.java (+225 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 itemis AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Matthias Wienand (itemis AG) - initial API and implementation
10
 *     
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
13
14
import junit.framework.TestCase;
15
16
import org.eclipse.gef4.geometry.Point;
17
import org.eclipse.gef4.geometry.shapes.QuadraticCurve;
18
19
public class QuadraticCurveTests extends TestCase {
20
	private final Point p = new Point(-10, -10), c = new Point(10, 0),
21
			q = new Point(0, 10);
22
23
	public void test_get() {
24
		QuadraticCurve curve = new QuadraticCurve(p, c, q);
25
26
		assertEquals("curve.get(0) returns the curve's start point", p,
27
				curve.get(0));
28
		assertEquals("curve.get(1) returns the curve's end point", q,
29
				curve.get(1));
30
31
		boolean thrown = false;
32
		try {
33
			curve.get(-0.1);
34
		} catch (IllegalArgumentException x) {
35
			thrown = true;
36
		}
37
		assertTrue("curve.get(t < 0) throws an IllegalArgumentException",
38
				thrown);
39
40
		thrown = false;
41
		try {
42
			curve.get(1.1);
43
		} catch (IllegalArgumentException x) {
44
			thrown = true;
45
		}
46
		assertTrue("curve.get(t > 1) throws an IllegalArgumentException",
47
				thrown);
48
	}
49
50
	public void test_contains_Point() {
51
		QuadraticCurve curve = new QuadraticCurve(p, c, q);
52
53
		// check fix points:
54
		assertEquals(curve.contains(p), true);
55
		assertEquals(curve.contains(q), true);
56
		assertEquals(curve.contains(c), false); // not always true, but for our
57
												// c it is
58
59
		// check 0 <= t <= 1:
60
		for (double t = 0; t <= 1; t += 0.0123456789) {
61
			assertEquals("curve.get(t = " + t
62
					+ " in range [0, 1]) lies on the curve", true,
63
					curve.contains(curve.get(t)));
64
		}
65
	}
66
67
	public void test_get_Bounds() {
68
		QuadraticCurve curve = new QuadraticCurve(p, c, q);
69
70
		// p is the top-left point: (y-coordinates are inverted)
71
		assertEquals(curve.getBounds().getTopLeft(), p);
72
	}
73
74
	// public void test_get_FatLine() {
75
	// QuadraticCurve curve = new QuadraticCurve(p, c, p);
76
	// assertEquals(null, curve.getFatLine());
77
	// }
78
79
	// public void test_clip_FatLine() {
80
	// QuadraticCurve curve = new QuadraticCurve(p, c, q);
81
	//
82
	// // FatLine L = new FatLine(new Straight(new Vector(0, -5),
83
	// // new Vector(1, 0)), -10, 0);
84
	// // QuadraticCurve clipped = curve.clip(L);
85
	// //
86
	// // assertTrue("clipped curve's endpoints lie on the FatLine",
87
	// // L.contains(clipped.getP1()));
88
	// // assertTrue("clipped curve's endpoints lie on the FatLine",
89
	// // L.contains(clipped.getP2()));
90
	// //
91
	// // L = new FatLine(new Straight(new Vector(100, 100), new Vector(100,
92
	// 0)),
93
	// // 0, 1);
94
	// // clipped = curve.clip(L);
95
	// // assertEquals(null, clipped);
96
	// //
97
	// // L = new FatLine(
98
	// // new Straight(new Vector(-100, -100), new Vector(100, 0)), -200,
99
	// // 0);
100
	// // clipped = curve.clip(L);
101
	// // assertEquals(curve, clipped);
102
	// }
103
104
	public void test_intersects_Line() {
105
		// TODO!
106
	}
107
108
	public void test_intersects_Rectangle() {
109
		// TODO!
110
	}
111
112
	public void test_getIntersections_QuadraticCurve() {
113
		// some general cases
114
		Point p1 = new Point(164.0, 43.0);
115
		Point p2 = new Point(169.0, 165.0);
116
		Point p3 = new Point(307.0, 239.0);
117
		Point q1 = new Point(100.0, 100.0);
118
		Point q2 = new Point(200.0, 200.0);
119
		Point q3 = new Point(300.0, 100.0);
120
121
		QuadraticCurve p = new QuadraticCurve(p1, p2, p3);
122
		QuadraticCurve q = new QuadraticCurve(q1, q2, q3);
123
124
		Point[] intersections = q.getIntersections(p);
125
		assertEquals("p and q have exactly one intersection", 1,
126
				intersections.length);
127
128
		for (Point poi : intersections) {
129
			assertEquals("each point of intersection lies on p", true,
130
					p.contains(poi));
131
			assertEquals("each point of intersection lies on q", true,
132
					q.contains(poi));
133
		}
134
135
		p1 = new Point(200.0, 100.0);
136
		p2 = new Point(304.0, 203.0);
137
		p3 = new Point(300.0, 300.0);
138
139
		p = new QuadraticCurve(p1, p2, p3);
140
141
		intersections = q.getIntersections(p);
142
		assertEquals("p and q have exactly one intersection", 1,
143
				intersections.length);
144
145
		for (Point poi : intersections) {
146
			assertEquals("each point of intersection lies on p", true,
147
					p.contains(poi));
148
			assertEquals("each point of intersection lies on q", true,
149
					q.contains(poi));
150
		}
151
152
		p1 = new Point(144.0, 59.0);
153
		p2 = new Point(358.0, 130.0);
154
		p3 = new Point(300.0, 300.0);
155
156
		p = new QuadraticCurve(p1, p2, p3);
157
158
		intersections = q.getIntersections(p);
159
		assertEquals("p and q have exactly one intersection", 1,
160
				intersections.length);
161
162
		for (Point poi : intersections) {
163
			assertEquals("each point of intersection lies on p", true,
164
					p.contains(poi));
165
			assertEquals("each point of intersection lies on q", true,
166
					q.contains(poi));
167
		}
168
169
		p1 = new Point(151.0, 272.0);
170
		p2 = new Point(101.0, 187.0);
171
		p3 = new Point(205.0, 48.0);
172
173
		p = new QuadraticCurve(p1, p2, p3);
174
175
		intersections = q.getIntersections(p);
176
		assertEquals("p and q have exactly one intersection", 1,
177
				intersections.length);
178
179
		for (Point poi : intersections) {
180
			assertEquals("each point of intersection lies on p", true,
181
					p.contains(poi));
182
			assertEquals("each point of intersection lies on q", true,
183
					q.contains(poi));
184
		}
185
186
		p1 = new Point(184.0, 83.0);
187
		p2 = new Point(400.0, 200.0);
188
		p3 = new Point(300.0, 300.0);
189
190
		p = new QuadraticCurve(p1, p2, p3);
191
192
		intersections = p.getIntersections(q);
193
		assertEquals("p and q have exactly one intersection", 1,
194
				intersections.length);
195
196
		for (Point poi : intersections) {
197
			assertEquals("each point of intersection lies on p", true,
198
					p.contains(poi));
199
			assertEquals("each point of intersection lies on q", true,
200
					q.contains(poi));
201
		}
202
203
		p1 = new Point(196.0, 89.0);
204
		p2 = new Point(335.0, 215.0);
205
		p3 = new Point(300.0, 300.0);
206
207
		p = new QuadraticCurve(p1, p2, p3);
208
209
		intersections = q.getIntersections(p);
210
		assertEquals("p and q have exactly one intersection", 1,
211
				intersections.length);
212
213
		for (Point poi : intersections) {
214
			assertEquals("each point of intersection lies on p", true,
215
					p.contains(poi));
216
			assertEquals("each point of intersection lies on q", true,
217
					q.contains(poi));
218
		}
219
220
		// special tangential cases
221
		// TODO
222
223
		// special
224
	}
225
}
(-)src/org/eclipse/gef4/geometry/tests/RectangleTests.java (-54 / +61 lines)
Lines 31-36 Link Here
31
	private static final double PRECISION_FRACTION = TestUtils
31
	private static final double PRECISION_FRACTION = TestUtils
32
			.getPrecisionFraction();
32
			.getPrecisionFraction();
33
33
34
	private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
35
			- PRECISION_FRACTION / 10;
36
37
	private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
38
			+ PRECISION_FRACTION / 10;
39
34
	public void testBorderPointsCalculation() {
40
	public void testBorderPointsCalculation() {
35
		Rectangle rect = new Rectangle(1, 2, 3, 4);
41
		Rectangle rect = new Rectangle(1, 2, 3, 4);
36
		assertEquals(rect.getTopLeft(), new Point(1, 2));
42
		assertEquals(rect.getTopLeft(), new Point(1, 2));
Lines 87-135 Link Here
87
		assertTrue(preciseRect.contains(topLeft));
93
		assertTrue(preciseRect.contains(topLeft));
88
		assertTrue(preciseRect.contains(topLeft.x, topLeft.y));
94
		assertTrue(preciseRect.contains(topLeft.x, topLeft.y));
89
		assertFalse(preciseRect.contains(topLeft.getTranslated(
95
		assertFalse(preciseRect.contains(topLeft.getTranslated(
90
				-PRECISION_FRACTION, -PRECISION_FRACTION)));
96
				-RECOGNIZABLE_FRACTION, -RECOGNIZABLE_FRACTION)));
91
97
92
		Point top = preciseRect.getTop();
98
		Point top = preciseRect.getTop();
93
		assertTrue(preciseRect.contains(top));
99
		assertTrue(preciseRect.contains(top));
94
		assertTrue(preciseRect.contains(top.x, top.y));
100
		assertTrue(preciseRect.contains(top.x, top.y));
95
		assertFalse(preciseRect.contains(top.getTranslated(0,
101
		assertFalse(preciseRect.contains(top.getTranslated(0,
96
				-PRECISION_FRACTION)));
102
				-RECOGNIZABLE_FRACTION)));
97
103
98
		Point topRight = preciseRect.getTopRight();
104
		Point topRight = preciseRect.getTopRight();
99
		assertTrue(preciseRect.contains(topRight));
105
		assertTrue(preciseRect.contains(topRight));
100
		assertTrue(preciseRect.contains(topRight.x, topRight.y));
106
		assertTrue(preciseRect.contains(topRight.x, topRight.y));
101
		assertFalse(preciseRect.contains(topRight.getTranslated(
107
		assertFalse(preciseRect.contains(topRight.getTranslated(
102
				PRECISION_FRACTION, -PRECISION_FRACTION)));
108
				RECOGNIZABLE_FRACTION, -RECOGNIZABLE_FRACTION)));
103
109
104
		Point left = preciseRect.getLeft();
110
		Point left = preciseRect.getLeft();
105
		assertTrue(preciseRect.contains(left));
111
		assertTrue(preciseRect.contains(left));
106
		assertTrue(preciseRect.contains(left.x, left.y));
112
		assertTrue(preciseRect.contains(left.x, left.y));
107
		assertFalse(preciseRect.contains(left.getTranslated(
113
		assertFalse(preciseRect.contains(left.getTranslated(
108
				-PRECISION_FRACTION, 0)));
114
				-RECOGNIZABLE_FRACTION, 0)));
109
115
110
		Point right = preciseRect.getRight();
116
		Point right = preciseRect.getRight();
111
		assertTrue(preciseRect.contains(right));
117
		assertTrue(preciseRect.contains(right));
112
		assertTrue(preciseRect.contains(right.x, right.y));
118
		assertTrue(preciseRect.contains(right.x, right.y));
113
		assertFalse(preciseRect.contains(right.getTranslated(
119
		assertFalse(preciseRect.contains(right.getTranslated(
114
				PRECISION_FRACTION, 0)));
120
				RECOGNIZABLE_FRACTION, 0)));
115
121
116
		Point bottomLeft = preciseRect.getBottomLeft();
122
		Point bottomLeft = preciseRect.getBottomLeft();
117
		assertTrue(preciseRect.contains(bottomLeft));
123
		assertTrue(preciseRect.contains(bottomLeft));
118
		assertTrue(preciseRect.contains(bottomLeft.x, bottomLeft.y));
124
		assertTrue(preciseRect.contains(bottomLeft.x, bottomLeft.y));
119
		assertFalse(preciseRect.contains(bottomLeft.getTranslated(
125
		assertFalse(preciseRect.contains(bottomLeft.getTranslated(
120
				-PRECISION_FRACTION, PRECISION_FRACTION)));
126
				-RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
121
127
122
		Point bottom = preciseRect.getBottom();
128
		Point bottom = preciseRect.getBottom();
123
		assertTrue(preciseRect.contains(bottom));
129
		assertTrue(preciseRect.contains(bottom));
124
		assertTrue(preciseRect.contains(bottom.x, bottom.y));
130
		assertTrue(preciseRect.contains(bottom.x, bottom.y));
125
		assertFalse(preciseRect.contains(bottom.getTranslated(0,
131
		assertFalse(preciseRect.contains(bottom.getTranslated(0,
126
				PRECISION_FRACTION)));
132
				RECOGNIZABLE_FRACTION)));
127
133
128
		Point bottomRight = preciseRect.getBottomRight();
134
		Point bottomRight = preciseRect.getBottomRight();
129
		assertTrue(preciseRect.contains(bottomRight));
135
		assertTrue(preciseRect.contains(bottomRight));
130
		assertTrue(preciseRect.contains(bottomRight.x, bottomRight.y));
136
		assertTrue(preciseRect.contains(bottomRight.x, bottomRight.y));
131
		assertFalse(preciseRect.contains(bottomRight.getTranslated(
137
		assertFalse(preciseRect.contains(bottomRight.getTranslated(
132
				PRECISION_FRACTION, PRECISION_FRACTION)));
138
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
133
	}
139
	}
134
140
135
	public void test_contains_Rectangle() {
141
	public void test_contains_Rectangle() {
Lines 141-174 Link Here
141
		assertTrue(preciseRect.contains(preciseRect.getX(), preciseRect.getY(),
147
		assertTrue(preciseRect.contains(preciseRect.getX(), preciseRect.getY(),
142
				preciseRect.getWidth(), preciseRect.getHeight()));
148
				preciseRect.getWidth(), preciseRect.getHeight()));
143
		assertFalse(preciseRect.contains(preciseRect.getExpanded(
149
		assertFalse(preciseRect.contains(preciseRect.getExpanded(
144
				PRECISION_FRACTION, PRECISION_FRACTION)));
150
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION)));
145
151
146
		// test precision tolerance, therefore increment by an amount not
152
		// test precision tolerance, therefore increment by an amount not
147
		// 'recognizable'
153
		// 'recognizable'
148
		Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION / 10,
154
149
				PRECISION_FRACTION / 10, 0, 0);
155
		Rectangle unrecognizableExpanded = preciseRect.getExpanded(
150
		Rectangle shrinked = preciseRect.getShrinked(0, 0,
156
				UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION, 0, 0);
151
				PRECISION_FRACTION / 10, PRECISION_FRACTION / 10);
157
		Rectangle unrecognizableShrinked = preciseRect.getShrinked(0, 0,
158
				UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION);
159
152
		// contains should not recognized the changes
160
		// contains should not recognized the changes
153
		assertTrue(preciseRect.contains(expanded));
161
		assertTrue(preciseRect.contains(unrecognizableExpanded));
154
		assertTrue(preciseRect.contains(shrinked));
162
		assertTrue(preciseRect.contains(unrecognizableShrinked));
155
		assertTrue(expanded.contains(preciseRect));
163
		assertTrue(unrecognizableExpanded.contains(preciseRect));
156
		assertTrue(shrinked.contains(preciseRect));
164
		assertTrue(unrecognizableShrinked.contains(preciseRect));
157
		assertTrue(expanded.contains(shrinked));
165
		assertTrue(unrecognizableExpanded.contains(unrecognizableShrinked));
158
		assertTrue(shrinked.contains(expanded));
159
166
160
		// now increment by an amount 'recognizable'
167
		// now increment by an amount 'recognizable'
161
		expanded = preciseRect.getExpanded(PRECISION_FRACTION,
168
		Rectangle recognizableExpanded = preciseRect.getExpanded(
162
				PRECISION_FRACTION, 0, 0);
169
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION, 0, 0);
163
		shrinked = preciseRect.getShrinked(0, 0, PRECISION_FRACTION,
170
		Rectangle recognizableShrinked = preciseRect.getShrinked(0, 0,
164
				PRECISION_FRACTION);
171
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
172
165
		// contains should now recognized the changes
173
		// contains should now recognized the changes
166
		assertFalse(preciseRect.contains(expanded));
174
		assertFalse(preciseRect.contains(recognizableExpanded));
167
		assertTrue(preciseRect.contains(shrinked));
175
		assertTrue(recognizableExpanded.contains(preciseRect));
168
		assertTrue(expanded.contains(preciseRect));
176
		assertFalse(recognizableShrinked.contains(preciseRect));
169
		assertFalse(shrinked.contains(preciseRect));
177
		assertFalse(recognizableShrinked.contains(recognizableExpanded));
170
		assertTrue(expanded.contains(shrinked));
171
		assertFalse(shrinked.contains(expanded));
172
	}
178
	}
173
179
174
	public void test_equals() {
180
	public void test_equals() {
Lines 183-206 Link Here
183
189
184
		// test precision tolerance, therefore increment by an amount not
190
		// test precision tolerance, therefore increment by an amount not
185
		// 'recognizable'
191
		// 'recognizable'
186
		Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION / 10,
192
		Rectangle unrecognizableExpanded = preciseRect.getExpanded(
187
				PRECISION_FRACTION / 10, 0, 0);
193
				UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION, 0, 0);
188
		Rectangle shrinked = preciseRect.getShrinked(0, 0,
194
		Rectangle unrecognizableShrinked = preciseRect.getShrinked(0, 0,
189
				PRECISION_FRACTION / 10, PRECISION_FRACTION / 10);
195
				UNRECOGNIZABLE_FRACTION, UNRECOGNIZABLE_FRACTION);
190
		// equals should not recognize the changes
196
		// equals should not recognize the changes
191
		assertTrue(preciseRect.equals(expanded));
197
		assertTrue(preciseRect.equals(unrecognizableExpanded));
192
		assertTrue(preciseRect.equals(shrinked));
198
		assertTrue(preciseRect.equals(unrecognizableShrinked));
193
		assertTrue(expanded.equals(shrinked));
194
199
195
		// increment by an amount 'recognizable'
200
		// increment by an amount 'recognizable'
196
		expanded = preciseRect.getExpanded(PRECISION_FRACTION,
201
		Rectangle recognizableExpanded = preciseRect.getExpanded(
197
				PRECISION_FRACTION, 0, 0);
202
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION, 0, 0);
198
		shrinked = preciseRect.getShrinked(0, 0, PRECISION_FRACTION,
203
		Rectangle recognizableShrinked = preciseRect.getShrinked(0, 0,
199
				PRECISION_FRACTION);
204
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
200
		// equals should now recognize the changes
205
		// equals should now recognize the changes
201
		assertFalse(preciseRect.equals(expanded));
206
		assertFalse(preciseRect.equals(recognizableExpanded));
202
		assertFalse(preciseRect.equals(shrinked));
207
		assertFalse(preciseRect.equals(recognizableShrinked));
203
		assertFalse(expanded.equals(shrinked));
208
		assertFalse(recognizableExpanded.equals(recognizableShrinked));
204
	}
209
	}
205
210
206
	public void test_scale() {
211
	public void test_scale() {
Lines 238-254 Link Here
238
	public void test_shrink_AND_expand() {
243
	public void test_shrink_AND_expand() {
239
		Rectangle preciseRect = new Rectangle(-9.486614173228347,
244
		Rectangle preciseRect = new Rectangle(-9.486614173228347,
240
				-34.431496062992125, 41.99055118110236, 25.92755905511811);
245
				-34.431496062992125, 41.99055118110236, 25.92755905511811);
241
		Rectangle expanded = preciseRect.getExpanded(PRECISION_FRACTION,
246
		Rectangle recognizableExpanded = preciseRect.getExpanded(
242
				PRECISION_FRACTION);
247
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
243
		Rectangle shrinked = preciseRect.getShrinked(PRECISION_FRACTION,
248
		Rectangle recognizableShrinked = preciseRect.getShrinked(
244
				PRECISION_FRACTION);
249
				RECOGNIZABLE_FRACTION, RECOGNIZABLE_FRACTION);
245
		assertFalse(preciseRect.equals(expanded));
250
		assertFalse(preciseRect.equals(recognizableExpanded));
246
		assertFalse(preciseRect.equals(shrinked));
251
		assertFalse(preciseRect.equals(recognizableShrinked));
247
		assertFalse(expanded.equals(shrinked));
252
		assertFalse(recognizableExpanded.equals(recognizableShrinked));
248
		expanded.shrink(PRECISION_FRACTION, PRECISION_FRACTION);
253
		recognizableExpanded.shrink(RECOGNIZABLE_FRACTION,
249
		shrinked.expand(PRECISION_FRACTION, PRECISION_FRACTION);
254
				RECOGNIZABLE_FRACTION);
250
		assertEquals(preciseRect, expanded);
255
		recognizableShrinked.expand(RECOGNIZABLE_FRACTION,
251
		assertEquals(preciseRect, shrinked);
256
				RECOGNIZABLE_FRACTION);
257
		assertEquals(preciseRect, recognizableExpanded);
258
		assertEquals(preciseRect, recognizableShrinked);
252
	}
259
	}
253
260
254
	public void test_toSWTRectangle() {
261
	public void test_toSWTRectangle() {
(-)src/org/eclipse/gef4/geometry/tests/StraightTests.java (-5 / +8 lines)
Lines 1-19 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
2
 * Copyright (c) 2010 Research Group Software Construction,
3
 *                    RWTH Aachen University and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 *
8
 * Contributors:
9
 * Contributors:
9
 *     Research Group Software Construction,
10
 *     Alexander Nyßen (Research Group Software Construction,
10
 *     RWTH Aachen University, Germany - Contribution for Bugzilla 245182
11
 *     RWTH Aachen University) - initial API and implementation
11
 *     
12
 *     
12
 *******************************************************************************/
13
 *******************************************************************************/
13
package org.eclipse.gef4.geometry.tests;
14
package org.eclipse.gef4.geometry.tests;
14
15
15
import junit.framework.TestCase;
16
import junit.framework.TestCase;
16
17
18
import org.eclipse.gef4.geometry.Angle;
17
import org.eclipse.gef4.geometry.Point;
19
import org.eclipse.gef4.geometry.Point;
18
import org.eclipse.gef4.geometry.euclidean.Straight;
20
import org.eclipse.gef4.geometry.euclidean.Straight;
19
import org.eclipse.gef4.geometry.euclidean.Vector;
21
import org.eclipse.gef4.geometry.euclidean.Vector;
Lines 93-103 Link Here
93
	public void test_getAngle_withStraight() {
95
	public void test_getAngle_withStraight() {
94
		Straight s1 = new Straight(new Vector(0, 0), new Vector(3, 3));
96
		Straight s1 = new Straight(new Vector(0, 0), new Vector(3, 3));
95
		Straight s2 = new Straight(new Vector(0, 4), new Vector(2, 2));
97
		Straight s2 = new Straight(new Vector(0, 4), new Vector(2, 2));
96
		assertTrue(s1.getAngle(s2) == 0.0);
98
		assertTrue(s1.getAngle(s2).equals(Angle.fromDeg(0)));
97
99
98
		s1 = new Straight(new Vector(0, 0), new Vector(5, 5));
100
		s1 = new Straight(new Vector(0, 0), new Vector(5, 5));
99
		s2 = new Straight(new Vector(0, 5), new Vector(0, 5));
101
		s2 = new Straight(new Vector(0, 5), new Vector(0, 5));
100
		assertTrue((float) s1.getAngle(s2) == 45.0); // rounding effects
102
		assertTrue(s1.getAngle(s2).equals(Angle.fromDeg(45))); // rounding
103
																// effects
101
	}
104
	}
102
105
103
	public void test_equals() {
106
	public void test_equals() {
(-)src/org/eclipse/gef4/geometry/tests/TestUtils.java (-9 / +6 lines)
Lines 11-17 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.gef4.geometry.tests;
12
package org.eclipse.gef4.geometry.tests;
13
13
14
import java.lang.reflect.Field;
14
import java.lang.reflect.Method;
15
15
16
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
16
import org.eclipse.gef4.geometry.utils.PrecisionUtils;
17
17
Lines 27-42 Link Here
27
		// this class should not be instantiated by clients
27
		// this class should not be instantiated by clients
28
	}
28
	}
29
29
30
	protected static double getPrecisionFraction() {
30
	public static double getPrecisionFraction() {
31
		return getPrecisionUtilsConstant("FRACTION");
31
		Method f;
32
	}
33
34
	private static double getPrecisionUtilsConstant(String name) {
35
		Field f;
36
		try {
32
		try {
37
			f = PrecisionUtils.class.getDeclaredField(name);
33
			f = PrecisionUtils.class.getDeclaredMethod("calculateFraction",
34
					int.class);
38
			f.setAccessible(true);
35
			f.setAccessible(true);
39
			return f.getDouble(PrecisionUtils.class);
36
			return ((Double) f.invoke(PrecisionUtils.class, 0)).doubleValue();
40
		} catch (Exception e) {
37
		} catch (Exception e) {
41
			throw new IllegalArgumentException(e);
38
			throw new IllegalArgumentException(e);
42
		}
39
		}
(-)src/org/eclipse/gef4/geometry/tests/VectorTests.java (-4 / +9 lines)
Lines 28-43 Link Here
28
	private static final double PRECISION_FRACTION = TestUtils
28
	private static final double PRECISION_FRACTION = TestUtils
29
			.getPrecisionFraction();
29
			.getPrecisionFraction();
30
30
31
	private static final double UNRECOGNIZABLE_FRACTION = PRECISION_FRACTION
32
			- PRECISION_FRACTION / 10;
33
	private static final double RECOGNIZABLE_FRACTION = PRECISION_FRACTION
34
			+ PRECISION_FRACTION / 10;
35
31
	public void test_Equals() {
36
	public void test_Equals() {
32
		Vector a = new Vector(3, 2);
37
		Vector a = new Vector(3, 2);
33
		Vector b = new Vector(2, -2);
38
		Vector b = new Vector(2, -2);
34
		assertTrue(a.equals(a));
39
		assertTrue(a.equals(a));
35
		assertFalse(a.equals(b));
40
		assertFalse(a.equals(b));
36
		assertFalse(a.equals(new Point(3, 2)));
41
		assertFalse(a.equals(new Point(3, 2)));
37
		assertTrue(a.equals(a.getAdded(new Vector(PRECISION_FRACTION / 10,
42
		assertTrue(a.equals(a.getAdded(new Vector(UNRECOGNIZABLE_FRACTION / 10,
38
				PRECISION_FRACTION / 10))));
43
				UNRECOGNIZABLE_FRACTION / 10))));
39
		assertFalse(a.equals(a.getAdded(new Vector(PRECISION_FRACTION,
44
		assertFalse(a.equals(a.getAdded(new Vector(RECOGNIZABLE_FRACTION,
40
				PRECISION_FRACTION))));
45
				RECOGNIZABLE_FRACTION))));
41
	}
46
	}
42
47
43
	public void test_getLength() {
48
	public void test_getLength() {

Return to bug 355997