source: osm/applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java@ 22387

Last change on this file since 22387 was 21493, checked in by pieren, 15 years ago

Improve renaming after municipality selection

File size: 16.0 KB
Line 
1// License: GPL. v2 and later. Copyright 2008-2009 by Pieren <pieren3@gmail.com> and others
2package cadastre_fr;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.MouseEvent;
9import java.awt.event.MouseListener;
10import java.beans.PropertyChangeEvent;
11import java.beans.PropertyChangeListener;
12import java.util.ArrayList;
13
14import javax.swing.JDialog;
15import javax.swing.JLabel;
16import javax.swing.JOptionPane;
17import javax.swing.JPanel;
18import javax.swing.JTextField;
19
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.actions.JosmAction;
22import org.openstreetmap.josm.data.coor.EastNorth;
23import org.openstreetmap.josm.gui.layer.Layer;
24import org.openstreetmap.josm.tools.GBC;
25
26public class MenuActionGrabPlanImage extends JosmAction implements Runnable, MouseListener {
27
28 /**
29 * Action calling the wms grabber for non georeferenced images called "plan image"
30 */
31 private static final long serialVersionUID = 1L;
32
33 public static String name = "Georeference an image";
34
35 private DownloadWMSPlanImage downloadWMSPlanImage;
36 private WMSLayer wmsLayer;
37 private int countMouseClicked = 0;
38 private int mode = 0;
39 private int cGetCorners = 1;
40 private int cGetLambertCrosspieces = 2;
41 private EastNorth ea1;
42 private EastNorth ea2;
43 private long mouseClickedTime = 0;
44 private EastNorth georefpoint1;
45 private EastNorth georefpoint2;
46 private boolean ignoreMouseClick = false;
47 private boolean clickOnTheMap = false;
48
49 /**
50 * The time which needs to pass between two clicks during georeferencing, in milliseconds
51 */
52 private int initialClickDelay;
53
54 public MenuActionGrabPlanImage() {
55 super(tr(name), "cadastre_small", tr("Grab non-georeferenced image"), null, false);
56 }
57
58 public void actionCompleted() {
59 countMouseClicked = 0;
60 mode = 0;
61 mouseClickedTime = System.currentTimeMillis();
62 }
63
64 public void actionInterrupted() {
65 actionCompleted();
66 if (wmsLayer != null) {
67 Main.map.mapView.removeLayer(wmsLayer);
68 wmsLayer = null;
69 }
70 }
71
72 @Override
73 protected void updateEnabledState() {
74 if (wmsLayer == null || Main.map == null || Main.map.mapView == null) return;
75 if (countMouseClicked == 0 && mode == 0) return;
76 for (Layer l : Main.map.mapView.getAllLayersAsList())
77 if (l == wmsLayer)
78 return;
79 JOptionPane.showMessageDialog(Main.parent, tr("Georeferencing interrupted"));
80 actionInterrupted();
81 }
82
83 public void actionPerformed(ActionEvent ae) {
84 if (Main.map != null) {
85 if (CadastrePlugin.isCadastreProjection()) {
86 //wmsLayer = WMSDownloadAction.getLayer();
87 wmsLayer = new MenuActionNewLocation().addNewLayer(new ArrayList<WMSLayer>());
88 if (wmsLayer == null) return;
89 downloadWMSPlanImage = new DownloadWMSPlanImage();
90 downloadWMSPlanImage.download(wmsLayer);
91 initialClickDelay = Main.pref.getInteger("cadastrewms.georef-click-delay",200);
92 // download sub-images of the cadastre scan and join them into one single
93 Main.worker.execute(this);
94 } else {
95 JOptionPane.showMessageDialog(Main.parent,
96 tr("To enable the cadastre WMS plugin, change\n"
97 + "the current projection to one of the cadastre\n"
98 + "projections and retry"));
99 }
100 }
101 }
102
103 public void run() {
104 // wait until plan image is fully loaded and joined into one single image
105 boolean loadedFromCache = downloadWMSPlanImage.waitFinished();
106 if (loadedFromCache) {
107 Main.map.repaint();
108 } else if (wmsLayer.images.size() == 0) {
109 // action cancelled or image loaded from cache (and already georeferenced)
110 actionInterrupted();
111 } else {
112 int reply = JOptionPane.CANCEL_OPTION;
113 if (wmsLayer.isAlreadyGeoreferenced()) {
114 reply = JOptionPane.showConfirmDialog(null,
115 tr("This image contains georeference data.\n"+
116 "Do you want to use them ?"),
117 null,
118 JOptionPane.YES_NO_OPTION);
119 }
120 if (reply == JOptionPane.OK_OPTION) {
121 transformGeoreferencedImg();
122 } else {
123 mouseClickedTime = System.currentTimeMillis();
124 Main.map.mapView.addMouseListener(this);
125 if (Main.pref.getBoolean("cadastrewms.noImageCropping", false) == false)
126 startCropping();
127 else
128 startGeoreferencing();
129 }
130 }
131 }
132
133 public void mouseClicked(MouseEvent e) {
134 if (System.currentTimeMillis() - mouseClickedTime < initialClickDelay) {
135 System.out.println("mouse click bounce detected");
136 return; // mouse click anti-bounce
137 }
138 else
139 mouseClickedTime = System.currentTimeMillis();
140 if (e.getButton() != MouseEvent.BUTTON1)
141 return;
142 if (ignoreMouseClick) return; // In case we are currently just allowing zooming to read lambert coordinates
143 EastNorth ea = Main.proj.latlon2eastNorth(Main.map.mapView.getLatLon(e.getX(), e.getY()));
144 System.out.println("clic:"+countMouseClicked+" ,"+ea+", mode:"+mode);
145 if (clickOnTheMap) {
146 clickOnTheMap = false;
147 handleNewCoordinates(ea.east(), ea.north());
148 } else {
149 countMouseClicked++;
150 // ignore clicks outside the image
151 if (ea.east() < wmsLayer.images.get(0).min.east() || ea.east() > wmsLayer.images.get(0).max.east()
152 || ea.north() < wmsLayer.images.get(0).min.north() || ea.north() > wmsLayer.images.get(0).max.north())
153 return;
154 if (mode == cGetCorners) {
155 if (countMouseClicked == 1) {
156 ea1 = ea;
157 continueCropping();
158 }
159 if (countMouseClicked == 2) {
160 wmsLayer.cropImage(ea1, ea);
161 Main.map.mapView.repaint();
162 startGeoreferencing();
163 }
164 } else if (mode == cGetLambertCrosspieces) {
165 if (countMouseClicked == 1) {
166 ea1 = ea;
167 inputLambertPosition(); // This will automatically asks for second point and continue the georeferencing
168 }
169 if (countMouseClicked == 2) {
170 ea2 = ea;
171 inputLambertPosition(); // This will automatically ends the georeferencing
172 }
173 }
174 }
175 }
176
177 /**
178 *
179 * @return false if all operations are canceled
180 */
181 private boolean startCropping() {
182 mode = cGetCorners;
183 countMouseClicked = 0;
184 Object[] options = { "OK", "Cancel" };
185 int ret = JOptionPane.showOptionDialog( null,
186 tr("Click first corner for image cropping\n(two points required)"),
187 tr("Image cropping"),
188 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
189 null, options, options[0]);
190 if (ret == JOptionPane.OK_OPTION) {
191 mouseClickedTime = System.currentTimeMillis();
192 } else
193 if (canceledOrRestartCurrAction("image cropping"))
194 return startCropping();
195 return true;
196 }
197
198 /**
199 *
200 * @return false if all operations are canceled
201 */
202 private boolean continueCropping() {
203 Object[] options = { "OK", "Cancel" };
204 int ret = JOptionPane.showOptionDialog( null,
205 tr("Click second corner for image cropping"),
206 tr("Image cropping"),
207 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
208 null, options, options[0]);
209 if (ret != JOptionPane.OK_OPTION) {
210 if (canceledOrRestartCurrAction("image cropping"))
211 return startCropping();
212 }
213 return true;
214 }
215
216 /**
217 *
218 * @return false if all operations are canceled
219 */
220 private boolean startGeoreferencing() {
221 countMouseClicked = 0;
222 mode = cGetLambertCrosspieces;
223 Object[] options = { "OK", "Cancel" };
224 int ret = JOptionPane.showOptionDialog( null,
225 tr("Click first Lambert crosspiece for georeferencing\n(two points required)"),
226 tr("Image georeferencing"),
227 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
228 null, options, options[0]);
229 if (ret == JOptionPane.OK_OPTION) {
230 mouseClickedTime = System.currentTimeMillis();
231 } else
232 if (canceledOrRestartCurrAction("georeferencing"))
233 return startGeoreferencing();
234 return true;
235 }
236
237 /**
238 *
239 * @return false if all operations are canceled
240 */
241 private boolean continueGeoreferencing() {
242 Object[] options = { "OK", "Cancel" };
243 int ret = JOptionPane.showOptionDialog( null,
244 tr("Click second Lambert crosspiece for georeferencing"),
245 tr("Image georeferencing"),
246 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
247 null, options, options[0]);
248 if (ret != JOptionPane.OK_OPTION) {
249 if (canceledOrRestartCurrAction("georeferencing"))
250 return startGeoreferencing();
251 }
252 return true;
253 }
254
255 /**
256 * Ends the georeferencing by computing the affine transformation
257 */
258 private void endGeoreferencing() {
259 Main.map.mapView.removeMouseListener(this);
260 affineTransform(ea1, ea2, georefpoint1, georefpoint2);
261 wmsLayer.saveNewCache();
262 Main.map.mapView.repaint();
263 actionCompleted();
264 clickOnTheMap = false;
265 ignoreMouseClick = false;
266 }
267
268 /**
269 *
270 * @return false if all operations are canceled
271 */
272 private boolean canceledOrRestartCurrAction(String action) {
273 Object[] options = { "Cancel", "Retry" };
274 int selectedValue = JOptionPane.showOptionDialog( null,
275 tr("Do you want to cancel completely\n"+
276 "or just retry "+action+" ?"), "",
277 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
278 null, options, options[0]);
279 countMouseClicked = 0;
280 if (selectedValue == 0) { // "Cancel"
281 // remove layer
282 Main.map.mapView.removeLayer(wmsLayer);
283 wmsLayer = null;
284 Main.map.mapView.removeMouseListener(this);
285 return false;
286 }
287 return true;
288 }
289
290 private void inputLambertPosition() {
291 JLabel labelEnterPosition = new JLabel(
292 tr("Enter cadastre east,north position"));
293 JLabel labelWarning = new JLabel(
294 tr("(Warning: verify north with arrow !!)"));
295 JPanel p = new JPanel(new GridBagLayout());
296 JLabel labelEast = new JLabel(tr("East"));
297 JLabel labelNorth = new JLabel(tr("North"));
298 final JTextField inputEast = new JTextField();
299 final JTextField inputNorth = new JTextField();
300 p.add(labelEnterPosition, GBC.eol());
301 p.add(labelWarning, GBC.eol());
302 p.add(labelEast, GBC.std().insets(0, 0, 10, 0));
303 p.add(inputEast, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
304 p.add(labelNorth, GBC.std().insets(0, 0, 10, 0));
305 p.add(inputNorth, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
306 final Object[] options = {tr("OK"),
307 tr("Cancel"),
308 tr("I use the mouse")};
309 final JOptionPane pane = new JOptionPane(p,
310 JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
311 null, options, options[0]);
312 String number;
313 if (countMouseClicked == 1)
314 number = "first";
315 else
316 number = "second";
317 JDialog dialog = pane.createDialog(Main.parent, tr(
318 "Set {0} Lambert coordinates", number));
319 dialog.setModal(false);
320 ignoreMouseClick = true; // To avoid mouseClicked from being called
321 // during coordinates reading
322 dialog.setAlwaysOnTop(true);
323 dialog.setVisible(true);
324 pane.addPropertyChangeListener(new PropertyChangeListener() {
325 public void propertyChange(PropertyChangeEvent evt) {
326 if (JOptionPane.VALUE_PROPERTY.equals(evt.getPropertyName())) {
327 ignoreMouseClick = false;
328 // Cancel
329 if (pane.getValue().equals(options[1])) {
330 if (canceledOrRestartCurrAction("georeferencing"))
331 startGeoreferencing();
332 }
333 // Click on the map
334 if (pane.getValue().equals(options[2])) {
335 clickOnTheMap = true;
336 } else {
337 // OK (coordinates manually entered)
338 clickOnTheMap = false;
339 if (inputEast.getText().length() != 0
340 && inputNorth.getText().length() != 0) {
341 double e, n;
342 try {
343 e = Double.parseDouble(inputEast.getText());
344 n = Double.parseDouble(inputNorth.getText());
345 } catch (NumberFormatException ex) {
346 return;
347 }
348 handleNewCoordinates(e, n);
349 }
350 }
351 }
352 }
353 });
354 }
355
356 private void handleNewCoordinates(double e, double n) {
357 if (countMouseClicked == 1) {
358 georefpoint1 = new EastNorth(e, n);
359 continueGeoreferencing();
360 } else {
361 georefpoint2 = new EastNorth(e, n);
362 endGeoreferencing();
363 }
364 }
365
366 /**
367 * Use point org1 as anchor for scale, then move org1 to dst1, then rotate org2 on dst2
368 * around org1/dst1 anchor
369 * @param org1 first point at original coordinate system (the grabbed image)
370 * @param org2 second point "
371 * @param dst1 first point at final destination coordinate system (the real east/north coordinate system)
372 * @param dst2 second point "
373 */
374 private void affineTransform(EastNorth org1, EastNorth org2, EastNorth dst1, EastNorth dst2) {
375 double angle = dst1.heading(dst2) - org1.heading(org2);
376 double proportion = dst1.distance(dst2)/org1.distance(org2);
377 // move
378 double dx = dst1.getX() - org1.getX();
379 double dy = dst1.getY() - org1.getY();
380 wmsLayer.images.get(0).shear(dx, dy);
381 org1 = org1.add(dx, dy); // org1=dst1 now
382 org2 = org2.add(dx, dy);
383 // rotate : org1(=dst1 now) is anchor for rotation and scale
384 wmsLayer.images.get(0).rotate(dst1, angle);
385 org2 = org2.rotate(dst1, angle);
386 // scale image from anchor org1(=dst1 now)
387 wmsLayer.images.get(0).scale(dst1, proportion);
388 }
389
390 private void transformGeoreferencedImg() {
391 georefpoint1 = new EastNorth(wmsLayer.X0, wmsLayer.Y0);
392 georefpoint2 = new EastNorth(wmsLayer.X0+wmsLayer.fX*wmsLayer.communeBBox.max.getX(),
393 wmsLayer.Y0+wmsLayer.fY*wmsLayer.communeBBox.max.getX());
394 ea1 = new EastNorth(wmsLayer.images.get(0).min.east(), wmsLayer.images.get(0).max.north());
395 EastNorth ea2 = wmsLayer.images.get(0).max;
396 affineTransform(ea1, ea2, georefpoint1, georefpoint2);
397 wmsLayer.saveNewCache();
398 Main.map.mapView.repaint();
399 }
400
401 public void mouseEntered(MouseEvent arg0) {
402 }
403
404 public void mouseExited(MouseEvent arg0) {
405 }
406
407 public void mousePressed(MouseEvent arg0) {
408 }
409
410 public void mouseReleased(MouseEvent arg0) {
411 }
412
413}
Note: See TracBrowser for help on using the repository browser.