Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor buildClosedWays method #171

Open
t-ober opened this issue Dec 8, 2021 · 0 comments
Open

Refactor buildClosedWays method #171

t-ober opened this issue Dec 8, 2021 · 0 comments

Comments

@t-ober
Copy link
Contributor

t-ober commented Dec 8, 2021

Refactor and move to new scala GeoUtils package

  /**
   * This method takes all {@link RelationMember}s and joins the given ways to have closed ways.
   * This only works, if the ways are connected all in a line.
   *
   * @param relation {@link Relation} relation to treat
   * @return Deep copy of the {@code relation} with closed ways
   * @deprecated This method is currently not under test and has to be revised thoroughly
   */
  @Deprecated
  public static Relation buildClosedWays(Relation relation) throws GeoPreparationException {
    /* Copy relation and empty the Members */
    Relation closedRelation = DeepCopy.copy(relation);
    closedRelation
        .getMembers()
        .removeAll(
            closedRelation.getMembers().stream()
                .filter(e -> e.getEntity() instanceof Way)
                .collect(Collectors.toList()));

    List<Way> ways =
        relation.getMembers().stream()
            .filter(e -> e.getEntity() instanceof Way)
            .map(e -> (Way) e.getEntity())
            .collect(Collectors.toList());

    /* Get an idea, of which ways do have intersections and where */
    HashMap<Node, Set<Way>> intersections = new HashMap<>();
    List<Way> comparativeWays = new LinkedList<>(ways);
    for (Way way1 : ways) {
      List<Node> nodes1 = way1.getNodes();

      for (Way way2 : comparativeWays) {
        if (way1.equals(way2)) continue;
        List<Node> nodes2 = way2.getNodes();
        Set<Node> sharedNodes =
            nodes1.stream().filter(nodes2::contains).collect(Collectors.toSet());
        for (Node node : sharedNodes) {
          intersections.putIfAbsent(node, new HashSet<>());
          intersections.get(node).add(way1);
          intersections.get(node).add(way2);
        }
      }

      // TODO: When there are no shared nodes, iterate through both ways once again and find
      // matching nodes based on a radius search
      comparativeWays.remove(way1);
    }

    if (intersections.values().stream().anyMatch(s -> s.size() > 2))
      throw new GeoPreparationException(
          "There is at least one intersection apparent with more then two ways, which would result in a concave hull curve. Exiting here.");

    /* As long as there are untreated ways iterate through them an build closed ways */
    while (!intersections.isEmpty()) {
      /* Take the first intersection node and it's adjacent ways. Remove those ways, to mark them as travelled */
      Node firstIntersection = intersections.keySet().iterator().next();
      Way closedWay = null;

      do {
        if (closedWay != null && intersections.get(firstIntersection).isEmpty()) {
          logger.warn(
              "There are no more intersections left, but the way is not closed right now. Adding the first node once again.");
          closedWay.getNodes().add(closedWay.getNodes().get(0));
          continue;
        }
        Way currentWay = intersections.get(firstIntersection).iterator().next();
        intersections.get(firstIntersection).remove(currentWay);

        /* Find the next way in order to get the two intersections on the current way */
        List<Node> candidateNodes =
            intersections.entrySet().stream()
                .filter(e -> e.getValue().contains(currentWay))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        Node secondIntersection;
        if (candidateNodes.size() > 1)
          throw new GeoPreparationException(
              "There is an intersection, where more then two ways meet. This is not supported, yet.");
        else if (candidateNodes.isEmpty()) {
          /* There is no more way. Close the way by adding the start node ones again */
          if (closedWay == null) {
            logger.warn("There is only one way in this relation.");
            closedWay = currentWay;
          } else if (!currentWay.getNodes().contains(closedWay.getNodes().get(0))) {
            throw new GeoPreparationException("Ran into an dead end.");
          }
          secondIntersection = closedWay.getNodes().get(0);
        } else {
          secondIntersection = candidateNodes.get(0);
          intersections.get(secondIntersection).remove(currentWay);
        }

        int[] nodePos =
            new int[] {
              currentWay.getNodes().indexOf(firstIntersection),
              currentWay.getNodes().indexOf(secondIntersection)
            };
        LinkedList<Node> nodesToAdd;
        if (nodePos[0] <= nodePos[1]) {
          /* Next way can be added in ascending order */
          nodesToAdd = new LinkedList<>(currentWay.getNodes().subList(nodePos[0], nodePos[1] + 1));
        } else {
          /* The intersection is at the end of the next way. Next way can be added in descending order */
          nodesToAdd = new LinkedList<>(currentWay.getNodes().subList(nodePos[1], nodePos[0] + 1));
          Collections.reverse(nodesToAdd);
        }

        /* If there is no buffer way, yet. Create a new one based on the part way identified first */
        if (closedWay == null)
          closedWay = new Way(currentWay.getId(), currentWay.getTags(), nodesToAdd);
        else closedWay.getNodes().addAll(nodesToAdd);

        /* Go one step ahead */
        firstIntersection = secondIntersection;
      } while (!closedWay.isClosed());

      /* Remove all travelled intersections */
      intersections.entrySet().removeIf(e -> e.getValue().isEmpty());

      /* Add the closed way to the relation */
      closedRelation.getMembers().add(new RelationMember(closedWay, "outer"));
    }

    return closedRelation;
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant