Logo Search packages:      
Sourcecode: josm version File versions  Download package

RotateCommand.java

package org.openstreetmap.josm.command;

import static org.openstreetmap.josm.tools.I18n.tr;
import static org.openstreetmap.josm.tools.I18n.trn;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.swing.JLabel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
import org.openstreetmap.josm.tools.ImageProvider;

/**
 * RotateCommand rotates a number of objects around their centre.
 * 
 * @author Frederik Ramm <frederik@remote.org>
 */
00028 public class RotateCommand extends Command {
      
      /**
       * The objects to rotate.
       */
00033       public Collection<Node> objects = new LinkedList<Node>();
      
      /**
       * pivot point
       */
00038       private Node pivot;
      
      /**
       * angle of rotation starting click to pivot
       */
00043       private double startAngle;
      
      /**
       * computed rotation angle between starting click and current mouse pos
       */
00048       private double rotationAngle;
      
      /**
       * List of all old states of the objects.
       */
00053       private Map<Node, MoveCommand.OldState> oldState = new HashMap<Node, MoveCommand.OldState>();
      
      /**
       * Creates a RotateCommand.
       * Assign the initial object set, compute pivot point and rotation angle.
       * Computation of pivot point is done by the same rules that are used in 
       * the "align nodes in circle" action.
       */
00061       public RotateCommand(Collection<OsmPrimitive> objects, EastNorth start, EastNorth end) {

            this.objects = AllNodesVisitor.getAllNodes(objects);
            pivot = new Node(new LatLon(0,0));
                  
            for (Node n : this.objects) {
                  MoveCommand.OldState os = new MoveCommand.OldState();
                  os.eastNorth = n.eastNorth;
                  os.latlon = n.coor;
                  os.modified = n.modified;
                  oldState.put(n, os);
                  pivot.eastNorth = new EastNorth(pivot.eastNorth.east()+os.eastNorth.east(), pivot.eastNorth.north()+os.eastNorth.north());
                  pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);
            }
            pivot.eastNorth = new EastNorth(pivot.eastNorth.east()/this.objects.size(), pivot.eastNorth.north()/this.objects.size());
            pivot.coor = Main.proj.eastNorth2latlon(pivot.eastNorth);   

            rotationAngle = Math.PI/2;
            rotateAgain(start, end);
      }

      /**
       * Rotate the same set of objects again, by the angle between given 
       * start and end nodes. Internally this is added to the existing
       * rotation so a later undo will undo the whole rotation.
       */
00087       public void rotateAgain(EastNorth start, EastNorth end) {
            // compute angle
            startAngle = Math.atan2(start.east()-pivot.eastNorth.east(), start.north()-pivot.eastNorth.north());
            double endAngle = Math.atan2(end.east()-pivot.eastNorth.east(), end.north()-pivot.eastNorth.north());
            rotationAngle += startAngle - endAngle;         
            rotateNodes(false);
      }
      
      /**
       * Helper for actually rotationg the nodes.
       * @param setModified - true if rotated nodes should be flagged "modified"
       */
00099       private void rotateNodes(boolean setModified) {
            for (Node n : objects) {
                  double cosPhi = Math.cos(rotationAngle);
                  double sinPhi = Math.sin(rotationAngle);
                  EastNorth oldEastNorth = oldState.get(n).eastNorth;
                  double x = oldEastNorth.east() - pivot.eastNorth.east();
                  double y = oldEastNorth.north() - pivot.eastNorth.north();
                  double nx =  sinPhi * x + cosPhi * y + pivot.eastNorth.east();
                  double ny = -cosPhi * x + sinPhi * y + pivot.eastNorth.north();
                  n.eastNorth = new EastNorth(nx, ny);
                  n.coor = Main.proj.eastNorth2latlon(n.eastNorth);
                  if (setModified)
                        n.modified = true;      
            }
      }
      
00115       @Override public void executeCommand() {
            rotateNodes(true);
      }

00119       @Override public void undoCommand() {
            for (Node n : objects) {
                  MoveCommand.OldState os = oldState.get(n);
                  n.eastNorth = os.eastNorth;
                  n.coor = os.latlon;
                  n.modified = os.modified;
            }
      }

00128       @Override public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) {
            for (OsmPrimitive osm : objects)
                  modified.add(osm);
      }

      @Override public MutableTreeNode description() {
            return new DefaultMutableTreeNode(new JLabel(tr("Rotate")+" "+objects.size()+" "+trn("node","nodes",objects.size()), ImageProvider.get("data", "node"), JLabel.HORIZONTAL));
    }
}

Generated by  Doxygen 1.6.0   Back to index