001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.relation.sort; 003 004import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.NONE; 005import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.ROUNDABOUT_LEFT; 006import static org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction.ROUNDABOUT_RIGHT; 007 008import org.openstreetmap.josm.data.coor.EastNorth; 009import org.openstreetmap.josm.data.osm.INode; 010import org.openstreetmap.josm.data.osm.IRelationMember; 011import org.openstreetmap.josm.data.osm.IWay; 012import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction; 013 014/** 015 * Utility classes for the {@link RelationSorter}. 016 */ 017final class RelationSortUtils { 018 019 private RelationSortUtils() { 020 // Hide default constructor for utils classes 021 } 022 023 /** 024 * determine, if the way i is a roundabout and if yes, what type of roundabout 025 * @param member relation member 026 * @return roundabout type 027 * @since 17862 (generics) 028 */ 029 static Direction roundaboutType(IRelationMember<?> member) { 030 if (member == null || !member.isWay()) return NONE; 031 return roundaboutType((IWay<?>) member.getWay()); 032 } 033 034 /** 035 * Check if a way is a roundabout type 036 * @param w The way to check 037 * @param <W> The way type 038 * @return The roundabout type 039 * @since 17862 (generics) 040 */ 041 static <W extends IWay<?>> Direction roundaboutType(W w) { 042 if (w != null && w.hasTag("junction", "circular", "roundabout")) { 043 int nodesCount = w.getNodesCount(); 044 if (nodesCount > 2 && nodesCount < 200) { 045 INode n1 = w.getNode(0); 046 INode n2 = w.getNode(1); 047 INode n3 = w.getNode(2); 048 if (n1 != null && n2 != null && n3 != null && w.isClosed()) { 049 /** do some simple determinant / cross product test on the first 3 nodes 050 to see, if the roundabout goes clock wise or ccw */ 051 EastNorth en1 = n1.getEastNorth(); 052 EastNorth en2 = n2.getEastNorth(); 053 EastNorth en3 = n3.getEastNorth(); 054 if (en1 != null && en2 != null && en3 != null) { 055 en1 = en2.subtract(en1); 056 en2 = en3.subtract(en2); 057 return en1.north() * en2.east() - en2.north() * en1.east() > 0 ? ROUNDABOUT_LEFT : ROUNDABOUT_RIGHT; 058 } 059 } 060 } 061 } 062 return NONE; 063 } 064 065 static boolean isBackward(final IRelationMember<?> member) { 066 return "backward".equals(member.getRole()); 067 } 068 069 static boolean isForward(final IRelationMember<?> member) { 070 return "forward".equals(member.getRole()); 071 } 072 073 static boolean isOneway(final IRelationMember<?> member) { 074 return isForward(member) || isBackward(member); 075 } 076}