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

Last change on this file since 20425 was 20214, checked in by pieren, 15 years ago

Add non-modal dialog in action grab planImage + more history in main plugin file.

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