Changeset 15959 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2020-02-29T08:07:39+01:00 (5 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java
r15928 r15959 428 428 return cells; 429 429 } 430 431 /** 432 * Find ways which are crossing without sharing a node. 433 * @param w way that is to be checked 434 * @param cellSegments map with already collected way segments 435 * @param crossingWays map to collect crossing ways and related segments 436 * @param findSharedWaySegments true: find shared way segments instead of crossings 437 */ 438 public static void findIntersectingWay(Way w, Map<Point2D, List<WaySegment>> cellSegments, 439 Map<List<Way>, List<WaySegment>> crossingWays, boolean findSharedWaySegments) { 440 int nodesSize = w.getNodesCount(); 441 for (int i = 0; i < nodesSize - 1; i++) { 442 final WaySegment es1 = new WaySegment(w, i); 443 final EastNorth en1 = es1.getFirstNode().getEastNorth(); 444 final EastNorth en2 = es1.getSecondNode().getEastNorth(); 445 if (en1 == null || en2 == null) { 446 Logging.warn("Crossing ways test skipped " + es1); 447 continue; 448 } 449 for (List<WaySegment> segments : CrossingWays.getSegments(cellSegments, en1, en2)) { 450 for (WaySegment es2 : segments) { 451 452 List<WaySegment> highlight; 453 if (es2.way == w // reported by CrossingWays.SelfIntersection 454 || (findSharedWaySegments && !es1.isSimilar(es2)) 455 || (!findSharedWaySegments && !es1.intersects(es2))) 456 continue; 457 458 List<Way> prims = Arrays.asList(es1.way, es2.way); 459 if ((highlight = crossingWays.get(prims)) == null) { 460 highlight = new ArrayList<>(); 461 highlight.add(es1); 462 highlight.add(es2); 463 crossingWays.put(prims, highlight); 464 } else { 465 highlight.add(es1); 466 highlight.add(es2); 467 } 468 } 469 segments.add(es1); 470 } 471 } 472 } 473 430 474 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
r15938 r15959 44 44 import org.openstreetmap.josm.data.osm.Tag; 45 45 import org.openstreetmap.josm.data.osm.Way; 46 import org.openstreetmap.josm.data.osm.WaySegment; 46 47 import org.openstreetmap.josm.data.preferences.sources.SourceEntry; 47 48 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; … … 93 94 */ 94 95 public class MapCSSTagChecker extends Test.TagTest { 95 MapCSSTagCheckerIndex indexData; 96 final Set<OsmPrimitive> tested = new HashSet<>(); 96 private MapCSSTagCheckerIndex indexData; 97 private final Set<OsmPrimitive> tested = new HashSet<>(); 98 final Map<IPrimitive, Area> mpAreaCache = new HashMap<>(); 97 99 98 100 /** … … 202 204 @Override 203 205 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 204 final Tag tag = Tag.ofString( evaluateObject(obj, p, matchingSelector));206 final Tag tag = Tag.ofString(FixCommand.evaluateObject(obj, p, matchingSelector)); 205 207 return new ChangePropertyCommand(p, tag.getKey(), tag.getValue()); 206 208 } … … 223 225 @Override 224 226 public Command createCommand(OsmPrimitive p, Selector matchingSelector) { 225 final String key = evaluateObject(obj, p, matchingSelector);227 final String key = FixCommand.evaluateObject(obj, p, matchingSelector); 226 228 return new ChangePropertyCommand(p, key, ""); 227 229 } … … 620 622 errorBuilder = errorBuilder.fix(() -> fix); 621 623 } 624 // check if we have special information about highlighted objects */ 625 boolean hiliteFound = false; 622 626 if (env.intersections != null) { 623 627 Area is = env.intersections.get(c); 624 628 if (is != null) { 625 629 errorBuilder = errorBuilder.highlight(is); 630 hiliteFound = true; 631 } 632 } 633 if (env.crossingWaysMap != null && !hiliteFound) { 634 Map<List<Way>, List<WaySegment>> is = env.crossingWaysMap.get(c); 635 if (is != null) { 636 Set<WaySegment> toHilite = new HashSet<>(); 637 for (List<WaySegment> wsList : is.values()) { 638 toHilite.addAll(wsList); 639 } 640 errorBuilder = errorBuilder.highlightWaySegments(toHilite); 626 641 } 627 642 } … … 709 724 710 725 Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null); 726 env.mpAreaCache = mpAreaCache; 727 711 728 // the declaration indices are sorted, so it suffices to save the last used index 712 729 Declaration lastDeclUsed = null; … … 775 792 } 776 793 777 private staticCollection<TestError> getErrorsForPrimitive(OsmPrimitive p, boolean includeOtherSeverity,794 private Collection<TestError> getErrorsForPrimitive(OsmPrimitive p, boolean includeOtherSeverity, 778 795 Collection<Set<TagCheck>> checksCol) { 796 // this variant is only used by the assertion tests 779 797 final List<TestError> r = new ArrayList<>(); 780 798 final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null); 799 env.mpAreaCache = mpAreaCache; 781 800 for (Set<TagCheck> schecks : checksCol) { 782 801 for (TagCheck check : schecks) { … … 992 1011 } 993 1012 tested.clear(); 1013 mpAreaCache.clear(); 994 1014 } 995 1015 … … 1023 1043 tested.clear(); 1024 1044 } 1025 super.endTest();1026 1045 // no need to keep the index, it is quickly build and doubles the memory needs 1027 1046 indexData = null; 1047 // always clear the cache to make sure that we catch changes in geometry 1048 mpAreaCache.clear(); 1049 super.endTest(); 1028 1050 } 1029 1051 } -
trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
r15586 r15959 37 37 import org.openstreetmap.josm.tools.Geometry; 38 38 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; 39 import org.openstreetmap.josm.tools.Logging;40 39 41 40 /** … … 626 625 for (Way w: r.getMemberPrimitives(Way.class)) { 627 626 if (!w.hasIncompleteNodes()) { 628 findIntersectingWay(w, cellSegments, crossingWays, findSharedWaySegments);627 CrossingWays.findIntersectingWay(w, cellSegments, crossingWays, findSharedWaySegments); 629 628 } 630 629 } 631 630 return crossingWays; 632 }633 634 /**635 * Find ways which are crossing without sharing a node.636 * @param w way that is member of the relation637 * @param cellSegments map with already collected way segments638 * @param crossingWays map to collect crossing ways and related segments639 * @param findSharedWaySegments true: find shared way segments instead of crossings640 */641 private static void findIntersectingWay(Way w, Map<Point2D, List<WaySegment>> cellSegments,642 Map<List<Way>, List<WaySegment>> crossingWays, boolean findSharedWaySegments) {643 int nodesSize = w.getNodesCount();644 for (int i = 0; i < nodesSize - 1; i++) {645 final WaySegment es1 = new WaySegment(w, i);646 final EastNorth en1 = es1.getFirstNode().getEastNorth();647 final EastNorth en2 = es1.getSecondNode().getEastNorth();648 if (en1 == null || en2 == null) {649 Logging.warn("Crossing ways test (MP) skipped " + es1);650 continue;651 }652 for (List<WaySegment> segments : CrossingWays.getSegments(cellSegments, en1, en2)) {653 for (WaySegment es2 : segments) {654 655 List<WaySegment> highlight;656 if (es2.way == w // reported by CrossingWays.SelfIntersection657 || (findSharedWaySegments && !es1.isSimilar(es2))658 || (!findSharedWaySegments && !es1.intersects(es2)))659 continue;660 661 List<Way> prims = Arrays.asList(es1.way, es2.way);662 if ((highlight = crossingWays.get(prims)) == null) {663 highlight = new ArrayList<>();664 highlight.add(es1);665 highlight.add(es2);666 crossingWays.put(prims, highlight);667 } else {668 highlight.add(es1);669 highlight.add(es2);670 }671 }672 segments.add(es1);673 }674 }675 631 } 676 632 -
trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
r15938 r15959 3 3 4 4 import java.awt.geom.Area; 5 import java.util.HashMap;6 5 import java.util.LinkedHashSet; 6 import java.util.List; 7 7 import java.util.Map; 8 8 import java.util.Set; … … 10 10 import org.openstreetmap.josm.data.osm.IPrimitive; 11 11 import org.openstreetmap.josm.data.osm.Relation; 12 import org.openstreetmap.josm.data.osm.Way; 13 import org.openstreetmap.josm.data.osm.WaySegment; 12 14 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context; 13 15 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector; … … 72 74 73 75 /** 76 * Crossing ways result from CrossingFinder, filled for incomplete ways/relations 77 */ 78 public Map<IPrimitive, Map<List<Way>, List<WaySegment>>> crossingWaysMap; 79 80 /** 74 81 * Intersection areas (only filled with CrossingFinder if children is not null) 75 82 */ 76 83 public Map<IPrimitive, Area> intersections; 84 85 /** 86 * Cache for multipolygon areas, can be null, used with CrossingFinder 87 */ 88 public Map<IPrimitive, Area> mpAreaCache; 77 89 78 90 /** … … 126 138 this.context = other.getContext(); 127 139 this.children = other.children == null ? null : new LinkedHashSet<>(other.children); 128 this.intersections = other.intersections == null ? null : new HashMap<>(other.intersections); 140 this.intersections = other.intersections; 141 this.crossingWaysMap = other.crossingWaysMap; 142 this.mpAreaCache = other.mpAreaCache; 129 143 } 130 144 … … 294 308 children = null; 295 309 intersections = null; 310 crossingWaysMap = null; 296 311 } 297 312 -
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
r15938 r15959 5 5 6 6 import java.awt.geom.Area; 7 import java.awt.geom.Point2D; 7 8 import java.text.MessageFormat; 8 9 import java.util.ArrayList; … … 12 13 import java.util.LinkedHashSet; 13 14 import java.util.List; 15 import java.util.Map; 14 16 import java.util.Objects; 15 17 import java.util.function.IntFunction; … … 26 28 import org.openstreetmap.josm.data.osm.OsmUtils; 27 29 import org.openstreetmap.josm.data.osm.Relation; 30 import org.openstreetmap.josm.data.osm.Way; 31 import org.openstreetmap.josm.data.osm.WaySegment; 28 32 import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor; 29 33 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache; 34 import org.openstreetmap.josm.data.validation.tests.CrossingWays; 30 35 import org.openstreetmap.josm.gui.mappaint.Environment; 31 36 import org.openstreetmap.josm.gui.mappaint.Range; … … 303 308 private final String layer; 304 309 private Area area; 310 /** Will contain all way segments, grouped by cells */ 311 Map<Point2D, List<WaySegment>> cellSegments; 305 312 306 313 private CrossingFinder(Environment e) { 307 314 super(e); 308 CheckParameterUtil.ensureThat( e.osm instanceof IWay, "Only ways are supported");315 CheckParameterUtil.ensureThat(isArea(e.osm), "Only areas are supported"); 309 316 layer = OsmUtils.getLayer(e.osm); 310 317 } 311 318 312 @Override 313 public void visit(IWay<?> w) { 314 if (Objects.equals(layer, OsmUtils.getLayer(w)) 315 && left.matches(new Environment(w).withParent(e.osm)) 316 && e.osm instanceof IWay) { 317 if (area == null) { 318 area = Geometry.getAreaEastNorth(e.osm); 319 } 320 Pair<PolygonIntersection, Area> is = Geometry.polygonIntersectionResult( 321 Geometry.getAreaEastNorth(w), area, Geometry.INTERSECTION_EPS_EAST_NORTH); 322 if (Geometry.PolygonIntersection.CROSSING == is.a) { 323 addToChildren(e, w); 324 // store intersection area to improve highlight and zoom to problem 325 if (e.intersections == null) { 326 e.intersections = new HashMap<>(); 319 private Area getAreaEastNorth(IPrimitive p, Environment e) { 320 if (e.mpAreaCache != null && p.isMultipolygon()) { 321 Area a = e.mpAreaCache.get(p); 322 if (a == null) { 323 a = Geometry.getAreaEastNorth(p); 324 e.mpAreaCache.put(p, a); 325 } 326 return a; 327 } 328 return Geometry.getAreaEastNorth(p); 329 } 330 331 private Map<List<Way>, List<WaySegment>> findCrossings(IPrimitive area, 332 Map<Point2D, List<WaySegment>> cellSegments) { 333 /** The detected crossing ways */ 334 Map<List<Way>, List<WaySegment>> crossingWays = new HashMap<>(50); 335 if (area instanceof Way) { 336 CrossingWays.findIntersectingWay((Way) area, cellSegments, crossingWays, false); 337 } else if (area instanceof Relation && area.isMultipolygon()) { 338 Relation r = (Relation) area; 339 for (Way w : r.getMemberPrimitives(Way.class)) { 340 if (!w.hasIncompleteNodes()) { 341 CrossingWays.findIntersectingWay(w, cellSegments, crossingWays, false); 327 342 } 328 e.intersections.put(w, is.b); 343 } 344 } 345 return crossingWays; 346 } 347 348 @Override 349 public void visit(Collection<? extends IPrimitive> primitives) { 350 List<? extends IPrimitive> toIgnore; 351 if (e.osm instanceof Relation) { 352 toIgnore = ((IRelation<?>) e.osm).getMemberPrimitivesList(); 353 } else { 354 toIgnore = null; 355 } 356 357 for (IPrimitive p : primitives) { 358 if (isPrimitiveUsable(p) && Objects.equals(layer, OsmUtils.getLayer(p)) 359 && left.matches(new Environment(p).withParent(e.osm)) && isArea(p) 360 && (toIgnore == null || !toIgnore.contains(p))) { 361 if (area == null) { 362 area = getAreaEastNorth(e.osm, e); 363 } 364 Area otherArea = getAreaEastNorth(p, e); 365 if (area.isEmpty() || otherArea.isEmpty()) { 366 if (cellSegments == null) { 367 // lazy initialisation 368 cellSegments = new HashMap<>(); 369 findCrossings(e.osm, cellSegments); // ignore self intersections etc. here 370 } 371 // need a copy 372 final Map<Point2D, List<WaySegment>> tmpCellSegments = new HashMap<>(cellSegments); 373 // calculate all crossings between e.osm and p 374 Map<List<Way>, List<WaySegment>> crossingWays = findCrossings(p, tmpCellSegments); 375 if (!crossingWays.isEmpty()) { 376 addToChildren(e, p); 377 if (e.crossingWaysMap == null) { 378 e.crossingWaysMap = new HashMap<>(); 379 } 380 e.crossingWaysMap.put(p, crossingWays); 381 } 382 } else { 383 // we have complete data. This allows to find intersections with shared nodes 384 // See #16707 385 Pair<PolygonIntersection, Area> is = Geometry.polygonIntersectionResult( 386 otherArea, area, Geometry.INTERSECTION_EPS_EAST_NORTH); 387 if (Geometry.PolygonIntersection.CROSSING == is.a) { 388 addToChildren(e, p); 389 // store intersection area to improve highlight and zoom to problem 390 if (e.intersections == null) { 391 e.intersections = new HashMap<>(); 392 } 393 e.intersections.put(p, is.b); 394 } 395 } 329 396 } 330 397 } … … 453 520 return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null; 454 521 455 } else if (ChildOrParentSelectorType.CROSSING == type && e.osm instanceof IWay) {522 } else if (ChildOrParentSelectorType.CROSSING == type) { 456 523 e.parent = e.osm; 457 if (right instanceof OptimizedGeneralSelector 458 && e.osm.getDataSet() != null 459 && ((OptimizedGeneralSelector) right).matchesBase(OsmPrimitiveType.WAY)) { 524 if (e.osm.getDataSet() != null && isArea(e.osm)) { 460 525 final CrossingFinder crossingFinder = new CrossingFinder(e); 461 crossingFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox())); 526 visitBBox(e, crossingFinder); 527 return e.children != null; 462 528 } 463 529 return e.children != null; -
trunk/src/org/openstreetmap/josm/tools/Geometry.java
r15942 r15959 562 562 return Geometry.getArea(((Way) p).getNodes()); 563 563 } 564 if (p instanceof Relation && p.isMultipolygon() && !p.isIncomplete() 565 && !((Relation) p).hasIncompleteMembers()) { 564 if (p instanceof Relation && p.isMultipolygon() && !p.isIncomplete()) { 566 565 Multipolygon mp = MultipolygonCache.getInstance().get((Relation) p); 567 Path2D path = new Path2D.Double(); 568 path.setWindingRule(Path2D.WIND_EVEN_ODD); 569 for (PolyData pd : mp.getCombinedPolygons()) { 570 path.append(pd.get(), false); 571 } 572 return new Area(path); 566 if (mp.getOpenEnds().isEmpty()) { 567 Path2D path = new Path2D.Double(); 568 path.setWindingRule(Path2D.WIND_EVEN_ODD); 569 for (PolyData pd : mp.getCombinedPolygons()) { 570 path.append(pd.get(), false); 571 } 572 return new Area(path); 573 } 573 574 } 574 575 return new Area();
Note:
See TracChangeset
for help on using the changeset viewer.