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 * @throws IllegalArgumentException if the node pair is not part of way 051 */ 052 public static WaySegment forNodePair(Way way, Node first, Node second) { 053 int endIndex = way.getNodesCount() - 1; 054 while (endIndex > 0) { 055 final int indexOfFirst = way.getNodes().subList(0, endIndex).lastIndexOf(first); 056 if (second.equals(way.getNode(indexOfFirst + 1))) { 057 return new WaySegment(way, indexOfFirst); 058 } 059 endIndex--; 060 } 061 throw new IllegalArgumentException("Node pair is not part of way!"); 062 } 063 064 /** 065 * Returns this way segment as complete way. 066 * @return the way segment as {@code Way} 067 */ 068 public Way toWay() { 069 Way w = new Way(); 070 w.addNode(getFirstNode()); 071 w.addNode(getSecondNode()); 072 return w; 073 } 074 075 @Override 076 public boolean equals(Object o) { 077 return o instanceof WaySegment 078 && ((WaySegment) o).way == way 079 && ((WaySegment) o).lowerIndex == lowerIndex; 080 } 081 082 @Override 083 public int hashCode() { 084 return way.hashCode() ^ lowerIndex; 085 } 086 087 @Override 088 public int compareTo(WaySegment o) { 089 return equals(o) ? 0 : toWay().compareTo(o.toWay()); 090 } 091 092 /** 093 * Checks whether this segment crosses other segment 094 * 095 * @param s2 The other segment 096 * @return true if both segments crosses 097 */ 098 public boolean intersects(WaySegment s2) { 099 if (getFirstNode().equals(s2.getFirstNode()) || getSecondNode().equals(s2.getSecondNode()) || 100 getFirstNode().equals(s2.getSecondNode()) || getSecondNode().equals(s2.getFirstNode())) 101 return false; 102 103 return Line2D.linesIntersect( 104 getFirstNode().getEastNorth().east(), getFirstNode().getEastNorth().north(), 105 getSecondNode().getEastNorth().east(), getSecondNode().getEastNorth().north(), 106 s2.getFirstNode().getEastNorth().east(), s2.getFirstNode().getEastNorth().north(), 107 s2.getSecondNode().getEastNorth().east(), s2.getSecondNode().getEastNorth().north()); 108 } 109 110 @Override 111 public String toString() { 112 return "WaySegment [way=" + way.getUniqueId() + ", lowerIndex=" + lowerIndex + ']'; 113 } 114}