/*******************************************************************************
* Copyright (c) 2011, 2015 itemis AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
* Matthias Wienand (itemis AG) - contribution for Bugzilla #355997
*
*******************************************************************************/
package org.eclipse.gef.geometry.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.eclipse.gef.geometry.planar.CubicCurve;
import org.eclipse.gef.geometry.planar.Ellipse;
import org.eclipse.gef.geometry.planar.IGeometry;
import org.eclipse.gef.geometry.planar.Line;
import org.eclipse.gef.geometry.planar.Path;
import org.eclipse.gef.geometry.planar.Path.Segment;
import org.eclipse.gef.geometry.planar.Point;
import org.eclipse.gef.geometry.planar.Rectangle;
import org.junit.Test;
/**
* Unit tests for {@link Ellipse}.
*
* @author anyssen
* @author mwienand
*
*/
public class EllipseTests {
private static final double PRECISION_FRACTION = TestUtils
.getPrecisionFraction();
private void checkPointContainment(Rectangle r, IGeometry g) {
assertFalse(g.contains(r.getTopLeft()));
assertFalse(g.contains(r.getTopRight()));
assertFalse(g.contains(r.getBottomLeft()));
assertFalse(g.contains(r.getBottomRight()));
assertTrue(g.contains(r.getCenter()));
assertTrue(g.contains(r.getLeft()));
assertTrue(g.contains(
r.getLeft().getTranslated(PRECISION_FRACTION * 1, 0)));
assertFalse(g.contains(
r.getLeft().getTranslated(-PRECISION_FRACTION * 1000, 0)));
// due to AWT's behavior, we won't check getTop() but a point very near
// to it, so that the Path() will survive these tests, too
assertTrue(g.contains(r.getTop().getTranslated(0, 1)));
assertTrue(g.contains(
r.getTop().getTranslated(0, PRECISION_FRACTION * 100)));
assertFalse(g.contains(
r.getTop().getTranslated(0, -PRECISION_FRACTION * 100)));
// due to AWT's behavior, we won't check getRight() but a point very
// near to it, so that the Path() will survive these tests, too
assertTrue(g.contains(r.getRight().getTranslated(-1, 0)));
assertTrue(g.contains(
r.getRight().getTranslated(-PRECISION_FRACTION * 100, 0)));
assertFalse(g.contains(
r.getRight().getTranslated(PRECISION_FRACTION * 100, 0)));
// due to AWT's behavior, we won't check getBottom() but a point very
// near to it, so that the Path() will survive these tests, too
assertTrue(g.contains(r.getBottom().getTranslated(0, -1)));
assertTrue(g.contains(
r.getBottom().getTranslated(0, -PRECISION_FRACTION * 100)));
assertFalse(g.contains(
r.getBottom().getTranslated(0, PRECISION_FRACTION * 100)));
}
private void checkPoints(Point[] expected, Point[] obtained) {
assertEquals(expected.length, obtained.length);
for (Point e : expected) {
boolean found = false;
for (Point o : obtained) {
if (e.equals(o)) {
found = true;
break;
}
}
assertTrue(found);
}
}
private void intersectionsTolerance(Ellipse e1, Ellipse e2,
Point... expected) {
Point[] intersections = e1.getIntersections(e2);
boolean[] foundExpected = new boolean[expected.length];
for (Point poi : intersections) {
assertTrue(
"All points of intersection have to be contained by the first ellipse.",
e1.contains(poi));
assertTrue(
"All points of intersection have to be contained by the second ellipse.",
e2.contains(poi));
for (int i = 0; i < expected.length; i++) {
if (poi.equals(expected[i])) {
foundExpected[i] = true;
}
}
}
for (int i = 0; i < expected.length; i++) {
assertTrue(
"An expected point of intersection " + expected[i]
+ " not found in the list of intersections.",
foundExpected[i]);
}
}
@Test
public void test_contains_Line() {
Ellipse e = new Ellipse(0, 0, 100, 50);
assertFalse(e.contains(new Line(-10, -10, 10, -10)));
assertFalse(e.contains(new Line(-10, -10, 50, 50)));
assertTrue(e.contains(new Line(1, 25, 99, 25)));
assertTrue(e.contains(new Line(0, 25, 100, 25)));
}
@Test
public void test_contains_Point() {
Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
Ellipse e = new Ellipse(r);
checkPointContainment(r, e);
// these things could not be tested in the general case, because of
// AWT's behavior
assertTrue(e.contains(r.getTop()));
assertTrue(e.contains(r.getRight()));
assertTrue(e.contains(r.getBottom()));
for (Point p : e.getIntersections(
new Line(r.getTopLeft(), r.getBottomRight()))) {
assertTrue(e.contains(p));
}
for (Point p : e.getIntersections(
new Line(r.getTopRight(), r.getBottomLeft()))) {
assertTrue(e.contains(p));
}
for (CubicCurve c : e.getOutlineSegments()) {
assertTrue(e.contains(c.get(0.5)));
}
}
@Test
public void test_equals() {
Ellipse e = new Ellipse(0, 0, 100, 50);
assertFalse(e.equals(null));
assertFalse(e.equals(new Point()));
assertEquals(e, e);
assertEquals(e, new Ellipse(0, 0, 100, 50));
assertEquals(e, new Ellipse(new Rectangle(0, 0, 100, 50)));
assertEquals(e, e.getCopy());
assertFalse(e.equals(new Ellipse(0, 0, 100, 10)));
assertFalse(e.equals(new Ellipse(0, 0, 10, 50)));
assertFalse(e.equals(new Ellipse(10, 0, 100, 50)));
assertFalse(e.equals(new Ellipse(0, 10, 100, 50)));
}
@Test
public void test_get_intersections_Ellipse_strict() {
Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
Ellipse e1 = new Ellipse(r);
Ellipse e2 = new Ellipse(r);
// ellipses are identical = returns no intersections, user can check
// this via equals()
Point[] intersections = e1.getIntersections(e2);
assertEquals(0, intersections.length);
// touching left
Rectangle r2 = r.getExpanded(0, -10, -10, -10);
e2 = new Ellipse(r2);
intersections = e1.getIntersections(e2);
for (Point poi : intersections) {
assertTrue(e1.contains(poi));
assertTrue(e2.contains(poi));
}
assertEquals(1, intersections.length);
// if we create an x-scaled ellipse at the same position as before, they
// should have 3 poi (the touching point and two crossing intersections)
r2 = r.getExpanded(0, 0, 100, 0);
e2 = new Ellipse(r2);
intersections = e1.getIntersections(e2);
assertEquals(3, intersections.length);
// if we create a y-scaled ellipse at the same position as before, they
// should have 3 poi (the touching point and two crossing intersections)
r2 = r.getExpanded(0, 0, 0, 100);
e2 = new Ellipse(r2);
intersections = e1.getIntersections(e2);
assertEquals(3, intersections.length);
// if we create an x-scaled ellipse at the same y-position as before,
// the
// two should touch at two positions:
r2 = r.getExpanded(50, 0, 50, 0);
e2 = new Ellipse(r2);
intersections = e1.getIntersections(e2);
assertEquals(2, intersections.length);
// the two poi are top and bottom border mid-points:
int equalsTop = 0;
int equalsBottom = 0;
Rectangle bounds = e1.getBounds();
for (Point poi : intersections) {
// we need to losen the equality test, because the points of
// intersection may be to unprecise
Point top = bounds.getTop();
if (top.equals(poi)) {
equalsTop++;
}
if (bounds.getBottom().equals(poi)) {
equalsBottom++;
}
}
assertEquals(
"The top border mid-point should be one of the two intersections.",
1, equalsTop);
assertEquals(
"The bottom border mid-point should be one of the two intersections.",
1, equalsBottom);
// if we create a y-scaled ellipse at the same x-position as before, the
// two should touch at two positions:
r2 = r.getExpanded(0, 50, 0, 50);
e2 = new Ellipse(r2);
intersections = e1.getIntersections(e2);
assertEquals(2, intersections.length);
// the two poi are left and right border mid-points:
int equalsLeft = 0;
int equalsRight = 0;
for (Point poi : intersections) {
if (bounds.getLeft().equals(poi)) {
equalsLeft++;
}
if (bounds.getRight().equals(poi)) {
equalsRight++;
}
}
assertEquals(
"The left border mid-point should be one of the two intersections.",
1, equalsLeft);
assertEquals(
"The right border mid-point should be one of the two intersections.",
1, equalsRight);
}
@Test
public void test_getCenter() {
Ellipse e = new Ellipse(0, 0, 100, 50);
assertEquals(new Point(50, 25), e.getCenter());
e.scale(2);
assertEquals(new Point(50, 25), e.getCenter());
e.scale(0.5);
e.scale(2, new Point());
assertEquals(new Point(100, 50), e.getCenter());
e.translate(-100, -50);
assertEquals(new Point(), e.getCenter());
}
// @Ignore("This test is too strict. For a liberal test see below:
// test_getIntersections_with_Ellipse_Bezier_special_tolerance")
@Test
public void test_getIntersections_Ellipse_Bezier_special() {
// 3 nearly tangential intersections
Ellipse e1 = new Ellipse(126, 90, 378, 270);
Ellipse e2 = new Ellipse(222, 77, 200, 200);
assertEquals(2, e1.getIntersections(e2).length);
e2 = new Ellipse(133, 90, 2 * (315 - 133), 200);
Point[] intersections = e1.getIntersections(e2);
assertEquals(3, intersections.length);
e2 = new Ellipse(143, 90, 2 * (315 - 143), 200);
assertEquals(3, e1.getIntersections(e2).length);
e2 = new Ellipse(145, 90, 2 * (315 - 145), 200);
assertEquals(3, e1.getIntersections(e2).length);
e1 = new Ellipse(126.0, 90.0, 378.0, 270.0);
e2 = new Ellipse(397.0, 327.0, 26.0, 22.0);
assertEquals(2, e1.getIntersections(e2).length);
}
@Test
public void test_getIntersections_Ellipse_Bezier_special_tolerance() {
// 3 nearly tangential intersections
Ellipse e1 = new Ellipse(126, 90, 378, 270);
Ellipse e2 = new Ellipse(222, 77, 200, 200);
intersectionsTolerance(e1, e2); // TODO: find out the 2 expected points
e2 = new Ellipse(133, 90, 2 * (315 - 133), 200);
intersectionsTolerance(e1, e2); // TODO: find out the 3 expected points
e2 = new Ellipse(143, 90, 2 * (315 - 143), 200);
intersectionsTolerance(e1, e2); // TODO: find out the 3 expected points
e2 = new Ellipse(145, 90, 2 * (315 - 145), 200);
intersectionsTolerance(e1, e2); // TODO: find out the 3 expected points
}
@Test
public void test_getIntersections_Ellipse_tolerance() {
Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
Ellipse e1 = new Ellipse(r);
Ellipse e2 = new Ellipse(r);
// ellipses are identical = returns no intersections, user can check
// this via equals()
Point[] intersections = e1.getIntersections(e2);
assertEquals(0, intersections.length);
// touching left
Rectangle r2 = r.getExpanded(0, -10, -10, -10);
e2 = new Ellipse(r2);
intersectionsTolerance(e1, e2, r.getLeft());
// if we create an x-scaled ellipse at the same position as before, they
// should have 3 poi (the touching point and two crossing intersections)
r2 = r.getExpanded(0, 0, 100, 0);
e2 = new Ellipse(r2);
intersectionsTolerance(e1, e2, r.getLeft()); // TODO: other two pois
// if we create a y-scaled ellipse at the same position as before, they
// should have 3 poi (the touching point and two crossing intersections)
r2 = r.getExpanded(0, 0, 0, 100);
e2 = new Ellipse(r2);
intersectionsTolerance(e1, e2, r.getTop()); // TODO: other two pois
// if we create an x-scaled ellipse at the same y-position as before,
// the two should touch at two positions:
r2 = r.getExpanded(50, 0, 50, 0);
e2 = new Ellipse(r2);
intersectionsTolerance(e1, e2, r.getTop(), r.getBottom());
// if we create a y-scaled ellipse at the same x-position as before, the
// two should touch at two positions:
r2 = r.getExpanded(0, 50, 0, 50);
e2 = new Ellipse(r2);
intersectionsTolerance(e1, e2, r.getLeft(), r.getRight());
}
@Test
public void test_getIntersections_Line() {
Ellipse e = new Ellipse(0, 0, 100, 50);
Line lh = new Line(0, 25, 100, 25);
Point[] is = e.getIntersections(lh);
checkPoints(new Point[] { new Point(0, 25), new Point(100, 25) }, is);
Line lv = new Line(50, 0, 50, 50);
is = e.getIntersections(lv);
checkPoints(new Point[] { new Point(50, 0), new Point(50, 50) }, is);
lh = lh.getTranslated(new Point(0, -25)).toLine();
is = e.getIntersections(lh);
checkPoints(new Point[] { new Point(50, 0) }, is);
lv = lv.getTranslated(new Point(-50, 0)).toLine();
is = e.getIntersections(lv);
checkPoints(new Point[] { new Point(0, 25) }, is);
Line li = new Line(-100, 100, 0, 50);
is = e.getIntersections(li);
assertEquals(0, is.length);
}
@Test
public void test_getIntersections_Line_failing() {
Ellipse e = new Ellipse(0.0, 0.0, 100.0, 100.0);
Point p1 = new Point(25.0, 25.0);
Point p2 = new Point(25.0, -93.0);
assertTrue(e.contains(p1));
assertFalse(e.contains(p2));
Line l = new Line(p1, p2);
Point[] intersections = e.getIntersections(l);
assertEquals(1, intersections.length);
}
@Test
public void test_getShrinked() {
Ellipse e = new Ellipse(0, 0, 100, 100);
assertEquals(new Ellipse(50, 0, 50, 100), e.getShrinked(50, 0, 0, 0));
assertEquals(new Ellipse(0, 50, 100, 50), e.getShrinked(0, 50, 0, 0));
assertEquals(new Ellipse(0, 0, 50, 100), e.getShrinked(0, 0, 50, 0));
assertEquals(new Ellipse(0, 0, 100, 50), e.getShrinked(0, 0, 0, 50));
}
@Test
public void test_intersects_Line() {
Rectangle r = new Rectangle(34.3435, 56.458945, 123.3098, 146.578);
Ellipse e = new Ellipse(r);
for (Line l : r.getOutlineSegments()) {
assertTrue(e.touches(l)); // line touches ellipse (tangent)
}
}
@Test
public void test_toPath() {
Rectangle r = new Rectangle(0, 0, 100, 50);
Ellipse e = new Ellipse(r);
Path path = e.toPath();
checkPointContainment(r, path);
// check path is closed
Segment[] segments = path.getSegments();
assertTrue(segments[segments.length - 1].getType() == Segment.CLOSE);
}
@Test
public void test_toString() {
Ellipse e = new Ellipse(0, 0, 100, 50);
assertEquals("Ellipse (0.0, 0.0, 100.0, 50.0)", e.toString());
}
}