001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.command; 003 004import static org.openstreetmap.josm.tools.I18n.trn; 005 006import java.util.Collection; 007 008import javax.swing.Icon; 009 010import org.openstreetmap.josm.data.coor.EastNorth; 011import org.openstreetmap.josm.data.osm.Node; 012import org.openstreetmap.josm.data.osm.OsmPrimitive; 013import org.openstreetmap.josm.tools.ImageProvider; 014 015/** 016 * RotateCommand rotates a number of objects around their centre. 017 * 018 * @author Frederik Ramm <frederik@remote.org> 019 */ 020public class RotateCommand extends TransformNodesCommand { 021 022 /** 023 * Pivot point 024 */ 025 private EastNorth pivot; 026 027 /** 028 * angle of rotation starting click to pivot 029 */ 030 private double startAngle = 0.0; 031 032 /** 033 * computed rotation angle between starting click and current mouse pos 034 */ 035 private double rotationAngle = 0.0; 036 037 /** 038 * Creates a RotateCommand. 039 * Assign the initial object set, compute pivot point and inital rotation angle. 040 */ 041 public RotateCommand(Collection<OsmPrimitive> objects, EastNorth currentEN) { 042 super(objects); 043 044 pivot = getNodesCenter(); 045 startAngle = getAngle(currentEN); 046 rotationAngle = 0.0; 047 048 handleEvent(currentEN); 049 } 050 051 /** 052 * Get angle between the horizontal axis and the line formed by the pivot and give points. 053 **/ 054 protected double getAngle(EastNorth currentEN) { 055 if ( pivot == null ) 056 return 0.0; // should never happen by contract 057 return Math.atan2(currentEN.east()-pivot.east(), currentEN.north()-pivot.north()); 058 } 059 060 /** 061 * Compute new rotation angle and transform nodes accordingly. 062 */ 063 @Override 064 public void handleEvent(EastNorth currentEN) { 065 double currentAngle = getAngle(currentEN); 066 rotationAngle = currentAngle - startAngle; 067 transformNodes(); 068 } 069 070 /** 071 * Rotate nodes. 072 */ 073 @Override 074 protected void transformNodes() { 075 for (Node n : nodes) { 076 double cosPhi = Math.cos(rotationAngle); 077 double sinPhi = Math.sin(rotationAngle); 078 EastNorth oldEastNorth = oldStates.get(n).eastNorth; 079 double x = oldEastNorth.east() - pivot.east(); 080 double y = oldEastNorth.north() - pivot.north(); 081 double nx = cosPhi * x + sinPhi * y + pivot.east(); 082 double ny = -sinPhi * x + cosPhi * y + pivot.north(); 083 n.setEastNorth(new EastNorth(nx, ny)); 084 } 085 } 086 087 @Override 088 public String getDescriptionText() { 089 return trn("Rotate {0} node", "Rotate {0} nodes", nodes.size(), nodes.size()); 090 } 091 092 @Override 093 public Icon getDescriptionIcon() { 094 return ImageProvider.get("data", "node"); 095 } 096}