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

Last change on this file since 29677 was 29677, checked in by pieren, 13 years ago

Change some default preference values. Fix in grab plan image case where mouse clic is outside the image.

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