source: josm/trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java@ 1169

Last change on this file since 1169 was 1169, checked in by stoecker, 15 years ago

removed usage of tab stops

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions.mapmode;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.BasicStroke;
8import java.awt.Color;
9import java.awt.Cursor;
10import java.awt.Graphics;
11import java.awt.Graphics2D;
12import java.awt.Point;
13import java.awt.event.KeyEvent;
14import java.awt.event.MouseEvent;
15import java.awt.geom.GeneralPath;
16import java.util.Collection;
17import java.util.LinkedList;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.command.AddCommand;
21import org.openstreetmap.josm.command.ChangeCommand;
22import org.openstreetmap.josm.command.Command;
23import org.openstreetmap.josm.command.SequenceCommand;
24import org.openstreetmap.josm.data.coor.EastNorth;
25import org.openstreetmap.josm.data.osm.Node;
26import org.openstreetmap.josm.data.osm.Way;
27import org.openstreetmap.josm.data.osm.WaySegment;
28import org.openstreetmap.josm.gui.MapFrame;
29import org.openstreetmap.josm.gui.MapView;
30import org.openstreetmap.josm.gui.layer.MapViewPaintable;
31import org.openstreetmap.josm.tools.ImageProvider;
32import org.openstreetmap.josm.tools.Shortcut;
33
34/**
35 * Makes a rectangle from a line, or modifies a rectangle.
36 *
37 * This class currently contains some "sleeping" code copied from DrawAction (move and rotate)
38 * which can eventually be removed, but it may also get activated here and removed in DrawAction.
39 */
40public class ExtrudeAction extends MapMode implements MapViewPaintable {
41
42 enum Mode { EXTRUDE, rotate, select }
43 private Mode mode = null;
44 private long mouseDownTime = 0;
45 private WaySegment selectedSegment = null;
46 private Color selectedColor;
47
48 double xoff;
49 double yoff;
50 double distance;
51
52 /**
53 * The old cursor before the user pressed the mouse button.
54 */
55 private Cursor oldCursor;
56 /**
57 * The current position of the mouse
58 */
59 private Point mousePos;
60 /**
61 * The position of the mouse cursor when the drag action was initiated.
62 */
63 private Point initialMousePos;
64 /**
65 * The time which needs to pass between click and release before something
66 * counts as a move, in milliseconds
67 */
68 private int initialMoveDelay = 200;
69
70 /**
71 * Create a new SelectAction
72 * @param mapFrame The MapFrame this action belongs to.
73 */
74 public ExtrudeAction(MapFrame mapFrame) {
75 super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
76 Shortcut.registerShortcut("mapmode:extrude", tr("Mode: {0}", tr("Extrude")), KeyEvent.VK_X, Shortcut.GROUP_EDIT),
77 mapFrame,
78 getCursor("normal", "rectangle", Cursor.DEFAULT_CURSOR));
79 putValue("help", "Action/Extrude/Extrude");
80 initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay",200);
81 selectedColor = Main.pref.getColor(marktr("selected"), Color.YELLOW);
82 }
83
84 private static Cursor getCursor(String name, String mod, int def) {
85 try {
86 return ImageProvider.getCursor(name, mod);
87 } catch (Exception e) {
88 }
89 return Cursor.getPredefinedCursor(def);
90 }
91
92 private void setCursor(Cursor c) {
93 if (oldCursor == null) {
94 oldCursor = Main.map.mapView.getCursor();
95 Main.map.mapView.setCursor(c);
96 }
97 }
98
99 private void restoreCursor() {
100 if (oldCursor != null) {
101 Main.map.mapView.setCursor(oldCursor);
102 oldCursor = null;
103 }
104 }
105
106 @Override public void enterMode() {
107 super.enterMode();
108 Main.map.mapView.addMouseListener(this);
109 Main.map.mapView.addMouseMotionListener(this);
110 }
111
112 @Override public void exitMode() {
113 super.exitMode();
114 Main.map.mapView.removeMouseListener(this);
115 Main.map.mapView.removeMouseMotionListener(this);
116 Main.map.mapView.removeTemporaryLayer(this);
117
118 }
119
120 /**
121 * If the left mouse button is pressed, move all currently selected
122 * objects (if one of them is under the mouse) or the current one under the
123 * mouse (which will become selected).
124 */
125 @Override public void mouseDragged(MouseEvent e) {
126 if (mode == Mode.select) return;
127
128 // do not count anything as a move if it lasts less than 100 milliseconds.
129 if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
130
131 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
132 return;
133
134 if (mode == Mode.EXTRUDE) {
135 setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
136 }
137
138 if (mousePos == null) {
139 mousePos = e.getPoint();
140 return;
141 }
142
143 Main.map.mapView.repaint();
144 mousePos = e.getPoint();
145
146 }
147
148 public void paint(Graphics g, MapView mv) {
149 if (selectedSegment != null) {
150 Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
151 Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
152
153 EastNorth en1 = n1.eastNorth;
154 EastNorth en2 = n2.eastNorth;
155 if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
156 EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
157
158 double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
159 // the point on the segment from which the distance to mouse pos is shortest
160 EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
161
162 // the distance, in projection units, between the base point and the mouse cursor
163 double len = base.distance(en3);
164
165 // find out the distance, in metres, between the base point and the mouse cursor
166 distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
167 Main.map.statusLine.setDist(distance);
168 updateStatusLine();
169
170 // compute the angle at which the segment is drawn
171 // and use it to compute the x and y offsets for the
172 // corner points.
173 double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
174
175 // this is a kludge because sometimes extrusion just goes the wrong direction
176 if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
177 xoff = sin_alpha * len;
178 yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
179
180 Graphics2D g2 = (Graphics2D) g;
181 g2.setColor(selectedColor);
182 g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
183 GeneralPath b = new GeneralPath();
184 Point p1=mv.getPoint(en1);
185 Point p2=mv.getPoint(en2);
186 Point p3=mv.getPoint(en1.add(-xoff, -yoff));
187 Point p4=mv.getPoint(en2.add(-xoff, -yoff));
188
189 b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
190 b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
191 b.lineTo(p1.x,p1.y);
192 g2.draw(b);
193 g2.setStroke(new BasicStroke(1));
194 }
195 }
196
197 /**
198 */
199 @Override public void mousePressed(MouseEvent e) {
200 if (!(Boolean)this.getValue("active")) return;
201 if (e.getButton() != MouseEvent.BUTTON1)
202 return;
203 // boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
204 // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
205 // boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
206
207 mouseDownTime = System.currentTimeMillis();
208
209 selectedSegment =
210 Main.map.mapView.getNearestWaySegment(e.getPoint());
211
212 mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
213 oldCursor = Main.map.mapView.getCursor();
214
215 updateStatusLine();
216 Main.map.mapView.addTemporaryLayer(this);
217 Main.map.mapView.repaint();
218
219 mousePos = e.getPoint();
220 initialMousePos = e.getPoint();
221 }
222
223 /**
224 * Restore the old mouse cursor.
225 */
226 @Override public void mouseReleased(MouseEvent e) {
227 restoreCursor();
228 if (selectedSegment == null) return;
229 if (mousePos.distance(initialMousePos) > 10) {
230 Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
231 Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
232 EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
233 Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
234 EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
235 Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
236 Way wnew = new Way(selectedSegment.way);
237 wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
238 wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
239 if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
240 Collection<Command> cmds = new LinkedList<Command>();
241 cmds.add(new AddCommand(n4));
242 cmds.add(new AddCommand(n3));
243 cmds.add(new ChangeCommand(selectedSegment.way, wnew));
244 Command c = new SequenceCommand(tr("Extrude Way"), cmds);
245 Main.main.undoRedo.add(c);
246 }
247
248 Main.map.mapView.removeTemporaryLayer(this);
249 selectedSegment = null;
250 mode = null;
251 updateStatusLine();
252 Main.map.mapView.repaint();
253 }
254
255 @Override public String getModeHelpText() {
256 if (mode == Mode.select) {
257 return tr("Release the mouse button to select the objects in the rectangle.");
258 } else if (mode == Mode.EXTRUDE) {
259 return tr("Draw a rectangle of the desired size, then release the mouse button.");
260 } else if (mode == Mode.rotate) {
261 return tr("Release the mouse button to stop rotating.");
262 } else {
263 return tr("Drag a way segment to make a rectangle.");
264 }
265 }
266}
Note: See TracBrowser for help on using the repository browser.