mirror of https://github.com/apache/lucene.git
LUCENE-6810: Spatial4j 0.5 upgrade. Mostly fixes a few edge-case bugs.
* the spatial4j tests jar is published and we use some utilities there; this adds a test dependency on it & SLF4J. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1704759 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4cbf0da8c6
commit
69e5f9bdf4
|
@ -150,6 +150,10 @@ Bug Fixes
|
||||||
handling a tragic exception but another is still committing (Mike
|
handling a tragic exception but another is still committing (Mike
|
||||||
McCandless)
|
McCandless)
|
||||||
|
|
||||||
|
* LUCENE-6810: Upgrade to Spatial4j 0.5 -- fixes some edge-case bugs in the
|
||||||
|
spatial module. See https://github.com/locationtech/spatial4j/blob/master/CHANGES.md
|
||||||
|
(David Smiley)
|
||||||
|
|
||||||
Other
|
Other
|
||||||
|
|
||||||
* LUCENE-6812: Upgrade RandomizedTesting to 2.1.17. (Dawid Weiss)
|
* LUCENE-6812: Upgrade RandomizedTesting to 2.1.17. (Dawid Weiss)
|
||||||
|
|
|
@ -41,7 +41,7 @@ com.google.inject.guice.version = 3.0
|
||||||
/com.googlecode.mp4parser/isoparser = 1.0.2
|
/com.googlecode.mp4parser/isoparser = 1.0.2
|
||||||
/com.ibm.icu/icu4j = 54.1
|
/com.ibm.icu/icu4j = 54.1
|
||||||
/com.pff/java-libpst = 0.8.1
|
/com.pff/java-libpst = 0.8.1
|
||||||
/com.spatial4j/spatial4j = 0.4.1
|
/com.spatial4j/spatial4j = 0.5
|
||||||
|
|
||||||
com.sun.jersey.version = 1.9
|
com.sun.jersey.version = 1.9
|
||||||
/com.sun.jersey.contribs/jersey-guice = ${com.sun.jersey.version}
|
/com.sun.jersey.contribs/jersey-guice = ${com.sun.jersey.version}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
2b8019b6249bb05d81d3a3094e468753e2b21311
|
|
@ -1 +0,0 @@
|
||||||
4234d12b1ba4d4b539fb3e29edd948a99539d9eb
|
|
|
@ -0,0 +1 @@
|
||||||
|
bdcdf20a723516a233b5bcc0ca7d4decaa88b6ed
|
|
@ -0,0 +1 @@
|
||||||
|
6e16edaf6b1ba76db7f08c2f3723fce3b358ecc3
|
|
@ -16,13 +16,20 @@
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
-->
|
-->
|
||||||
<ivy-module version="2.0">
|
<ivy-module version="2.0" xmlns:maven="http://ant.apache.org/ivy/maven">
|
||||||
<info organisation="org.apache.lucene" module="spatial"/>
|
<info organisation="org.apache.lucene" module="spatial"/>
|
||||||
<configurations defaultconfmapping="compile->master">
|
<configurations defaultconfmapping="compile->master;test->master">
|
||||||
<conf name="compile" transitive="false"/>
|
<conf name="compile" transitive="false"/>
|
||||||
|
<conf name="test" transitive="false"/>
|
||||||
</configurations>
|
</configurations>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency org="com.spatial4j" name="spatial4j" rev="${/com.spatial4j/spatial4j}" conf="compile"/>
|
<dependency org="com.spatial4j" name="spatial4j" rev="${/com.spatial4j/spatial4j}" conf="compile">
|
||||||
<exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
|
<artifact name="spatial4j" ext="jar" />
|
||||||
|
<artifact name="spatial4j" type="test" ext="jar" maven:classifier="tests" />
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency org="org.slf4j" name="slf4j-api" rev="${/org.slf4j/slf4j-api}" conf="test"/>
|
||||||
|
|
||||||
|
<exclude org="*" ext="*" matcher="regexp" type="${ivy.exclude.types}"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</ivy-module>
|
</ivy-module>
|
||||||
|
|
|
@ -266,6 +266,11 @@ public abstract class NumberRangePrefixTree extends SpatialPrefixTree {
|
||||||
lastLevelInCommon = level - 1;
|
lastLevelInCommon = level - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpatialContext getContext() {
|
||||||
|
return DUMMY_CTX;
|
||||||
|
}
|
||||||
|
|
||||||
public UnitNRShape getMinUnit() { return minLV; }
|
public UnitNRShape getMinUnit() { return minLV; }
|
||||||
|
|
||||||
public UnitNRShape getMaxUnit() { return maxLV; }
|
public UnitNRShape getMaxUnit() { return maxLV; }
|
||||||
|
@ -953,6 +958,11 @@ public abstract class NumberRangePrefixTree extends SpatialPrefixTree {
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpatialContext getContext() {
|
||||||
|
return DUMMY_CTX;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
//trick to re-use bytesref; provided that we re-instate it
|
//trick to re-use bytesref; provided that we re-instate it
|
||||||
|
|
|
@ -61,6 +61,11 @@ public class Geo3dShape implements Shape {
|
||||||
this.shape = shape;
|
this.shape = shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpatialContext getContext() {
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpatialRelation relate(Shape other) {
|
public SpatialRelation relate(Shape other) {
|
||||||
if (other instanceof Rectangle)
|
if (other instanceof Rectangle)
|
||||||
|
|
|
@ -57,27 +57,18 @@ public class TestBBoxStrategy extends RandomSpatialOpStrategyTestCase {
|
||||||
int worldHeight = (int) Math.round(world.getHeight());
|
int worldHeight = (int) Math.round(world.getHeight());
|
||||||
int deltaTop = nextIntInclusive(worldHeight);
|
int deltaTop = nextIntInclusive(worldHeight);
|
||||||
int deltaBottom = nextIntInclusive(worldHeight - deltaTop);
|
int deltaBottom = nextIntInclusive(worldHeight - deltaTop);
|
||||||
|
if (ctx.isGeo() && (deltaLeft != 0 || deltaRight != 0)) {
|
||||||
double rectMinX = world.getMinX() + deltaLeft;
|
//if geo & doesn't world-wrap, we shift randomly to potentially cross dateline
|
||||||
double rectMaxX = world.getMaxX() - deltaRight;
|
int shift = nextIntInclusive(360);
|
||||||
if (ctx.isGeo()) {
|
return ctx.makeRectangle(
|
||||||
int shift = 0;
|
DistanceUtils.normLonDEG(world.getMinX() + deltaLeft + shift),
|
||||||
if ((deltaLeft != 0 || deltaRight != 0)) {
|
DistanceUtils.normLonDEG(world.getMaxX() - deltaRight + shift),
|
||||||
//if geo & doesn't world-wrap, we shift randomly to potentially cross dateline
|
world.getMinY() + deltaBottom, world.getMaxY() - deltaTop);
|
||||||
shift = nextIntInclusive(360);
|
} else {
|
||||||
}
|
return ctx.makeRectangle(
|
||||||
rectMinX = DistanceUtils.normLonDEG(rectMinX + shift);
|
world.getMinX() + deltaLeft, world.getMaxX() - deltaRight,
|
||||||
rectMaxX = DistanceUtils.normLonDEG(rectMaxX + shift);
|
world.getMinY() + deltaBottom, world.getMaxY() - deltaTop);
|
||||||
if (rectMinX == 180 && rectMaxX == 180) {
|
|
||||||
// Work-around for https://github.com/spatial4j/spatial4j/issues/85
|
|
||||||
rectMinX = -180;
|
|
||||||
rectMaxX = -180;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ctx.makeRectangle(
|
|
||||||
rectMinX,
|
|
||||||
rectMaxX,
|
|
||||||
world.getMinY() + deltaBottom, world.getMaxY() - deltaTop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** next int, inclusive, rounds to multiple of 10 if given evenly divisible. */
|
/** next int, inclusive, rounds to multiple of 10 if given evenly divisible. */
|
||||||
|
|
|
@ -447,7 +447,7 @@ public class RandomSpatialOpFuzzyPrefixTreeTest extends StrategyTestCase {
|
||||||
final boolean biasContainsThenWithin;
|
final boolean biasContainsThenWithin;
|
||||||
|
|
||||||
public ShapePair(Shape shape1, Shape shape2, boolean containsThenWithin) {
|
public ShapePair(Shape shape1, Shape shape2, boolean containsThenWithin) {
|
||||||
super(Arrays.asList(shape1, shape2), ctx);
|
super(Arrays.asList(shape1, shape2), RandomSpatialOpFuzzyPrefixTreeTest.this.ctx);
|
||||||
this.shape1 = shape1;
|
this.shape1 = shape1;
|
||||||
this.shape2 = shape2;
|
this.shape2 = shape2;
|
||||||
this.shape1_2D = toNonGeo(shape1);
|
this.shape1_2D = toNonGeo(shape1);
|
||||||
|
|
|
@ -22,10 +22,12 @@ import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import com.carrotsearch.randomizedtesting.RandomizedContext;
|
import com.carrotsearch.randomizedtesting.RandomizedContext;
|
||||||
|
import com.spatial4j.core.TestLog;
|
||||||
import com.spatial4j.core.context.SpatialContext;
|
import com.spatial4j.core.context.SpatialContext;
|
||||||
import com.spatial4j.core.distance.DistanceUtils;
|
import com.spatial4j.core.distance.DistanceUtils;
|
||||||
import com.spatial4j.core.shape.Circle;
|
import com.spatial4j.core.shape.Circle;
|
||||||
import com.spatial4j.core.shape.Point;
|
import com.spatial4j.core.shape.Point;
|
||||||
|
import com.spatial4j.core.shape.RectIntersectionTestHelper;
|
||||||
import org.apache.lucene.geo3d.LatLonBounds;
|
import org.apache.lucene.geo3d.LatLonBounds;
|
||||||
import org.apache.lucene.geo3d.GeoBBox;
|
import org.apache.lucene.geo3d.GeoBBox;
|
||||||
import org.apache.lucene.geo3d.GeoBBoxFactory;
|
import org.apache.lucene.geo3d.GeoBBoxFactory;
|
||||||
|
@ -44,7 +46,7 @@ public abstract class Geo3dShapeRectRelationTestCase extends RandomizedShapeTest
|
||||||
protected final static double RADIANS_PER_DEGREE = Math.PI/180.0;
|
protected final static double RADIANS_PER_DEGREE = Math.PI/180.0;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final LogRule testLog = LogRule.instance;
|
public final TestLog testLog = TestLog.instance;
|
||||||
|
|
||||||
protected static Random random() {
|
protected static Random random() {
|
||||||
return RandomizedContext.current().getRandom();
|
return RandomizedContext.current().getRandom();
|
||||||
|
@ -91,15 +93,26 @@ public abstract class Geo3dShapeRectRelationTestCase extends RandomizedShapeTest
|
||||||
super(ctx);
|
super(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//20 times each -- should be plenty
|
||||||
protected int getMaxLaps() {
|
|
||||||
//sometimes, getWithinMinimum needs some more attempts then normal; 20k is suggested max.
|
protected int getContainsMinimum(int laps) {
|
||||||
return 200_000;//200k
|
return 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected int getIntersectsMinimum(int laps) {
|
||||||
protected int getDefaultMinimumPredicateFrequency(int maxLaps) {
|
return 20;
|
||||||
return 20;//20 times each -- should be plenty in 200k
|
}
|
||||||
|
|
||||||
|
protected int getWithinMinimum(int laps) {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getDisjointMinimum(int laps) {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getBoundingMinimum(int laps) {
|
||||||
|
return 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package org.apache.lucene.spatial.spatial4j;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility logger for tests in which log statements are logged following
|
|
||||||
* test failure only. Add this to a JUnit based test class with a {@link org.junit.Rule}
|
|
||||||
* annotation.
|
|
||||||
*/
|
|
||||||
public class LogRule extends TestRuleAdapter {
|
|
||||||
|
|
||||||
//TODO does this need to be threadsafe (such as via thread-local state)?
|
|
||||||
private static ArrayList<LogEntry> logStack = new ArrayList<LogEntry>();
|
|
||||||
private static final int MAX_LOGS = 1000;
|
|
||||||
|
|
||||||
public static final LogRule instance = new LogRule();
|
|
||||||
|
|
||||||
private LogRule() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void before() throws Throwable {
|
|
||||||
logStack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void afterAlways(List<Throwable> errors) throws Throwable {
|
|
||||||
if (!errors.isEmpty())
|
|
||||||
logThenClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logThenClear() {
|
|
||||||
for (LogEntry entry : logStack) {
|
|
||||||
//no SLF4J in Lucene... fallback to this
|
|
||||||
if (entry.args != null && entry.args.length > 0) {
|
|
||||||
System.out.println(entry.msg + " " + Arrays.asList(entry.args) + "(no slf4j subst; sorry)");
|
|
||||||
} else {
|
|
||||||
System.out.println(entry.msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logStack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clear() {
|
|
||||||
logStack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enqueues a log message with substitution arguments ala SLF4J (i.e. {} syntax).
|
|
||||||
* If the test fails then it'll be logged then, otherwise it'll be forgotten.
|
|
||||||
*/
|
|
||||||
public static void log(String msg, Object... args) {
|
|
||||||
if (logStack.size() > MAX_LOGS) {
|
|
||||||
throw new RuntimeException("Too many log statements: "+logStack.size() + " > "+MAX_LOGS);
|
|
||||||
}
|
|
||||||
LogEntry entry = new LogEntry();
|
|
||||||
entry.msg = msg;
|
|
||||||
entry.args = args;
|
|
||||||
logStack.add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LogEntry { String msg; Object[] args; }
|
|
||||||
}
|
|
|
@ -1,242 +0,0 @@
|
||||||
package org.apache.lucene.spatial.spatial4j;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.spatial4j.core.context.SpatialContext;
|
|
||||||
import com.spatial4j.core.shape.Point;
|
|
||||||
import com.spatial4j.core.shape.Rectangle;
|
|
||||||
import com.spatial4j.core.shape.Shape;
|
|
||||||
import com.spatial4j.core.shape.SpatialRelation;
|
|
||||||
import com.spatial4j.core.shape.impl.InfBufLine;
|
|
||||||
import com.spatial4j.core.shape.impl.PointImpl;
|
|
||||||
|
|
||||||
import static com.spatial4j.core.shape.SpatialRelation.CONTAINS;
|
|
||||||
import static com.spatial4j.core.shape.SpatialRelation.DISJOINT;
|
|
||||||
|
|
||||||
public abstract class RectIntersectionTestHelper<S extends Shape> extends RandomizedShapeTestCase {
|
|
||||||
|
|
||||||
public RectIntersectionTestHelper(SpatialContext ctx) {
|
|
||||||
super(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Override to return true if generateRandomShape is essentially a Rectangle. */
|
|
||||||
protected boolean isRandomShapeRectangular() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract S generateRandomShape(Point nearP);
|
|
||||||
|
|
||||||
/** shape has no area; return a point in it */
|
|
||||||
protected abstract Point randomPointInEmptyShape(S shape);
|
|
||||||
|
|
||||||
// Minimum distribution of relationships
|
|
||||||
|
|
||||||
// Each shape has different characteristics, so we don't expect (for instance) shapes that
|
|
||||||
// are likely to be long and thin to contain as many rectangles as those that
|
|
||||||
// short and fat.
|
|
||||||
|
|
||||||
/** Called once by {@link #testRelateWithRectangle()} to determine the max laps to try before failing. */
|
|
||||||
protected int getMaxLaps() {
|
|
||||||
return scaledRandomIntBetween(20_000, 200_000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The minimum number of times we need to see each predicate in {@code laps} iterations. */
|
|
||||||
protected int getDefaultMinimumPredicateFrequency(int maxLaps) {
|
|
||||||
return maxLaps / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getContainsMinimum(int maxLaps) {
|
|
||||||
return getDefaultMinimumPredicateFrequency(maxLaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getIntersectsMinimum(int maxLaps) {
|
|
||||||
return getDefaultMinimumPredicateFrequency(maxLaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getWithinMinimum(int maxLaps) {
|
|
||||||
return getDefaultMinimumPredicateFrequency(maxLaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getDisjointMinimum(int maxLaps) {
|
|
||||||
return getDefaultMinimumPredicateFrequency(maxLaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getBoundingMinimum(int maxLaps) {
|
|
||||||
return getDefaultMinimumPredicateFrequency(maxLaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
protected Point randomPointInOrNull(Shape shape) {
|
|
||||||
if (!shape.hasArea()) {
|
|
||||||
final Point pt = randomPointInEmptyShape((S) shape);
|
|
||||||
assert shape.relate(pt).intersects() : "faulty randomPointInEmptyShape";
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
return super.randomPointInOrNull(shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRelateWithRectangle() {
|
|
||||||
//counters for the different intersection cases
|
|
||||||
int i_C = 0, i_I = 0, i_W = 0, i_D = 0, i_bboxD = 0;
|
|
||||||
int lap = 0;
|
|
||||||
final int MAXLAPS = getMaxLaps();
|
|
||||||
while(i_C < getContainsMinimum(MAXLAPS) || i_I < getIntersectsMinimum(MAXLAPS) || i_W < getWithinMinimum(MAXLAPS)
|
|
||||||
|| (!isRandomShapeRectangular() && i_D < getDisjointMinimum(MAXLAPS)) || i_bboxD < getBoundingMinimum(MAXLAPS)) {
|
|
||||||
lap++;
|
|
||||||
|
|
||||||
LogRule.clear();
|
|
||||||
|
|
||||||
if (lap > MAXLAPS) {
|
|
||||||
fail("Did not find enough contains/within/intersection/disjoint/bounds cases in a reasonable number" +
|
|
||||||
" of attempts. CWIDbD: " +
|
|
||||||
i_C + "("+getContainsMinimum(MAXLAPS)+")," +
|
|
||||||
i_W + "("+getWithinMinimum(MAXLAPS)+")," +
|
|
||||||
i_I + "("+getIntersectsMinimum(MAXLAPS)+")," +
|
|
||||||
i_D + "("+getDisjointMinimum(MAXLAPS)+")," +
|
|
||||||
i_bboxD + "("+getBoundingMinimum(MAXLAPS)+")"
|
|
||||||
+ " Laps exceeded " + MAXLAPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point nearP = randomPointIn(ctx.getWorldBounds());
|
|
||||||
|
|
||||||
S s = generateRandomShape(nearP);
|
|
||||||
|
|
||||||
Rectangle r = randomRectangle(s.getBoundingBox().getCenter());
|
|
||||||
|
|
||||||
SpatialRelation ic = s.relate(r);
|
|
||||||
|
|
||||||
LogRule.log("S-R Rel: {}, Shape {}, Rectangle {} lap# {}", ic, s, r, lap);
|
|
||||||
|
|
||||||
if (ic != DISJOINT) {
|
|
||||||
assertTrue("if not disjoint then the shape's bbox shouldn't be disjoint",
|
|
||||||
s.getBoundingBox().relate(r).intersects());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
int MAX_TRIES = scaledRandomIntBetween(10, 100);
|
|
||||||
switch (ic) {
|
|
||||||
case CONTAINS:
|
|
||||||
i_C++;
|
|
||||||
for (int j = 0; j < MAX_TRIES; j++) {
|
|
||||||
Point p = randomPointIn(r);
|
|
||||||
assertRelation(null, CONTAINS, s, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WITHIN:
|
|
||||||
i_W++;
|
|
||||||
for (int j = 0; j < MAX_TRIES; j++) {
|
|
||||||
Point p = randomPointInOrNull(s);
|
|
||||||
if (p == null) {//couldn't find a random point in shape
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
assertRelation(null, CONTAINS, r, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DISJOINT:
|
|
||||||
if (!s.getBoundingBox().relate(r).intersects()) {//bboxes are disjoint
|
|
||||||
i_bboxD++;
|
|
||||||
if (i_bboxD >= getBoundingMinimum(MAXLAPS))
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
i_D++;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < MAX_TRIES; j++) {
|
|
||||||
Point p = randomPointIn(r);
|
|
||||||
assertRelation(null, DISJOINT, s, p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INTERSECTS:
|
|
||||||
i_I++;
|
|
||||||
SpatialRelation pointR = null;//set once
|
|
||||||
Rectangle randomPointSpace = null;
|
|
||||||
MAX_TRIES = 1000;//give many attempts
|
|
||||||
for (int j = 0; j < MAX_TRIES; j++) {
|
|
||||||
Point p;
|
|
||||||
if (j < 4) {
|
|
||||||
p = new PointImpl(0, 0, ctx);
|
|
||||||
InfBufLine.cornerByQuadrant(r, j + 1, p);
|
|
||||||
} else {
|
|
||||||
if (randomPointSpace == null) {
|
|
||||||
if (pointR == DISJOINT) {
|
|
||||||
randomPointSpace = intersectRects(r,s.getBoundingBox());
|
|
||||||
} else {//CONTAINS
|
|
||||||
randomPointSpace = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p = randomPointIn(randomPointSpace);
|
|
||||||
}
|
|
||||||
SpatialRelation pointRNew = s.relate(p);
|
|
||||||
if (pointR == null) {
|
|
||||||
pointR = pointRNew;
|
|
||||||
} else if (pointR != pointRNew) {
|
|
||||||
break;
|
|
||||||
} else if (j >= MAX_TRIES) {
|
|
||||||
//TODO consider logging instead of failing
|
|
||||||
fail("Tried intersection brute-force too many times without success");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: fail(""+ic);
|
|
||||||
} // switch
|
|
||||||
} catch (AssertionError e) {
|
|
||||||
onAssertFail(e, s, r, ic);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // while loop
|
|
||||||
|
|
||||||
System.out.println("Laps: "+lap + " CWIDbD: "+i_C+","+i_W+","+i_I+","+i_D+","+i_bboxD);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onAssertFail(AssertionError e, S s, Rectangle r, SpatialRelation ic) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rectangle intersectRects(Rectangle r1, Rectangle r2) {
|
|
||||||
assert r1.relate(r2).intersects();
|
|
||||||
final double minX, maxX;
|
|
||||||
if (r1.relateXRange(r2.getMinX(),r2.getMinX()).intersects()) {
|
|
||||||
minX = r2.getMinX();
|
|
||||||
} else {
|
|
||||||
minX = r1.getMinX();
|
|
||||||
}
|
|
||||||
if (r1.relateXRange(r2.getMaxX(),r2.getMaxX()).intersects()) {
|
|
||||||
maxX = r2.getMaxX();
|
|
||||||
} else {
|
|
||||||
maxX = r1.getMaxX();
|
|
||||||
}
|
|
||||||
final double minY, maxY;
|
|
||||||
if (r1.relateYRange(r2.getMinY(),r2.getMinY()).intersects()) {
|
|
||||||
minY = r2.getMinY();
|
|
||||||
} else {
|
|
||||||
minY = r1.getMinY();
|
|
||||||
}
|
|
||||||
if (r1.relateYRange(r2.getMaxY(),r2.getMaxY()).intersects()) {
|
|
||||||
maxY = r2.getMaxY();
|
|
||||||
} else {
|
|
||||||
maxY = r1.getMaxY();
|
|
||||||
}
|
|
||||||
return ctx.makeRectangle(minX, maxX, minY, maxY);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
6e16edaf6b1ba76db7f08c2f3723fce3b358ecc3
|
Loading…
Reference in New Issue