| | 394 | } else if (alt) { |
| | 395 | Collection<Way> ways = getCurrentDataSet().getWays(); |
| | 396 | LatLon latlon = Main.map.mapView.getLatLon(e.getX(), e.getY()); |
| | 397 | double x = latlon.lon(); |
| | 398 | double y = latlon.lat(); |
| | 399 | BBox mbox = new BBox(latlon, latlon); |
| | 400 | |
| | 401 | long start = System.currentTimeMillis(); |
| | 402 | int polies = 0; |
| | 403 | List<Way> polygons = new LinkedList<Way>(); |
| | 404 | for (Way way : ways) |
| | 405 | { |
| | 406 | // we're only looking for polygons |
| | 407 | if (!way.isClosed()) { |
| | 408 | continue; |
| | 409 | } |
| | 410 | polies++; |
| | 411 | if (pointInPoly(way, mbox, x, y)) { |
| | 412 | polygons.add(way); |
| | 413 | } |
| | 414 | } |
| | 415 | long end = System.currentTimeMillis(); |
| | 416 | long time = end - start; |
| | 417 | System.out.println("processing " + polies + " polygons took " + time + " ms and found " + polygons.size() + " polygons"); |
| | 418 | |
| | 419 | start = System.currentTimeMillis(); |
| | 420 | if (polygons.size() > 1) |
| | 421 | { |
| | 422 | // have to figure out which is the tighter one |
| | 423 | boolean removedOne = false; |
| | 424 | do { |
| | 425 | removedOne = false; |
| | 426 | Iterator<Way> it = polygons.iterator(); |
| | 427 | Way firstEntry = it.next(); |
| | 428 | while (it.hasNext()){ |
| | 429 | Way way = it.next(); |
| | 430 | Intersection res = polyInPoly(way, firstEntry); |
| | 431 | if (res == Intersection.INSIDE) { |
| | 432 | System.out.println("1 removing polygon " + polygons.get(0).getUniqueId()); |
| | 433 | polygons.remove(0); |
| | 434 | removedOne = true; |
| | 435 | break; |
| | 436 | } |
| | 437 | else |
| | 438 | if (res == Intersection.OUTSIDE) { |
| | 439 | System.out.println("2 removing polygon " + way.getUniqueId()); |
| | 440 | it.remove(); |
| | 441 | removedOne = true; |
| | 442 | } |
| | 443 | } |
| | 444 | } while (removedOne && polygons.size() > 1); |
| | 445 | } |
| | 446 | end = System.currentTimeMillis(); |
| | 447 | time = end - start; |
| | 448 | System.out.println("determining the inner polygontook " + time + " ms and found " + polygons.size() + " polygons"); |
| | 449 | |
| | 450 | // Now we've only one polygon or multiple intersecting ones. |
| | 451 | // The first case is ok and for the second one I lack criteria to |
| | 452 | // say which one is the better fit, so take them all. |
| | 453 | selectPrims(new ArrayList<OsmPrimitive>(polygons), shift, false, false, false); |
| | 454 | |
| | 455 | mode = Mode.select; |
| | 456 | oldCursor = Main.map.mapView.getCursor(); |
| | 457 | selectionManager.register(Main.map.mapView); |
| | 482 | * Tests if the first polygon lies within the second polygon or not. |
| | 483 | * "Lies within" is defined as all its points lie within, though that |
| | 484 | * could still mean the borders intersect. |
| | 485 | * This should be sufficient for our needs though. |
| | 486 | * |
| | 487 | * @param poly the way of the first polygon |
| | 488 | * @param poly the way of the second polygon |
| | 489 | * @return INSIDE if the first lies completely within the second polygon, |
| | 490 | * OUTSIDE it lies completely outside of it and CROSSING if it partially |
| | 491 | * lies within. |
| | 492 | */ |
| | 493 | private Intersection polyInPoly(Way poly1, Way poly2) |
| | 494 | { |
| | 495 | int contains = 0; |
| | 496 | List <Node> nodes = poly1.getNodes(); |
| | 497 | for (Node node : nodes) { |
| | 498 | double x = node.getCoor().lon(); |
| | 499 | double y = node.getCoor().lat(); |
| | 500 | if (pointInPoly(poly2, node.getBBox(), x, y)) { |
| | 501 | contains++; |
| | 502 | } |
| | 503 | } |
| | 504 | |
| | 505 | if (contains == nodes.size()) return Intersection.INSIDE; |
| | 506 | if (contains == 0) return Intersection.OUTSIDE; |
| | 507 | return Intersection.CROSSING; |
| | 508 | } |
| | 509 | |
| | 510 | /** |
| | 511 | * Tests if the given point is within the polygon or not. |
| | 512 | * The source of this code is http://www.visibone.com/inpoly/ |
| | 513 | * |
| | 514 | * @param poly the way of the polygon |
| | 515 | * @param mbox bounding box of the mouse point |
| | 516 | * @param xt X coordinate of the mouse cursor |
| | 517 | * @param yt Y coordinate of the mouse cursor |
| | 518 | * @return true if the point is within the polygon, false otherwise |
| | 519 | */ |
| | 520 | private boolean pointInPoly(Way poly, BBox mbox, double xt, double yt) |
| | 521 | { |
| | 522 | List <Node> nodes = poly.getNodes(); |
| | 523 | int npoints = nodes.size(); |
| | 524 | double xnew, ynew; |
| | 525 | double xold, yold; |
| | 526 | double x1, y1; |
| | 527 | double x2, y2; |
| | 528 | |
| | 529 | if (npoints < 4) |
| | 530 | return(false); |
| | 531 | |
| | 532 | // in this case intersects is a test for "is contained" |
| | 533 | if (!poly.getBBox().intersects(mbox)) |
| | 534 | return false; |
| | 535 | |
| | 536 | LatLon old_ = nodes.get(npoints - 1).getCoor(); |
| | 537 | xold = old_.getX(); |
| | 538 | yold = old_.getY(); |
| | 539 | boolean inside = false; |
| | 540 | for (Node node : nodes) { |
| | 541 | LatLon new_ = node.getCoor(); |
| | 542 | xnew = new_.getX(); |
| | 543 | ynew = new_.getY(); |
| | 544 | if (xnew > xold) { |
| | 545 | x1 = xold; |
| | 546 | x2 = xnew; |
| | 547 | y1 = yold; |
| | 548 | y2 = ynew; |
| | 549 | } |
| | 550 | else { |
| | 551 | x1 = xnew; |
| | 552 | x2 = xold; |
| | 553 | y1 = ynew; |
| | 554 | y2 = yold; |
| | 555 | } |
| | 556 | |
| | 557 | if ((xnew < xt) == (xt <= xold) /* edge "open" at one end */ |
| | 558 | && (yt - y1) * (x2 - x1) |
| | 559 | < (y2 - y1) * (xt - x1)) { |
| | 560 | inside = !inside; |
| | 561 | } |
| | 562 | |
| | 563 | xold = xnew; |
| | 564 | yold = ynew; |
| | 565 | } |
| | 566 | |
| | 567 | return(inside); |
| | 568 | } |
| | 569 | |
| | 570 | |
| | 571 | /** |
| | 572 | * Handle left double clicks for selecting connected ways |
| | 573 | */ |
| | 574 | @Override public void mouseClicked(MouseEvent e) { |
| | 575 | if (!Main.map.mapView.isActiveLayerVisible()) |
| | 576 | return; |
| | 577 | // request focus in order to enable the expected keyboard shortcuts |
| | 578 | // |
| | 579 | Main.map.mapView.requestFocus(); |
| | 580 | |
| | 581 | cancelDrawMode = false; |
| | 582 | if (! (Boolean)this.getValue("active")) return; |
| | 583 | if (e.getButton() != MouseEvent.BUTTON1 || |
| | 584 | e.getClickCount() != 2) |
| | 585 | return; |
| | 586 | |
| | 587 | Collection<Way> sel = getCurrentDataSet().getSelectedWays(); |
| | 588 | selectWaysRecursions = 0; |
| | 589 | // remove selection for the initial input to not fall prey |
| | 590 | // to the first condition in selectWays |
| | 591 | getCurrentDataSet().clearSelection(sel); |
| | 592 | selectWays(sel); |
| | 593 | } |
| | 594 | |
| | 595 | /** |
| | 596 | * This is method recursively calls itself |
| | 597 | * |
| | 598 | * @param ways all selected ways |
| | 599 | */ |
| | 600 | private void selectWays(Collection<Way> ways) |
| | 601 | { |
| | 602 | // limit the number of recursions to a reasonable amount |
| | 603 | if (selectWaysRecursions++ < 10) { |
| | 604 | for (Way way : ways) { |
| | 605 | // this way may have been selected already in a deeper recursion |
| | 606 | if (way.isSelected()) { |
| | 607 | continue; |
| | 608 | } |
| | 609 | getCurrentDataSet().addSelected(way); |
| | 610 | for (Node node : way.getNodes()) |
| | 611 | { |
| | 612 | Collection<Way> newways = OsmPrimitive.getFilteredList(node.getReferrers(), Way.class); |
| | 613 | newways.removeAll(getCurrentDataSet().getSelectedWays()); |
| | 614 | |
| | 615 | if (!newways.isEmpty()) { |
| | 616 | selectWays(newways); |
| | 617 | } |
| | 618 | } |
| | 619 | } |
| | 620 | } |
| | 621 | selectWaysRecursions--; |
| | 622 | } |
| | 623 | |
| | 624 | /** |