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