001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm; 003 004import java.awt.geom.Line2D; 005import java.util.Objects; 006 007/** 008 * A segment consisting of 2 consecutive nodes out of a way. 009 */ 010public final class WaySegment implements Comparable<WaySegment> { 011 012 /** 013 * The way. 014 */ 015 public Way way; 016 017 /** 018 * The index of one of the 2 nodes in the way. The other node has the 019 * index <code>lowerIndex + 1</code>. 020 */ 021 public int lowerIndex; 022 023 /** 024 * Constructs a new {@code WaySegment}. 025 * @param w The way 026 * @param i The node lower index 027 * @throws IllegalArgumentException in case of invalid index 028 */ 029 public WaySegment(Way w, int i) { 030 way = w; 031 lowerIndex = i; 032 if (i < 0 || i >= w.getNodesCount() - 1) { 033 throw new IllegalArgumentException(toString()); 034 } 035 } 036 037 /** 038 * Returns the first node of the way segment. 039 * @return the first node 040 */ 041 public Node getFirstNode() { 042 return way.getNode(lowerIndex); 043 } 044 045 /** 046 * Returns the second (last) node of the way segment. 047 * @return the second node 048 */ 049 public Node getSecondNode() { 050 return way.getNode(lowerIndex + 1); 051 } 052 053 /** 054 * Determines and returns the way segment for the given way and node pair. 055 * @param way way 056 * @param first first node 057 * @param second second node 058 * @return way segment 059 * @throws IllegalArgumentException if the node pair is not part of way 060 */ 061 public static WaySegment forNodePair(Way way, Node first, Node second) { 062 int endIndex = way.getNodesCount() - 1; 063 while (endIndex > 0) { 064 final int indexOfFirst = way.getNodes().subList(0, endIndex).lastIndexOf(first); 065 if (second.equals(way.getNode(indexOfFirst + 1))) { 066 return new WaySegment(way, indexOfFirst); 067 } 068 endIndex--; 069 } 070 throw new IllegalArgumentException("Node pair is not part of way!"); 071 } 072 073 /** 074 * Returns this way segment as complete way. 075 * @return the way segment as {@code Way} 076 */ 077 public Way toWay() { 078 Way w = new Way(); 079 w.addNode(getFirstNode()); 080 w.addNode(getSecondNode()); 081 return w; 082 } 083 084 @Override 085 public boolean equals(Object o) { 086 if (this == o) return true; 087 if (o == null || getClass() != o.getClass()) return false; 088 WaySegment that = (WaySegment) o; 089 return lowerIndex == that.lowerIndex && 090 Objects.equals(way, that.way); 091 } 092 093 @Override 094 public int hashCode() { 095 return Objects.hash(way, lowerIndex); 096 } 097 098 @Override 099 public int compareTo(WaySegment o) { 100 return o == null ? -1 : (equals(o) ? 0 : toWay().compareTo(o.toWay())); 101 } 102 103 /** 104 * Checks whether this segment crosses other segment 105 * 106 * @param s2 The other segment 107 * @return true if both segments crosses 108 */ 109 public boolean intersects(WaySegment s2) { 110 if (getFirstNode().equals(s2.getFirstNode()) || getSecondNode().equals(s2.getSecondNode()) || 111 getFirstNode().equals(s2.getSecondNode()) || getSecondNode().equals(s2.getFirstNode())) 112 return false; 113 114 return Line2D.linesIntersect( 115 getFirstNode().getEastNorth().east(), getFirstNode().getEastNorth().north(), 116 getSecondNode().getEastNorth().east(), getSecondNode().getEastNorth().north(), 117 s2.getFirstNode().getEastNorth().east(), s2.getFirstNode().getEastNorth().north(), 118 s2.getSecondNode().getEastNorth().east(), s2.getSecondNode().getEastNorth().north()); 119 } 120 121 /** 122 * Checks whether this segment and another way segment share the same points 123 * @param s2 The other segment 124 * @return true if other way segment is the same or reverse 125 */ 126 public boolean isSimilar(WaySegment s2) { 127 return (getFirstNode().equals(s2.getFirstNode()) && getSecondNode().equals(s2.getSecondNode())) 128 || (getFirstNode().equals(s2.getSecondNode()) && getSecondNode().equals(s2.getFirstNode())); 129 } 130 131 @Override 132 public String toString() { 133 return "WaySegment [way=" + way.getUniqueId() + ", lowerIndex=" + lowerIndex + ']'; 134 } 135}