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

Last change on this file since 21202 was 21202, checked in by pieren, 14 years ago

Added last departement saved in preference file; now possibility to enter coordinates by mouse click during georeferencing

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