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

Last change on this file since 15972 was 15972, checked in by pieren, 17 years ago

fixed load/save menu from layer context menu

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