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.Node;
010import org.openstreetmap.josm.data.osm.RelationMember;
011import org.openstreetmap.josm.data.osm.Way;
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     */
028    static Direction roundaboutType(RelationMember member) {
029        if (member == null || !member.isWay()) return NONE;
030        return roundaboutType(member.getWay());
031    }
032
033    static Direction roundaboutType(Way w) {
034        if (w != null && w.hasTag("junction", "roundabout")) {
035            int nodesCount = w.getNodesCount();
036            if (nodesCount > 2 && nodesCount < 200) {
037                Node n1 = w.getNode(0);
038                Node n2 = w.getNode(1);
039                Node n3 = w.getNode(2);
040                if (n1 != null && n2 != null && n3 != null && w.isClosed()) {
041                    /** do some simple determinant / cross product test on the first 3 nodes
042                        to see, if the roundabout goes clock wise or ccw */
043                    EastNorth en1 = n1.getEastNorth();
044                    EastNorth en2 = n2.getEastNorth();
045                    EastNorth en3 = n3.getEastNorth();
046                    if (en1 != null && en2 != null && en3 != null) {
047                        en1 = en2.subtract(en1);
048                        en2 = en3.subtract(en2);
049                        return en1.north() * en2.east() - en2.north() * en1.east() > 0 ? ROUNDABOUT_LEFT : ROUNDABOUT_RIGHT;
050                    }
051                }
052            }
053        }
054        return NONE;
055    }
056
057    static boolean isBackward(final RelationMember member) {
058        return "backward".equals(member.getRole());
059    }
060
061    static boolean isForward(final RelationMember member) {
062        return "forward".equals(member.getRole());
063    }
064
065    static boolean isOneway(final RelationMember member) {
066        return isForward(member) || isBackward(member);
067    }
068}