Hi Gerd
Here is a replacement for is_in-function_v10.patch with the additions:
- method ..,none)=true to replace ..,any_in_or_on)=false.
- revised documentation.
- detection of holes within the rule.polygon. Will set OUT, ie stop
'all' being true, and, if exactly ON, not set IN, ie stop 'any' being
true.
- removal the kind parameters and related logic from IsInUtil; the
IsInFunction driver has better understanding of how POLYGON processing
should differ from POLYLINE.
- restructure the MethodArg enum to include all the method dependent
logic.
Test case b14 (rule.polygon being the hole in the multiPolygon)
should be OUT, or maybe OUT|ON but the test driver only understands ALL
or ANY for polygons. It still fails because isLineInShape returns
IN|ON|OUT for the rule.polygon against one of the cut simple polygons,
where it should be ON|OUT
Ticker
On Tue, 2020-02-18 at 00:23 -0700, Gerd Petermann wrote:
> Ticker Berkin wrote
> > I suggest replacing ANY_IN_OR_ON with SOME_OUT_NONE_IN, giving it
> > the
> > method string "none", like SOME_IN_NONE_OUT is referenced as "all".
>
> Yes, much better.
>
> Gerd
>
>
>
>
> --
> Sent from:
> http://gis.19327.n8.nabble.com/Mkgmap-Development-f5324443.html
> _______________________________________________
> mkgmap-dev mailing list
> [email protected]
> http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev
Index: doc/styles/rules.txt
===================================================================
--- doc/styles/rules.txt (revision 4453)
+++ doc/styles/rules.txt (working copy)
@@ -286,21 +286,26 @@
+true+ if the element is in polygon(s) having the specified +tag+=+value+ according to the +method+, +false+ otherwise.
The methods available depend on the Style section:
-* points:
+. polygons:
+ +all+ - all of the closed Way is within the polygon(s).
+ +any+ - some is within.
+
+. points:
+in+ - the Node is within a polygon.
+in_or_on+ - it is within or on the edge.
+on+ - it is on the edge.
-* lines:
+. lines:
+all+ - part of the Way is within the polygon(s), none is outside; it might touch an edge.
- +all_in_or_on+ - none is outside. This is useful for the negative - is_in(...,all_in_or_on)=false - for processing a line that is outside the polgon(s).
+ +all_in_or_on+ - none is outside.
+on+ - it runs along the edge.
+any+ - part is within.
- +any_in_or_on+ - part is within or in the edge.
+ +none+ - part is outside, none is inside
-* polygons:
- +all+ - all of the closed Way is within the polygon(s).
- +any+ - some is within.
+A common case is a line outside the polygon that runs to the edge, joining a line that is inside.
+The method to match an outside line (+none+) allows part to be on the edge,
+likewise, the method to match an inside line (+all+) allows part to be on the edge.
+The method +all_in_or_on+ additionally matches lines are only on the edge of the polygon.
|====
Index: src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java (revision 4453)
+++ src/uk/me/parabola/mkgmap/osmstyle/function/IsInFunction.java (working copy)
@@ -43,19 +43,33 @@
private enum MethodArg {
- // can stop when: IN ON OUT
- POINT_IN("in", FeatureKind.POINT, true, false, false),
- POINT_IN_OR_ON("in_or_on", FeatureKind.POINT, true, true, false),
- POINT_ON("on", FeatureKind.POINT, false, true, false),
+ // can stop when: IN ON OUT MERGE
+ POINT_IN("in", FeatureKind.POINT, true, false, false, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn;} },
+ POINT_IN_OR_ON("in_or_on", FeatureKind.POINT, true, true, false, false)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn || hasOn;} },
+ POINT_ON("on", FeatureKind.POINT, false, true, false, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasOn;} },
- LINE_SOME_IN_NONE_OUT("all", FeatureKind.POLYLINE, false, false, true),
- LINE_ALL_IN_OR_ON("all_in_or_on", FeatureKind.POLYLINE, false, false, true),
- LINE_ALL_ON("on", FeatureKind.POLYLINE, true, false, true),
- LINE_ANY_IN("any", FeatureKind.POLYLINE, true, false, false),
- LINE_ANY_IN_OR_ON("any_in_or_on", FeatureKind.POLYLINE, true, true, false),
+ LINE_SOME_IN_NONE_OUT("all", FeatureKind.POLYLINE, false, false, true, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn && !hasOut;} },
+ LINE_ALL_IN_OR_ON("all_in_or_on", FeatureKind.POLYLINE, false, false, true, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return !hasOut;} },
+ LINE_ALL_ON("on", FeatureKind.POLYLINE, true, false, true, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return !(hasIn || hasOut);} },
+ LINE_ANY_IN("any", FeatureKind.POLYLINE, true, false, false, false)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn;} },
+// LINE_ANY_IN_OR_ON("any_in_or_on", FeatureKind.POLYLINE, true, false, false, true)
+// { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn || !hasOut;} },
+ LINE_NONE_IN_SOME_OUT("none", FeatureKind.POLYLINE, true, false, false, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return !hasIn && hasOut;} },
+
+ POLYGON_ALL("all", FeatureKind.POLYGON, false, false, true, true)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return !hasOut;} },
+ POLYGON_ANY("any", FeatureKind.POLYGON, true, false, false, false)
+ { @Override public boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut) {return hasIn;} };
- POLYGON_ALL("all", FeatureKind.POLYGON, false, false, true),
- POLYGON_ANY("any", FeatureKind.POLYGON, true, false, false);
+ public abstract boolean mapFlags(boolean hasIn, boolean hasOn, boolean hasOut);
private final String methodName;
private final FeatureKind kind;
@@ -62,13 +76,15 @@
private final boolean stopIn;
private final boolean stopOn;
private final boolean stopOut;
+ private final boolean needMerge;
- MethodArg(String methodName, FeatureKind kind, boolean stopIn, boolean stopOn, boolean stopOut) {
+ MethodArg(String methodName, FeatureKind kind, boolean stopIn, boolean stopOn, boolean stopOut, boolean needMerge) {
this.methodName = methodName;
this.kind = kind;
this.stopIn = stopIn;
this.stopOn = stopOn;
this.stopOut = stopOut;
+ this.needMerge = needMerge;
}
public String toString() {
@@ -88,6 +104,9 @@
public boolean canStopOut() {
return stopOut;
}
+ public boolean needMerge() {
+ return needMerge;
+ }
}
private class CanStopProcessing extends RuntimeException {};
@@ -134,7 +153,9 @@
}
} catch (CanStopProcessing e) {}
log.info("done", System.identityHashCode(this), hasIn, hasOn, hasOut);
- return String.valueOf(mapHasFlagsAnswer());
+ if (!hasIn && !hasOn)
+ hasOut = true;
+ return String.valueOf(method.mapFlags(hasIn, hasOn, hasOut));
}
/* don't have this for CachedFunction
@@ -169,7 +190,7 @@
private void setIn() {
log.info("setIn", hasIn, hasOn, hasOut);
hasIn = true;
- if (method.canStopIn() || (hasOn && hasOut))
+ if (method.canStopIn() || hasOut)
throw new CanStopProcessing();
}
@@ -182,45 +203,20 @@
private void setOut() {
log.info("setOut", hasIn, hasOn, hasOut);
hasOut = true;
- if (method.canStopOut() || (hasIn && hasOn))
+ if (method.canStopOut() || hasIn)
throw new CanStopProcessing();
}
private void setHasFromFlags(int flags) {
+ log.info("setFlags", flags);
+ if ((flags & IsInUtil.ON) != 0)
+ setOn();
if ((flags & IsInUtil.IN) != 0)
setIn();
- if ((flags & IsInUtil.ON) != 0)
- setOn();
if ((flags & IsInUtil.OUT) != 0)
setOut();
}
- private boolean mapHasFlagsAnswer() {
- switch (method) {
- case POINT_IN:
- return hasIn;
- case POINT_IN_OR_ON:
- return hasIn || hasOn;
- case POINT_ON:
- return hasOn;
- case LINE_SOME_IN_NONE_OUT:
- return hasIn && !hasOut;
- case LINE_ALL_IN_OR_ON:
- return !hasOut;
- case LINE_ALL_ON:
- return !(hasIn || hasOut);
- case LINE_ANY_IN:
- return hasIn;
- case LINE_ANY_IN_OR_ON:
- return hasIn || hasOn;
- case POLYGON_ALL:
- return !hasOut;
- case POLYGON_ANY:
- return hasIn;
- }
- return false;
- }
-
private static boolean notInHole(Coord c, List<List<Coord>> holes) {
if (holes == null)
return true;
@@ -263,7 +259,7 @@
Area elementBbox = Area.getBBox(Collections.singletonList(c));
Set<Way> polygons = qt.get(elementBbox).stream().map(e -> (Way) e)
.collect(Collectors.toCollection(LinkedHashSet::new));
- if ((method == MethodArg.POINT_IN || method == MethodArg.POINT_ON) && polygons.size() > 1) {
+ if (method.needMerge() && polygons.size() > 1) {
// need to merge shapes so that POI on shared boundary becomes IN rather than ON
List<List<Coord>> outers = new ArrayList<>();
List<List<Coord>> holes = new ArrayList<>();
@@ -290,9 +286,11 @@
doCommonTest(el);
}
- private void checkHoles(List<Coord> polyLine, List<List<Coord>> holes, Area elementBbox) {
+ private boolean checkHoles(List<Coord> polyLine, List<List<Coord>> holes, Area elementBbox) {
+ boolean foundSomething = false;
for (List<Coord> hole : holes) {
- int flags = IsInUtil.isLineInShape(kind, polyLine, hole, elementBbox);
+ int flags = IsInUtil.isLineInShape(polyLine, hole, elementBbox);
+ log.info("checkhole", flags);
if ((flags & IsInUtil.IN) != 0) {
setOut();
if ((flags & IsInUtil.ON) != 0)
@@ -299,49 +297,78 @@
setOn();
if ((flags & IsInUtil.OUT) != 0)
setIn();
+ return true;
+ } else if ((flags & IsInUtil.ON) != 0) {
+ setOn();
+ if ((flags & IsInUtil.OUT) != 0)
+ setIn();
+ foundSomething = true;
+ }
+ }
+ return foundSomething;
+ }
+
+ private void checkHoleInThis(List<Coord> polyLine, List<List<Coord>> holes, Area elementBbox) {
+ for (List<Coord> hole : holes) {
+ int flags = IsInUtil.isLineInShape(hole, polyLine, elementBbox);
+ log.info("holeInThis", flags);
+ if ((flags & IsInUtil.IN) != 0 ||
+ (flags == IsInUtil.ON)) { // exactly on hole
+ setOut();
return;
}
}
}
- /*
-make above function return boolean depending on it finding something.
-maybe should also respond to ON
-in below, delay setting the IN flag until have done the above, because the line could all be ON the inner.
-and use return from above to set IN, assume that when it finds something, it will set IN of OUT etc
-
-for POLY, still need a final check that, even if ON/IN, none of the holes is in this one, so
-we need another check (can we use above not-in-hole...) that takes a point from the hole and
-checks if it is the polyLine
- */
private void doCommonTest(Element el) {
List<Coord> polyLine = ((Way)el).getPoints();
Area elementBbox = Area.getBBox(polyLine);
Set<Way> polygons = qt.get(elementBbox).stream().map(e -> (Way) e)
.collect(Collectors.toCollection(LinkedHashSet::new));
- if ((method == MethodArg.LINE_SOME_IN_NONE_OUT ||
- method == MethodArg.LINE_ALL_IN_OR_ON ||
- method == MethodArg.LINE_ALL_ON ||
- method == MethodArg.POLYGON_ALL) && polygons.size() > 1) {
- // ALL-like methods need to merge shapes
+ if (log.isInfoEnabled()) {
+ log.info("line", polyLine);
+ log.info(polygons.size(), "polygons");
+ for (Way polygon : polygons)
+ log.info("polygon", polygon.getPoints());
+ }
+ if (method.needMerge() && polygons.size() > 1) { // ALL-like methods need to merge shapes
List<List<Coord>> outers = new ArrayList<>();
List<List<Coord>> holes = new ArrayList<>();
IsInUtil.mergePolygons(polygons, outers, holes);
- log.info("polyMerge", polygons.size(), outers.size(), holes.size());
+ if (log.isInfoEnabled()) {
+ log.info(outers.size(), "outers", holes.size(), "holes");
+ for (List<Coord> shape : outers)
+ log.info("outer", shape);
+ for (List<Coord> hole : holes)
+ log.info("hole", hole);
+ }
for (List<Coord> shape : outers) {
- int flags = IsInUtil.isLineInShape(kind, polyLine, shape, elementBbox);
- if ((flags & (IsInUtil.IN | IsInUtil.ON)) != 0) {
- // this shape is the one to consider
- setHasFromFlags(flags); // might set OUT and stop
- if ((flags & IsInUtil.IN) != 0)
- checkHoles(polyLine, holes, elementBbox);
+ int flags = IsInUtil.isLineInShape(polyLine, shape, elementBbox);
+ log.info("checkShape", flags);
+ if ((flags & IsInUtil.IN) != 0) { // this shape is the one to consider
+ if ((flags & IsInUtil.ON) != 0)
+ setOn();
+ if ((flags & IsInUtil.OUT) != 0)
+ setOut();
+ if (!checkHoles(polyLine, holes, elementBbox))
+ setIn();
+ if (!hasOut && kind == FeatureKind.POLYGON)
+ checkHoleInThis(polyLine, holes, elementBbox);
break;
+ } else if ((flags & IsInUtil.ON) != 0) { // might still be IN later one
+ setOn();
+ if ((flags & IsInUtil.OUT) != 0)
+ setOut();
+ else { // exactly on
+ if (kind == FeatureKind.POLYGON)
+ checkHoleInThis(polyLine, holes, elementBbox);
+ break; // hence can't be in another
+ }
}
}
- } else { // an ANY-like method
- log.info("poly1by1", polygons.size());
+ } else { // an ANY-like method or 1 polygon
for (Way polygon : polygons)
- setHasFromFlags(IsInUtil.isLineInShape(kind, polyLine, polygon.getPoints(), elementBbox));
+ setHasFromFlags(IsInUtil.isLineInShape(polyLine, polygon.getPoints(), elementBbox));
}
}
Index: src/uk/me/parabola/util/IsInUtil.java
===================================================================
--- src/uk/me/parabola/util/IsInUtil.java (revision 4453)
+++ src/uk/me/parabola/util/IsInUtil.java (working copy)
@@ -25,7 +25,6 @@
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.reader.osm.Element;
-import uk.me.parabola.mkgmap.reader.osm.FeatureKind;
import uk.me.parabola.mkgmap.reader.osm.Node;
import uk.me.parabola.mkgmap.reader.osm.Way;
@@ -80,7 +79,7 @@
}
- public static int isLineInShape(FeatureKind kind, List<Coord> lineToTest, List<Coord> shape, Area elementBbox) {
+ public static int isLineInShape(List<Coord> lineToTest, List<Coord> shape, Area elementBbox) {
final int n = lineToTest.size();
int status = isPointInShape(lineToTest.get(0), shape);
BitSet onBoundary = new BitSet();
@@ -185,7 +184,7 @@
status |= insidePolygon(pTest, false, shape) ? IN : OUT;
return status;
}
- status |= checkAllOn(kind, lineToTest, shape);
+ status |= checkAllOn(lineToTest, shape);
}
return status;
}
@@ -193,12 +192,11 @@
/**
* Handle special case that all points of {@code lineToTest} are on the edge of shape
- * @param kind
* @param lineToTest
* @param shape
* @return
*/
- private static int checkAllOn(FeatureKind kind, List<Coord> lineToTest, List<Coord> shape) {
+ private static int checkAllOn(List<Coord> lineToTest, List<Coord> shape) {
int n = lineToTest.size();
// all points are on boundary
for (int i = 0; i < n-1; i++) {
@@ -212,51 +210,6 @@
return resMidPoint;
}
}
-
- // if we get here we can assume that the line runs along the shape
- if (kind == FeatureKind.POLYGON) {
- // lineToTest is a polygon and all segments are on boundary
- // find a node inside lineToTest and check if this point is in shape
-
- // find topmost node(s)
- int maxLat = Integer.MIN_VALUE;
- List<SimpleEntry<Coord, Integer>> topNodes = new ArrayList<>();
- for (int i = 0; i < lineToTest.size() - 1; i++) {
- Coord c = lineToTest.get(i);
- int latHp = c.getHighPrecLat();
- if (latHp > maxLat) {
- maxLat = latHp;
- topNodes.clear();
- }
- if (latHp >= maxLat) {
- topNodes.add(new SimpleEntry<>(c,i));
- }
- }
-
- for (SimpleEntry<Coord, Integer> topNode : topNodes) {
- int pos = topNode.getValue();
- Coord top = topNode.getKey();
- Coord prev = lineToTest.get(pos == 0 ? n - 2 : pos - 1);
- Coord next = lineToTest.get(pos == n - 1 ? 1 : pos + 1);
- double b1 = top.bearingTo(prev);
- double b2 = top.bearingTo(next);
- // b1 and b2 must be heading south or exactly east or west
- // find heading of angle bisector
- double bisectorBearing = (b1 + b2) / 2;
- if (bisectorBearing > -90 && bisectorBearing < 90) {
- // don't go north of top
- bisectorBearing -= 180;
- if (bisectorBearing < -180)
- bisectorBearing += 360;
- }
- Coord pTest = topNode.getKey().destOnRhumLine(0.1, bisectorBearing);
- // double check: the calculated point may not be inside the
- // element
- if (isPointInShape(pTest, lineToTest) == IN && isPointInShape(pTest, shape) == IN) {
- return IN; // all ON and areas intersect
- }
- }
- }
return ON;
}
Index: test/uk/me/parabola/util/IsInUtilTest.java
===================================================================
--- test/uk/me/parabola/util/IsInUtilTest.java (revision 4453)
+++ test/uk/me/parabola/util/IsInUtilTest.java (working copy)
@@ -41,103 +41,74 @@
import uk.me.parabola.mkgmap.reader.osm.OsmMapDataSource;
import uk.me.parabola.mkgmap.reader.osm.Way;
-import uk.me.parabola.mkgmap.osmstyle.function.IsInFunction;
+/*
+Source: test/resources/in/osm/is-in-samples.osm
+errors: test-reports/uk/me/parabola/util/62_IsInUtilTest-err.html
+b14 failed, expected: 4 got 5
+*/
+
public class IsInUtilTest {
- private static int calcInsideness(FeatureKind kind, Element el, Set<Way> polygons) {
- int result = 0;
- if (polygons == null || polygons.isEmpty()) {
- return IsInUtil.OUT;
- }
-
- Area elementBbox;
- if (el instanceof Node) {
- Coord c = ((Node) el).getLocation();
- for (Way polygon : polygons) {
- switch (IsInUtil.isPointInShape(c, polygon.getPoints())) {
- case IsInUtil.IN:
- return IsInUtil.IN;
- case IsInUtil.ON:
- result |= IsInUtil.ON;
- default:
- }
- }
- return result == 0 ? IsInUtil.OUT : IsInUtil.ON;
- } else if (el instanceof Way) {
- Way w = (Way) el;
- if (w.isComplete()) {
- elementBbox = Area.getBBox(w.getPoints());
- if (polygons.size() > 1) {
- // combine all polygons which intersect the bbox of the element if possible
- Path2D.Double path = new Path2D.Double();
- for (Way polygon : polygons) {
- path.append(Java2DConverter.createPath2D(polygon.getPoints()), false);
- }
- java.awt.geom.Area polygonsArea = new java.awt.geom.Area(path);
- List<List<Coord>> mergedShapes = Java2DConverter.areaToShapes(polygonsArea);
+ Area testSourceBbox = null;
- // combination of polygons may contain holes. They are counter clockwise.
- List<List<Coord>> holes = new ArrayList<>();
- List<List<Coord>> outers = new ArrayList<>();
- for (List<Coord> shape : mergedShapes) {
- (Way.clockwise(shape) ? outers : holes).add(shape);
- }
-
- // check if any outer intersects with the way
- for (List<Coord> shape : outers) {
- int tmpRes = IsInUtil.isLineInShape(kind, w.getPoints(), shape, elementBbox);
- if (tmpRes != IsInUtil.OUT) {
- result |= tmpRes;
- if ((tmpRes & IsInUtil.IN) != 0) {
- result = tmpRes;
- break;
- }
- }
- }
- if ((result & IsInUtil.IN) != 0 && !holes.isEmpty()) {
- // an outer ring matched
- // check if any hole intersects with the way
- for (List<Coord> hole : holes) {
- int tmpRes = IsInUtil.isLineInShape(kind, w.getPoints(), hole, elementBbox);
- if (tmpRes == IsInUtil.IN_ON_OUT)
- return tmpRes;
- if ((tmpRes & IsInUtil.IN) != 0)
- result = IsInUtil.OUT;
- result |= tmpRes & IsInUtil.ON;
-
- }
- }
-
- } else if (polygons.size() == 1) {
- result = IsInUtil.isLineInShape(kind, w.getPoints(), (polygons.iterator().next()).getPoints(), elementBbox);
- }
- }
- }
- if (result == 0)
- result = IsInUtil.OUT;
- return result;
+ private static boolean invokeMethod(IsInFunction anInst, String method, FeatureKind kind, Element el) {
+ anInst.setParams(Arrays.asList("landuse", "residential", method), kind); // tag key/value don't matter
+ String rslt = anInst.calcImpl(el);
+ return "true".equals(rslt);
}
- private static int dev_calcInsideness(FeatureKind kind, Element el, Set<Way> polygons) {
- int result = 0;
- if (polygons == null || polygons.isEmpty()) {
+ private int calcInsideness(FeatureKind kind, Element el, Set<Way> polygons) {
+ int result = 0;
+ if (polygons == null || polygons.isEmpty()) {
return IsInUtil.OUT;
}
- Area tileBbox = null; // ??? Area.getBBox(el); maybe
IsInFunction anInst = new IsInFunction();
- // [javac] /norbert/svn/branches/is-in/test/uk/me/parabola/util/IsInUtilTest.java:125: error: incompatible types: Set<Way> cannot be converted to Collection<Element>
- //fix anInst.unitTestAugment(new ElementQuadTree(tileBbox, polygons));
- anInst.setParams(Arrays.asList("landuse", "residential", "all"), kind);
- String rslt = anInst.calcImpl(el);
- /* TODO: %%%
-choose 3 methods depending on Kind whose combination will give us IN/ON/OUT
-test the rslt string for "True" and set the bits in result as appropriate
- */
+ List<Element> matchingPolygons = new ArrayList<>();
+ for (Way polygon : polygons)
+ matchingPolygons.add(polygon);
+ anInst.unitTestAugment(new ElementQuadTree(testSourceBbox, matchingPolygons));
+ switch (kind) {
+ case POINT:
+ if (invokeMethod(anInst, "in_or_on", kind, el))
+ if (invokeMethod(anInst, "in", kind, el))
+ result = IsInUtil.IN;
+ else
+ result = IsInUtil.ON;
+ else
+ result = IsInUtil.OUT;
+ break;
+ case POLYLINE:
+ /* all=someInNoneOut, any=anyIn, none=someOutNoneIn
+a) IN all allInOrOn any
+b) IN ON all allInOrOn any
+c) IN ON OUT any
+d) ON allInOrOn on
+e) ON OUT none
+f) OUT none
+ */
+ if (invokeMethod(anInst, "all", kind, el)) /*a,b*/
+ result = IsInUtil.IN | IsInUtil.ON; // methods won't say if also ON
+ else /*c,d,e,f*/ if (invokeMethod(anInst, "on", kind, el)) /*d*/
+ result = IsInUtil.ON;
+ else /*c,e,f*/ if (invokeMethod(anInst, "any", kind, el)) /*c*/
+ result = IsInUtil.IN | IsInUtil.ON | IsInUtil.OUT;
+ else /*e,f*/
+ result = IsInUtil.OUT | IsInUtil.ON; // methods won't say if also ON
+ break;
+ case POLYGON: // ON is meaningless for polygons
+ if (invokeMethod(anInst, "all", kind, el))
+ result = IsInUtil.IN;
+ else if (invokeMethod(anInst, "any", kind, el))
+ result = IsInUtil.IN | IsInUtil.OUT;
+ else
+ result = IsInUtil.OUT;
+ break;
+ }
return result;
}
-
- public static List<String> testWithVariants(FeatureKind kind, Element el, String name, Set<Way> polygons) {
+
+ public List<String> testWithVariants(FeatureKind kind, Element el, String name, Set<Way> polygons) {
List<String> errors = new ArrayList<>();
int res = calcInsideness(kind, el, polygons);
@@ -144,6 +115,21 @@
String expectedVal = el.getTag("expected");
if (expectedVal != null && !"?".equals(expectedVal)) {
int expected = Integer.parseInt(expectedVal);
+
+/*
+Using the "method" interface to emulate the old version of IsInUtil.calcInsideness and try and deduce
+the IN/ON/OUT flags to compare with the 'expected' tag isn't quite possible:
+ For POLYGONs the ON flag is meaningless - it can be wholly or partially within
+ For LINEs, the methods don't distinguish between a line that is totally ON and one that is IN but touches the edge,
+ Similarly a line that is OUT and one that touches the edge.
+So here we adjust the expected value to match what can be tested.
+*/
+ if (kind == FeatureKind.POLYGON)
+ expected &= ~IsInUtil.ON;
+ else if (kind == FeatureKind.POLYLINE)
+ if (expected == IsInUtil.IN || expected == IsInUtil.OUT)
+ expected |= IsInUtil.ON;
+
if (expected != res) {
errors.add(name + " failed, expected: " + expected + " got "+ res);
return errors;
@@ -205,6 +191,7 @@
TestSource src = new TestSource();
src.config(new EnhancedProperties());
src.load(Args.TEST_RESOURCE_OSM + "is-in-samples.osm", false);
+ testSourceBbox = src.getElementSaver().getBoundingBox();
ElementQuadTree qt = IsInFunction.buildTree(src.getElementSaver(), "landuse", "residential");
ArrayList<String> allErrors = new ArrayList<>();
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev