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

Last change on this file since 15962 was 15962, checked in by stoecker, 16 years ago

fix exception handling again

  • Property svn:eol-style set to native
File size: 20.0 KB
Line 
1package cadastre_fr;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.Component;
6import java.awt.Graphics;
7import java.awt.Graphics2D;
8import java.awt.Toolkit;
9import java.awt.event.ActionEvent;
10import java.awt.image.BufferedImage;
11import java.io.EOFException;
12import java.io.File;
13import java.io.FileInputStream;
14import java.io.FileOutputStream;
15import java.io.IOException;
16import java.io.ObjectInputStream;
17import java.io.ObjectOutputStream;
18import java.util.ArrayList;
19
20import javax.swing.AbstractAction;
21import javax.swing.Icon;
22import javax.swing.ImageIcon;
23import javax.swing.JFileChooser;
24import javax.swing.JMenuItem;
25import javax.swing.JOptionPane;
26import javax.swing.JSeparator;
27
28import org.openstreetmap.josm.Main;
29import org.openstreetmap.josm.actions.DiskAccessAction;
30import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
31import org.openstreetmap.josm.data.projection.Lambert;
32import org.openstreetmap.josm.data.Bounds;
33import org.openstreetmap.josm.gui.MapView;
34import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
35import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
36import org.openstreetmap.josm.gui.layer.Layer;
37import org.openstreetmap.josm.io.OsmTransferException;
38import org.openstreetmap.josm.tools.ImageProvider;
39import org.openstreetmap.josm.data.coor.EastNorth;
40
41/**
42 * This is a layer that grabs the current screen from the french cadastre WMS
43 * server. The data fetched this way is tiled and managed to the disc to reduce
44 * server load.
45 */
46public class WMSLayer extends Layer {
47
48 Component[] component = null;
49
50 public int lambertZone = -1;
51
52 protected static final Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(
53 CadastrePlugin.class.getResource("/images/cadastre_small.png")));
54
55 protected ArrayList<GeorefImage> images = new ArrayList<GeorefImage>();
56
57 protected final int serializeFormatVersion = 2;
58
59 private ArrayList<EastNorthBound> dividedBbox = new ArrayList<EastNorthBound>();
60
61 private CacheControl cacheControl = null;
62
63 private String location = "";
64
65 private String codeCommune = "";
66
67 private EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0,0), new EastNorth(0,0));
68
69 private boolean isRaster = false;
70
71 private EastNorth rasterMin;
72
73 private EastNorth rasterCenter;
74
75 private double rasterRatio;
76
77 double cRasterMaxSizeX = 12286;
78 double cRasterMaxSizeY = 8730;
79
80 public WMSLayer() {
81 this(tr("Blank Layer"), "", -1);
82 }
83
84 public WMSLayer(String location, String codeCommune, int lambertZone) {
85 super(buildName(location, codeCommune));
86 this.location = location;
87 this.codeCommune = codeCommune;
88 this.lambertZone = Lambert.layoutZone;
89 // enable auto-sourcing option
90 CadastrePlugin.pluginUsed = true;
91 }
92
93 private static String buildName(String location, String codeCommune) {
94 String ret = new String(location.toUpperCase());
95 if (codeCommune != null && !codeCommune.equals(""))
96 ret += "(" + codeCommune + ")";
97 return ret;
98 }
99
100 private String rebuildName() {
101 return buildName(this.location.toUpperCase(), this.codeCommune);
102 }
103
104 public void grab(CadastreGrabber grabber, Bounds b) throws IOException {
105 divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.scale", Scale.X1.toString())));
106
107 for (EastNorthBound n : dividedBbox) {
108 GeorefImage newImage;
109 try {
110 newImage = grabber.grab(this, n.min, n.max);
111 } catch (IOException e) {
112 System.out.println("Download action cancelled by user or server did not respond");
113 break;
114 } catch (OsmTransferException e) {
115 System.out.println("OSM transfer failed");
116 break;
117 }
118 if (grabber.getWmsInterface().downloadCancelled) {
119 System.out.println("Download action cancelled by user");
120 break;
121 }
122 if (CadastrePlugin.backgroundTransparent) {
123 for (GeorefImage img : images) {
124 if (img.overlap(newImage))
125 // mask overlapping zone in already grabbed image
126 img.withdraw(newImage);
127 else
128 // mask overlapping zone in new image only when new
129 // image covers completely the existing image
130 newImage.withdraw(img);
131 }
132 }
133 images.add(newImage);
134 saveToCache(newImage);
135 Main.map.mapView.repaint();
136 /*
137 try { if (dividedBbox.size() > 1) Thread.sleep(1000);
138 } catch (InterruptedException e) {};*/
139 }
140 }
141
142 /**
143 *
144 * @param b the original bbox, usually the current bbox on screen
145 * @param factor 1 = source bbox 1:1
146 * 2 = source bbox divided by 2x2 smaller boxes
147 * 3 = source bbox divided by 3x3 smaller boxes
148 * 4 = hard coded size of boxes (100 meters) rounded allowing
149 * grabbing of next contiguous zone
150 */
151 private void divideBbox(Bounds b, int factor) {
152 EastNorth lambertMin = Main.proj.latlon2eastNorth(b.min);
153 EastNorth lambertMax = Main.proj.latlon2eastNorth(b.max);
154 double minEast = lambertMin.east();
155 double minNorth = lambertMin.north();
156 double dEast = (lambertMax.east() - minEast) / factor;
157 double dNorth = (lambertMax.north() - minNorth) / factor;
158 dividedBbox.clear();
159 if (factor < 4) {
160 for (int xEast = 0; xEast < factor; xEast++)
161 for (int xNorth = 0; xNorth < factor; xNorth++) {
162 dividedBbox.add(new EastNorthBound(new EastNorth(minEast + xEast * dEast, minNorth + xNorth * dNorth),
163 new EastNorth(minEast + (xEast + 1) * dEast, minNorth + (xNorth + 1) * dNorth)));
164 }
165 } else {
166 // divide to fixed size squares
167 int cSquare = Integer.parseInt(Main.pref.get("cadastrewms.squareSize", "100"));
168 minEast = minEast - minEast % cSquare;
169 minNorth = minNorth - minNorth % cSquare;
170 for (int xEast = (int)minEast; xEast < lambertMax.east(); xEast+=cSquare)
171 for (int xNorth = (int)minNorth; xNorth < lambertMax.north(); xNorth+=cSquare) {
172 dividedBbox.add(new EastNorthBound(new EastNorth(xEast, xNorth),
173 new EastNorth(xEast + cSquare, xNorth + cSquare)));
174 }
175 }
176 }
177
178 @Override
179 public Icon getIcon() {
180 return icon;
181 }
182
183 @Override
184 public String getToolTipText() {
185 String str = tr("WMS layer ({0}), {1} tile(s) loaded", name, images.size());
186 if (isRaster) {
187 str += "\n"+tr("Is not vectorized.");
188 str += "\n"+tr("Raster center: {0}", rasterCenter);
189 } else
190 str += "\n"+tr("Is vectorized.");
191 str += "\n"+tr("Commune bbox: {0}", communeBBox);
192 return str;
193 }
194
195 @Override
196 public boolean isMergable(Layer other) {
197 return false;
198 }
199
200 @Override
201 public void mergeFrom(Layer from) {
202 }
203
204 @Override
205 public void paint(Graphics g, final MapView mv) {
206 for (GeorefImage img : images)
207 img.paint((Graphics2D) g, mv, CadastrePlugin.backgroundTransparent,
208 CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
209 }
210
211 @Override
212 public void visitBoundingBox(BoundingXYVisitor v) {
213 for (GeorefImage img : images) {
214 v.visit(img.min);
215 v.visit(img.max);
216 }
217 }
218
219 @Override
220 public Object getInfoComponent() {
221 return getToolTipText();
222 }
223
224 @Override
225 public Component[] getMenuEntries() {
226 /*
227 return new Component[] { new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
228 new JMenuItem(new LayerListDialog.DeleteLayerAction(this)), new JMenuItem(new LoadWmsAction()),
229 new JMenuItem(new SaveWmsAction()), new JSeparator(),
230 new JMenuItem(new LayerListPopup.InfoAction(this)) };
231 */
232 component = new Component[] { new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
233 new JMenuItem(new LayerListDialog.DeleteLayerAction(this)), new JMenuItem(new LoadWmsAction()),
234 new JMenuItem(new SaveWmsAction()), new JSeparator(),
235 new JMenuItem(new LayerListPopup.InfoAction(this)) };
236 return component;
237 }
238
239 public GeorefImage findImage(EastNorth eastNorth) {
240 // Iterate in reverse, so we return the image which is painted last.
241 // (i.e. the topmost one)
242 for (int i = images.size() - 1; i >= 0; i--) {
243 if (images.get(i).contains(eastNorth)) {
244 return images.get(i);
245 }
246 }
247 return null;
248 }
249
250 public boolean isOverlapping(Bounds bounds) {
251 GeorefImage georefImage =
252 new GeorefImage(new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB ), // not really important
253 Main.proj.latlon2eastNorth(bounds.min),
254 Main.proj.latlon2eastNorth(bounds.max));
255 for (GeorefImage img : images) {
256 if (img.overlap(georefImage))
257 return true;
258 }
259 return false;
260 }
261
262 public void saveToCache(GeorefImage image) {
263 if (CacheControl.cacheEnabled) {
264 getCacheControl().saveCache(image);
265 }
266 }
267
268 public void saveNewCache() {
269 if (CacheControl.cacheEnabled) {
270 getCacheControl().deleteCacheFile();
271 for (GeorefImage image : images)
272 getCacheControl().saveCache(image);
273 }
274 }
275
276 public CacheControl getCacheControl() {
277 if (cacheControl == null)
278 cacheControl = new CacheControl(this);
279 return cacheControl;
280 }
281
282 public class SaveWmsAction extends AbstractAction {
283 private static final long serialVersionUID = 1L;
284
285 public SaveWmsAction() {
286 super(tr("Save WMS layer to file"), ImageProvider.get("save"));
287 }
288
289 public void actionPerformed(ActionEvent ev) {
290 File f = DiskAccessAction.createAndOpenSaveFileChooser(
291 tr("Save WMS layer"), ".wms");
292 try {
293 FileOutputStream fos = new FileOutputStream(f);
294 ObjectOutputStream oos = new ObjectOutputStream(fos);
295 oos.writeInt(serializeFormatVersion);
296 oos.writeInt(lambertZone);
297 oos.writeInt(images.size());
298 for (GeorefImage img : images) {
299 oos.writeObject(img);
300 }
301 oos.close();
302 fos.close();
303 } catch (Exception ex) {
304 ex.printStackTrace(System.out);
305 }
306 }
307 }
308
309 public class LoadWmsAction extends AbstractAction {
310 private static final long serialVersionUID = 1L;
311
312 public LoadWmsAction() {
313 super(tr("Load WMS layer from file"), ImageProvider.get("load"));
314 }
315
316 public void actionPerformed(ActionEvent ev) {
317 JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
318 false, tr("Load WMS layer"));
319 if(fc == null) return;
320 File f = fc.getSelectedFile();
321 if (f == null) return;
322 try {
323 FileInputStream fis = new FileInputStream(f);
324 ObjectInputStream ois = new ObjectInputStream(fis);
325 int sfv = ois.readInt();
326 if (sfv != serializeFormatVersion) {
327 JOptionPane.showMessageDialog(Main.parent, tr(
328 "Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
329 tr("File Format Error"), JOptionPane.ERROR_MESSAGE);
330 return;
331 }
332 lambertZone = ois.readInt();
333 int numImg = ois.readInt();
334 for (int i = 0; i < numImg; i++) {
335 GeorefImage img = (GeorefImage) ois.readObject();
336 images.add(img);
337 }
338 ois.close();
339 fis.close();
340 } catch (Exception ex) {
341 // FIXME be more specific
342 ex.printStackTrace(System.out);
343 JOptionPane.showMessageDialog(Main.parent, tr("Error loading file"), tr("Error"),
344 JOptionPane.ERROR_MESSAGE);
345 return;
346 }
347 }
348 }
349
350 /**
351 * Convert the eastNorth input coordinates to raster coordinates.
352 * The original raster size is [0,0,12286,8730] where 0,0 is the upper left corner and
353 * 12286,8730 is the approx. raster max size.
354 * @return the raster coordinates for the wms server request URL (minX,minY,maxX,maxY)
355 */
356 public String eastNorth2raster(EastNorth min, EastNorth max) {
357 double minX = (min.east() - rasterMin.east()) / rasterRatio;
358 double minY = (min.north() - rasterMin.north()) / rasterRatio;
359 double maxX = (max.east() - rasterMin.east()) / rasterRatio;
360 double maxY = (max.north() - rasterMin.north()) / rasterRatio;
361 return minX+","+minY+","+maxX+","+maxY;
362 }
363
364
365 public String getLocation() {
366 return location;
367 }
368
369 public void setLocation(String location) {
370 this.location = location;
371 this.name = rebuildName();
372 repaintLayerListDialog();
373 }
374
375 public String getCodeCommune() {
376 return codeCommune;
377 }
378
379 public void setCodeCommune(String codeCommune) {
380 this.codeCommune = codeCommune;
381 this.name = rebuildName();
382 repaintLayerListDialog();
383 }
384
385 public boolean isRaster() {
386 return isRaster;
387 }
388
389 public void setRaster(boolean isRaster) {
390 this.isRaster = isRaster;
391 }
392
393 /**
394 * Set the eastNorth position in rasterMin which is the 0,0 coordinate (bottom left corner).
395 * The bounds width is the raster width and height is calculate on a fixed image ratio.
396 * @param bounds
397 */
398 public void setRasterBounds(Bounds bounds) {
399 rasterMin = new EastNorth(Main.proj.latlon2eastNorth(bounds.min).east(), Main.proj.latlon2eastNorth(bounds.min).north());
400 EastNorth rasterMax = new EastNorth(Main.proj.latlon2eastNorth(bounds.max).east(), Main.proj.latlon2eastNorth(bounds.max).north());
401 // now, resize on same proportion as wms server raster images (bounds center)
402 double rasterHalfHeight = (rasterMax.east() - rasterMin.east())/cRasterMaxSizeX*cRasterMaxSizeY/2;
403 double rasterMid = rasterMin.north() + (rasterMax.north()-rasterMin.north())/2;
404 rasterMin.setLocation(rasterMin.east(), rasterMid - rasterHalfHeight);
405 rasterMax.setLocation(rasterMax.east(), rasterMid + rasterHalfHeight);
406 rasterCenter = new EastNorth(rasterMin.east()+(rasterMax.east()-rasterMin.east())/2,
407 rasterMin.north()+(rasterMax.north()-rasterMin.north())/2);
408 rasterRatio = (rasterMax.east() - rasterMin.east()) / cRasterMaxSizeX;
409 }
410
411 public EastNorth getRasterMin() {
412 return rasterMin;
413 }
414
415 public void setRasterMin(EastNorth rasterMin) {
416 this.rasterMin = rasterMin;
417 }
418
419 public void displace(double dx, double dy) {
420 this.rasterMin = new EastNorth(rasterMin.east() + dx, rasterMin.north() + dy);
421 this.rasterCenter = new EastNorth(rasterCenter.east() + dx, rasterCenter.north() + dy);
422 for (GeorefImage img : images)
423 img.displace(dx, dy);
424 }
425
426 public void resize(double proportion) {
427 this.rasterMin = rasterMin.interpolate(rasterCenter, proportion);
428 for (GeorefImage img : images)
429 img.resize(rasterCenter, proportion);
430 }
431
432 public void rotate(double angle) {
433 this.rasterMin = rasterMin.rotate(rasterCenter, angle);
434 for (GeorefImage img : images)
435 img.rotate(rasterCenter, angle);
436 }
437
438 /**
439 * Repaint the LayerList dialog.
440 * This is the only way I found to refresh the layer name in the layer list when it changes
441 * later (after the construction).
442 */
443 private void repaintLayerListDialog() {
444 if (Main.map != null) {
445 for (Component c : Main.map.toggleDialogs.getComponents()) {
446 if (c instanceof LayerListDialog) {
447 c.repaint();
448 }
449 }
450 }
451 }
452
453 /**
454 * Called by CacheControl when a new cache file is created on disk
455 * @param oos
456 * @throws IOException
457 */
458 public void write(ObjectOutputStream oos, ArrayList<GeorefImage> imgs) throws IOException {
459 oos.writeInt(this.serializeFormatVersion);
460 oos.writeObject(this.location);
461 oos.writeObject(this.codeCommune);
462 oos.writeInt(this.lambertZone);
463 oos.writeBoolean(this.isRaster);
464 if (this.isRaster) {
465 oos.writeObject(this.rasterMin);
466 oos.writeObject(this.rasterCenter);
467 oos.writeDouble(this.rasterRatio);
468 } else {
469 oos.writeObject(this.communeBBox);
470 }
471 for (GeorefImage img : imgs) {
472 oos.writeObject(img);
473 }
474 }
475
476 /**
477 * Called by CacheControl when a cache file is read from disk
478 * @param ois
479 * @throws IOException
480 * @throws ClassNotFoundException
481 */
482 public boolean read(ObjectInputStream ois, int currentLambertZone) throws IOException, ClassNotFoundException {
483 int sfv = ois.readInt();
484 if (sfv != this.serializeFormatVersion) {
485 JOptionPane.showMessageDialog(Main.parent, tr("Unsupported cache file version; found {0}, expected {1}\nCreate a new one.",
486 sfv, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
487 return false;
488 }
489 this.setLocation((String) ois.readObject());
490 this.setCodeCommune((String) ois.readObject());
491 this.lambertZone = ois.readInt();
492 this.isRaster = ois.readBoolean();
493 if (this.isRaster) {
494 this.rasterMin = (EastNorth) ois.readObject();
495 this.rasterCenter = (EastNorth) ois.readObject();
496 this.rasterRatio = ois.readDouble();
497 } else {
498 this.communeBBox = (EastNorthBound) ois.readObject();
499 }
500 if (this.lambertZone != currentLambertZone) {
501 JOptionPane.showMessageDialog(Main.parent, tr("Lambert zone {0} in cache "+
502 "incompatible with current Lambert zone {1}",
503 this.lambertZone+1, currentLambertZone), tr("Cache Lambert Zone Error"), JOptionPane.ERROR_MESSAGE);
504 return false;
505 }
506 boolean EOF = false;
507 try {
508 while (!EOF) {
509 GeorefImage newImage = (GeorefImage) ois.readObject();
510 for (GeorefImage img : this.images) {
511 if (CadastrePlugin.backgroundTransparent) {
512 if (img.overlap(newImage))
513 // mask overlapping zone in already grabbed image
514 img.withdraw(newImage);
515 else
516 // mask overlapping zone in new image only when
517 // new image covers completely the existing image
518 newImage.withdraw(img);
519 }
520 }
521 this.images.add(newImage);
522 }
523 } catch (EOFException ex) {
524 // expected exception when all images are read
525 }
526 return true;
527 }
528
529 public double getRasterRatio() {
530 return rasterRatio;
531 }
532
533 public void setRasterRatio(double rasterRatio) {
534 this.rasterRatio = rasterRatio;
535 }
536
537 public EastNorth getRasterCenter() {
538 return rasterCenter;
539 }
540
541 public void setRasterCenter(EastNorth rasterCenter) {
542 this.rasterCenter = rasterCenter;
543 }
544
545 public EastNorthBound getCommuneBBox() {
546 return communeBBox;
547 }
548
549 public void setCommuneBBox(EastNorthBound entireCommune) {
550 this.communeBBox = entireCommune;
551 }
552
553}
Note: See TracBrowser for help on using the repository browser.