Ignore:
Timestamp:
2009-10-28T23:58:42+01:00 (15 years ago)
Author:
dhansen
Message:

Use JMapViewer code.

Location:
applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java

    r17822 r18354  
    2121import java.util.List;
    2222import java.util.LinkedList;
    23 import java.util.TreeSet;
     23import java.util.HashSet;
    2424
    2525import javax.swing.AbstractAction;
    2626import javax.swing.Icon;
    2727import javax.swing.JMenuItem;
     28import javax.swing.JCheckBoxMenuItem;
    2829import javax.swing.JPopupMenu;
    2930import javax.swing.JSeparator;
     
    4142import org.openstreetmap.josm.tools.ImageProvider;
    4243
     44import org.openstreetmap.gui.jmapviewer.*;
     45import org.openstreetmap.gui.jmapviewer.interfaces.*;
     46import org.openstreetmap.gui.jmapviewer.Tile;
     47
    4348/**
    4449 * Class that displays a slippy map layer.
     
    4954 *
    5055 */
    51 public class SlippyMapLayer extends Layer implements ImageObserver,
    52     PreferenceChangedListener {
     56public class SlippyMapLayer extends Layer implements PreferenceChangedListener, ImageObserver,
     57    TileLoaderListener {
     58    boolean debug = false;
     59    void out(String s)
     60    {
     61        Main.debug(s);
     62    }
     63
     64    protected MemoryTileCache tileCache;
     65    protected TileSource tileSource = new OsmTileSource.Mapnik();
     66    protected TileLoader tileLoader;
     67    JobDispatcher jobDispatcher = JobDispatcher.getInstance();
     68
     69    HashSet<Tile> tileRequestsOutstanding = new HashSet<Tile>();
     70    public synchronized void tileLoadingFinished(Tile tile, boolean success)
     71    {
     72        tile.setLoaded(true);
     73        needRedraw = true;
     74        Main.map.repaint(100);
     75        tileRequestsOutstanding.remove(tile);
     76        if (debug)
     77            out("tileLoadingFinished() tile: " + tile + " success: " + success);
     78    }
     79    public TileCache getTileCache()
     80    {
     81        return tileCache;
     82    }
     83    void clearTileStorage()
     84    {
     85        out("clearing tile storage");
     86        tileCache = new MemoryTileCache();
     87        tileCache.setCacheSize(2000);
     88    }
     89
    5390    /**
    5491     * Actual zoom lvl. Initial zoom lvl is set to
    5592     * {@link SlippyMapPreferences#getMinZoomLvl()}.
    5693     */
    57     public int currentZoomLevel = SlippyMapPreferences.getMinZoomLvl();
    58     private Hashtable<SlippyMapKey, SlippyMapTile> tileStorage = null;
    59 
    60     Point[][] pixelpos = new Point[21][21];
     94    public int currentZoomLevel;
     95
    6196    LatLon lastTopLeft;
    6297    LatLon lastBotRight;
    6398    private Image bufferImage;
    64     private SlippyMapTile clickedTile;
     99    private Tile clickedTile;
    65100    private boolean needRedraw;
    66101    private JPopupMenu tileOptionMenu;
    67 
    68     static void debug(String msg)
    69     {
    70 
    71     }
     102    JCheckBoxMenuItem autoZoomPopup;
     103    Tile showMetadataTile;
     104
     105    void redraw()
     106    {
     107        needRedraw = true;
     108        Main.map.repaint();
     109    }
     110
    72111    @SuppressWarnings("serial")
    73112    public SlippyMapLayer() {
    74113        super(tr("Slippy Map"));
     114
    75115        setBackgroundLayer(true);
    76 
     116        this.setVisible(true);
     117
     118        currentZoomLevel = SlippyMapPreferences.getLastZoom();
     119        if (currentZoomLevel <= 0)
     120            currentZoomLevel = SlippyMapPreferences.getMinZoomLvl();
    77121        clearTileStorage();
     122        //tileLoader = new OsmTileLoader(this);
     123        tileLoader = new OsmFileCacheTileLoader(this);
    78124
    79125        tileOptionMenu = new JPopupMenu();
     126
     127        autoZoomPopup = new JCheckBoxMenuItem();
     128        autoZoomPopup.setAction(new AbstractAction(tr("Auto Zoom")) {
     129            public void actionPerformed(ActionEvent ae) {
     130                boolean new_state = !SlippyMapPreferences.getAutozoom();
     131                SlippyMapPreferences.setAutozoom(new_state);
     132            }
     133        });
     134        autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom());
     135        tileOptionMenu.add(autoZoomPopup);
     136
    80137        tileOptionMenu.add(new JMenuItem(new AbstractAction(tr("Load Tile")) {
    81138            public void actionPerformed(ActionEvent ae) {
    82139                if (clickedTile != null) {
    83                     loadSingleTile(clickedTile);
    84                     needRedraw = true;
    85                     Main.map.repaint();
     140                    loadTile(clickedTile);
     141                    redraw();
    86142                }
    87143            }
     
    89145
    90146        tileOptionMenu.add(new JMenuItem(new AbstractAction(
    91                 tr("Show Tile Status")) {
     147                tr("Show Tile Info")) {
    92148            public void actionPerformed(ActionEvent ae) {
     149                out("info tile: " + clickedTile);
    93150                if (clickedTile != null) {
    94                     clickedTile.loadMetadata();
    95                     needRedraw = true;
    96                     Main.map.repaint();
     151                    showMetadataTile = clickedTile;
     152                    redraw();
    97153                }
    98154            }
     
    103159            public void actionPerformed(ActionEvent ae) {
    104160                if (clickedTile != null) {
    105                     clickedTile.requestUpdate();
    106                     needRedraw = true;
    107                     Main.map.repaint();
     161                    //FIXME//clickedTile.requestUpdate();
     162                    redraw();
    108163                }
    109164            }
     
    114169            public void actionPerformed(ActionEvent ae) {
    115170                loadAllTiles();
    116                 needRedraw = true;
    117                 Main.map.repaint();
     171                redraw();
    118172            }
    119173        }));
     
    124178                    public void actionPerformed(ActionEvent ae) {
    125179                        increaseZoomLevel();
    126                         needRedraw = true;
    127                         Main.map.repaint();
     180                        redraw();
    128181                    }
    129182                }));
     
    141194                    public void actionPerformed(ActionEvent ae) {
    142195                        System.out.print("flushing all tiles...");
    143                         for (SlippyMapTile t : tileStorage.values()) {
    144                             t.dropImage();
    145                         }
     196                        clearTileStorage();
    146197                        System.out.println("done");
    147                         shrinkTileStorage(0);
    148198                    }
    149199                }));
     
    158208                            return;
    159209                        clickedTile = getTileForPixelpos(e.getX(), e.getY());
    160                         tileOptionMenu.show(e.getComponent(), e.getX(), e
    161                                 .getY());
     210                        tileOptionMenu.show(e.getComponent(), e.getX(), e.getY());
    162211                    }
    163212                });
     
    180229    }
    181230
     231    void zoomChanged()
     232    {
     233        if (debug)
     234            out("zoomChanged(): " + currentZoomLevel);
     235        needRedraw = true;
     236        jobDispatcher.cancelOutstandingJobs();
     237        tileRequestsOutstanding.clear();
     238        SlippyMapPreferences.setLastZoom(currentZoomLevel);
     239    }
    182240    /**
    183241     * Zoom in, go closer to map.
     
    188246    {
    189247        boolean zia = currentZoomLevel < SlippyMapPreferences.getMaxZoomLvl();
    190         this.debug("zoomIncreaseAllowed(): " + zia + " " + currentZoomLevel + " vs. " + SlippyMapPreferences.getMaxZoomLvl() );
     248        if (debug)
     249            out("zoomIncreaseAllowed(): " + zia + " " + currentZoomLevel + " vs. " + SlippyMapPreferences.getMaxZoomLvl() );
    191250        return zia;
    192251    }
     
    196255        if (zoomIncreaseAllowed()) {
    197256            currentZoomLevel++;
    198             this.debug("increasing zoom level to: " + currentZoomLevel);
    199             needRedraw = true;
     257            if (debug)
     258                out("increasing zoom level to: " + currentZoomLevel);
     259            zoomChanged();
    200260        } else {
    201261            System.err.println("current zoom lvl ("+currentZoomLevel+") couldnt be increased. "+
     
    219279        lastImageScale = null;
    220280        if (zoomDecreaseAllowed()) {
    221             this.debug("decreasing zoom level to: " + currentZoomLevel);
     281            if (debug)
     282                out("decreasing zoom level to: " + currentZoomLevel);
    222283            currentZoomLevel--;
    223             needRedraw = true;
     284            zoomChanged();
    224285        } else {
    225286            System.err.println("current zoom lvl couldnt be decreased. MinZoomLvl("+minZoom+") reached.");
     
    229290    }
    230291
    231     public void clearTileStorage() {
    232         // when max zoom lvl is begin saved, this method is called and probably
    233         // the setting isnt saved yet.
    234         int maxZoom = SlippyMapPreferences.getMaxZoomLvl();
    235         tileStorage = new Hashtable<SlippyMapKey, SlippyMapTile>();
    236         checkTileStorage();
    237     }
    238 
    239     class TileTimeComp implements Comparator<SlippyMapTile> {
    240             public int compare(SlippyMapTile s1, SlippyMapTile s2) {
    241                     long t1 = s1.access_time();
    242                     long t2 = s2.access_time();
    243                     if (s1 == s2)
    244                             return 0;
    245                     if (t1 == t2) {
    246                             t1 = s1.hashCode();
    247                             t2 = s2.hashCode();
    248                     }
    249                     if (t1 < t2)
    250                             return -1;
    251                     return 1;
    252             }
    253     }
    254 
    255     /**
    256      * <p>
    257      * Check if tiles.size() is not more than maxNrTiles.
    258      * If yes, oldest tiles by timestamp are flushed from
    259      * the cache.
    260      * </p>
     292    synchronized Tile getOrCreateTile(int x, int y, int zoom) {
     293        Tile tile = getTile(x, y, zoom);
     294        if (tile == null) {
     295            tile = new Tile(tileSource, x, y, zoom);
     296            tileCache.addTile(tile);
     297            tile.loadPlaceholderFromCache(tileCache);
     298        }
     299        return tile;
     300    }
     301
     302    /*
     303     * This can and will return null for tiles that are not
     304     * already in the cache.
    261305     */
    262     public void shrinkTileStorage(int maxNrTiles)
    263     {
    264         TreeSet<SlippyMapTile> tiles = new TreeSet<SlippyMapTile>(new TileTimeComp());
    265         tiles.addAll(tileStorage.values());
    266         int nr_to_drop = tiles.size() - maxNrTiles;
    267         if (nr_to_drop <= 0) {
    268             this.debug("total of " + tiles.size() + " loaded tiles, size OK (< " + maxNrTiles + ")");
    269             return;
    270         }
    271         this.debug("total of " + tiles.size() + " tiles, need to flush " + nr_to_drop + " tiles");
    272         for (SlippyMapTile t : tiles) {
    273             if (nr_to_drop <= 0)
    274                 break;
    275             t.dropImage();
    276             nr_to_drop--;
    277             //tileStorage.remove(t.getKey());
    278         }
    279     }
    280     long lastCheck = 0;
    281     public void checkTileStorage() {
    282         long now = System.currentTimeMillis();
    283         if (now - lastCheck < 1000)
    284             return;
    285         lastCheck = now;
    286         shrinkTileStorage(200);
    287     }
    288 
    289     LinkedList<SlippyMapTile> downloadQueue = new LinkedList<SlippyMapTile>();
    290     LinkedList<Image> downloadList = new LinkedList<Image>();
    291     int simultaneousTileDownloads = 5;
    292     int maxQueueSize = 50;
    293     synchronized void markDone(Image i)
    294     {
    295         boolean inList = downloadList.remove(i);
    296         if (!inList) {
    297             Main.debug("ERROR: downloaded image was not queued");
    298             return;
    299         }
    300         //System.out.print("currently downloading: " + downloadList.size() +
    301         //                   " queue size: " + downloadQueue.size() +"    \r");
    302         if (downloadQueue.size() > 0)
    303             loadSingleTile(downloadQueue.getLast());
    304     }
    305     synchronized void loadSingleTile(SlippyMapTile tile)
    306     {
    307         // this moves the tile to the front of the line
    308         if (downloadQueue.contains(tile))
    309             downloadQueue.remove(tile);
    310         downloadQueue.addLast(tile);
    311         // We assume that a queue larger than this is
    312         // too big and the downloads at the end of it
    313         // too old to be relevant.
    314         while (downloadQueue.size() > maxQueueSize)
    315             downloadQueue.removeFirst();
    316         if (downloadList.size() > simultaneousTileDownloads)
    317             return;
    318         //System.out.print("currently downloading: " + downloadList.size() +
    319         //                   " queue size: " + downloadQueue.size() + "    \r");
    320         while (!downloadQueue.isEmpty()) {
    321             // This is a FIFO queue.  The reasoning is
    322             // that we want to draw the most recently
    323             // requested images now.  We may have panned
    324             // or zoomed away
    325             tile = downloadQueue.removeLast();
    326             Image img = tile.loadImage();
    327             if (imageLoaded(img))
    328                 continue;
    329             Toolkit.getDefaultToolkit().prepareImage(img, -1, -1, this);
    330             downloadList.add(img);
    331             break;
    332         }
    333     }
    334 
    335     synchronized SlippyMapTile getTile(int x, int y, int zoom) {
    336         SlippyMapKey key = new SlippyMapKey(x, y, zoom);
    337         if (!key.valid) {
    338             return null;
    339         }
    340         return tileStorage.get(key);
    341     }
    342 
    343     synchronized SlippyMapTile putTile(SlippyMapTile tile, int x, int y, int zoom) {
    344         SlippyMapKey key = new SlippyMapKey(x, y, zoom);
    345         if (!key.valid) {
    346             return null;
    347         }
    348         return tileStorage.put(key, tile);
    349     }
    350 
    351     synchronized SlippyMapTile getOrCreateTile(int x, int y, int zoom) {
    352         SlippyMapTile tile = getTile(x, y, zoom);
    353         if (tile != null) {
    354             return tile;
    355         }
    356         tile = new SlippyMapTile(x, y, zoom);
    357         putTile(tile, x, y, zoom);
     306    synchronized Tile getTile(int x, int y, int zoom) {
     307        int max = (1 << zoom);
     308        if (x < 0 || x >= max || y < 0 || y >= max)
     309                return null;
     310        Tile tile = tileCache.getTile(tileSource, x, y, zoom);
    358311        return tile;
     312    }
     313
     314    synchronized boolean loadTile(Tile tile)
     315    {
     316        if (tile == null)
     317            return false;
     318        if (tile.isLoaded())
     319            return false;
     320        if (tile.isLoading())
     321            return false;
     322        if (tileRequestsOutstanding.contains(tile))
     323            return false;
     324        tileRequestsOutstanding.add(tile);
     325        jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource,
     326                             tile.getXtile(), tile.getYtile(), tile.getZoom()));
     327        return true;
    359328    }
    360329
     
    372341            return;
    373342        }
    374 
    375         for (Tile t : ts.allTiles()) {
    376             SlippyMapTile tile = getOrCreateTile(t.x, t.y, currentZoomLevel);
    377             if (tile.getImage() == null) {
    378                 this.loadSingleTile(tile);
    379             }
    380         }//end of for Tile t
     343        ts.loadAllTiles();
    381344    }
    382345
     
    386349     */
    387350    Image lastScaledImage = null;
     351    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
     352        boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0);
     353        needRedraw = true;
     354        Main.map.repaint(done ? 0 : 100);
     355        return !done;
     356    }
     357    boolean imageLoaded(Image i) {
     358        if (i == null)
     359            return false;
     360        int status = Toolkit.getDefaultToolkit().checkImage(i, -1, -1, this);
     361        if ((status & ALLBITS) != 0)
     362            return true;
     363        return false;
     364    }
     365    Image getLoadedTileImage(Tile tile)
     366    {
     367        if (!tile.isLoaded())
     368            return null;
     369        Image img = tile.getImage();
     370        if (!imageLoaded(img))
     371            return null;
     372        return img;
     373    }
    388374
    389375    double getImageScaling(Image img, Point p0, Point p1) {
     
    425411    }
    426412
    427     boolean imageLoaded(Image i) {
    428         if (i == null)
    429             return false;
    430 
    431         int status = Toolkit.getDefaultToolkit().checkImage(i, -1, -1, this);
    432         if ((status & ALLBITS) != 0)
    433             return true;
    434         return false;
    435     }
    436 
     413    LatLon tileLatLon(Tile t)
     414    {
     415        int zoom = t.getZoom();
     416        return new LatLon(tileYToLat(t.getYtile(), zoom),
     417                          tileXToLon(t.getXtile(), zoom));
     418    }
     419
     420    int paintFromOtherZooms(Graphics g, Tile topLeftTile, Tile botRightTile)
     421    {
     422        LatLon topLeft  = tileLatLon(topLeftTile);
     423        LatLon botRight = tileLatLon(botRightTile);
     424
     425        /*
     426         * Go looking for tiles in zoom levels *other* than the current
     427         * one. Even if they might look bad, they look better than a
     428         * blank tile.
     429         *
     430         * Make darn sure that the tilesCache can either hold all of
     431         * these "fake" tiles or that they don't get inserted in it to
     432         * begin with.
     433         */
     434        //int otherZooms[] = {-5, -4, -3, 2, -2, 1, -1};
     435        int otherZooms[] = { -1, 1, -2, 2, -3, -4, -5};
     436        int painted = 0;;
     437        for (int zoomOff : otherZooms) {
     438            int zoom = currentZoomLevel + zoomOff;
     439            if ((zoom < SlippyMapPreferences.getMinZoomLvl()) ||
     440                (zoom > SlippyMapPreferences.getMaxZoomLvl())) {
     441                continue;
     442            }
     443            TileSet ts = new TileSet(topLeft, botRight, zoom);
     444            int zoom_painted = this.paintTileImages(g, ts, zoom);
     445            if (debug && zoom_painted > 0)
     446                out("painted " + zoom_painted + "/"+ ts.size() +
     447                    " tiles from zoom("+zoomOff+"): " + zoom);
     448            painted += zoom_painted;
     449            if (zoom_painted >= ts.size()) {
     450                if (debug)
     451                    out("broke after drawing " + zoom_painted + "/"+ ts.size() + " at zoomOff: " + zoomOff);
     452                break;
     453            }
     454        }
     455        /*
     456         * Save this for last since it will get painted over all the others
     457         */
     458        return painted;
     459    }
     460    // This function is called for several zoom levels, not just
     461    // the current one.  It should not trigger any tiles to be
     462    // downloaded.  It should also avoid polluting the tile cache
     463    // with any tiles since these tiles are not mandatory.
    437464    Double lastImageScale = null;
    438465    int paintTileImages(Graphics g, TileSet ts, int zoom) {
    439466        int paintedTiles = 0;
    440467        boolean imageScaleRecorded = false;
    441         Image img = null;
    442         for (Tile t : ts.allTiles()) {
    443             SlippyMapTile tile = getTile(t.x, t.y, zoom);
    444             if (tile == null) {
    445                 // Don't trigger tile loading if this isn't
    446                 // the exact zoom level we're looking for
    447                 if (zoom != currentZoomLevel)
    448                     continue;
    449                 tile = getOrCreateTile(t.x, t.y, zoom);
    450                 if (SlippyMapPreferences.getAutoloadTiles())
    451                     loadSingleTile(tile);
    452             }
    453             img = tile.getImage();
    454             if (img == null)
    455                 continue;
    456             if ((zoom != currentZoomLevel) && !tile.isDownloaded())
    457                 continue;
    458             Point p = t.pixelPos(zoom);
     468        for (Tile tile : ts.allTiles()) {
    459469            /*
    460470             * We need to get a box in which to draw, so advance by one tile in
    461              * each direction to find the other corner of the box
     471             * each direction to find the other corner of the box.
     472             * Note: this somewhat pollutes the tile cache
    462473             */
    463             Tile t2 = new Tile(t.x + 1, t.y + 1);
    464             Point p2 = t2.pixelPos(zoom);
    465             if (imageLoaded(img)) {
    466                 g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this);
    467                 paintedTiles++;
    468             }
    469             if (img == null)
     474            Tile t2 = getOrCreateTile(tile.getXtile() + 1, tile.getYtile() + 1, zoom);
     475            Image img = getLoadedTileImage(tile);
     476            Point p = pixelPos(tile);
     477            Point p2 = pixelPos(t2);
     478            if (currentZoomLevel == zoom && img == null) {
     479                int painted = paintFromOtherZooms(g, tile, t2);
     480                if (painted > 0 && debug)
     481                    out("painted a total of " + painted);
    470482                continue;
     483            }
     484            g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this);
     485            paintedTiles++;
    471486            if (!imageScaleRecorded && zoom == currentZoomLevel) {
    472487                lastImageScale = new Double(getImageScaling(img, p, p2));
     
    483498    }
    484499
    485     void paintTileText(TileSet ts, Graphics g, MapView mv, int zoom, Tile t) {
     500    void paintTileText(TileSet ts, Tile tile, Graphics g, MapView mv, int zoom, Tile t) {
    486501        int fontHeight = g.getFontMetrics().getHeight();
    487 
    488         SlippyMapTile tile = getTile(t.x, t.y, zoom);
    489         if (tile == null) {
     502        if (tile == null)
    490503            return;
    491         }
    492         if (tile.getImage() == null) {
    493             loadSingleTile(tile);
    494         }
    495         Point p = t.pixelPos(zoom);
     504        Point p = pixelPos(t);
    496505        int texty = p.y + 2 + fontHeight;
    497506
    498507        if (SlippyMapPreferences.getDrawDebug()) {
    499             g.drawString("x=" + t.x + " y=" + t.y + " z=" + zoom + "", p.x + 2, texty);
     508            g.drawString("x=" + t.getXtile() + " y=" + t.getYtile() + " z=" + zoom + "", p.x + 2, texty);
    500509            texty += 1 + fontHeight;
    501             if ((t.x % 32 == 0) && (t.y % 32 == 0)) {
    502                 g.drawString("x=" + t.x / 32 + " y=" + t.y / 32 + " z=7", p.x + 2, texty);
     510            if ((t.getXtile() % 32 == 0) && (t.getYtile() % 32 == 0)) {
     511                g.drawString("x=" + t.getXtile() / 32 + " y=" + t.getYtile() / 32 + " z=7", p.x + 2, texty);
    503512                texty += 1 + fontHeight;
    504513            }
    505514        }// end of if draw debug
    506515
    507         String md = tile.getMetadata();
    508         if (md != null) {
    509             g.drawString(md, p.x + 2, texty);
    510             texty += 1 + fontHeight;
     516        if (tile == showMetadataTile) {
     517            String md = tile.toString();
     518            if (md != null) {
     519                g.drawString(md, p.x + 2, texty);
     520                texty += 1 + fontHeight;
     521            }
    511522        }
    512523
    513524        String tileStatus = tile.getStatus();
    514         Image tileImage = tile.getImage();
    515         if (!imageLoaded(tileImage)) {
     525        if (!tile.isLoaded()) {
    516526            g.drawString(tr("image " + tileStatus), p.x + 2, texty);
    517527            texty += 1 + fontHeight;
     
    521531        we don't need to poll like this
    522532        */
    523         if (!imageLoaded(tileImage)) {
    524             needRedraw = true;
    525             Main.map.repaint(100);
    526         }
     533        if (!tile.isLoaded())
     534            redraw();
    527535
    528536        if (SlippyMapPreferences.getDrawDebug()) {
    529537            if (ts.leftTile(t)) {
    530                 if (t.y % 32 == 31) {
     538                if (t.getYtile() % 32 == 31) {
    531539                    g.fillRect(0, p.y - 1, mv.getWidth(), 3);
    532540                } else {
     
    537545    }
    538546
    539     private class Tile {
    540         public int x;
    541         public int y;
    542 
    543         Tile(int x, int y) {
    544             this.x = x;
    545             this.y = y;
    546         }
    547 
    548         public Point pixelPos(int zoom) {
    549             double lon = tileXToLon(this.x, zoom);
    550             LatLon tmpLL = new LatLon(tileYToLat(this.y, zoom), lon);
     547    public Point pixelPos(Tile t) {
     548            double lon = tileXToLon(t.getXtile(), t.getZoom());
     549            LatLon tmpLL = new LatLon(tileYToLat(t.getYtile(), t.getZoom()), lon);
    551550            MapView mv = Main.map.mapView;
    552551            return mv.getPoint(tmpLL);
    553552        }
    554     }
    555553    private class TileSet {
    556554        int z12x0, z12x1, z12y0, z12y1;
     
    581579        }
    582580        double tilesSpanned() {
    583             int x_span = z12x1 - z12x0;
    584             int y_span = z12y1 - z12y0;
    585             return Math.sqrt(1.0 * x_span * y_span);
     581            return Math.sqrt(1.0 * this.size());
     582        }
     583
     584        int size() {
     585            int x_span = z12x1 - z12x0 + 1;
     586            int y_span = z12y1 - z12y0 + 1;
     587            return x_span * y_span;
    586588        }
    587589
    588590        /*
    589          * This is pretty silly. Should probably just be implemented as an
    590          * iterator to keep from having to instantiate all these tiles.
     591         * Get all tiles represented by this TileSet that are
     592         * already in the tileCache.
    591593         */
    592594        List<Tile> allTiles()
     595        {
     596            return this.allTiles(false);
     597        }
     598        private List<Tile> allTiles(boolean create)
    593599        {
    594600            List<Tile> ret = new ArrayList<Tile>();
    595601            for (int x = z12x0; x <= z12x1; x++) {
    596602                for (int y = z12y0; y <= z12y1; y++) {
    597                     Tile t = new Tile(x % tileMax, y % tileMax);
    598                     ret.add(t);
     603                    Tile t;
     604                    if (create)
     605                        t = getOrCreateTile(x % tileMax, y % tileMax, zoom);
     606                    else
     607                        t = getTile(x % tileMax, y % tileMax, zoom);
     608                    if (t != null)
     609                        ret.add(t);
    599610                }
    600611            }
    601612            return ret;
    602613        }
    603 
     614        void loadAllTiles()
     615        {
     616            List<Tile> tiles = this.allTiles(true);
     617            int nr_queued = 0;
     618            for (Tile t : tiles) {
     619                if (loadTile(t))
     620                    nr_queued++;
     621            }
     622            if (debug)
     623                if (nr_queued > 0)
     624                    out("queued to load: " + nr_queued + "/" + tiles.size() + " tiles at zoom: " + zoom);
     625        }
    604626        boolean topTile(Tile t) {
    605             if (t.y == z12y0 )
     627            if (t.getYtile() == z12y0 )
    606628                return true;
    607629            return false;
     
    609631
    610632        boolean leftTile(Tile t) {
    611             if (t.x == z12x0 )
     633            if (t.getXtile() == z12x0 )
    612634                return true;
    613635            return false;
     
    615637    }
    616638
     639    boolean autoZoomEnabled()
     640    {
     641        return autoZoomPopup.isSelected();
     642    }
    617643    /**
    618644     */
     
    634660                && !needRedraw) {
    635661
    636             this.debug("drawing buffered image");
     662            if (debug)
     663                out("drawing buffered image");
    637664            g.drawImage(bufferImage, 0, 0, null);
    638665            return;
     
    645672        g = bufferImage.getGraphics();
    646673
    647         TileSet ts = new TileSet(topLeft, botRight, currentZoomLevel);
    648674        int zoom = currentZoomLevel;
    649 
    650         if (zoomDecreaseAllowed() && (ts.tilesSpanned() > 18)) {
    651             this.debug("too many tiles, decreasing zoom from " + currentZoomLevel);
    652             if (decreaseZoomLevel())
    653                 this.paint(oldg, mv);
     675        TileSet ts = new TileSet(topLeft, botRight, zoom);
     676
     677        if (autoZoomEnabled()) {
     678            if (zoomDecreaseAllowed() && (ts.tilesSpanned() > 18)) {
     679                if (debug)
     680                    out("too many tiles, decreasing zoom from " + currentZoomLevel);
     681                if (decreaseZoomLevel())
     682                    this.paint(oldg, mv);
     683                return;
     684            }
     685            if (zoomIncreaseAllowed() && (ts.tilesSpanned() < 1.0)) {
     686                if (debug)
     687                    out("doesn't even cover one tile (" + ts.tilesSpanned()
     688                        + "), increasing zoom from " + currentZoomLevel);
     689                if (increaseZoomLevel())
     690                     this.paint(oldg, mv);
     691                return;
     692            }
     693        }
     694
     695        // Too many tiles... refuse to draw
     696        if (ts.tilesSpanned() > 18)
    654697            return;
    655         }
    656         if (zoomIncreaseAllowed() && (ts.tilesSpanned() < 1.0)) {
    657             this.debug("doesn't even cover one tile (" + ts.tilesSpanned()
    658                        + "), increasing zoom from " + currentZoomLevel);
    659             if (increaseZoomLevel())
    660                  this.paint(oldg, mv);
    661             return;
    662         }
    663 
    664         if (ts.tilesSpanned() <= 0) {
    665             System.out.println("doesn't even cover one tile, increasing zoom from " + currentZoomLevel);
    666             if (increaseZoomLevel()) {
    667                 this.paint(oldg, mv);
    668             }
    669             return;
    670         }
     698
     699        ts.loadAllTiles();
    671700
    672701        int fontHeight = g.getFontMetrics().getHeight();
     
    674703        g.setColor(Color.DARK_GRAY);
    675704
    676         /*
    677          * Go looking for tiles in zoom levels *other* than the current
    678          * one. Even if they might look bad, they look better than a
    679          * blank tile.
    680          */
    681         int otherZooms[] = {-5, -4, -3, 2, -2, 1, -1};
    682         for (int zoomOff : otherZooms) {
    683             int zoom2 = currentZoomLevel + zoomOff;
    684             if ((zoom2 < SlippyMapPreferences.getMinZoomLvl()) ||
    685                 (zoom2 > SlippyMapPreferences.getMaxZoomLvl())) {
    686                 continue;
    687             }
    688             TileSet ts2 = new TileSet(topLeft, botRight, zoom2);
    689             int painted = this.paintTileImages(g, ts2, zoom2);
    690             //if (painted > 0)
    691             //    System.out.println("painted " + painted + " tiles from zoom: " + zoom2);
    692         }
    693         /*
    694          * Save this for last since it will get painted over all the others
    695          */
    696705        this.paintTileImages(g, ts, currentZoomLevel);
    697706        g.setColor(Color.red);
    698707
     708        // The current zoom tileset is guaranteed to have all of
     709        // its tiles
    699710        for (Tile t : ts.allTiles()) {
    700711            // This draws the vertical lines for the entire
     
    702713            // the column.
    703714            if (ts.topTile(t)) {
    704                 Point p = t.pixelPos(currentZoomLevel);
     715                Point p = pixelPos(t);
    705716                if (SlippyMapPreferences.getDrawDebug()) {
    706                     if (t.x % 32 == 0) {
     717                    if (t.getXtile() % 32 == 0) {
    707718                        // level 7 tile boundary
    708719                        g.fillRect(p.x - 1, 0, 3, mv.getHeight());
     
    712723                }
    713724            }
    714             this.paintTileText(ts, g, mv, currentZoomLevel, t);
     725            this.paintTileText(ts, t, g, mv, currentZoomLevel, t);
    715726        }
    716727        float fadeBackground = SlippyMapPreferences.getFadeBackground();
     
    721732            // drawn pixels, zoom in... getting too pixelated
    722733            if (lastImageScale > 3 && zoomIncreaseAllowed()) {
    723                 if (SlippyMapPreferences.getAutozoom()) {
    724                     this.debug("autozoom increase: scale: " + lastImageScale);
     734                if (autoZoomEnabled()) {
     735                    if (debug)
     736                        out("autozoom increase: scale: " + lastImageScale);
    725737                    increaseZoomLevel();
    726738                }
     
    729741            // of a drawn pixels, zoom out.
    730742            } else if ((lastImageScale < 0.45) && (lastImageScale > 0) && zoomDecreaseAllowed()) {
    731                 if (SlippyMapPreferences.getAutozoom()) {
    732                     this.debug("autozoom decrease: scale: " + lastImageScale);
     743                if (autoZoomEnabled()) {
     744                    if (debug)
     745                        out("autozoom decrease: scale: " + lastImageScale);
    733746                    decreaseZoomLevel();
    734747                }
     
    744757     * user right-clicks on the map.
    745758     */
    746     SlippyMapTile getTileForPixelpos(int px, int py) {
     759    Tile getTileForPixelpos(int px, int py) {
     760        if (debug)
     761            out("getTileForPixelpos("+px+", "+py+")");
    747762        MapView mv = Main.map.mapView;
    748763        Point clicked = new Point(px, py);
    749764        LatLon topLeft = mv.getLatLon(0, 0);
    750765        LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight());
    751         TileSet ts = new TileSet(topLeft, botRight, currentZoomLevel);
    752766        int z = currentZoomLevel;
    753 
     767        TileSet ts = new TileSet(topLeft, botRight, z);
     768
     769        ts.loadAllTiles(); // make sure there are tile objects for all tiles
    754770        Tile clickedTile = null;
    755771        Point p1 = null, p2 = null;
    756772        for (Tile t1 : ts.allTiles()) {
    757             Tile t2 = new Tile(t1.x+1, t1.y+1);
    758             p1 = t1.pixelPos(z);
    759             p2 = t2.pixelPos(z);
    760             Rectangle r = new Rectangle(p1,new Dimension(p2.x, p2.y));
     773            Tile t2 = getOrCreateTile(t1.getXtile()+1, t1.getYtile()+1, z);
     774            Rectangle r = new Rectangle(pixelPos(t1));
     775            r.add(pixelPos(t2));
     776            if (debug)
     777                out("r: " + r + " clicked: " + clicked);
    761778            if (!r.contains(clicked))
    762779                continue;
     
    766783        if (clickedTile == null)
    767784             return null;
    768         System.out.println("clicked on tile: " + clickedTile.x + " " + clickedTile.y +
     785        System.out.println("clicked on tile: " + clickedTile.getXtile() + " " + clickedTile.getYtile() +
    769786                           " scale: " + lastImageScale + " currentZoomLevel: " + currentZoomLevel);
    770         SlippyMapTile tile = getOrCreateTile(clickedTile.x, clickedTile.y, currentZoomLevel);
    771         checkTileStorage();
    772         return tile;
     787        return clickedTile;
    773788    }
    774789
     
    833848    }
    834849
    835     private SlippyMapTile imgToTile(Image img) {
    836         // we use the enumeration to avoid ConcurrentUpdateExceptions
    837         // with other users of the tileStorage
    838         Enumeration<SlippyMapTile> e = tileStorage.elements();
    839         while (e.hasMoreElements()) {
    840             SlippyMapTile t = e.nextElement();
    841             if (t.getImageNoTimestamp() != img) {
    842                 continue;
    843             }
    844             return t;
    845         }
    846         return null;
    847     }
    848 
    849850    private static int nr_loaded = 0;
    850851    private static int at_zoom = -1;
    851 
    852     public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
    853         boolean error = (infoflags & ERROR) != 0;
    854         boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0);
    855         boolean success = ((infoflags & (ALLBITS)) != 0);
    856         SlippyMapTile imageTile = imgToTile(img);
    857         if (success || error) {
    858             this.debug("tile done loading: " + imageTile);
    859             markDone(img);
    860         }
    861         if (imageTile == null) {
    862             System.err.println("no tile for image");
    863             return false;
    864         }
    865 
    866         if ((infoflags & ERROR) != 0) {
    867             String url; // = "unknown";
    868             url = imageTile.getImageURL().toString();
    869             System.err.println("imageUpdate(" + img + ") error " + url + ")");
    870         }
    871         if (((infoflags & ALLBITS) != 0)) {
    872             int z = imageTile.getZoom();
    873             if (z == at_zoom) {
    874                 nr_loaded++;
    875             } else {
    876                 //System.out.println("downloaded " + nr_loaded + " at: " + at_zoom + " now going to " + z +
    877                 //                " class: " + img.getClass());
    878                 nr_loaded = 0;
    879                 at_zoom = z;
    880             }
    881         }
    882         if ((infoflags & SOMEBITS) != 0) {
    883             // if (y%100 == 0)
    884             //System.out.println("imageUpdate("+img+") SOMEBITS ("+x+","+y+")");
    885         }
    886         // Repaint immediately if we are done, otherwise batch up
    887         // repaint requests every 100 milliseconds
    888         needRedraw = true;
    889         Main.map.repaint(done ? 0 : 100);
    890         return !done;
    891     }
    892852
    893853    /*
     
    904864            // TODO move this code to SlippyMapPreferences class.
    905865            if (!key.equals(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND)) {
    906                 clearTileStorage();
    907             }
     866                autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom());
     867            }
     868            redraw();
    908869        }
    909870    }
  • applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java

    r17433 r18354  
    1919    public static final String PREFERENCE_MIN_ZOOM_LVL = PREFERENCE_PREFIX + ".min_zoom_lvl";
    2020    public static final String PREFERENCE_MAX_ZOOM_LVL = PREFERENCE_PREFIX + ".max_zoom_lvl";
     21    public static final String PREFERENCE_LAST_ZOOM = PREFERENCE_PREFIX + ".last_zoom_lvl";
    2122    public static final String PREFERENCE_FADE_BACKGROUND = PREFERENCE_PREFIX + ".fade_background";
    2223    public static final String PREFERENCE_DRAW_DEBUG = PREFERENCE_PREFIX + ".draw_debug";
     
    6061    }
    6162   
     63    public static void setLastZoom(int zoom) {
     64        Main.pref.put(SlippyMapPreferences.PREFERENCE_LAST_ZOOM, ""+zoom);
     65    }
     66    public static int getLastZoom() {
     67        int ret = -1;
     68        String pref = Main.pref.get(SlippyMapPreferences.PREFERENCE_LAST_ZOOM);
     69        try {
     70            ret = Integer.parseInt(pref);
     71        } catch (NumberFormatException e) {
     72        }
     73        return ret;
     74    }
     75
    6276    public static boolean getDrawDebug()
    6377    {
  • applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapTile.java

    r16460 r18354  
    1 package org.openstreetmap.josm.plugins.slippymap;
    2 
    3 import static org.openstreetmap.josm.tools.I18n.tr;
    4 
    5 import java.awt.Image;
    6 import java.awt.Toolkit;
    7 import java.awt.image.ImageObserver;
    8 import java.io.BufferedReader;
    9 import java.io.InputStreamReader;
    10 import java.net.MalformedURLException;
    11 import java.net.URL;
    12 import java.net.URLConnection;
    13 
    14 /**
    15  * Class that contains information about one single slippy map tile.
    16  *
    17  * @author Frederik Ramm <frederik@remote.org>
    18  * @author LuVar <lubomir.varga@freemap.sk>
    19  * @author Dave Hansen <dave@sr71.net>
    20  *
    21  */
    22 public class SlippyMapTile implements ImageObserver
    23 {
    24     private Image  tileImage;
    25         private long timestamp;
    26 
    27         private int x;
    28         private int y;
    29         private int z;
    30         // Setting this to pending is a bit of a hack
    31         // as it requires knowledge that SlippyMapLayer
    32         // will put this tile in a queue before it calls
    33         // loadImage().  But, this gives the best message
    34         // to the user.
    35         private String status = "pending download";
    36    
    37     private boolean imageDownloaded = false;
    38 
    39     private String metadata;
    40 
    41     public SlippyMapTile(int x, int y, int z)
    42     {
    43         this.x = x;
    44         this.y = y;
    45         this.z = z;
    46                 timestamp = System.currentTimeMillis();
    47     }
    48 
    49     public String getStatus()
    50     {
    51         return status;
    52     }
    53     public String getMetadata()
    54     {
    55         return metadata;
    56     }
    57 
    58     public URL getImageURL()
    59     {
    60         try
    61         {
    62             return new URL(SlippyMapPreferences.getMapUrl() + "/" + z + "/" + x + "/" + y + ".png");
    63         }
    64         catch (MalformedURLException mfu)
    65         {
    66             mfu.printStackTrace();
    67         }
    68             return null;
    69         }
    70 
    71     public Image loadImage()
    72     {
    73                 // We do not update the timestamp in this function
    74                 // The download code prioritizes the most recent
    75                 // downloads and will download the oldest tiles last.
    76         URL imageURL = this.getImageURL();
    77         tileImage = Toolkit.getDefaultToolkit().createImage(imageURL);
    78         Toolkit.getDefaultToolkit().prepareImage(tileImage, -1, -1, this);
    79                 Toolkit.getDefaultToolkit().sync();
    80                 status = "being downloaded";
    81                 return tileImage;
    82     }
    83         public String toString()
    84         {
    85                         return "SlippyMapTile{zoom=" + z + " (" + x + "," + y + ") '" + status + "'}";
    86         }
    87         synchronized public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
    88         {
    89                 if ((infoflags & ALLBITS) != 0) {
    90             imageDownloaded = true;
    91                 status = "downloaded";
    92                         if (tileImage == null) {
    93                 System.out.println("completed null'd image: " + this.toString());
    94                         }
    95                         tileImage = img;
    96                         return false;
    97         }
    98                 return true;
    99         }
    100 
    101     public Image getImageNoTimestamp() {
    102         return tileImage;
    103     }
    104    
    105     public Image getImage()
    106     {
    107         timestamp = System.currentTimeMillis();
    108         return tileImage;
    109     }
    110 
    111     public int getZoom() {
    112         return z;
    113     }
    114    
    115     synchronized public void dropImage()
    116     {
    117                 if(tileImage != null) {
    118                         tileImage.flush();
    119                     status = "dropped";
    120                 }
    121                 tileImage = null;
    122                 //  This should work in theory but doesn't seem to actually
    123                 //  reduce the X server memory usage
    124                 //tileImage.flush();
    125             imageDownloaded = false;
    126     }
    127    
    128     public boolean isDownloaded() {
    129         return imageDownloaded;
    130     }
    131    
    132     public void loadMetadata()
    133     {
    134         try
    135         {
    136             URL dev = new URL(
    137                     "http://tah.openstreetmap.org/Tiles/info_short.php?x=" + x
    138                             + "&y=" + y + "&z=" + z + "/layer=tile");
    139             URLConnection devc = dev.openConnection();
    140             BufferedReader in = new BufferedReader(new InputStreamReader(devc
    141                     .getInputStream()));
    142             metadata = tr(in.readLine());
    143         }
    144         catch (Exception ex)
    145         {
    146             metadata = tr("error loading metadata" + ex.toString());
    147         }
    148 
    149     }
    150 
    151     public void requestUpdate()
    152     {
    153                 if (z != 12) {
    154             metadata = tr("error requesting update: not zoom-level 12");
    155                 }
    156         try
    157         {
    158             URL dev = new URL("http://tah.openstreetmap.org/Request/create/?x=" + x
    159                     + "&y=" + y + "&priority=1&src=slippymap_plugin");
    160             URLConnection devc = dev.openConnection();
    161             BufferedReader in = new BufferedReader(new InputStreamReader(devc
    162                     .getInputStream()));
    163                         timestamp = System.currentTimeMillis();
    164             metadata = tr("requested: {0}", tr(in.readLine()));
    165         }
    166         catch (Exception ex)
    167         {
    168             metadata = tr("error requesting update");
    169         }
    170     }
    171 
    172     public long access_time()
    173     {
    174         return timestamp;
    175     }
    176 
    177     public boolean equals(Object o)
    178     {
    179         if (!(o instanceof SlippyMapTile))
    180             return false;
    181         SlippyMapTile other = (SlippyMapTile) o;
    182         return (this.x == other.x && this.y == other.y && this.z == other.z);
    183     }
    184     SlippyMapKey getKey()
    185     {
    186             return new SlippyMapKey(x, y, z);
    187     }
    188 }
Note: See TracChangeset for help on using the changeset viewer.