diff --git a/nbproject/configs/BulkDownloadCli.properties b/nbproject/configs/BulkDownloadCli.properties
new file mode 100644
index 0000000000..67f431cdef
--- /dev/null
+++ b/nbproject/configs/BulkDownloadCli.properties
@@ -0,0 +1 @@
+main.class=gov.nasa.worldwindx.examples.util.BulkDownloadCli
diff --git a/src/config/Earth/OpenStreetMap2.xml b/src/config/Earth/OpenStreetMap2.xml
new file mode 100644
index 0000000000..7ef7a8f339
--- /dev/null
+++ b/src/config/Earth/OpenStreetMap2.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+ Open Street Map
+
+ https://worldwind47.arc.nasa.gov/mapcache
+ https://worldwind47.arc.nasa.gov/mapcache
+ osm
+
+ 0.40
+ true
+
+ 01 11 2022 22:52:00 GMT
+ Earth/OpenStreetMap2
+ image/jpeg
+
+ image/jpeg
+
+ .jpg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ true
+
+
+
+
+
+
diff --git a/src/gov/nasa/worldwind/layers/BasicTiledImageLayer.java b/src/gov/nasa/worldwind/layers/BasicTiledImageLayer.java
index 1b73e7d839..57dffc22bb 100644
--- a/src/gov/nasa/worldwind/layers/BasicTiledImageLayer.java
+++ b/src/gov/nasa/worldwind/layers/BasicTiledImageLayer.java
@@ -55,7 +55,8 @@
public class BasicTiledImageLayer extends TiledImageLayer implements BulkRetrievable
{
protected final Object fileLock = new Object();
-
+ protected long averageFileSize=BasicTiledImageLayerBulkDownloader.DEFAULT_AVERAGE_FILE_SIZE; // The average file size of an individual tile to use for size estimates.
+
// Layer resource properties.
protected static final int RESOURCE_ID_OGC_CAPABILITIES = 1;
@@ -523,12 +524,18 @@ public long getEstimatedMissingDataSize(Sector sector, double resolution, FileSt
BasicTiledImageLayerBulkDownloader downloader = new BasicTiledImageLayerBulkDownloader(this, sector, resolution,
fileStore != null ? fileStore : this.getDataFileStore(), null);
-
+ downloader.setAverageFileSize(this.averageFileSize);
return downloader.getEstimatedMissingDataSize();
}
- // *** Tile download ***
- // *** Tile download ***
+ /**
+ * Set the average size of a tile image to use in estimating download sizes.
+ * @param value The average size of a tile image.
+ */
+ public void setAverageFileSize(long value) {
+ this.averageFileSize=value;
+ }
+
// *** Tile download ***
protected void retrieveTexture(TextureTile tile, DownloadPostProcessor postProcessor)
diff --git a/src/gov/nasa/worldwind/layers/BasicTiledImageLayerBulkDownloader.java b/src/gov/nasa/worldwind/layers/BasicTiledImageLayerBulkDownloader.java
index fd343df397..8139a15e82 100644
--- a/src/gov/nasa/worldwind/layers/BasicTiledImageLayerBulkDownloader.java
+++ b/src/gov/nasa/worldwind/layers/BasicTiledImageLayerBulkDownloader.java
@@ -58,6 +58,7 @@ public class BasicTiledImageLayerBulkDownloader extends BulkRetrievalThread
protected final BasicTiledImageLayer layer;
protected final int level;
protected ArrayList missingTiles;
+ protected long averageFileSize=DEFAULT_AVERAGE_FILE_SIZE;
/**
* Constructs a downloader to retrieve imagery not currently available in the WorldWind file cache.
@@ -472,7 +473,7 @@ public boolean accept(File file)
}
}
- Long averageTileSize = DEFAULT_AVERAGE_FILE_SIZE;
+ Long averageTileSize = this.averageFileSize;
if (count > 0 && size > 0)
{
averageTileSize = size / count;
@@ -481,6 +482,14 @@ public boolean accept(File file)
return averageTileSize;
}
+
+ /**
+ * Set the average size of a tile image to use in estimating download sizes.
+ * @param value The average size of a tile image.
+ */
+ public void setAverageFileSize(long value) {
+ this.averageFileSize=value;
+ }
protected long computeAverageTileSize(File dir)
{
diff --git a/src/gov/nasa/worldwind/wms/WMSTiledImageLayer.java b/src/gov/nasa/worldwind/wms/WMSTiledImageLayer.java
index 315533bfee..7a012a3524 100644
--- a/src/gov/nasa/worldwind/wms/WMSTiledImageLayer.java
+++ b/src/gov/nasa/worldwind/wms/WMSTiledImageLayer.java
@@ -196,18 +196,16 @@ public URLBuilder(AVList params)
String version = params.getStringValue(AVKey.WMS_VERSION);
String coordSystemKey;
- String defaultCS;
+ String defaultCS = "EPSG:4326";
if (version == null || WWUtil.compareVersion(version, "1.3.0") >= 0)
{
this.wmsVersion = MAX_VERSION;
coordSystemKey = "&crs=";
- defaultCS = "CRS:84"; // would like to do EPSG:4326 but that's incompatible with our old WMS server, see WWJ-474
}
else
{
this.wmsVersion = version;
coordSystemKey = "&srs=";
- defaultCS = "EPSG:4326";
}
String coordinateSystem = params.getStringValue(AVKey.COORDINATE_SYSTEM);
@@ -220,7 +218,6 @@ public URL getURL(Tile tile, String altImageFormat) throws MalformedURLException
if (this.URLTemplate == null)
{
sb = new StringBuffer(WWXML.fixGetMapString(tile.getLevel().getService()));
-
if (!sb.toString().toLowerCase().contains("service=wms"))
sb.append("service=WMS");
sb.append("&request=GetMap");
diff --git a/src/gov/nasa/worldwindx/examples/util/BulkDownloadCli.java b/src/gov/nasa/worldwindx/examples/util/BulkDownloadCli.java
new file mode 100644
index 0000000000..7d6d6bd7ec
--- /dev/null
+++ b/src/gov/nasa/worldwindx/examples/util/BulkDownloadCli.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the
+ * Administrator of the National Aeronautics and Space Administration.
+ * All rights reserved.
+ *
+ * The NASA World Wind Java (WWJ) platform is licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source
+ * software:
+ *
+ * Jackson Parser – Licensed under Apache 2.0
+ * GDAL – Licensed under MIT
+ * JOGL – Licensed under Berkeley Software Distribution (BSD)
+ * Gluegen – Licensed under Berkeley Software Distribution (BSD)
+ *
+ * A complete listing of 3rd Party software notices and licenses included in
+ * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party
+ * notices and licenses PDF found in code directory.
+ */
+package gov.nasa.worldwindx.examples.util;
+
+import gov.nasa.worldwind.cache.BasicDataFileStore;
+import gov.nasa.worldwind.geom.LatLon;
+import gov.nasa.worldwind.geom.Sector;
+import gov.nasa.worldwind.globes.Earth;
+import gov.nasa.worldwind.globes.Globe;
+import gov.nasa.worldwind.layers.BasicLayerFactory;
+import gov.nasa.worldwind.layers.BasicTiledImageLayer;
+import gov.nasa.worldwind.layers.BasicTiledImageLayerBulkDownloader;
+import gov.nasa.worldwind.retrieve.Progress;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.StringTokenizer;
+
+public class BulkDownloadCli {
+
+ private static class FileUtils extends SimpleFileVisitor {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException ex) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+
+ static void deleteDirectory(File f) throws IOException {
+ Files.walkFileTree(Path.of(f.getAbsolutePath()), new FileUtils());
+ }
+ }
+
+ private static final String VERSION = "1.1";
+ private static final long OSM_AVERAGE_TILE_SIZE = 15000;
+
+ public static String makeSizeDescription(long size) {
+ double sizeInMegaBytes = size / 1024 / 1024;
+ if (sizeInMegaBytes < 1024) {
+ return String.format("%,.1f MB", sizeInMegaBytes);
+ } else if (sizeInMegaBytes < 1024 * 1024) {
+ return String.format("%,.1f GB", sizeInMegaBytes / 1024);
+ }
+ return String.format("%,.1f TB", sizeInMegaBytes / 1024 / 1024);
+ }
+
+ public static void cliDownload(String[] args) {
+ System.out.println("WorldWind Bulk Download Tool v" + VERSION);
+ Globe globe = new Earth();
+ String usage = "Usage: BulkDownload -sector [centerLat,centerLon,radius meters] -path [path for download] -estimate";
+ String outputPath = null;
+ Sector sector = null;
+ boolean estimate = false;
+ int i = 0;
+ while (i < args.length) {
+ switch (args[i]) {
+ case "-help":
+ System.out.println(usage);
+ return;
+ case "-sector":
+ i++;
+ StringTokenizer st = new StringTokenizer(args[i], ",");
+ if (st.countTokens() != 3) {
+ System.out.println("Error: Invalid sector specification.");
+ System.out.println(usage);
+ return;
+ }
+ double lat = Double.parseDouble(st.nextToken());
+ double lon = Double.parseDouble(st.nextToken());
+ double radius = Double.parseDouble(st.nextToken());
+ sector = Sector.boundingSector(globe, LatLon.fromDegrees(lat, lon), radius);
+ break;
+ case "-path":
+ i++;
+ outputPath = args[i];
+ break;
+ case "-estimate":
+ estimate = true;
+ break;
+ default:
+ System.out.println("Unknown argument: " + args[i]);
+ System.out.println(usage);
+ break;
+ }
+ i++;
+ }
+
+ if (sector == null) {
+ System.out.println("Error: Sector not specified.");
+ System.out.println(usage);
+ return;
+ }
+
+ System.out.println("Sector: " + sector);
+ BasicLayerFactory factory = new BasicLayerFactory();
+ BasicTiledImageLayer layer = (BasicTiledImageLayer) factory.createFromConfigSource("config/Earth/OpenStreetMap2.xml", null);
+ layer.setAverageFileSize(OSM_AVERAGE_TILE_SIZE);
+ if (estimate) {
+ System.out.println(layer.getName() + " estimated download size: " + makeSizeDescription(layer.getEstimatedMissingDataSize(sector, 0)));
+ return;
+ }
+
+ if (outputPath == null) {
+ System.out.println("Error: Output path not specified.");
+ System.out.println(usage);
+ return;
+ }
+
+ try {
+ String earthPath = outputPath + "/Earth";
+ String osmPath = earthPath + "/OpenStreetMap2";
+ File previousTilePath = new File(earthPath);
+ File previousOsmPath = new File(osmPath);
+ if (previousTilePath.exists() && previousTilePath.isDirectory() && previousOsmPath.exists()) {
+ FileUtils.deleteDirectory(previousTilePath);
+ }
+
+ BasicDataFileStore cache = new BasicDataFileStore(new File(outputPath));
+ BasicTiledImageLayerBulkDownloader downloadThread = (BasicTiledImageLayerBulkDownloader) layer.makeLocal(sector, 0, cache, null);
+ downloadThread.setAverageFileSize(OSM_AVERAGE_TILE_SIZE);
+ Progress progress = downloadThread.getProgress();
+ System.out.println("Downloading " + layer.getName() + " Tiles");
+ int lastPercent = -1;
+ long lastCurrentSize = -1;
+ while (downloadThread.isAlive()) {
+ int percent = 0;
+ if (progress.getTotalCount() > 0) {
+ percent = (int) ((float) progress.getCurrentCount() / progress.getTotalCount() * 100f);
+ }
+ if (lastPercent != percent || lastCurrentSize != progress.getCurrentSize()) {
+ lastPercent = percent;
+ lastCurrentSize = progress.getCurrentSize();
+ String text = percent + "% ";
+ text += " (" + makeSizeDescription(lastCurrentSize)
+ + " / " + makeSizeDescription(progress.getTotalSize())
+ + ")";
+ System.out.println(text);
+ }
+ Thread.sleep(1000);
+ }
+ int nRemoveLevels = 9;
+ for (i = 0; i < nRemoveLevels; i++) {
+ File levelPath = new File(osmPath + "/" + i);
+ if (levelPath.exists() && levelPath.isDirectory()) {
+ FileUtils.deleteDirectory(levelPath);
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ cliDownload(args);
+ }
+}