source: osm/applications/editors/josm/plugins/slippymap/slippymap/SlippyMapLayer.java@ 5269

Last change on this file since 5269 was 5269, checked in by frederik, 17 years ago

removed unused references to RawGpsLayer

File size: 13.1 KB
Line 
1package slippymap;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.Color;
6import java.awt.Component;
7import java.awt.Graphics;
8import java.awt.Image;
9import java.awt.Point;
10import java.awt.Rectangle;
11import java.awt.event.ActionEvent;
12import java.awt.event.ActionListener;
13import java.awt.event.MouseAdapter;
14import java.awt.event.MouseEvent;
15import java.awt.image.ImageObserver;
16import java.io.File;
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.Date;
20import java.util.HashMap;
21
22import javax.swing.AbstractAction;
23import javax.swing.Action;
24import javax.swing.Icon;
25import javax.swing.JColorChooser;
26import javax.swing.JLabel;
27import javax.swing.JMenuItem;
28import javax.swing.JOptionPane;
29import javax.swing.JPopupMenu;
30import javax.swing.JSeparator;
31import javax.swing.SwingUtilities;
32
33import org.openstreetmap.josm.Main;
34import org.openstreetmap.josm.actions.JosmAction;
35import org.openstreetmap.josm.actions.RenameLayerAction;
36import org.openstreetmap.josm.data.coor.EastNorth;
37import org.openstreetmap.josm.data.coor.LatLon;
38import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
39import org.openstreetmap.josm.data.projection.Mercator;
40import org.openstreetmap.josm.data.projection.Projection;
41import org.openstreetmap.josm.gui.MapFrame;
42import org.openstreetmap.josm.gui.MapView;
43import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
44import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
45import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
46import org.openstreetmap.josm.gui.layer.Layer;
47import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
48import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
49import org.openstreetmap.josm.tools.ColorHelper;
50import org.openstreetmap.josm.tools.ImageProvider;
51
52/**
53 * Class that displays a slippy map layer.
54 *
55 * @author Frederik Ramm <frederik@remote.org>
56 *
57 */
58public class SlippyMapLayer extends Layer implements ImageObserver {
59
60 ArrayList<HashMap<Integer, SlippyMapTile>> tileStorage = new ArrayList<HashMap<Integer, SlippyMapTile>>(20);
61 Point[][] pixelpos = new Point[21][21];
62 LatLon lastTopLeft;
63 LatLon lastBotRight;
64
65 int z12x0, z12x1, z12y0, z12y1;
66
67 private Image bufferImage;
68 private SlippyMapTile clickedTile;
69 private boolean needRedraw;
70
71 private JPopupMenu tileOptionMenu;
72
73 public SlippyMapLayer()
74 {
75 super("Slippy Map");
76 for (int i=0; i<18; i++)
77 tileStorage.add(new HashMap<Integer, SlippyMapTile>());
78
79 tileOptionMenu = new JPopupMenu();
80 tileOptionMenu.add(new JMenuItem(new AbstractAction("Load Tile") {
81 public void actionPerformed(ActionEvent ae) {
82 if (clickedTile != null)
83 {
84 clickedTile.loadImage();
85 needRedraw = true;
86 Main.map.repaint();
87 }
88 }
89 }));
90
91 tileOptionMenu.add(new JMenuItem(new AbstractAction("Show Tile Status") {
92 public void actionPerformed(ActionEvent ae) {
93 if (clickedTile != null)
94 {
95 clickedTile.loadMetadata();
96 needRedraw = true;
97 Main.map.repaint();
98 }
99 }
100 }));
101
102 tileOptionMenu.add(new JMenuItem(new AbstractAction("Request Update") {
103 public void actionPerformed(ActionEvent ae) {
104 if (clickedTile != null)
105 {
106 clickedTile.requestUpdate();
107 needRedraw = true;
108 Main.map.repaint();
109 }
110 }
111 }));
112
113 tileOptionMenu.add(new JMenuItem(new AbstractAction("Load All Tiles") {
114 public void actionPerformed(ActionEvent ae) {
115 loadAllTiles();
116 needRedraw = true;
117 Main.map.repaint();
118 }
119 }));
120
121 SwingUtilities.invokeLater(new Runnable(){
122 public void run() {
123 Main.map.mapView.addMouseListener(new MouseAdapter() {
124 @Override public void mouseClicked(MouseEvent e) {
125 if (e.getButton() != MouseEvent.BUTTON3)
126 return;
127 clickedTile = getTileForPixelpos(e.getX(), e.getY());
128 tileOptionMenu.show(e.getComponent(), e.getX(), e.getY());
129 }
130 });
131
132 Main.map.mapView.addLayerChangeListener(new MapView.LayerChangeListener(){
133 public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
134 public void layerAdded(Layer newLayer) {}
135 public void layerRemoved(Layer oldLayer) {
136 Main.pref.listener.remove(SlippyMapLayer.this);
137 }
138 });
139 }
140 });
141 }
142
143 void loadAllTiles()
144 {
145 MapView mv = Main.map.mapView;
146 LatLon topLeft = mv.getLatLon(0, 0);
147 LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight());
148 z12x0 = lonToTileX(topLeft.lon());
149 z12x1 = lonToTileX(botRight.lon());
150 z12y0 = latToTileY(topLeft.lat());
151 z12y1 = latToTileY(botRight.lat());
152 if (z12x0>z12x1) { int tmp = z12x0; z12x0=z12x1; z12x1=tmp; }
153 if (z12y0>z12y1) { int tmp = z12y0; z12y0=z12y1; z12y1=tmp; }
154 if (z12x1-z12x0 > 18) return;
155 if (z12y1-z12y0 > 18) return;
156 for(int x = z12x0-1; x <= z12x1; x++)
157 {
158 for (int y=z12y0-1; y <= z12y1; y++)
159 {
160 int key = (y <<19) + x;
161 SlippyMapTile tile = tileStorage.get(12).get(key);
162 if (tile.getImage() == null) tile.loadImage();
163 }
164 }
165 }
166
167
168 /**
169 */
170 @Override public void paint(Graphics g, MapView mv)
171 {
172 LatLon topLeft = mv.getLatLon(0, 0);
173 LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight());
174 Graphics oldg = g;
175
176 if (lastTopLeft != null &&
177 lastBotRight != null &&
178 topLeft.equalsEpsilon(lastTopLeft) &&
179 botRight.equalsEpsilon(lastBotRight) &&
180 bufferImage != null &&
181 mv.getWidth() == bufferImage.getWidth(null) &&
182 mv.getHeight() == bufferImage.getHeight(null) &&
183 !needRedraw)
184 {
185
186 g.drawImage(bufferImage, 0, 0, null);
187 return;
188 }
189
190 needRedraw = false;
191 lastTopLeft = topLeft;
192 lastBotRight = botRight;
193 bufferImage = mv.createImage(mv.getWidth(), mv.getHeight());
194 g = bufferImage.getGraphics();
195
196 z12x0 = lonToTileX(topLeft.lon());
197 z12x1 = lonToTileX(botRight.lon());
198 z12y0 = latToTileY(topLeft.lat());
199 z12y1 = latToTileY(botRight.lat());
200
201 if (z12x0>z12x1) { int tmp = z12x0; z12x0=z12x1; z12x1=tmp; }
202 if (z12y0>z12y1) { int tmp = z12y0; z12y0=z12y1; z12y1=tmp; }
203
204 if (z12x1-z12x0 > 18) return;
205 if (z12y1-z12y0 > 18) return;
206
207 for (int x = z12x0 -1; x <= z12x1+1; x++)
208 {
209 double lon = tileXToLon(x);
210 for (int y = z12y0 -1; y <= z12y1+1; y++)
211 {
212 LatLon tmpLL = new LatLon(tileYToLat(y), lon);
213 pixelpos[x-z12x0+1][y-z12y0+1] = mv.getPoint(Main.proj.latlon2eastNorth(tmpLL));
214 }
215 }
216
217 int fontHeight = g.getFontMetrics().getHeight();
218
219 g.setColor(Color.DARK_GRAY);
220
221 for (int x = z12x0 -1; x <= z12x1; x++)
222 {
223 for (int y = z12y0 -1; y <= z12y1; y++)
224 {
225 int key = (y << 19) + x;
226 SlippyMapTile tile = tileStorage.get(12).get(key);
227
228 if (tile == null)
229 {
230 tileStorage.get(12).put(key, tile = new SlippyMapTile(x, y, 12));
231 }
232 Image img = tile.getImage();
233
234 if (img != null)
235 {
236 Point p = pixelpos[x-z12x0+1][y-z12y0+1];
237 Point p2 = pixelpos[x-z12x0+2][y-z12y0+2];
238 g.drawImage(img, p.x, p.y, p2.x-p.x, p2.y-p.y, this);
239 }
240 }
241 }
242
243 for (int x = z12x0 -1; x <= z12x1; x++)
244 {
245 Point p = pixelpos[x-z12x0+1][0];
246
247 if (x % 32 == 0)
248 {
249 // level 7 tile boundary
250 g.fillRect(p.x - 1, 0, 3, mv.getHeight());
251 }
252 else
253 {
254 g.drawLine(p.x, 0, p.x, mv.getHeight());
255 }
256
257 for (int y = z12y0 -1; y <= z12y1; y++)
258 {
259 int key = (y <<19) + x;
260 int texty = p.y + 2 + fontHeight;
261 SlippyMapTile tile = tileStorage.get(12).get(key);
262 p = pixelpos[x-z12x0+1][y-z12y0+2];
263 g.drawString("x=" + x + " y="+ y + " z=12", p.x + 2, texty);
264 texty += 1 + fontHeight;
265 if ((x % 32 == 0) && (y % 32 == 0))
266 {
267 g.drawString("x=" + x/32 + " y="+ y/32 + " z=7", p.x+2, texty);
268 texty += 1 + fontHeight;
269 }
270
271 String md = tile.getMetadata();
272 if (md != null)
273 {
274 g.drawString(md, p.x+2, texty);
275 texty += 1 + fontHeight;
276 }
277
278 if (tile.getImage() == null)
279 {
280 g.drawString("image not loaded", p.x+2, texty);
281 texty += 1 + fontHeight;
282 }
283
284 if (x == z12x0-1)
285 {
286 if (y % 32 == 31)
287 {
288 g.fillRect(0, p.y - 1, mv.getWidth(), 3);
289 }
290 else
291 {
292 g.drawLine(0, p.y, mv.getWidth(), p.y);
293 }
294 }
295 }
296 }
297
298 oldg.drawImage(bufferImage, 0, 0, null);
299
300 }
301
302 SlippyMapTile getTileForPixelpos(int px, int py)
303 {
304 int tilex=z12x1;
305 int tiley=z12y1;
306 for (int x = z12x0; x <= z12x1; x++)
307 {
308
309 if (pixelpos[x-z12x0+1][0].x > px)
310 {
311 tilex = x-1;
312 break;
313 }
314 }
315 if (tilex==-1) return null;
316 for (int y = z12y0; y <= z12y1; y++)
317 {
318
319 if (pixelpos[0][y-z12y0+1].y > py)
320 {
321 tiley = y-1;
322 break;
323 }
324 }
325 if (tiley==-1) return null;
326
327 int key = (tiley <<19) + tilex;
328 SlippyMapTile tile = tileStorage.get(12).get(key);
329 if (tile==null) tileStorage.get(12).put(key, tile = new SlippyMapTile(tilex, tiley, 12));
330 return tile;
331 }
332
333 @Override
334 public Icon getIcon() {
335 // TODO Auto-generated method stub
336 return ImageProvider.get("slippymap");
337 }
338
339 @Override
340 public Object getInfoComponent() {
341 // TODO Auto-generated method stub
342 return null;
343 }
344
345 @Override public Component[] getMenuEntries() {
346 /*
347 JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
348 color.addActionListener(new ActionListener(){
349 public void actionPerformed(ActionEvent e) {
350 String col = Main.pref.get("color.layer "+name, Main.pref.get("color.gps marker", ColorHelper.color2html(Color.gray)));
351 JColorChooser c = new JColorChooser(ColorHelper.html2color(col));
352 Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
353 int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
354 switch (answer) {
355 case 0:
356 Main.pref.put("color.layer "+name, ColorHelper.color2html(c.getColor()));
357 break;
358 case 1:
359 return;
360 case 2:
361 Main.pref.put("color.layer "+name, null);
362 break;
363 }
364 Main.map.repaint();
365 }
366 });
367 */
368
369 return new Component[] {
370 new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
371 new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
372 new JSeparator(),
373 // color,
374 new JMenuItem(new RenameLayerAction(associatedFile, this)),
375 new JSeparator(),
376 new JMenuItem(new LayerListPopup.InfoAction(this))
377 };
378 }
379
380 @Override
381 public String getToolTipText() {
382 // TODO Auto-generated method stub
383 return null;
384 }
385
386 @Override
387 public boolean isMergable(Layer other) {
388 return false;
389 }
390
391 @Override
392 public void mergeFrom(Layer from) {
393 }
394
395 @Override
396 public void visitBoundingBox(BoundingXYVisitor v) {
397 // TODO Auto-generated method stub
398 }
399
400 private int latToTileY(double lat) {
401 double l = lat / 180 * Math.PI;
402 double pf = Math.log(Math.tan(l) + (1/Math.cos(l)));
403 return (int) (2048.0 * (Math.PI - pf) / Math.PI);
404 }
405
406 private int lonToTileX(double lon) {
407 return (int) (512.0 * (lon + 180.0) / 45.0);
408 }
409
410 private double tileYToLat(int y) {
411 return Math.atan(Math.sinh(Math.PI - (Math.PI*y / 2048.0))) * 180 / Math.PI;
412 }
413
414 private double tileXToLon(int x) {
415 return x * 45.0 / 512.0 - 180.0;
416 }
417
418 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
419
420 boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0);
421 // Repaint immediately if we are done, otherwise batch up
422 // repaint requests every 100 milliseconds
423 needRedraw = true;
424 Main.map.repaint(done ? 0 : 100);
425 return !done;
426 }
427}
Note: See TracBrowser for help on using the repository browser.