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

Last change on this file since 1750 was 1750, checked in by Gubaer, 15 years ago

new: replaced global conflict list by conflict list per layer, similar to datasets

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