Esempio n. 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;
    }
Esempio n. 2
0
 @Override
 public boolean equals(Object obj) {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   Segment other = (Segment) obj;
   if (end == null) {
     if (other.end != null) return false;
   } else if (!end.equals(other.end)) return false;
   if (start == null) {
     if (other.start != null) return false;
   } else if (!start.equals(other.start)) return false;
   if (way == null) {
     if (other.way != null) return false;
   } else if (!way.equals(other.way)) return false;
   return true;
 }
Esempio n. 3
0
      @Override
      public void visit(Way w) {
        /*
         * If e.parent is already set to the first matching referrer. We skip any following
         * referrer injected into the visitor.
         */
        if (e.parent != null) return;

        if (!left.matches(e.withPrimitive(w))) return;
        for (int i = 0; i < w.getNodesCount(); i++) {
          Node n = w.getNode(i);
          if (n.equals(e.osm)) {
            if (link.matches(e.withParentAndIndexAndLinkContext(w, i, w.getNodesCount()))) {
              e.parent = w;
              e.index = i;
              e.count = w.getNodesCount();
              return;
            }
          }
        }
      }
Esempio n. 4
0
  /**
   * Tests if point is inside a polygon. The polygon can be self-intersecting. In such case the
   * contains function works in xor-like manner.
   *
   * @param polygonNodes list of nodes from polygon path.
   * @param point the point to test
   * @return true if the point is inside polygon.
   */
  public static boolean nodeInsidePolygon(Node point, List<Node> polygonNodes) {
    if (polygonNodes.size() < 2) return false;

    boolean inside = false;
    Node p1, p2;

    // iterate each side of the polygon, start with the last segment
    Node oldPoint = polygonNodes.get(polygonNodes.size() - 1);

    for (Node newPoint : polygonNodes) {
      // skip duplicate points
      if (newPoint.equals(oldPoint)) {
        continue;
      }

      // order points so p1.lat <= p2.lat;
      if (newPoint.getEastNorth().getY() > oldPoint.getEastNorth().getY()) {
        p1 = oldPoint;
        p2 = newPoint;
      } else {
        p1 = newPoint;
        p2 = oldPoint;
      }

      // test if the line is crossed and if so invert the inside flag.
      if ((newPoint.getEastNorth().getY() < point.getEastNorth().getY())
              == (point.getEastNorth().getY() <= oldPoint.getEastNorth().getY())
          && (point.getEastNorth().getX() - p1.getEastNorth().getX())
                  * (p2.getEastNorth().getY() - p1.getEastNorth().getY())
              < (p2.getEastNorth().getX() - p1.getEastNorth().getX())
                  * (point.getEastNorth().getY() - p1.getEastNorth().getY())) {
        inside = !inside;
      }

      oldPoint = newPoint;
    }

    return inside;
  }
Esempio n. 5
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;
  }