예제 #1
0
파일: Way.java 프로젝트: codesman/josm
  @Override
  public void load(PrimitiveData data) {
    boolean locked = writeLock();
    try {
      super.load(data);

      WayData wayData = (WayData) data;

      if (!wayData.getNodes().isEmpty() && getDataSet() == null) {
        throw new AssertionError("Data consistency problem - way without dataset detected");
      }

      List<Node> newNodes = new ArrayList<>(wayData.getNodes().size());
      for (Long nodeId : wayData.getNodes()) {
        Node node = (Node) getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE);
        if (node != null) {
          newNodes.add(node);
        } else {
          throw new AssertionError("Data consistency problem - way with missing node detected");
        }
      }
      setNodes(newNodes);
    } finally {
      writeUnlock(locked);
    }
  }
예제 #2
0
파일: Way.java 프로젝트: codesman/josm
 @Override
 public WayData save() {
   WayData data = new WayData();
   saveCommonAttributes(data);
   for (Node node : nodes) {
     data.getNodes().add(node.getUniqueId());
   }
   return data;
 }
예제 #3
0
  /**
   * Outline: 1. Find direction of all segments - direction = 0..3 (right,up,left,down) - right is
   * not really right, you may have to turn your screen 2. Find average heading of all segments -
   * heading = angle of a vector in polar coordinates - sum up horizontal segments (those with
   * direction 0 or 2) - sum up vertical segments - turn the vertical sum by 90 degrees and add it
   * to the horizontal sum - get the average heading from this total sum 3. Rotate all nodes by the
   * average heading so that right is really right and all segments are approximately NS or EW. 4.
   * If nodes are connected by a horizontal segment: Replace their y-Coordinate by the mean value of
   * their y-Coordinates. - The same for vertical segments. 5. Rotate back.
   */
  private static Collection<Command> orthogonalize(
      List<WayData> wayDataList, List<Node> headingNodes) throws InvalidUserInputException {
    // find average heading
    double headingAll;
    try {
      if (headingNodes.isEmpty()) {
        // find directions of the segments and make them consistent between different ways
        wayDataList.get(0).calcDirections(Direction.RIGHT);
        double refHeading = wayDataList.get(0).heading;
        EastNorth totSum = new EastNorth(0., 0.);
        for (WayData w : wayDataList) {
          w.calcDirections(Direction.RIGHT);
          int directionOffset = angleToDirectionChange(w.heading - refHeading, TOLERANCE2);
          w.calcDirections(Direction.RIGHT.changeBy(directionOffset));
          if (angleToDirectionChange(refHeading - w.heading, TOLERANCE2) != 0)
            throw new RuntimeException();
          totSum = EN.sum(totSum, w.segSum);
        }
        headingAll = EN.polar(new EastNorth(0., 0.), totSum);
      } else {
        headingAll =
            EN.polar(headingNodes.get(0).getEastNorth(), headingNodes.get(1).getEastNorth());
        for (WayData w : wayDataList) {
          w.calcDirections(Direction.RIGHT);
          int directionOffset = angleToDirectionChange(w.heading - headingAll, TOLERANCE2);
          w.calcDirections(Direction.RIGHT.changeBy(directionOffset));
        }
      }
    } catch (RejectedAngleException ex) {
      throw new InvalidUserInputException(
          tr(
              "<html>Please make sure all selected ways head in a similar direction<br>"
                  + "or orthogonalize them one by one.</html>"),
          ex);
    }

    // put the nodes of all ways in a set
    final Set<Node> allNodes = new HashSet<>();
    for (WayData w : wayDataList) {
      for (Node n : w.way.getNodes()) {
        allNodes.add(n);
      }
    }

    // the new x and y value for each node
    final Map<Node, Double> nX = new HashMap<>();
    final Map<Node, Double> nY = new HashMap<>();

    // calculate the centroid of all nodes
    // it is used as rotation center
    EastNorth pivot = new EastNorth(0., 0.);
    for (Node n : allNodes) {
      pivot = EN.sum(pivot, n.getEastNorth());
    }
    pivot = new EastNorth(pivot.east() / allNodes.size(), pivot.north() / allNodes.size());

    // rotate
    for (Node n : allNodes) {
      EastNorth tmp = EN.rotateCC(pivot, n.getEastNorth(), -headingAll);
      nX.put(n, tmp.east());
      nY.put(n, tmp.north());
    }

    // orthogonalize
    final Direction[] HORIZONTAL = {Direction.RIGHT, Direction.LEFT};
    final Direction[] VERTICAL = {Direction.UP, Direction.DOWN};
    final Direction[][] ORIENTATIONS = {HORIZONTAL, VERTICAL};
    for (Direction[] orientation : ORIENTATIONS) {
      final Set<Node> s = new HashSet<>(allNodes);
      int s_size = s.size();
      for (int dummy = 0; dummy < s_size; ++dummy) {
        if (s.isEmpty()) {
          break;
        }
        final Node dummy_n = s.iterator().next(); // pick arbitrary element of s

        final Set<Node> cs =
            new HashSet<>(); // will contain each node that can be reached from dummy_n
        cs.add(dummy_n); // walking only on horizontal / vertical segments

        boolean somethingHappened = true;
        while (somethingHappened) {
          somethingHappened = false;
          for (WayData w : wayDataList) {
            for (int i = 0; i < w.nSeg; ++i) {
              Node n1 = w.way.getNodes().get(i);
              Node n2 = w.way.getNodes().get(i + 1);
              if (Arrays.asList(orientation).contains(w.segDirections[i])) {
                if (cs.contains(n1) && !cs.contains(n2)) {
                  cs.add(n2);
                  somethingHappened = true;
                }
                if (cs.contains(n2) && !cs.contains(n1)) {
                  cs.add(n1);
                  somethingHappened = true;
                }
              }
            }
          }
        }

        final Map<Node, Double> nC = (orientation == HORIZONTAL) ? nY : nX;

        double average = 0;
        for (Node n : cs) {
          s.remove(n);
          average += nC.get(n).doubleValue();
        }
        average = average / cs.size();

        // if one of the nodes is a heading node, forget about the average and use its value
        for (Node fn : headingNodes) {
          if (cs.contains(fn)) {
            average = nC.get(fn);
          }
        }

        // At this point, the two heading nodes (if any) are horizontally aligned, i.e. they
        // have the same y coordinate. So in general we shouldn't find them in a vertical string
        // of segments. This can still happen in some pathological cases (see #7889). To avoid
        // both heading nodes collapsing to one point, we simply skip this segment string and
        // don't touch the node coordinates.
        if (orientation == VERTICAL && headingNodes.size() == 2 && cs.containsAll(headingNodes)) {
          continue;
        }

        for (Node n : cs) {
          nC.put(n, average);
        }
      }
      if (!s.isEmpty()) throw new RuntimeException();
    }

    // rotate back and log the change
    final Collection<Command> commands = new LinkedList<>();
    for (Node n : allNodes) {
      EastNorth tmp = new EastNorth(nX.get(n), nY.get(n));
      tmp = EN.rotateCC(pivot, tmp, headingAll);
      final double dx = tmp.east() - n.getEastNorth().east();
      final double dy = tmp.north() - n.getEastNorth().north();
      if (headingNodes.contains(n)) { // The heading nodes should not have changed
        final double EPSILON = 1E-6;
        if (Math.abs(dx) > Math.abs(EPSILON * tmp.east())
            || Math.abs(dy) > Math.abs(EPSILON * tmp.east())) throw new AssertionError();
      } else {
        OrthogonalizeAction.rememberMovements.put(n, new EastNorth(dx, dy));
        commands.add(new MoveCommand(n, dx, dy));
      }
    }
    return commands;
  }