001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.awt.event.ActionEvent; 008import java.awt.event.KeyEvent; 009import java.util.Collection; 010import java.util.HashSet; 011import java.util.LinkedList; 012 013import javax.swing.JOptionPane; 014 015import org.openstreetmap.josm.Main; 016import org.openstreetmap.josm.command.Command; 017import org.openstreetmap.josm.command.MoveCommand; 018import org.openstreetmap.josm.command.SequenceCommand; 019import org.openstreetmap.josm.data.osm.Node; 020import org.openstreetmap.josm.data.osm.OsmPrimitive; 021import org.openstreetmap.josm.data.osm.Way; 022import org.openstreetmap.josm.gui.Notification; 023import org.openstreetmap.josm.tools.Shortcut; 024 025/** 026 * Mirror the selected nodes or ways along the vertical axis 027 * 028 * Note: If a ways are selected, their nodes are mirrored 029 * 030 * @author Teemu Koskinen, based on much copy&Paste from other Actions. 031 */ 032public final class MirrorAction extends JosmAction { 033 034 public MirrorAction() { 035 super(tr("Mirror"), "mirror", tr("Mirror selected nodes and ways."), 036 Shortcut.registerShortcut("tools:mirror", tr("Tool: {0}", tr("Mirror")), 037 KeyEvent.VK_M, Shortcut.SHIFT), true); 038 putValue("help", ht("/Action/Mirror")); 039 } 040 041 @Override 042 public void actionPerformed(ActionEvent e) { 043 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected(); 044 HashSet<Node> nodes = new HashSet<Node>(); 045 046 for (OsmPrimitive osm : sel) { 047 if (osm instanceof Node) { 048 nodes.add((Node)osm); 049 } else if (osm instanceof Way) { 050 nodes.addAll(((Way)osm).getNodes()); 051 } 052 } 053 054 if (nodes.isEmpty()) { 055 new Notification( 056 tr("Please select at least one node or way.")) 057 .setIcon(JOptionPane.INFORMATION_MESSAGE) 058 .setDuration(Notification.TIME_SHORT) 059 .show(); 060 return; 061 } 062 063 double minEast = 20000000000.0; 064 double maxEast = -20000000000.0; 065 for (Node n : nodes) { 066 double east = n.getEastNorth().east(); 067 minEast = Math.min(minEast, east); 068 maxEast = Math.max(maxEast, east); 069 } 070 double middle = (minEast + maxEast) / 2; 071 072 Collection<Command> cmds = new LinkedList<Command>(); 073 074 for (Node n : nodes) { 075 cmds.add(new MoveCommand(n, 2 * (middle - n.getEastNorth().east()), 0.0)); 076 } 077 078 Main.main.undoRedo.add(new SequenceCommand(tr("Mirror"), cmds)); 079 Main.map.repaint(); 080 } 081 082 @Override 083 protected void updateEnabledState() { 084 if (getCurrentDataSet() == null) { 085 setEnabled(false); 086 } else { 087 updateEnabledState(getCurrentDataSet().getSelected()); 088 } 089 } 090 091 @Override 092 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 093 setEnabled(selection != null && !selection.isEmpty()); 094 } 095}