| /******************************************************************************* |
| * Copyright (c) 2008, 2010 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Alexander Shatalin (Borland) - initial API and implementation |
| * Alexander Nyssen (itemis) - Bugzilla #162082: testLinesIntersect() |
| *******************************************************************************/ |
| package org.eclipse.draw2d.test; |
| |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.geometry.Geometry; |
| import org.eclipse.draw2d.geometry.PointList; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.widgets.Display; |
| |
| public class GeometryTest extends AbstractFixtureTestCase { |
| |
| /* |
| * For Geometry.polygonContainsPoint tests |
| */ |
| private static final PointList RHOMB = new PointList(new int[] { 0, 2, 2, |
| 0, 4, 2, 2, 4 }); |
| |
| private static final PointList CONCAVE_PENTAGON = new PointList(new int[] { |
| 0, 0, 0, 8, 4, 4, 8, 8, 8, 0 }); |
| |
| private static final PointList CONCAVE_OCTAGON = new PointList(new int[] { |
| 0, 0, 0, 4, 2, 4, 2, 2, 4, 2, 4, 4, 6, 4, 6, 0 }); |
| |
| /* |
| * For Geometry.polylineContainsPoint tests |
| */ |
| private static final PointList POLYLINE = new PointList(new int[] { 0, 0, |
| 1, 0, 6, 5 }); |
| |
| private static final int TOLERANCE = 2; |
| |
| /* |
| * shifting all PointLists to this value |
| */ |
| private static final int POINT_LIST_SHIFT = TOLERANCE + 1; |
| |
| /* |
| * 8 = Max(x1, y1, x2, y2, ..) for all coordinates specified in the sample |
| * PointLists |
| */ |
| private static final int IMAGE_SIZE = 8 + POINT_LIST_SHIFT * 2; |
| |
| /** |
| * Testing points inside/outside the rhomb located in top half. Excluding |
| * points of RHOMB border - separate test present for it |
| */ |
| public void testTopRhombHalfPoints() { |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 1)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 2, 1)); |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 4, 1)); |
| } |
| |
| /** |
| * Testing points inside/outside the rhomb located in bottop half. Excluding |
| * points of RHOMB border - separate test present for it |
| */ |
| public void testBottomRhombHalfPoints() { |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 3)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 2, 3)); |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 4, 3)); |
| } |
| |
| /** |
| * Testing points inside/outside the rhomb located on the equator. Excluding |
| * points of RHOMB border - separate test present for it |
| */ |
| public void testRhombEquatorPoints() { |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, -1, 2)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 2, 2)); |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 5, 2)); |
| } |
| |
| /** |
| * Testing points outside the rhomb located on top horizontal tangent line. |
| * Excluding points of RHOMB border - separate test present for it |
| */ |
| public void testTopRhombTangentPoints() { |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 0)); |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 4, 0)); |
| } |
| |
| /** |
| * Testing points outside the rhomb located on bottom horizontal tangent |
| * line. Excluding points of RHOMB border - separate test present for it |
| */ |
| public void testBottomRhombTangentPoints() { |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 4)); |
| assertFalse("This point is outside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 4, 4)); |
| } |
| |
| /** |
| * Testing points of RHOMB border - all vertexes + one point on the edge |
| */ |
| public void testRhombBorderPoints() { |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 2)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 0, 2)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 2, 4)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 2, 2)); |
| assertTrue("This point is inside the rhomb", |
| Geometry.polygonContainsPoint(RHOMB, 1, 1)); |
| } |
| |
| /** |
| * Testing points inside/outside the pentagon located on equator of concave. |
| * Excluding points of CONCAVE_PENTAGON border - separate test present for |
| * it |
| */ |
| public void testConcavePentagonEquatorPoints() { |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, -1, 6)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 1, 6)); |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 4, 6)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 7, 6)); |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 9, 6)); |
| } |
| |
| /** |
| * Testing points outside the pentagon located on top concave tangent. |
| * Excluding points of CONCAVE_PENTAGON border - separate test present for |
| * it |
| */ |
| public void testTopConcavePentagonTangentPoints() { |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, -1, 8)); |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 4, 8)); |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 9, 8)); |
| } |
| |
| /** |
| * Testing points inside/outside the pentagon located on bottom concave |
| * tangent. Excluding points of CONCAVE_PENTAGON border - separate test |
| * present for it |
| */ |
| public void testBottomConcavePentagonTangentPoints() { |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, -1, 4)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 1, 4)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 5, 4)); |
| assertFalse("This point is outside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 9, 4)); |
| } |
| |
| /** |
| * Testing points of CONCAVE_PENTAGON border - all vertexes + points on |
| * concave edges |
| */ |
| public void testConcavePentagonBorderPoints() { |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 0, 8)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 2, 6)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 4, 4)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 6, 6)); |
| assertTrue("This point is inside the pentagon", |
| Geometry.polygonContainsPoint(CONCAVE_PENTAGON, 8, 8)); |
| } |
| |
| /** |
| * Testing points located of the horizontal line containing one of the |
| * "concave" edges |
| */ |
| public void testConcaveOctagonBottomTangentPoints() { |
| assertFalse("This point is outside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, -1, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 0, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 1, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 2, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 3, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 4, 2)); |
| assertTrue("This point is inside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 5, 2)); |
| assertFalse("This point is outside the octagon", |
| Geometry.polygonContainsPoint(CONCAVE_OCTAGON, 7, 2)); |
| } |
| |
| public void testNotPolylinePoints() { |
| // Point is outside of (polyline.bounds +- tolerance) rectangle |
| assertFalse(Geometry.polylineContainsPoint(POLYLINE, 9, 5, TOLERANCE)); |
| // Point is inside of (polyline.bounds +- tolerance) rectangle, but |
| // quite far from segments |
| assertFalse(Geometry.polylineContainsPoint(POLYLINE, 1, 4, TOLERANCE)); |
| } |
| |
| public void testPolylinePoints() { |
| // point is close to horizontal segment |
| assertTrue(Geometry.polylineContainsPoint(POLYLINE, -1, 0, TOLERANCE)); |
| // point is close to the slopping segment |
| assertTrue(Geometry.polylineContainsPoint(POLYLINE, 2, 3, TOLERANCE)); |
| // point is on polyline |
| assertTrue(Geometry.polylineContainsPoint(POLYLINE, 0, 0, TOLERANCE)); |
| assertTrue(Geometry.polylineContainsPoint(POLYLINE, 1, 0, TOLERANCE)); |
| assertTrue(Geometry.polylineContainsPoint(POLYLINE, 2, 1, TOLERANCE)); |
| } |
| |
| /** |
| * Testing |
| * {@link Geometry#linesIntersect(int, int, int, int, int, int, int, int)}. |
| */ |
| public void testLinesIntersect() { |
| // line segments collapsed to single points |
| assertTrue("Starting point on segment", |
| Geometry.linesIntersect(0, 0, 0, 0, 0, 0, 3, 3)); |
| assertTrue("Starting point on segment", |
| Geometry.linesIntersect(0, 0, 3, 3, 0, 0, 0, 0)); |
| assertFalse("Single point next to starting point of segment", |
| Geometry.linesIntersect(-1, -1, -1, -1, 0, 0, 2, 2)); |
| assertFalse("Single point next to starting point of segment", |
| Geometry.linesIntersect(0, 0, 2, 2, -1, -1, -1, -1)); |
| assertTrue("Mid point on segment", |
| Geometry.linesIntersect(0, 0, 0, 0, 3, 3, -3, -3)); |
| assertTrue("Mid point on segment", |
| Geometry.linesIntersect(3, 3, -3, -3, 0, 0, 0, 0)); |
| assertFalse("Single point next to mid point of segment", |
| Geometry.linesIntersect(0, 1, 0, 1, 0, 0, 2, 2)); |
| assertFalse("Single point next to mid point of segment", |
| Geometry.linesIntersect(0, 0, 2, 2, 0, 1, 0, 1)); |
| assertTrue("Ending point on segment", |
| Geometry.linesIntersect(3, 3, 3, 3, 0, 0, 3, 3)); |
| assertTrue("Ending point on segment", |
| Geometry.linesIntersect(0, 0, 3, 3, 3, 3, 3, 3)); |
| assertFalse("Single point next to end point of segment", |
| Geometry.linesIntersect(3, 3, 3, 3, 0, 0, 2, 2)); |
| assertFalse("Single point next to end point of segment", |
| Geometry.linesIntersect(0, 0, 2, 2, 3, 3, 3, 3)); |
| assertTrue("Identical points", |
| Geometry.linesIntersect(1, 1, 1, 1, 1, 1, 1, 1)); |
| assertFalse("Distinct points", |
| Geometry.linesIntersect(1, 1, 1, 1, 2, 2, 2, 2)); |
| |
| // non-parallel |
| assertTrue("Line segments cross at (2.5, 2.5).", |
| Geometry.linesIntersect(0, 0, 5, 5, 0, 5, 5, 0)); |
| assertTrue("Line segments cross at (0, 1).", |
| Geometry.linesIntersect(-2, 1, 1, 1, 0, 0, 0, 3)); |
| assertTrue("Line segments share starting point", |
| Geometry.linesIntersect(0, 0, 5, 5, 0, 0, 5, 0)); |
| assertTrue("Line segments share ending point", |
| Geometry.linesIntersect(0, 0, 5, 5, 0, 5, 5, 5)); |
| assertTrue("First line segment contains starting point of second one.", |
| Geometry.linesIntersect(0, 0, 5, 5, 3, 3, 0, 5)); |
| assertFalse( |
| "Line segments are non-parallel and do not cross and should thus not be regarded as intersecting.", |
| Geometry.linesIntersect(0, 0, 2, 2, 0, 1, 0, 2)); |
| |
| // parallel |
| assertFalse( |
| "Line segments are parallel but not co-linear and should thus not be regarded as intersecting.", |
| Geometry.linesIntersect(0, 0, 5, 5, 1, 0, 6, 5)); |
| assertFalse( |
| "Line segments are parallel but not co-linear and should thus not be regarded as intersecting.", |
| Geometry.linesIntersect(0, 0, 3, 3, 4, 0, 6, 2)); |
| |
| // co-linear |
| assertTrue("Line segments are co-linear, partly-overlapping.", |
| Geometry.linesIntersect(0, 0, 5, 5, 3, 3, 6, 6)); |
| assertTrue("Line segments are co-linear, partly-overlapping.", |
| Geometry.linesIntersect(3, 3, 6, 6, 0, 0, 5, 5)); |
| assertTrue("Line segments are co-linear, fully-overlapping.", |
| Geometry.linesIntersect(0, 0, 5, 5, 1, 1, 3, 3)); |
| assertTrue("Line segments are co-linear, fully-overlapping.", |
| Geometry.linesIntersect(1, 1, 5, 5, -1, -1, 6, 6)); |
| assertTrue( |
| "Line segments are co-linear, sharing ending/starting point.", |
| Geometry.linesIntersect(0, 0, 5, 5, 5, 5, 6, 6)); |
| assertTrue( |
| "Line segments are co-linear, sharing starting/ending point.", |
| Geometry.linesIntersect(3, 3, 6, 6, 0, 0, 3, 3)); |
| assertFalse( |
| "Line segments are co-linear but non-overlapping, and should thus not be regarded as intersecting.", |
| Geometry.linesIntersect(0, 0, 5, 5, 10, 10, 20, 20)); |
| assertFalse( |
| "Line segments are co-linear but non-overlapping, and should thus not be regarded as intersecting.", |
| Geometry.linesIntersect(0, 0, 5, 5, -10, -10, -20, -20)); |
| } |
| |
| public void off_testDrawPolygons() { |
| checkFilledPolygonPoints(translatePointList(RHOMB)); |
| checkFilledPolygonPoints(translatePointList(CONCAVE_PENTAGON)); |
| checkFilledPolygonPoints(translatePointList(CONCAVE_OCTAGON)); |
| } |
| |
| public void off_testDrawPolylines() { |
| checkPolylinePoints(translatePointList(RHOMB)); |
| checkPolylinePoints(translatePointList(CONCAVE_PENTAGON)); |
| checkPolylinePoints(translatePointList(CONCAVE_OCTAGON)); |
| checkPolylinePoints(translatePointList(POLYLINE)); |
| } |
| |
| private PointList translatePointList(PointList original) { |
| PointList translated = original.getCopy(); |
| translated.performTranslate(POINT_LIST_SHIFT, POINT_LIST_SHIFT); |
| return translated; |
| } |
| |
| private void checkFilledPolygonPoints(PointList pointlist) { |
| Display display = Display.getDefault(); |
| Image image = new Image(display, IMAGE_SIZE, IMAGE_SIZE); |
| GC gc = new GC(image.getDevice()); |
| cleanupImage(gc); |
| gc.setBackground(ColorConstants.black()); |
| gc.setForeground(ColorConstants.black()); |
| gc.fillPolygon(pointlist.toIntArray()); |
| gc.drawPolygon(pointlist.toIntArray()); |
| gc.dispose(); |
| ImageData imageData = image.getImageData(); |
| for (int x = 0; x < IMAGE_SIZE; x++) { |
| for (int y = 0; y < IMAGE_SIZE; y++) { |
| boolean isPolygonPoint = imageData.getPixel(x, y) == 0; |
| assertTrue( |
| "Point (" + x + "," + y + ") is" |
| + (isPolygonPoint ? " " : " not ") |
| + "a point of polygon", |
| Geometry.polygonContainsPoint(pointlist, x, y) == isPolygonPoint); |
| } |
| } |
| } |
| |
| private void checkPolylinePoints(PointList pointlist) { |
| Display display = Display.getDefault(); |
| Image image = new Image(display, IMAGE_SIZE, IMAGE_SIZE); |
| GC gc = new GC(image.getDevice()); |
| cleanupImage(gc); |
| gc.setForeground(ColorConstants.black()); |
| gc.drawPolyline(pointlist.toIntArray()); |
| gc.dispose(); |
| ImageData imageData = image.getImageData(); |
| for (int x = 0; x < IMAGE_SIZE; x++) { |
| for (int y = 0; y < IMAGE_SIZE; y++) { |
| if (imageData.getPixel(x, y) == 0) { |
| assertTrue("Point (" + x + "," + y |
| + ") is a point of polyline", |
| Geometry.polylineContainsPoint(pointlist, x, y, |
| TOLERANCE)); |
| } |
| } |
| } |
| } |
| |
| // Filling initial image with white color |
| private void cleanupImage(GC gc) { |
| gc.setBackground(ColorConstants.white()); |
| gc.setForeground(ColorConstants.white()); |
| gc.fillRectangle(0, 0, IMAGE_SIZE, IMAGE_SIZE); |
| gc.drawRectangle(0, 0, IMAGE_SIZE, IMAGE_SIZE); |
| } |
| |
| } |