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

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

checkstyle

File size: 13.5 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 org1 = org1.add(dx, dy); // org1=dst1 now
191 org2 = org2.add(dx, dy);
192 // rotate : org1(=dst1 now) is anchor for rotation and scale
193 wmsLayer.getImage(0).rotate(dst1, angle);
194 org2 = org2.rotate(dst1, angle);
195 // scale image from anchor org1(=dst1 now)
196 wmsLayer.getImage(0).scale(dst1, proportion);
197 }
198
199 /**
200 * Ends the georeferencing by computing the affine transformation
201 */
202 private void endGeoreferencing() {
203 Main.map.mapView.removeMouseListener(this);
204 affineTransform(ea1, ea2, georefpoint1, georefpoint2);
205 wmsLayer.grabThread.saveNewCache();
206 Main.map.mapView.repaint();
207 actionCompleted();
208 clickOnTheMap = false;
209 ignoreMouseClick = false;
210 }
211
212 private void inputLambertPosition() {
213 JLabel labelEnterPosition = new JLabel(
214 tr("Enter cadastre east,north position"));
215 JLabel labelWarning = new JLabel(
216 tr("(Warning: verify north with arrow !!)"));
217 JPanel p = new JPanel(new GridBagLayout());
218 JLabel labelEast = new JLabel(tr("East"));
219 JLabel labelNorth = new JLabel(tr("North"));
220 final JTextField inputEast = new JTextField();
221 final JTextField inputNorth = new JTextField();
222 p.add(labelEnterPosition, GBC.eol());
223 p.add(labelWarning, GBC.eol());
224 p.add(labelEast, GBC.std().insets(0, 0, 10, 0));
225 p.add(inputEast, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
226 p.add(labelNorth, GBC.std().insets(0, 0, 10, 0));
227 p.add(inputNorth, GBC.eol().fill(GBC.HORIZONTAL).insets(10, 5, 0, 5));
228 final Object[] options = {tr("OK"),
229 tr("Cancel"),
230 tr("I use the mouse")};
231 final JOptionPane pane = new JOptionPane(p,
232 JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION,
233 null, options, options[0]);
234 String number;
235 if (countMouseClicked == 1)
236 number = "first";
237 else
238 number = "second";
239 JDialog dialog = pane.createDialog(Main.parent, tr(
240 "Set {0} Lambert coordinates", number));
241 dialog.setModal(false);
242 ignoreMouseClick = true; // To avoid mouseClicked from being called
243 // during coordinates reading
244 dialog.setAlwaysOnTop(true);
245 dialog.setVisible(true);
246 pane.addPropertyChangeListener(new PropertyChangeListener() {
247 @Override
248 public void propertyChange(PropertyChangeEvent evt) {
249 if (JOptionPane.VALUE_PROPERTY.equals(evt.getPropertyName())) {
250 ignoreMouseClick = false;
251 // Cancel
252 if (pane.getValue().equals(options[1])) {
253 if (canceledOrRestartCurrAction("georeferencing"))
254 startGeoreferencing(wmsLayer);
255 }
256 // Click on the map
257 if (pane.getValue().equals(options[2])) {
258 clickOnTheMap = true;
259 } else {
260 // OK (coordinates manually entered)
261 clickOnTheMap = false;
262 if (inputEast.getText().length() != 0
263 && inputNorth.getText().length() != 0) {
264 double e, n;
265 try {
266 e = Double.parseDouble(inputEast.getText());
267 n = Double.parseDouble(inputNorth.getText());
268 } catch (NumberFormatException ex) {
269 return;
270 }
271 handleNewCoordinates(e, n);
272 }
273 }
274 }
275 }
276 });
277 }
278
279 /**
280 *
281 * @return false if all operations are canceled
282 */
283private boolean continueCropping() {
284 Object[] options = {"OK", "Cancel"};
285 int ret = JOptionPane.showOptionDialog(null,
286 tr("Click second corner for image cropping"),
287 tr("Image cropping"),
288 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
289 null, options, options[0]);
290 if (ret != JOptionPane.OK_OPTION) {
291 if (canceledOrRestartCurrAction("image cropping"))
292 return startCropping(wmsLayer);
293 }
294 return true;
295}
296
297public void transformGeoreferencedImg() {
298 georefpoint1 = new EastNorth(wmsLayer.X0, wmsLayer.Y0);
299 georefpoint2 = new EastNorth(wmsLayer.X0+wmsLayer.fX*wmsLayer.communeBBox.max.getX(),
300 wmsLayer.Y0+wmsLayer.fY*wmsLayer.communeBBox.max.getX());
301 ea1 = new EastNorth(wmsLayer.getImage(0).min.east(), wmsLayer.getImage(0).max.north());
302 EastNorth ea2 = wmsLayer.getImage(0).max;
303 affineTransform(ea1, ea2, georefpoint1, georefpoint2);
304 wmsLayer.grabThread.saveNewCache();
305 Main.map.mapView.repaint();
306}
307
308
309 /**
310 *
311 * @return false if all operations are canceled
312 */
313private boolean continueGeoreferencing() {
314 Object[] options = {"OK", "Cancel"};
315 int ret = JOptionPane.showOptionDialog(null,
316 tr("Click second Lambert crosspiece for georeferencing"),
317 tr("Image georeferencing"),
318 JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
319 null, options, options[0]);
320 if (ret != JOptionPane.OK_OPTION) {
321 if (canceledOrRestartCurrAction("georeferencing"))
322 return startGeoreferencing(wmsLayer);
323 }
324 return true;
325}
326
327 private void handleNewCoordinates(double e, double n) {
328 if (countMouseClicked == 1) {
329 georefpoint1 = new EastNorth(e, n);
330 continueGeoreferencing();
331 } else {
332 georefpoint2 = new EastNorth(e, n);
333 endGeoreferencing();
334 }
335 }
336
337 private void actionCompleted() {
338 countMouseClicked = 0;
339 mode = 0;
340 mouseClickedTime = System.currentTimeMillis();
341 }
342
343 public void actionInterrupted() {
344 actionCompleted();
345 if (wmsLayer != null) {
346 Main.getLayerManager().removeLayer(wmsLayer);
347 wmsLayer = null;
348 }
349 }
350
351 @Override
352 public void mouseEntered(MouseEvent arg0) {
353 }
354
355 @Override
356 public void mouseExited(MouseEvent arg0) {
357 }
358
359 @Override
360 public void mousePressed(MouseEvent arg0) {
361 }
362
363 @Override
364 public void mouseReleased(MouseEvent arg0) {
365 }
366}
Note: See TracBrowser for help on using the repository browser.