// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.data.osm; import java.awt.geom.Line2D; import java.util.Objects; /** * A segment consisting of 2 consecutive nodes out of a way. */ public final class WaySegment implements Comparable<WaySegment> { /** * The way. */ public Way way; /** * The index of one of the 2 nodes in the way. The other node has the * index <code>lowerIndex + 1</code>. */ public int lowerIndex; /** * Constructs a new {@code WaySegment}. * @param w The way * @param i The node lower index */ public WaySegment(Way w, int i) { way = w; lowerIndex = i; } /** * Returns the first node of the way segment. * @return the first node */ public Node getFirstNode() { return way.getNode(lowerIndex); } /** * Returns the second (last) node of the way segment. * @return the second node */ public Node getSecondNode() { return way.getNode(lowerIndex + 1); } /** * Determines and returns the way segment for the given way and node pair. * @param way way * @param first first node * @param second second node * @return way segment * @throws IllegalArgumentException if the node pair is not part of way */ public static WaySegment forNodePair(Way way, Node first, Node second) { int endIndex = way.getNodesCount() - 1; while (endIndex > 0) { final int indexOfFirst = way.getNodes().subList(0, endIndex).lastIndexOf(first); if (second.equals(way.getNode(indexOfFirst + 1))) { return new WaySegment(way, indexOfFirst); } endIndex--; } throw new IllegalArgumentException("Node pair is not part of way!"); } /** * Returns this way segment as complete way. * @return the way segment as {@code Way} */ public Way toWay() { Way w = new Way(); w.addNode(getFirstNode()); w.addNode(getSecondNode()); return w; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; WaySegment that = (WaySegment) o; return lowerIndex == that.lowerIndex && Objects.equals(way, that.way); } @Override public int hashCode() { return Objects.hash(way, lowerIndex); } @Override public int compareTo(WaySegment o) { return o == null ? -1 : (equals(o) ? 0 : toWay().compareTo(o.toWay())); } /** * Checks whether this segment crosses other segment * * @param s2 The other segment * @return true if both segments crosses */ public boolean intersects(WaySegment s2) { if (getFirstNode().equals(s2.getFirstNode()) || getSecondNode().equals(s2.getSecondNode()) || getFirstNode().equals(s2.getSecondNode()) || getSecondNode().equals(s2.getFirstNode())) return false; return Line2D.linesIntersect( getFirstNode().getEastNorth().east(), getFirstNode().getEastNorth().north(), getSecondNode().getEastNorth().east(), getSecondNode().getEastNorth().north(), s2.getFirstNode().getEastNorth().east(), s2.getFirstNode().getEastNorth().north(), s2.getSecondNode().getEastNorth().east(), s2.getSecondNode().getEastNorth().north()); } /** * Checks whether this segment and another way segment share the same points * @param s2 The other segment * @return true if other way segment is the same or reverse */ public boolean isSimilar(WaySegment s2) { if (getFirstNode().equals(s2.getFirstNode()) && getSecondNode().equals(s2.getSecondNode())) return true; if (getFirstNode().equals(s2.getSecondNode()) && getSecondNode().equals(s2.getFirstNode())) return true; return false; } @Override public String toString() { return "WaySegment [way=" + way.getUniqueId() + ", lowerIndex=" + lowerIndex + ']'; } }