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 */ 028 public WaySegment(Way w, int i) { 029 way = w; 030 lowerIndex = i; 031 } 032 033 /** 034 * Returns the first node of the way segment. 035 * @return the first node 036 */ 037 public Node getFirstNode() { 038 return way.getNode(lowerIndex); 039 } 040 041 /** 042 * Returns the second (last) node of the way segment. 043 * @return the second node 044 */ 045 public Node getSecondNode() { 046 return way.getNode(lowerIndex + 1); 047 } 048 049 /** 050 * Determines and returns the way segment for the given way and node pair. 051 * @param way way 052 * @param first first node 053 * @param second second node 054 * @return way segment 055 * @throws IllegalArgumentException if the node pair is not part of way 056 */ 057 public static WaySegment forNodePair(Way way, Node first, Node second) { 058 int endIndex = way.getNodesCount() - 1; 059 while (endIndex > 0) { 060 final int indexOfFirst = way.getNodes().subList(0, endIndex).lastIndexOf(first); 061 if (second.equals(way.getNode(indexOfFirst + 1))) { 062 return new WaySegment(way, indexOfFirst); 063 } 064 endIndex--; 065 } 066 throw new IllegalArgumentException("Node pair is not part of way!"); 067 } 068 069 /** 070 * Returns this way segment as complete way. 071 * @return the way segment as {@code Way} 072 */ 073 public Way toWay() { 074 Way w = new Way(); 075 w.addNode(getFirstNode()); 076 w.addNode(getSecondNode()); 077 return w; 078 } 079 080 @Override 081 public boolean equals(Object o) { 082 if (this == o) return true; 083 if (o == null || getClass() != o.getClass()) return false; 084 WaySegment that = (WaySegment) o; 085 return lowerIndex == that.lowerIndex && 086 Objects.equals(way, that.way); 087 } 088 089 @Override 090 public int hashCode() { 091 return Objects.hash(way, lowerIndex); 092 } 093 094 @Override 095 public int compareTo(WaySegment o) { 096 return equals(o) ? 0 : toWay().compareTo(o.toWay()); 097 } 098 099 /** 100 * Checks whether this segment crosses other segment 101 * 102 * @param s2 The other segment 103 * @return true if both segments crosses 104 */ 105 public boolean intersects(WaySegment s2) { 106 if (getFirstNode().equals(s2.getFirstNode()) || getSecondNode().equals(s2.getSecondNode()) || 107 getFirstNode().equals(s2.getSecondNode()) || getSecondNode().equals(s2.getFirstNode())) 108 return false; 109 110 return Line2D.linesIntersect( 111 getFirstNode().getEastNorth().east(), getFirstNode().getEastNorth().north(), 112 getSecondNode().getEastNorth().east(), getSecondNode().getEastNorth().north(), 113 s2.getFirstNode().getEastNorth().east(), s2.getFirstNode().getEastNorth().north(), 114 s2.getSecondNode().getEastNorth().east(), s2.getSecondNode().getEastNorth().north()); 115 } 116 117 @Override 118 public String toString() { 119 return "WaySegment [way=" + way.getUniqueId() + ", lowerIndex=" + lowerIndex + ']'; 120 } 121}