Пример #1
0
    private WayInPolygon advanceNextWay(boolean rightmost) {

      Node headNode = !lastWayReverse ? lastWay.way.lastNode() : lastWay.way.firstNode();
      Node prevNode =
          !lastWayReverse
              ? lastWay.way.getNode(lastWay.way.getNodesCount() - 2)
              : lastWay.way.getNode(1);

      // find best next way
      WayInPolygon bestWay = null;
      Node bestWayNextNode = null;
      boolean bestWayReverse = false;

      for (WayInPolygon way : availableWays) {
        if (way.way.firstNode().equals(headNode)) {
          // start adjacent to headNode
          Node nextNode = way.way.getNode(1);

          if (nextNode.equals(prevNode)) {
            // this is the path we came from - ignore it.
          } else if (bestWay == null
              || (Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)
                  == rightmost)) {
            // the new way is better
            bestWay = way;
            bestWayReverse = false;
            bestWayNextNode = nextNode;
          }
        }

        if (way.way.lastNode().equals(headNode)) {
          // end adjacent to headNode
          Node nextNode = way.way.getNode(way.way.getNodesCount() - 2);

          if (nextNode.equals(prevNode)) {
            // this is the path we came from - ignore it.
          } else if (bestWay == null
              || (Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)
                  == rightmost)) {
            // the new way is better
            bestWay = way;
            bestWayReverse = true;
            bestWayNextNode = nextNode;
          }
        }
      }

      lastWay = bestWay;
      lastWayReverse = bestWayReverse;

      return lastWay;
    }
Пример #2
0
  /**
   * This method analyzes the way and assigns each part what direction polygon "inside" is.
   *
   * @param parts the split parts of the way
   * @param isInner - if true, reverts the direction (for multipolygon islands)
   * @return list of parts, marked with the inside orientation.
   */
  private List<WayInPolygon> markWayInsideSide(List<Way> parts, boolean isInner) {

    List<WayInPolygon> result = new ArrayList<WayInPolygon>();

    // prepare prev and next maps
    Map<Way, Way> nextWayMap = new HashMap<Way, Way>();
    Map<Way, Way> prevWayMap = new HashMap<Way, Way>();

    for (int pos = 0; pos < parts.size(); pos++) {

      if (!parts.get(pos).lastNode().equals(parts.get((pos + 1) % parts.size()).firstNode()))
        throw new RuntimeException("Way not circular");

      nextWayMap.put(parts.get(pos), parts.get((pos + 1) % parts.size()));
      prevWayMap.put(parts.get(pos), parts.get((pos + parts.size() - 1) % parts.size()));
    }

    // find the node with minimum y - it's guaranteed to be outer. (What about the south pole?)
    Way topWay = null;
    Node topNode = null;
    int topIndex = 0;
    double minY = Double.POSITIVE_INFINITY;

    for (Way way : parts) {
      for (int pos = 0; pos < way.getNodesCount(); pos++) {
        Node node = way.getNode(pos);

        if (node.getEastNorth().getY() < minY) {
          minY = node.getEastNorth().getY();
          topWay = way;
          topNode = node;
          topIndex = pos;
        }
      }
    }

    // get the upper way and it's orientation.

    boolean wayClockwise; // orientation of the top way.

    if (topNode.equals(topWay.firstNode()) || topNode.equals(topWay.lastNode())) {
      Node headNode = null; // the node at junction
      Node prevNode = null; // last node from previous path
      wayClockwise = false;

      // node is in split point - find the outermost way from this point

      headNode = topNode;
      // make a fake node that is downwards from head node (smaller Y). It will be a division point
      // between paths.
      prevNode =
          new Node(
              new EastNorth(headNode.getEastNorth().getX(), headNode.getEastNorth().getY() - 1e5));

      topWay = null;
      wayClockwise = false;
      Node bestWayNextNode = null;

      for (Way way : parts) {
        if (way.firstNode().equals(headNode)) {
          Node nextNode = way.getNode(1);

          if (topWay == null
              || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) {
            // the new way is better
            topWay = way;
            wayClockwise = true;
            bestWayNextNode = nextNode;
          }
        }

        if (way.lastNode().equals(headNode)) {
          // end adjacent to headNode
          Node nextNode = way.getNode(way.getNodesCount() - 2);

          if (topWay == null
              || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) {
            // the new way is better
            topWay = way;
            wayClockwise = false;
            bestWayNextNode = nextNode;
          }
        }
      }
    } else {
      // node is inside way - pick the clockwise going end.
      Node prev = topWay.getNode(topIndex - 1);
      Node next = topWay.getNode(topIndex + 1);

      // there will be no parallel segments in the middle of way, so all fine.
      wayClockwise = Geometry.angleIsClockwise(prev, topNode, next);
    }

    Way curWay = topWay;
    boolean curWayInsideToTheRight = wayClockwise ^ isInner;

    // iterate till full circle is reached
    while (true) {

      // add cur way
      WayInPolygon resultWay = new WayInPolygon(curWay, curWayInsideToTheRight);
      result.add(resultWay);

      // process next way
      Way nextWay = nextWayMap.get(curWay);
      Node prevNode = curWay.getNode(curWay.getNodesCount() - 2);
      Node headNode = curWay.lastNode();
      Node nextNode = nextWay.getNode(1);

      if (nextWay == topWay) {
        // full loop traversed - all done.
        break;
      }

      // find intersecting segments
      // the intersections will look like this:
      //
      //                       ^
      //                       |
      //                       X wayBNode
      //                       |
      //                  wayB |
      //                       |
      //             curWay    |       nextWay
      // ----X----------------->X----------------------X---->
      //    prevNode           ^headNode              nextNode
      //                       |
      //                       |
      //                  wayA |
      //                       |
      //                       X wayANode
      //                       |

      int intersectionCount = 0;

      for (Way wayA : parts) {

        if (wayA == curWay) {
          continue;
        }

        if (wayA.lastNode().equals(headNode)) {

          Way wayB = nextWayMap.get(wayA);

          // test if wayA is opposite wayB relative to curWay and nextWay

          Node wayANode = wayA.getNode(wayA.getNodesCount() - 2);
          Node wayBNode = wayB.getNode(1);

          boolean wayAToTheRight =
              Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayANode);
          boolean wayBToTheRight =
              Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayBNode);

          if (wayAToTheRight != wayBToTheRight) {
            intersectionCount++;
          }
        }
      }

      // if odd number of crossings, invert orientation
      if (intersectionCount % 2 != 0) {
        curWayInsideToTheRight = !curWayInsideToTheRight;
      }

      curWay = nextWay;
    }

    return result;
  }