Changeset 33108 in osm for applications/editors/josm/plugins/pt_assistant
- Timestamp:
- 2016-12-29T20:05:17+01:00 (8 years ago)
- Location:
- applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/PTAssistantValidatorTest.java
r33091 r33108 44 44 public class PTAssistantValidatorTest extends Test { 45 45 46 public static final int ERROR_CODE_SORTING = 3711; 47 public static final int ERROR_CODE_ROAD_TYPE = 3721; 48 public static final int ERROR_CODE_CONSTRUCTION = 3722; 49 public static final int ERROR_CODE_DIRECTION = 3731; 50 public static final int ERROR_CODE_END_STOP = 3741; 51 public static final int ERROR_CODE_SPLIT_WAY = 3742; 52 public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743; 53 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751; 54 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752; 55 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753; 56 public static final int ERROR_CODE_STOP_BY_STOP = 3754; 57 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761; 58 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762; 59 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763; 60 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764; 61 62 private PTAssistantLayer layer; 63 64 public PTAssistantValidatorTest() { 65 super(tr("Public Transport Assistant tests"), 66 tr("Check if route relations are compatible with public transport version 2")); 67 68 layer = PTAssistantLayer.getLayer(); 69 DataSet.addSelectionListener(layer); 70 71 } 72 73 @Override 74 public void visit(Node n) { 75 76 if (n.isIncomplete()) { 77 return; 78 } 79 80 NodeChecker nodeChecker = new NodeChecker(n, this); 81 82 // select only stop_positions 83 if (n.hasTag("public_transport", "stop_position")) { 84 85 // check if stop positions are on a way: 86 nodeChecker.performSolitaryStopPositionTest(); 87 88 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 89 // check if stop positions are in any stop_area relation: 90 nodeChecker.performNodePartOfStopAreaTest(); 91 } 92 93 } 94 95 // select only platforms 96 if (n.hasTag("public_transport", "platform")) { 97 98 // check that platforms are not part of any way: 99 nodeChecker.performPlatformPartOfWayTest(); 100 101 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 102 // check if platforms are in any stop_area relation: 103 nodeChecker.performNodePartOfStopAreaTest(); 104 } 105 106 } 107 108 this.errors.addAll(nodeChecker.getErrors()); 109 110 } 111 112 @Override 113 public void visit(Relation r) { 114 115 // Download incomplete members. If the download does not work, return 116 // and do not do any testing. 117 if (r.hasIncompleteMembers()) { 118 119 boolean downloadSuccessful = this.downloadIncompleteMembers(); 120 if (!downloadSuccessful) { 121 return; 122 } 123 } 124 125 if (r.hasIncompleteMembers()) { 126 return; 127 } 128 129 130 // Do some testing on stop area relations 131 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true && StopUtils.isStopArea(r)) { 132 133 StopChecker stopChecker = new StopChecker(r, this); 134 135 // Check if stop area relation has one stop position. 136 stopChecker.performStopAreaStopPositionTest(); 137 138 // Check if stop area relation has one platform. 139 stopChecker.performStopAreaPlatformTest(); 140 141 // Check if stop position(s) belong the same route relation as 142 // related platform(s) 143 stopChecker.performStopAreaRelationsTest(); 144 145 // Attach thrown errors 146 this.errors.addAll(stopChecker.getErrors()); 147 } 148 149 150 if (!RouteUtils.isTwoDirectionRoute(r)) { 151 return; 152 } 153 154 // Check individual ways using the oneway direction test and the road 155 // type test: 156 WayChecker wayChecker = new WayChecker(r, this); 157 wayChecker.performDirectionTest(); 158 wayChecker.performRoadTypeTest(); 159 this.errors.addAll(wayChecker.getErrors()); 160 161 proceedWithSorting(r); 162 163 // This allows to modify the route before the sorting and 164 // SegmentChecker are carried out: 165 // if (this.errors.isEmpty()) { 166 // proceedWithSorting(r); 167 // } else { 168 // this.proceedAfterWayCheckerErrors(r); 169 // } 170 171 } 172 173 /** 174 * Downloads incomplete relation members in an extra thread (user input 175 * required) 176 * 177 * @return true if successful, false if not successful 178 */ 179 private boolean downloadIncompleteMembers() { 180 181 final int[] userSelection = {0}; 182 183 try { 184 185 if (SwingUtilities.isEventDispatchThread()) { 186 187 userSelection[0] = showIncompleteMembersDownloadDialog(); 188 189 } else { 190 191 SwingUtilities.invokeAndWait(new Runnable() { 192 @Override 193 public void run() { 194 try { 195 userSelection[0] = showIncompleteMembersDownloadDialog(); 196 } catch (InterruptedException e) { 197 e.printStackTrace(); 198 } 199 200 } 201 }); 202 203 } 204 205 } catch (InterruptedException | InvocationTargetException e) { 206 return false; 207 } 208 209 if (userSelection[0] == JOptionPane.YES_OPTION) { 210 211 Thread t = new IncompleteMembersDownloadThread(); 212 t.start(); 213 synchronized (t) { 214 try { 215 t.wait(); 216 } catch (InterruptedException e) { 217 return false; 218 } 219 } 220 221 } 222 223 return true; 224 225 } 226 227 /** 228 * Shows the dialog asking the user about an incomplete member download 229 * 230 * @return user's selection 231 * @throws InterruptedException if interrupted 232 */ 233 private int showIncompleteMembersDownloadDialog() throws InterruptedException { 234 235 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) { 236 return JOptionPane.YES_OPTION; 237 } 238 239 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) { 240 return JOptionPane.NO_OPTION; 241 } 242 243 IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog(); 244 return incompleteMembersDownloadDialog.getUserSelection(); 245 246 } 247 248 /** 249 * Gets user input after errors were detected by WayChecker. Although this 250 * method is not used in the current implementation, it can be used to fix 251 * errors from the previous testing stage and modify the route before the 252 * second stage of testing is carried out. 253 */ 254 @SuppressWarnings("unused") 255 private void proceedAfterWayCheckerErrors(Relation r) { 256 257 // count errors of each type: 258 int numberOfDirectionErrors = 0; 259 int numberOfRoadTypeErrors = 0; 260 for (TestError e : this.errors) { 261 if (e.getCode() == ERROR_CODE_DIRECTION) { 262 numberOfDirectionErrors++; 263 } 264 if (e.getCode() == ERROR_CODE_ROAD_TYPE) { 265 numberOfRoadTypeErrors++; 266 } 267 } 268 269 final int[] userInput = {0}; 270 final long idParameter = r.getId(); 271 final int directionErrorParameter = numberOfDirectionErrors; 272 final int roadTypeErrorParameter = numberOfRoadTypeErrors; 273 274 if (SwingUtilities.isEventDispatchThread()) { 275 276 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 277 278 } else { 279 280 try { 281 SwingUtilities.invokeAndWait(new Runnable() { 282 @Override 283 public void run() { 284 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 285 286 } 287 }); 288 } catch (InvocationTargetException | InterruptedException e1) { 289 e1.printStackTrace(); 290 } 291 292 } 293 294 if (userInput[0] == 0) { 295 this.fixErrorFromPlugin(this.errors); 296 proceedWithSorting(r); 297 return; 298 } 299 300 if (userInput[0] == 1) { 301 JOptionPane.showMessageDialog(null, "This is not implemented yet!"); 302 return; 303 } 304 305 if (userInput[0] == 2) { 306 proceedWithSorting(r); 307 } 308 309 // if userInput==-1 (i.e. no input), do nothing and stop testing of the 310 // route. 311 312 } 313 314 private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 315 316 if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) { 317 return 2; 318 } 319 320 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) { 321 return 0; 322 } 323 324 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) { 325 return 2; 326 } 327 328 ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors); 329 return proceedDialog.getUserSelection(); 330 331 } 332 333 /** 334 * Carries out the second stage of the testing: sorting 335 * 336 * @param r relation 337 */ 338 private void proceedWithSorting(Relation r) { 339 340 // Check if the relation is correct, or only has a wrong sorting order: 341 RouteChecker routeChecker = new RouteChecker(r, this); 342 routeChecker.performSortingTest(); 343 List<TestError> routeCheckerErrors = routeChecker.getErrors(); 344 345 /*- At this point, there are 3 variants: 346 * 347 * 1) There are no errors => route is correct 348 * 2) There is only a sorting error (can only be 1), but otherwise 349 * correct. 350 * 3) There are some other errors/gaps that cannot be fixed by 351 * sorting => start further test (stop-by-stop) 352 * 353 * */ 354 355 if (!routeCheckerErrors.isEmpty()) { 356 // Variant 2 357 // If there is only the sorting error, add it 358 this.errors.addAll(routeChecker.getErrors()); 359 } 360 361 // if (!routeChecker.getHasGap()) { 362 // // Variant 1 363 // storeCorrectRouteSegments(r); 364 // } 365 366 // Variant 3: 367 proceedAfterSorting(r); 368 369 } 370 371 /** 372 * Carries out the stop-by-stop testing which includes building the route 373 * data model. 374 * 375 * @param r route relation 376 */ 377 private void proceedAfterSorting(Relation r) { 378 379 SegmentChecker segmentChecker = new SegmentChecker(r, this); 380 381 // Check if the creation of the route data model in the segment checker 382 // worked. If it did not, it means the roles in the route relation do 383 // not match the tags of the route members. 384 if (!segmentChecker.getErrors().isEmpty()) { 385 this.errors.addAll(segmentChecker.getErrors()); 386 } 387 388 segmentChecker.performFirstStopTest(); 389 segmentChecker.performLastStopTest(); 390 segmentChecker.performStopNotServedTest(); 391 392 boolean sortingErrorFound = false; 393 for (TestError error : this.errors) { 394 if (error.getCode() == ERROR_CODE_SORTING) { 395 sortingErrorFound = true; 396 break; 397 } 398 } 399 if (!sortingErrorFound) { 400 segmentChecker.performStopByStopTest(); 401 segmentChecker.findFixes(); 402 } 403 404 for (TestError error: segmentChecker.getErrors()) { 405 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) { 406 this.errors.add(error); 407 } 408 } 409 } 410 411 /** 412 * Overrides the superclass method 413 */ 414 public void startTest() { 415 super.startTest(progressMonitor); 416 SegmentChecker.reset(); 417 } 418 419 /** 420 * Method is called after all primitives has been visited, overrides the method of the superclass. 421 */ 422 public void endTest() { 423 424 // modify the error messages for the stop-by-stop test: 425 SegmentChecker.modifyStopByStopErrorMessages(); 426 427 // add the stop-by-stop errors with modified messages: 428 for (Entry<Builder, PTRouteSegment> entry: SegmentChecker.wrongSegmentBuilders.entrySet()) { 429 TestError error = entry.getKey().build(); 430 SegmentChecker.wrongSegments.put(error, entry.getValue()); 431 this.errors.add(error); 432 } 433 434 super.endTest(); 435 436 } 437 438 /** 439 * Creates the PTRouteSegments of a route that has been found correct and 440 * stores them in the list of correct route segments 441 * 442 * @param r 443 * route relation 444 */ 445 @SuppressWarnings("unused") 446 private void storeCorrectRouteSegments(Relation r) { 447 PTRouteDataManager manager = new PTRouteDataManager(r); 448 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 449 if (manager.getPTStops().size() > 1) { 450 for (int i = 1; i < manager.getPTStops().size(); i++) { 451 PTStop segmentStartStop = manager.getPTStops().get(i - 1); 452 PTStop segmentEndStop = manager.getPTStops().get(i); 453 Way segmentStartWay = assigner.get(segmentStartStop); 454 Way segmentEndWay = assigner.get(segmentEndStop); 455 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay); 456 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r); 457 SegmentChecker.addCorrectSegment(routeSegment); 458 } 459 } 460 } 461 462 /** 463 * Checks if the test error is fixable 464 */ 465 @Override 466 public boolean isFixable(TestError testError) { 467 if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE 468 || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING 469 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 470 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 471 return true; 472 } 473 474 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) { 475 return true; 476 } 477 478 return false; 479 } 480 481 /** 482 * Fixes the given error 483 */ 484 @Override 485 public Command fixError(TestError testError) { 486 487 // repaint the relation in the pt_assistant layer: 488 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) { 489 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next(); 490 this.layer.repaint(relationToBeFixed); 491 } 492 493 // reset the last fix: 494 PTAssistantPlugin.setLastFix(null); 495 496 List<Command> commands = new ArrayList<>(); 497 498 if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) { 499 commands.add(WayChecker.fixErrorByZooming(testError)); 500 } 501 502 if (testError.getCode() == ERROR_CODE_DIRECTION) { 503 commands.add(WayChecker.fixErrorByZooming(testError)); 504 505 } 506 507 if (testError.getCode() == ERROR_CODE_SORTING) { 508 commands.add(RouteChecker.fixSortingError(testError)); 509 } 510 511 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION 512 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 513 commands.add(NodeChecker.fixError(testError)); 514 } 515 516 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) { 517 commands.add(SegmentChecker.fixError(testError)); 518 // make sure the primitives of this testError are selected: 519 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>(); 520 for (Object obj : testError.getPrimitives()) { 521 primitivesToSelect.add((OsmPrimitive) obj); 522 } 523 SelectCommand selectCommand = new SelectCommand(primitivesToSelect); 524 SwingUtilities.invokeLater(new Runnable() { 525 @Override 526 public void run() { 527 selectCommand.executeCommand(); 528 } 529 }); 530 } 531 532 if (commands.isEmpty()) { 533 return null; 534 } 535 536 if (commands.size() == 1) { 537 return commands.get(0); 538 } 539 540 return new SequenceCommand(tr("Fix error"), commands); 541 } 542 543 /** 544 * This method is the counterpart of the fixError(TestError testError) 545 * method. The fixError method is invoked from the core validator (e.g. when 546 * user presses the "Fix" button in the validator). This method is invoken 547 * when the fix is initiated from within the plugin (e.g. automated fixes). 548 */ 549 private void fixErrorFromPlugin(List<TestError> testErrors) { 550 551 // run fix task asynchronously 552 FixTask fixTask = new FixTask(testErrors); 553 554 Thread t = new Thread(fixTask); 555 t.start(); 556 try { 557 t.join(); 558 errors.removeAll(testErrors); 559 560 } catch (InterruptedException e) { 561 JOptionPane.showMessageDialog(null, "Error occurred during fixing"); 562 } 563 564 } 565 566 public void addFixVariants(List<List<PTWay>> fixVariants) { 567 layer.addFixVariants(fixVariants); 568 } 569 570 public void clearFixVariants() { 571 layer.clearFixVariants(); 572 } 573 574 public List<PTWay> getFixVariant(Character c) { 575 return layer.getFixVariant(c); 576 } 577 578 @SuppressWarnings("unused") 579 private void performDummyTest(Relation r) { 580 List<Relation> primitives = new ArrayList<>(1); 581 primitives.add(r); 582 Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION); 583 builder.message(tr("PT: dummy test warning")); 584 builder.primitives(primitives); 585 errors.add( 586 builder.build()); 587 } 46 public static final int ERROR_CODE_SORTING = 3711; 47 public static final int ERROR_CODE_ROAD_TYPE = 3721; 48 public static final int ERROR_CODE_CONSTRUCTION = 3722; 49 public static final int ERROR_CODE_DIRECTION = 3731; 50 public static final int ERROR_CODE_END_STOP = 3741; 51 public static final int ERROR_CODE_SPLIT_WAY = 3742; 52 public static final int ERROR_CODE_RELAITON_MEMBER_ROLES = 3743; 53 public static final int ERROR_CODE_SOLITARY_STOP_POSITION = 3751; 54 public static final int ERROR_CODE_PLATFORM_PART_OF_HIGHWAY = 3752; 55 public static final int ERROR_CODE_STOP_NOT_SERVED = 3753; 56 public static final int ERROR_CODE_STOP_BY_STOP = 3754; 57 public static final int ERROR_CODE_NOT_PART_OF_STOP_AREA = 3761; 58 public static final int ERROR_CODE_STOP_AREA_NO_STOPS = 3762; 59 public static final int ERROR_CODE_STOP_AREA_NO_PLATFORM = 3763; 60 public static final int ERROR_CODE_STOP_AREA_COMPARE_RELATIONS = 3764; 61 62 private PTAssistantLayer layer; 63 64 public PTAssistantValidatorTest() { 65 super(tr("Public Transport Assistant tests"), 66 tr("Check if route relations are compatible with public transport version 2")); 67 68 layer = PTAssistantLayer.getLayer(); 69 DataSet.addSelectionListener(layer); 70 71 } 72 73 @Override 74 public void visit(Node n) { 75 76 if (n.isIncomplete()) { 77 return; 78 } 79 80 NodeChecker nodeChecker = new NodeChecker(n, this); 81 82 // select only stop_positions 83 if (n.hasTag("public_transport", "stop_position")) { 84 85 // check if stop positions are on a way: 86 nodeChecker.performSolitaryStopPositionTest(); 87 88 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 89 // check if stop positions are in any stop_area relation: 90 nodeChecker.performNodePartOfStopAreaTest(); 91 } 92 93 } 94 95 // select only platforms 96 if (n.hasTag("public_transport", "platform")) { 97 98 // check that platforms are not part of any way: 99 nodeChecker.performPlatformPartOfWayTest(); 100 101 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true) { 102 // check if platforms are in any stop_area relation: 103 nodeChecker.performNodePartOfStopAreaTest(); 104 } 105 106 } 107 108 this.errors.addAll(nodeChecker.getErrors()); 109 110 } 111 112 @Override 113 public void visit(Relation r) { 114 115 // Download incomplete members. If the download does not work, return 116 // and do not do any testing. 117 if (r.hasIncompleteMembers()) { 118 119 boolean downloadSuccessful = this.downloadIncompleteMembers(); 120 if (!downloadSuccessful) { 121 return; 122 } 123 } 124 125 if (r.hasIncompleteMembers()) { 126 return; 127 } 128 129 // Do some testing on stop area relations 130 if (Main.pref.getBoolean("pt_assistant.stop-area-tests", true) == true && StopUtils.isStopArea(r)) { 131 132 StopChecker stopChecker = new StopChecker(r, this); 133 134 // Check if stop area relation has one stop position. 135 stopChecker.performStopAreaStopPositionTest(); 136 137 // Check if stop area relation has one platform. 138 stopChecker.performStopAreaPlatformTest(); 139 140 // Check if stop position(s) belong the same route relation as 141 // related platform(s) 142 stopChecker.performStopAreaRelationsTest(); 143 144 // Attach thrown errors 145 this.errors.addAll(stopChecker.getErrors()); 146 } 147 148 if (!RouteUtils.isTwoDirectionRoute(r)) { 149 return; 150 } 151 152 // Check individual ways using the oneway direction test and the road 153 // type test: 154 WayChecker wayChecker = new WayChecker(r, this); 155 wayChecker.performDirectionTest(); 156 wayChecker.performRoadTypeTest(); 157 this.errors.addAll(wayChecker.getErrors()); 158 159 proceedWithSorting(r); 160 161 // This allows to modify the route before the sorting and 162 // SegmentChecker are carried out: 163 // if (this.errors.isEmpty()) { 164 // proceedWithSorting(r); 165 // } else { 166 // this.proceedAfterWayCheckerErrors(r); 167 // } 168 169 } 170 171 /** 172 * Downloads incomplete relation members in an extra thread (user input 173 * required) 174 * 175 * @return true if successful, false if not successful 176 */ 177 private boolean downloadIncompleteMembers() { 178 179 final int[] userSelection = { 0 }; 180 181 try { 182 183 if (SwingUtilities.isEventDispatchThread()) { 184 185 userSelection[0] = showIncompleteMembersDownloadDialog(); 186 187 } else { 188 189 SwingUtilities.invokeAndWait(new Runnable() { 190 @Override 191 public void run() { 192 try { 193 userSelection[0] = showIncompleteMembersDownloadDialog(); 194 } catch (InterruptedException e) { 195 e.printStackTrace(); 196 } 197 198 } 199 }); 200 201 } 202 203 } catch (InterruptedException | InvocationTargetException e) { 204 return false; 205 } 206 207 if (userSelection[0] == JOptionPane.YES_OPTION) { 208 209 Thread t = new IncompleteMembersDownloadThread(); 210 t.start(); 211 synchronized (t) { 212 try { 213 t.wait(); 214 } catch (InterruptedException e) { 215 return false; 216 } 217 } 218 219 } 220 221 return true; 222 223 } 224 225 /** 226 * Shows the dialog asking the user about an incomplete member download 227 * 228 * @return user's selection 229 * @throws InterruptedException 230 * if interrupted 231 */ 232 private int showIncompleteMembersDownloadDialog() throws InterruptedException { 233 234 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == true) { 235 return JOptionPane.YES_OPTION; 236 } 237 238 if (Main.pref.getBoolean("pt_assistant.download-incomplete", false) == false) { 239 return JOptionPane.NO_OPTION; 240 } 241 242 IncompleteMembersDownloadDialog incompleteMembersDownloadDialog = new IncompleteMembersDownloadDialog(); 243 return incompleteMembersDownloadDialog.getUserSelection(); 244 245 } 246 247 /** 248 * Gets user input after errors were detected by WayChecker. Although this 249 * method is not used in the current implementation, it can be used to fix 250 * errors from the previous testing stage and modify the route before the 251 * second stage of testing is carried out. 252 */ 253 @SuppressWarnings("unused") 254 private void proceedAfterWayCheckerErrors(Relation r) { 255 256 // count errors of each type: 257 int numberOfDirectionErrors = 0; 258 int numberOfRoadTypeErrors = 0; 259 for (TestError e : this.errors) { 260 if (e.getCode() == ERROR_CODE_DIRECTION) { 261 numberOfDirectionErrors++; 262 } 263 if (e.getCode() == ERROR_CODE_ROAD_TYPE) { 264 numberOfRoadTypeErrors++; 265 } 266 } 267 268 final int[] userInput = { 0 }; 269 final long idParameter = r.getId(); 270 final int directionErrorParameter = numberOfDirectionErrors; 271 final int roadTypeErrorParameter = numberOfRoadTypeErrors; 272 273 if (SwingUtilities.isEventDispatchThread()) { 274 275 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 276 277 } else { 278 279 try { 280 SwingUtilities.invokeAndWait(new Runnable() { 281 @Override 282 public void run() { 283 userInput[0] = showProceedDialog(idParameter, directionErrorParameter, roadTypeErrorParameter); 284 285 } 286 }); 287 } catch (InvocationTargetException | InterruptedException e1) { 288 e1.printStackTrace(); 289 } 290 291 } 292 293 if (userInput[0] == 0) { 294 this.fixErrorFromPlugin(this.errors); 295 proceedWithSorting(r); 296 return; 297 } 298 299 if (userInput[0] == 1) { 300 JOptionPane.showMessageDialog(null, "This is not implemented yet!"); 301 return; 302 } 303 304 if (userInput[0] == 2) { 305 proceedWithSorting(r); 306 } 307 308 // if userInput==-1 (i.e. no input), do nothing and stop testing of the 309 // route. 310 311 } 312 313 private int showProceedDialog(long id, int numberOfDirectionErrors, int numberOfRoadTypeErrors) { 314 315 if (numberOfDirectionErrors == 0 && numberOfRoadTypeErrors == 0) { 316 return 2; 317 } 318 319 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == false) { 320 return 0; 321 } 322 323 if (Main.pref.getBoolean("pt_assistant.proceed-without-fix", true) == true) { 324 return 2; 325 } 326 327 ProceedDialog proceedDialog = new ProceedDialog(id, numberOfDirectionErrors, numberOfRoadTypeErrors); 328 return proceedDialog.getUserSelection(); 329 330 } 331 332 /** 333 * Carries out the second stage of the testing: sorting 334 * 335 * @param r 336 * relation 337 */ 338 private void proceedWithSorting(Relation r) { 339 340 // Check if the relation is correct, or only has a wrong sorting order: 341 RouteChecker routeChecker = new RouteChecker(r, this); 342 routeChecker.performSortingTest(); 343 List<TestError> routeCheckerErrors = routeChecker.getErrors(); 344 345 /*- At this point, there are 3 variants: 346 * 347 * 1) There are no errors => route is correct 348 * 2) There is only a sorting error (can only be 1), but otherwise 349 * correct. 350 * 3) There are some other errors/gaps that cannot be fixed by 351 * sorting => start further test (stop-by-stop) 352 * 353 * */ 354 355 if (!routeCheckerErrors.isEmpty()) { 356 // Variant 2 357 // If there is only the sorting error, add it 358 this.errors.addAll(routeChecker.getErrors()); 359 } 360 361 // if (!routeChecker.getHasGap()) { 362 // // Variant 1 363 // storeCorrectRouteSegments(r); 364 // } 365 366 // Variant 3: 367 proceedAfterSorting(r); 368 369 } 370 371 /** 372 * Carries out the stop-by-stop testing which includes building the route 373 * data model. 374 * 375 * @param r 376 * route relation 377 */ 378 private void proceedAfterSorting(Relation r) { 379 380 SegmentChecker segmentChecker = new SegmentChecker(r, this); 381 382 // Check if the creation of the route data model in the segment checker 383 // worked. If it did not, it means the roles in the route relation do 384 // not match the tags of the route members. 385 if (!segmentChecker.getErrors().isEmpty()) { 386 this.errors.addAll(segmentChecker.getErrors()); 387 } 388 389 segmentChecker.performFirstStopTest(); 390 segmentChecker.performLastStopTest(); 391 segmentChecker.performStopNotServedTest(); 392 393 boolean sortingErrorFound = false; 394 for (TestError error : this.errors) { 395 if (error.getCode() == ERROR_CODE_SORTING) { 396 sortingErrorFound = true; 397 break; 398 } 399 } 400 if (!sortingErrorFound) { 401 segmentChecker.performStopByStopTest(); 402 segmentChecker.findFixes(); 403 } 404 405 for (TestError error : segmentChecker.getErrors()) { 406 if (error.getCode() != PTAssistantValidatorTest.ERROR_CODE_RELAITON_MEMBER_ROLES) { 407 this.errors.add(error); 408 } 409 } 410 } 411 412 /** 413 * Method is called after all primitives has been visited, overrides the 414 * method of the superclass. 415 */ 416 public void endTest() { 417 418 // modify the error messages for the stop-by-stop test: 419 SegmentChecker.modifyStopByStopErrorMessages(); 420 421 // add the stop-by-stop errors with modified messages: 422 for (Entry<Builder, PTRouteSegment> entry : SegmentChecker.wrongSegmentBuilders.entrySet()) { 423 TestError error = entry.getKey().build(); 424 SegmentChecker.wrongSegments.put(error, entry.getValue()); 425 this.errors.add(error); 426 } 427 428 // reset the static collections in SegmentChecker: 429 SegmentChecker.reset(); 430 431 super.endTest(); 432 433 } 434 435 /** 436 * Creates the PTRouteSegments of a route that has been found correct and 437 * stores them in the list of correct route segments 438 * 439 * @param r 440 * route relation 441 */ 442 @SuppressWarnings("unused") 443 private void storeCorrectRouteSegments(Relation r) { 444 PTRouteDataManager manager = new PTRouteDataManager(r); 445 StopToWayAssigner assigner = new StopToWayAssigner(manager.getPTWays()); 446 if (manager.getPTStops().size() > 1) { 447 for (int i = 1; i < manager.getPTStops().size(); i++) { 448 PTStop segmentStartStop = manager.getPTStops().get(i - 1); 449 PTStop segmentEndStop = manager.getPTStops().get(i); 450 Way segmentStartWay = assigner.get(segmentStartStop); 451 Way segmentEndWay = assigner.get(segmentEndStop); 452 List<PTWay> waysBetweenStops = manager.getPTWaysBetween(segmentStartWay, segmentEndWay); 453 PTRouteSegment routeSegment = new PTRouteSegment(segmentStartStop, segmentEndStop, waysBetweenStops, r); 454 SegmentChecker.addCorrectSegment(routeSegment); 455 } 456 } 457 } 458 459 /** 460 * Checks if the test error is fixable 461 */ 462 @Override 463 public boolean isFixable(TestError testError) { 464 if (testError.getCode() == ERROR_CODE_DIRECTION || testError.getCode() == ERROR_CODE_ROAD_TYPE 465 || testError.getCode() == ERROR_CODE_CONSTRUCTION || testError.getCode() == ERROR_CODE_SORTING 466 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_SOLITARY_STOP_POSITION 467 || testError.getCode() == PTAssistantValidatorTest.ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 468 return true; 469 } 470 471 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP && SegmentChecker.isFixable(testError)) { 472 return true; 473 } 474 475 return false; 476 } 477 478 /** 479 * Fixes the given error 480 */ 481 @Override 482 public Command fixError(TestError testError) { 483 484 // repaint the relation in the pt_assistant layer: 485 if (testError.getPrimitives().iterator().next().getType().equals(OsmPrimitiveType.RELATION)) { 486 Relation relationToBeFixed = (Relation) testError.getPrimitives().iterator().next(); 487 this.layer.repaint(relationToBeFixed); 488 } 489 490 // reset the last fix: 491 PTAssistantPlugin.setLastFix(null); 492 493 List<Command> commands = new ArrayList<>(); 494 495 if (testError.getCode() == ERROR_CODE_ROAD_TYPE || testError.getCode() == ERROR_CODE_CONSTRUCTION) { 496 commands.add(WayChecker.fixErrorByZooming(testError)); 497 } 498 499 if (testError.getCode() == ERROR_CODE_DIRECTION) { 500 commands.add(WayChecker.fixErrorByZooming(testError)); 501 502 } 503 504 if (testError.getCode() == ERROR_CODE_SORTING) { 505 commands.add(RouteChecker.fixSortingError(testError)); 506 } 507 508 if (testError.getCode() == ERROR_CODE_SOLITARY_STOP_POSITION 509 || testError.getCode() == ERROR_CODE_PLATFORM_PART_OF_HIGHWAY) { 510 commands.add(NodeChecker.fixError(testError)); 511 } 512 513 if (testError.getCode() == ERROR_CODE_STOP_BY_STOP) { 514 commands.add(SegmentChecker.fixError(testError)); 515 // make sure the primitives of this testError are selected: 516 Collection<OsmPrimitive> primitivesToSelect = new ArrayList<>(); 517 for (Object obj : testError.getPrimitives()) { 518 primitivesToSelect.add((OsmPrimitive) obj); 519 } 520 SelectCommand selectCommand = new SelectCommand(primitivesToSelect); 521 SwingUtilities.invokeLater(new Runnable() { 522 @Override 523 public void run() { 524 selectCommand.executeCommand(); 525 } 526 }); 527 } 528 529 if (commands.isEmpty()) { 530 return null; 531 } 532 533 if (commands.size() == 1) { 534 return commands.get(0); 535 } 536 537 return new SequenceCommand(tr("Fix error"), commands); 538 } 539 540 /** 541 * This method is the counterpart of the fixError(TestError testError) 542 * method. The fixError method is invoked from the core validator (e.g. when 543 * user presses the "Fix" button in the validator). This method is invoken 544 * when the fix is initiated from within the plugin (e.g. automated fixes). 545 */ 546 private void fixErrorFromPlugin(List<TestError> testErrors) { 547 548 // run fix task asynchronously 549 FixTask fixTask = new FixTask(testErrors); 550 551 Thread t = new Thread(fixTask); 552 t.start(); 553 try { 554 t.join(); 555 errors.removeAll(testErrors); 556 557 } catch (InterruptedException e) { 558 JOptionPane.showMessageDialog(null, "Error occurred during fixing"); 559 } 560 561 } 562 563 public void addFixVariants(List<List<PTWay>> fixVariants) { 564 layer.addFixVariants(fixVariants); 565 } 566 567 public void clearFixVariants() { 568 layer.clearFixVariants(); 569 } 570 571 public List<PTWay> getFixVariant(Character c) { 572 return layer.getFixVariant(c); 573 } 574 575 @SuppressWarnings("unused") 576 private void performDummyTest(Relation r) { 577 List<Relation> primitives = new ArrayList<>(1); 578 primitives.add(r); 579 Builder builder = TestError.builder(this, Severity.WARNING, ERROR_CODE_DIRECTION); 580 builder.message(tr("PT: dummy test warning")); 581 builder.primitives(primitives); 582 errors.add(builder.build()); 583 } 588 584 589 585 } -
applications/editors/josm/plugins/pt_assistant/src/org/openstreetmap/josm/plugins/pt_assistant/validation/SegmentChecker.java
r33091 r33108 296 296 Node firstNode = findFirstNodeOfRouteSegmentInDirectionOfTravel(segmentWays.get(0)); 297 297 298 // get last added TestErrorBuilder:299 300 298 if (firstNode == null) { 301 299 // check if this error has just been reported: 302 if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted .size() == 1300 if (wrongSegmentBuilders.isEmpty() && lastCreatedBuilderHighlighted != null && lastCreatedBuilderHighlighted.size() == 1 303 301 && lastCreatedBuilderHighlighted.get(0) == startWay) { 304 302 // do nothing, this error has already been reported in
Note:
See TracChangeset
for help on using the changeset viewer.