jmapviewer-1.02/0000755000175000017500000000000012224055556012613 5ustar felixfelixjmapviewer-1.02/Gpl.txt0000644000175000017500000004325412223625012014073 0ustar felixfelix GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. jmapviewer-1.02/build.xml0000644000175000017500000000603712224055432014433 0ustar felixfelix jmapviewer-1.02/src/0000755000175000017500000000000012224055556013402 5ustar felixfelixjmapviewer-1.02/src/org/0000755000175000017500000000000012202517774014172 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/0000755000175000017500000000000012202517774017060 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/0000755000175000017500000000000012202517774017644 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/0000755000175000017500000000000012223624304022004 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java0000644000175000017500000001424112223625012025477 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import org.openstreetmap.gui.jmapviewer.checkBoxTree.CheckBoxNodePanel; import org.openstreetmap.gui.jmapviewer.checkBoxTree.CheckBoxTree; import org.openstreetmap.gui.jmapviewer.interfaces.MapObject; /** * Tree of layers for JMapViewer component * @author galo */ public class JMapViewerTree extends JPanel{ /** Serial Version UID */ private static final long serialVersionUID = 3050203054402323972L; private JMapViewer map; private CheckBoxTree tree; private JPanel treePanel; private JSplitPane splitPane; public JMapViewerTree(String name){ this(name, false); } public JMapViewerTree(String name, boolean treeVisible){ super(); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); tree = new CheckBoxTree(name); treePanel = new JPanel(); treePanel.setLayout(new BorderLayout()); treePanel.add(tree, BorderLayout.CENTER); treePanel.add(new JLabel("
Use right mouse button to
show/hide texts
"), BorderLayout.SOUTH); map = new JMapViewer(); splitPane.setOneTouchExpandable(true); splitPane.setDividerLocation(150); //Provide minimum sizes for the two components in the split pane Dimension minimumSize = new Dimension(100, 50); //tree.setMinimumSize(minimumSize); map.setMinimumSize(minimumSize); createRefresh(); setLayout(new BorderLayout()); setTreeVisible(treeVisible); tree.addNodeListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { e.getSource(); AbstractLayer layer = ((CheckBoxNodePanel)e.getComponent()).getData().getAbstractLayer(); if(layer!=null) JMapViewerTree.this.createPopupMenu(layer).show(e.getComponent(), e.getX(), e.getY()); } } }); } private JPopupMenu createPopupMenu(final AbstractLayer layer) { JMenuItem menuItemShow = new JMenuItem("show texts"); JMenuItem menuItemHide = new JMenuItem("hide texts"); //Create the popup menu. JPopupMenu popup = new JPopupMenu(); // Create items if(layer.isVisibleTexts()==null){ popup.add(menuItemShow); popup.add(menuItemHide); }else if(layer.isVisibleTexts()) popup.add(menuItemHide); else popup.add(menuItemShow); menuItemShow.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { setVisibleTexts(layer, true); if(layer.getParent()!=null) layer.getParent().calculateVisibleTexts(); map.repaint(); } }); menuItemHide.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { setVisibleTexts(layer, false); if(layer.getParent()!=null) layer.getParent().calculateVisibleTexts(); map.repaint(); } }); return popup; } private void setVisibleTexts(AbstractLayer layer, boolean visible){ layer.setVisibleTexts(visible); if(layer instanceof LayerGroup){ LayerGroup group = (LayerGroup)layer; if(group.getLayers()!=null) for(AbstractLayer al: group.getLayers()) setVisibleTexts(al, visible); } } public Layer addLayer(String name){ Layer layer = new Layer(name); this.addLayer(layer); return layer; } public JMapViewerTree addLayer(Layer layer){ tree.addLayer(layer); return this; } public JMapViewerTree addLayer(MapObject element){ //element.getLayer().add(element); return addLayer(element.getLayer()); } public Layer removeFromLayer(MapObject element){ element.getLayer().getElements().remove(element); return element.getLayer(); } public static int size(List list){ return list==null?0:list.size(); } public JMapViewer getViewer(){ return map; } public CheckBoxTree getTree(){ return tree; } public void addMapObject(MapObject o){ } public void setTreeVisible(boolean visible){ removeAll(); revalidate(); if(visible){ splitPane.setLeftComponent(treePanel); splitPane.setRightComponent(map); add(splitPane, BorderLayout.CENTER); }else add(map, BorderLayout.CENTER); repaint(); } private void createRefresh(){ tree.getModel().addTreeModelListener(new TreeModelListener() { @Override public void treeNodesChanged(final TreeModelEvent e) { repaint(); } @Override public void treeNodesInserted(TreeModelEvent arg0) { // TODO Auto-generated method stub } @Override public void treeNodesRemoved(TreeModelEvent arg0) { // TODO Auto-generated method stub } @Override public void treeStructureChanged(TreeModelEvent arg0) { // TODO Auto-generated method stub } }); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java0000644000175000017500000010671512223625012024667 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.LinkedList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent.COMMAND; import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener; import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon; import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle; import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource; /** * * Provides a simple panel that displays pre-rendered map tiles loaded from the * OpenStreetMap project. * * @author Jan Peter Stotz * */ public class JMapViewer extends JPanel implements TileLoaderListener { private static final long serialVersionUID = 1L; /** * Vectors for clock-wise tile painting */ protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) }; public static final int MAX_ZOOM = 22; public static final int MIN_ZOOM = 0; protected List mapMarkerList; protected List mapRectangleList; protected List mapPolygonList; protected boolean mapMarkersVisible; protected boolean mapRectanglesVisible; protected boolean mapPolygonsVisible; protected boolean tileGridVisible; protected boolean scrollWrapEnabled; protected TileController tileController; /** * x- and y-position of the center of this map-panel on the world map * denoted in screen pixel regarding the current zoom level. */ protected Point center; /** * Current zoom level */ protected int zoom; protected JSlider zoomSlider; protected JButton zoomInButton; protected JButton zoomOutButton; public static enum ZOOM_BUTTON_STYLE { HORIZONTAL, VERTICAL } protected ZOOM_BUTTON_STYLE zoomButtonStyle; private TileSource tileSource; protected AttributionSupport attribution = new AttributionSupport(); /** * Creates a standard {@link JMapViewer} instance that can be controlled via * mouse: hold right mouse button for moving, double click left mouse button * or use mouse wheel for zooming. Loaded tiles are stored the * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for * retrieving the tiles. */ public JMapViewer() { this(new MemoryTileCache(), 8); new DefaultMapController(this); } public JMapViewer(TileCache tileCache, int downloadThreadCount) { super(); JobDispatcher.setMaxWorkers(downloadThreadCount); tileSource = new OsmTileSource.Mapnik(); tileController = new TileController(tileSource, tileCache, this); mapMarkerList = new LinkedList(); mapPolygonList = new LinkedList(); mapRectangleList = new LinkedList(); mapMarkersVisible = true; mapRectanglesVisible = true; mapPolygonsVisible = true; tileGridVisible = false; setLayout(null); initializeZoomSlider(); setMinimumSize(new Dimension(tileSource.getTileSize(), tileSource.getTileSize())); setPreferredSize(new Dimension(400, 400)); setDisplayPositionByLatLon(50, 9, 3); //setToolTipText(""); } @Override public String getToolTipText(MouseEvent event) { // Point screenPoint = event.getLocationOnScreen(); // Coordinate c = getPosition(screenPoint); return super.getToolTipText(event); } protected void initializeZoomSlider() { zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom()); zoomSlider.setOrientation(JSlider.VERTICAL); zoomSlider.setBounds(10, 10, 30, 150); zoomSlider.setOpaque(false); zoomSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setZoom(zoomSlider.getValue()); } }); zoomSlider.setFocusable(false); add(zoomSlider); int size = 18; try { ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/plus.png")); zoomInButton = new JButton(icon); } catch (Exception e) { zoomInButton = new JButton("+"); zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9)); zoomInButton.setMargin(new Insets(0, 0, 0, 0)); } zoomInButton.setBounds(4, 155, size, size); zoomInButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { zoomIn(); } }); zoomInButton.setFocusable(false); add(zoomInButton); try { ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/minus.png")); zoomOutButton = new JButton(icon); } catch (Exception e) { zoomOutButton = new JButton("-"); zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9)); zoomOutButton.setMargin(new Insets(0, 0, 0, 0)); } zoomOutButton.setBounds(8 + size, 155, size, size); zoomOutButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { zoomOut(); } }); zoomOutButton.setFocusable(false); add(zoomOutButton); } /** * Changes the map pane so that it is centered on the specified coordinate * at the given zoom level. * * @param lat * latitude of the specified coordinate * @param lon * longitude of the specified coordinate * @param zoom * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM} */ public void setDisplayPositionByLatLon(double lat, double lon, int zoom) { setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), lat, lon, zoom); } /** * Changes the map pane so that the specified coordinate at the given zoom * level is displayed on the map at the screen coordinate * mapPoint. * * @param mapPoint * point on the map denoted in pixels where the coordinate should * be set * @param lat * latitude of the specified coordinate * @param lon * longitude of the specified coordinate * @param zoom * {@link #MIN_ZOOM} <= zoom level <= * {@link TileSource#getMaxZoom()} */ public void setDisplayPositionByLatLon(Point mapPoint, double lat, double lon, int zoom) { int x = OsmMercator.LonToX(lon, zoom); int y = OsmMercator.LatToY(lat, zoom); setDisplayPosition(mapPoint, x, y, zoom); } public void setDisplayPosition(int x, int y, int zoom) { setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom); } public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { if (zoom > tileController.getTileSource().getMaxZoom() || zoom < MIN_ZOOM) return; // Get the plain tile number Point p = new Point(); p.x = x - mapPoint.x + getWidth() / 2; p.y = y - mapPoint.y + getHeight() / 2; center = p; setIgnoreRepaint(true); try { int oldZoom = this.zoom; this.zoom = zoom; if (oldZoom != zoom) { zoomChanged(oldZoom); } if (zoomSlider.getValue() != zoom) { zoomSlider.setValue(zoom); } } finally { setIgnoreRepaint(false); repaint(); } } /** * Sets the displayed map pane and zoom level so that all chosen map elements are * visible. */ public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) { int nbElemToCheck = 0; if (markers && mapMarkerList != null) nbElemToCheck += mapMarkerList.size(); if (rectangles && mapRectangleList != null) nbElemToCheck += mapRectangleList.size(); if (polygons && mapPolygonList != null) nbElemToCheck += mapPolygonList.size(); if (nbElemToCheck == 0) return; int x_min = Integer.MAX_VALUE; int y_min = Integer.MAX_VALUE; int x_max = Integer.MIN_VALUE; int y_max = Integer.MIN_VALUE; int mapZoomMax = tileController.getTileSource().getMaxZoom(); if (markers) { for (MapMarker marker : mapMarkerList) { if(marker.isVisible()){ int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax); int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax); x_max = Math.max(x_max, x); y_max = Math.max(y_max, y); x_min = Math.min(x_min, x); y_min = Math.min(y_min, y); } } } if (rectangles) { for (MapRectangle rectangle : mapRectangleList) { if(rectangle.isVisible()){ x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax)); y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax)); x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax)); y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax)); } } } if (polygons) { for (MapPolygon polygon : mapPolygonList) { if(polygon.isVisible()){ for (ICoordinate c : polygon.getPoints()) { int x = OsmMercator.LonToX(c.getLon(), mapZoomMax); int y = OsmMercator.LatToY(c.getLat(), mapZoomMax); x_max = Math.max(x_max, x); y_max = Math.max(y_max, y); x_min = Math.min(x_min, x); y_min = Math.min(y_min, y); } } } } int height = Math.max(0, getHeight()); int width = Math.max(0, getWidth()); int newZoom = mapZoomMax; int x = x_max - x_min; int y = y_max - y_min; while (x > width || y > height) { newZoom--; x >>= 1; y >>= 1; } x = x_min + (x_max - x_min) / 2; y = y_min + (y_max - y_min) / 2; int z = 1 << (mapZoomMax - newZoom); x /= z; y /= z; setDisplayPosition(x, y, newZoom); } /** * Sets the displayed map pane and zoom level so that all map markers are * visible. */ public void setDisplayToFitMapMarkers() { setDisplayToFitMapElements(true, false, false); } /** * Sets the displayed map pane and zoom level so that all map rectangles are * visible. */ public void setDisplayToFitMapRectangles() { setDisplayToFitMapElements(false, true, false); } /** * Sets the displayed map pane and zoom level so that all map polygons are * visible. */ public void setDisplayToFitMapPolygons() { setDisplayToFitMapElements(false, false, true); } /** * @return the center */ public Point getCenter() { return center; } /** * @param center the center to set */ public void setCenter(Point center) { this.center = center; } /** * Calculates the latitude/longitude coordinate of the center of the * currently displayed map area. * * @return latitude / longitude */ public Coordinate getPosition() { double lon = OsmMercator.XToLon(center.x, zoom); double lat = OsmMercator.YToLat(center.y, zoom); return new Coordinate(lat, lon); } /** * Converts the relative pixel coordinate (regarding the top left corner of * the displayed map) into a latitude / longitude coordinate * * @param mapPoint * relative pixel coordinate regarding the top left corner of the * displayed map * @return latitude / longitude */ public Coordinate getPosition(Point mapPoint) { return getPosition(mapPoint.x, mapPoint.y); } /** * Converts the relative pixel coordinate (regarding the top left corner of * the displayed map) into a latitude / longitude coordinate * * @param mapPointX * @param mapPointY * @return latitude / longitude */ public Coordinate getPosition(int mapPointX, int mapPointY) { int x = center.x + mapPointX - getWidth() / 2; int y = center.y + mapPointY - getHeight() / 2; double lon = OsmMercator.XToLon(x, zoom); double lat = OsmMercator.YToLat(y, zoom); return new Coordinate(lat, lon); } /** * Calculates the position on the map of a given coordinate * * @param lat * @param lon * @param checkOutside * @return point on the map or null if the point is not visible * and checkOutside set to true */ public Point getMapPosition(double lat, double lon, boolean checkOutside) { int x = OsmMercator.LonToX(lon, zoom); int y = OsmMercator.LatToY(lat, zoom); x -= center.x - getWidth() / 2; y -= center.y - getHeight() / 2; if (checkOutside) { if (x < 0 || y < 0 || x > getWidth() || y > getHeight()) return null; } return new Point(x, y); } /** * Calculates the position on the map of a given coordinate * * @param lat Latitude * @param offset Offset respect Latitude * @param checkOutside * @return Integer the radius in pixels */ public Integer getLatOffset(double lat, double offset, boolean checkOutside) { int y = OsmMercator.LatToY(lat+offset, zoom); y -= center.y - getHeight() / 2; if (checkOutside) { if (y < 0 || y > getHeight()) return null; } return y; } /** * Calculates the position on the map of a given coordinate * * @param lat * @param lon * @return point on the map or null if the point is not visible */ public Point getMapPosition(double lat, double lon) { return getMapPosition(lat, lon, true); } /** * Calculates the position on the map of a given coordinate * * @param marker MapMarker object that define the x,y coordinate * @return Integer the radius in pixels */ public Integer getRadius(MapMarker marker, Point p) { if(marker.getMarkerStyle() == MapMarker.STYLE.FIXED) return (int)marker.getRadius(); else if(p!=null){ Integer radius = getLatOffset(marker.getLat(), marker.getRadius(), false); radius = radius==null?null:p.y-radius.intValue(); return radius; }else return null; } /** * Calculates the position on the map of a given coordinate * * @param coord * @return point on the map or null if the point is not visible */ public Point getMapPosition(Coordinate coord) { if (coord != null) return getMapPosition(coord.getLat(), coord.getLon()); else return null; } /** * Calculates the position on the map of a given coordinate * * @param coord * @return point on the map or null if the point is not visible * and checkOutside set to true */ public Point getMapPosition(ICoordinate coord, boolean checkOutside) { if (coord != null) return getMapPosition(coord.getLat(), coord.getLon(), checkOutside); else return null; } /** * Gets the meter per pixel. * * @return the meter per pixel * @author Jason Huntley */ public double getMeterPerPixel() { Point origin=new Point(5,5); Point center=new Point(getWidth()/2, getHeight()/2); double pDistance=center.distance(origin); Coordinate originCoord=getPosition(origin); Coordinate centerCoord=getPosition(center); double mDistance=OsmMercator.getDistance(originCoord.getLat(), originCoord.getLon(), centerCoord.getLat(), centerCoord.getLon()); return mDistance/pDistance; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int iMove = 0; int tilesize = tileSource.getTileSize(); int tilex = center.x / tilesize; int tiley = center.y / tilesize; int off_x = (center.x % tilesize); int off_y = (center.y % tilesize); int w2 = getWidth() / 2; int h2 = getHeight() / 2; int posx = w2 - off_x; int posy = h2 - off_y; int diff_left = off_x; int diff_right = tilesize - off_x; int diff_top = off_y; int diff_bottom = tilesize - off_y; boolean start_left = diff_left < diff_right; boolean start_top = diff_top < diff_bottom; if (start_top) { if (start_left) { iMove = 2; } else { iMove = 3; } } else { if (start_left) { iMove = 1; } else { iMove = 0; } } // calculate the visibility borders int x_min = -tilesize; int y_min = -tilesize; int x_max = getWidth(); int y_max = getHeight(); // calculate the length of the grid (number of squares per edge) int gridLength = 1 << zoom; // paint the tiles in a spiral, starting from center of the map boolean painted = true; int x = 0; while (painted) { painted = false; for (int i = 0; i < 4; i++) { if (i % 2 == 0) { x++; } for (int j = 0; j < x; j++) { if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) { // tile is visible Tile tile; if (scrollWrapEnabled) { // in case tilex is out of bounds, grab the tile to use for wrapping int tilexWrap = (((tilex % gridLength) + gridLength) % gridLength); tile = tileController.getTile(tilexWrap, tiley, zoom); } else { tile = tileController.getTile(tilex, tiley, zoom); } if (tile != null) { tile.paint(g, posx, posy); if (tileGridVisible) { g.drawRect(posx, posy, tilesize, tilesize); } } painted = true; } Point p = move[iMove]; posx += p.x * tilesize; posy += p.y * tilesize; tilex += p.x; tiley += p.y; } iMove = (iMove + 1) % move.length; } } // outer border of the map int mapSize = tilesize << zoom; if (scrollWrapEnabled) { g.drawLine(0, h2 - center.y, getWidth(), h2 - center.y); g.drawLine(0, h2 - center.y + mapSize, getWidth(), h2 - center.y + mapSize); } else { g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize); } // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20); // keep x-coordinates from growing without bound if scroll-wrap is enabled if (scrollWrapEnabled) { center.x = center.x % mapSize; } if (mapPolygonsVisible && mapPolygonList != null) { for (MapPolygon polygon : mapPolygonList) { if(polygon.isVisible()) paintPolygon(g, polygon); } } if (mapRectanglesVisible && mapRectangleList != null) { for (MapRectangle rectangle : mapRectangleList) { if(rectangle.isVisible()) paintRectangle(g, rectangle); } } if (mapMarkersVisible && mapMarkerList != null) { for (MapMarker marker : mapMarkerList) { if(marker.isVisible())paintMarker(g, marker); } } attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this); } /** * Paint a single marker. */ protected void paintMarker(Graphics g, MapMarker marker) { Point p = getMapPosition(marker.getLat(), marker.getLon(), marker.getMarkerStyle()==MapMarker.STYLE.FIXED); Integer radius = getRadius(marker, p); if (scrollWrapEnabled) { int tilesize = tileSource.getTileSize(); int mapSize = tilesize << zoom; if (p == null) { p = getMapPosition(marker.getLat(), marker.getLon(), false); radius = getRadius(marker, p); } marker.paint(g, p, radius); int xSave = p.x; int xWrap = xSave; // overscan of 15 allows up to 30-pixel markers to gracefully scroll off the edge of the panel while ((xWrap -= mapSize) >= -15) { p.x = xWrap; marker.paint(g, p, radius); } xWrap = xSave; while ((xWrap += mapSize) <= getWidth() + 15) { p.x = xWrap; marker.paint(g, p, radius); } } else { if (p != null) { marker.paint(g, p, radius); } } } /** * Paint a single rectangle. */ protected void paintRectangle(Graphics g, MapRectangle rectangle) { Coordinate topLeft = rectangle.getTopLeft(); Coordinate bottomRight = rectangle.getBottomRight(); if (topLeft != null && bottomRight != null) { Point pTopLeft = getMapPosition(topLeft, false); Point pBottomRight = getMapPosition(bottomRight, false); if (pTopLeft != null && pBottomRight != null) { rectangle.paint(g, pTopLeft, pBottomRight); if (scrollWrapEnabled) { int tilesize = tileSource.getTileSize(); int mapSize = tilesize << zoom; int xTopLeftSave = pTopLeft.x; int xTopLeftWrap = xTopLeftSave; int xBottomRightSave = pBottomRight.x; int xBottomRightWrap = xBottomRightSave; while ((xBottomRightWrap -= mapSize) >= 0) { xTopLeftWrap -= mapSize; pTopLeft.x = xTopLeftWrap; pBottomRight.x = xBottomRightWrap; rectangle.paint(g, pTopLeft, pBottomRight); } xTopLeftWrap = xTopLeftSave; xBottomRightWrap = xBottomRightSave; while ((xTopLeftWrap += mapSize) <= getWidth()) { xBottomRightWrap += mapSize; pTopLeft.x = xTopLeftWrap; pBottomRight.x = xBottomRightWrap; rectangle.paint(g, pTopLeft, pBottomRight); } } } } } /** * Paint a single polygon. */ protected void paintPolygon(Graphics g, MapPolygon polygon) { List coords = polygon.getPoints(); if (coords != null && coords.size() >= 3) { List points = new LinkedList(); for (ICoordinate c : coords) { Point p = getMapPosition(c, false); if (p == null) { return; } points.add(p); } polygon.paint(g, points); if (scrollWrapEnabled) { int tilesize = tileSource.getTileSize(); int mapSize = tilesize << zoom; List pointsWrapped = new LinkedList(points); boolean keepWrapping = true; while (keepWrapping) { for (Point p : pointsWrapped) { p.x -= mapSize; if (p.x < 0) { keepWrapping = false; } } polygon.paint(g, pointsWrapped); } pointsWrapped = new LinkedList(points); keepWrapping = true; while (keepWrapping) { for (Point p : pointsWrapped) { p.x += mapSize; if (p.x > getWidth()) { keepWrapping = false; } } polygon.paint(g, pointsWrapped); } } } } /** * Moves the visible map pane. * * @param x * horizontal movement in pixel. * @param y * vertical movement in pixel */ public void moveMap(int x, int y) { tileController.cancelOutstandingJobs(); // Clear outstanding load center.x += x; center.y += y; repaint(); this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this)); } /** * @return the current zoom level */ public int getZoom() { return zoom; } /** * Increases the current zoom level by one */ public void zoomIn() { setZoom(zoom + 1); } /** * Increases the current zoom level by one */ public void zoomIn(Point mapPoint) { setZoom(zoom + 1, mapPoint); } /** * Decreases the current zoom level by one */ public void zoomOut() { setZoom(zoom - 1); } /** * Decreases the current zoom level by one * * @param mapPoint point to choose as center for new zoom level */ public void zoomOut(Point mapPoint) { setZoom(zoom - 1, mapPoint); } /** * Set the zoom level and center point for display * * @param zoom new zoom level * @param mapPoint point to choose as center for new zoom level */ public void setZoom(int zoom, Point mapPoint) { if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom() || zoom == this.zoom) return; Coordinate zoomPos = getPosition(mapPoint); tileController.cancelOutstandingJobs(); // Clearing outstanding load // requests setDisplayPositionByLatLon(mapPoint, zoomPos.getLat(), zoomPos.getLon(), zoom); this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this)); } /** * Set the zoom level * * @param zoom new zoom level */ public void setZoom(int zoom) { setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2)); } /** * Every time the zoom level changes this method is called. Override it in * derived implementations for adapting zoom dependent values. The new zoom * level can be obtained via {@link #getZoom()}. * * @param oldZoom * the previous zoom level */ protected void zoomChanged(int oldZoom) { zoomSlider.setToolTipText("Zoom level " + zoom); zoomInButton.setToolTipText("Zoom to level " + (zoom + 1)); zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1)); zoomOutButton.setEnabled(zoom > tileController.getTileSource().getMinZoom()); zoomInButton.setEnabled(zoom < tileController.getTileSource().getMaxZoom()); } public boolean isTileGridVisible() { return tileGridVisible; } public void setTileGridVisible(boolean tileGridVisible) { this.tileGridVisible = tileGridVisible; repaint(); } public boolean getMapMarkersVisible() { return mapMarkersVisible; } /** * Enables or disables painting of the {@link MapMarker} * * @param mapMarkersVisible * @see #addMapMarker(MapMarker) * @see #getMapMarkerList() */ public void setMapMarkerVisible(boolean mapMarkersVisible) { this.mapMarkersVisible = mapMarkersVisible; repaint(); } public void setMapMarkerList(List mapMarkerList) { this.mapMarkerList = mapMarkerList; repaint(); } public List getMapMarkerList() { return mapMarkerList; } public void setMapRectangleList(List mapRectangleList) { this.mapRectangleList = mapRectangleList; repaint(); } public List getMapRectangleList() { return mapRectangleList; } public void setMapPolygonList(List mapPolygonList) { this.mapPolygonList = mapPolygonList; repaint(); } public List getMapPolygonList() { return mapPolygonList; } public void addMapMarker(MapMarker marker) { mapMarkerList.add(marker); repaint(); } public void removeMapMarker(MapMarker marker) { mapMarkerList.remove(marker); repaint(); } public void removeAllMapMarkers() { mapMarkerList.clear(); repaint(); } public void addMapRectangle(MapRectangle rectangle) { mapRectangleList.add(rectangle); repaint(); } public void removeMapRectangle(MapRectangle rectangle) { mapRectangleList.remove(rectangle); repaint(); } public void removeAllMapRectangles() { mapRectangleList.clear(); repaint(); } public void addMapPolygon(MapPolygon polygon) { mapPolygonList.add(polygon); repaint(); } public void removeMapPolygon(MapPolygon polygon) { mapPolygonList.remove(polygon); repaint(); } public void removeAllMapPolygons() { mapPolygonList.clear(); repaint(); } public void setZoomContolsVisible(boolean visible) { zoomSlider.setVisible(visible); zoomInButton.setVisible(visible); zoomOutButton.setVisible(visible); } public boolean getZoomContolsVisible() { return zoomSlider.isVisible(); } public void setTileSource(TileSource tileSource) { if (tileSource.getMaxZoom() > MAX_ZOOM) throw new RuntimeException("Maximum zoom level too high"); if (tileSource.getMinZoom() < MIN_ZOOM) throw new RuntimeException("Minumim zoom level too low"); this.tileSource = tileSource; tileController.setTileSource(tileSource); zoomSlider.setMinimum(tileSource.getMinZoom()); zoomSlider.setMaximum(tileSource.getMaxZoom()); tileController.cancelOutstandingJobs(); if (zoom > tileSource.getMaxZoom()) { setZoom(tileSource.getMaxZoom()); } attribution.initialize(tileSource); repaint(); } public void tileLoadingFinished(Tile tile, boolean success) { repaint(); } public boolean isMapRectanglesVisible() { return mapRectanglesVisible; } /** * Enables or disables painting of the {@link MapRectangle} * * @param mapRectanglesVisible * @see #addMapRectangle(MapRectangle) * @see #getMapRectangleList() */ public void setMapRectanglesVisible(boolean mapRectanglesVisible) { this.mapRectanglesVisible = mapRectanglesVisible; repaint(); } public boolean isMapPolygonsVisible() { return mapPolygonsVisible; } /** * Enables or disables painting of the {@link MapPolygon} * * @param mapPolygonsVisible * @see #addMapPolygon(MapPolygon) * @see #getMapPolygonList() */ public void setMapPolygonsVisible(boolean mapPolygonsVisible) { this.mapPolygonsVisible = mapPolygonsVisible; repaint(); } public boolean isScrollWrapEnabled() { return scrollWrapEnabled; } public void setScrollWrapEnabled(boolean scrollWrapEnabled) { this.scrollWrapEnabled = scrollWrapEnabled; repaint(); } public ZOOM_BUTTON_STYLE getZoomButtonStyle() { return zoomButtonStyle; } public void setZoomButtonStyle(ZOOM_BUTTON_STYLE style) { zoomButtonStyle = style; if (zoomSlider == null || zoomInButton == null || zoomOutButton == null) { return; } switch (style) { case HORIZONTAL: zoomSlider.setBounds(10, 10, 30, 150); zoomInButton.setBounds(4, 155, 18, 18); zoomOutButton.setBounds(26, 155, 18, 18); break; case VERTICAL: zoomSlider.setBounds(10, 27, 30, 150); zoomInButton.setBounds(14, 8, 20, 20); zoomOutButton.setBounds(14, 176, 20, 20); break; default: zoomSlider.setBounds(10, 10, 30, 150); zoomInButton.setBounds(4, 155, 18, 18); zoomOutButton.setBounds(26, 155, 18, 18); break; } repaint(); } public TileController getTileController() { return tileController; } /** * Return tile information caching class * @see TileLoaderListener#getTileCache() */ public TileCache getTileCache() { return tileController.getTileCache(); } public void setTileLoader(TileLoader loader) { tileController.setTileLoader(loader); } public AttributionSupport getAttribution() { return attribution; } protected EventListenerList listenerList = new EventListenerList(); /** * @param listener listener to set */ public void addJMVListener(JMapViewerEventListener listener) { listenerList.add(JMapViewerEventListener.class, listener); } /** * @param listener listener to remove */ public void removeJMVListener(JMapViewerEventListener listener) { listenerList.remove(JMapViewerEventListener.class, listener); } /** * Send an update to all objects registered with viewer * * @param evt event to dispatch */ void fireJMVEvent(JMVCommandEvent evt) { Object[] listeners = listenerList.getListenerList(); for (int i=0; inull if the tile * was not found in the cache. */ public Tile getTile(int tilex, int tiley, int zoom) { int max = (1 << zoom); if (tilex < 0 || tilex >= max || tiley < 0 || tiley >= max) return null; Tile tile = tileCache.getTile(tileSource, tilex, tiley, zoom); if (tile == null) { tile = new Tile(tileSource, tilex, tiley, zoom); tileCache.addTile(tile); tile.loadPlaceholderFromCache(tileCache); } if (tile.error) { tile.loadPlaceholderFromCache(tileCache); } if (!tile.isLoaded()) { jobDispatcher.addJob(tileLoader.createTileLoaderJob(tile)); } return tile; } public TileCache getTileCache() { return tileCache; } public void setTileCache(TileCache tileCache) { this.tileCache = tileCache; } public TileLoader getTileLoader() { return tileLoader; } public void setTileLoader(TileLoader tileLoader) { this.tileLoader = tileLoader; } public TileSource getTileLayerSource() { return tileSource; } public TileSource getTileSource() { return tileSource; } public void setTileSource(TileSource tileSource) { this.tileSource = tileSource; } /** * */ public void cancelOutstandingJobs() { jobDispatcher.cancelOutstandingJobs(); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java0000644000175000017500000001310412223625012026731 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; /** * Default map controller which implements map moving by pressing the right * mouse button and zooming by double click or by mouse wheel. * * @author Jan Peter Stotz * */ public class DefaultMapController extends JMapController implements MouseListener, MouseMotionListener, MouseWheelListener { private static final int MOUSE_BUTTONS_MASK = MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK; private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK; public DefaultMapController(JMapViewer map) { super(map); } private Point lastDragPoint; private boolean isMoving = false; private boolean movementEnabled = true; private int movementMouseButton = MouseEvent.BUTTON3; private int movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; private boolean wheelZoomEnabled = true; private boolean doubleClickZoomEnabled = true; public void mouseDragged(MouseEvent e) { if (!movementEnabled || !isMoving) return; // Is only the selected mouse button pressed? if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask) { Point p = e.getPoint(); if (lastDragPoint != null) { int diffx = lastDragPoint.x - p.x; int diffy = lastDragPoint.y - p.y; map.moveMap(diffx, diffy); } lastDragPoint = p; } } public void mouseClicked(MouseEvent e) { if (doubleClickZoomEnabled && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { map.zoomIn(e.getPoint()); } } public void mousePressed(MouseEvent e) { if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) { lastDragPoint = null; isMoving = true; } } public void mouseReleased(MouseEvent e) { if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1) { lastDragPoint = null; isMoving = false; } } public void mouseWheelMoved(MouseWheelEvent e) { if (wheelZoomEnabled) { map.setZoom(map.getZoom() - e.getWheelRotation(), e.getPoint()); } } public boolean isMovementEnabled() { return movementEnabled; } /** * Enables or disables that the map pane can be moved using the mouse. * * @param movementEnabled */ public void setMovementEnabled(boolean movementEnabled) { this.movementEnabled = movementEnabled; } public int getMovementMouseButton() { return movementMouseButton; } /** * Sets the mouse button that is used for moving the map. Possible values * are: *
    *
  • {@link MouseEvent#BUTTON1} (left mouse button)
  • *
  • {@link MouseEvent#BUTTON2} (middle mouse button)
  • *
  • {@link MouseEvent#BUTTON3} (right mouse button)
  • *
* * @param movementMouseButton */ public void setMovementMouseButton(int movementMouseButton) { this.movementMouseButton = movementMouseButton; switch (movementMouseButton) { case MouseEvent.BUTTON1: movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; break; case MouseEvent.BUTTON2: movementMouseButtonMask = MouseEvent.BUTTON2_DOWN_MASK; break; case MouseEvent.BUTTON3: movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; break; default: throw new RuntimeException("Unsupported button"); } } public boolean isWheelZoomEnabled() { return wheelZoomEnabled; } public void setWheelZoomEnabled(boolean wheelZoomEnabled) { this.wheelZoomEnabled = wheelZoomEnabled; } public boolean isDoubleClickZoomEnabled() { return doubleClickZoomEnabled; } public void setDoubleClickZoomEnabled(boolean doubleClickZoomEnabled) { this.doubleClickZoomEnabled = doubleClickZoomEnabled; } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseMoved(MouseEvent e) { // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence no dragging events get fired. // if (isPlatformOsx()) { if (!movementEnabled || !isMoving) return; // Is only the selected mouse button pressed? if (e.getModifiersEx() == MouseEvent.CTRL_DOWN_MASK) { Point p = e.getPoint(); if (lastDragPoint != null) { int diffx = lastDragPoint.x - p.x; int diffy = lastDragPoint.y - p.y; map.moveMap(diffx, diffy); } lastDragPoint = p; } } } /** * Replies true if we are currently running on OSX * * @return true if we are currently running on OSX */ public static boolean isPlatformOsx() { String os = System.getProperty("os.name"); return os != null && os.toLowerCase().startsWith("mac os x"); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/0000755000175000017500000000000012223624304024127 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java0000644000175000017500000000221312223625012027327 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; //License: GPL. Copyright 2009 by Stefan Zeller import java.awt.Graphics; import java.awt.Point; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.JMapViewer; /** * Interface to be implemented by rectangles that can be displayed on the map. * * @author Stefan Zeller * @see JMapViewer#addMapRectangle(MapRectangle) * @see JMapViewer#getMapRectangleList() */ public interface MapRectangle extends MapObject{ /** * @return Latitude/Longitude of top left of rectangle */ public Coordinate getTopLeft(); /** * @return Latitude/Longitude of bottom right of rectangle */ public Coordinate getBottomRight(); /** * Paints the map rectangle on the map. The topLeft and * bottomRight are specifying the coordinates within g * * @param g graphics structure for painting * @param topLeft lop left edge of painting region * @param bottomRight bottom right edge of painting region */ public void paint(Graphics g, Point topLeft, Point bottomRight); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java0000644000175000017500000000033712223625012027172 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; public interface ICoordinate { public double getLat(); public void setLat(double lat); public double getLon(); public void setLon(double lon); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java0000644000175000017500000000121312223625012030516 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import org.openstreetmap.gui.jmapviewer.Tile; //License: GPL. Copyright 2008 by Jan Peter Stotz public interface TileLoaderListener { /** * Will be called if a new {@link Tile} has been loaded successfully. * Loaded can mean downloaded or loaded from file cache. * * @param tile */ public void tileLoadingFinished(Tile tile, boolean success); /** * Return the {@link TileCache} class containing {@link Tile} * data for requested and loaded tiles * * @return tile information caching class */ public TileCache getTileCache(); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java0000644000175000017500000000252312223625012026612 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import org.openstreetmap.gui.jmapviewer.JMapViewer; import org.openstreetmap.gui.jmapviewer.Tile; //License: GPL. Copyright 2008 by Jan Peter Stotz /** * Implement this interface for creating your custom tile cache for * {@link JMapViewer}. * * @author Jan Peter Stotz */ public interface TileCache { /** * Retrieves a tile from the cache if present, otherwise null * will be returned. * * @param source * the tile source * @param x * tile number on the x axis of the tile to be retrieved * @param y * tile number on the y axis of the tile to be retrieved * @param z * zoom level of the tile to be retrieved * @return the requested tile or null if the tile is not * present in the cache */ public Tile getTile(TileSource source, int x, int y, int z); /** * Adds a tile to the cache. How long after adding a tile can be retrieved * via {@link #getTile(TileSource, int, int, int)} is unspecified and depends on the * implementation. * * @param tile the tile to be added */ public void addTile(Tile tile); /** * @return the number of tiles hold by the cache */ public int getTileCount(); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/MapMarker.java0000644000175000017500000000251212223625012026646 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Graphics; import java.awt.Point; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.JMapViewer; /** * Interface to be implemented by all one dimensional elements that can be displayed on the map. * * @author Jan Peter Stotz * @see JMapViewer#addMapMarker(MapMarker) * @see JMapViewer#getMapMarkerList() */ public interface MapMarker extends MapObject, ICoordinate{ public static enum STYLE {FIXED, VARIABLE}; /** * @return Latitude and Longitude of the map marker position */ public Coordinate getCoordinate(); /** * @return Latitude of the map marker position */ public double getLat(); /** * @return Longitude of the map marker position */ public double getLon(); /** * @return Radius of the map marker position */ public double getRadius(); /** * @return Style of the map marker */ public STYLE getMarkerStyle(); /** * Paints the map marker on the map. The position specifies the * coordinates within g * * @param g * @param position * @param radio */ public void paint(Graphics g, Point position, int radio); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java0000644000175000017500000000074712223625012026327 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; //License: GPL. Copyright 2012 by Dirk Stöcker import org.openstreetmap.gui.jmapviewer.Tile; /** * Interface for implementing a tile loading job. Tiles are usually loaded via HTTP * or from a file. * * @author Dirk Stöcker */ public interface TileJob extends Runnable { /** * Function to return the tile associated with the job * * @return {@link Tile} to be handled */ public Tile getTile(); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java0000644000175000017500000000125012223625012027011 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; //License: GPL. Copyright 2008 by Jan Peter Stotz import org.openstreetmap.gui.jmapviewer.Tile; /** * Interface for implementing a tile loader. Tiles are usually loaded via HTTP * or from a file. * * @author Jan Peter Stotz */ public interface TileLoader { /** * A typical implementation of this function should create and return a * new {@link TileJob} instance that performs the load action. * * @param tile the tile to be loaded * @return {@link TileJob} implementation that performs the desired load * action. */ public TileJob createTileLoaderJob(Tile tile); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/JMapViewerEventListener.java0000644000175000017500000000066612223625012031520 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; //License: GPL. import java.util.EventListener; import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent; /** * Must be implemented for processing commands while user * interacts with map viewer. * * @author Jason Huntley * */ public interface JMapViewerEventListener extends EventListener { public void processCommand(JMVCommandEvent command); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java0000644000175000017500000000606112223625012027050 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import java.io.IOException; import org.openstreetmap.gui.jmapviewer.JMapViewer; //License: GPL. Copyright 2008 by Jan Peter Stotz /** * * @author Jan Peter Stotz */ public interface TileSource extends Attributed { /** * Specifies the different mechanisms for detecting updated tiles * respectively only download newer tiles than those stored locally. * *
    *
  • {@link #IfNoneMatch} Server provides ETag header entry for all tiles * and supports conditional download via If-None-Match * header entry.
  • *
  • {@link #ETag} Server provides ETag header entry for all tiles but * does not support conditional download via * If-None-Match header entry.
  • *
  • {@link #IfModifiedSince} Server provides Last-Modified header entry * for all tiles and supports conditional download via * If-Modified-Since header entry.
  • *
  • {@link #LastModified} Server provides Last-Modified header entry for * all tiles but does not support conditional download via * If-Modified-Since header entry.
  • *
  • {@link #None} The server does not support any of the listed * mechanisms.
  • *
* */ public enum TileUpdate { IfNoneMatch, ETag, IfModifiedSince, LastModified, None } /** * Specifies the maximum zoom value. The number of zoom levels is [0.. * {@link #getMaxZoom()}]. * * @return maximum zoom value that has to be smaller or equal to * {@link JMapViewer#MAX_ZOOM} */ int getMaxZoom(); /** * Specifies the minimum zoom value. This value is usually 0. * Only for maps that cover a certain region up to a limited zoom level * this method should return a value different than 0. * * @return minimum zoom value - usually 0 */ int getMinZoom(); /** * @return The supported tile update mechanism * @see TileUpdate */ TileUpdate getTileUpdate(); /** * A tile layer name has to be unique and has to consist only of characters * valid for filenames. * * @return Name of the tile layer */ String getName(); /** * Constructs the tile url. * * @param zoom * @param tilex * @param tiley * @return fully qualified url for downloading the specified tile image */ String getTileUrl(int zoom, int tilex, int tiley) throws IOException; /** * Specifies the tile image type. For tiles rendered by Mapnik or * Osmarenderer this is usually "png". * * @return file extension of the tile image type */ String getTileType(); /** * Specifies how large each tile is. * @return The size of a single tile in pixels. */ int getTileSize(); double latToTileY(double lat, int zoom); double lonToTileX(double lon, int zoom); double tileYToLat(int y, int zoom); double tileXToLon(int x, int zoom); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java0000644000175000017500000000315612223625012027103 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import java.awt.Image; import org.openstreetmap.gui.jmapviewer.Coordinate; //License: GPL. public interface Attributed { /** * @return True if the tile source requires attribution in text or image form. */ boolean requiresAttribution(); /** * @param zoom The optional zoom level for the view. * @param botRight The bottom right of the bounding box for attribution. * @param topLeft The top left of the bounding box for attribution. * @return Attribution text for the image source. */ String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight); /** * @return The URL to open when the user clicks the attribution text. */ String getAttributionLinkURL(); /** * @return The URL for the attribution image. Null if no image should be displayed. */ Image getAttributionImage(); /** * @return The URL to open when the user clicks the attribution image. * When return value is null, the image is still displayed (provided getAttributionImage() * returns a value other than null), but the image does not link to a website. */ String getAttributionImageURL(); /** * @return The attribution "Terms of Use" text. * In case it returns null, but getTermsOfUseURL() is not null, a default * terms of use text is used. */ String getTermsOfUseText(); /** * @return The URL to open when the user clicks the attribution "Terms of Use" text. */ String getTermsOfUseURL(); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java0000644000175000017500000000111412223625012026630 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import java.awt.Color; import java.awt.Font; import java.awt.Stroke; import org.openstreetmap.gui.jmapviewer.Layer; import org.openstreetmap.gui.jmapviewer.Style; public interface MapObject { public Layer getLayer(); public void setLayer(Layer layer); public Style getStyle(); public Style getStyleAssigned(); public Color getColor(); public Color getBackColor(); public Stroke getStroke(); public Font getFont(); public String getName(); public boolean isVisible(); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java0000644000175000017500000000044512223625012030702 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.interfaces; import java.io.File; public interface TileClearController { void initClearDir(File dir); void initClearFiles(File[] files); boolean cancel(); void fileDeleted(File file); void clearFinished(); }jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java0000644000175000017500000000176012223625012027060 0ustar felixfelix// License: GPL. For details, see LICENSE file. package org.openstreetmap.gui.jmapviewer.interfaces; import java.awt.Graphics; import java.awt.Point; import java.awt.Polygon; import java.util.List; /** * Interface to be implemented by polygons that can be displayed on the map. * * @author Vincent */ public interface MapPolygon extends MapObject{ /** * @return Latitude/Longitude of each point of polygon */ public List getPoints(); /** * Paints the map rectangle on the map. The points * are specifying the coordinates within g * * @param g * @param points */ public void paint(Graphics g, List points); /** * Paints the map rectangle on the map. The polygon * is specifying the coordinates within g * * @param g * @param polygon */ public void paint(Graphics g, Polygon polygon); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/interfaces/CachedTileLoader.java0000644000175000017500000000052412223625012030104 0ustar felixfelix// License: GPL package org.openstreetmap.gui.jmapviewer.interfaces; /** * Interface that allow cleaning the tile cache without specifying exact type of loader */ public interface CachedTileLoader { public void clearCache(TileSource source); public void clearCache(TileSource source, TileClearController controller); } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java0000644000175000017500000001404612223625014025665 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; /** * {@link TileCache} implementation that stores all {@link Tile} objects in * memory up to a certain limit ({@link #getCacheSize()}). If the limit is * exceeded the least recently used {@link Tile} objects will be deleted. * * @author Jan Peter Stotz */ public class MemoryTileCache implements TileCache { protected static final Logger log = Logger.getLogger(MemoryTileCache.class.getName()); /** * Default cache size */ protected int cacheSize = 200; protected final Map hash; /** * List of all tiles in their last recently used order */ protected final CacheLinkedListElement lruTiles; public MemoryTileCache() { hash = new HashMap(cacheSize); lruTiles = new CacheLinkedListElement(); } @Override public synchronized void addTile(Tile tile) { CacheEntry entry = createCacheEntry(tile); hash.put(tile.getKey(), entry); lruTiles.addFirst(entry); if (hash.size() > cacheSize) { removeOldEntries(); } } @Override public synchronized Tile getTile(TileSource source, int x, int y, int z) { CacheEntry entry = hash.get(Tile.getTileKey(source, x, y, z)); if (entry == null) return null; // We don't care about placeholder tiles and hourglass image tiles, the // important tiles are the loaded ones if (entry.tile.isLoaded()) lruTiles.moveElementToFirstPos(entry); return entry.tile; } /** * Removes the least recently used tiles */ protected synchronized void removeOldEntries() { try { while (lruTiles.getElementCount() > cacheSize) { removeEntry(lruTiles.getLastElement()); } } catch (Exception e) { log.warning(e.getMessage()); } } protected synchronized void removeEntry(CacheEntry entry) { hash.remove(entry.tile.getKey()); lruTiles.removeEntry(entry); } protected CacheEntry createCacheEntry(Tile tile) { return new CacheEntry(tile); } /** * Clears the cache deleting all tiles from memory */ public synchronized void clear() { hash.clear(); lruTiles.clear(); } @Override public int getTileCount() { return hash.size(); } public int getCacheSize() { return cacheSize; } /** * Changes the maximum number of {@link Tile} objects that this cache holds. * * @param cacheSize * new maximum number of tiles */ public synchronized void setCacheSize(int cacheSize) { this.cacheSize = cacheSize; if (hash.size() > cacheSize) removeOldEntries(); } /** * Linked list element holding the {@link Tile} and links to the * {@link #next} and {@link #prev} item in the list. */ protected static class CacheEntry { Tile tile; CacheEntry next; CacheEntry prev; protected CacheEntry(Tile tile) { this.tile = tile; } public Tile getTile() { return tile; } public CacheEntry getNext() { return next; } public CacheEntry getPrev() { return prev; } } /** * Special implementation of a double linked list for {@link CacheEntry} * elements. It supports element removal in constant time - in difference to * the Java implementation which needs O(n). * * @author Jan Peter Stotz */ protected static class CacheLinkedListElement { protected CacheEntry firstElement = null; protected CacheEntry lastElement; protected int elementCount; public CacheLinkedListElement() { clear(); } public void clear() { elementCount = 0; firstElement = null; lastElement = null; } /** * Add the element to the head of the list. * * @param element new element to be added */ public void addFirst(CacheEntry element) { if (element == null) return; if (elementCount == 0) { firstElement = element; lastElement = element; element.prev = null; element.next = null; } else { element.next = firstElement; firstElement.prev = element; element.prev = null; firstElement = element; } elementCount++; } /** * Removes the specified element from the list. * * @param element element to be removed */ public void removeEntry(CacheEntry element) { if (element == null) return; if (element.next != null) { element.next.prev = element.prev; } if (element.prev != null) { element.prev.next = element.next; } if (element == firstElement) firstElement = element.next; if (element == lastElement) lastElement = element.prev; element.next = null; element.prev = null; elementCount--; } public void moveElementToFirstPos(CacheEntry entry) { if (firstElement == entry) return; removeEntry(entry); addFirst(entry); } public int getElementCount() { return elementCount; } public CacheEntry getLastElement() { return lastElement; } public CacheEntry getFirstElement() { return firstElement; } } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/images/0000755000175000017500000000000012202517774023262 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/images/error.png0000644000175000017500000001304412223625012025107 0ustar felixfelix‰PNG  IHDR\r¨fsRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< pHYsPPs[‘õtEXtSoftwarePaint.NET v3.22·‘}iIDATx^í ´UuÆí ÔZ ÂäÁÓTEÑ´2‹å¢–¨8!Ѝ8 "!‚¨8OÅrX¶ÌFE<&b–>‰JÅLHÀ!Íe¡eƒÚ<®µÛûðîórAïq ûÿï_k]y\‹ãÙûû}ßÙû¼ó>´zôHÙ‚ÿq¸>ï€@ÖU‡Ž˜ÍÁ= |ô€i>5û‹]D¶ààÐ>zÀ4€ÐwÚÀiáqxŸUgpÇ=?Ë8J€à¸€ãâãðñ;|V 8îà¸øYîÀùø$Ç=‡ßá³j ÀqÇÅÏrÎÇŸ 8îà¸ø8|üŸUcHŽ{8.~–;p>þ„ ÀqÇÅÇáãwø¬@pÜÀqñ³Üóñ'HŽ{8.>¿ÃgՀ㎋Ÿåœ?!@pÜÀqñqøø>«Æ÷p\ü,wà|ü €ãŽ‹ÃÇïðY5€à¸€ãâg¹çãO÷p\|>~‡Ïª1$Ç=?Ë8B€à¸€ãâãðñ;|V 8îà¸øYîÀùø$Ç=‡ßá³j ÀqÇÅÏrÎÇŸ 8îà¸ø8|üŸUcHŽ{8.~–;p>þ„ ÀqÇÅÇáãwø¬@pÜÀqñ³Üóñ'HŽ{8.>¿ÃgՀ㎋Ÿåœ?!@pÜÀqñqøø>«Æ÷p\ü,wà|ü €ãŽ‹ÃÇïðY5€à¸€ãâg¹çãO÷p\|>~‡Ïª1$Ç=?Ë8B€à¸€ãâãðñ;|V 8îà¸øYîÀùø$Ç=‡ßá³j ÀqÇÅÏrÎÇŸ 8îà¸ø8|üŸUcHŽ{8.~–;p>þ„ ÀqÇÅÇáãwø¬@pÜÀqñ³Üóñ'HŽ{8.>¿ÃgՀ㎋Ÿåœ?!@pÜÀqñqøø>«Æ÷p\ü,wà|ü €ãŽ‹ÃÇïðY5€à¸€ãâg¹çãO÷p\|>~‡Ïª1$Ç=?Ë8Bà–í»ÔÜÜ\¸Z575Znl.6—p/ë][¸´wm‹kælWÛ¢Çfû³7×cì*zÿ½*|¹½¹‹¨øåËÍ…ä†Í6ñ'*z¹r»‚\¢Ÿ½]m¢¨§@@Å*u#¿ Á­*ü—ê·–wºËªú­äæ¾]d~ßB¢Ç&¢:~áRû\ýCõ]dYÃÖò`}A ³ôŸ_ÜBI @¨ðkMü_1ñ×m%Ýg˜ü÷ÒËäÏ{ï!«ë¶”×+®Û0ñ«Ð“ËUìßSñ/ßu{yyÌaòÌ.}e‘Bà’ÆZ™ÙX›\‚®€À`âר_*~uüTüs¯ÿ^~¥ü[!ðödžÊ*…À—×ö)$-}òKöŒ_.þWŽ>B^Öã¥#•§ö‘³33k6Y Åa+ý:@@Pá›øÞ²ñÿç²¹ €Ë埳fË[{í.?WÌïSkzl´MüúœŸ\VâüEñÿâ¨Ã£å…Ñ'4ÉB…À̆™ÞP“è±Ñv¥‹(äëÀį¾ûõÙ?}æ/uþ¢øÿ5{ŽücÖ%ò‹fÊï÷,Ë×)æ)æ5u*üLñ¿ø¹Qò⟕çG'ú÷–{ëkå‹ Ó€@Å>€ Â/Øtÿ¦¾y1Kü_,Ÿ9Sþ~átysÏÝäg k› ruS!¹ª©ãÃ9¿M÷uè×þÌ_îüEñ¿pøÁ²zôHY5êYÚ¿Q¾£Ð Ô×$çד*1)€ k½›nPñ¯,{æ_ÏùÛÄÿ·3ä¯Ó§Ë_Î?_Þ6Hž®ßR®iÒu]SmrE `+½‹ÿЃdå¨å¹C†Ë’~ r·B@Å/çÕ×´T¢¼_ºÒûÍ­:Ôû“®úlÚo¿Lñ_8MþrÁò§sϕׇí*O)æ)æöÖõNò³ßÄo+½9»ø÷——gÚWnè*ÓSëkÖdý™œßüo€ +½ëu¥'+uåg«>›öÛÀ¯ý™¿ÜùÛÄÿçó¦Ê;S§Ê[gO‘×ö(OÔu•«z׊¾Ä“Ø‹<ï%8~*þ9:ÍØV}ƒvÌØ_&þå#ö“Ö~uiPñ˹$€Šœ€`ûüku¯CŸ.éŠÏV}6íO~âûœs䭳Β?žyº¼:t€üH!p…B@÷ùößz0ñë‹<¹ˆÿ›º Ðç9·®&9§Ž@%&¬qlŸ¯Gr½B`¥BÀV}6í·_û3™ó·‹Ê™ò‡3&Ëï&M”Wvï/KöŸ­õJ_ݵ7øLüö29ÿ³vþzIÅ_W#*üälÄ_‘îo}€Ëöù_R\«°=¿­úlÚŸü²Ä?y’¼9y¢üvâùÅ~Òª°¾Eý6×/Ø|ëˆÿ˜µ/ù÷üëMû7û׊ÿ|Ä_±¢/M" XálŸo+=[í=«°UŸMûmàW|æ_ÏùÛÄÿæ¤ÓäÍÓ&Èo&Œ—†ì,Õu{Î7áÛ1»ô™¿â¼ß»âW×Çùè-@‘ÊŸmŸo+=[í=£°UŸMûmà—)þSO–7&œ$¯?Až¼“|_£¾ ?/ñŸ§Îoâ?‹ØO¨Ä¡G,×dû|æ%ót ·L!`«>›ö§¿â3¹óÅò8YsÒñò«••ƒwL_ðI§ý»}T^é¤óCc¿‰_…ø2@@Å*‡—íó/W\©xR!`«>›ö§¿ ñÿzÜq €±òÚqGÉsCv’zlŒø§¶‰ ΄ó{  +bñÃWè@ï':سUŸMûmà×þÌ_æüïŠÿyUð˱côø|‡~öÌoÎoâWá'Sz±ê -a€À` WüI=û}[ñ٪ϦýéÀo‰¿µÿZñëŽ_TøÉ™ˆ?(ç'D üR·)}oÿ‡ [õÙ´?øµ=óçåü¥âWá«ø«3_-ͽ\/ "ßâ³]þc [õÙ´ß~ù‰¿!uþszÕˆ ?9ñéü$€ˆ„_êVºÏ/èç¸Òþ£ºç·UŸMû×ü6µÿ»âWá#þzˆAËãª~Ž«ðÅÆšäbýYüGt½g«>›öoÔÀ¯Müg÷ªÿé8ÐÎOˆPø¥ °OqÙ'¹.RØŽßV}™ö¯ùiY2`»4ö›øUøˆ?¢Þ!DTÌR觸 ö9® €Å ÛówtÕgâ_>âSÒªøš`Š`²@†~‘ô ˆ¤åâ×ïð%öM¾Å:èÌ~EñÿìÀ}å™ý?!?Ðÿ]ú³ýgô¬–I=«“/ô1l @d°p¦âןÃOÅo?ÒÛÁ×{×ÿŸ”Ÿ*–}foydç^r§B`²B`¢Bà4 üDÿ›@üOßGžR<¹ßž²x§žr‡B@S€œºmu2a[’@ÈID~Á¾¾kßß{H?ý˜GÎ_ÿSŸÞ+Àû•E;m+·ÕÕÊÄm«å…€Ìí#háJ]G…_Ð/ïnñï!?Qüèƒå·‘[ô5`Mr²B`| bÀ¾·_*þÎ|ÀsCÏüë;ÿZñÿø“CdéÇË÷ÞU’v—›§ô¨–“zT'ã€@p30Lüú½ývçïŒøíë½¶ç·UŸMûmà—%þ¥û ’% €Ç÷(÷íÐ]nhƒÀ‰=ª’zTñ8PO€€ŠU1Uø©ø/l{æ·ßÒÛ™Ow?noøÕän=lÕgÓ~ø½ûÌ¿®óÅ¿äc¥uÏòè°~rÏöÝd~]µŒß¦JŽß¦*ÑÒW B•‹_¿µ¿ÑâOßíWáÛnߎ»t°g«>ö­ø½¿øÖ_Ý£Ÿ|èŽò­æÈuuUr¢Bà8…À±@ ˆÇTøÿ´tþRñë>ßvúÉ$è}U!`«>›ö—>ó—;»øw×ï ²ƒ|£ùÃrM}šdl÷ªä˜î$J €€`â×ß°“LÓgn[õu6ö§?ϯκº¾ _'ùÛçë‘Øjï…€­úlÚo¿"~ÀâA}åîæ­ežBà¸îUr´Bà( PÑI€TüúÙ-ûey‰ß^ä1ñ]Êöù¶Ò³ÕÞmú²­úlÚo¿â3ÿ†œßÄÿðnÍò`Ñ.MrWß­äJ…€¦£Ó$P©Iuý‚ý†ÿ¢pþô~êüö*ï{½Ågû|[éMÐÕÞWô1ÃV}6í·_¦øwm’ö–ïl”;ûl)sGw«’#»U%Ÿ™@Pñ·è·ö%ÉCüêîõßï^ÛçÓ•ÞÉ=ªäæúêtÕgÓþtàWòÌ¿ŽóůëÄd@ƒÜ¯°¹½OW¹DƒŸSèÁ¯¯À^X”ò¸¨â_3MŸË—5l-/9¬s_ïUç·!Ÿ‰ÿƒ¼ºkûütšo«½¶ê³iqà÷~âOTü w®“:LœßX-:#ºUñëÁ+°×@¥úË6Zô³ÛrŸŠø™]úÊKGªÇhù ¿«¯ûMü}oßöù¶Ò§˜¯°UŸ ÿ‰çžrkSW™¥ @Åo  { T`QÊ`ßÛ·¯ïÚy…ÀÓûÈ ‡"/ñYýûÁ²zôHYµ_ÔYÿÚį¾¿ cûü± ÔÅmÏo«>›ö§¿²Øßîüm⟣ÿ¾>ÿ›ø=:ügWêà,¦ëÀN¿ÃW«Ÿãºß °P!ðä€&y~ôˆ÷kÛÀÏÄo“ýΈ¿Øè¶Ï×#±Õ^‹ölÕgÓþtà×öÌ_.~{öGüR‘ƒ¿R€€@`EÓOqÕêÏá/œ¢Sü½ òDÿÞ²jÔ²rÔòÜ!ûËŠƒ‡ë'¼öÿ×Eñï„󗻜íóõHlµg{~[õÙ´ß~8å ý½R VDýW­÷Ù«»÷¨È—öoTñ/]*~{¡G…ŸëéêN¿`+=[í]¥°UŸMûÓ_1öë?Çùà ýW­¾Á·À¾Êómû’~ òìAûªó—ˆ_wùºÏÏý¹ÛöùºÒKŽRØžßV}6í·ßýÿúÒÏüõ¨X¥1N_ä©Ñ•Þ›îM!ðpCWýaž‚œÖö³ù›BüÅ?ßz6Ø3±_ª¢·UßlÄ_ñÏûz ÀŠ©k½=îÕŸ¾×_#úßfû0G¶âÓaqÕÇ´?°~¬œâúœ_£Â¿Z¾Áײ9¿ÊÓ{ÉÇöü¬úÂyöç7.ü˜vÑü·üÿÀAA>»| pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû ÀqÇÅÙ¹¸ö|Ò $Ç=ÍÇEC¾÷p\ü‹kÏ'½@pÜÀqñqÑ|\4äû Àq¬€Õ£G¶Ú?ààÐ>zÀ4¯‡laáàÐ>{à=¯Ïzqý¸IEND®B`‚jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/images/minus.png0000644000175000017500000000025312223625012025107 0ustar felixfelix‰PNG  IHDR Vu\çgAMA± üa pHYs::þ6)QtEXtSoftwarePaint.NET v3.317ƒw†)IDAT(Sc``ÐÄ⥠/ÿ'ÿ#KÃy .bñ9 Ì$âÁsÖ,)…vÝcËIEND®B`‚jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/images/plus.png0000644000175000017500000000034112223625012024735 0ustar felixfelix‰PNG  IHDR Vu\çgAMA± üa pHYs::þ6)QtEXtSoftwarePaint.NET v3.317ƒw†_IDAT(Sc`@Œ@î ¾ Å34H '`ÊìâÿP¼s`4,Z‹Œ_ 9é9šÜRg`î%†þG–†ó@]Èø3’­ŸÐäÎl`F¬@ö>$ »€l45(q2âtÎFuÊgAMA± üa pHYs;;,q˵tEXtSoftwarePaint.NET v3.317ƒw†#IDATx^í X•UÖÇSAÒP±ÌÊÔ0­ìâ]²Ëä-/xÁ ¦˜¡xA‘¼‹¢©‚xA%EQD‘$‘"&³ñ2&cãðE~SÎØÅù›GÇjLe}ëÿr¶½ACšäïóüŸƒpÎ{ùwíµöÚkï}Ë-üG$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$Py TÑ[ÿµ©ò~[¼s('cäUõóÕrÑWW›ªëÏÿ2׈ë5׎û0÷TN$ü Üü`$ÆèÁÃÈÝT5T5ºM_ír×ÿÿÜr¾sm¸Î[Ó˜Fàæÿy‡$p솣ÑÈ`d0ìÚ*U]Õíª;lª§?ÿ2×€ëÁuáúê¨j9® .Ü"6×ùPðí7?gÇÁÀ“ˆ`P0ìúª{T÷ªª©;é>ýiòÔß—G¥Ëùœ¸\® ×w—ãzÑ ÁBã…FŒ ÀÍÿóËAÆÏ1ÞF·Ã¸`¼ÍTªš«Q=êÐcújÔB6j©?µÒŸíj­ÿ·ËùïöÏšãÙσŸq~\Çê‡××D_Ñ  !¸Så¡BäÂ@!ð Ø ¯¾1B}xÊÛkºUíX×ÝÅ¿Îm.ujº¼Pç¶jAî5ªU«&¸×¬¢š¨ uèE}-Qj“T“š¢¯ÐT'MÓÿÛåüw|ÆÇ›tåø%ç1çh]OjãUc\]ªø:ƒûõ"4¸/D4¸O†ÿ´Pv¯>rí{nw5øCß&OowYUükÒŒÁœÓ†+PïQASG€‘ î ¢Ü7ÿ‘@¥%`ïë¯ïáõ GAúìö’îõ«SêÌöÒ¢I­,ýFÛ;Dè €ðßîý+íÏ'{È£€qÜÑ¢Ií÷ãCZȯQ±ãZHóFî»õ>žVµV!Gðù $0Mß¡?ÿ‘@¥%`7~Œ£^}·éA=_îùÉú„CÃJ6äAUÉ«õ;ów¼VÀùFx7ºàæZe¦ÞG'U;’“!@èì?B$6iü•ö±çƒ@iƱóûܪWV·–뚺î®Iuk¹lÖäß6Mþejòo—j·&÷¨ÞP½¥ú­êM¸ýNuн¦Ë{uÜo}ÿîFMÿêùØSÿhÖ¶ëÙVý¾iÛÕÿ;¯nŸìx¹ƒÏˆKí¼‡^lÓyÐ…‡¼|¾nÒ♳÷6kñeÚî'ôóÇUhRïOª÷UGT¿×cÐó¼«Úë8gž¾æêõä8®k‡«Ë-Óõú{Óøù€“Àµ ”ö£`¦ Ãzn{Rå­ê£¬z^¤¯š¤‚±…«^V-öhÜzË#Ý‚ô–zvttîÅ û‹g¯=(³×”9úji]É+~–°_¦¯Ú'Sã÷Éø¥ùÅýg¦_ð4÷Ô]t:RÅÅ-[¹UµQõªj¹*Z5_5[5U5Q5Võ‚ê9U?UwÃ~>ý$p ÎÆá0Æö=U?o«úª› À U€j¤*X…`–ǽ-V?=<²pÌâüï"6ÈÊíÇdýëE’”s\Ö¼V$ñ;‹$.S_³Ž[ÂÏË·ɲŒBY¼å˜D¤ȼõ‡­FaÆêýVCà’x®ÁcÞ‡o©Ru›žc½j¥j‘jžj†*T5F5B5Äaø>úÚQ…„j0îÏ„ß5þ©òpêC¿¡?¼?2å0 4O©º¨z8Œ Æo;¾éÓþIãc÷~½$£HRòNÈë‡>•ÿsZ–·þð…lÛwJ6æ”u¹¥kmÎ Y»û„Õ(,ÛV(Q©G­†À¸%ùÅí„ÿµZuwD«Æ?G_'«àñ‡«Ð a| *>Š€0Ô‡Ê?ÓßGÕ¢êcŸ¿ò>ó¼sgï1Õ}hà9‘4CÀËa\02Û¯a©³Öü;!ç¤ì6vßicJþ§–§G¸îë VðÚÁSVW ,F}=ï‰Óó-ÞþQ±æ2õ:ÂTª^*x~?Êxáõ9…÷:¿t¾ìœG¬Ò_£¶¾Ý§¯)8ãOÛ[büùaüúË+ë=F]Ö÷"±¨ÑFqóNyz/©F«úªÐçG.Ý?2ûö!=†ù|¶Ià:Ø»è7ã÷|Ø'xȼÔÂï,ãû‡žÿƒ“ç,㿞ßaüòäà°#z=è÷£ÈÈO…±}ôùçGÈÏ!½ëø²ùVp&` €ìÆß¤¥ïä@$û–g´úöïž¶}ðüÈôï~ï «;PV^Ö÷ã6(æC½ÐHÆú1ÎÿŒ ó÷Ÿ‹vð™&r0Æýh„ýžÍ:Ž8gã±Ãó'å}j ë!ÑãÿäôyyûŸðCaŒ¿mŸÐÃz iüåüVù1(ÒŒÿ¾êµêµ“ÿ9ŒßTöýñã3V¿ÿô?oÌPÆúq¾ˆ´¢Ë:Ö ?*Œõ;‡ý¨K0a?KxËð%ó-$P»ñ[kû©Pí÷ØS‘Ñ‘éÇ/#Ðÿí÷¿/òAÆcÿú[U~ZûoÆùûMIú{U·µz ˜ÜƒI=Høaæ!²ý¨êóPqÎ>Ÿgø‰LÒÉ3xSxUô«®v«{Ç~3Óö#ûžðú Ù¹_ZËñ~t0ö‘€r—öª§G}?fÿ%ì,4cüjßÕô5=¬ v`bÆù1çÕ}(ðAY2jL5ßODÀ“@å%`ÆûáMaX00Zû;îo7ô……¹Ÿ¡Ø–sPö(?~\RßT»VÖ¿‰?« G§û.LÚ'ñk“uzðQ™öêÁ‹M:ô;¤ç…×E… ?êú[«PzŒ:ŒJ˜uú8ÄWyŸ[Þy€Á‹šŒ¿Uè£ÂZú=îm8`vú‹·/ÎÚ“/r¥èøq)ü¸d:/†ËìýuЫÙ:­7%_æÇ$ÈÒ%1²l³ÎíÝ{¡Á£èù°¨&öÀëª0³!?ÆøM¦ß>ÆO㯀€‡¨¼ìý~ú£oÙs˜7ß½†Gý‘]FÇî})ùØÅ­»Êá½™Rx$O ýVv¿µO’÷ɆÜ:ô§23üÌ«þ~½.ø±i×~INN–˜˜™:{¾¼²(V¢6–!s3þ¥…oëyRTXÉ“zÆ©0Äg¼>¦ï¢ôØ,ÏmÖè£ñWÞç–w^ì•~f‘Oãý1¶Žê:”ØŽxà7C׌Y’vÍkÇ$ÿL9øfªìݵVò2â$'#A²w$IÖŽÉܾY236IfúzÉÚºZ²Rb$9ᙿ B‚§FȬũXÖëRûþSÿêr«µo²ÃðQÕ7A……D0¡}}ìÔc/ëE„böå«€Ûç!H rpöþŠ}x\,ò"„àÏ׺³Éï±qˆH9z)}gŽäe®’¼mË$wë’+ÊI‹(;e¡d&EKÂòHõö2zZ´L^œ-ÂÒ¿©×Ì cù¨áß Z¦‚LJáU!ɇ…;Ðø  RÚʼôú•û™åÝWç:ü˜…>1ÅséM kî…ÞßÁ/QÀ«ÛJζU%†Ÿ¾Dr¶¨á§FKö¦hÉØ%ÑÑ‘2rR„ÍŠ— ¨œË­{‡~ªÞþ-=ÖíCr/F5K…P†~>–éB’ᾇʾD ¿‚¾x†@À>ì‡ðßÞ`¥_4¨±GóìÇ»×oÕ{rÒÇ‹·-ÎÚžl5–×ߣ†¿HDDÊÐ jø/%‹ÿÜÌ w7+õ ÌOS­V¡Š«cÖéÃ"¢ðøÆð}`ø‘ûðñ%LÀ„ÿH¨aèÃj&@#ðÊXAË|©V½føSÃ"Ƥg¤'[^?+%Z"#_¿12rnš š•þMÍÛÔ÷£r/U¯BßU  U|]UèãÛí áßà/œ‡'CƵký! G?‹k`‘Od䃪¹¸ÍêlùŽ¢â¬´•’´:Jž!}C4›ŸuÁýÎ&ÆÛe3ü—õg, Ž:QÁç¼ûŽ õéñùl’ÀÏHÀ„ÿfÁOÓ€†Q"‡qwxégUT£o­]þ„ûίKÏW¯)Ÿÿ9YÅžû!ÔÇÆš›UXš<ðø¨Þ3†¥Ã1´ˆ•zÜÃ^i†Ï¾þÏø ðT•“@i €ÙðÃ4Ï`H•xã}_\{téÖ£2iV¤<ù\Œô‘qѵF„úèã¯Q-R¡€}|„úÇÇ~{Άo–è²/ÈIïœÏ"ïú àܰGè˜a@$±ÓO`÷ñño;.ÁÓ"å©á±â–ùæÕÇpÞ ÕváÁ’Üf8¢ ¬ Lÿ |Ñ<% ”FÀ>ˆ9ÿðÈf­?ÌþCøõõzTw¯;rôâü3±;?’™óc¤ÓÈ8_|_;ß½úw é-Ua,«ó Yˆ.ƒñúXž KqÛ·Ø6…<ôø|6Ià P&ã¯RÕµWÇQ±Ù‹¶/Æ&qqËeð‹ñ2|~†øÎé›hü¿À·ÇS’@9 ”)ì¯êêÖééç£×Gl)º¼F×ÞGmÚÆx I–þ33dÜâ½ÒgJònµê¡Ï¿@Ű¿œ_?F?2%ütÆ_ד’²#·]ÂJ<ÖZ}jü©«$1-ÛÚ–;`^¶ŒY”/ºÀ™;š´Ã^|&á‡Q‚ëIøý÷Ís@¥&P–¡¾GèÁ{4 8C —g¨¯R1¼y¸‘J õM•ŸUä£ÞÞëÙñkׄm8ú/,Êñ¦ÎéÇê¾Öö]˜Æ ãßœ i™¹V$€@ÌÖB™ñêAÝw¿ÌJ,(î35ùÄíž­1Þ"Ÿ~ªÎ*$ÿ°T‰,ò¹‘ß2M¥¸VyoÓ;úˆÊûߥ™]†§ßÿn×ýù9k}?ûŠ>I‹eëö¬+K{£K€(`Iz¡Õ,Ý~\Bã÷ŸoÓwò6]¯ÏŒù#ûºçò^Ì10+÷p©n>¶$p”6±Ão ´z¯y×à„Ý®û¬}5ß¿ýã¼µƒÏ¯¯ž>)§H2×GHÚæäÿXá"D HêÞ—5 (¬}σÓô<œØs¾T’~Œ€}H^Ö¬äÛ NƒæùNOÛ•qüòú7u  óÿòç­e¼±Çk‡~¸uצÌ|5þ«òþØÖÜØ tÔ¢¼ÜùÀX­—Szì›âßI ‚ ˜pßòxèñï¾³©WKÿyYoëæ™—±yúöðöؼããSŽ{lv&ê’]éÉ+%cí\Õ·$p 8{}ÌÞkÐaXdÐÜ”ÂcÓlÉý™nÓuþ õ5Á‡PßnøïS·©á¯3†×’ŸÓ’â­<Àí×·êõ’@§èJAØ©‡ xÞÀ/‡&€ñÿ`én‰wÿˆèüãØ> ^ùPÑW–á#äÏ=òCÏŽä^‰±oô–÷_3GÒfKZbŒlÜUpíþ?Öò×A_J9vQ·ëŠÓk Tqén>£$p üǦt ôÖqü¯aüððÈèÃø±_ŸµN¿fõ­å¸5¹—žõƒPÿŠÑ¿n¾Qj|¸¬ßœ¥IÀ®Ú˜:u¿=z¿Ü´ã~é<4 ؇÷®l×ÕºÿŒaÖÝØ§/ç¨|x├ùç9Ùä˜lÙ‘-iÉ«%#ñå=¼¼Ýà?§­ “äåÓ$qñ$Yý¢Ä/œ,q±‹debº¬Ü%+’²%.9WâRòtŸB+ô÷½ô}ýjÌv]=}n×Åç•*€½¿á=Œë7~´Wès ÒŠ.ÂøÓS×JÑÑwä«ÓŸÉþ=›J’yÆÐaॼêLJIjÜ IZ6E~¢$DN¸ãdéÜ ‰ž9BæO*á!ƒeƘþòB? ÚW^YeÿÓCçþA¯Ã¾Q'öàFøÅóP$`7~TÒÕSÝר­oϰǰ?5e½ìÛ%_|þ±ìÛ¾½fñM8ïÚ[¿²ÄÓÃèáíN”øˆñ;oŒÄÌ)‘Ó‡ËüIC$| 5ü~ú‚¯ôà/}ú ’ˆ„Ëøî2â½”ÿbL‚!¨üÃæHHÚ·èæ|>Ç$P¥¿gíͼbß—0þĤdÉß¹FN|xTöålRÄò0t¼ÂØáá“c§^1xãé¿7ú@Ëè#¦ÈÜÐ!<@¦Žê+¡#zÉоҲ{ˆøôñ—…öŠ-J£6=ßÐ{Á²Þ!*TþuTaáP³s¿_6?BvÆøí›t6Ñ7´Ñâž÷á…WmΓ´Õóåð;¯KÞŽu’¼¢$”O\ü¢åÙKúò­þ̇°ßSÕªM¿s¢3>º¼bû1+I—¾.ÊRBTIoWÜü1ûRÕŸ™(Ña/\ñô&Äg¼}O Ú]=+ÝzûKÃ.aò°w¨Œž&Q[‹¤Whâ—zþuª—UïÇBŸö°ûÏ¥¾öWÐÁÃTÎõü˜ºkõùU-´¦ßw̲½§áýcEiŸ}¬zô ²t |¤eäæÕ» íaðïáéÃÆù9Büžà#c‡xKà€.Ò³·Ÿåñt —Ž=$äå4½(¯¸A ŸCz~ìæƒM;Ǩ°¼7~WÛ¦›3ý*Ï3Ë;ý‰ŒÇ7ãû¨çÇî<ö…9±]Ö3ÍŸ š§E7bÓ $búH«Ïn2ö–Æ>w¢ÿ÷ÔOÞ×ê×sýÀNЯ³ôêå+M»N–»ºÌ•æ]‚¥‡ÿd¾ [Ú ˜ûE•jnézîXÊ|UØ ‹„"Ûï¼[/v2ÞŸÀO|0øñ››€ñövÃG=¿Y“Ëg{ª`üO«út»çåÔÂKQqi6~°•¬ûԳû#s$ÞäÀÞjðêå‡ûXá½åéÕèGôï$þ}ºJGËãßÝ)\šu•§z•SR¥Óèø¯Ý<bO,󭚢 Pak0Ìó‡ñcSD'h¨Ð`!WaF7÷³Ë»û œ—ç‚Ç7†õòaT TfO>„Ú½´Î~„× ð]3 .D®L—ÉA~V‚‘[zÞaìêáÁ êªá½zú¾Åß·ÄÛ·ô+ :Í{;N•‡:•'{‡ˆß´Ti;8âŸnuþNϯ ™~lŠMA`üûÑ%Áæè÷£›rµ€QÀOxPøÑ›‹€³áÃc"i¸9¶È‚á{ªàaÛ¨aï­‚÷ mØÚg〙iŸ‡'ä_ž2-\ý{j¶¾$c?b€·¥¿g5¬ïªÆÞÅR¿žÝ¤sw?iÕ5Pšv ÏŽ¡–Ñ·÷+>£bÄ{Bâ¥&O =U­º»ÙË/Yυ߬ïÙ}ðüØ´¥ U~ðþXæ "³»#€›ë™åÝTÓÇ7{ïÇᠢžÕTïÚÚalXV ɶá*ÔÙÏÕ( ¶q›žy]F-=å7=ù»¡“b‹ •^ýħ—ŸtïÑOº©ºvï'º/ïiõl´Rß¡w¨xÌ—.K‹3béwžü¿tu¯÷»÷b\Ã{ÈòǨf©°¹æö£ê¬Âô^쌭½`MAD+f—D1l*àá!nÎY}xJ7×*­êÖªX×½ú˜:·¹Œ¯ãîò¢¾Ns¯áæ^Óå%÷Õ^QŨVÖ¼µjbM·ªinÕ«f¹¹V}Ó­ºË~÷Úu >úÌßïo×ól‹.ß>Ù7äòS}ƒ‹Ÿì=¶øñâÕ#H:ôÒŸU­»^jêå{¡Q‹®ßzÜÝ䌛›ÛßܪWûD¯áÏzÌBÕ{zÜ}ª\ý9SÏ•ªZ£ç^®Z¤×³@®×6­jk¹o4Rèž`§D-*³±§= xó|‹¼(SÈ£@¹V}êC§lv>>¤Eq|H«ë‘ègJQ+ý]YTÚggç*×Ô¢8¤Ïýç´‘@D€¢D+hìI@ä2ÌV_åÀÅÀÍAÀÙë[Y}¯=§Íj'éá^¿:¥Îl/Í»£‹Ð^…zT$¢ €Ü…óJ¿7Ç·È» rp6~Çí­ï¯s ž:!´õ¯Nqã[JóFî¹zŠl­Bãÿðþö>1ôÇ$Pi Øß¬ÏW¯~Ýêá¡ýš^š;ì¡ârHô37R×¼¦`ß&5/®ßh'•}£ôýÍø?º84þJûØóÆA Tã×ß7Õ$Þ¸únËU ªõõjWO©WÛu‹*CµC•¥zM•­Ú]×Ýuê Už*¿n-—·UûT¿«ëîr@uHõ{ÕaÕ{ª#NÂïð7¼ç ~î€ê]Õ;Ö±Ü]ßR½©ÊÕóå¨^wœב鸮4W—* ôúû8Œ¡¿ÙåÇÙøÑïç?¨´J û1¼‡$Y3U+Šy¼寯Ú©B]ý8æÔcgÝI*TÝMW¡ôÞõ÷0F̽Raém Õ-Q-u~‡¿¡zÓu#ŸÅ1f«°r6ïÀ9^Tax{ƪF©žWaÜÛ{¡ð“}P€°ßTþ1ìWüG `7~dÁ‘ðCb cûž* ™!t†!a©l,˜‰Å3Ð £Ž6Õ TÁƒTh0†•x0VÓ8LÕŸaÄh$ìÂïð·ÉŽ÷¢AÁgaàhdpL Î…}üÐ SÁè1µ†ùý÷GÆC~(PBÑ~ ÿHÀpêC¿É1x •Á€Ð @?Q@&Ô 1€Á¡Ø·¿ SlÑ@`‘Á*4(ÃEcC…Ðh”&ü ïÃûaÐø,ŽÃÆ1qlœçÂ9qnùàzÐ8uV!чpó½ Ù‡Å>ÊäPŸBà?Ò†û`(04*C¿ÕsmUð¨O¨Ð "€Pê o ¡èì nºªP ¡á€`¨¥ÉüïÅç ÇÃq!œçƒpn;Ê{QßF e¾ˆXÐpÁð1©´a>Ü7ÿ‘@¥&à\Þë<™cäè3£@íüCãBDï ¡a0‚ñAȵ֟пšìï³Þ¯ösáܸŒç£Âõ!ÌÇ6ÞõMuÂ}x}–÷VêG7_ãýM}¿iЀ×D7“e`PˆÐÀÀ ÔÑÛå©ÿwŽëUiÇÁïœÏ‡kÀõÀËãú¯€Ñ›‰=Ècà~ìá>½>í€lœ³ˆŒYrtÐÀ¨0"¡Q(M0¾¡«ׂëÂõá:q½¸nÎéç#Ne$`o°vÂd3¯†„I?0*¡ô‹Ì5áúpÆÓãúq¦–Ÿ¿ŒßV9 ˜*à`4iLc€Âôß_ZæZðŠë3ïlô4üÊù<ó®ËAÀÞ !°7¦Qøo|5×j–í2÷Qü À¯„Àÿ ns&%ÒIEND®B`‚jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/JMapController.java0000644000175000017500000000205512223625012025541 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelListener; /** * Abstract base class for all mouse controller implementations. For * implementing your own controller create a class that derives from this one * and implements one or more of the following interfaces: *
    *
  • {@link MouseListener}
  • *
  • {@link MouseMotionListener}
  • *
  • {@link MouseWheelListener}
  • *
* * @author Jan Peter Stotz */ public abstract class JMapController { protected JMapViewer map; public JMapController(JMapViewer map) { this.map = map; if (this instanceof MouseListener) map.addMouseListener((MouseListener) this); if (this instanceof MouseWheelListener) map.addMouseWheelListener((MouseWheelListener) this); if (this instanceof MouseMotionListener) map.addMouseMotionListener((MouseMotionListener) this); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java0000644000175000017500000000673112223625014025343 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Point; import java.awt.Stroke; import javax.swing.UIManager; public abstract class MapObjectImpl { private Layer layer; private String name; private Style style; private Boolean visible; public MapObjectImpl(String name) { this(null, name, null); } public MapObjectImpl(Layer layer) { this(layer, null, null); } public MapObjectImpl(Layer layer, String name, Style style) { super(); this.layer = layer; this.name = name; this.style = style; } public Layer getLayer() { return layer; } public void setLayer(Layer layer) { this.layer = layer; } public Style getStyle(){ return style; } public Style getStyleAssigned(){ return style == null ? (layer == null ? null : layer.getStyle()) : style; } public void setStyle(Style style){ this.style = style; } public Color getColor() { Style styleAssigned = getStyleAssigned(); return styleAssigned == null ? null : getStyleAssigned().getColor(); } public void setColor(Color color) { if(style==null&&color!=null) style=new Style(); if(style!=null) style.setColor(color); } public Color getBackColor() { Style styleAssigned = getStyleAssigned(); return styleAssigned == null ? null : getStyleAssigned().getBackColor(); } public void setBackColor(Color backColor) { if(style==null&&backColor!=null) style=new Style(); if(style!=null) style.setBackColor(backColor); } public Stroke getStroke() { Style styleAssigned = getStyleAssigned(); return styleAssigned == null ? null : getStyleAssigned().getStroke(); } public void setStroke(Stroke stroke) { if(style==null&&stroke!=null) style=new Style(); if(style!=null) style.setStroke(stroke); } public Font getFont() { Style styleAssigned = getStyleAssigned(); return styleAssigned == null ? null : getStyleAssigned().getFont(); } public void setFont(Font font) { if(style==null&&font!=null) style=new Style(); if(style!=null) style.setFont(font); } private boolean isVisibleLayer(){ return layer==null||layer.isVisible()==null?true:layer.isVisible(); } public boolean isVisible() { return visible==null?isVisibleLayer():visible.booleanValue(); } public void setVisible(Boolean visible) { this.visible = visible; } public String getName() { return name; } public void setName(String txt) { this.name = txt; } public static Font getDefaultFont(){ Font f = UIManager.getDefaults().getFont("TextField.font"); return new Font(f.getName(), Font.BOLD, f.getSize()); } public void paintText(Graphics g, Point position) { if(name!=null && g!=null && position!=null){ if(getFont()==null){ Font f = getDefaultFont(); // g.getFont(); setFont(new Font(f.getName(), Font.BOLD, f.getSize())); } g.setColor(Color.DARK_GRAY); g.setFont(getFont()); g.drawString(name, position.x+MapMarkerDot.DOT_RADIUS+2, position.y+MapMarkerDot.DOT_RADIUS); } } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/OsmFileCacheTileLoader.java0000644000175000017500000004752012223625014027105 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; import org.openstreetmap.gui.jmapviewer.interfaces.CachedTileLoader; import org.openstreetmap.gui.jmapviewer.interfaces.TileClearController; import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource.TileUpdate; /** * A {@link TileLoader} implementation that loads tiles from OSM via HTTP and * saves all loaded files in a directory located in the temporary directory. * If a tile is present in this file cache it will not be loaded from OSM again. * * @author Jan Peter Stotz * @author Stefan Zeller */ public class OsmFileCacheTileLoader extends OsmTileLoader implements CachedTileLoader { private static final Logger log = Logger.getLogger(OsmFileCacheTileLoader.class.getName()); private static final String ETAG_FILE_EXT = ".etag"; private static final String TAGS_FILE_EXT = ".tags"; private static final Charset TAGS_CHARSET = Charset.forName("UTF-8"); public static final long FILE_AGE_ONE_DAY = 1000 * 60 * 60 * 24; public static final long FILE_AGE_ONE_WEEK = FILE_AGE_ONE_DAY * 7; protected String cacheDirBase; protected final Map sourceCacheDirMap; protected long maxCacheFileAge = FILE_AGE_ONE_WEEK; protected long recheckAfter = FILE_AGE_ONE_DAY; public static File getDefaultCacheDir() throws SecurityException { String tempDir = null; String userName = System.getProperty("user.name"); try { tempDir = System.getProperty("java.io.tmpdir"); } catch (SecurityException e) { log.log(Level.WARNING, "Failed to access system property ''java.io.tmpdir'' for security reasons. Exception was: " + e.toString()); throw e; // rethrow } try { if (tempDir == null) throw new IOException("No temp directory set"); String subDirName = "JMapViewerTiles"; // On Linux/Unix systems we do not have a per user tmp directory. // Therefore we add the user name for getting a unique dir name. if (userName != null && userName.length() > 0) { subDirName += "_" + userName; } File cacheDir = new File(tempDir, subDirName); return cacheDir; } catch (Exception e) { } return null; } /** * Create a OSMFileCacheTileLoader with given cache directory. * If cacheDir is not set or invalid, IOException will be thrown. * @param map the listener checking for tile load events (usually the map for display) * @param cacheDir directory to store cached tiles */ public OsmFileCacheTileLoader(TileLoaderListener map, File cacheDir) throws IOException { super(map); if (cacheDir == null || (!cacheDir.exists() && !cacheDir.mkdirs())) throw new IOException("Cannot access cache directory"); log.finest("Tile cache directory: " + cacheDir); cacheDirBase = cacheDir.getAbsolutePath(); sourceCacheDirMap = new HashMap(); } /** * Create a OSMFileCacheTileLoader with system property temp dir. * If not set an IOException will be thrown. * @param map the listener checking for tile load events (usually the map for display) */ public OsmFileCacheTileLoader(TileLoaderListener map) throws SecurityException, IOException { this(map, getDefaultCacheDir()); } @Override public TileJob createTileLoaderJob(final Tile tile) { return new FileLoadJob(tile); } protected File getSourceCacheDir(TileSource source) { File dir = sourceCacheDirMap.get(source); if (dir == null) { dir = new File(cacheDirBase, source.getName().replaceAll("[\\\\/:*?\"<>|]", "_")); if (!dir.exists()) { dir.mkdirs(); } } return dir; } protected class FileLoadJob implements TileJob { InputStream input = null; Tile tile; File tileCacheDir; File tileFile = null; long fileAge = 0; boolean fileTilePainted = false; public FileLoadJob(Tile tile) { this.tile = tile; } @Override public Tile getTile() { return tile; } @Override public void run() { synchronized (tile) { if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading()) return; tile.loaded = false; tile.error = false; tile.loading = true; } tileCacheDir = getSourceCacheDir(tile.getSource()); if (loadTileFromFile()) { return; } if (fileTilePainted) { TileJob job = new TileJob() { @Override public void run() { loadOrUpdateTile(); } @Override public Tile getTile() { return tile; } }; JobDispatcher.getInstance().addJob(job); } else { loadOrUpdateTile(); } } protected void loadOrUpdateTile() { try { URLConnection urlConn = loadTileFromOsm(tile); if (tileFile != null) { switch (tile.getSource().getTileUpdate()) { case IfModifiedSince: urlConn.setIfModifiedSince(fileAge); break; case LastModified: if (!isOsmTileNewer(fileAge)) { log.finest("LastModified test: local version is up to date: " + tile); tile.setLoaded(true); tileFile.setLastModified(System.currentTimeMillis() - maxCacheFileAge + recheckAfter); return; } break; } } if (tile.getSource().getTileUpdate() == TileUpdate.ETag || tile.getSource().getTileUpdate() == TileUpdate.IfNoneMatch) { String fileETag = tile.getValue("etag"); if (fileETag != null) { switch (tile.getSource().getTileUpdate()) { case IfNoneMatch: urlConn.addRequestProperty("If-None-Match", fileETag); break; case ETag: if (hasOsmTileETag(fileETag)) { tile.setLoaded(true); tileFile.setLastModified(System.currentTimeMillis() - maxCacheFileAge + recheckAfter); return; } } } tile.putValue("etag", urlConn.getHeaderField("ETag")); } if (urlConn instanceof HttpURLConnection && ((HttpURLConnection)urlConn).getResponseCode() == 304) { // If we are isModifiedSince or If-None-Match has been set // and the server answers with a HTTP 304 = "Not Modified" log.finest("ETag test: local version is up to date: " + tile); tile.setLoaded(true); tileFile.setLastModified(System.currentTimeMillis() - maxCacheFileAge + recheckAfter); return; } loadTileMetadata(tile, urlConn); saveTagsToFile(); if ("no-tile".equals(tile.getValue("tile-info"))) { tile.setError("No tile at this zoom level"); listener.tileLoadingFinished(tile, true); } else { for(int i = 0; i < 5; ++i) { if (urlConn instanceof HttpURLConnection && ((HttpURLConnection)urlConn).getResponseCode() == 503) { Thread.sleep(5000+(new Random()).nextInt(5000)); continue; } byte[] buffer = loadTileInBuffer(urlConn); if (buffer != null) { tile.loadImage(new ByteArrayInputStream(buffer)); tile.setLoaded(true); listener.tileLoadingFinished(tile, true); saveTileToFile(buffer); break; } } } } catch (Exception e) { tile.setError(e.getMessage()); listener.tileLoadingFinished(tile, false); if (input == null) { try { System.err.println("Failed loading " + tile.getUrl() +": " + e.getMessage()); } catch(IOException i) { } } } finally { tile.loading = false; tile.setLoaded(true); } } protected boolean loadTileFromFile() { FileInputStream fin = null; try { tileFile = getTileFile(); if (!tileFile.exists()) return false; loadTagsFromFile(); if ("no-tile".equals(tile.getValue("tile-info"))) { tile.setError("No tile at this zoom level"); if (tileFile.exists()) { tileFile.delete(); } tileFile = getTagsFile(); } else { fin = new FileInputStream(tileFile); if (fin.available() == 0) throw new IOException("File empty"); tile.loadImage(fin); fin.close(); } fileAge = tileFile.lastModified(); boolean oldTile = System.currentTimeMillis() - fileAge > maxCacheFileAge; if (!oldTile) { tile.setLoaded(true); listener.tileLoadingFinished(tile, true); fileTilePainted = true; return true; } listener.tileLoadingFinished(tile, true); fileTilePainted = true; } catch (Exception e) { try { if (fin != null) { fin.close(); tileFile.delete(); } } catch (Exception e1) { } tileFile = null; fileAge = 0; } return false; } protected byte[] loadTileInBuffer(URLConnection urlConn) throws IOException { input = urlConn.getInputStream(); try { ByteArrayOutputStream bout = new ByteArrayOutputStream(input.available()); byte[] buffer = new byte[2048]; boolean finished = false; do { int read = input.read(buffer); if (read >= 0) { bout.write(buffer, 0, read); } else { finished = true; } } while (!finished); if (bout.size() == 0) return null; return bout.toByteArray(); } finally { input.close(); input = null; } } /** * Performs a HEAD request for retrieving the * LastModified header value. * * Note: This does only work with servers providing the * LastModified header: *
    *
  • {@link tilesources.OsmTileSource.CycleMap} - supported
  • *
  • {@link tilesources.OsmTileSource.Mapnik} - not supported
  • *
* * @param fileAge time of the * @return true if the tile on the server is newer than the * file * @throws IOException */ protected boolean isOsmTileNewer(long fileAge) throws IOException { URL url; url = new URL(tile.getUrl()); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); prepareHttpUrlConnection(urlConn); urlConn.setRequestMethod("HEAD"); urlConn.setReadTimeout(30000); // 30 seconds read timeout // System.out.println("Tile age: " + new // Date(urlConn.getLastModified()) + " / " // + new Date(fileAge)); long lastModified = urlConn.getLastModified(); if (lastModified == 0) return true; // no LastModified time returned return (lastModified > fileAge); } protected boolean hasOsmTileETag(String eTag) throws IOException { URL url; url = new URL(tile.getUrl()); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); prepareHttpUrlConnection(urlConn); urlConn.setRequestMethod("HEAD"); urlConn.setReadTimeout(30000); // 30 seconds read timeout // System.out.println("Tile age: " + new // Date(urlConn.getLastModified()) + " / " // + new Date(fileAge)); String osmETag = urlConn.getHeaderField("ETag"); if (osmETag == null) return true; return (osmETag.equals(eTag)); } protected File getTileFile() { return new File(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + "." + tile.getSource().getTileType()); } protected File getTagsFile() { return new File(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + TAGS_FILE_EXT); } protected void saveTileToFile(byte[] rawData) { try { FileOutputStream f = new FileOutputStream(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + "." + tile.getSource().getTileType()); f.write(rawData); f.close(); // System.out.println("Saved tile to file: " + tile); } catch (Exception e) { System.err.println("Failed to save tile content: " + e.getLocalizedMessage()); } } protected void saveTagsToFile() { File tagsFile = getTagsFile(); if (tile.getMetadata() == null) { tagsFile.delete(); return; } try { final PrintWriter f = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tagsFile), TAGS_CHARSET)); for (Entry entry : tile.getMetadata().entrySet()) { f.println(entry.getKey() + "=" + entry.getValue()); } f.close(); } catch (Exception e) { System.err.println("Failed to save tile tags: " + e.getLocalizedMessage()); } } /** Load backward-compatiblity .etag file and if it exists move it to new .tags file*/ private void loadOldETagfromFile() { File etagFile = new File(tileCacheDir, tile.getZoom() + "_" + tile.getXtile() + "_" + tile.getYtile() + ETAG_FILE_EXT); if (!etagFile.exists()) return; try { FileInputStream f = new FileInputStream(etagFile); byte[] buf = new byte[f.available()]; f.read(buf); f.close(); String etag = new String(buf, TAGS_CHARSET.name()); tile.putValue("etag", etag); if (etagFile.delete()) { saveTagsToFile(); } } catch (IOException e) { System.err.println("Failed to load compatiblity etag: " + e.getLocalizedMessage()); } } protected void loadTagsFromFile() { loadOldETagfromFile(); File tagsFile = getTagsFile(); try { final BufferedReader f = new BufferedReader(new InputStreamReader(new FileInputStream(tagsFile), TAGS_CHARSET)); for (String line = f.readLine(); line != null; line = f.readLine()) { final int i = line.indexOf('='); if (i == -1 || i == 0) { System.err.println("Malformed tile tag in file '" + tagsFile.getName() + "':" + line); continue; } tile.putValue(line.substring(0,i),line.substring(i+1)); } f.close(); } catch (FileNotFoundException e) { } catch (Exception e) { System.err.println("Failed to load tile tags: " + e.getLocalizedMessage()); } } } public long getMaxFileAge() { return maxCacheFileAge; } /** * Sets the maximum age of the local cached tile in the file system. If a * local tile is older than the specified file age * {@link OsmFileCacheTileLoader} will connect to the tile server and check * if a newer tile is available using the mechanism specified for the * selected tile source/server. * * @param maxFileAge * maximum age in milliseconds * @see #FILE_AGE_ONE_DAY * @see #FILE_AGE_ONE_WEEK * @see TileSource#getTileUpdate() */ public void setCacheMaxFileAge(long maxFileAge) { this.maxCacheFileAge = maxFileAge; } public String getCacheDirBase() { return cacheDirBase; } public void setTileCacheDir(String tileCacheDir) { File dir = new File(tileCacheDir); dir.mkdirs(); this.cacheDirBase = dir.getAbsolutePath(); } @Override public void clearCache(TileSource source) { clearCache(source, null); } @Override public void clearCache(TileSource source, TileClearController controller) { File dir = getSourceCacheDir(source); if (dir != null) { if (controller != null) controller.initClearDir(dir); if (dir.isDirectory()) { File[] files = dir.listFiles(); if (controller != null) controller.initClearFiles(files); for (File file : files) { if (controller != null && controller.cancel()) return; file.delete(); if (controller != null) controller.fileDeleted(file); } } dir.delete(); } if (controller != null) controller.clearFinished(); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/Coordinate.java0000644000175000017500000000255112223625012024736 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2009 by Stefan Zeller import java.awt.geom.Point2D; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; /** * This class encapsulates a Point2D.Double and provide access * via lat and lon. * * @author Jan Peter Stotz * */ public class Coordinate implements Serializable, ICoordinate { private transient Point2D.Double data; public Coordinate(double lat, double lon) { data = new Point2D.Double(lon, lat); } public double getLat() { return data.y; } public void setLat(double lat) { data.y = lat; } public double getLon() { return data.x; } public void setLon(double lon) { data.x = lon; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(data.x); out.writeObject(data.y); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { data = new Point2D.Double(); data.x = (Double) in.readObject(); data.y = (Double) in.readObject(); } public String toString() { return "Coordinate[" + data.y + ", " + data.x + "]"; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/Style.java0000644000175000017500000000321512223625014023747 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.awt.Stroke; public class Style { private Color color; private Color backColor; private Stroke stroke; private Font font; private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC); public Style(){ super(); } public Style(Color color, Color backColor, Stroke stroke, Font font) { super(); this.color = color; this.backColor = backColor; this.stroke = stroke; this.font = font; } public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public Color getBackColor() { return backColor; } public void setBackColor(Color backColor) { this.backColor = backColor; } public Stroke getStroke() { return stroke; } public void setStroke(Stroke stroke) { this.stroke = stroke; } public Font getFont() { return font; } public void setFont(Font font) { this.font = font; } private AlphaComposite getAlphaComposite(Color color){ return color.getAlpha()==255?OPAQUE:TRANSPARENCY; } public AlphaComposite getAlphaComposite(){ return getAlphaComposite(color); } public AlphaComposite getBackAlphaComposite(){ return getAlphaComposite(backColor); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java0000644000175000017500000000476312223625012025416 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; import java.util.ArrayList; import java.util.List; public class AbstractLayer { private LayerGroup parent; private String name; private String description; private Style style; private Boolean visible; private Boolean visibleTexts=true; public AbstractLayer(String name){ this(name, (String)null); } public AbstractLayer(String name, String description){ this(name, description, MapMarkerCircle.getDefaultStyle()); } public AbstractLayer(String name, Style style){ this(name, null, style); } public AbstractLayer(String name, String description, Style style){ this(null, name, description, style); } public AbstractLayer(LayerGroup parent, String name){ this(parent, name, MapMarkerCircle.getDefaultStyle()); } public AbstractLayer(LayerGroup parent, String name, Style style){ this(parent, name, null, style); } public AbstractLayer(LayerGroup parent, String name, String description, Style style){ setParent(parent); setName(name); setDescription(description); setStyle(style); setVisible(true); if(parent!=null) parent.add(this); } public LayerGroup getParent() { return parent; } public void setParent(LayerGroup parent) { this.parent = parent; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Style getStyle() { return style; } public void setStyle(Style style) { this.style = style; } public Boolean isVisible() { return visible; } public void setVisible(Boolean visible) { this.visible = visible; } public static List add(List list, E element) { if(element!=null){ if(list==null) list = new ArrayList(); if(!list.contains(element)) list.add(element); } return list; } public Boolean isVisibleTexts() { return visibleTexts; } public void setVisibleTexts(Boolean visibleTexts) { this.visibleTexts = visibleTexts; } public String toString(){ return name; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/0000755000175000017500000000000012202517774024363 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java0000644000175000017500000000674012223625012030664 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.checkBoxTree; import java.awt.Component; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.EventObject; import javax.swing.AbstractCellEditor; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreePath; /** * Editor for checkBox Tree * * @author galo */ public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor{ /** SerialVersionUID */ private static final long serialVersionUID = -8921320784224636657L; private final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer(); private final CheckBoxTree theTree; public CheckBoxNodeEditor(final CheckBoxTree tree) { theTree = tree; } @Override public Object getCellEditorValue() { final CheckBoxNodePanel panel = renderer.getPanel(); /*final CheckBoxNodeData checkBoxNode = new CheckBoxNodeData(panel.label.getText(), panel.check.isSelected()); return checkBoxNode; CheckBoxNodeData data = search(theTree.rootNode(), panel.label.getText()); data.setSelected(panel.check.isSelected());*/ return panel.getData(); } /*public CheckBoxNodeData search(DefaultMutableTreeNode node, String name){ CheckBoxNodeData data = CheckBoxTree.data(node); if(data.getText().equals(name)) return data; else{ data = null; for(int i=0; i points; public MapPolygonImpl(ICoordinate ... points) { this(null, null, points); } public MapPolygonImpl(List points) { this(null, null, points); } public MapPolygonImpl(String name, List points) { this(null, name, points); } public MapPolygonImpl(String name, ICoordinate ... points) { this(null, name, points); } public MapPolygonImpl(Layer layer, List points) { this(layer, null, points); } public MapPolygonImpl(Layer layer, String name, List points) { this(layer, name, points, getDefaultStyle()); } public MapPolygonImpl(Layer layer, String name, ICoordinate ... points) { this(layer, name, Arrays.asList(points), getDefaultStyle()); } public MapPolygonImpl(Layer layer, String name, List points, Style style) { super(layer, name, style); this.points = points; } /* (non-Javadoc) * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#getPoints() */ @Override public List getPoints() { return this.points; } /* (non-Javadoc) * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#paint(java.awt.Graphics, java.util.List) */ @Override public void paint(Graphics g, List points) { Polygon polygon = new Polygon(); for (Point p : points) { polygon.addPoint(p.x, p.y); } paint(g, polygon); } /* (non-Javadoc) * @see org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon#paint(java.awt.Graphics, java.awt.Polygon) */ @Override public void paint(Graphics g, Polygon polygon) { // Prepare graphics Color oldColor = g.getColor(); g.setColor(getColor()); Stroke oldStroke = null; if (g instanceof Graphics2D) { Graphics2D g2 = (Graphics2D) g; oldStroke = g2.getStroke(); g2.setStroke(getStroke()); } // Draw g.drawPolygon(polygon); if (g instanceof Graphics2D && getBackColor()!=null) { Graphics2D g2 = (Graphics2D) g; Composite oldComposite = g2.getComposite(); g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); g2.setPaint(getBackColor()); g2.fillPolygon(polygon); g2.setComposite(oldComposite); } // Restore graphics g.setColor(oldColor); if (g instanceof Graphics2D) { ((Graphics2D) g).setStroke(oldStroke); } Rectangle rec = polygon.getBounds(); Point corner = rec.getLocation(); Point p= new Point(corner.x+(rec.width/2), corner.y+(rec.height/2)); if(getLayer()==null||getLayer().isVisibleTexts()) paintText(g, p); } public static Style getDefaultStyle(){ return new Style(Color.BLUE, new Color(100,100,100,50), new BasicStroke(2), getDefaultFont()); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "MapPolygon [points=" + points + "]"; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java0000644000175000017500000001366712223625012026562 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. import static org.openstreetmap.gui.jmapviewer.FeatureAdapter.tr; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.font.TextAttribute; import java.awt.geom.Rectangle2D; import java.awt.image.ImageObserver; import java.util.HashMap; import org.openstreetmap.gui.jmapviewer.interfaces.Attributed; public class AttributionSupport { private Attributed source; private Image attrImage; private String attrTermsText; private String attrTermsUrl; public static final Font ATTR_FONT = new Font("Arial", Font.PLAIN, 10); public static final Font ATTR_LINK_FONT; protected Rectangle attrTextBounds = null; protected Rectangle attrToUBounds = null; protected Rectangle attrImageBounds = null; static { HashMap aUnderline = new HashMap(); aUnderline.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); ATTR_LINK_FONT = ATTR_FONT.deriveFont(aUnderline); } public void initialize(Attributed source) { this.source = source; boolean requireAttr = source.requiresAttribution(); if (requireAttr) { attrImage = source.getAttributionImage(); attrTermsText = source.getTermsOfUseText(); attrTermsUrl = source.getTermsOfUseURL(); if (attrTermsUrl != null && attrTermsText == null) { attrTermsText = tr("Background Terms of Use"); } } else { attrImage = null; attrTermsUrl = null; } } public void paintAttribution(Graphics g, int width, int height, Coordinate topLeft, Coordinate bottomRight, int zoom, ImageObserver observer) { if (source == null || !source.requiresAttribution()) { attrToUBounds = null; attrImageBounds = null; attrTextBounds = null; return; } // Draw attribution Font font = g.getFont(); g.setFont(ATTR_LINK_FONT); // Draw terms of use text int termsTextHeight = 0; int termsTextY = height; if (attrTermsText != null) { Rectangle2D termsStringBounds = g.getFontMetrics().getStringBounds(attrTermsText, g); int textRealHeight = (int) termsStringBounds.getHeight(); termsTextHeight = textRealHeight - 5; int termsTextWidth = (int) termsStringBounds.getWidth(); termsTextY = height - termsTextHeight; int x = 2; int y = height - termsTextHeight; attrToUBounds = new Rectangle(x, y-termsTextHeight, termsTextWidth, textRealHeight); g.setColor(Color.black); g.drawString(attrTermsText, x + 1, y + 1); g.setColor(Color.white); g.drawString(attrTermsText, x, y); } else { attrToUBounds = null; } // Draw attribution logo if (attrImage != null) { int x = 2; int imgWidth = attrImage.getWidth(observer); int imgHeight = attrImage.getHeight(observer); int y = termsTextY - imgHeight - termsTextHeight - 5; attrImageBounds = new Rectangle(x, y, imgWidth, imgHeight); g.drawImage(attrImage, x, y, null); } else { attrImageBounds = null; } g.setFont(ATTR_FONT); String attributionText = source.getAttributionText(zoom, topLeft, bottomRight); if (attributionText != null) { Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(attributionText, g); int textHeight = (int) stringBounds.getHeight() - 5; int x = width - (int) stringBounds.getWidth(); int y = height - textHeight; g.setColor(Color.black); g.drawString(attributionText, x + 1, y + 1); g.setColor(Color.white); g.drawString(attributionText, x, y); attrTextBounds = new Rectangle(x, y-textHeight, (int) stringBounds.getWidth(), (int) stringBounds.getHeight()); } else { attrTextBounds = null; } g.setFont(font); } public boolean handleAttributionCursor(Point p) { if (attrTextBounds != null && attrTextBounds.contains(p)) { return true; } else if (attrImageBounds != null && attrImageBounds.contains(p)) { return true; } else if (attrToUBounds != null && attrToUBounds.contains(p)) { return true; } return false; } public boolean handleAttribution(Point p, boolean click) { if (source == null || !source.requiresAttribution()) return false; if (attrTextBounds != null && attrTextBounds.contains(p)) { String attributionURL = source.getAttributionLinkURL(); if (attributionURL != null) { if (click) { FeatureAdapter.openLink(attributionURL); } return true; } } else if (attrImageBounds != null && attrImageBounds.contains(p)) { String attributionImageURL = source.getAttributionImageURL(); if (attributionImageURL != null) { if (click) { FeatureAdapter.openLink(source.getAttributionImageURL()); } return true; } } else if (attrToUBounds != null && attrToUBounds.contains(p)) { String termsOfUseURL = source.getTermsOfUseURL(); if (termsOfUseURL != null) { if (click) { FeatureAdapter.openLink(termsOfUseURL); } return true; } } return false; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java0000644000175000017500000000356312223625014024746 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; import java.util.List; public class LayerGroup extends AbstractLayer{ private List layers; public LayerGroup(String name){ super(name); } public LayerGroup(String name, String description){ super(name, description); } public LayerGroup(String name, Style style){ super(name, style); } public LayerGroup(String name, String description, Style style){ super(name, description, style); } public LayerGroup(LayerGroup parent, String name){ super(parent, name); } public LayerGroup(LayerGroup parent, String name, String description, Style style){ super(name, description, style); } public List getLayers() { return layers; } public void setElements(List layers) { this.layers = layers; } public Layer addLayer(String name) { Layer layer = new Layer(this, name); layers = add(layers, layer); return layer; } public LayerGroup add(AbstractLayer layer) { layer.setParent(this); layers = add(layers, layer); return this; } public void calculateVisibleTexts(){ Boolean calculate=null; if(layers!=null&&layers.size()>0){ calculate=layers.get(0).isVisibleTexts(); for(int i=1;i elements; public Layer(String name){ super(name); } public Layer(String name, String description){ super(name, description); } public Layer(String name, Style style){ super(name, style); } public Layer(String name, String description, Style style){ super(name, description, style); } public Layer(LayerGroup parent, String name){ super(parent, name); } public Layer(LayerGroup parent, String name, Style style){ super(parent, name, style); } public Layer(LayerGroup parent, String name, String description, Style style){ super(parent, name, description, style); } public List getElements() { return elements; } public void setElements(List elements) { this.elements = elements; } public Layer add(MapObject element) { element.setLayer(this); elements = add(elements, element); return this; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java0000644000175000017500000000411712223625012025543 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.MessageFormat; public class FeatureAdapter { public static interface BrowserAdapter { void openLink(String url); } public static interface TranslationAdapter { String tr(String text, Object... objects); // TODO: more i18n functions } private static BrowserAdapter browserAdapter = new DefaultBrowserAdapter(); private static TranslationAdapter translationAdapter = new DefaultTranslationAdapter(); public static void registerBrowserAdapter(BrowserAdapter browserAdapter) { FeatureAdapter.browserAdapter = browserAdapter; } public static void registerTranslationAdapter(TranslationAdapter translationAdapter) { FeatureAdapter.translationAdapter = translationAdapter; } public static void openLink(String url) { browserAdapter.openLink(url); } public static String tr(String text, Object... objects) { return translationAdapter.tr(text, objects); } public static class DefaultBrowserAdapter implements BrowserAdapter { @Override public void openLink(String url) { if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { try { Desktop.getDesktop().browse(new URI(url)); } catch (IOException e) { e.printStackTrace(); } catch (URISyntaxException e) { e.printStackTrace(); } } else { System.err.println(tr("Opening link not supported on current platform (''{0}'')", url)); } } } public static class DefaultTranslationAdapter implements TranslationAdapter { @Override public String tr(String text, Object... objects) { return MessageFormat.format(text, objects); } } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java0000644000175000017500000001022712223625014025353 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; /** * A {@link TileLoader} implementation that loads tiles from OSM. * * @author Jan Peter Stotz */ public class OsmTileLoader implements TileLoader { /** * Holds the HTTP headers. Insert e.g. User-Agent here when default should not be used. */ public Map headers = new HashMap(); public int timeoutConnect = 0; public int timeoutRead = 0; protected TileLoaderListener listener; public OsmTileLoader(TileLoaderListener listener) { headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*"); this.listener = listener; } public TileJob createTileLoaderJob(final Tile tile) { return new TileJob() { InputStream input = null; public void run() { synchronized (tile) { if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading()) return; tile.loaded = false; tile.error = false; tile.loading = true; } try { URLConnection conn = loadTileFromOsm(tile); loadTileMetadata(tile, conn); if ("no-tile".equals(tile.getValue("tile-info"))) { tile.setError("No tile at this zoom level"); } else { input = conn.getInputStream(); try { tile.loadImage(input); } finally { input.close(); input = null; } } tile.setLoaded(true); listener.tileLoadingFinished(tile, true); } catch (Exception e) { tile.setError(e.getMessage()); listener.tileLoadingFinished(tile, false); if (input == null) { try { System.err.println("Failed loading " + tile.getUrl() +": " + e.getMessage()); } catch(IOException i) { } } } finally { tile.loading = false; tile.setLoaded(true); } } public Tile getTile() { return tile; } }; } protected URLConnection loadTileFromOsm(Tile tile) throws IOException { URL url; url = new URL(tile.getUrl()); URLConnection urlConn = url.openConnection(); if (urlConn instanceof HttpURLConnection) { prepareHttpUrlConnection((HttpURLConnection)urlConn); } urlConn.setReadTimeout(30000); // 30 seconds read timeout return urlConn; } protected void loadTileMetadata(Tile tile, URLConnection urlConn) { String str = urlConn.getHeaderField("X-VE-TILEMETA-CaptureDatesRange"); if (str != null) { tile.putValue("capture-date", str); } str = urlConn.getHeaderField("X-VE-Tile-Info"); if (str != null) { tile.putValue("tile-info", str); } } protected void prepareHttpUrlConnection(HttpURLConnection urlConn) { for(Entry e : headers.entrySet()) { urlConn.setRequestProperty(e.getKey(), e.getValue()); } if(timeoutConnect != 0) urlConn.setConnectTimeout(timeoutConnect); if(timeoutRead != 0) urlConn.setReadTimeout(timeoutRead); } @Override public String toString() { return getClass().getSimpleName(); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/Tile.java0000644000175000017500000002175512223625014023555 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import org.openstreetmap.gui.jmapviewer.interfaces.TileCache; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; /** * Holds one map tile. Additionally the code for loading the tile image and * painting it is also included in this class. * * @author Jan Peter Stotz */ public class Tile { /** * Hourglass image that is displayed until a map tile has been loaded */ public static BufferedImage LOADING_IMAGE; public static BufferedImage ERROR_IMAGE; static { try { LOADING_IMAGE = ImageIO.read(JMapViewer.class.getResourceAsStream("images/hourglass.png")); ERROR_IMAGE = ImageIO.read(JMapViewer.class.getResourceAsStream("images/error.png")); } catch (Exception e1) { LOADING_IMAGE = null; ERROR_IMAGE = null; } } protected TileSource source; protected int xtile; protected int ytile; protected int zoom; protected BufferedImage image; protected String key; protected boolean loaded = false; protected boolean loading = false; protected boolean error = false; protected String error_message; /** TileLoader-specific tile metadata */ protected Map metadata; /** * Creates a tile with empty image. * * @param source * @param xtile * @param ytile * @param zoom */ public Tile(TileSource source, int xtile, int ytile, int zoom) { super(); this.source = source; this.xtile = xtile; this.ytile = ytile; this.zoom = zoom; this.image = LOADING_IMAGE; this.key = getTileKey(source, xtile, ytile, zoom); } public Tile(TileSource source, int xtile, int ytile, int zoom, BufferedImage image) { this(source, xtile, ytile, zoom); this.image = image; } /** * Tries to get tiles of a lower or higher zoom level (one or two level * difference) from cache and use it as a placeholder until the tile has * been loaded. */ public void loadPlaceholderFromCache(TileCache cache) { BufferedImage tmpImage = new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) tmpImage.getGraphics(); // g.drawImage(image, 0, 0, null); for (int zoomDiff = 1; zoomDiff < 5; zoomDiff++) { // first we check if there are already the 2^x tiles // of a higher detail level int zoom_high = zoom + zoomDiff; if (zoomDiff < 3 && zoom_high <= JMapViewer.MAX_ZOOM) { int factor = 1 << zoomDiff; int xtile_high = xtile << zoomDiff; int ytile_high = ytile << zoomDiff; double scale = 1.0 / factor; g.setTransform(AffineTransform.getScaleInstance(scale, scale)); int paintedTileCount = 0; for (int x = 0; x < factor; x++) { for (int y = 0; y < factor; y++) { Tile tile = cache.getTile(source, xtile_high + x, ytile_high + y, zoom_high); if (tile != null && tile.isLoaded()) { paintedTileCount++; tile.paint(g, x * source.getTileSize(), y * source.getTileSize()); } } } if (paintedTileCount == factor * factor) { image = tmpImage; return; } } int zoom_low = zoom - zoomDiff; if (zoom_low >= JMapViewer.MIN_ZOOM) { int xtile_low = xtile >> zoomDiff; int ytile_low = ytile >> zoomDiff; int factor = (1 << zoomDiff); double scale = factor; AffineTransform at = new AffineTransform(); int translate_x = (xtile % factor) * source.getTileSize(); int translate_y = (ytile % factor) * source.getTileSize(); at.setTransform(scale, 0, 0, scale, -translate_x, -translate_y); g.setTransform(at); Tile tile = cache.getTile(source, xtile_low, ytile_low, zoom_low); if (tile != null && tile.isLoaded()) { tile.paint(g, 0, 0); image = tmpImage; return; } } } } public TileSource getSource() { return source; } /** * @return tile number on the x axis of this tile */ public int getXtile() { return xtile; } /** * @return tile number on the y axis of this tile */ public int getYtile() { return ytile; } /** * @return zoom level of this tile */ public int getZoom() { return zoom; } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public void loadImage(InputStream input) throws IOException { image = ImageIO.read(input); } /** * @return key that identifies a tile */ public String getKey() { return key; } public boolean isLoaded() { return loaded; } public boolean isLoading() { return loading; } public void setLoaded(boolean loaded) { this.loaded = loaded; } public String getUrl() throws IOException { return source.getTileUrl(zoom, xtile, ytile); } /** * Paints the tile-image on the {@link Graphics} g at the * position x/y. * * @param g * @param x * x-coordinate in g * @param y * y-coordinate in g */ public void paint(Graphics g, int x, int y) { if (image == null) return; g.drawImage(image, x, y, null); } @Override public String toString() { return "Tile " + key; } /** * Note that the hash code does not include the {@link #source}. * Therefore a hash based collection can only contain tiles * of one {@link #source}. */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + xtile; result = prime * result + ytile; result = prime * result + zoom; return result; } /** * Compares this object with obj based on * the fields {@link #xtile}, {@link #ytile} and * {@link #zoom}. * The {@link #source} field is ignored. */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Tile other = (Tile) obj; if (xtile != other.xtile) return false; if (ytile != other.ytile) return false; if (zoom != other.zoom) return false; return true; } public static String getTileKey(TileSource source, int xtile, int ytile, int zoom) { return zoom + "/" + xtile + "/" + ytile + "@" + source.getName(); } public String getStatus() { if (this.error) return "error"; if (this.loaded) return "loaded"; if (this.loading) return "loading"; return "new"; } public boolean hasError() { return error; } public String getErrorMessage() { return error_message; } public void setError(String message) { error = true; setImage(ERROR_IMAGE); error_message = message; } /** * Puts the given key/value pair to the metadata of the tile. * If value is null, the (possibly existing) key/value pair is removed from * the meta data. * * @param key * @param value */ public void putValue(String key, String value) { if (value == null || value.isEmpty()) { if (metadata != null) { metadata.remove(key); } return; } if (metadata == null) { metadata = new HashMap(); } metadata.put(key, value); } public String getValue(String key) { if (metadata == null) return null; return metadata.get(key); } public Map getMetadata() { return metadata; } public void initLoading() { loaded = false; error = false; loading = true; } public void finishLoading() { loading = false; loaded = true; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java0000644000175000017500000001433112223625014025103 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; // License: GPL. Copyright 2007 by Tim Haussmann /** * This class implements the Mercator Projection as it is used by Openstreetmap * (and google). It provides methods to translate coordinates from 'map space' * into latitude and longitude (on the WGS84 ellipsoid) and vice versa. Map * space is measured in pixels. The origin of the map space is the top left * corner. The map space origin (0,0) has latitude ~85 and longitude -180 * * @author Tim Haussmann * */ public class OsmMercator { private static int TILE_SIZE = 256; public static final double MAX_LAT = 85.05112877980659; public static final double MIN_LAT = -85.05112877980659; private static double EARTH_RADIUS = 6378137; // equatorial earth radius for EPSG:3857 (Mercator) public static double radius(int aZoomlevel) { return (TILE_SIZE * (1 << aZoomlevel)) / (2.0 * Math.PI); } /** * Returns the absolut number of pixels in y or x, defined as: 2^Zoomlevel * * TILE_WIDTH where TILE_WIDTH is the width of a tile in pixels * * @param aZoomlevel zoom level to request pixel data * @return number of pixels */ public static int getMaxPixels(int aZoomlevel) { return TILE_SIZE * (1 << aZoomlevel); } public static int falseEasting(int aZoomlevel) { return getMaxPixels(aZoomlevel) / 2; } public static int falseNorthing(int aZoomlevel) { return (-1 * getMaxPixels(aZoomlevel) / 2); } /** * Transform pixelspace to coordinates and get the distance. * * @param x1 the first x coordinate * @param y1 the first y coordinate * @param x2 the second x coordinate * @param y2 the second y coordinate * * @param zoomLevel the zoom level * @return the distance * @author Jason Huntley */ public static double getDistance(int x1, int y1, int x2, int y2, int zoomLevel) { double la1 = YToLat(y1, zoomLevel); double lo1 = XToLon(x1, zoomLevel); double la2 = YToLat(y2, zoomLevel); double lo2 = XToLon(x2, zoomLevel); return getDistance(la1, lo1, la2, lo2); } /** * Gets the distance using Spherical law of cosines. * * @param la1 the Latitude in degrees * @param lo1 the Longitude in degrees * @param la2 the Latitude from 2nd coordinate in degrees * @param lo2 the Longitude from 2nd coordinate in degrees * @return the distance * @author Jason Huntley */ public static double getDistance(double la1, double lo1, double la2, double lo2) { double aStartLat = Math.toRadians(la1); double aStartLong = Math.toRadians(lo1); double aEndLat =Math.toRadians(la2); double aEndLong = Math.toRadians(lo2); double distance = Math.acos(Math.sin(aStartLat) * Math.sin(aEndLat) + Math.cos(aStartLat) * Math.cos(aEndLat) * Math.cos(aEndLong - aStartLong)); return (EARTH_RADIUS * distance); } /** * Transform longitude to pixelspace * *

* Mathematical optimization
* * x = radius(aZoomlevel) * toRadians(aLongitude) + falseEasting(aZoomLevel)
* x = getMaxPixels(aZoomlevel) / (2 * PI) * (aLongitude * PI) / 180 + getMaxPixels(aZoomlevel) / 2
* x = getMaxPixels(aZoomlevel) * aLongitude / 360 + 180 * getMaxPixels(aZoomlevel) / 360
* x = getMaxPixels(aZoomlevel) * (aLongitude + 180) / 360
*
*

* * @param aLongitude * [-180..180] * @return [0..2^Zoomlevel*TILE_SIZE[ * @author Jan Peter Stotz */ public static int LonToX(double aLongitude, int aZoomlevel) { int mp = getMaxPixels(aZoomlevel); int x = (int) ((mp * (aLongitude + 180l)) / 360l); x = Math.min(x, mp - 1); return x; } /** * Transforms latitude to pixelspace *

* Mathematical optimization
* * log(u) := log((1.0 + sin(toRadians(aLat))) / (1.0 - sin(toRadians(aLat))
* * y = -1 * (radius(aZoomlevel) / 2 * log(u)))) - falseNorthing(aZoomlevel))
* y = -1 * (getMaxPixel(aZoomlevel) / 2 * PI / 2 * log(u)) - -1 * getMaxPixel(aZoomLevel) / 2
* y = getMaxPixel(aZoomlevel) / (-4 * PI) * log(u)) + getMaxPixel(aZoomLevel) / 2
* y = getMaxPixel(aZoomlevel) * ((log(u) / (-4 * PI)) + 1/2)
*
*

* @param aLat * [-90...90] * @return [0..2^Zoomlevel*TILE_SIZE[ * @author Jan Peter Stotz */ public static int LatToY(double aLat, int aZoomlevel) { if (aLat < MIN_LAT) aLat = MIN_LAT; else if (aLat > MAX_LAT) aLat = MAX_LAT; double sinLat = Math.sin(Math.toRadians(aLat)); double log = Math.log((1.0 + sinLat) / (1.0 - sinLat)); int mp = getMaxPixels(aZoomlevel); int y = (int) (mp * (0.5 - (log / (4.0 * Math.PI)))); y = Math.min(y, mp - 1); return y; } /** * Transforms pixel coordinate X to longitude * *

* Mathematical optimization
* * lon = toDegree((aX - falseEasting(aZoomlevel)) / radius(aZoomlevel))
* lon = 180 / PI * ((aX - getMaxPixels(aZoomlevel) / 2) / getMaxPixels(aZoomlevel) / (2 * PI)
* lon = 180 * ((aX - getMaxPixels(aZoomlevel) / 2) / getMaxPixels(aZoomlevel))
* lon = 360 / getMaxPixels(aZoomlevel) * (aX - getMaxPixels(aZoomlevel) / 2)
* lon = 360 * aX / getMaxPixels(aZoomlevel) - 180
*
*

* @param aX * [0..2^Zoomlevel*TILE_WIDTH[ * @return ]-180..180[ * @author Jan Peter Stotz */ public static double XToLon(int aX, int aZoomlevel) { return ((360d * aX) / getMaxPixels(aZoomlevel)) - 180.0; } /** * Transforms pixel coordinate Y to latitude * * @param aY * [0..2^Zoomlevel*TILE_WIDTH[ * @return [MIN_LAT..MAX_LAT] is about [-85..85] */ public static double YToLat(int aY, int aZoomlevel) { aY += falseNorthing(aZoomlevel); double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel)))); return -1 * Math.toDegrees(latitude); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/events/0000755000175000017500000000000012223624304023310 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/events/JMVCommandEvent.java0000644000175000017500000000172312223625012027110 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.events; //License: GPL. import java.util.EventObject; /** * Used for passing events between UI components and other * objects that register as a JMapViewerEventListener * * @author Jason Huntley * */ public class JMVCommandEvent extends EventObject { public static enum COMMAND { MOVE, ZOOM } private COMMAND command; /** * */ private static final long serialVersionUID = 8701544867914969620L; public JMVCommandEvent(COMMAND cmd, Object source) { super(source); setCommand(cmd); } public JMVCommandEvent(Object source) { super(source); } /** * @return the command */ public COMMAND getCommand() { return command; } /** * @param command the command to set */ public void setCommand(COMMAND command) { this.command = command; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java0000644000175000017500000000317412223625014025201 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Color; import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker; /** * A simple implementation of the {@link MapMarker} interface. Each map marker * is painted as a circle with a black border line and filled with a specified * color. * * @author Jan Peter Stotz * */ public class MapMarkerDot extends MapMarkerCircle { public static final int DOT_RADIUS = 5; public MapMarkerDot(Coordinate coord) { this(null, null, coord); } public MapMarkerDot(String name, Coordinate coord) { this(null, name, coord); } public MapMarkerDot(Layer layer, Coordinate coord) { this(layer, null, coord); } public MapMarkerDot(Layer layer, String name, Coordinate coord) { this(layer, name, coord, getDefaultStyle()); } public MapMarkerDot(Color color, double lat, double lon) { this(null, null, lat, lon); setColor(color); } public MapMarkerDot(double lat, double lon) { this(null, null, lat, lon); } public MapMarkerDot(Layer layer, double lat, double lon) { this(layer, null, lat, lon); } public MapMarkerDot(Layer layer, String name, double lat, double lon) { this(layer, name, new Coordinate(lat, lon), getDefaultStyle()); } public MapMarkerDot(Layer layer, String name, Coordinate coord, Style style) { super(layer, name, coord, DOT_RADIUS, STYLE.FIXED, style); } public static Style getDefaultStyle(){ return new Style(Color.BLACK, Color.YELLOW, null, getDefaultFont()); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/package.html0000644000175000017500000000101412223625014024260 0ustar felixfelix org.openstreetmap.gui.jmapviewer

This package and all sub-packages are belonging to the Java component JMapViewer

JMapViewer is designed to run as stand-alone component without any further requirements. Therefore please do not add any code that depends on other libraries or applications. Only functions and methods provided by the runtime library of Java 5 should be used.

jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/JobDispatcher.java0000644000175000017500000001212412223625012025365 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; /** * A generic class that processes a list of {@link Runnable} one-by-one using * one or more {@link Thread}-instances. The number of instances varies between * 1 and {@link #workerThreadMaxCount} (default: 8). If an instance is idle * more than {@link #workerThreadTimeout} seconds (default: 30), the instance * ends itself. * * @author Jan Peter Stotz */ public class JobDispatcher { private static final JobDispatcher instance = new JobDispatcher(); /** * @return the singelton instance of the {@link JobDispatcher} */ public static JobDispatcher getInstance() { return instance; } private JobDispatcher() { addWorkerThread().firstThread = true; } protected BlockingDeque jobQueue = new LinkedBlockingDeque(); protected static int workerThreadMaxCount = 8; /** * Specifies the time span in seconds that a worker thread waits for new * jobs to perform. If the time span has elapsed the worker thread * terminates itself. Only the first worker thread works differently, it * ignores the timeout and will never terminate itself. */ protected static int workerThreadTimeout = 30; /** * Type of queue, FIFO if false, LIFO if true */ protected boolean modeLIFO = false; /** * Total number of worker threads currently idle or active */ protected int workerThreadCount = 0; /** * Number of worker threads currently idle */ protected int workerThreadIdleCount = 0; /** * Just an id for identifying an worker thread instance */ protected int workerThreadId = 0; /** * Removes all jobs from the queue that are currently not being processed. */ public void cancelOutstandingJobs() { jobQueue.clear(); } /** * Function to set the maximum number of workers for tile loading. */ static public void setMaxWorkers(int workers) { workerThreadMaxCount = workers; } /** * Function to set the LIFO/FIFO mode for tile loading job. * * @param lifo true for LIFO mode, false for FIFO mode */ public void setLIFO(boolean lifo) { modeLIFO = lifo; } /** * Adds a job to the queue. * Jobs for tiles already contained in the are ignored (using a null tile * prevents skipping). * * @param job the the job to be added */ public void addJob(TileJob job) { try { if(job.getTile() != null) { for(TileJob oldJob : jobQueue) { if(oldJob.getTile() == job.getTile()) { return; } } } jobQueue.put(job); if (workerThreadIdleCount == 0 && workerThreadCount < workerThreadMaxCount) addWorkerThread(); } catch (InterruptedException e) { } } protected JobThread addWorkerThread() { JobThread jobThread = new JobThread(++workerThreadId); synchronized (this) { workerThreadCount++; } jobThread.start(); return jobThread; } public class JobThread extends Thread { Runnable job; boolean firstThread = false; public JobThread(int threadId) { super("OSMJobThread " + threadId); setDaemon(true); job = null; } @Override public void run() { executeJobs(); synchronized (instance) { workerThreadCount--; } } protected void executeJobs() { while (!isInterrupted()) { try { synchronized (instance) { workerThreadIdleCount++; } if(modeLIFO) { if (firstThread) job = jobQueue.takeLast(); else job = jobQueue.pollLast(workerThreadTimeout, TimeUnit.SECONDS); } else { if (firstThread) job = jobQueue.take(); else job = jobQueue.poll(workerThreadTimeout, TimeUnit.SECONDS); } } catch (InterruptedException e1) { return; } finally { synchronized (instance) { workerThreadIdleCount--; } } if (job == null) return; try { job.run(); job = null; } catch (Exception e) { e.printStackTrace(); } } } } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/0000755000175000017500000000000012223624304024345 5ustar felixfelixjmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java0000644000175000017500000000456112223625014031343 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; //License: GPL. import java.awt.Image; import java.io.IOException; import javax.swing.ImageIcon; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; public abstract class AbstractTMSTileSource extends AbstractTileSource { protected String name; protected String baseUrl; public AbstractTMSTileSource(String name, String base_url) { this.name = name; this.baseUrl = base_url; if(baseUrl.endsWith("/")) { baseUrl = baseUrl.substring(0,baseUrl.length()-1); } } @Override public String getName() { return name; } @Override public int getMaxZoom() { return 21; } @Override public int getMinZoom() { return 0; } public String getExtension() { return "png"; } /** * @throws IOException when subclass cannot return the tile URL */ public String getTilePath(int zoom, int tilex, int tiley) throws IOException { return "/" + zoom + "/" + tilex + "/" + tiley + "." + getExtension(); } public String getBaseUrl() { return this.baseUrl; } @Override public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); } @Override public String toString() { return getName(); } @Override public String getTileType() { return "png"; } @Override public int getTileSize() { return 256; } @Override public double latToTileY(double lat, int zoom) { double l = lat / 180 * Math.PI; double pf = Math.log(Math.tan(l) + (1 / Math.cos(l))); return Math.pow(2.0, zoom - 1) * (Math.PI - pf) / Math.PI; } @Override public double lonToTileX(double lon, int zoom) { return Math.pow(2.0, zoom - 3) * (lon + 180.0) / 45.0; } @Override public double tileYToLat(int y, int zoom) { return Math.atan(Math.sinh(Math.PI - (Math.PI * y / Math.pow(2.0, zoom - 1)))) * 180 / Math.PI; } @Override public double tileXToLon(int x, int zoom) { return x * 45.0 / Math.pow(2.0, zoom - 3) - 180.0; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java0000644000175000017500000000303412223625014027744 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; /** * OSM Tile source. */ public class OsmTileSource { /** * The default "Mapnik" OSM tile source URL */ public static final String MAP_MAPNIK = "http://tile.openstreetmap.org"; /** * The default "Mapnik" OSM tile source. */ public static class Mapnik extends AbstractOsmTileSource { /** * Constructs a new {@code "Mapnik"} tile source. */ public Mapnik() { super("Mapnik", MAP_MAPNIK); } public TileUpdate getTileUpdate() { return TileUpdate.IfNoneMatch; } } /** * The "Cycle Map" OSM tile source. */ public static class CycleMap extends AbstractOsmTileSource { private static final String PATTERN = "http://%s.tile.opencyclemap.org/cycle"; private static final String[] SERVER = { "a", "b", "c" }; private int SERVER_NUM = 0; /** * Constructs a new {@code CycleMap} tile source. */ public CycleMap() { super("OSM Cycle Map", PATTERN); } @Override public String getBaseUrl() { String url = String.format(this.baseUrl, new Object[] { SERVER[SERVER_NUM] }); SERVER_NUM = (SERVER_NUM + 1) % SERVER.length; return url; } @Override public int getMaxZoom() { return 18; } public TileUpdate getTileUpdate() { return TileUpdate.LastModified; } } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java0000644000175000017500000000414112223625014030751 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import java.awt.Image; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; import org.openstreetmap.gui.jmapviewer.Coordinate; //License: GPL. Copyright 2008 by Jan Peter Stotz abstract public class AbstractTileSource implements TileSource { protected String attributionText; protected String attributionLinkURL; protected Image attributionImage; protected String attributionImageURL; protected String termsOfUseText; protected String termsOfUseURL; @Override public boolean requiresAttribution() { return attributionText != null || attributionImage != null || termsOfUseText != null || termsOfUseURL != null; } @Override public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) { return attributionText; } @Override public String getAttributionLinkURL() { return attributionLinkURL; } @Override public Image getAttributionImage() { return attributionImage; } @Override public String getAttributionImageURL() { return attributionImageURL; } @Override public String getTermsOfUseText() { return termsOfUseText; } @Override public String getTermsOfUseURL() { return termsOfUseURL; } public void setAttributionText(String attributionText) { this.attributionText = attributionText; } public void setAttributionLinkURL(String attributionLinkURL) { this.attributionLinkURL = attributionLinkURL; } public void setAttributionImage(Image attributionImage) { this.attributionImage = attributionImage; } public void setAttributionImageURL(String attributionImageURL) { this.attributionImageURL = attributionImageURL; } public void setTermsOfUseText(String termsOfUseText) { this.termsOfUseText = termsOfUseText; } public void setTermsOfUseURL(String termsOfUseURL) { this.termsOfUseURL = termsOfUseURL; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java0000644000175000017500000000626512223625014031522 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import java.util.Map; import java.util.HashMap; import java.util.Random; import java.util.regex.Pattern; import java.util.regex.Matcher; public class TemplatedTMSTileSource extends TMSTileSource { private Random rand = null; private String[] randomParts = null; private Map headers = new HashMap(); public static final String PATTERN_ZOOM = "\\{(?:(\\d+)-)?zoom([+-]\\d+)?\\}"; public static final String PATTERN_X = "\\{x\\}"; public static final String PATTERN_Y = "\\{y\\}"; public static final String PATTERN_Y_YAHOO = "\\{!y\\}"; public static final String PATTERN_NEG_Y = "\\{-y\\}"; public static final String PATTERN_SWITCH = "\\{switch:([^}]+)\\}"; public static final String PATTERN_HEADER = "\\{header\\(([^,]+),([^}]+)\\)\\}"; public static final String[] ALL_PATTERNS = { PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y, PATTERN_SWITCH }; public TemplatedTMSTileSource(String name, String url, int maxZoom) { super(name, url, maxZoom); handleTemplate(); } public TemplatedTMSTileSource(String name, String url, int minZoom, int maxZoom) { super(name, url, minZoom, maxZoom); handleTemplate(); } private void handleTemplate() { // Capturing group pattern on switch values Matcher m = Pattern.compile(".*"+PATTERN_SWITCH+".*").matcher(baseUrl); if (m.matches()) { rand = new Random(); randomParts = m.group(1).split(","); } Pattern pattern = Pattern.compile(PATTERN_HEADER); StringBuffer output = new StringBuffer(); Matcher matcher = pattern.matcher(baseUrl); while (matcher.find()) { headers.put(matcher.group(1),matcher.group(2)); matcher.appendReplacement(output, ""); } matcher.appendTail(output); baseUrl = output.toString(); } public Map getHeaders() { return headers; } @Override public String getTileUrl(int zoom, int tilex, int tiley) { int finalZoom = zoom; Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl); if (m.matches()) { if(m.group(1) != null) { finalZoom = Integer.valueOf(m.group(1))-zoom; } if(m.group(2) != null) { String ofs = m.group(2); if(ofs.startsWith("+")) ofs = ofs.substring(1); finalZoom += Integer.valueOf(ofs); } } String r = this.baseUrl .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom)) .replaceAll(PATTERN_X, Integer.toString(tilex)) .replaceAll(PATTERN_Y, Integer.toString(tiley)) .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int)Math.pow(2, zoom-1)-1-tiley)) .replaceAll(PATTERN_NEG_Y, Integer.toString((int)Math.pow(2, zoom)-1-tiley)); if (rand != null) { r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]); } return r; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java0000644000175000017500000001007612223625014030433 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import java.util.Random; import org.openstreetmap.gui.jmapviewer.OsmMercator; public class ScanexTileSource extends AbstractTMSTileSource { private static String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7"; private enum ScanexLayer { IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"), SPOT("spot", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=F51CE95441284AF6B2FC319B609C7DEC"); private String name; private String uri; ScanexLayer(String name, String uri) { this.name = name; this.uri = uri; } public String getName() { return name; } public String getUri() { return uri; } } /* IRS by default */ private ScanexLayer Layer = ScanexLayer.IRS; public ScanexTileSource(String url) { super("Scanex " + url, "http://maps.kosmosnimki.ru"); for (ScanexLayer layer : ScanexLayer.values()) { if (url.equalsIgnoreCase(layer.getName())) { this.Layer = layer; break; } } } @Override public int getMaxZoom() { return 14; } @Override public String getExtension() { return("jpeg"); } @Override public String getTilePath(int zoom, int tilex, int tiley) { int tmp = (int)Math.pow(2.0, zoom - 1); tilex = tilex - tmp; tiley = tmp - tiley - 1; return this.Layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom; } public TileUpdate getTileUpdate() { return TileUpdate.IfNoneMatch; } private static double RADIUS_E = 6378137; /* radius of Earth at equator, m */ private static double EQUATOR = 40075016.68557849; /* equator length, m */ private static double E = 0.0818191908426; /* eccentricity of Earth's ellipsoid */ @Override public double latToTileY(double lat, int zoom) { double tmp = Math.tan(Math.PI/4 * (1 + lat/90)); double pow = Math.pow(Math.tan(Math.PI/4 + Math.asin(E * Math.sin(Math.toRadians(lat)))/2), E); return (EQUATOR/2 - (RADIUS_E * Math.log(tmp/pow))) * Math.pow(2.0, zoom) / EQUATOR; } @Override public double lonToTileX(double lon, int zoom) { return (RADIUS_E * lon * Math.PI / (90*EQUATOR) + 1) * Math.pow(2.0, zoom - 1); } /* * To solve inverse formula latitude = f(y) we use * Newton's method. We cache previous calculated latitude, * because new one is usually close to the old one. In case * if solution gets out of bounds, we reset to a new random * value. */ private double cached_lat = 0; @Override public double tileYToLat(int y, int zoom) { Random r= new Random(); double lat0, lat; lat = cached_lat; do { lat0 = lat; lat = lat - Math.toDegrees(NextTerm(Math.toRadians(lat), y, zoom)); if (lat > OsmMercator.MAX_LAT || lat < OsmMercator.MIN_LAT) { lat = OsmMercator.MIN_LAT + (double )r.nextInt((int )(OsmMercator.MAX_LAT - OsmMercator.MIN_LAT)); } } while ((Math.abs(lat0 - lat) > 0.000001)); cached_lat = lat; return (lat); } /* Next term in Newton's polynomial */ private double NextTerm(double lat, double y, int zoom) { double sinl=Math.sin(lat); double cosl=Math.cos(lat); double ec, f, df; zoom = (int )Math.pow(2.0, zoom - 1); ec = Math.exp((1 - y/zoom)*Math.PI); f = (Math.tan(Math.PI/4+lat/2) - ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E)); df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) * (Math.sqrt (1 - E * E * sinl * sinl))); return (f/df); } @Override public double tileXToLon(int x, int zoom) { return (x / Math.pow(2.0, zoom - 1) - 1) * (90*EQUATOR) / RADIUS_E / Math.PI; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractMapQuestTileSource.java0000644000175000017500000000510612223625014032433 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import java.awt.Image; import java.io.ByteArrayInputStream; import java.io.IOException; import javax.imageio.ImageIO; import javax.xml.bind.DatatypeConverter; public class AbstractMapQuestTileSource extends AbstractOsmTileSource { // MapQuest logo in base64: http://developer.mapquest.com/content/osm/mq_logo.png private static final String LOGO_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJl"+ "YWR5ccllPAAAAZtJREFUeNpi/P//P0PPcYf/DGSAEssDjIzdx+zJ0gwDLMQqVBWyZVAStGRgBMK33x8wnH62"+ "kngD+DmkGBwUshn42SXA/P8M/xg+/3rDcOPNPuIMMJeKAmv+8OMpw7ffHxikeLUZXBTzgez3DEzEGMDGzAmm"+ "jz5ewLDqWiHE6UwcDHxsYhAXsLPwMFhKxzIIccozPP18ieHhx3MMGsKOYP7td4fBzgUBN+ViBkeFLDD7zbf7"+ "DK++3WFgAMXC448X/uMDV17t+H/r7UEM8VNPl/8Hu0CGTx9s6tXXOxhEuJQYxLnVgK44w/Dzz1cGNWF7BlGg"+ "2KJLqQzCQBcxMbEw/P77g0FTxBkYJs8gXgCFKiMwOLbf6WDQF/djcFUqAvv33fdHYAM4WPjAFrz9/hAeLsef"+ "LALT4EBkhIYlMxMrAxerIJjNCdTExy4OZv/59xNnAKPEAh+bBNAQSMwKcsgAQ5odzBbilGNghcYE1pS4+14f"+ "MKq4GP79/w1OHCC/v/x6Exzv+x9MhbiOEeh3LAZQnBeYGCgEjJRmZ4AAAwCE6rplT3Ba/gAAAABJRU5ErkJg"+ "gg=="; protected static final String MAPQUEST_ATTRIBUTION = "Tiles Courtesy of MapQuest "; protected static final String MAPQUEST_WEBSITE = "http://www.mapquest.com"; private static final int NUMBER_OF_SERVERS = 4; private int SERVER_NUM = 1; public AbstractMapQuestTileSource(String name, String base_url) { super(name, base_url); } @Override public String getBaseUrl() { String url = String.format(this.baseUrl, SERVER_NUM); SERVER_NUM = (SERVER_NUM % NUMBER_OF_SERVERS) + 1; return url; } @Override public TileUpdate getTileUpdate() { return TileUpdate.IfModifiedSince; } @Override public Image getAttributionImage() { try { return ImageIO.read(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(LOGO_BASE64))); } catch (IOException e) { e.printStackTrace(); return null; } } @Override public String getAttributionImageURL() { return MAPQUEST_WEBSITE; } /* (non-Javadoc) * @see org.openstreetmap.gui.jmapviewer.tilesources.AbstractOsmTileSource#getTermsOfUseURL() */ @Override public String getTermsOfUseURL() { return "http://developer.mapquest.com/web/products/open/map#terms"; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java0000644000175000017500000000111712223625014031424 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import org.openstreetmap.gui.jmapviewer.Coordinate; public class MapQuestOsmTileSource extends AbstractMapQuestTileSource { private static final String PATTERN = "http://otile%d.mqcdn.com/tiles/1.0.0/osm"; public MapQuestOsmTileSource() { super("MapQuest-OSM", PATTERN); } @Override public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) { return super.getAttributionText(zoom, topLeft, botRight)+" - "+MAPQUEST_ATTRIBUTION; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java0000644000175000017500000000310712223625014031431 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import java.awt.Image; import org.openstreetmap.gui.jmapviewer.Coordinate; /** * Abstract clas for OSM Tile sources */ public abstract class AbstractOsmTileSource extends AbstractTMSTileSource { /** * The OSM attribution. Must be always in line with http://www.openstreetmap.org/copyright/en */ public static final String DEFAULT_OSM_ATTRIBUTION = "\u00a9 OpenStreetMap contributors"; /** * Constructs a new OSM tile source * @param name Source name as displayed in GUI * @param base_url Source URL */ public AbstractOsmTileSource(String name, String base_url) { super(name, base_url); } public int getMaxZoom() { return 19; } @Override public boolean requiresAttribution() { return true; } @Override public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) { return DEFAULT_OSM_ATTRIBUTION; } @Override public String getAttributionLinkURL() { return "http://openstreetmap.org/"; } @Override public Image getAttributionImage() { return null; } @Override public String getAttributionImageURL() { return null; } @Override public String getTermsOfUseText() { return null; } @Override public String getTermsOfUseURL() { return "http://www.openstreetmap.org/copyright"; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java0000644000175000017500000000134112223625014032704 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; import org.openstreetmap.gui.jmapviewer.Coordinate; public class MapQuestOpenAerialTileSource extends AbstractMapQuestTileSource { private static final String PATTERN = "http://oatile%d.mqcdn.com/tiles/1.0.0/sat"; public MapQuestOpenAerialTileSource() { super("MapQuest Open Aerial", PATTERN); } @Override public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) { return "Portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency - "+MAPQUEST_ATTRIBUTION; } @Override public String getAttributionLinkURL() { return MAPQUEST_WEBSITE; } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java0000644000175000017500000002565712223625014031222 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; //License: GPL. import java.awt.Image; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.JMapViewer; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class BingAerialTileSource extends AbstractTMSTileSource { private static String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU"; private static volatile Future> attributions; // volatile is required for getAttribution(), see below. private static String imageUrlTemplate; private static Integer imageryZoomMax; private static String[] subdomains; private static final Pattern subdomainPattern = Pattern.compile("\\{subdomain\\}"); private static final Pattern quadkeyPattern = Pattern.compile("\\{quadkey\\}"); private static final Pattern culturePattern = Pattern.compile("\\{culture\\}"); public BingAerialTileSource() { super("Bing Aerial Maps", "http://example.com/"); } protected class Attribution { String attribution; int minZoom; int maxZoom; Coordinate min; Coordinate max; } @Override public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { // make sure that attribution is loaded. otherwise subdomains is null. if (getAttribution() == null) throw new IOException("Attribution is not loaded yet"); int t = (zoom + tilex + tiley) % subdomains.length; String subdomain = subdomains[t]; String url = imageUrlTemplate; url = subdomainPattern.matcher(url).replaceAll(subdomain); url = quadkeyPattern.matcher(url).replaceAll(computeQuadTree(zoom, tilex, tiley)); return url; } protected URL getAttributionUrl() throws MalformedURLException { return new URL("http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&output=xml&key=" + API_KEY); } protected List parseAttributionText(InputSource xml) throws IOException { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(xml); XPathFactory xPathFactory = XPathFactory.newInstance(); XPath xpath = xPathFactory.newXPath(); imageUrlTemplate = xpath.compile("//ImageryMetadata/ImageUrl/text()").evaluate(document); imageUrlTemplate = culturePattern.matcher(imageUrlTemplate).replaceAll(Locale.getDefault().toString()); imageryZoomMax = Integer.parseInt(xpath.compile("//ImageryMetadata/ZoomMax/text()").evaluate(document)); NodeList subdomainTxt = (NodeList) xpath.compile("//ImageryMetadata/ImageUrlSubdomains/string/text()").evaluate(document, XPathConstants.NODESET); subdomains = new String[subdomainTxt.getLength()]; for(int i = 0; i < subdomainTxt.getLength(); i++) { subdomains[i] = subdomainTxt.item(i).getNodeValue(); } XPathExpression attributionXpath = xpath.compile("Attribution/text()"); XPathExpression coverageAreaXpath = xpath.compile("CoverageArea"); XPathExpression zoomMinXpath = xpath.compile("ZoomMin/text()"); XPathExpression zoomMaxXpath = xpath.compile("ZoomMax/text()"); XPathExpression southLatXpath = xpath.compile("BoundingBox/SouthLatitude/text()"); XPathExpression westLonXpath = xpath.compile("BoundingBox/WestLongitude/text()"); XPathExpression northLatXpath = xpath.compile("BoundingBox/NorthLatitude/text()"); XPathExpression eastLonXpath = xpath.compile("BoundingBox/EastLongitude/text()"); NodeList imageryProviderNodes = (NodeList) xpath.compile("//ImageryMetadata/ImageryProvider").evaluate(document, XPathConstants.NODESET); List attributions = new ArrayList(imageryProviderNodes.getLength()); for (int i = 0; i < imageryProviderNodes.getLength(); i++) { Node providerNode = imageryProviderNodes.item(i); String attribution = attributionXpath.evaluate(providerNode); NodeList coverageAreaNodes = (NodeList) coverageAreaXpath.evaluate(providerNode, XPathConstants.NODESET); for(int j = 0; j < coverageAreaNodes.getLength(); j++) { Node areaNode = coverageAreaNodes.item(j); Attribution attr = new Attribution(); attr.attribution = attribution; attr.maxZoom = Integer.parseInt(zoomMaxXpath.evaluate(areaNode)); attr.minZoom = Integer.parseInt(zoomMinXpath.evaluate(areaNode)); Double southLat = Double.parseDouble(southLatXpath.evaluate(areaNode)); Double northLat = Double.parseDouble(northLatXpath.evaluate(areaNode)); Double westLon = Double.parseDouble(westLonXpath.evaluate(areaNode)); Double eastLon = Double.parseDouble(eastLonXpath.evaluate(areaNode)); attr.min = new Coordinate(southLat, westLon); attr.max = new Coordinate(northLat, eastLon); attributions.add(attr); } } return attributions; } catch (SAXException e) { System.err.println("Could not parse Bing aerials attribution metadata."); e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (XPathExpressionException e) { e.printStackTrace(); } return null; } @Override public int getMaxZoom() { if(imageryZoomMax != null) return imageryZoomMax; else return 22; } @Override public TileUpdate getTileUpdate() { return TileUpdate.IfNoneMatch; } @Override public boolean requiresAttribution() { return true; } @Override public String getAttributionLinkURL() { //return "http://bing.com/maps" // FIXME: I've set attributionLinkURL temporarily to ToU URL to comply with bing ToU // (the requirement is that we have such a link at the bottom of the window) return "http://go.microsoft.com/?linkid=9710837"; } @Override public Image getAttributionImage() { try { return ImageIO.read(JMapViewer.class.getResourceAsStream("images/bing_maps.png")); } catch (IOException e) { return null; } } @Override public String getAttributionImageURL() { return "http://opengeodata.org/microsoft-imagery-details"; } @Override public String getTermsOfUseText() { return null; } @Override public String getTermsOfUseURL() { return "http://opengeodata.org/microsoft-imagery-details"; } protected Callable> getAttributionLoaderCallable() { return new Callable>() { @Override public List call() throws Exception { int waitTimeSec = 1; while (true) { try { InputSource xml = new InputSource(getAttributionUrl().openStream()); List r = parseAttributionText(xml); System.out.println("Successfully loaded Bing attribution data."); return r; } catch (IOException ex) { System.err.println("Could not connect to Bing API. Will retry in " + waitTimeSec + " seconds."); Thread.sleep(waitTimeSec * 1000L); waitTimeSec *= 2; } } } }; } protected List getAttribution() { if (attributions == null) { // see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html synchronized (BingAerialTileSource.class) { if (attributions == null) { attributions = Executors.newSingleThreadExecutor().submit(getAttributionLoaderCallable()); } } } try { return attributions.get(1000, TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { System.err.println("Bing: attribution data is not yet loaded."); } catch (ExecutionException ex) { throw new RuntimeException(ex.getCause()); } catch (InterruptedException ign) { } return null; } @Override public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) { try { final List data = getAttribution(); if (data == null) return "Error loading Bing attribution data"; StringBuilder a = new StringBuilder(); for (Attribution attr : data) { if (zoom <= attr.maxZoom && zoom >= attr.minZoom) { if (topLeft.getLon() < attr.max.getLon() && botRight.getLon() > attr.min.getLon() && topLeft.getLat() > attr.min.getLat() && botRight.getLat() < attr.max.getLat()) { a.append(attr.attribution); a.append(" "); } } } return a.toString(); } catch (Exception e) { e.printStackTrace(); } return "Error loading Bing attribution data"; } static String computeQuadTree(int zoom, int tilex, int tiley) { StringBuilder k = new StringBuilder(); for (int i = zoom; i > 0; i--) { char digit = 48; int mask = 1 << (i - 1); if ((tilex & mask) != 0) { digit += 1; } if ((tiley & mask) != 0) { digit += 2; } k.append(digit); } return k.toString(); } } jmapviewer-1.02/src/org/openstreetmap/gui/jmapviewer/tilesources/TMSTileSource.java0000644000175000017500000000156712223625014027662 0ustar felixfelixpackage org.openstreetmap.gui.jmapviewer.tilesources; //License: GPL. import java.awt.Image; import org.openstreetmap.gui.jmapviewer.Coordinate; public class TMSTileSource extends AbstractTMSTileSource { protected int maxZoom; protected int minZoom = 0; public TMSTileSource(String name, String url, int maxZoom) { super(name, url); this.maxZoom = maxZoom; } public TMSTileSource(String name, String url, int minZoom, int maxZoom) { super(name, url); this.minZoom = minZoom; this.maxZoom = maxZoom; } @Override public int getMinZoom() { return (minZoom == 0) ? super.getMinZoom() : minZoom; } @Override public int getMaxZoom() { return (maxZoom == 0) ? super.getMaxZoom() : maxZoom; } public TileUpdate getTileUpdate() { return TileUpdate.IfNoneMatch; } } jmapviewer-1.02/Readme.txt0000644000175000017500000000153312223625012014540 0ustar felixfelixJMapViewer (c) 2008 Jan Peter Stotz and others This work bases partly on the JOSM plugin "Slippy Map Chooser" by Tim Haussmann License: GPL FAQ: 1. What is JMapViewer? JMapViewer is a Java Swing component for integrating OSM maps in to your Java application. JMapViewer allows you to set markers on the map or zoom to a specific location on the map. 2. How does JMapViewer work? JMapViewer loads bitmap tiles from the OpenStreetmap tile server (Mapnik renderer). Therefore any application using JMapViewer requires a working Internet connection. 3. How do I use JMapViewer in my application? You can just create an instance of the class org.openstreetmap.gui.jmapviewer.JMapViewer using the default constructor and add it to your panel/frame/windows. For more details please see the Demo class in the same package.