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; 007import java.util.HashMap; 008import java.util.LinkedList; 009import java.util.Map; 010 011import javax.swing.Icon; 012 013import org.openstreetmap.josm.data.coor.EastNorth; 014import org.openstreetmap.josm.data.osm.Node; 015import org.openstreetmap.josm.data.osm.OsmPrimitive; 016import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor; 017import org.openstreetmap.josm.tools.ImageProvider; 018 019/** 020 * Abstract class with common services for nodes rotation and scaling commands. 021 * 022 * @author Olivier Croquette <ocroquette@free.fr> 023 */ 024public abstract class TransformNodesCommand extends Command { 025 026 /** 027 * The nodes to transform. 028 */ 029 protected Collection<Node> nodes = new LinkedList<>(); 030 031 032 /** 033 * List of all old states of the nodes. 034 */ 035 protected Map<Node, OldNodeState> oldStates = new HashMap<>(); 036 037 /** 038 * Stores the state of the nodes before the command. 039 */ 040 protected final void storeOldState() { 041 for (Node n : this.nodes) { 042 oldStates.put(n, new OldNodeState(n)); 043 } 044 } 045 046 /** 047 * Creates a TransformNodesObject. 048 * Find out the impacted nodes and store their initial state. 049 */ 050 public TransformNodesCommand(Collection<OsmPrimitive> objects) { 051 this.nodes = AllNodesVisitor.getAllNodes(objects); 052 storeOldState(); 053 } 054 055 /** 056 * Handling of a mouse event (e.g. dragging event). 057 * @param currentEN the current world position of the mouse 058 */ 059 public abstract void handleEvent(EastNorth currentEN); 060 061 /** 062 * Implementation for the nodes transformation. 063 * No parameters are given here, you should handle the user input in handleEvent() 064 * and store it internally. 065 */ 066 protected abstract void transformNodes(); 067 068 /** 069 * Finally apply the transformation of the nodes. 070 * This is called when the user is happy with the current state of the command 071 * and its effects. 072 */ 073 @Override 074 public boolean executeCommand() { 075 transformNodes(); 076 flagNodesAsModified(); 077 return true; 078 } 079 080 /** 081 * Flag all nodes as modified. 082 */ 083 public void flagNodesAsModified() { 084 for (Node n : nodes) { 085 n.setModified(true); 086 } 087 } 088 089 /** 090 * Restore the state of the nodes from the backup. 091 */ 092 @Override 093 public void undoCommand() { 094 for (Node n : nodes) { 095 OldNodeState os = oldStates.get(n); 096 n.setCoor(os.latlon); 097 n.setModified(os.modified); 098 } 099 } 100 101 @Override 102 public void fillModifiedData(Collection<OsmPrimitive> modified, Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 103 } 104 105 @Override 106 public Collection<? extends OsmPrimitive> getParticipatingPrimitives() { 107 return nodes; 108 } 109 110 @Override 111 public String getDescriptionText() { 112 return trn("Transform {0} node", "Transform {0} nodes", nodes.size(), nodes.size()); 113 } 114 115 @Override 116 public Icon getDescriptionIcon() { 117 return ImageProvider.get("data", "node"); 118 } 119 120 /** 121 * Get the nodes with the current transformation applied. 122 */ 123 public Collection<Node> getTransformedNodes() { 124 return nodes; 125 } 126 127 /** 128 * Get the center of the nodes under modification. 129 * It's just the barycenter. 130 * @see org.openstreetmap.josm.tools.Geometry#getCentroid(java.util.List) 131 */ 132 public EastNorth getNodesCenter() { 133 EastNorth sum = new EastNorth(0,0); 134 135 for (Node n : nodes ) { 136 EastNorth en = n.getEastNorth(); 137 sum = sum.add(en.east(), en.north()); 138 } 139 return new EastNorth(sum.east()/this.nodes.size(), sum.north()/this.nodes.size()); 140 141 } 142}