Changeset 4745 in josm


Ignore:
Timestamp:
29.12.2011 18:07:04 (5 months ago)
Author:
jttt
Message:

Add precache wms tiles action to gpx layers (it will download wms tiles along track to cache for faster work afterwards)

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/.classpath

    r4728 r4745  
    2222        <classpathentry kind="lib" path="test/lib/unitils-core/ognl-2.6.9.jar"/> 
    2323        <classpathentry kind="lib" path="test/lib/unitils-core/unitils-core-3.1.jar"/> 
     24        <classpathentry kind="lib" path="test/lib/fest/debug-1.0.jar"/> 
    2425        <classpathentry kind="output" path="bin"/> 
    2526</classpath> 
  • trunk/src/org/openstreetmap/josm/data/imagery/WmsCache.java

    r4186 r4745  
    6262        final double north; 
    6363        final ProjectionBounds bounds; 
     64        final String filename; 
    6465 
    6566        long lastUsed; 
    6667        long lastModified; 
    67         String filename; 
    68  
    69         CacheEntry(double pixelPerDegree, double east, double north, int tileSize) { 
     68 
     69        CacheEntry(double pixelPerDegree, double east, double north, int tileSize, String filename) { 
    7070            this.pixelPerDegree = pixelPerDegree; 
    7171            this.east = east; 
    7272            this.north = north; 
    7373            this.bounds = new ProjectionBounds(east, north, east + tileSize / pixelPerDegree, north + tileSize / pixelPerDegree); 
     74            this.filename = filename; 
    7475        } 
    7576    } 
     
    201202                ProjectionEntries projection = getProjectionEntries(projectionType.getName(), projectionType.getCacheDirectory()); 
    202203                for (EntryType entry: projectionType.getEntry()) { 
    203                     CacheEntry ce = new CacheEntry(entry.getPixelPerDegree(), entry.getEast(), entry.getNorth(), tileSize); 
     204                    CacheEntry ce = new CacheEntry(entry.getPixelPerDegree(), entry.getEast(), entry.getNorth(), tileSize, entry.getFilename()); 
    204205                    ce.lastUsed = entry.getLastUsed().getTimeInMillis(); 
    205                     ce.filename = entry.getFilename(); 
    206206                    ce.lastModified = entry.getLastModified().getTimeInMillis(); 
    207207                    projection.entries.add(ce); 
     
    315315    } 
    316316 
     317 
    317318    private BufferedImage loadImage(ProjectionEntries projectionEntries, CacheEntry entry) throws IOException { 
    318         entry.lastUsed = System.currentTimeMillis(); 
    319  
    320         SoftReference<BufferedImage> memCache = memoryCache.get(entry); 
    321         if (memCache != null) { 
    322             BufferedImage result = memCache.get(); 
    323             if (result != null) 
     319 
     320        synchronized (this) { 
     321            entry.lastUsed = System.currentTimeMillis(); 
     322 
     323            SoftReference<BufferedImage> memCache = memoryCache.get(entry); 
     324            if (memCache != null) { 
     325                BufferedImage result = memCache.get(); 
     326                if (result != null) 
     327                    return result; 
     328            } 
     329        } 
     330 
     331        try { 
     332            // Reading can't be in synchronized section, it's too slow 
     333            BufferedImage result = ImageIO.read(getImageFile(projectionEntries, entry)); 
     334            synchronized (this) { 
     335                if (result == null) { 
     336                    projectionEntries.entries.remove(entry); 
     337                    totalFileSizeDirty = true; 
     338                } 
    324339                return result; 
    325         } 
    326  
    327         try { 
    328             BufferedImage result = ImageIO.read(getImageFile(projectionEntries, entry)); 
    329             if (result == null) { 
     340            } 
     341        } catch (IOException e) { 
     342            synchronized (this) { 
    330343                projectionEntries.entries.remove(entry); 
    331344                totalFileSizeDirty = true; 
    332             } 
    333             return result; 
    334         } catch (IOException e) { 
    335             projectionEntries.entries.remove(entry); 
    336             totalFileSizeDirty = true; 
    337             throw e; 
     345                throw e; 
     346            } 
    338347        } 
    339348    } 
     
    347356    } 
    348357 
    349     public synchronized BufferedImage getExactMatch(Projection projection, double pixelPerDegree, double east, double north) { 
     358    public synchronized boolean hasExactMatch(Projection projection, double pixelPerDegree, double east, double north) { 
    350359        ProjectionEntries projectionEntries = getProjectionEntries(projection); 
    351360        CacheEntry entry = findEntry(projectionEntries, pixelPerDegree, east, north); 
     361        return (entry != null); 
     362    } 
     363 
     364    public BufferedImage getExactMatch(Projection projection, double pixelPerDegree, double east, double north) { 
     365        CacheEntry entry = null; 
     366        ProjectionEntries projectionEntries = null; 
     367        synchronized (this) { 
     368            projectionEntries = getProjectionEntries(projection); 
     369            entry = findEntry(projectionEntries, pixelPerDegree, east, north); 
     370        } 
    352371        if (entry != null) { 
    353372            try { 
    354                 entry.lastUsed = System.currentTimeMillis(); 
    355373                return loadImage(projectionEntries, entry); 
    356374            } catch (IOException e) { 
     
    363381    } 
    364382 
    365     public synchronized BufferedImage getPartialMatch(Projection projection, double pixelPerDegree, double east, double north) { 
    366         List<CacheEntry> matches = new ArrayList<WmsCache.CacheEntry>(); 
    367  
    368         double minPPD = pixelPerDegree / 5; 
    369         double maxPPD = pixelPerDegree * 5; 
    370         ProjectionEntries projectionEntries = getProjectionEntries(projection); 
    371  
    372         ProjectionBounds bounds = new ProjectionBounds(east, north, 
    373                 east + tileSize / pixelPerDegree, north + tileSize / pixelPerDegree); 
    374  
    375         //TODO Do not load tile if it is completely overlapped by other tile with better ppd 
    376         for (CacheEntry entry: projectionEntries.entries) { 
    377             if (entry.pixelPerDegree >= minPPD && entry.pixelPerDegree <= maxPPD && entry.bounds.intersects(bounds)) { 
    378                 entry.lastUsed = System.currentTimeMillis(); 
    379                 matches.add(entry); 
    380             } 
    381         } 
    382  
    383         if (matches.isEmpty()) 
    384             return null; 
    385  
    386  
    387         Collections.sort(matches, new Comparator<CacheEntry>() { 
    388             @Override 
    389             public int compare(CacheEntry o1, CacheEntry o2) { 
    390                 return Double.compare(o2.pixelPerDegree, o1.pixelPerDegree); 
    391             } 
    392         }); 
     383    public  BufferedImage getPartialMatch(Projection projection, double pixelPerDegree, double east, double north) { 
     384        ProjectionEntries projectionEntries; 
     385        List<CacheEntry> matches; 
     386        synchronized (this) { 
     387            matches = new ArrayList<WmsCache.CacheEntry>(); 
     388 
     389            double minPPD = pixelPerDegree / 5; 
     390            double maxPPD = pixelPerDegree * 5; 
     391            projectionEntries = getProjectionEntries(projection); 
     392 
     393            double size2 = tileSize / pixelPerDegree; 
     394            double border = tileSize * 0.01; // Make sure not to load neighboring tiles that intersects this tile only slightly 
     395            ProjectionBounds bounds = new ProjectionBounds(east + border, north + border, 
     396                    east + size2 - border, north + size2 - border); 
     397 
     398            //TODO Do not load tile if it is completely overlapped by other tile with better ppd 
     399            for (CacheEntry entry: projectionEntries.entries) { 
     400                if (entry.pixelPerDegree >= minPPD && entry.pixelPerDegree <= maxPPD && entry.bounds.intersects(bounds)) { 
     401                    entry.lastUsed = System.currentTimeMillis(); 
     402                    matches.add(entry); 
     403                } 
     404            } 
     405 
     406            if (matches.isEmpty()) 
     407                return null; 
     408 
     409 
     410            Collections.sort(matches, new Comparator<CacheEntry>() { 
     411                @Override 
     412                public int compare(CacheEntry o1, CacheEntry o2) { 
     413                    return Double.compare(o2.pixelPerDegree, o1.pixelPerDegree); 
     414                } 
     415            }); 
     416        } 
    393417 
    394418        //TODO Use alpha layer only when enabled on wms layer 
     
    396420        Graphics2D g = result.createGraphics(); 
    397421 
     422 
    398423        boolean drawAtLeastOnce = false; 
     424        Map<CacheEntry, SoftReference<BufferedImage>> localCache = new HashMap<WmsCache.CacheEntry, SoftReference<BufferedImage>>(); 
    399425        for (CacheEntry ce: matches) { 
    400426            BufferedImage img; 
    401427            try { 
    402428                img = loadImage(projectionEntries, ce); 
    403                 memoryCache.put(ce, new SoftReference<BufferedImage>(img)); 
     429                localCache.put(ce, new SoftReference<BufferedImage>(img)); 
    404430            } catch (IOException e) { 
    405431                continue; 
     
    418444        } 
    419445 
    420         if (drawAtLeastOnce) 
     446        if (drawAtLeastOnce) { 
     447            synchronized (this) { 
     448                memoryCache.putAll(localCache); 
     449            } 
    421450            return result; 
    422         else 
     451        } else 
    423452            return null; 
    424453    } 
     
    461490 
    462491    /** 
    463      *  
     492     * 
    464493     * @param img Used only when overlapping is used, when not used, used raw from imageData 
    465494     * @param imageData 
     
    475504        File imageFile; 
    476505        if (entry == null) { 
    477             entry = new CacheEntry(pixelPerDegree, east, north, tileSize); 
    478             entry.lastUsed = System.currentTimeMillis(); 
    479             entry.lastModified = entry.lastUsed; 
    480506 
    481507            String mimeType; 
     
    485511                mimeType = URLConnection.guessContentTypeFromStream(imageData); 
    486512            } 
    487             entry.filename = generateFileName(projectionEntries, pixelPerDegree, projection, east, north, mimeType); 
     513            entry = new CacheEntry(pixelPerDegree, east, north, tileSize,generateFileName(projectionEntries, pixelPerDegree, projection, east, north, mimeType)); 
     514            entry.lastUsed = System.currentTimeMillis(); 
     515            entry.lastModified = entry.lastUsed; 
    488516            projectionEntries.entries.add(entry); 
    489517            imageFile = getImageFile(projectionEntries, entry); 
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r4718 r4745  
    2424import java.awt.geom.Rectangle2D; 
    2525import java.io.File; 
     26import java.io.IOException; 
    2627import java.net.MalformedURLException; 
    2728import java.net.URL; 
     
    3940import javax.swing.AbstractAction; 
    4041import javax.swing.Action; 
     42import javax.swing.DefaultComboBoxModel; 
    4143import javax.swing.Icon; 
     44import javax.swing.JComboBox; 
    4245import javax.swing.JComponent; 
    4346import javax.swing.JFileChooser; 
     
    5760 
    5861import org.openstreetmap.josm.Main; 
     62import org.openstreetmap.josm.actions.AbstractMergeAction.LayerListCellRenderer; 
    5963import org.openstreetmap.josm.actions.RenameLayerAction; 
    6064import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTaskList; 
     
    8084import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 
    8185import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 
     86import org.openstreetmap.josm.gui.layer.WMSLayer.PrecacheTask; 
    8287import org.openstreetmap.josm.gui.layer.markerlayer.AudioMarker; 
    8388import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 
     
    8691import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor; 
    8792import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
     93import org.openstreetmap.josm.gui.progress.ProgressTaskId; 
     94import org.openstreetmap.josm.gui.progress.ProgressTaskIds; 
    8895import org.openstreetmap.josm.gui.widgets.HtmlPanel; 
    8996import org.openstreetmap.josm.io.JpgImporter; 
     97import org.openstreetmap.josm.io.OsmTransferException; 
    9098import org.openstreetmap.josm.tools.AudioUtil; 
    9199import org.openstreetmap.josm.tools.DateUtils; 
     
    96104import org.openstreetmap.josm.tools.Utils; 
    97105import org.openstreetmap.josm.tools.WindowGeometry; 
     106import org.xml.sax.SAXException; 
    98107 
    99108public class GpxLayer extends Layer { 
     
    297306                new ConvertToDataLayerAction(), 
    298307                new DownloadAlongTrackAction(), 
     308                new DownloadWmsAlongTrackAction(), 
    299309                SeparatorLayerAction.INSTANCE, 
    300310                new ChooseTrackVisibilityAction(), 
     
    12451255        } 
    12461256 
     1257 
    12471258        /** 
    12481259         * Area "a" contains the hull that we would like to download data for. however we 
     
    13091320                    } 
    13101321                    ); 
     1322        } 
     1323    } 
     1324 
     1325 
     1326    public class DownloadWmsAlongTrackAction extends AbstractAction { 
     1327        public DownloadWmsAlongTrackAction() { 
     1328            super(tr("Precache imagery tiles along this track"), ImageProvider.get("downloadalongtrack")); 
     1329        } 
     1330 
     1331        public void actionPerformed(ActionEvent e) { 
     1332 
     1333            final List<LatLon> points = new ArrayList<LatLon>(); 
     1334 
     1335            for (GpxTrack trk : data.tracks) { 
     1336                for (GpxTrackSegment segment : trk.getSegments()) { 
     1337                    for (WayPoint p : segment.getWayPoints()) { 
     1338                        points.add(p.getCoor()); 
     1339                    } 
     1340                } 
     1341            } 
     1342            for (WayPoint p : data.waypoints) { 
     1343                points.add(p.getCoor()); 
     1344            } 
     1345 
     1346 
     1347            final WMSLayer layer = askWMSLayer(); 
     1348            if (layer != null) { 
     1349                PleaseWaitRunnable task = new PleaseWaitRunnable(tr("Precaching WMS")) { 
     1350 
     1351                    private PrecacheTask precacheTask; 
     1352 
     1353                    @Override 
     1354                    protected void realRun() throws SAXException, IOException, OsmTransferException { 
     1355                        precacheTask = new PrecacheTask(progressMonitor); 
     1356                        layer.downloadAreaToCache(precacheTask, points, 0, 0); 
     1357                        while (!precacheTask.isFinished() && !progressMonitor.isCanceled()) { 
     1358                            synchronized (this) { 
     1359                                try { 
     1360                                    wait(200); 
     1361                                } catch (InterruptedException e) { 
     1362                                    e.printStackTrace(); 
     1363                                } 
     1364                            } 
     1365                        } 
     1366                    } 
     1367 
     1368                    @Override 
     1369                    protected void finish() { 
     1370                    } 
     1371 
     1372                    @Override 
     1373                    protected void cancel() { 
     1374                        precacheTask.cancel(); 
     1375                    } 
     1376 
     1377                    @Override 
     1378                    public ProgressTaskId canRunInBackground() { 
     1379                        return ProgressTaskIds.PRECACHE_WMS; 
     1380                    } 
     1381                }; 
     1382                Main.worker.execute(task); 
     1383            } 
     1384 
     1385 
     1386        } 
     1387 
     1388        protected WMSLayer askWMSLayer() { 
     1389            List<WMSLayer> targetLayers = Main.map.mapView.getLayersOfType(WMSLayer.class); 
     1390 
     1391            if (targetLayers.isEmpty()) { 
     1392                warnNoImageryLayers(); 
     1393                return null; 
     1394            } 
     1395 
     1396            JComboBox layerList = new JComboBox(); 
     1397            layerList.setRenderer(new LayerListCellRenderer()); 
     1398            layerList.setModel(new DefaultComboBoxModel(targetLayers.toArray())); 
     1399            layerList.setSelectedIndex(0); 
     1400 
     1401            JPanel pnl = new JPanel(); 
     1402            pnl.setLayout(new GridBagLayout()); 
     1403            pnl.add(new JLabel(tr("Please select the imagery layer.")), GBC.eol()); 
     1404            pnl.add(layerList, GBC.eol()); 
     1405 
     1406            ExtendedDialog ed = new ExtendedDialog(Main.parent, 
     1407                    tr("Select imagery layer"), 
     1408                    new String[] { tr("Download"), tr("Cancel") }); 
     1409            ed.setButtonIcons(new String[] { "dialogs/down", "cancel" }); 
     1410            ed.setContent(pnl); 
     1411            ed.showDialog(); 
     1412            if (ed.getValue() != 1) 
     1413                return null; 
     1414 
     1415            WMSLayer targetLayer = (WMSLayer) layerList.getSelectedItem(); 
     1416            return targetLayer; 
     1417        } 
     1418 
     1419        protected void warnNoImageryLayers() { 
     1420            JOptionPane.showMessageDialog(Main.parent, 
     1421                    tr("There are no imagery layers."), 
     1422                    tr("No imagery layers"), JOptionPane.WARNING_MESSAGE); 
    13111423        } 
    13121424    } 
  • trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java

    r4633 r4745  
    88import java.awt.Graphics2D; 
    99import java.awt.Image; 
     10import java.awt.Point; 
    1011import java.awt.event.ActionEvent; 
    1112import java.awt.event.MouseAdapter; 
     
    4546import org.openstreetmap.josm.data.ProjectionBounds; 
    4647import org.openstreetmap.josm.data.coor.EastNorth; 
     48import org.openstreetmap.josm.data.coor.LatLon; 
    4749import org.openstreetmap.josm.data.imagery.GeorefImage; 
    4850import org.openstreetmap.josm.data.imagery.GeorefImage.State; 
     
    6163import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 
    6264import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 
     65import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
    6366import org.openstreetmap.josm.io.imagery.Grabber; 
    6467import org.openstreetmap.josm.io.imagery.HTMLGrabber; 
     
    6770import org.openstreetmap.josm.tools.ImageProvider; 
    6871 
     72 
    6973/** 
    7074 * This is a layer that grabs the current screen from an WMS server. The data 
     
    7276 */ 
    7377public class WMSLayer extends ImageryLayer implements ImageObserver, PreferenceChangedListener { 
     78 
     79    public static class PrecacheTask { 
     80        private final ProgressMonitor progressMonitor; 
     81        private volatile int totalCount; 
     82        private volatile int processedCount; 
     83        private volatile boolean isCancelled; 
     84 
     85        public PrecacheTask(ProgressMonitor progressMonitor) { 
     86            this.progressMonitor = progressMonitor; 
     87        } 
     88 
     89        boolean isFinished() { 
     90            return totalCount == processedCount; 
     91        } 
     92 
     93        public int getTotalCount() { 
     94            return totalCount; 
     95        } 
     96 
     97        public void cancel() { 
     98            isCancelled = true; 
     99        } 
     100    } 
    74101 
    75102    private static final ObjectFactory OBJECT_FACTORY = null; // Fake reference to keep build scripts from removing ObjectFactory class. This class is not used directly but it's necessary for jaxb to work 
     
    159186        } 
    160187 
     188 
    161189        Main.pref.addPreferenceChangeListener(this); 
    162190 
     
    205233    public boolean hasAutoDownload(){ 
    206234        return autoDownloadEnabled; 
     235    } 
     236 
     237    public void downloadAreaToCache(PrecacheTask precacheTask, List<LatLon> points, double bufferX, double bufferY) { 
     238        Set<Point> requestedTiles = new HashSet<Point>(); 
     239        for (LatLon point: points) { 
     240            EastNorth minEn = Main.getProjection().latlon2eastNorth(new LatLon(point.lat() - bufferY, point.lon() - bufferX)); 
     241            EastNorth maxEn = Main.getProjection().latlon2eastNorth(new LatLon(point.lat() + bufferY, point.lon() + bufferX)); 
     242            int minX = getImageXIndex(minEn.east()); 
     243            int maxX = getImageXIndex(maxEn.east()); 
     244            int minY = getImageYIndex(minEn.north()); 
     245            int maxY = getImageYIndex(maxEn.north()); 
     246 
     247            for (int x=minX; x<=maxX; x++) { 
     248                for (int y=minY; y<=maxY; y++) { 
     249                    requestedTiles.add(new Point(x, y)); 
     250                } 
     251            } 
     252        } 
     253 
     254        for (Point p: requestedTiles) { 
     255            addRequest(new WMSRequest(p.x, p.y, info.getPixelPerDegree(), true, false, precacheTask)); 
     256        } 
     257 
     258        precacheTask.progressMonitor.setTicksCount(precacheTask.getTotalCount()); 
     259        precacheTask.progressMonitor.setCustomText(tr("Downloaded {0}/{1} tiles", 0, precacheTask.totalCount)); 
    207260    } 
    208261 
     
    472525        int dy = request.getYIndex() - mouseY; 
    473526 
    474         return dx * dx + dy * dy; 
    475     } 
    476  
    477     public WMSRequest getRequest() { 
     527        return 1 + dx * dx + dy * dy; 
     528    } 
     529 
     530    private void sortRequests(boolean localOnly) { 
     531        Iterator<WMSRequest> it = requestQueue.iterator(); 
     532        while (it.hasNext()) { 
     533            WMSRequest item = it.next(); 
     534 
     535            if (item.getPrecacheTask() != null && item.getPrecacheTask().isCancelled) { 
     536                it.remove(); 
     537                continue; 
     538            } 
     539 
     540            int priority = getRequestPriority(item); 
     541            if (priority == -1 && item.isPrecacheOnly()) { 
     542                priority = Integer.MAX_VALUE; // Still download, but prefer requests in current view 
     543            } 
     544 
     545            if (localOnly && !item.hasExactMatch()) { 
     546                priority = Integer.MAX_VALUE; // Only interested in tiles that can be loaded from file immediately 
     547            } 
     548 
     549            if (       priority == -1 
     550                    || finishedRequests.contains(item) 
     551                    || processingRequests.contains(item)) { 
     552                it.remove(); 
     553            } else { 
     554                item.setPriority(priority); 
     555            } 
     556        } 
     557        Collections.sort(requestQueue); 
     558    } 
     559 
     560    public WMSRequest getRequest(boolean localOnly) { 
    478561        requestQueueLock.lock(); 
    479562        try { 
    480563            workingThreadCount--; 
    481             Iterator<WMSRequest> it = requestQueue.iterator(); 
    482             while (it.hasNext()) { 
    483                 WMSRequest item = it.next(); 
    484                 int priority = getRequestPriority(item); 
    485                 if (priority == -1 || finishedRequests.contains(item) || processingRequests.contains(item)) { 
    486                     it.remove(); 
    487                 } else { 
    488                     item.setPriority(priority); 
    489                 } 
    490             } 
    491             Collections.sort(requestQueue); 
    492  
    493             EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY()); 
    494             int mouseX = getImageXIndex(cursorEastNorth.east()); 
    495             int mouseY = getImageYIndex(cursorEastNorth.north()); 
    496             boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY; 
    497  
    498             // If there is only one thread left then keep it in case we need to download other tile urgently 
    499             while (!canceled && 
    500                     (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) { 
     564 
     565            sortRequests(localOnly); 
     566            while (!canceled && (requestQueue.isEmpty() || (localOnly && !requestQueue.get(0).hasExactMatch()))) { 
    501567                try { 
    502568                    queueEmpty.await(); 
     569                    sortRequests(localOnly); 
    503570                } catch (InterruptedException e) { 
    504571                    // Shouldn't happen 
     
    523590        requestQueueLock.lock(); 
    524591        try { 
     592            PrecacheTask task = request.getPrecacheTask(); 
     593            if (task != null) { 
     594                task.processedCount++; 
     595                if (!task.progressMonitor.isCanceled()) { 
     596                    task.progressMonitor.worked(1); 
     597                    task.progressMonitor.setCustomText(tr("Downloaded {0}/{1} tiles", task.processedCount, task.totalCount)); 
     598                } 
     599            } 
    525600            processingRequests.remove(request); 
    526             if (request.getState() != null) { 
     601            if (request.getState() != null && !request.isPrecacheOnly()) { 
    527602                finishedRequests.add(request); 
    528603                mv.repaint(); 
     
    536611        requestQueueLock.lock(); 
    537612        try { 
     613 
     614            ProjectionBounds b = getBounds(request); 
     615            // Checking for exact match is fast enough, no need to do it in separated thread 
     616            request.setHasExactMatch(cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)); 
     617            if (request.isPrecacheOnly() && request.hasExactMatch()) 
     618                return; // We already have this tile cached 
     619 
    538620            if (!requestQueue.contains(request) && !finishedRequests.contains(request) && !processingRequests.contains(request)) { 
    539621                requestQueue.add(request); 
     622                if (request.getPrecacheTask() != null) { 
     623                    request.getPrecacheTask().totalCount++; 
     624                } 
    540625                queueEmpty.signalAll(); 
    541626            } 
     
    545630    } 
    546631 
    547     public boolean requestIsValid(WMSRequest request) { 
     632    public boolean requestIsVisible(WMSRequest request) { 
    548633        return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex(); 
    549634    } 
     
    871956            grabberThreads.clear(); 
    872957            for (int i=0; i<threadCount; i++) { 
    873                 Grabber grabber = getGrabber(); 
     958                Grabber grabber = getGrabber(i == 0 && threadCount > 1); 
    874959                grabbers.add(grabber); 
    875960                Thread t = new Thread(grabber, "WMS " + getName() + " " + i); 
     
    914999    } 
    9151000 
    916     protected Grabber getGrabber(){ 
     1001    protected Grabber getGrabber(boolean localOnly){ 
    9171002        if(getInfo().getImageryType() == ImageryType.HTML) 
    918             return new HTMLGrabber(mv, this); 
     1003            return new HTMLGrabber(mv, this, localOnly); 
    9191004        else if(getInfo().getImageryType() == ImageryType.WMS) 
    920             return new WMSGrabber(mv, this); 
     1005            return new WMSGrabber(mv, this, localOnly); 
    9211006        else throw new IllegalStateException("getGrabber() called for non-WMS layer type"); 
     1007    } 
     1008 
     1009    public ProjectionBounds getBounds(WMSRequest request) { 
     1010        ProjectionBounds result = new ProjectionBounds( 
     1011                getEastNorth(request.getXIndex(), request.getYIndex()), 
     1012                getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1)); 
     1013 
     1014        if (WMSLayer.PROP_OVERLAP.get()) { 
     1015            double eastSize =  result.maxEast - result.minEast; 
     1016            double northSize =  result.maxNorth - result.minNorth; 
     1017 
     1018            double eastCoef = WMSLayer.PROP_OVERLAP_EAST.get() / 100.0; 
     1019            double northCoef = WMSLayer.PROP_OVERLAP_NORTH.get() / 100.0; 
     1020 
     1021            result = new ProjectionBounds(result.getMin(), 
     1022                    new EastNorth(result.maxEast + eastCoef * eastSize, 
     1023                            result.maxNorth + northCoef * northSize)); 
     1024        } 
     1025        return result; 
    9221026    } 
    9231027 
  • trunk/src/org/openstreetmap/josm/gui/progress/ProgressTaskIds.java

    r4718 r4745  
    55 
    66    ProgressTaskId DOWNLOAD_GPS = new ProgressTaskId("core", "downloadGps"); 
     7    ProgressTaskId PRECACHE_WMS = new ProgressTaskId("core", "precacheWms"); 
    78 
    89} 
  • trunk/src/org/openstreetmap/josm/io/imagery/Grabber.java

    r4126 r4745  
    44import org.openstreetmap.josm.Main; 
    55import org.openstreetmap.josm.data.ProjectionBounds; 
    6 import org.openstreetmap.josm.data.coor.EastNorth; 
    76import org.openstreetmap.josm.data.imagery.GeorefImage.State; 
    8 import org.openstreetmap.josm.data.projection.Projection; 
    97import org.openstreetmap.josm.gui.MapView; 
    108import org.openstreetmap.josm.gui.layer.WMSLayer; 
     
    1311    protected final MapView mv; 
    1412    protected final WMSLayer layer; 
     13    private final boolean localOnly; 
    1514 
    1615    protected ProjectionBounds b; 
    17     protected Projection proj; 
    18     protected double pixelPerDegree; 
    19     protected WMSRequest request; 
    2016    protected volatile boolean canceled; 
    2117 
    22     Grabber(MapView mv, WMSLayer layer) { 
     18    Grabber(MapView mv, WMSLayer layer, boolean localOnly) { 
    2319        this.mv = mv; 
    2420        this.layer = layer; 
    25     } 
    26  
    27     private void updateState(WMSRequest request) { 
    28         b = new ProjectionBounds( 
    29                 layer.getEastNorth(request.getXIndex(), request.getYIndex()), 
    30                 layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1)); 
    31         if (WMSLayer.PROP_OVERLAP.get()) { 
    32             double eastSize =  b.maxEast - b.minEast; 
    33             double northSize =  b.maxNorth - b.minNorth; 
    34  
    35             double eastCoef = WMSLayer.PROP_OVERLAP_EAST.get() / 100.0; 
    36             double northCoef = WMSLayer.PROP_OVERLAP_NORTH.get() / 100.0; 
    37  
    38             this.b = new ProjectionBounds(b.getMin(), 
    39                     new EastNorth(b.maxEast + eastCoef * eastSize, 
    40                             b.maxNorth + northCoef * northSize)); 
    41         } 
    42  
    43         this.proj = Main.getProjection(); 
    44         this.pixelPerDegree = request.getPixelPerDegree(); 
    45         this.request = request; 
     21        this.localOnly = localOnly; 
    4622    } 
    4723 
     
    6036            if (canceled) 
    6137                return; 
    62             WMSRequest request = layer.getRequest(); 
     38            WMSRequest request = layer.getRequest(localOnly); 
    6339            if (request == null) 
    6440                return; 
    65             updateState(request); 
    66             if(!loadFromCache(request)){ 
    67                 attempt(request); 
     41            this.b = layer.getBounds(request); 
     42            if (request.isPrecacheOnly()) { 
     43                if (!layer.cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)) { 
     44                    attempt(request); 
     45                } 
     46            } else { 
     47                if(!loadFromCache(request)){ 
     48                    attempt(request); 
     49                } 
    6850            } 
    6951            layer.finishRequest(request); 
     
    7759                return; 
    7860            try { 
    79                 if (!layer.requestIsValid(request)) 
     61                if (!request.isPrecacheOnly() && !layer.requestIsVisible(request)) 
    8062                    return; 
    8163                fetch(request, i); 
  • trunk/src/org/openstreetmap/josm/io/imagery/HTMLGrabber.java

    r4126 r4745  
    2222    public static final StringProperty PROP_BROWSER = new StringProperty("imagery.wms.browser", "webkit-image {0}"); 
    2323 
    24     public HTMLGrabber(MapView mv, WMSLayer layer) { 
    25         super(mv, layer); 
     24    public HTMLGrabber(MapView mv, WMSLayer layer, boolean localOnly) { 
     25        super(mv, layer, localOnly); 
    2626    } 
    2727 
    2828    @Override 
    29     protected BufferedImage grab(URL url, int attempt) throws IOException { 
     29    protected BufferedImage grab(WMSRequest request, URL url, int attempt) throws IOException { 
    3030        String urlstring = url.toExternalForm(); 
    3131 
     
    5252        BufferedImage img = layer.normalizeImage(ImageIO.read(bais)); 
    5353        bais.reset(); 
    54         layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth); 
     54        layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 
    5555 
    5656        return img; 
  • trunk/src/org/openstreetmap/josm/io/imagery/WMSGrabber.java

    r4432 r4745  
    11// License: GPL. For details, see LICENSE file. 
    22package org.openstreetmap.josm.io.imagery; 
    3  
    4 import static org.openstreetmap.josm.tools.I18n.tr; 
    53 
    64import java.awt.image.BufferedImage; 
     
    1816import java.text.DecimalFormatSymbols; 
    1917import java.text.NumberFormat; 
    20 import java.util.ArrayList; 
    21 import java.util.List; 
    22 import java.util.Map.Entry; 
     18import java.util.HashMap; 
    2319import java.util.Locale; 
    2420import java.util.Map; 
    25 import java.util.HashMap; 
     21import java.util.Map.Entry; 
    2622import java.util.regex.Matcher; 
    2723import java.util.regex.Pattern; 
    2824 
    2925import javax.imageio.ImageIO; 
    30 import javax.swing.JOptionPane; 
    3126 
    3227import org.openstreetmap.josm.Main; 
     
    5045    private Map<String, String> props = new HashMap<String, String>(); 
    5146 
    52     public WMSGrabber(MapView mv, WMSLayer layer) { 
    53         super(mv, layer); 
     47    public WMSGrabber(MapView mv, WMSLayer layer, boolean localOnly) { 
     48        super(mv, layer, localOnly); 
    5449        this.info = layer.getInfo(); 
    5550        this.baseURL = info.getUrl(); 
     
    7772                    b.maxEast, b.maxNorth, 
    7873                    width(), height()); 
    79             request.finish(State.IMAGE, grab(url, attempt)); 
     74            request.finish(State.IMAGE, grab(request, url, attempt)); 
    8075 
    8176        } catch(Exception e) { 
     
    10297 
    10398        return new URL(baseURL.replaceAll("\\{proj(\\([^})]+\\))?\\}", myProj) 
    104             .replaceAll("\\{bbox\\}", latLonFormat.format(w) + "," 
    105                 + latLonFormat.format(s) + "," 
    106                 + latLonFormat.format(e) + "," 
    107                 + latLonFormat.format(n)) 
    108             .replaceAll("\\{w\\}", latLonFormat.format(w)) 
    109             .replaceAll("\\{s\\}", latLonFormat.format(s)) 
    110             .replaceAll("\\{e\\}", latLonFormat.format(e)) 
    111             .replaceAll("\\{n\\}", latLonFormat.format(n)) 
    112             .replaceAll("\\{width\\}", String.valueOf(wi)) 
    113             .replaceAll("\\{height\\}", String.valueOf(ht)) 
    114             .replace(" ", "%20")); 
     99                .replaceAll("\\{bbox\\}", latLonFormat.format(w) + "," 
     100                        + latLonFormat.format(s) + "," 
     101                        + latLonFormat.format(e) + "," 
     102                        + latLonFormat.format(n)) 
     103                        .replaceAll("\\{w\\}", latLonFormat.format(w)) 
     104                        .replaceAll("\\{s\\}", latLonFormat.format(s)) 
     105                        .replaceAll("\\{e\\}", latLonFormat.format(e)) 
     106                        .replaceAll("\\{n\\}", latLonFormat.format(n)) 
     107                        .replaceAll("\\{width\\}", String.valueOf(wi)) 
     108                        .replaceAll("\\{height\\}", String.valueOf(ht)) 
     109                        .replace(" ", "%20")); 
    115110    } 
    116111 
    117112    @Override 
    118113    public boolean loadFromCache(WMSRequest request) { 
    119         BufferedImage cached = layer.cache.getExactMatch(Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth); 
     114        BufferedImage cached = layer.cache.getExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 
    120115 
    121116        if (cached != null) { 
     
    123118            return true; 
    124119        } else if (request.isAllowPartialCacheMatch()) { 
    125             BufferedImage partialMatch = layer.cache.getPartialMatch(Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth); 
     120            BufferedImage partialMatch = layer.cache.getPartialMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 
    126121            if (partialMatch != null) { 
    127122                request.finish(State.PARTLY_IN_CACHE, partialMatch); 
     
    138133    } 
    139134 
    140     protected BufferedImage grab(URL url, int attempt) throws IOException, OsmTransferException { 
     135    protected BufferedImage grab(WMSRequest request, URL url, int attempt) throws IOException, OsmTransferException { 
    141136        System.out.println("Grabbing WMS " + (attempt > 1? "(attempt " + attempt + ") ":"") + url); 
    142137 
     
    164159        BufferedImage img = layer.normalizeImage(ImageIO.read(bais)); 
    165160        bais.reset(); 
    166         layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), pixelPerDegree, b.minEast, b.minNorth); 
     161        layer.cache.saveToCache(layer.isOverlapEnabled()?img:null, bais, Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth); 
    167162        return img; 
    168163    } 
  • trunk/src/org/openstreetmap/josm/io/imagery/WMSRequest.java

    r4065 r4745  
    55 
    66import org.openstreetmap.josm.data.imagery.GeorefImage.State; 
     7import org.openstreetmap.josm.gui.layer.WMSLayer.PrecacheTask; 
    78 
    89public class WMSRequest implements Comparable<WMSRequest> { 
     
    1112    private final double pixelPerDegree; 
    1213    private final boolean real; // Download even if autodownloading is disabled 
     14    private final PrecacheTask precacheTask; // Download even when wms tile is not currently visible (precache) 
    1315    private final boolean allowPartialCacheMatch; 
    1416    private int priority; 
     17    private boolean hasExactMatch; 
    1518    // Result 
    1619    private State state; 
     
    1821 
    1922    public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real, boolean allowPartialCacheMatch) { 
     23        this(xIndex, yIndex, pixelPerDegree, real, allowPartialCacheMatch, null); 
     24    } 
     25 
     26    public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real, boolean allowPartialCacheMatch, PrecacheTask precacheTask) { 
    2027        this.xIndex = xIndex; 
    2128        this.yIndex = yIndex; 
    2229        this.pixelPerDegree = pixelPerDegree; 
    2330        this.real = real; 
     31        this.precacheTask = precacheTask; 
    2432        this.allowPartialCacheMatch = allowPartialCacheMatch; 
    2533    } 
     34 
    2635 
    2736    public void finish(State state, BufferedImage image) { 
     
    99108    public String toString() { 
    100109        return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex 
    101         + ", pixelPerDegree=" + pixelPerDegree + "]"; 
     110                + ", pixelPerDegree=" + pixelPerDegree + "]"; 
    102111    } 
    103112 
     
    106115    } 
    107116 
     117    public boolean isPrecacheOnly() { 
     118        return precacheTask != null; 
     119    } 
     120 
     121    public PrecacheTask getPrecacheTask() { 
     122        return precacheTask; 
     123    } 
     124 
    108125    public boolean isAllowPartialCacheMatch() { 
    109126        return allowPartialCacheMatch; 
    110127    } 
     128 
     129    public boolean hasExactMatch() { 
     130        return hasExactMatch; 
     131    } 
     132 
     133    public void setHasExactMatch(boolean hasExactMatch) { 
     134        this.hasExactMatch = hasExactMatch; 
     135    } 
    111136} 
Note: See TracChangeset for help on using the changeset viewer.