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

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

fixed typos

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