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

Last change on this file since 33047 was 33047, checked in by donvip, 8 years ago

findbugs

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