source: osm/applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java@ 30244

Last change on this file since 30244 was 30244, checked in by glebius, 11 years ago

To match getPosition() and simplify code rename setDisplayPositionByLatLon()
into setDisplayPosition(Coordinate to, ...).

File size: 35.4 KB
Line 
1// License: GPL. For details, see Readme.txt file.
2package org.openstreetmap.gui.jmapviewer;
3
4import java.awt.Dimension;
5import java.awt.Font;
6import java.awt.Graphics;
7import java.awt.Insets;
8import java.awt.Point;
9import java.awt.event.ActionEvent;
10import java.awt.event.ActionListener;
11import java.awt.event.MouseEvent;
12import java.util.LinkedList;
13import java.util.List;
14
15import javax.swing.ImageIcon;
16import javax.swing.JButton;
17import javax.swing.JPanel;
18import javax.swing.JSlider;
19import javax.swing.event.ChangeEvent;
20import javax.swing.event.ChangeListener;
21import javax.swing.event.EventListenerList;
22
23import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent;
24import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent.COMMAND;
25import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
26import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener;
27import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
28import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
29import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
30import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
31import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
32import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
33import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
34import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
35
36/**
37 * Provides a simple panel that displays pre-rendered map tiles loaded from the
38 * OpenStreetMap project.
39 *
40 * @author Jan Peter Stotz
41 *
42 */
43public class JMapViewer extends JPanel implements TileLoaderListener {
44
45 private static final long serialVersionUID = 1L;
46
47 /**
48 * Vectors for clock-wise tile painting
49 */
50 protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) };
51
52 public static final int MAX_ZOOM = 22;
53 public static final int MIN_ZOOM = 0;
54
55 protected List<MapMarker> mapMarkerList;
56 protected List<MapRectangle> mapRectangleList;
57 protected List<MapPolygon> mapPolygonList;
58
59 protected boolean mapMarkersVisible;
60 protected boolean mapRectanglesVisible;
61 protected boolean mapPolygonsVisible;
62
63 protected boolean tileGridVisible;
64 protected boolean scrollWrapEnabled;
65
66 protected TileController tileController;
67
68 /**
69 * x- and y-position of the center of this map-panel on the world map
70 * denoted in screen pixel regarding the current zoom level.
71 */
72 protected Point center;
73
74 /**
75 * Current zoom level
76 */
77 protected int zoom;
78
79 protected JSlider zoomSlider;
80 protected JButton zoomInButton;
81 protected JButton zoomOutButton;
82
83 public static enum ZOOM_BUTTON_STYLE {
84 HORIZONTAL,
85 VERTICAL
86 }
87 protected ZOOM_BUTTON_STYLE zoomButtonStyle;
88
89 private TileSource tileSource;
90
91 protected AttributionSupport attribution = new AttributionSupport();
92
93 /**
94 * Creates a standard {@link JMapViewer} instance that can be controlled via
95 * mouse: hold right mouse button for moving, double click left mouse button
96 * or use mouse wheel for zooming. Loaded tiles are stored the
97 * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for
98 * retrieving the tiles.
99 */
100 public JMapViewer() {
101 this(new MemoryTileCache(), 8);
102 new DefaultMapController(this);
103 }
104
105 public JMapViewer(TileCache tileCache, int downloadThreadCount) {
106 super();
107 JobDispatcher.setMaxWorkers(downloadThreadCount);
108 tileSource = new OsmTileSource.Mapnik();
109 tileController = new TileController(tileSource, tileCache, this);
110 mapMarkerList = new LinkedList<MapMarker>();
111 mapPolygonList = new LinkedList<MapPolygon>();
112 mapRectangleList = new LinkedList<MapRectangle>();
113 mapMarkersVisible = true;
114 mapRectanglesVisible = true;
115 mapPolygonsVisible = true;
116 tileGridVisible = false;
117 setLayout(null);
118 initializeZoomSlider();
119 setMinimumSize(new Dimension(tileSource.getTileSize(), tileSource.getTileSize()));
120 setPreferredSize(new Dimension(400, 400));
121 setDisplayPosition(new Coordinate(50, 9), 3);
122 //setToolTipText("");
123 }
124
125 @Override
126 public String getToolTipText(MouseEvent event) {
127 // Point screenPoint = event.getLocationOnScreen();
128 // Coordinate c = getPosition(screenPoint);
129 return super.getToolTipText(event);
130 }
131
132 protected void initializeZoomSlider() {
133 zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom());
134 zoomSlider.setOrientation(JSlider.VERTICAL);
135 zoomSlider.setBounds(10, 10, 30, 150);
136 zoomSlider.setOpaque(false);
137 zoomSlider.addChangeListener(new ChangeListener() {
138 public void stateChanged(ChangeEvent e) {
139 setZoom(zoomSlider.getValue());
140 }
141 });
142 zoomSlider.setFocusable(false);
143 add(zoomSlider);
144 int size = 18;
145 try {
146 ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/plus.png"));
147 zoomInButton = new JButton(icon);
148 } catch (Exception e) {
149 zoomInButton = new JButton("+");
150 zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9));
151 zoomInButton.setMargin(new Insets(0, 0, 0, 0));
152 }
153 zoomInButton.setBounds(4, 155, size, size);
154 zoomInButton.addActionListener(new ActionListener() {
155
156 public void actionPerformed(ActionEvent e) {
157 zoomIn();
158 }
159 });
160 zoomInButton.setFocusable(false);
161 add(zoomInButton);
162 try {
163 ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/minus.png"));
164 zoomOutButton = new JButton(icon);
165 } catch (Exception e) {
166 zoomOutButton = new JButton("-");
167 zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9));
168 zoomOutButton.setMargin(new Insets(0, 0, 0, 0));
169 }
170 zoomOutButton.setBounds(8 + size, 155, size, size);
171 zoomOutButton.addActionListener(new ActionListener() {
172
173 public void actionPerformed(ActionEvent e) {
174 zoomOut();
175 }
176 });
177 zoomOutButton.setFocusable(false);
178 add(zoomOutButton);
179 }
180
181 /**
182 * Changes the map pane so that it is centered on the specified coordinate
183 * at the given zoom level.
184 *
185 * @param lat
186 * latitude of the specified coordinate
187 * @param lon
188 * longitude of the specified coordinate
189 * @param zoom
190 * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM}
191 */
192 public void setDisplayPosition(Coordinate to, int zoom) {
193 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), to, zoom);
194 }
195
196 /**
197 * Changes the map pane so that the specified coordinate at the given zoom
198 * level is displayed on the map at the screen coordinate
199 * <code>mapPoint</code>.
200 *
201 * @param mapPoint
202 * point on the map denoted in pixels where the coordinate should
203 * be set
204 * @param lat
205 * latitude of the specified coordinate
206 * @param lon
207 * longitude of the specified coordinate
208 * @param zoom
209 * {@link #MIN_ZOOM} <= zoom level <=
210 * {@link TileSource#getMaxZoom()}
211 */
212 public void setDisplayPosition(Point mapPoint, Coordinate to, int zoom) {
213 int x = OsmMercator.LonToX(to.getLon(), zoom);
214 int y = OsmMercator.LatToY(to.getLat(), zoom);
215 setDisplayPosition(mapPoint, x, y, zoom);
216 }
217
218 public void setDisplayPosition(int x, int y, int zoom) {
219 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom);
220 }
221
222 public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) {
223 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < MIN_ZOOM)
224 return;
225
226 // Get the plain tile number
227 Point p = new Point();
228 p.x = x - mapPoint.x + getWidth() / 2;
229 p.y = y - mapPoint.y + getHeight() / 2;
230 center = p;
231 setIgnoreRepaint(true);
232 try {
233 int oldZoom = this.zoom;
234 this.zoom = zoom;
235 if (oldZoom != zoom) {
236 zoomChanged(oldZoom);
237 }
238 if (zoomSlider.getValue() != zoom) {
239 zoomSlider.setValue(zoom);
240 }
241 } finally {
242 setIgnoreRepaint(false);
243 repaint();
244 }
245 }
246
247 /**
248 * Sets the displayed map pane and zoom level so that all chosen map elements are
249 * visible.
250 */
251 public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) {
252 int nbElemToCheck = 0;
253 if (markers && mapMarkerList != null)
254 nbElemToCheck += mapMarkerList.size();
255 if (rectangles && mapRectangleList != null)
256 nbElemToCheck += mapRectangleList.size();
257 if (polygons && mapPolygonList != null)
258 nbElemToCheck += mapPolygonList.size();
259 if (nbElemToCheck == 0)
260 return;
261
262 int x_min = Integer.MAX_VALUE;
263 int y_min = Integer.MAX_VALUE;
264 int x_max = Integer.MIN_VALUE;
265 int y_max = Integer.MIN_VALUE;
266 int mapZoomMax = tileController.getTileSource().getMaxZoom();
267
268 if (markers) {
269 for (MapMarker marker : mapMarkerList) {
270 if(marker.isVisible()){
271 int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
272 int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
273 x_max = Math.max(x_max, x);
274 y_max = Math.max(y_max, y);
275 x_min = Math.min(x_min, x);
276 y_min = Math.min(y_min, y);
277 }
278 }
279 }
280
281 if (rectangles) {
282 for (MapRectangle rectangle : mapRectangleList) {
283 if(rectangle.isVisible()){
284 x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
285 y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
286 x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
287 y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
288 }
289 }
290 }
291
292 if (polygons) {
293 for (MapPolygon polygon : mapPolygonList) {
294 if(polygon.isVisible()){
295 for (ICoordinate c : polygon.getPoints()) {
296 int x = OsmMercator.LonToX(c.getLon(), mapZoomMax);
297 int y = OsmMercator.LatToY(c.getLat(), mapZoomMax);
298 x_max = Math.max(x_max, x);
299 y_max = Math.max(y_max, y);
300 x_min = Math.min(x_min, x);
301 y_min = Math.min(y_min, y);
302 }
303 }
304 }
305 }
306
307 int height = Math.max(0, getHeight());
308 int width = Math.max(0, getWidth());
309 int newZoom = mapZoomMax;
310 int x = x_max - x_min;
311 int y = y_max - y_min;
312 while (x > width || y > height) {
313 newZoom--;
314 x >>= 1;
315 y >>= 1;
316 }
317 x = x_min + (x_max - x_min) / 2;
318 y = y_min + (y_max - y_min) / 2;
319 int z = 1 << (mapZoomMax - newZoom);
320 x /= z;
321 y /= z;
322 setDisplayPosition(x, y, newZoom);
323 }
324
325
326 /**
327 * Sets the displayed map pane and zoom level so that all map markers are
328 * visible.
329 */
330 public void setDisplayToFitMapMarkers() {
331 setDisplayToFitMapElements(true, false, false);
332 }
333
334 /**
335 * Sets the displayed map pane and zoom level so that all map rectangles are
336 * visible.
337 */
338 public void setDisplayToFitMapRectangles() {
339 setDisplayToFitMapElements(false, true, false);
340 }
341
342 /**
343 * Sets the displayed map pane and zoom level so that all map polygons are
344 * visible.
345 */
346 public void setDisplayToFitMapPolygons() {
347 setDisplayToFitMapElements(false, false, true);
348 }
349
350 /**
351 * @return the center
352 */
353 public Point getCenter() {
354 return center;
355 }
356
357 /**
358 * @param center the center to set
359 */
360 public void setCenter(Point center) {
361 this.center = center;
362 }
363
364 /**
365 * Calculates the latitude/longitude coordinate of the center of the
366 * currently displayed map area.
367 *
368 * @return latitude / longitude
369 */
370 public Coordinate getPosition() {
371 double lon = OsmMercator.XToLon(center.x, zoom);
372 double lat = OsmMercator.YToLat(center.y, zoom);
373 return new Coordinate(lat, lon);
374 }
375
376 /**
377 * Converts the relative pixel coordinate (regarding the top left corner of
378 * the displayed map) into a latitude / longitude coordinate
379 *
380 * @param mapPoint
381 * relative pixel coordinate regarding the top left corner of the
382 * displayed map
383 * @return latitude / longitude
384 */
385 public Coordinate getPosition(Point mapPoint) {
386 return getPosition(mapPoint.x, mapPoint.y);
387 }
388
389 /**
390 * Converts the relative pixel coordinate (regarding the top left corner of
391 * the displayed map) into a latitude / longitude coordinate
392 *
393 * @param mapPointX
394 * @param mapPointY
395 * @return latitude / longitude
396 */
397 public Coordinate getPosition(int mapPointX, int mapPointY) {
398 int x = center.x + mapPointX - getWidth() / 2;
399 int y = center.y + mapPointY - getHeight() / 2;
400 double lon = OsmMercator.XToLon(x, zoom);
401 double lat = OsmMercator.YToLat(y, zoom);
402 return new Coordinate(lat, lon);
403 }
404
405 /**
406 * Calculates the position on the map of a given coordinate
407 *
408 * @param lat
409 * @param lon
410 * @param checkOutside
411 * @return point on the map or <code>null</code> if the point is not visible
412 * and checkOutside set to <code>true</code>
413 */
414 public Point getMapPosition(double lat, double lon, boolean checkOutside) {
415 int x = OsmMercator.LonToX(lon, zoom);
416 int y = OsmMercator.LatToY(lat, zoom);
417 x -= center.x - getWidth() / 2;
418 y -= center.y - getHeight() / 2;
419 if (checkOutside) {
420 if (x < 0 || y < 0 || x > getWidth() || y > getHeight())
421 return null;
422 }
423 return new Point(x, y);
424 }
425
426 /**
427 * Calculates the position on the map of a given coordinate
428 *
429 * @param lat Latitude
430 * @param offset Offset respect Latitude
431 * @param checkOutside
432 * @return Integer the radius in pixels
433 */
434 public Integer getLatOffset(double lat, double offset, boolean checkOutside) {
435 int y = OsmMercator.LatToY(lat+offset, zoom);
436 y -= center.y - getHeight() / 2;
437 if (checkOutside) {
438 if (y < 0 || y > getHeight())
439 return null;
440 }
441 return y;
442 }
443
444 /**
445 * Calculates the position on the map of a given coordinate
446 *
447 * @param lat
448 * @param lon
449 * @return point on the map or <code>null</code> if the point is not visible
450 */
451 public Point getMapPosition(double lat, double lon) {
452 return getMapPosition(lat, lon, true);
453 }
454
455 /**
456 * Calculates the position on the map of a given coordinate
457 *
458 * @param marker MapMarker object that define the x,y coordinate
459 * @return Integer the radius in pixels
460 */
461 public Integer getRadius(MapMarker marker, Point p) {
462 if(marker.getMarkerStyle() == MapMarker.STYLE.FIXED)
463 return (int)marker.getRadius();
464 else if(p!=null){
465 Integer radius = getLatOffset(marker.getLat(), marker.getRadius(), false);
466 radius = radius==null?null:p.y-radius.intValue();
467 return radius;
468 }else return null;
469 }
470
471 /**
472 * Calculates the position on the map of a given coordinate
473 *
474 * @param coord
475 * @return point on the map or <code>null</code> if the point is not visible
476 */
477 public Point getMapPosition(Coordinate coord) {
478 if (coord != null)
479 return getMapPosition(coord.getLat(), coord.getLon());
480 else
481 return null;
482 }
483
484 /**
485 * Calculates the position on the map of a given coordinate
486 *
487 * @param coord
488 * @return point on the map or <code>null</code> if the point is not visible
489 * and checkOutside set to <code>true</code>
490 */
491 public Point getMapPosition(ICoordinate coord, boolean checkOutside) {
492 if (coord != null)
493 return getMapPosition(coord.getLat(), coord.getLon(), checkOutside);
494 else
495 return null;
496 }
497
498 /**
499 * Gets the meter per pixel.
500 *
501 * @return the meter per pixel
502 * @author Jason Huntley
503 */
504 public double getMeterPerPixel() {
505 Point origin=new Point(5,5);
506 Point center=new Point(getWidth()/2, getHeight()/2);
507
508 double pDistance=center.distance(origin);
509
510 Coordinate originCoord=getPosition(origin);
511 Coordinate centerCoord=getPosition(center);
512
513 double mDistance=OsmMercator.getDistance(originCoord.getLat(), originCoord.getLon(),
514 centerCoord.getLat(), centerCoord.getLon());
515
516 return mDistance/pDistance;
517 }
518
519 @Override
520 protected void paintComponent(Graphics g) {
521 super.paintComponent(g);
522
523 int iMove = 0;
524
525 int tilesize = tileSource.getTileSize();
526 int tilex = center.x / tilesize;
527 int tiley = center.y / tilesize;
528 int off_x = (center.x % tilesize);
529 int off_y = (center.y % tilesize);
530
531 int w2 = getWidth() / 2;
532 int h2 = getHeight() / 2;
533 int posx = w2 - off_x;
534 int posy = h2 - off_y;
535
536 int diff_left = off_x;
537 int diff_right = tilesize - off_x;
538 int diff_top = off_y;
539 int diff_bottom = tilesize - off_y;
540
541 boolean start_left = diff_left < diff_right;
542 boolean start_top = diff_top < diff_bottom;
543
544 if (start_top) {
545 if (start_left) {
546 iMove = 2;
547 } else {
548 iMove = 3;
549 }
550 } else {
551 if (start_left) {
552 iMove = 1;
553 } else {
554 iMove = 0;
555 }
556 } // calculate the visibility borders
557 int x_min = -tilesize;
558 int y_min = -tilesize;
559 int x_max = getWidth();
560 int y_max = getHeight();
561
562 // calculate the length of the grid (number of squares per edge)
563 int gridLength = 1 << zoom;
564
565 // paint the tiles in a spiral, starting from center of the map
566 boolean painted = true;
567 int x = 0;
568 while (painted) {
569 painted = false;
570 for (int i = 0; i < 4; i++) {
571 if (i % 2 == 0) {
572 x++;
573 }
574 for (int j = 0; j < x; j++) {
575 if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) {
576 // tile is visible
577 Tile tile;
578 if (scrollWrapEnabled) {
579 // in case tilex is out of bounds, grab the tile to use for wrapping
580 int tilexWrap = (((tilex % gridLength) + gridLength) % gridLength);
581 tile = tileController.getTile(tilexWrap, tiley, zoom);
582 } else {
583 tile = tileController.getTile(tilex, tiley, zoom);
584 }
585 if (tile != null) {
586 tile.paint(g, posx, posy);
587 if (tileGridVisible) {
588 g.drawRect(posx, posy, tilesize, tilesize);
589 }
590 }
591 painted = true;
592 }
593 Point p = move[iMove];
594 posx += p.x * tilesize;
595 posy += p.y * tilesize;
596 tilex += p.x;
597 tiley += p.y;
598 }
599 iMove = (iMove + 1) % move.length;
600 }
601 }
602 // outer border of the map
603 int mapSize = tilesize << zoom;
604 if (scrollWrapEnabled) {
605 g.drawLine(0, h2 - center.y, getWidth(), h2 - center.y);
606 g.drawLine(0, h2 - center.y + mapSize, getWidth(), h2 - center.y + mapSize);
607 } else {
608 g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize);
609 }
610
611 // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20);
612
613 // keep x-coordinates from growing without bound if scroll-wrap is enabled
614 if (scrollWrapEnabled) {
615 center.x = center.x % mapSize;
616 }
617
618 if (mapPolygonsVisible && mapPolygonList != null) {
619 for (MapPolygon polygon : mapPolygonList) {
620 if(polygon.isVisible()) paintPolygon(g, polygon);
621 }
622 }
623
624 if (mapRectanglesVisible && mapRectangleList != null) {
625 for (MapRectangle rectangle : mapRectangleList) {
626 if(rectangle.isVisible()) paintRectangle(g, rectangle);
627 }
628 }
629
630 if (mapMarkersVisible && mapMarkerList != null) {
631 for (MapMarker marker : mapMarkerList) {
632 if(marker.isVisible())paintMarker(g, marker);
633 }
634 }
635
636 attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this);
637 }
638
639 /**
640 * Paint a single marker.
641 */
642 protected void paintMarker(Graphics g, MapMarker marker) {
643 Point p = getMapPosition(marker.getLat(), marker.getLon(), marker.getMarkerStyle()==MapMarker.STYLE.FIXED);
644 Integer radius = getRadius(marker, p);
645 if (scrollWrapEnabled) {
646 int tilesize = tileSource.getTileSize();
647 int mapSize = tilesize << zoom;
648 if (p == null) {
649 p = getMapPosition(marker.getLat(), marker.getLon(), false);
650 radius = getRadius(marker, p);
651 }
652 marker.paint(g, p, radius);
653 int xSave = p.x;
654 int xWrap = xSave;
655 // overscan of 15 allows up to 30-pixel markers to gracefully scroll off the edge of the panel
656 while ((xWrap -= mapSize) >= -15) {
657 p.x = xWrap;
658 marker.paint(g, p, radius);
659 }
660 xWrap = xSave;
661 while ((xWrap += mapSize) <= getWidth() + 15) {
662 p.x = xWrap;
663 marker.paint(g, p, radius);
664 }
665 } else {
666 if (p != null) {
667 marker.paint(g, p, radius);
668 }
669 }
670 }
671
672 /**
673 * Paint a single rectangle.
674 */
675 protected void paintRectangle(Graphics g, MapRectangle rectangle) {
676 Coordinate topLeft = rectangle.getTopLeft();
677 Coordinate bottomRight = rectangle.getBottomRight();
678 if (topLeft != null && bottomRight != null) {
679 Point pTopLeft = getMapPosition(topLeft, false);
680 Point pBottomRight = getMapPosition(bottomRight, false);
681 if (pTopLeft != null && pBottomRight != null) {
682 rectangle.paint(g, pTopLeft, pBottomRight);
683 if (scrollWrapEnabled) {
684 int tilesize = tileSource.getTileSize();
685 int mapSize = tilesize << zoom;
686 int xTopLeftSave = pTopLeft.x;
687 int xTopLeftWrap = xTopLeftSave;
688 int xBottomRightSave = pBottomRight.x;
689 int xBottomRightWrap = xBottomRightSave;
690 while ((xBottomRightWrap -= mapSize) >= 0) {
691 xTopLeftWrap -= mapSize;
692 pTopLeft.x = xTopLeftWrap;
693 pBottomRight.x = xBottomRightWrap;
694 rectangle.paint(g, pTopLeft, pBottomRight);
695 }
696 xTopLeftWrap = xTopLeftSave;
697 xBottomRightWrap = xBottomRightSave;
698 while ((xTopLeftWrap += mapSize) <= getWidth()) {
699 xBottomRightWrap += mapSize;
700 pTopLeft.x = xTopLeftWrap;
701 pBottomRight.x = xBottomRightWrap;
702 rectangle.paint(g, pTopLeft, pBottomRight);
703 }
704
705 }
706 }
707 }
708 }
709
710 /**
711 * Paint a single polygon.
712 */
713 protected void paintPolygon(Graphics g, MapPolygon polygon) {
714 List<? extends ICoordinate> coords = polygon.getPoints();
715 if (coords != null && coords.size() >= 3) {
716 List<Point> points = new LinkedList<Point>();
717 for (ICoordinate c : coords) {
718 Point p = getMapPosition(c, false);
719 if (p == null) {
720 return;
721 }
722 points.add(p);
723 }
724 polygon.paint(g, points);
725 if (scrollWrapEnabled) {
726 int tilesize = tileSource.getTileSize();
727 int mapSize = tilesize << zoom;
728 List<Point> pointsWrapped = new LinkedList<Point>(points);
729 boolean keepWrapping = true;
730 while (keepWrapping) {
731 for (Point p : pointsWrapped) {
732 p.x -= mapSize;
733 if (p.x < 0) {
734 keepWrapping = false;
735 }
736 }
737 polygon.paint(g, pointsWrapped);
738 }
739 pointsWrapped = new LinkedList<Point>(points);
740 keepWrapping = true;
741 while (keepWrapping) {
742 for (Point p : pointsWrapped) {
743 p.x += mapSize;
744 if (p.x > getWidth()) {
745 keepWrapping = false;
746 }
747 }
748 polygon.paint(g, pointsWrapped);
749 }
750 }
751 }
752 }
753
754 /**
755 * Moves the visible map pane.
756 *
757 * @param x
758 * horizontal movement in pixel.
759 * @param y
760 * vertical movement in pixel
761 */
762 public void moveMap(int x, int y) {
763 tileController.cancelOutstandingJobs(); // Clear outstanding load
764 center.x += x;
765 center.y += y;
766 repaint();
767 this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this));
768 }
769
770 /**
771 * @return the current zoom level
772 */
773 public int getZoom() {
774 return zoom;
775 }
776
777 /**
778 * Increases the current zoom level by one
779 */
780 public void zoomIn() {
781 setZoom(zoom + 1);
782 }
783
784 /**
785 * Increases the current zoom level by one
786 */
787 public void zoomIn(Point mapPoint) {
788 setZoom(zoom + 1, mapPoint);
789 }
790
791 /**
792 * Decreases the current zoom level by one
793 */
794 public void zoomOut() {
795 setZoom(zoom - 1);
796 }
797
798 /**
799 * Decreases the current zoom level by one
800 *
801 * @param mapPoint point to choose as center for new zoom level
802 */
803 public void zoomOut(Point mapPoint) {
804 setZoom(zoom - 1, mapPoint);
805 }
806
807 /**
808 * Set the zoom level and center point for display
809 *
810 * @param zoom new zoom level
811 * @param mapPoint point to choose as center for new zoom level
812 */
813 public void setZoom(int zoom, Point mapPoint) {
814 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom()
815 || zoom == this.zoom)
816 return;
817 Coordinate zoomPos = getPosition(mapPoint);
818 tileController.cancelOutstandingJobs(); // Clearing outstanding load
819 // requests
820 setDisplayPosition(mapPoint, zoomPos, zoom);
821
822 this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this));
823 }
824
825 /**
826 * Set the zoom level
827 *
828 * @param zoom new zoom level
829 */
830 public void setZoom(int zoom) {
831 setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2));
832 }
833
834 /**
835 * Every time the zoom level changes this method is called. Override it in
836 * derived implementations for adapting zoom dependent values. The new zoom
837 * level can be obtained via {@link #getZoom()}.
838 *
839 * @param oldZoom
840 * the previous zoom level
841 */
842 protected void zoomChanged(int oldZoom) {
843 zoomSlider.setToolTipText("Zoom level " + zoom);
844 zoomInButton.setToolTipText("Zoom to level " + (zoom + 1));
845 zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1));
846 zoomOutButton.setEnabled(zoom > tileController.getTileSource().getMinZoom());
847 zoomInButton.setEnabled(zoom < tileController.getTileSource().getMaxZoom());
848 }
849
850 public boolean isTileGridVisible() {
851 return tileGridVisible;
852 }
853
854 public void setTileGridVisible(boolean tileGridVisible) {
855 this.tileGridVisible = tileGridVisible;
856 repaint();
857 }
858
859 public boolean getMapMarkersVisible() {
860 return mapMarkersVisible;
861 }
862
863 /**
864 * Enables or disables painting of the {@link MapMarker}
865 *
866 * @param mapMarkersVisible
867 * @see #addMapMarker(MapMarker)
868 * @see #getMapMarkerList()
869 */
870 public void setMapMarkerVisible(boolean mapMarkersVisible) {
871 this.mapMarkersVisible = mapMarkersVisible;
872 repaint();
873 }
874
875 public void setMapMarkerList(List<MapMarker> mapMarkerList) {
876 this.mapMarkerList = mapMarkerList;
877 repaint();
878 }
879
880 public List<MapMarker> getMapMarkerList() {
881 return mapMarkerList;
882 }
883
884 public void setMapRectangleList(List<MapRectangle> mapRectangleList) {
885 this.mapRectangleList = mapRectangleList;
886 repaint();
887 }
888
889 public List<MapRectangle> getMapRectangleList() {
890 return mapRectangleList;
891 }
892
893 public void setMapPolygonList(List<MapPolygon> mapPolygonList) {
894 this.mapPolygonList = mapPolygonList;
895 repaint();
896 }
897
898 public List<MapPolygon> getMapPolygonList() {
899 return mapPolygonList;
900 }
901
902 public void addMapMarker(MapMarker marker) {
903 mapMarkerList.add(marker);
904 repaint();
905 }
906
907 public void removeMapMarker(MapMarker marker) {
908 mapMarkerList.remove(marker);
909 repaint();
910 }
911
912 public void removeAllMapMarkers() {
913 mapMarkerList.clear();
914 repaint();
915 }
916
917 public void addMapRectangle(MapRectangle rectangle) {
918 mapRectangleList.add(rectangle);
919 repaint();
920 }
921
922 public void removeMapRectangle(MapRectangle rectangle) {
923 mapRectangleList.remove(rectangle);
924 repaint();
925 }
926
927 public void removeAllMapRectangles() {
928 mapRectangleList.clear();
929 repaint();
930 }
931
932 public void addMapPolygon(MapPolygon polygon) {
933 mapPolygonList.add(polygon);
934 repaint();
935 }
936
937 public void removeMapPolygon(MapPolygon polygon) {
938 mapPolygonList.remove(polygon);
939 repaint();
940 }
941
942 public void removeAllMapPolygons() {
943 mapPolygonList.clear();
944 repaint();
945 }
946
947 public void setZoomContolsVisible(boolean visible) {
948 zoomSlider.setVisible(visible);
949 zoomInButton.setVisible(visible);
950 zoomOutButton.setVisible(visible);
951 }
952
953 public boolean getZoomContolsVisible() {
954 return zoomSlider.isVisible();
955 }
956
957 public void setTileSource(TileSource tileSource) {
958 if (tileSource.getMaxZoom() > MAX_ZOOM)
959 throw new RuntimeException("Maximum zoom level too high");
960 if (tileSource.getMinZoom() < MIN_ZOOM)
961 throw new RuntimeException("Minumim zoom level too low");
962 this.tileSource = tileSource;
963 tileController.setTileSource(tileSource);
964 zoomSlider.setMinimum(tileSource.getMinZoom());
965 zoomSlider.setMaximum(tileSource.getMaxZoom());
966 tileController.cancelOutstandingJobs();
967 if (zoom > tileSource.getMaxZoom()) {
968 setZoom(tileSource.getMaxZoom());
969 }
970
971 attribution.initialize(tileSource);
972 repaint();
973 }
974
975 public void tileLoadingFinished(Tile tile, boolean success) {
976 repaint();
977 }
978
979 public boolean isMapRectanglesVisible() {
980 return mapRectanglesVisible;
981 }
982
983 /**
984 * Enables or disables painting of the {@link MapRectangle}
985 *
986 * @param mapRectanglesVisible
987 * @see #addMapRectangle(MapRectangle)
988 * @see #getMapRectangleList()
989 */
990 public void setMapRectanglesVisible(boolean mapRectanglesVisible) {
991 this.mapRectanglesVisible = mapRectanglesVisible;
992 repaint();
993 }
994
995 public boolean isMapPolygonsVisible() {
996 return mapPolygonsVisible;
997 }
998
999 /**
1000 * Enables or disables painting of the {@link MapPolygon}
1001 *
1002 * @param mapPolygonsVisible
1003 * @see #addMapPolygon(MapPolygon)
1004 * @see #getMapPolygonList()
1005 */
1006 public void setMapPolygonsVisible(boolean mapPolygonsVisible) {
1007 this.mapPolygonsVisible = mapPolygonsVisible;
1008 repaint();
1009 }
1010
1011 public boolean isScrollWrapEnabled() {
1012 return scrollWrapEnabled;
1013 }
1014
1015 public void setScrollWrapEnabled(boolean scrollWrapEnabled) {
1016 this.scrollWrapEnabled = scrollWrapEnabled;
1017 repaint();
1018 }
1019
1020 public ZOOM_BUTTON_STYLE getZoomButtonStyle() {
1021 return zoomButtonStyle;
1022 }
1023
1024 public void setZoomButtonStyle(ZOOM_BUTTON_STYLE style) {
1025 zoomButtonStyle = style;
1026 if (zoomSlider == null || zoomInButton == null || zoomOutButton == null) {
1027 return;
1028 }
1029 switch (style) {
1030 case HORIZONTAL:
1031 zoomSlider.setBounds(10, 10, 30, 150);
1032 zoomInButton.setBounds(4, 155, 18, 18);
1033 zoomOutButton.setBounds(26, 155, 18, 18);
1034 break;
1035 case VERTICAL:
1036 zoomSlider.setBounds(10, 27, 30, 150);
1037 zoomInButton.setBounds(14, 8, 20, 20);
1038 zoomOutButton.setBounds(14, 176, 20, 20);
1039 break;
1040 default:
1041 zoomSlider.setBounds(10, 10, 30, 150);
1042 zoomInButton.setBounds(4, 155, 18, 18);
1043 zoomOutButton.setBounds(26, 155, 18, 18);
1044 break;
1045 }
1046 repaint();
1047 }
1048
1049 public TileController getTileController() {
1050 return tileController;
1051 }
1052
1053 /**
1054 * Return tile information caching class
1055 * @see TileLoaderListener#getTileCache()
1056 */
1057 public TileCache getTileCache() {
1058 return tileController.getTileCache();
1059 }
1060
1061 public void setTileLoader(TileLoader loader) {
1062 tileController.setTileLoader(loader);
1063 }
1064
1065 public AttributionSupport getAttribution() {
1066 return attribution;
1067 }
1068
1069 protected EventListenerList listenerList = new EventListenerList();
1070
1071 /**
1072 * @param listener listener to set
1073 */
1074 public void addJMVListener(JMapViewerEventListener listener) {
1075 listenerList.add(JMapViewerEventListener.class, listener);
1076 }
1077
1078 /**
1079 * @param listener listener to remove
1080 */
1081 public void removeJMVListener(JMapViewerEventListener listener) {
1082 listenerList.remove(JMapViewerEventListener.class, listener);
1083 }
1084
1085 /**
1086 * Send an update to all objects registered with viewer
1087 *
1088 * @param evt event to dispatch
1089 */
1090 void fireJMVEvent(JMVCommandEvent evt) {
1091 Object[] listeners = listenerList.getListenerList();
1092 for (int i=0; i<listeners.length; i+=2) {
1093 if (listeners[i]==JMapViewerEventListener.class) {
1094 ((JMapViewerEventListener)listeners[i+1]).processCommand(evt);
1095 }
1096 }
1097 }
1098}
Note: See TracBrowser for help on using the repository browser.