| 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 | /** |