Subject: [PATCH] 24046
---
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java b/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java
|
a
|
b
|
|
| 154 | 154 | * @throws JoinedPolygonCreationException if the creation fails. |
| 155 | 155 | */ |
| 156 | 156 | public static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWays(Relation multipolygon) { |
| | 157 | return joinWays(null, multipolygon); |
| | 158 | } |
| | 159 | |
| | 160 | /** |
| | 161 | * Joins the given {@code multipolygon} to a pair of outer and inner multipolygon rings. |
| | 162 | * |
| | 163 | * @param multipolygon the multipolygon to join. |
| | 164 | * @return a pair of outer and inner multipolygon rings. |
| | 165 | * @throws JoinedPolygonCreationException if the creation fails. |
| | 166 | * @since xxx |
| | 167 | */ |
| | 168 | public static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWays( |
| | 169 | Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> cache, Relation multipolygon) { |
| | 170 | if (cache != null) { |
| | 171 | return cache.computeIfAbsent(multipolygon, MultipolygonBuilder::joinWaysActual); |
| | 172 | } |
| | 173 | return joinWaysActual(multipolygon); |
| | 174 | } |
| | 175 | |
| | 176 | /** |
| | 177 | * Perform the actual join ways calculation |
| | 178 | * |
| | 179 | * @param multipolygon the multipolygon to join. |
| | 180 | * @return a pair of outer and inner multipolygon rings. |
| | 181 | * @throws JoinedPolygonCreationException if the creation fails. |
| | 182 | */ |
| | 183 | private static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWaysActual(IRelation<?> multipolygon) { |
| 157 | 184 | CheckParameterUtil.ensureThat(multipolygon.isMultipolygon(), "multipolygon.isMultipolygon"); |
| 158 | | final Map<String, Set<Way>> members = multipolygon.getMembers().stream() |
| 159 | | .filter(RelationMember::isWay) |
| 160 | | .collect(Collectors.groupingBy(RelationMember::getRole, Collectors.mapping(RelationMember::getWay, Collectors.toSet()))); |
| | 185 | CheckParameterUtil.ensureThat(multipolygon instanceof Relation, |
| | 186 | "This method currently only supports Relation objects due to potential breakage"); |
| | 187 | final Map<String, Set<Way>> members = ((Relation) multipolygon).getMembers().stream() |
| | 188 | .filter(IRelationMember::isWay) |
| | 189 | .collect(Collectors.groupingBy(IRelationMember::getRole, Collectors.mapping(RelationMember::getWay, Collectors.toSet()))); |
| 161 | 190 | final List<JoinedPolygon> outerRings = joinWays(members.getOrDefault("outer", Collections.emptySet())); |
| 162 | 191 | final List<JoinedPolygon> innerRings = joinWays(members.getOrDefault("inner", Collections.emptySet())); |
| 163 | 192 | return Pair.create(outerRings, innerRings); |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java b/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
|
a
|
b
|
|
| 24 | 24 | import java.util.stream.Stream; |
| 25 | 25 | |
| 26 | 26 | import org.openstreetmap.josm.data.osm.IPrimitive; |
| | 27 | import org.openstreetmap.josm.data.osm.IRelation; |
| | 28 | import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon; |
| 27 | 29 | import org.openstreetmap.josm.data.osm.OsmPrimitive; |
| 28 | 30 | import org.openstreetmap.josm.data.preferences.BooleanProperty; |
| 29 | 31 | import org.openstreetmap.josm.data.preferences.CachingProperty; |
| … |
… |
|
| 49 | 51 | import org.openstreetmap.josm.tools.I18n; |
| 50 | 52 | import org.openstreetmap.josm.tools.Logging; |
| 51 | 53 | import org.openstreetmap.josm.tools.MultiMap; |
| | 54 | import org.openstreetmap.josm.tools.Pair; |
| 52 | 55 | import org.openstreetmap.josm.tools.Stopwatch; |
| 53 | 56 | import org.openstreetmap.josm.tools.Utils; |
| 54 | 57 | |
| … |
… |
|
| 60 | 63 | private MapCSSStyleIndex indexData; |
| 61 | 64 | private final Map<MapCSSRule, MapCSSTagCheckerAndRule> ruleToCheckMap = new HashMap<>(); |
| 62 | 65 | private static final Map<IPrimitive, Area> mpAreaCache = new HashMap<>(); |
| | 66 | private static final Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> mpJoinedAreaCache = new HashMap<>(); |
| 63 | 67 | private static final Set<IPrimitive> toMatchForSurrounding = new HashSet<>(); |
| 64 | 68 | static final boolean ALL_TESTS = true; |
| 65 | 69 | static final boolean ONLY_SELECTED_TESTS = false; |
| … |
… |
|
| 163 | 167 | |
| 164 | 168 | final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null); |
| 165 | 169 | env.mpAreaCache = mpAreaCache; |
| | 170 | env.mpJoinedAreaCache = mpJoinedAreaCache; |
| 166 | 171 | env.toMatchForSurrounding = toMatchForSurrounding; |
| 167 | 172 | |
| 168 | 173 | Iterator<MapCSSRule> candidates = indexData.getRuleCandidates(p); |
| … |
… |
|
| 221 | 226 | final List<TestError> r = new ArrayList<>(); |
| 222 | 227 | final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null); |
| 223 | 228 | env.mpAreaCache = mpAreaCache; |
| | 229 | env.mpJoinedAreaCache = mpJoinedAreaCache; |
| 224 | 230 | env.toMatchForSurrounding = toMatchForSurrounding; |
| 225 | 231 | for (Set<MapCSSTagCheckerRule> schecks : checksCol) { |
| 226 | 232 | for (MapCSSTagCheckerRule check : schecks) { |
| … |
… |
|
| 376 | 382 | // always clear the cache to make sure that we catch changes in geometry |
| 377 | 383 | mpAreaCache.clear(); |
| 378 | 384 | ruleToCheckMap.clear(); |
| | 385 | mpJoinedAreaCache.clear(); |
| 379 | 386 | toMatchForSurrounding.clear(); |
| 380 | 387 | super.endTest(); |
| 381 | 388 | } |
| … |
… |
|
| 396 | 403 | } |
| 397 | 404 | |
| 398 | 405 | mpAreaCache.clear(); |
| | 406 | mpJoinedAreaCache.clear(); |
| 399 | 407 | toMatchForSurrounding.clear(); |
| 400 | 408 | |
| 401 | 409 | Set<OsmPrimitive> surrounding = new HashSet<>(); |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
|
a
|
b
|
|
| 490 | 490 | public void visit(IRelation<?> r) { |
| 491 | 491 | if (r instanceof Relation && r.isMultipolygon() && r.getBBox().bounds(e.osm.getBBox()) |
| 492 | 492 | && left.matches(new Environment(r).withParent(e.osm)) |
| 493 | | && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r).isEmpty()) { |
| | 493 | && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r, e.mpJoinedAreaCache).isEmpty()) { |
| 494 | 494 | addToChildren(e, r); |
| 495 | 495 | } |
| 496 | 496 | } |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/gui/mappaint/Environment.java b/src/org/openstreetmap/josm/gui/mappaint/Environment.java
|
a
|
b
|
|
| 8 | 8 | import java.util.Set; |
| 9 | 9 | |
| 10 | 10 | import org.openstreetmap.josm.data.osm.IPrimitive; |
| | 11 | import org.openstreetmap.josm.data.osm.IRelation; |
| | 12 | import org.openstreetmap.josm.data.osm.MultipolygonBuilder; |
| 11 | 13 | import org.openstreetmap.josm.data.osm.Relation; |
| 12 | 14 | import org.openstreetmap.josm.data.osm.Way; |
| 13 | 15 | import org.openstreetmap.josm.data.osm.WaySegment; |
| … |
… |
|
| 15 | 17 | import org.openstreetmap.josm.gui.mappaint.mapcss.Selector; |
| 16 | 18 | import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector; |
| 17 | 19 | import org.openstreetmap.josm.tools.CheckParameterUtil; |
| | 20 | import org.openstreetmap.josm.tools.Pair; |
| 18 | 21 | |
| 19 | 22 | /** |
| 20 | 23 | * Environment is a data object to provide access to various "global" parameters. |
| … |
… |
|
| 90 | 93 | * Cache for multipolygon areas, can be null, used with CrossingFinder |
| 91 | 94 | */ |
| 92 | 95 | public Map<IPrimitive, Area> mpAreaCache; |
| | 96 | /** |
| | 97 | * Cache for multipolygon areas as calculated by {@link MultipolygonBuilder#joinWays(Relation)}, can be {@code null} |
| | 98 | */ |
| | 99 | public Map<IRelation<?>, Pair<List<MultipolygonBuilder.JoinedPolygon>, List<MultipolygonBuilder.JoinedPolygon>>> mpJoinedAreaCache; |
| 93 | 100 | |
| 94 | 101 | /** |
| 95 | 102 | * Can be null, may contain primitives when surrounding objects of the primitives are tested |
| … |
… |
|
| 162 | 169 | this.intersections = other.intersections; |
| 163 | 170 | this.crossingWaysMap = other.crossingWaysMap; |
| 164 | 171 | this.mpAreaCache = other.mpAreaCache; |
| | 172 | this.mpJoinedAreaCache = other.mpJoinedAreaCache; |
| 165 | 173 | this.toMatchForSurrounding = other.toMatchForSurrounding; |
| 166 | 174 | this.selector = selector; |
| 167 | 175 | } |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/tools/Geometry.java b/src/org/openstreetmap/josm/tools/Geometry.java
|
a
|
b
|
|
| 17 | 17 | import java.util.Iterator; |
| 18 | 18 | import java.util.LinkedHashSet; |
| 19 | 19 | import java.util.List; |
| | 20 | import java.util.Map; |
| 20 | 21 | import java.util.Set; |
| 21 | 22 | import java.util.TreeSet; |
| 22 | 23 | import java.util.function.Predicate; |
| … |
… |
|
| 32 | 33 | import org.openstreetmap.josm.data.osm.DataSet; |
| 33 | 34 | import org.openstreetmap.josm.data.osm.INode; |
| 34 | 35 | import org.openstreetmap.josm.data.osm.IPrimitive; |
| | 36 | import org.openstreetmap.josm.data.osm.IRelation; |
| 35 | 37 | import org.openstreetmap.josm.data.osm.IWay; |
| 36 | 38 | import org.openstreetmap.josm.data.osm.MultipolygonBuilder; |
| 37 | 39 | import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon; |
| … |
… |
|
| 1191 | 1193 | if (polygonArea == null) { |
| 1192 | 1194 | polygonArea = getArea(polygon.getNodes()); |
| 1193 | 1195 | } |
| 1194 | | Multipolygon mp = new Multipolygon((Relation) p); |
| | 1196 | Multipolygon mp = p.getDataSet() != null ? MultipolygonCache.getInstance().get((Relation) p) : new Multipolygon((Relation) p); |
| 1195 | 1197 | boolean inside = true; |
| 1196 | 1198 | // a (valid) multipolygon is inside the polygon if all outer rings are inside |
| 1197 | 1199 | for (PolyData outer : mp.getOuterPolygons()) { |
| … |
… |
|
| 1220 | 1222 | * @since 15069 |
| 1221 | 1223 | */ |
| 1222 | 1224 | public static List<IPrimitive> filterInsideMultipolygon(Collection<IPrimitive> primitives, Relation multiPolygon) { |
| | 1225 | return filterInsideMultipolygon(primitives, multiPolygon, null); |
| | 1226 | } |
| | 1227 | |
| | 1228 | /** |
| | 1229 | * Find all primitives in the given collection which are inside the given multipolygon. Members of the multipolygon are |
| | 1230 | * ignored. Unclosed ways and multipolygon relations with unclosed outer rings are ignored. |
| | 1231 | * @param primitives the primitives |
| | 1232 | * @param multiPolygon the multipolygon relation |
| | 1233 | * @param cache The cache to avoid calculating joined inner/outer ways multiple times (see {@link MultipolygonBuilder#joinWays(Relation)}) |
| | 1234 | * @return a new list containing the found primitives, empty if multipolygon is invalid or nothing was found. |
| | 1235 | * @since xxx |
| | 1236 | */ |
| | 1237 | public static List<IPrimitive> filterInsideMultipolygon(Collection<IPrimitive> primitives, Relation multiPolygon, |
| | 1238 | Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> cache) { |
| 1223 | 1239 | List<IPrimitive> res = new ArrayList<>(); |
| 1224 | 1240 | if (primitives.isEmpty()) |
| 1225 | 1241 | return res; |
| 1226 | 1242 | |
| 1227 | 1243 | final Pair<List<JoinedPolygon>, List<JoinedPolygon>> outerInner; |
| 1228 | 1244 | try { |
| 1229 | | outerInner = MultipolygonBuilder.joinWays(multiPolygon); |
| | 1245 | outerInner = MultipolygonBuilder.joinWays(cache, multiPolygon); |
| 1230 | 1246 | } catch (MultipolygonBuilder.JoinedPolygonCreationException ex) { |
| 1231 | 1247 | Logging.trace(ex); |
| 1232 | 1248 | Logging.debug("Invalid multipolygon " + multiPolygon); |
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/test/unit/org/openstreetmap/josm/tools/GeometryTest.java b/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
|
a
|
b
|
|
| 367 | 367 | mp2.addMember(new RelationMember("inner", inner)); |
| 368 | 368 | mp2.put("type", "multipolygon"); |
| 369 | 369 | assertFalse(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null)); |
| 370 | | assertFalse(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2).contains(w1)); |
| | 370 | assertFalse(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2, null).contains(w1)); |
| 371 | 371 | |
| 372 | 372 | node4.setCoor(new LatLon(1.006, 0.99)); |
| 373 | 373 | // now w1 is inside |
| 374 | 374 | assertTrue(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null)); |
| 375 | | assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2).contains(w1)); |
| 376 | | assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(mp1), mp2).contains(mp1)); |
| 377 | | assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(w1)); |
| 378 | | assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(mp1)); |
| | 375 | assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2, null).contains(w1)); |
| | 376 | assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(mp1), mp2, null).contains(mp1)); |
| | 377 | assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2, null).contains(w1)); |
| | 378 | assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2, null).contains(mp1)); |
| 379 | 379 | } |
| 380 | 380 | |
| 381 | 381 | /** |