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

Last change on this file since 18838 was 18838, checked in by pieren, 15 years ago

Fix minor issues if Grab is called without layer (possible since projection rework)

  • Property svn:eol-style set to native
File size: 24.4 KB
Line 
1// License: GPL. v2 and later. Copyright 2008-2009 by Pieren <pieren3@gmail.com> and others
2package cadastre_fr;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Graphics;
9import java.awt.Graphics2D;
10import java.awt.Image;
11import java.awt.Point;
12import java.awt.Toolkit;
13import java.awt.image.BufferedImage;
14import java.awt.image.ImageObserver;
15import java.io.EOFException;
16import java.io.IOException;
17import java.io.ObjectInputStream;
18import java.io.ObjectOutputStream;
19import java.util.ArrayList;
20import java.util.Vector;
21
22import javax.swing.Icon;
23import javax.swing.ImageIcon;
24import javax.swing.JMenuItem;
25import javax.swing.JOptionPane;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.data.Bounds;
29import org.openstreetmap.josm.data.coor.EastNorth;
30import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
31import org.openstreetmap.josm.gui.MapView;
32import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
33import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
34import org.openstreetmap.josm.gui.layer.Layer;
35import org.openstreetmap.josm.io.OsmTransferException;
36
37/**
38 * This is a layer that grabs the current screen from the French cadastre WMS
39 * server. The data fetched this way is tiled and managed to the disc to reduce
40 * server load.
41 */
42public class WMSLayer extends Layer implements ImageObserver {
43
44 Component[] component = null;
45
46 private int lambertZone = -1;
47
48 protected static final Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(
49 CadastrePlugin.class.getResource("/images/cadastre_small.png")));
50
51 protected Vector<GeorefImage> images = new Vector<GeorefImage>();
52
53 protected final int serializeFormatVersion = 2;
54
55 private ArrayList<EastNorthBound> dividedBbox = new ArrayList<EastNorthBound>();
56
57 private CacheControl cacheControl = null;
58
59 private String location = "";
60
61 private String codeCommune = "";
62
63 public EastNorthBound communeBBox = new EastNorthBound(new EastNorth(0,0), new EastNorth(0,0));
64
65 private boolean isRaster = false;
66
67 private boolean isAlreadyGeoreferenced = false;
68
69 public double X0, Y0, angle, fX, fY;
70
71 private EastNorth rasterMin;
72 private EastNorth rasterMax;
73 private double rasterRatio;
74
75 private JMenuItem saveAsPng;
76
77 public WMSLayer() {
78 this(tr("Blank Layer"), "", -1);
79 }
80
81 public WMSLayer(String location, String codeCommune, int lambertZone) {
82 super(buildName(location, codeCommune));
83 this.location = location;
84 this.codeCommune = codeCommune;
85 this.lambertZone = lambertZone;
86 // enable auto-sourcing option
87 CadastrePlugin.pluginUsed = true;
88 }
89
90 private static String buildName(String location, String codeCommune) {
91 String ret = new String(location.toUpperCase());
92 if (codeCommune != null && !codeCommune.equals(""))
93 ret += "(" + codeCommune + ")";
94 return ret;
95 }
96
97 private String rebuildName() {
98 return buildName(this.location.toUpperCase(), this.codeCommune);
99 }
100
101 public void grab(CadastreGrabber grabber, Bounds b) throws IOException {
102 grab(grabber, b, true);
103 }
104
105 public void grab(CadastreGrabber grabber, Bounds b, boolean useFactor) throws IOException {
106 if (useFactor) {
107 if (isRaster) {
108 b = new Bounds(Main.proj.eastNorth2latlon(rasterMin), Main.proj.eastNorth2latlon(rasterMax));
109 divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.rasterDivider",
110 CadastrePreferenceSetting.DEFAULT_RASTER_DIVIDER)));
111 } else
112 divideBbox(b, Integer.parseInt(Main.pref.get("cadastrewms.scale", Scale.X1.toString())));
113 } else
114 divideBbox(b, 1);
115
116 for (EastNorthBound n : dividedBbox) {
117 GeorefImage newImage;
118 try {
119 newImage = grabber.grab(this, n.min, n.max);
120 } catch (IOException e) {
121 System.out.println("Download action cancelled by user or server did not respond");
122 break;
123 } catch (OsmTransferException e) {
124 System.out.println("OSM transfer failed");
125 break;
126 }
127 if (grabber.getWmsInterface().downloadCancelled) {
128 System.out.println("Download action cancelled by user");
129 break;
130 }
131 if (CadastrePlugin.backgroundTransparent) {
132 for (GeorefImage img : images) {
133 if (img.overlap(newImage))
134 // mask overlapping zone in already grabbed image
135 img.withdraw(newImage);
136 else
137 // mask overlapping zone in new image only when new
138 // image covers completely the existing image
139 newImage.withdraw(img);
140 }
141 }
142 images.add(newImage);
143 saveToCache(newImage);
144 Main.map.mapView.repaint();
145 }
146 }
147
148 /**
149 *
150 * @param b the original bbox, usually the current bbox on screen
151 * @param factor 1 = source bbox 1:1
152 * 2 = source bbox divided by 2x2 smaller boxes
153 * 3 = source bbox divided by 3x3 smaller boxes
154 * 4 = hard coded size of boxes (100 meters) rounded allowing
155 * grabbing of next contiguous zone
156 */
157 private void divideBbox(Bounds b, int factor) {
158 EastNorth lambertMin = Main.proj.latlon2eastNorth(b.getMin());
159 EastNorth lambertMax = Main.proj.latlon2eastNorth(b.getMax());
160 double minEast = lambertMin.east();
161 double minNorth = lambertMin.north();
162 double dEast = (lambertMax.east() - minEast) / factor;
163 double dNorth = (lambertMax.north() - minNorth) / factor;
164 dividedBbox.clear();
165 if (factor < 4 || isRaster) {
166 for (int xEast = 0; xEast < factor; xEast++)
167 for (int xNorth = 0; xNorth < factor; xNorth++) {
168 dividedBbox.add(new EastNorthBound(new EastNorth(minEast + xEast * dEast, minNorth + xNorth * dNorth),
169 new EastNorth(minEast + (xEast + 1) * dEast, minNorth + (xNorth + 1) * dNorth)));
170 }
171 } else {
172 // divide to fixed size squares
173 int cSquare = Integer.parseInt(Main.pref.get("cadastrewms.squareSize", "100"));
174 minEast = minEast - minEast % cSquare;
175 minNorth = minNorth - minNorth % cSquare;
176 for (int xEast = (int)minEast; xEast < lambertMax.east(); xEast+=cSquare)
177 for (int xNorth = (int)minNorth; xNorth < lambertMax.north(); xNorth+=cSquare) {
178 dividedBbox.add(new EastNorthBound(new EastNorth(xEast, xNorth),
179 new EastNorth(xEast + cSquare, xNorth + cSquare)));
180 }
181 }
182 }
183
184 @Override
185 public Icon getIcon() {
186 return icon;
187 }
188
189 @Override
190 public String getToolTipText() {
191 String str = tr("WMS layer ({0}), {1} tile(s) loaded", getName(), images.size());
192 if (isRaster) {
193 str += "\n"+tr("Is not vectorized.");
194 str += "\n"+tr("Raster size: {0}", communeBBox);
195 } else
196 str += "\n"+tr("Is vectorized.");
197 str += "\n"+tr("Commune bbox: {0}", communeBBox);
198 return str;
199 }
200
201 @Override
202 public boolean isMergable(Layer other) {
203 return false;
204 }
205
206 @Override
207 public void mergeFrom(Layer from) {
208 }
209
210 @Override
211 public void paint(Graphics2D g, final MapView mv, Bounds bounds) {
212 synchronized(this){
213 for (GeorefImage img : images)
214 img.paint(g, mv, CadastrePlugin.backgroundTransparent,
215 CadastrePlugin.transparency, CadastrePlugin.drawBoundaries);
216 }
217 if (this.isRaster) {
218 paintCrosspieces(g, mv);
219 }
220 }
221
222 @Override
223 public void visitBoundingBox(BoundingXYVisitor v) {
224 for (GeorefImage img : images) {
225 v.visit(img.min);
226 v.visit(img.max);
227 }
228 }
229
230 @Override
231 public Object getInfoComponent() {
232 return getToolTipText();
233 }
234
235 @Override
236 public Component[] getMenuEntries() {
237 saveAsPng = new JMenuItem(new MenuActionSaveRasterAs(this));
238 saveAsPng.setEnabled(isRaster);
239 component = new Component[] { new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
240 new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
241 new JMenuItem(new MenuActionLoadFromCache()),
242 saveAsPng,
243 new JMenuItem(new LayerListPopup.InfoAction(this)),
244
245 };
246 return component;
247 }
248
249 public GeorefImage findImage(EastNorth eastNorth) {
250 // Iterate in reverse, so we return the image which is painted last.
251 // (i.e. the topmost one)
252 for (int i = images.size() - 1; i >= 0; i--) {
253 if (images.get(i).contains(eastNorth)) {
254 return images.get(i);
255 }
256 }
257 return null;
258 }
259
260 public boolean isOverlapping(Bounds bounds) {
261 GeorefImage georefImage =
262 new GeorefImage(new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB ), // not really important
263 Main.proj.latlon2eastNorth(bounds.getMin()),
264 Main.proj.latlon2eastNorth(bounds.getMax()));
265 for (GeorefImage img : images) {
266 if (img.overlap(georefImage))
267 return true;
268 }
269 return false;
270 }
271
272 public void saveToCache(GeorefImage image) {
273 if (CacheControl.cacheEnabled && !isRaster()) {
274 getCacheControl().saveCache(image);
275 }
276 }
277
278 public void saveNewCache() {
279 if (CacheControl.cacheEnabled) {
280 getCacheControl().deleteCacheFile();
281 for (GeorefImage image : images)
282 getCacheControl().saveCache(image);
283 }
284 }
285
286 public CacheControl getCacheControl() {
287 if (cacheControl == null)
288 cacheControl = new CacheControl(this);
289 return cacheControl;
290 }
291
292 /**
293 * Convert the eastNorth input coordinates to raster coordinates.
294 * The original raster size is [0,0,12286,8730] where 0,0 is the upper left corner and
295 * 12286,8730 is the approx. raster max size.
296 * @return the raster coordinates for the wms server request URL (minX,minY,maxX,maxY)
297 */
298 public String eastNorth2raster(EastNorth min, EastNorth max) {
299 double minX = (min.east() - rasterMin.east()) / rasterRatio;
300 double minY = (min.north() - rasterMin.north()) / rasterRatio;
301 double maxX = (max.east() - rasterMin.east()) / rasterRatio;
302 double maxY = (max.north() - rasterMin.north()) / rasterRatio;
303 return minX+","+minY+","+maxX+","+maxY;
304 }
305
306
307 public String getLocation() {
308 return location;
309 }
310
311 public void setLocation(String location) {
312 this.location = location;
313 setName(rebuildName());
314 }
315
316 public String getCodeCommune() {
317 return codeCommune;
318 }
319
320 public void setCodeCommune(String codeCommune) {
321 this.codeCommune = codeCommune;
322 setName(rebuildName());
323 }
324
325 public boolean isRaster() {
326 return isRaster;
327 }
328
329 public void setRaster(boolean isRaster) {
330 this.isRaster = isRaster;
331 if (saveAsPng != null)
332 saveAsPng.setEnabled(isRaster);
333 }
334
335 public boolean isAlreadyGeoreferenced() {
336 return isAlreadyGeoreferenced;
337 }
338
339 public void setAlreadyGeoreferenced(boolean isAlreadyGeoreferenced) {
340 this.isAlreadyGeoreferenced = isAlreadyGeoreferenced;
341 }
342
343 /**
344 * Set raster positions used for grabbing and georeferencing.
345 * rasterMin is the Eaast North of bottom left corner raster image on the screen when image is grabbed.
346 * The bounds width and height are the raster width and height. The image width matches the current view
347 * and the image height is adapted.
348 * Required: the communeBBox must be set (normally it is catched by CadastreInterface and saved by DownloadWMSPlanImage)
349 * @param bounds the current main map view boundaries
350 */
351 public void setRasterBounds(Bounds bounds) {
352 EastNorth rasterCenter = Main.proj.latlon2eastNorth(bounds.getCenter());
353 EastNorth eaMin = Main.proj.latlon2eastNorth(bounds.getMin());
354 EastNorth eaMax = Main.proj.latlon2eastNorth(bounds.getMax());
355 double rasterSizeX = communeBBox.max.getX() - communeBBox.min.getX();
356 double rasterSizeY = communeBBox.max.getY() - communeBBox.min.getY();
357 double ratio = rasterSizeY/rasterSizeX;
358 // keep same ratio on screen as WMS bbox (stored in communeBBox)
359 rasterMin = new EastNorth(eaMin.getX(), rasterCenter.getY()-(eaMax.getX()-eaMin.getX())*ratio/2);
360 rasterMax = new EastNorth(eaMax.getX(), rasterCenter.getY()+(eaMax.getX()-eaMin.getX())*ratio/2);
361 rasterRatio = (rasterMax.getX()-rasterMin.getX())/rasterSizeX;
362 }
363
364 /**
365 * Called by CacheControl when a new cache file is created on disk.
366 * Save only primitives to keep cache independent of software changes.
367 * @param oos
368 * @throws IOException
369 */
370 public void write(ObjectOutputStream oos) throws IOException {
371 oos.writeInt(this.serializeFormatVersion);
372 oos.writeObject(this.location); // String
373 oos.writeObject(this.codeCommune); // String
374 oos.writeInt(this.lambertZone);
375 oos.writeBoolean(this.isRaster);
376 if (this.isRaster) {
377 oos.writeDouble(this.rasterMin.getX());
378 oos.writeDouble(this.rasterMin.getY());
379 oos.writeDouble(this.rasterMax.getX());
380 oos.writeDouble(this.rasterMax.getY());
381 oos.writeDouble(this.rasterRatio);
382 }
383 oos.writeDouble(this.communeBBox.min.getX());
384 oos.writeDouble(this.communeBBox.min.getY());
385 oos.writeDouble(this.communeBBox.max.getX());
386 oos.writeDouble(this.communeBBox.max.getY());
387 }
388
389 /**
390 * Called by CacheControl when a cache file is read from disk.
391 * Cache uses only primitives to stay independent of software changes.
392 * @param ois
393 * @throws IOException
394 * @throws ClassNotFoundException
395 */
396 public boolean read(ObjectInputStream ois, int currentLambertZone) throws IOException, ClassNotFoundException {
397 int sfv = ois.readInt();
398 if (sfv != this.serializeFormatVersion) {
399 JOptionPane.showMessageDialog(Main.parent, tr("Unsupported cache file version; found {0}, expected {1}\nCreate a new one.",
400 sfv, this.serializeFormatVersion), tr("Cache Format Error"), JOptionPane.ERROR_MESSAGE);
401 return false;
402 }
403 this.setLocation((String) ois.readObject());
404 this.setCodeCommune((String) ois.readObject());
405 this.lambertZone = ois.readInt();
406 this.setRaster(ois.readBoolean());
407 if (this.isRaster) {
408 double X = ois.readDouble();
409 double Y = ois.readDouble();
410 this.rasterMin = new EastNorth(X, Y);
411 X = ois.readDouble();
412 Y = ois.readDouble();
413 this.rasterMax = new EastNorth(X, Y);
414 this.rasterRatio = ois.readDouble();
415 }
416 double minX = ois.readDouble();
417 double minY = ois.readDouble();
418 double maxX = ois.readDouble();
419 double maxY = ois.readDouble();
420 this.communeBBox = new EastNorthBound(new EastNorth(minX, minY), new EastNorth(maxX, maxY));
421 if (this.lambertZone != currentLambertZone && currentLambertZone != -1) {
422 JOptionPane.showMessageDialog(Main.parent, tr("Lambert zone {0} in cache "+
423 "incompatible with current Lambert zone {1}",
424 this.lambertZone+1, currentLambertZone), tr("Cache Lambert Zone Error"), JOptionPane.ERROR_MESSAGE);
425 return false;
426 }
427 synchronized(this){
428 boolean EOF = false;
429 try {
430 while (!EOF) {
431 GeorefImage newImage = (GeorefImage) ois.readObject();
432 for (GeorefImage img : this.images) {
433 if (CadastrePlugin.backgroundTransparent) {
434 if (img.overlap(newImage))
435 // mask overlapping zone in already grabbed image
436 img.withdraw(newImage);
437 else
438 // mask overlapping zone in new image only when
439 // new image covers completely the existing image
440 newImage.withdraw(img);
441 }
442 }
443 this.images.add(newImage);
444 }
445 } catch (EOFException ex) {
446 // expected exception when all images are read
447 }
448 }
449 System.out.println("Cache loaded for location "+location+" with "+images.size()+" images");
450 return true;
451 }
452
453 /**
454 * Join the grabbed images into one single.
455 * Works only for images grabbed from non-georeferenced images (Feuilles cadastrales)(same amount of
456 * images in x and y)
457 */
458 public void joinRasterImages() {
459 if (images.size() > 1) {
460 EastNorth min = images.get(0).min;
461 EastNorth max = images.get(images.size()-1).max;
462 int oldImgWidth = images.get(0).image.getWidth();
463 int oldImgHeight = images.get(0).image.getHeight();
464 int newWidth = oldImgWidth*(int)Math.sqrt(images.size());
465 int newHeight = oldImgHeight*(int)Math.sqrt(images.size());
466 BufferedImage new_img = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
467 Graphics g = new_img.getGraphics();
468 // Coordinate (0,0) is on top,left corner where images are grabbed from bottom left
469 int rasterDivider = (int)Math.sqrt(images.size());
470 for (int h = 0; h < rasterDivider; h++) {
471 for (int v = 0; v < rasterDivider; v++) {
472 int newx = h*oldImgWidth;
473 int newy = newHeight - oldImgHeight - (v*oldImgHeight);
474 int j = h*rasterDivider + v;
475 g.drawImage(images.get(j).image, newx, newy, this);
476 }
477 }
478 synchronized(this) {
479 images.clear();
480 images.add(new GeorefImage(new_img, min, max));
481 }
482 }
483 }
484
485 /**
486 * Image cropping based on two EN coordinates pointing to two corners in diagonal
487 * Because it's coming from user mouse clics, we have to sort de positions first.
488 * Works only for raster image layer (only one image in collection).
489 * Updates layer georeferences.
490 * @param en1
491 * @param en2
492 */
493 public void cropImage(EastNorth en1, EastNorth en2){
494 // adj1 is corner bottom, left
495 EastNorth adj1 = new EastNorth(en1.east() <= en2.east() ? en1.east() : en2.east(),
496 en1.north() <= en2.north() ? en1.north() : en2.north());
497 // adj2 is corner top, right
498 EastNorth adj2 = new EastNorth(en1.east() > en2.east() ? en1.east() : en2.east(),
499 en1.north() > en2.north() ? en1.north() : en2.north());
500 // s1 and s2 have 0,0 at top, left where all EastNorth coord. have 0,0 at bottom, left
501 int sx1 = (int)((adj1.getX() - images.get(0).min.getX())*images.get(0).getPixelPerEast());
502 int sy1 = (int)((images.get(0).max.getY() - adj2.getY())*images.get(0).getPixelPerNorth());
503 int sx2 = (int)((adj2.getX() - images.get(0).min.getX())*images.get(0).getPixelPerEast());
504 int sy2 = (int)((images.get(0).max.getY() - adj1.getY())*images.get(0).getPixelPerNorth());
505 int newWidth = Math.abs(sx2 - sx1);
506 int newHeight = Math.abs(sy2 - sy1);
507 BufferedImage new_img = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
508 Graphics g = new_img.getGraphics();
509 g.drawImage(images.get(0).image, 0, 0, newWidth-1, newHeight-1,
510 sx1, sy1, sx2, sy2,
511 this);
512 images.set(0, new GeorefImage(new_img, adj1, adj2));
513 // important: update the layer georefs !
514 rasterMin = adj1;
515 rasterMax = adj2;
516 rasterRatio = (rasterMax.getX()-rasterMin.getX())/(communeBBox.max.getX() - communeBBox.min.getX());
517 setCommuneBBox(new EastNorthBound(new EastNorth(0,0), new EastNorth(newWidth-1,newHeight-1)));
518 }
519
520 public EastNorthBound getCommuneBBox() {
521 return communeBBox;
522 }
523
524 public void setCommuneBBox(EastNorthBound entireCommune) {
525 this.communeBBox = entireCommune;
526// if (Main.proj instanceof LambertCC9Zones)
527// setLambertCC9Zone(communeBBox.min.north());
528 }
529
530 /**
531 * Method required by ImageObserver when drawing an image
532 */
533 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
534 return false;
535 }
536
537 public int getLambertZone() {
538 return lambertZone;
539 }
540
541// public void setLambertCC9Zone(double north) {
542// int lambertZone = LambertCC9Zones.north2ZoneNumber(north);
543// this.lambertZone = lambertZone;
544// if (((LambertCC9Zones)Main.proj).getLayoutZone() != lambertZone) {
545// String currentZone = MenuActionLambertZone.lambert9zones[((LambertCC9Zones)Main.proj).getLayoutZone()+1];
546// String destZone = MenuActionLambertZone.lambert9zones[lambertZone+1];
547// if (Main.map.mapView.getAllLayers().size() == 1) {
548// /* Enable this code below when JOSM will have a proper support of dynamic projection change
549// *
550// System.out.println("close all layers and change current Lambert zone from "+LambertCC9Zones.layoutZone+" to "+lambertZone);
551// Bounds b = null;
552// if (Main.map != null && Main.map.mapView != null)
553// b = Main.map.mapView.getRealBounds();
554// LambertCC9Zones.layoutZone = lambertZone;
555// Main.map.mapView.zoomTo(b);
556// */
557// } else {
558// JOptionPane.showMessageDialog(Main.parent, tr("Current layer is in Lambert CC9 Zone \"{0}\"\n"+
559// "where the commune is in Lambert CC9 Zone \"{1}\".\n"+
560// "Upload your changes, close all layers and change\n"+
561// "manually the Lambert zone from the Cadastre menu"
562// , currentZone, destZone));
563// }
564// }
565// }
566
567 public EastNorth getRasterCenter() {
568 return new EastNorth((images.get(0).max.east()+images.get(0).min.east())/2,
569 (images.get(0).max.north()+images.get(0).min.north())/2);
570 }
571
572 public void displace(double dx, double dy) {
573 this.rasterMin = new EastNorth(rasterMin.east() + dx, rasterMin.north() + dy);
574 images.get(0).shear(dx, dy);
575 }
576
577 public void resize(EastNorth rasterCenter, double proportion) {
578 this.rasterMin = rasterMin.interpolate(rasterCenter, proportion);
579 images.get(0).scale(rasterCenter, proportion);
580 }
581
582 public void rotate(EastNorth rasterCenter, double angle) {
583 this.rasterMin = rasterMin.rotate(rasterCenter, angle);
584 images.get(0).rotate(rasterCenter, angle);
585 }
586
587 private void paintCrosspieces(Graphics g, MapView mv) {
588 String crosspieces = Main.pref.get("cadastrewms.crosspieces", "0");
589 if (!crosspieces.equals("0")) {
590 int modulo = 50;
591 if (crosspieces.equals("2")) modulo = 100;
592 EastNorthBound currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
593 mv.getEastNorth(mv.getWidth(), 0));
594 int minX = ((int)currentView.min.east()/modulo+1)*modulo;
595 int minY = ((int)currentView.min.north()/modulo+1)*modulo;
596 int maxX = ((int)currentView.max.east()/modulo)*modulo;
597 int maxY = ((int)currentView.max.north()/modulo)*modulo;
598 int size=(maxX-minX)/modulo;
599 if (size<20) {
600 int px= size > 10 ? 2 : Math.abs(12-size);
601 g.setColor(Color.green);
602 for (int x=minX; x<=maxX; x+=modulo) {
603 for (int y=minY; y<=maxY; y+=modulo) {
604 Point p = mv.getPoint(new EastNorth(x,y));
605 g.drawLine(p.x-px, p.y, p.x+px, p.y);
606 g.drawLine(p.x, p.y-px, p.x, p.y+px);
607 }
608 }
609 }
610 }
611 }
612
613}
Note: See TracBrowser for help on using the repository browser.