/******************************************************************************* * Copyright (c) 2015 Voyager Search and MITRE * All rights reserved. This program and the accompanying materials * are made available under the terms of the Apache License, Version 2.0 which * accompanies this distribution and is available at * http://www.apache.org/licenses/LICENSE-2.0.txt ******************************************************************************/ package org.locationtech.spatial4j.shape; import com.carrotsearch.randomizedtesting.RandomizedTest; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.locationtech.spatial4j.TestLog; import org.locationtech.spatial4j.context.SpatialContext; import org.locationtech.spatial4j.context.SpatialContextFactory; import org.locationtech.spatial4j.shape.impl.BufferedLine; import org.locationtech.spatial4j.shape.impl.PointImpl; import org.locationtech.spatial4j.shape.impl.RectangleImpl; import org.junit.Rule; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class BufferedLineTest extends RandomizedTest { private final SpatialContext ctx = new SpatialContextFactory() {{geo = false; worldBounds = new RectangleImpl(-100, 100, -50, 50, null);}}.newSpatialContext(); @Rule public TestLog testLog = TestLog.instance; //SpatialContext.GEO ;// public static void logShapes(final BufferedLine line, final Rectangle rect) { String lineWKT = "LINESTRING(" + line.getA().getX() + " " + line.getA().getY() + "," + line.getB().getX() + " " + line.getB().getY() + ")"; System.out.println( "GEOMETRYCOLLECTION(" + lineWKT + "," + rectToWkt(line.getBoundingBox ()) + ")"); String rectWKT = rectToWkt(rect); System.out.println(rectWKT); } static private String rectToWkt(Rectangle rect) { return "POLYGON((" + rect.getMinX() + " " + rect.getMinY() + "," + rect.getMaxX() + " " + rect.getMinY() + "," + rect.getMaxX() + " " + rect.getMaxY() + "," + rect.getMinX() + " " + rect.getMaxY() + "," + rect.getMinX() + " " + rect.getMinY() + "))"; } @Test public void distance() { //negative slope testDistToPoint(ctx.makePoint(7, -4), ctx.makePoint(3, 2), ctx.makePoint(5, 6), 3.88290); //positive slope testDistToPoint(ctx.makePoint(3, 2), ctx.makePoint(7, 5), ctx.makePoint(5, 6), 2.0); //vertical line testDistToPoint(ctx.makePoint(3, 2), ctx.makePoint(3, 8), ctx.makePoint(4, 3), 1.0); //horiz line testDistToPoint(ctx.makePoint(3, 2), ctx.makePoint(6, 2), ctx.makePoint(4, 3), 1.0); } private void testDistToPoint(Point pA, Point pB, Point pC, double dist) { if (dist > 0) { assertFalse(new BufferedLine(pA, pB, dist * 0.999, ctx).contains(pC)); } else { assert dist == 0; assertTrue(new BufferedLine(pA, pB, 0, ctx).contains(pC)); } assertTrue(new BufferedLine(pA, pB, dist * 1.001, ctx).contains(pC)); } @Test public void misc() { //pa == pb Point pt = ctx.makePoint(10, 1); BufferedLine line = new BufferedLine(pt, pt, 3, ctx); assertTrue(line.contains(ctx.makePoint(10, 1 + 3 - 0.1))); assertFalse(line.contains(ctx.makePoint(10, 1 + 3 + 0.1))); } @Test @Repeat(iterations = 15) public void quadrants() { //random line BufferedLine line = newRandomLine(); // if (line.getA().equals(line.getB())) // return;//this test doesn't work Rectangle rect = newRandomLine().getBoundingBox(); //logShapes(line, rect); //compute closest corner brute force ArrayList<Point> corners = quadrantCorners(rect); // a collection instead of 1 value due to ties Collection<Integer> farthestDistanceQuads = new LinkedList<Integer>(); double farthestDistance = -1; int quad = 1; for (Point corner : corners) { double d = line.getLinePrimary().distanceUnbuffered(corner); if (Math.abs(d - farthestDistance) < 0.000001) {//about equal farthestDistanceQuads.add(quad); } else if (d > farthestDistance) { farthestDistanceQuads.clear(); farthestDistanceQuads.add(quad); farthestDistance = d; } quad++; } //compare results int calcClosestQuad = line.getLinePrimary().quadrant(rect.getCenter()); assertTrue(farthestDistanceQuads.contains(calcClosestQuad)); } private BufferedLine newRandomLine() { Point pA = new PointImpl(randomInt(9), randomInt(9), ctx); Point pB = new PointImpl(randomInt(9), randomInt(9), ctx); int buf = randomInt(5); return new BufferedLine(pA, pB, buf, ctx); } private ArrayList<Point> quadrantCorners(Rectangle rect) { ArrayList<Point> corners = new ArrayList<Point>(4); corners.add(ctx.makePoint(rect.getMaxX(), rect.getMaxY())); corners.add(ctx.makePoint(rect.getMinX(), rect.getMaxY())); corners.add(ctx.makePoint(rect.getMinX(), rect.getMinY())); corners.add(ctx.makePoint(rect.getMaxX(), rect.getMinY())); return corners; } @Test public void testRectIntersect() { new RectIntersectionTestHelper<BufferedLine>(ctx) { @Override protected BufferedLine generateRandomShape(Point nearP) { Rectangle nearR = randomRectangle(nearP); ArrayList<Point> corners = quadrantCorners(nearR); int r4 = randomInt(3);//0..3 Point pA = corners.get(r4); Point pB = corners.get((r4 + 2) % 4); double maxBuf = Math.max(nearR.getWidth(), nearR.getHeight()); double buf = Math.abs(randomGaussian()) * maxBuf / 4; buf = randomInt((int) divisible(buf)); return new BufferedLine(pA, pB, buf, ctx); } protected Point randomPointInEmptyShape(BufferedLine shape) { int r = randomInt(1); if (r == 0) return shape.getA(); //if (r == 1) return shape.getB(); // Point c = shape.getCenter(); // if (shape.contains(c)); } }.testRelateWithRectangle(); } private BufferedLine newBufLine(int x1, int y1, int x2, int y2, int buf) { Point pA = ctx.makePoint(x1, y1); Point pB = ctx.makePoint(x2, y2); if (randomBoolean()) { return new BufferedLine(pB, pA, buf, ctx); } else { return new BufferedLine(pA, pB, buf, ctx); } } }