Ticket #20716: josm_20716_power_v8.patch
File josm_20716_power_v8.patch, 31.3 KB (added by , 3 years ago) |
---|
-
src/org/openstreetmap/josm/data/osm/Node.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/osm/Node.java b/src/org/openstreetmap/josm/data/osm/Node.java
a b 232 232 * Merges the technical and semantical attributes from <code>other</code> onto this. 233 233 * 234 234 * Both this and other must be new, or both must be assigned an OSM ID. If both this and <code>other</code> 235 * have an assig end OSM id, the IDs have to be the same.235 * have an assigned OSM id, the IDs have to be the same. 236 236 * 237 237 * @param other the other primitive. Must not be null. 238 238 * @throws IllegalArgumentException if other is null. -
src/org/openstreetmap/josm/data/osm/TagMap.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/osm/TagMap.java b/src/org/openstreetmap/josm/data/osm/TagMap.java
a b 40 40 */ 41 41 private final String[] tags; 42 42 /** 43 * Current tag index. Always amultiple of 2.43 * Current tag index. Always multiple of 2. 44 44 */ 45 45 private int currentIndex; 46 46 -
src/org/openstreetmap/josm/data/osm/Way.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/osm/Way.java b/src/org/openstreetmap/josm/data/osm/Way.java
a b 650 650 return length; 651 651 } 652 652 653 /** 654 * Calculates the segment lengths of the way as computed by {@link LatLon#greatCircleDistance}. 655 * @return The segment lengths of a way in metres, following way direction 656 * @since xxx 657 */ 658 public double[] getSegmentLengths() { 659 double[] segmentLengths = new double[nodes.length - 1]; 660 Node prevNode = this.firstNode(); 661 662 for (int i = 1; i < nodes.length; i++) { 663 Node n = nodes[i]; 664 665 double distance = n.getCoor().greatCircleDistance(prevNode.getCoor()); 666 segmentLengths[i - 1] = distance; 667 prevNode = n; 668 } 669 670 return segmentLengths; 671 } 672 653 673 /** 654 674 * Replies the length of the longest segment of the way, in metres, as computed by {@link LatLon#greatCircleDistance}. 655 675 * @return The length of the segment, in metres -
src/org/openstreetmap/josm/data/validation/tests/PowerLines.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/tests/PowerLines.java b/src/org/openstreetmap/josm/data/validation/tests/PowerLines.java
a b 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.gui.MainApplication.getLayerManager; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 6 7 import java.util.ArrayList; 7 8 import java.util.Arrays; 8 9 import java.util.Collection; 9 import java.util.LinkedHashSet; 10 import java.util.Collections; 11 import java.util.HashSet; 10 12 import java.util.List; 11 13 import java.util.Set; 12 14 15 import org.openstreetmap.josm.data.coor.EastNorth; 13 16 import org.openstreetmap.josm.data.osm.Node; 14 17 import org.openstreetmap.josm.data.osm.OsmPrimitive; 15 18 import org.openstreetmap.josm.data.osm.Relation; 16 19 import org.openstreetmap.josm.data.osm.RelationMember; 17 20 import org.openstreetmap.josm.data.osm.Way; 21 import org.openstreetmap.josm.data.osm.WaySegment; 18 22 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon; 19 23 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay; 20 24 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache; 25 import org.openstreetmap.josm.data.preferences.CachingProperty; 26 import org.openstreetmap.josm.data.preferences.DoubleProperty; 27 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper; 21 28 import org.openstreetmap.josm.data.validation.Severity; 22 29 import org.openstreetmap.josm.data.validation.Test; 23 30 import org.openstreetmap.josm.data.validation.TestError; 24 31 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 25 32 import org.openstreetmap.josm.tools.Geometry; 33 import org.openstreetmap.josm.tools.Logging; 34 import org.openstreetmap.josm.tools.Pair; 26 35 27 36 /** 28 * Checks for nodes in power lines/minor_lines that do not have a power=tower/pole tag.<br> 29 * See #7812 for discussions about this test. 37 * Checks for 38 * <ul> 39 * <li>nodes in power lines/minor_lines that do not have a power=tower/pole/portal tag 40 * <li>nodes where the reference numbering not consistent 41 * <li>ways where are unusually long segments without line support feature 42 * <li>ways where the line type is possibly misused 43 * </ul> 44 * See #7812 and #20716 for discussions about this test. 30 45 */ 31 46 public class PowerLines extends Test { 32 47 33 / ** Test identifier */34 protected static final int POWER_ LINES= 2501;48 // Test identifiers 49 protected static final int POWER_SUPPORT = 2501; 35 50 protected static final int POWER_CONNECTION = 2502; 51 protected static final int POWER_SEGMENT_LENGTH = 2503; 52 protected static final int POWER_LOCAL_REF_CONTINUITY = 2504; 53 protected static final int POWER_WAY_REF_CONTINUITY = 2505; 54 protected static final int POWER_LINE_TYPE = 2506; 55 56 protected static final CachingProperty<Double> HILLY_COMPENSATION = new DoubleProperty( 57 ValidatorPrefHelper.PREFIX + ".powerlines.hilly_compensation", 58 0.2).cached(); 59 protected static final CachingProperty<Double> HILLY_THRESHOLD = new DoubleProperty( 60 ValidatorPrefHelper.PREFIX + ".powerlines.hilly_threshold", 61 4.0).cached(); 36 62 37 63 /** Values for {@code power} key interpreted as power lines */ 38 64 static final Collection<String> POWER_LINE_TAGS = Arrays.asList("line", "minor_line"); 39 65 /** Values for {@code power} key interpreted as power towers */ 40 static final Collection<String> POWER_TOWER_TAGS = Arrays.asList(" tower", "pole");66 static final Collection<String> POWER_TOWER_TAGS = Arrays.asList("catenary_mast", "pole", "portal", "tower"); 41 67 /** Values for {@code power} key interpreted as power stations */ 42 static final Collection<String> POWER_STATION_TAGS = Arrays.asList(" station", "sub_station", "substation", "plant", "generator");68 static final Collection<String> POWER_STATION_TAGS = Arrays.asList("generator", "plant", "substation"); 43 69 /** Values for {@code building} key interpreted as power stations */ 44 70 static final Collection<String> BUILDING_STATION_TAGS = Arrays.asList("transformer_tower"); 45 71 /** Values for {@code power} key interpreted as allowed power items */ 46 static final Collection<String> POWER_ ALLOWED_TAGS = Arrays.asList("switch", "transformer", "busbar", "generator", "switchgear",47 " portal", "terminal", "insulator");72 static final Collection<String> POWER_INFRASTRUCTURE_TAGS = Arrays.asList("compensator", "converter", 73 "generator", "insulator", "switch", "switchgear", "terminal", "transformer"); 48 74 49 private final Set<Node> badConnections = new LinkedHashSet<>(); 50 private final Set<Node> missingTowerOrPole = new LinkedHashSet<>(); 75 private final Set<Node> badConnections = new HashSet<>(); 76 private final Set<Node> missingTags = new HashSet<>(); 77 private final Set<Way> wrongLineType = new HashSet<>(); 78 private final Set<OsmPrimitive> refDiscontinuities = new HashSet<>(); 79 private final List<Set<Node>> segmentRefDiscontinuities = new ArrayList<>(); 80 private final Set<WaySegment> missingNodes = new HashSet<>(); 51 81 52 82 private final List<OsmPrimitive> powerStations = new ArrayList<>(); 53 83 84 private final Collection<Way> datasetWaterways = new HashSet<>(64); 85 54 86 /** 55 87 * Constructs a new {@code PowerLines} test. 56 88 */ 57 89 public PowerLines() { 58 super(tr("Power lines"), tr("Checks for nodes in power lines that do not have a power=tower/pole tag.")); 59 } 60 61 @Override 62 public void visit(Way w) { 63 if (w.isUsable()) { 64 if (isPowerLine(w) && !w.hasTag("location", "underground")) { 65 for (Node n : w.getNodes()) { 66 if (!isPowerTower(n) && !isPowerAllowed(n) && IN_DOWNLOADED_AREA.test(n) 67 && (!w.isFirstLastNode(n) || !isPowerStation(n))) { 68 missingTowerOrPole.add(n); 69 } 70 } 71 } else if (w.isClosed() && isPowerStation(w)) { 72 powerStations.add(w); 73 } 74 } 90 super(tr("Power lines"), tr("Checks if power line missing a support node and " + 91 "for nodes in power lines that do not have a power=tower/pole tag")); 92 } 93 94 /** 95 * Power line support features ref=* numbering direction. 96 */ 97 private enum NumberingDirection { 98 /** No direction */ 99 NONE, 100 /** Numbering follows way direction */ 101 SAME, 102 /** Numbering goes opposite way direction */ 103 OPPOSITE 75 104 } 76 105 77 106 @Override … … 89 118 badConnections.add(n); 90 119 } 91 120 92 private static boolean isRelatedToPower(Way way) { 93 if (way.hasTag("power") || way.hasTag("building")) 94 return true; 95 for (OsmPrimitive ref : way.getReferrers()) { 96 if (ref instanceof Relation && ref.isMultipolygon() && (ref.hasTag("power") || ref.hasTag("building"))) { 97 for (RelationMember rm : ((Relation) ref).getMembers()) { 98 if (way == rm.getMember()) 99 return true; 121 @Override 122 public void visit(Way w) { 123 if (!isPrimitiveUsable(w)) return; 124 125 if (isPowerLine(w) && !w.hasKey("line") && !w.hasTag("location", "underground")) { 126 final int segmentCount = w.getNodesCount() - 1; 127 final double mean = w.getLength() / segmentCount; 128 final double stdDev = calculateStdDev(w.getSegmentLengths(), mean); 129 int poleCount = 0; 130 int towerCount = 0; 131 Node prevNode = w.firstNode(); 132 133 double baseThreshold = w.hasTag("power", "line") ? 1.6 : 1.8; 134 if (mean / stdDev < HILLY_THRESHOLD.get()) { 135 //compensate for possibly hilly areas where towers can't be put anywhere 136 baseThreshold += HILLY_COMPENSATION.get(); 137 } 138 139 for (int i = 1; i < w.getRealNodesCount(); i++) { 140 final Node n = w.getNode(i); 141 142 /// handle power station line connections (eg. power=line + line=*) 143 if (isConnectedToStationLine(n, w)) { 144 prevNode = n; 145 continue; // skip, it would be false positive 100 146 } 147 148 /// handle missing power line support tags (e.g. tower) 149 if (!isPowerTower(n) && !isPowerInfrastructure(n) && IN_DOWNLOADED_AREA.test(n) 150 && (!w.isFirstLastNode(n) || !isPowerStation(n))) 151 missingTags.add(n); 152 153 /// handle missing nodes 154 double segmentLen = n.getCoor().greatCircleDistance(prevNode.getCoor()); 155 final Pair<Node, Node> pair = Pair.create(prevNode, n); 156 final Set<Way> crossingWaterWays = new HashSet<>(8); 157 final Set<Node> crossingPositions = new HashSet<>(); 158 findCrossings(datasetWaterways, w, pair, crossingWaterWays, crossingPositions); 159 160 if (!crossingWaterWays.isEmpty()) { 161 double compensation = calculateIntersectingLen(prevNode, crossingPositions); 162 segmentLen -= compensation; 163 } 164 165 if (segmentCount > 4 166 && segmentLen > mean * baseThreshold 167 && !isPowerInfrastructure(n) 168 && IN_DOWNLOADED_AREA.test(n)) 169 missingNodes.add(WaySegment.forNodePair(w, prevNode, n)); 170 171 /// handle wrong line types 172 if (n.hasTag("power", "pole")) 173 poleCount++; 174 else if (n.hasTag("power", "tower", "portal")) 175 towerCount++; 176 177 prevNode = n; 101 178 } 179 180 /// handle ref=* numbering discontinuities 181 if (detectDiscontinuity(w, refDiscontinuities, segmentRefDiscontinuities)) 182 refDiscontinuities.add(w); 183 184 /// handle wrong line types 185 if ((poleCount > towerCount && w.hasTag("power", "line")) || 186 (poleCount < towerCount && w.hasTag("power", "minor_line"))) 187 wrongLineType.add(w); 188 189 } else if (w.isClosed() && isPowerStation(w)) { 190 powerStations.add(w); 102 191 } 103 return false;104 192 } 105 193 106 194 @Override … … 113 201 @Override 114 202 public void startTest(ProgressMonitor progressMonitor) { 115 203 super.startTest(progressMonitor); 116 clearCollections(); 204 // the test run can take a bit of time, show detailed progress 205 setShowElements(true); 206 207 // collect all waterways 208 getLayerManager() 209 .getActiveDataSet() 210 .getWays() 211 .parallelStream() 212 .filter(way -> 213 way.hasTag("water", "river", "lake") || 214 way.hasKey("waterway") || 215 way.hasTag("natural", "coastline") || 216 way.referrers(Relation.class) 217 .anyMatch(relation -> 218 relation.hasTag("water", "river", "lake") || 219 relation.hasKey("waterway") || 220 relation.hasTag("natural", "coastline") 221 )) 222 .forEach(datasetWaterways::add); 117 223 } 118 224 119 225 @Override 120 226 public void endTest() { 121 for (Node n : missingT owerOrPole) {227 for (Node n : missingTags) { 122 228 if (!isInPowerStation(n)) { 123 errors.add(TestError.builder(this, Severity.WARNING, POWER_LINES) 124 .message(tr("Missing power tower/pole within power line")) 229 errors.add(TestError.builder(this, Severity.WARNING, POWER_SUPPORT) 230 // the "missing tag" grouping can become broken if the MapCSS message get reworded 231 .message(tr("missing tag"), tr("node without power=*")) 125 232 .primitives(n) 126 233 .build()); 127 234 } … … 130 237 for (Node n : badConnections) { 131 238 errors.add(TestError.builder(this, Severity.WARNING, POWER_CONNECTION) 132 239 .message(tr("Node connects a power line or cable with an object " 133 + "which is not related to the power infrastructure.")) 134 .primitives(n).build()); 240 + "which is not related to the power infrastructure")) 241 .primitives(n) 242 .build()); 243 } 244 245 for (WaySegment s : missingNodes) { 246 errors.add(TestError.builder(this, Severity.WARNING, POWER_SEGMENT_LENGTH) 247 .message(tr("Possibly missing line support node within power line")) 248 .primitives(s.getFirstNode(), s.getSecondNode()) 249 .highlightWaySegments(new HashSet<>(Collections.singleton(s))) 250 .build()); 135 251 } 136 clearCollections(); 252 253 for (OsmPrimitive p : refDiscontinuities) { 254 if (p instanceof Way) 255 errors.add(TestError.builder(this, Severity.WARNING, POWER_WAY_REF_CONTINUITY) 256 .message(tr("Mixed reference numbering")) 257 .primitives(p) 258 .build()); 259 } 260 261 final String discontinuityMsg = tr("Reference numbering don''t match majority of way''s nodes"); 262 263 for (OsmPrimitive p : refDiscontinuities) { 264 if (p instanceof Node) 265 errors.add(TestError.builder(this, Severity.WARNING, POWER_LOCAL_REF_CONTINUITY) 266 .message(discontinuityMsg) 267 .primitives(p) 268 .build()); 269 } 270 271 for (Set<Node> nodes : segmentRefDiscontinuities) { 272 errors.add(TestError.builder(this, Severity.WARNING, POWER_LOCAL_REF_CONTINUITY) 273 .message(discontinuityMsg) 274 .primitives(nodes) 275 .build()); 276 } 277 278 for (Way w : wrongLineType) { 279 errors.add(TestError.builder(this, Severity.WARNING, POWER_LINE_TYPE) 280 .message(tr("Possibly wrong power line type used")) 281 .primitives(w) 282 .build()); 283 } 284 137 285 super.endTest(); 138 286 } 139 287 288 /** 289 * Calculates the standard deviation from the given values. 290 * @param values An array of values 291 * @param mean Precalculated average value of the array 292 * @return standard deviation of the given array 293 */ 294 protected static double calculateStdDev(double[] values, double mean) { 295 double standardDeviation = 0; 296 297 for (double length : values) { 298 standardDeviation += Math.pow(length - mean, 2); 299 } 300 301 return Math.sqrt(standardDeviation / values.length); 302 } 303 304 /** 305 * The summarized length (in metres) of a way where a power line hangs over a water area. 306 * @param ref Reference point 307 * @param crossingNodes Crossing nodes, unordered 308 * @return The summarized length (in metres) of a way where a power line hangs over a water area 309 */ 310 private static double calculateIntersectingLen(Node ref, Set<Node> crossingNodes) { 311 double min = Double.POSITIVE_INFINITY; 312 double max = Double.NEGATIVE_INFINITY; 313 314 for (Node n : crossingNodes) { 315 double dist = ref.getCoor().greatCircleDistance(n.getCoor()); 316 317 if (dist < min) 318 min = dist; 319 if (dist > max) 320 max = dist; 321 } 322 return max - min; 323 } 324 325 /** 326 * Searches for way intersections, which intersect the {@code pair} attribute. 327 * @param ways collection of ways to search 328 * @param parent parent way for {@code pair} param 329 * @param pair {@link Node} pair among which search for another way 330 * @param crossingWays found crossing ways 331 * @param crossingPositions collection of the crossing positions 332 * @implNote Inspired by {@code utilsplugin2/selection/NodeWayUtils.java#addWaysIntersectingWay()} 333 */ 334 private static void findCrossings(Collection<Way> ways, Way parent, Pair<Node, Node> pair, Set<Way> crossingWays, 335 Set<Node> crossingPositions) { 336 for (Way way : ways) { 337 if (way.isUsable() 338 && !crossingWays.contains(way) 339 && way.getBBox().intersects(parent.getBBox())) { 340 for (Pair<Node, Node> pair2 : way.getNodePairs(false)) { 341 EastNorth eastNorth = Geometry.getSegmentSegmentIntersection( 342 pair.a.getEastNorth(), pair.b.getEastNorth(), 343 pair2.a.getEastNorth(), pair2.b.getEastNorth()); 344 if (eastNorth != null) { 345 crossingPositions.add(new Node(eastNorth)); 346 crossingWays.add(way); 347 } 348 } 349 } 350 } 351 } 352 353 /** 354 * Helper class for reference numbering test. Used for storing continuous reference segment info. 355 */ 356 private static class SegmentInfo { 357 /** Follows ways direction */ 358 private final int firstNodeIndex; 359 private final int length; 360 private final int startingRef; 361 private final NumberingDirection direction; 362 363 SegmentInfo(int firstNodeIndex, int length, int ref, NumberingDirection direction) { 364 this.firstNodeIndex = firstNodeIndex; 365 this.length = length; 366 this.direction = direction; 367 368 if (direction == NumberingDirection.SAME) 369 this.startingRef = ref - length; 370 else 371 this.startingRef = ref + length; 372 } 373 374 @Override 375 public String toString() { 376 return String.format("SegmentInfo{firstNodeIndex=%d, length=%d, startingRef=%d, direction=%s}", 377 firstNodeIndex, length, startingRef, direction); 378 } 379 } 380 381 /** 382 * Detects ref=* numbering discontinuities in the given way. 383 * @param way checked way 384 * @param nRefDiscontinuities single node ref=* discontinuities 385 * @param sRefDiscontinuities continuous node ref=* discontinuities 386 * @return {@code true} if warning needs to be issued for the whole way 387 */ 388 static boolean detectDiscontinuity(Way way, Set<OsmPrimitive> nRefDiscontinuities, List<Set<Node>> sRefDiscontinuities) { 389 final ArrayList<SegmentInfo> segments = new RefChecker(way).getSegments(); 390 final Set<NumberingDirection> directions = new HashSet<>(4); 391 SegmentInfo referenceSegment = null; 392 int longestSegmentLen = 0; 393 int counter = 0; 394 395 // calculate longest segment 396 for (SegmentInfo segment : segments) { 397 if (segment.length > longestSegmentLen) { 398 longestSegmentLen = segment.length; 399 referenceSegment = segment; 400 directions.clear(); 401 directions.add(segment.direction); 402 counter = 0; 403 } else if (segment.length == longestSegmentLen) { 404 counter++; 405 directions.add(segment.direction); 406 } 407 } 408 409 // there are multiple segments with the same longest length and their directions don't match 410 if (counter > 0 && directions.size() > 1) 411 return true; 412 413 // if reference is null, but we have segments, select one randomly 414 if (referenceSegment == null && !segments.isEmpty()) 415 referenceSegment = segments.iterator().next(); 416 417 // collect disconnected ref segments which are not align up to the reference 418 for (SegmentInfo segment : segments) { 419 if (!isSegmentAlign(referenceSegment, segment)) { 420 if (referenceSegment.length == 0) 421 return true; 422 423 if (segment.length == 0) { 424 nRefDiscontinuities.add(way.getNode(segment.firstNodeIndex)); 425 } else { 426 final Set<Node> nodeGroup = new HashSet<>(); 427 428 for (int i = segment.firstNodeIndex; i <= segment.firstNodeIndex + segment.length; i++) { 429 nodeGroup.add(way.getNode(i)); 430 } 431 sRefDiscontinuities.add(nodeGroup); 432 } 433 } 434 } 435 436 return false; 437 } 438 439 /** 440 * Checks if parameter segments align. 441 * @param reference Reference segment to check against 442 * @param candidate Candidate segment 443 * @return {@code true} if the two segments ref=* numbering align 444 */ 445 private static boolean isSegmentAlign(SegmentInfo reference, SegmentInfo candidate) { 446 return candidate.firstNodeIndex - reference.firstNodeIndex == candidate.startingRef - reference.startingRef; 447 } 448 449 /** 450 * Detects continuous reference numbering sequences. Ignores the first and last node because 451 * ways can be connected, and the connection nodes can have different numbering. 452 * <p> 453 * If the numbering switches in the middle of the way, this can also be seen as error, 454 * because line relations would require split ways. 455 */ 456 static class RefChecker { 457 final ArrayList<SegmentInfo> segments = new ArrayList<>(); 458 459 NumberingDirection direction = NumberingDirection.NONE; 460 Integer startIndex = null; 461 Integer previousRef = null; 462 463 RefChecker(final Way way) { 464 run(way); 465 } 466 467 private void run(Way way) { 468 final int wayLength = way.getNodesCount(); 469 470 // first and last node skipped 471 for (int i = 1; i < wayLength - 1; i++) { 472 Node n = way.getNode(i); 473 maintain(parseRef(n.get("ref")), i); 474 } 475 476 // needed for creation of the last segment 477 maintain(null, wayLength - 1); 478 } 479 480 private Integer parseRef(String value) { 481 try { 482 return Integer.parseInt(value); 483 } catch (NumberFormatException ignore) { 484 Logging.trace("The PowerLines.RefChecker couldn't parse ref=" + value + ", consider rewriting the parser"); 485 return null; 486 } 487 } 488 489 /** 490 * Maintains the class variables a constructs a new segment when necessary. 491 * @param ref recognised ref=* number 492 * @param index {@link Node} index in a way 493 */ 494 private void maintain(Integer ref, int index) { 495 if (this.startIndex == null) { 496 startIndex = index; 497 } 498 499 if (ref == null) { 500 if (previousRef == null) { 501 reset(); 502 return; 503 } 504 505 segments.add(new SegmentInfo(startIndex, index - 1 - startIndex, previousRef, direction)); 506 reset(); 507 return; 508 } 509 510 if (previousRef == null) { 511 previousRef = ref; 512 return; 513 } 514 515 if (Math.abs(ref - previousRef) != 1) { 516 segments.add(new SegmentInfo(startIndex, index - 1 - startIndex, previousRef, direction)); 517 startIndex = index; 518 } 519 520 if (ref > previousRef) 521 direction = NumberingDirection.SAME; 522 else if (ref < previousRef) 523 direction = NumberingDirection.OPPOSITE; 524 525 previousRef = ref; 526 } 527 528 private void reset() { 529 this.direction = NumberingDirection.NONE; 530 this.startIndex = null; 531 this.previousRef = null; 532 } 533 534 ArrayList<SegmentInfo> getSegments() { 535 return segments; 536 } 537 } 538 539 private static boolean isRelatedToPower(Way way) { 540 if (way.hasTag("power") || way.hasTag("building")) 541 return true; 542 for (OsmPrimitive ref : way.getReferrers()) { 543 if (ref instanceof Relation && ref.isMultipolygon() && (ref.hasTag("power") || ref.hasTag("building"))) { 544 for (RelationMember rm : ((Relation) ref).getMembers()) { 545 if (way == rm.getMember()) 546 return true; 547 } 548 } 549 } 550 return false; 551 } 552 553 /** 554 * Determines if the current node connected to a line which used usually used inside power stations. 555 * @param n node to check 556 * @param w parent way of {@code n} 557 * @return {@code true} if {@code n} connected to power=line + line=* 558 */ 559 private static boolean isConnectedToStationLine(Node n, Way w) { 560 for (OsmPrimitive p : n.getReferrers()) { 561 if (p instanceof Way && !p.equals(w) && isPowerLine((Way) p) && p.hasKey("line")) 562 return true; 563 } 564 return false; 565 } 566 567 /** 568 * Checks if the given node is inside a power station. 569 * @param n Node to be checked 570 */ 140 571 protected final boolean isInPowerStation(Node n) { 141 572 for (OsmPrimitive station : powerStations) { 142 573 List<List<Node>> nodesLists = new ArrayList<>(); … … 171 602 /** 172 603 * Determines if the specified primitive denotes a power station. 173 604 * @param p The primitive to be tested 174 * @return {@code true} if power key is set and equal to station/sub_station/plant605 * @return {@code true} if power key is set and equal to generator/substation/plant 175 606 */ 176 607 protected static final boolean isPowerStation(OsmPrimitive p) { 177 608 return isPowerIn(p, POWER_STATION_TAGS) || isBuildingIn(p, BUILDING_STATION_TAGS); 178 609 } 179 610 180 611 /** 181 * Determines if the specified node denotes a power tower/pole.612 * Determines if the specified node denotes a power support feature. 182 613 * @param n The node to be tested 183 * @return {@code true} if power key is set and equal to tower/pole614 * @return {@code true} if power key is set and equal to pole/tower/portal/catenary_mast 184 615 */ 185 616 protected static final boolean isPowerTower(Node n) { 186 617 return isPowerIn(n, POWER_TOWER_TAGS); … … 189 620 /** 190 621 * Determines if the specified node denotes a power infrastructure allowed on a power line. 191 622 * @param n The node to be tested 192 * @return True if power key is set and equal to switch/tranformer/busbar/generator 623 * @return {@code true} if power key is set and equal to compensator/converter/generator/insulator 624 * /switch/switchgear/terminal/transformer 193 625 */ 194 protected static final boolean isPower Allowed(Node n) {195 return isPowerIn(n, POWER_ ALLOWED_TAGS);626 protected static final boolean isPowerInfrastructure(Node n) { 627 return isPowerIn(n, POWER_INFRASTRUCTURE_TAGS); 196 628 } 197 629 198 630 /** … … 215 647 return p.hasTag("building", values); 216 648 } 217 649 218 private void clearCollections() { 650 @Override 651 public void clear() { 652 super.clear(); 219 653 powerStations.clear(); 220 654 badConnections.clear(); 221 missingTowerOrPole.clear(); 655 missingTags.clear(); 656 missingNodes.clear(); 657 wrongLineType.clear(); 658 refDiscontinuities.clear(); 659 segmentRefDiscontinuities.clear(); 660 datasetWaterways.clear(); 222 661 } 223 662 } -
src/org/openstreetmap/josm/data/validation/Test.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/data/validation/Test.java b/src/org/openstreetmap/josm/data/validation/Test.java
a b 371 371 errors.clear(); 372 372 } 373 373 374 /** 375 * Sets the validator progress bar elements counter visibility. 376 * @param b True if element counter shown 377 */ 374 378 protected void setShowElements(boolean b) { 375 379 showElementCount = b; 376 380 }