// License: GPL. For details, see LICENSE file.
package MichiganLeft;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.command.AddCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.command.SequenceCommand;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.gui.MainMenu;
import org.openstreetmap.josm.plugins.Plugin;
import org.openstreetmap.josm.plugins.PluginInformation;
import org.openstreetmap.josm.tools.Shortcut;
/**
* Plugin for easily creating turn restrictions at "Michigan left" intersections.
*/
public class MichiganLeft extends Plugin {
JMenuItem MichiganLeft;
/**
* Constructs a new {@code MichiganLeft} plugin.
*
* @param info plugin info
*/
public MichiganLeft(PluginInformation info) {
super(info);
MichiganLeft = MainMenu.add(Main.main.menu.dataMenu, new MichiganLeftAction());
}
private class MichiganLeftAction extends JosmAction {
private LinkedList<Command> cmds = new LinkedList<>();
MichiganLeftAction() {
super(tr("Michigan Left"), "michigan_left",
tr("Adds no left turn for sets of 4 or 5 ways."),
Shortcut.registerShortcut("tools:michigan_left",
tr("Tool: {0}", tr("Michigan Left")), KeyEvent.VK_N, Shortcut.ALT_SHIFT), true);
}
@Override
public void actionPerformed(ActionEvent e) {
Collection<OsmPrimitive> mainSelection = Main.getLayerManager().getEditDataSet().getSelected();
ArrayList<OsmPrimitive> selection = new ArrayList<>();
for (OsmPrimitive prim : mainSelection) {
selection.add(prim);
}
int ways = 0;
for (OsmPrimitive prim : selection) {
if (prim instanceof Way)
ways++;
}
if ((ways != 4) && (ways != 5)) {
JOptionPane.showMessageDialog(Main.parent,
tr("Please select 4 or 5 ways to assign no left turns."));
return;
}
if (ways == 4) {
// Find extremities of ways
Hashtable<Node, Integer> extremNodes = new Hashtable<>();
for (OsmPrimitive prim : selection) {
if (prim instanceof Way) {
Way way = (Way) prim;
incrementHashtable(extremNodes, way.firstNode());
incrementHashtable(extremNodes, way.lastNode());
}
}
if (extremNodes.size() != 4) {
JOptionPane.showMessageDialog(Main.parent,
tr("Please select 4 ways that form a closed relation."));
return;
}
// order the ways
ArrayList<Way> orderedWays = new ArrayList<>();
Way currentWay = (Way) selection.iterator().next();
orderedWays.add(currentWay);
selection.remove(currentWay);
while (selection.size() > 0) {
boolean found = false;
Node nextNode = currentWay.lastNode();
for (OsmPrimitive prim : selection) {
Way tmpWay = (Way) prim;
if (tmpWay.firstNode() == nextNode) {
orderedWays.add(tmpWay);
selection.remove(prim);
currentWay = tmpWay;
found = true;
break;
}
}
if (!found) {
JOptionPane.showMessageDialog(Main.parent,
tr("Unable to order the ways. Please verify their directions"));
return;
}
}
// Build relations
for (int index = 0; index < 4; index++) {
Way firstWay = orderedWays.get(index);
Way lastWay = orderedWays.get((index + 1) % 4);
Node lastNode = firstWay.lastNode();
buildRelation(firstWay, lastWay, lastNode);
}
Command c = new SequenceCommand(tr("Create Michigan left turn restriction"), cmds);
Main.main.undoRedo.add(c);
cmds.clear();
}
if (ways == 5) {
// Find extremities of ways
Hashtable<Node, Integer> extremNodes = new Hashtable<>();
for (OsmPrimitive prim : selection) {
if (prim instanceof Way) {
Way way = (Way) prim;
incrementHashtable(extremNodes, way.firstNode());
incrementHashtable(extremNodes, way.lastNode());
}
}
ArrayList<Node> viaNodes = new ArrayList<>();
// find via nodes (they have 3 occurences in the list)
for (Enumeration<Node> enumKey = extremNodes.keys(); enumKey.hasMoreElements();) {
Node extrem = enumKey.nextElement();
Integer nb = extremNodes.get(extrem);
if (nb.intValue() == 3) {
viaNodes.add(extrem);
}
}
if (viaNodes.size() != 2) {
JOptionPane.showMessageDialog(Main.parent,
tr("Unable to find via nodes. Please check your selection"));
return;
}
Node viaFirst = viaNodes.get(0);
Node viaLast = viaNodes.get(1); // Find middle segment
Way middle = null;
for (OsmPrimitive prim : selection) {
if (prim instanceof Way) {
Way way = (Way) prim;
Node first = way.firstNode();
Node last = way.lastNode();
if ((first.equals(viaFirst) && last.equals(viaLast))
|| (first.equals(viaLast) && last.equals(viaFirst)))
middle = way;
}
}
// Build relations
for (OsmPrimitive prim : selection) {
if (prim instanceof Way) {
Way way = (Way) prim;
if (way != middle) {
Node first = way.firstNode();
Node last = way.lastNode();
if (first == viaFirst)
buildRelation(middle, way, viaNodes.get(0));
else if (first == viaLast)
buildRelation(middle, way, viaNodes.get(1));
else if (last == viaFirst)
buildRelation(way, middle, viaNodes.get(0));
else if (last == viaLast)
buildRelation(way, middle, viaNodes.get(1));
}
}
}
Command c = new SequenceCommand(tr("Create Michigan left turn restriction"), cmds);
Main.main.undoRedo.add(c);
cmds.clear();
}
}
public void incrementHashtable(Hashtable<Node, Integer> hash, Node node) {
if (hash.containsKey(node)) {
Integer nb = hash.get(node);
hash.put(node, new Integer(nb.intValue() + 1));
} else {
hash.put(node, new Integer(1));
}
}
public void buildRelation(Way fromWay, Way toWay, Node viaNode) {
Relation relation = new Relation();
RelationMember from = new RelationMember("from", fromWay);
relation.addMember(from);
RelationMember to = new RelationMember("to", toWay);
relation.addMember(to);
RelationMember via = new RelationMember("via", viaNode);
relation.addMember(via);
relation.put("type", "restriction");
relation.put("restriction", "no_left_turn");
cmds.add(new AddCommand(relation));
}
@Override
protected void updateEnabledState() {
setEnabled(getLayerManager().getEditLayer() != null);
}
@Override
protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
// do nothing
}
}
}