Changeset 3702 in josm for trunk/src


Ignore:
Timestamp:
2010-12-07T09:53:12+01:00 (14 years ago)
Author:
bastiK
Message:

applied #5652 (patch by Olivier Croquette) - add support for scaling objects

Location:
trunk/src/org/openstreetmap/josm
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

    r3642 r3702  
    2727import org.openstreetmap.josm.command.MoveCommand;
    2828import org.openstreetmap.josm.command.RotateCommand;
     29import org.openstreetmap.josm.command.ScaleCommand;
    2930import org.openstreetmap.josm.command.SequenceCommand;
    3031import org.openstreetmap.josm.data.coor.EastNorth;
     
    6162    //static private final Logger logger = Logger.getLogger(SelectAction.class.getName());
    6263
    63     enum Mode { move, rotate, select }
     64    enum Mode { move, rotate, scale, select }
     65   
    6466    private Mode mode = null;
    6567    private SelectionManager selectionManager;
    66 
    6768    private boolean cancelDrawMode = false;
    6869    private boolean didMouseDrag = false;
    69 
    7070    /**
    7171     * The component this SelectAction is associated with.
    7272     */
    7373    private final MapView mv;
    74 
    7574    /**
    7675     * The old cursor before the user pressed the mouse button.
    7776     */
    7877    private Cursor oldCursor;
    79 
    80     /**
    81      * The position of the mouse before the user moves a node.
    82      */
    83     private Point mousePos;
    84 
     78    /**
     79     * The position of the mouse before the user starts to drag it while pressing a button.
     80     */
     81    private Point startingDraggingPos;
     82    /**
     83     * The last known position of the mouse.
     84     */
     85    private Point lastMousePos;
    8586    /**
    8687     * The time of the user mouse down event.
    8788     */
    8889    private long mouseDownTime = 0;
    89 
    9090    /**
    9191     * The time which needs to pass between click and release before something
     
    9393     */
    9494    private int initialMoveDelay;
    95 
    9695    /**
    9796     * The screen distance which needs to be travelled before something
     
    106105     */
    107106    public SelectAction(MapFrame mapFrame) {
    108         super(tr("Select"), "move/move", tr("Select, move and rotate objects"),
     107        super(tr("Select"), "move/move", tr("Select, move, scale and rotate objects"),
    109108                Shortcut.registerShortcut("mapmode:select", tr("Mode: {0}", tr("Select")), KeyEvent.VK_S, Shortcut.GROUP_EDIT),
    110109                mapFrame,
     
    113112        putValue("help", "Action/Move/Move");
    114113        selectionManager = new SelectionManager(this, false, mv);
    115         initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
    116         initialMoveThreshold = Main.pref.getInteger("edit.initial-move-threshold",5);
     114        initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay", 200);
     115        initialMoveThreshold = Main.pref.getInteger("edit.initial-move-threshold", 5);
    117116    }
    118117
     
    139138    }
    140139
    141     @Override public void enterMode() {
     140    @Override
     141    public void enterMode() {
    142142        super.enterMode();
    143143        mv.addMouseListener(this);
     
    147147    }
    148148
    149     @Override public void exitMode() {
     149    @Override
     150    public void exitMode() {
    150151        super.exitMode();
    151152        selectionManager.unregister(mv);
     
    160161     * mouse (which will become selected).
    161162     */
    162     @Override public void mouseDragged(MouseEvent e) {
    163         if(!mv.isActiveLayerVisible())
     163    @Override
     164    public void mouseDragged(MouseEvent e) {
     165        if (!mv.isActiveLayerVisible())
    164166            return;
    165167
    166168        cancelDrawMode = true;
    167         if (mode == Mode.select) return;
     169        if (mode == Mode.select)
     170            return;
    168171
    169172        // do not count anything as a move if it lasts less than 100 milliseconds.
    170         if ((mode == Mode.move) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
    171 
    172         if(mode != Mode.rotate) // button is pressed in rotate mode
     173        if ((mode == Mode.move) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay))
     174            return;
     175
     176        if (mode != Mode.rotate && mode != Mode.scale) // button is pressed in rotate mode
     177        {
    173178            if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
    174179                return;
     180        }
    175181
    176182        if (mode == Mode.move) {
     
    178184        }
    179185
     186        if (startingDraggingPos == null) {
     187            startingDraggingPos = new Point(e.getX(), e.getY());
     188        }
     189
    180190        if (!initialMoveThresholdExceeded) {
    181             int dxp = mousePos.x - e.getX();
    182             int dyp = mousePos.y - e.getY();
    183             int dp = (int) Math.sqrt(dxp*dxp+dyp*dyp);
    184             if (dp < initialMoveThreshold) return;
     191            int dxp = lastMousePos.x - e.getX();
     192            int dyp = lastMousePos.y - e.getY();
     193            int dp = (int) Math.sqrt(dxp * dxp + dyp * dyp);
     194            if (dp < initialMoveThreshold)
     195                return;
    185196            initialMoveThresholdExceeded = true;
    186197        }
    187198
    188         EastNorth mouseEN = mv.getEastNorth(e.getX(), e.getY());
    189         EastNorth mouseStartEN = mv.getEastNorth(mousePos.x, mousePos.y);
    190         double dx = mouseEN.east() - mouseStartEN.east();
    191         double dy = mouseEN.north() - mouseStartEN.north();
     199        EastNorth currentEN = mv.getEastNorth(e.getX(), e.getY());
     200        EastNorth lastEN = mv.getEastNorth(lastMousePos.x, lastMousePos.y);
     201        //EastNorth startEN = mv.getEastNorth(startingDraggingPos.x, startingDraggingPos.y);
     202        double dx = currentEN.east() - lastEN.east();
     203        double dy = currentEN.north() - lastEN.north();
    192204        if (dx == 0 && dy == 0)
    193205            return;
     
    199211                Way w = virtualWay.way;
    200212                Way wnew = new Way(w);
    201                 wnew.addNode(virtualWay.lowerIndex+1, virtualNode);
     213                wnew.addNode(virtualWay.lowerIndex + 1, virtualNode);
    202214                virtualCmds.add(new ChangeCommand(w, wnew));
    203215            }
     
    207219                    virtualWays.size());
    208220            Main.main.undoRedo.add(new SequenceCommand(text, virtualCmds));
    209             getCurrentDataSet().setSelected(Collections.singleton((OsmPrimitive)virtualNode));
     221            getCurrentDataSet().setSelected(Collections.singleton((OsmPrimitive) virtualNode));
    210222            virtualWays.clear();
    211223            virtualNode = null;
    212224        } else {
    213             // Currently we support moving and rotating, which do not affect relations.
     225            // Currently we support only transformations which do not affect relations.
    214226            // So don't add them in the first place to make handling easier
    215227            Collection<OsmPrimitive> selection = getCurrentDataSet().getSelectedNodesAndWays();
    216228            Collection<Node> affectedNodes = AllNodesVisitor.getAllNodes(selection);
    217229
    218             // when rotating, having only one node makes no sense - quit silently
    219             if (mode == Mode.rotate && affectedNodes.size() < 2)
     230            // for these transformations, having only one node makes no sense - quit silently
     231            if (affectedNodes.size() < 2 && (mode == Mode.rotate || mode == Mode.scale))
    220232                return;
    221233
    222234            Command c = !Main.main.undoRedo.commands.isEmpty()
    223             ? Main.main.undoRedo.commands.getLast() : null;
     235                    ? Main.main.undoRedo.commands.getLast() : null;
    224236            if (c instanceof SequenceCommand) {
    225                 c = ((SequenceCommand)c).getLastCommand();
     237                c = ((SequenceCommand) c).getLastCommand();
    226238            }
    227239
    228240            if (mode == Mode.move) {
    229                 if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand)c).getParticipatingPrimitives())) {
    230                     ((MoveCommand)c).moveAgain(dx,dy);
     241                if (c instanceof MoveCommand && affectedNodes.equals(((MoveCommand) c).getParticipatingPrimitives())) {
     242                    ((MoveCommand) c).moveAgain(dx, dy);
    231243                } else {
    232244                    Main.main.undoRedo.add(
     
    243255                                tr("Cannot move objects outside of the world."),
    244256                                tr("Warning"),
    245                                 JOptionPane.WARNING_MESSAGE
    246 
    247                         );
     257                                JOptionPane.WARNING_MESSAGE);
    248258                        restoreCursor();
    249259                        return;
     
    251261                }
    252262            } else if (mode == Mode.rotate) {
    253                 if (c instanceof RotateCommand && affectedNodes.equals(((RotateCommand)c).getRotatedNodes())) {
    254                     ((RotateCommand)c).rotateAgain(mouseStartEN, mouseEN);
     263                if (c instanceof RotateCommand && affectedNodes.equals(((RotateCommand) c).getTransformedNodes())) {
     264                    ((RotateCommand) c).handleEvent(currentEN);
    255265                } else {
    256                     Main.main.undoRedo.add(new RotateCommand(selection, mouseStartEN, mouseEN));
     266                    Main.main.undoRedo.add(new RotateCommand(selection, currentEN));
     267                }
     268            } else if (mode == Mode.scale) {
     269                if (c instanceof ScaleCommand && affectedNodes.equals(((ScaleCommand) c).getTransformedNodes())) {
     270                    ((ScaleCommand) c).handleEvent(currentEN);
     271                } else {
     272                    Main.main.undoRedo.add(new ScaleCommand(selection, currentEN));
    257273                }
    258274            }
     
    260276
    261277        mv.repaint();
    262         mousePos = e.getPoint();
     278        if (mode != Mode.scale) {
     279            lastMousePos = e.getPoint();
     280        }
    263281
    264282        didMouseDrag = true;
    265283    }
    266284
    267     @Override public void mouseMoved(MouseEvent e) {
     285    @Override
     286    public void mouseMoved(MouseEvent e) {
    268287        // Mac OSX simulates with  ctrl + mouse 1  the second mouse button hence no dragging events get fired.
    269288        //
    270         if ((Main.platform instanceof PlatformHookOsx) && mode == Mode.rotate) {
     289        if ((Main.platform instanceof PlatformHookOsx) && (mode == Mode.rotate || mode == Mode.scale)) {
    271290            mouseDragged(e);
    272291        }
    273292    }
    274 
    275293    private Node virtualNode = null;
    276294    private Collection<WaySegment> virtualWays = new LinkedList<WaySegment>();
     
    295313            Way w = null;
    296314
    297             for(WaySegment ws : mv.getNearestWaySegments(p, OsmPrimitive.isSelectablePredicate)) {
     315            for (WaySegment ws : mv.getNearestWaySegments(p, OsmPrimitive.isSelectablePredicate)) {
    298316                w = ws.way;
    299317
    300318                Point2D p1 = mv.getPoint2D(wnp.a = w.getNode(ws.lowerIndex));
    301                 Point2D p2 = mv.getPoint2D(wnp.b = w.getNode(ws.lowerIndex+1));
    302                 if(SimplePaintVisitor.isLargeSegment(p1, p2, virtualSpace))
    303                 {
    304                     Point2D pc = new Point2D.Double((p1.getX()+p2.getX())/2, (p1.getY()+p2.getY())/2);
    305                     if (p.distanceSq(pc) < virtualSnapDistSq)
    306                     {
     319                Point2D p2 = mv.getPoint2D(wnp.b = w.getNode(ws.lowerIndex + 1));
     320                if (SimplePaintVisitor.isLargeSegment(p1, p2, virtualSpace)) {
     321                    Point2D pc = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2);
     322                    if (p.distanceSq(pc) < virtualSnapDistSq) {
    307323                        // Check that only segments on top of each other get added to the
    308324                        // virtual ways list. Otherwise ways that coincidentally have their
     
    327343        return !virtualWays.isEmpty();
    328344    }
    329 
    330345    private Collection<OsmPrimitive> cycleList = Collections.emptyList();
    331346    private boolean cyclePrims = false;
     
    347362            boolean waitForMouseUp = Main.pref.getBoolean("mappaint.select.waits-for-mouse-up", false);
    348363            boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    349             boolean alt = ((e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0
    350                     || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false));
     364            boolean alt = ((e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0 || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false));
    351365
    352366            if (!alt) {
     
    364378                }
    365379
    366                 if (cycleList.size()>1) {
     380                if (cycleList.size() > 1) {
    367381                    cyclePrims = false;
    368382
     
    378392                    // special case:  for cycle groups of 2, we can toggle to the
    379393                    // true nearest primitive on mousePressed right away
    380                     if (cycleList.size()==2 && !waitForMouseUp) {
     394                    if (cycleList.size() == 2 && !waitForMouseUp) {
    381395                        if (!(osm.equals(old) || osm.isNew() || ctrl)) {
    382396                            cyclePrims = false;
     
    405419     * cursor to movement.
    406420     */
    407     @Override public void mousePressed(MouseEvent e) {
     421    @Override
     422    public void mousePressed(MouseEvent e) {
    408423        debug("mousePressed: e.getPoint()=" + e.getPoint());
    409424
    410425        // return early
    411         if(!mv.isActiveLayerVisible()
    412                 || !(Boolean)this.getValue("active")
    413                 || e.getButton() != MouseEvent.BUTTON1)
     426        if (!mv.isActiveLayerVisible() || !(Boolean) this.getValue("active") || e.getButton() != MouseEvent.BUTTON1) {
    414427            return;
     428        }
    415429
    416430        // request focus in order to enable the expected keyboard shortcuts
     
    419433        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    420434        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     435        boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
    421436
    422437        // We don't want to change to draw tool if the user tries to (de)select
     
    426441        initialMoveThresholdExceeded = false;
    427442        mouseDownTime = System.currentTimeMillis();
    428         mousePos = e.getPoint();
     443        lastMousePos = e.getPoint();
    429444
    430445        Collection<OsmPrimitive> c = MapView.asColl(
     
    443458            setCursor(ImageProvider.getCursor("rotate", null));
    444459            mv.repaint();
     460        } else if (alt && ctrl) {
     461            mode = Mode.scale;
     462
     463            if (getCurrentDataSet().getSelected().isEmpty()) {
     464                getCurrentDataSet().setSelected(c);
     465            }
     466
     467            // Mode.select redraws when selectPrims is called
     468            // Mode.move   redraws when mouseDragged is called
     469            // Mode.scale redraws here
     470            setCursor(ImageProvider.getCursor("scale", null));
     471            mv.repaint();
    445472        } else if (!c.isEmpty()) {
    446473            mode = Mode.move;
     
    466493        debug("mouseReleased: e.getPoint()=" + e.getPoint());
    467494
    468         if(!mv.isActiveLayerVisible())
     495        if (!mv.isActiveLayerVisible()) {
    469496            return;
     497        }
     498
     499        startingDraggingPos = null;
    470500
    471501        restoreCursor();
     
    474504
    475505            // Select Draw Tool if no selection has been made
    476             if(getCurrentDataSet().getSelected().size() == 0 && !cancelDrawMode) {
     506            if (getCurrentDataSet().getSelected().size() == 0 && !cancelDrawMode) {
    477507                Main.map.selectDrawTool(true);
    478508                return;
     
    488518                // do nothing if the click was to short to be recognized as a drag,
    489519                // but the release position is farther than 10px away from the press position
    490                 if (mousePos.distanceSq(e.getPoint())<100) {
     520                if (lastMousePos.distanceSq(e.getPoint()) < 100) {
    491521                    selectPrims(cyclePrims(cycleList, e), e, true, false);
    492522
    493523                    // If the user double-clicked a node, change to draw mode
    494524                    Collection<OsmPrimitive> c = getCurrentDataSet().getSelected();
    495                     if(e.getClickCount() >=2 && c.size() == 1 && c.iterator().next() instanceof Node) {
     525                    if (e.getClickCount() >= 2 && c.size() == 1 && c.iterator().next() instanceof Node) {
    496526                        // We need to do it like this as otherwise drawAction will see a double
    497527                        // click and switch back to SelectMode
    498                         Main.worker.execute(new Runnable(){
     528                        Main.worker.execute(new Runnable() {
     529
    499530                            public void run() {
    500531                                Main.map.selectDrawTool(true);
     
    508539                for (OsmPrimitive osm : getCurrentDataSet().getSelected()) {
    509540                    if (osm instanceof Way) {
    510                         limit -= ((Way)osm).getNodes().size();
     541                        limit -= ((Way) osm).getNodes().size();
    511542                    }
    512543                    if ((limit -= 1) < 0) {
     
    518549                            Main.parent,
    519550                            tr("Move elements"),
    520                             new String[] {tr("Move them"), tr("Undo move")});
    521                     ed.setButtonIcons(new String[] {"reorder.png", "cancel.png"});
    522                     ed.setContent(tr("You moved more than {0} elements. "
    523                             + "Moving a large number of elements is often an error.\n"
    524                             + "Really move them?", max));
     551                            new String[]{tr("Move them"), tr("Undo move")});
     552                    ed.setButtonIcons(new String[]{"reorder.png", "cancel.png"});
     553                    ed.setContent(tr("You moved more than {0} elements. " + "Moving a large number of elements is often an error.\n" + "Really move them?", max));
    525554                    ed.setCancelButton(2);
    526555                    ed.toggleEnable("movedManyElements");
    527556                    ed.showDialog();
    528557
    529                     if(ed.getValue() != 1) {
     558                    if (ed.getValue() != 1) {
    530559                        Main.main.undoRedo.undo();
    531560                    }
     
    572601            nxt = first;
    573602
    574             for (Iterator<OsmPrimitive> i = prims.iterator(); i.hasNext(); ) {
     603            for (Iterator<OsmPrimitive> i = prims.iterator(); i.hasNext();) {
    575604                if (cyclePrims && shift) {
    576605                    if (!(nxt = i.next()).isSelected()) {
     
    631660
    632661                Command cmd = MergeNodesAction.mergeNodes(Main.main.getEditLayer(), nodesToMerge, target.iterator().next());
    633                 if(cmd != null) {
     662                if (cmd != null) {
    634663                    Main.main.undoRedo.add(cmd);
    635664                }
     
    644673
    645674        // not allowed together: do not change dataset selection, return early
    646         if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty()))
     675        if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty())) {
    647676            return;
     677        }
    648678
    649679        if (!released) {
     
    672702    }
    673703
    674     @Override public String getModeHelpText() {
    675         if (mode == Mode.select)
     704    @Override
     705    public String getModeHelpText() {
     706        if (mode == Mode.select) {
    676707            return tr("Release the mouse button to select the objects in the rectangle.");
    677         else if (mode == Mode.move)
     708        } else if (mode == Mode.move) {
    678709            return tr("Release the mouse button to stop moving. Ctrl to merge with nearest node.");
    679         else if (mode == Mode.rotate)
     710        } else if (mode == Mode.rotate) {
    680711            return tr("Release the mouse button to stop rotating.");
    681         else
    682             return tr("Move objects by dragging; Shift to add to selection (Ctrl to toggle); Shift-Ctrl to rotate selected; or change selection");
    683     }
    684 
    685     @Override public boolean layerIsSupported(Layer l) {
     712        } else if (mode == Mode.scale) {
     713            return tr("Release the mouse button to stop scaling.");
     714        } else {
     715            return tr("Move objects by dragging; Shift to add to selection (Ctrl to toggle); Shift-Ctrl to rotate selected; Alt-Ctrl to scale selected; or change selection");
     716        }
     717    }
     718
     719    @Override
     720    public boolean layerIsSupported(Layer l) {
    686721        return l instanceof OsmDataLayer;
    687722    }
  • trunk/src/org/openstreetmap/josm/command/RotateCommand.java

    r3262 r3702  
     1// License: GPL. For details, see LICENSE file.
    12package org.openstreetmap.josm.command;
    23
     
    45
    56import java.util.Collection;
    6 import java.util.HashMap;
    7 import java.util.LinkedList;
    8 import java.util.Map;
    97
    108import javax.swing.JLabel;
    119
    1210import org.openstreetmap.josm.data.coor.EastNorth;
    13 import org.openstreetmap.josm.data.coor.LatLon;
    1411import org.openstreetmap.josm.data.osm.Node;
    1512import org.openstreetmap.josm.data.osm.OsmPrimitive;
    16 import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
    1713import org.openstreetmap.josm.tools.ImageProvider;
    1814
     
    2218 * @author Frederik Ramm <frederik@remote.org>
    2319 */
    24 public class RotateCommand extends Command {
     20public class RotateCommand extends TransformNodesCommand {
    2521
    2622    /**
    27      * The objects to rotate.
    28      */
    29     private Collection<Node> nodes = new LinkedList<Node>();
    30 
    31     /**
    32      * pivot point
     23     * Pivot point
    3324     */
    3425    private EastNorth pivot;
    3526
    3627    /**
    37      * Small helper for holding the interesting part of the old data state of the
    38      * objects.
     28     * World position of the mouse when the user started the command.
     29     *
    3930     */
    40     public static class OldState {
    41         LatLon latlon;
    42         EastNorth eastNorth;
    43         boolean modified;
    44     }
     31    EastNorth startEN = null;
    4532
    4633    /**
    4734     * angle of rotation starting click to pivot
    4835     */
    49     private double startAngle;
     36    private double startAngle = 0.0;
    5037
    5138    /**
    5239     * computed rotation angle between starting click and current mouse pos
    5340     */
    54     private double rotationAngle;
    55 
    56     /**
    57      * List of all old states of the objects.
    58      */
    59     private Map<Node, OldState> oldState = new HashMap<Node, OldState>();
     41    private double rotationAngle = 0.0;
    6042
    6143    /**
    6244     * Creates a RotateCommand.
    63      * Assign the initial object set, compute pivot point and rotation angle.
    64      * Computation of pivot point is done by the same rules that are used in
    65      * the "align nodes in circle" action.
     45     * Assign the initial object set, compute pivot point and inital rotation angle.
    6646     */
    67     public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {
     47    public RotateCommand(Collection<OsmPrimitive> objects, EastNorth currentEN) {
     48        super(objects);
    6849
    69         this.nodes = AllNodesVisitor.getAllNodes(objects);
    70         pivot = new EastNorth(0,0);
     50        pivot = getNodesCenter();
    7151
    72         for (Node n : this.nodes) {
    73             OldState os = new OldState();
    74             os.latlon = new LatLon(n.getCoor());
    75             os.eastNorth = n.getEastNorth();
    76             os.modified = n.isModified();
    77             oldState.put(n, os);
    78             pivot = pivot.add(os.eastNorth.east(), os.eastNorth.north());
    79         }
    80         pivot = new EastNorth(pivot.east()/this.nodes.size(), pivot.north()/this.nodes.size());
     52        // We remember the very first position of the mouse for this action.
     53        // Note that SelectAction will keep the same ScaleCommand when the user
     54        // releases the button and presses it again with the same modifiers.
     55        // The very first point of this operation is stored here.
     56        startEN   = currentEN;
    8157
    82         rotationAngle = Math.PI/2;
    83         rotateAgain(start, end);
     58        startAngle = getAngle(currentEN);
     59        rotationAngle = 0.0;
     60
     61        handleEvent(currentEN);
     62    }
     63   
     64    /**
     65     * Get angle between the horizontal axis and the line formed by the pivot and give points.
     66     **/
     67    protected double getAngle(EastNorth currentEN) {
     68        if ( pivot == null )
     69            return 0.0; // should never happen by contract
     70        return Math.atan2(currentEN.east()-pivot.east(), currentEN.north()-pivot.north());
    8471    }
    8572
    8673    /**
    87      * Rotate the same set of objects again, by the angle between given
    88      * start and end nodes. Internally this is added to the existing
    89      * rotation so a later undo will undo the whole rotation.
     74     * Compute new rotation angle and transform nodes accordingly.
    9075     */
    91     public void rotateAgain(EastNorth start, EastNorth end) {
    92         // compute angle
    93         startAngle = Math.atan2(start.east()-pivot.east(), start.north()-pivot.north());
    94         double endAngle = Math.atan2(end.east()-pivot.east(), end.north()-pivot.north());
    95         rotationAngle += startAngle - endAngle;
    96         rotateNodes(false);
     76    @Override
     77    public void handleEvent(EastNorth currentEN) {
     78        double currentAngle = getAngle(currentEN);
     79        rotationAngle = currentAngle - startAngle;
     80        transformNodes();
    9781    }
    9882
    9983    /**
    100      * Helper for actually rotationg the nodes.
    101      * @param setModified - true if rotated nodes should be flagged "modified"
     84     * Rotate nodes.
    10285     */
    103     private void rotateNodes(boolean setModified) {
     86    @Override
     87    protected void transformNodes() {
    10488        for (Node n : nodes) {
    10589            double cosPhi = Math.cos(rotationAngle);
    10690            double sinPhi = Math.sin(rotationAngle);
    107             EastNorth oldEastNorth = oldState.get(n).eastNorth;
     91            EastNorth oldEastNorth = oldStates.get(n).eastNorth;
    10892            double x = oldEastNorth.east() - pivot.east();
    10993            double y = oldEastNorth.north() - pivot.north();
    110             double nx =  sinPhi * x + cosPhi * y + pivot.east();
    111             double ny = -cosPhi * x + sinPhi * y + pivot.north();
     94            double nx =  cosPhi * x + sinPhi * y + pivot.east();
     95            double ny = -sinPhi * x + cosPhi * y + pivot.north();
    11296            n.setEastNorth(new EastNorth(nx, ny));
    113             if (setModified) {
    114                 n.setModified(true);
    115             }
    11697        }
    11798    }
    11899
    119     @Override public boolean executeCommand() {
    120         rotateNodes(true);
    121         return true;
    122     }
    123 
    124     @Override public void undoCommand() {
    125         for (Node n : nodes) {
    126             OldState os = oldState.get(n);
    127             n.setCoor(os.latlon);
    128             n.setModified(os.modified);
    129         }
    130     }
    131 
    132     @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
    133         for (OsmPrimitive osm : nodes) {
    134             modified.add(osm);
    135         }
    136     }
    137 
    138     @Override public JLabel getDescription() {
     100    @Override
     101    public JLabel getDescription() {
    139102        return new JLabel(trn("Rotate {0} node", "Rotate {0} nodes", nodes.size(), nodes.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL);
    140103    }
    141 
    142     public Collection<Node> getRotatedNodes() {
    143         return nodes;
    144     }
    145104}
Note: See TracChangeset for help on using the changeset viewer.