Ticket #13165: 13165_v1.patch
File 13165_v1.patch, 14.7 KB (added by , 7 years ago) |
---|
-
src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.validation.tests; 3 3 4 import static org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker.FixCommand.evaluateObject; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 6 7 import java.io.BufferedReader; … … 575 576 final String description1 = group == null ? description : group; 576 577 final String description2 = group == null ? null : description; 577 578 final List<OsmPrimitive> primitives; 579 final Collection<OsmPrimitive> hilite; 578 580 if (env.child != null) { 579 581 primitives = Arrays.asList(p, env.child); 580 582 } else { 581 583 primitives = Collections.singletonList(p); 582 584 } 585 hilite = env.hilite != null && !env.hilite.isEmpty() ? env.hilite : primitives; 586 583 587 final TestError.Builder error = TestError.builder(tester, getSeverity(), 3000) 584 588 .messageWithManuallyTranslatedDescription(description1, description2, matchingSelector.toString()) 585 .primitives(primitives); 589 .primitives(primitives) 590 .highlight(hilite); 591 586 592 if (fix != null) { 587 593 return error.fix(() -> fix).build(); 588 594 } else { -
src/org/openstreetmap/josm/gui/mappaint/Environment.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.gui.mappaint; 3 3 4 import java.util.Collection; 5 4 6 import org.openstreetmap.josm.data.osm.OsmPrimitive; 5 7 import org.openstreetmap.josm.data.osm.Relation; 6 8 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context; … … 21 23 public StyleSource source; 22 24 private Context context = Context.PRIMITIVE; 23 25 public static final String DEFAULT_LAYER = "default"; 26 public Collection<OsmPrimitive> hilite; 24 27 25 28 /** 26 29 * If not null, this is the matching parent object if a condition or an expression … … 90 93 this.index = other.index; 91 94 this.count = other.count; 92 95 this.context = other.getContext(); 96 this.hilite = other.hilite; 93 97 } 94 98 95 99 /** … … 243 247 child = null; 244 248 index = null; 245 249 count = null; 250 hilite = null; 246 251 } 247 252 248 253 public Cascade getCascade(String layer) { -
src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
3 3 4 4 import static org.openstreetmap.josm.data.projection.Ellipsoid.WGS84; 5 5 6 import java.awt.geom.Area; 7 import java.util.ArrayList; 6 8 import java.util.Collection; 7 9 import java.util.Collections; 10 import java.util.HashSet; 8 11 import java.util.List; 9 12 import java.util.NoSuchElementException; 13 import java.util.Set; 10 14 import java.util.function.IntFunction; 11 15 import java.util.function.IntSupplier; 12 import java.util.Set;13 16 import java.util.regex.PatternSyntaxException; 14 17 15 18 import org.openstreetmap.josm.Main; … … 16 19 import org.openstreetmap.josm.data.osm.Node; 17 20 import org.openstreetmap.josm.data.osm.OsmPrimitive; 18 21 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 22 import org.openstreetmap.josm.data.osm.PrimitiveId; 19 23 import org.openstreetmap.josm.data.osm.Relation; 20 24 import org.openstreetmap.josm.data.osm.RelationMember; 21 25 import org.openstreetmap.josm.data.osm.Way; 22 26 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor; 27 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon; 28 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData; 23 29 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache; 24 30 import org.openstreetmap.josm.gui.mappaint.Environment; 25 31 import org.openstreetmap.josm.gui.mappaint.Range; … … 26 32 import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.OpenEndPseudoClassCondition; 27 33 import org.openstreetmap.josm.tools.CheckParameterUtil; 28 34 import org.openstreetmap.josm.tools.Geometry; 35 import org.openstreetmap.josm.tools.Geometry.PolygonIntersection; 29 36 import org.openstreetmap.josm.tools.Pair; 30 37 import org.openstreetmap.josm.tools.SubclassFilteredCollection; 31 38 import org.openstreetmap.josm.tools.Utils; … … 242 249 } 243 250 244 251 private final class CrossingFinder extends AbstractFinder { 252 HashSet<PrimitiveId> checkedPrimitives = new HashSet<>(); 253 245 254 private CrossingFinder(Environment e) { 246 255 super(e); 247 256 CheckParameterUtil.ensureThat(e.osm instanceof Way, "Only ways are supported"); 248 257 } 249 258 259 /** 260 * Check two areas for intersection, if found, find elements to highlight 261 * @param a1 1st area 262 * @param a2 2nd area 263 * @param p2 primitive that is or contains area a2 264 */ 265 void checkIntersection(Area a1, Area a2, OsmPrimitive p2) { 266 PolygonIntersection is = Geometry.polygonIntersection(a1, a2); 267 if (is == PolygonIntersection.CROSSING) { 268 e.child = p2; 269 } 270 } 271 250 272 @Override 251 273 public void visit(Way w) { 252 274 if (e.child == null && left.matches(new Environment(w).withParent(e.osm))) { 253 if (e.osm instanceof Way && Geometry.PolygonIntersection.CROSSING.equals( 254 Geometry.polygonIntersection(w.getNodes(), ((Way) e.osm).getNodes()))) { 255 e.child = w; 275 // check way-way intersection 276 Area a = Geometry.getArea(w.getNodes()); 277 Area b = Geometry.getArea(((Way) e.osm).getNodes()); 278 checkIntersection(a, b, w); 279 return; 280 } 281 if (e.parent.isMultipolygon()) { 282 // check mp-way intersection 283 if (e.child == null && left.matches(new Environment(w).withParent(e.parent))) { 284 if (checkedPrimitives.contains(w)) 285 return; 286 checkedPrimitives.add(w); 287 for (OsmPrimitive p : w.getReferrers()) { 288 if (p == e.parent) 289 return; 290 } 291 Multipolygon polygon = MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) e.parent); 292 if (polygon == null) 293 return; 294 Area a1 = Geometry.getArea(w.getNodes()); 295 for (PolyData pd : polygon.getCombinedPolygons()) { 296 Area a2 = new Area(pd.get()); 297 checkIntersection(a1, a2, w); 298 if (e.child != null) { 299 if (e.hilite == null) { 300 Set<OsmPrimitive> hilite = new HashSet<>(); 301 hilite.add(w); 302 hilite.addAll(getMpWays(e.parent, pd)); 303 e.hilite = new ArrayList<>(hilite); 304 } 305 return; 306 } 307 } 256 308 } 309 if (e.child == null) { 310 // is way member of a matching mp relation ? 311 for (OsmPrimitive otherParent : w.getReferrers()) { 312 if (otherParent.isMultipolygon() && !otherParent.isIncomplete() && e.parent != otherParent) { 313 if (((Relation) otherParent).hasIncompleteMembers()) 314 continue; 315 if (left.matches(new Environment(otherParent).withParent(otherParent))) { 316 if (checkedPrimitives.contains(otherParent)) 317 continue; 318 checkedPrimitives.add(otherParent); 319 // okay, we have two different complete multipolygons, check if they are overlapping 320 Multipolygon p1 = MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) e.parent); 321 if (p1 == null) 322 continue; 323 Multipolygon p2 = MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) otherParent); 324 if (p2 == null) 325 continue; 326 for (PolyData pd1 : p1.getCombinedPolygons()) { 327 Area a1 = new Area(pd1.get()); 328 for (PolyData pd2 : p2.getCombinedPolygons()) { 329 Area a2 = new Area(pd2.get()); 330 checkIntersection(a1, a2, otherParent); 331 if (e.child != null) { 332 if (e.hilite == null) { 333 Set<OsmPrimitive> hilite = new HashSet<>(); 334 hilite.addAll(getMpWays(e.parent, pd1)); 335 hilite.addAll(getMpWays(otherParent, pd2)); 336 e.hilite = new ArrayList<>(hilite); 337 } 338 return; 339 } 340 } 341 } 342 } 343 } 344 } 345 } 346 } else { 347 // check way-mp intersection 348 for (OsmPrimitive otherParent : w.getReferrers()) { 349 if (otherParent.isMultipolygon() && ((Relation) otherParent).hasIncompleteMembers() == false) { 350 if (left.matches(new Environment(otherParent).withParent(otherParent))) { 351 checkedPrimitives.add(otherParent); 352 if (e.parent == otherParent || ((Relation) otherParent).hasIncompleteMembers()) 353 return; 354 // we have a matching way that might cross a multipolygon, check if they are overlapping 355 Area a1 = Geometry.getArea(((Way) e.osm).getNodes()); 356 357 Multipolygon p2 = MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) otherParent); 358 if (p2 == null) 359 return; 360 for (PolyData pd2 : p2.getCombinedPolygons()) { 361 Area a2 = new Area(pd2.get()); 362 checkIntersection(a1, a2, otherParent); 363 if (e.child != null) { 364 if (e.hilite == null) { 365 Set<OsmPrimitive> hilite = new HashSet<>(); 366 hilite.add(e.osm); 367 hilite.addAll(getMpWays(otherParent, pd2)); 368 e.hilite = new ArrayList<>(hilite); 369 } 370 return; 371 } 372 } 373 } 374 } 375 } 257 376 } 258 377 } 378 379 private Collection<? extends OsmPrimitive> getMpWays(OsmPrimitive mpRelation, PolyData pd) { 380 List<OsmPrimitive> ways = new ArrayList<>(); 381 for (Long id : pd.getWayIds()) { 382 ways.add(mpRelation.getDataSet().getPrimitiveById(id, OsmPrimitiveType.WAY)); 383 } 384 return ways; 385 } 259 386 } 260 387 261 388 private class ContainsFinder extends AbstractFinder { … … 350 477 crossingFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox())); 351 478 } 352 479 return e.child != null; 480 } else if (ChildOrParentSelectorType.CROSSING.equals(type) && e.osm.isMultipolygon()) { 481 Relation r = (Relation) e.osm; 482 if (r.hasIncompleteMembers()) 483 return false; 484 List<RelationMember> members = r.getMembers(); 485 for (int i = 0; i < members.size(); i++) { 486 OsmPrimitive member = members.get(i).getMember(); 487 if (member instanceof Way) { 488 Environment ew = new Environment(member); 489 ew.parent = e.osm; 490 final CrossingFinder crossingFinder = new CrossingFinder(ew); 491 if (right instanceof OptimizedGeneralSelector 492 && ((OptimizedGeneralSelector) right).matchesBase(OsmPrimitiveType.WAY)) { 493 List<Way> nearWays = ew.osm.getDataSet().searchWays(ew.osm.getBBox()); 494 crossingFinder.visit(nearWays); 495 if (ew.child != null) { 496 e.child = ew.child; 497 e.hilite = ew.hilite; 498 return true; 499 } 500 } 501 } 502 } 503 return e.child != null; 353 504 } else if (ChildOrParentSelectorType.SIBLING.equals(type)) { 354 505 if (e.osm instanceof Node) { 355 506 for (Way w : Utils.filteredCollection(e.osm.getReferrers(true), Way.class)) {