Repository: graphhopper/graphhopper
Pull request #1261 (2018-01-05 16:29:41)

Android: VTM 0.9.2 OpenGL vector map library
[VTM 0.9.2](https://groups.google.com/forum/#!topic/mapsforge-dev/RRvROF866r8) OpenGL vector map library was released!


Patch:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 62f766591..9dcf0d482 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-Submit a new issue only if you are sure it is a missing feature or a bug. Otherwise, [discuss the topic](http://graphhopper.com/#developers) first. 
+Submit a new issue only if you are sure it is a missing feature or a bug. Otherwise, [discuss the topic](https://discuss.graphhopper.com/c/graphhopper) first. 
 For new translations or fixes to existing translations,
 please refer to [this documentation](https://github.com/graphhopper/graphhopper/blob/master/docs/core/translations.md).
 
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 13bc699c3..9fa9d7ced 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -42,15 +42,15 @@ dependencies {
        exclude group: 'org.apache.xmlgraphics', module: 'xmlgraphics-commons'
     }
 
-    implementation 'org.mapsforge:vtm:0.9.1'
-    implementation 'org.mapsforge:vtm-android:0.9.1'
-    implementation 'org.mapsforge:vtm-android:0.9.1:natives-armeabi'
-    implementation 'org.mapsforge:vtm-android:0.9.1:natives-armeabi-v7a'
-    implementation 'org.mapsforge:vtm-android:0.9.1:natives-arm64-v8a'
-    implementation 'org.mapsforge:vtm-android:0.9.1:natives-x86'
-    implementation 'org.mapsforge:vtm-android:0.9.1:natives-x86_64'
-    implementation 'org.mapsforge:vtm-jts:0.9.1'
-    implementation 'org.mapsforge:vtm-themes:0.9.1'
+    implementation 'org.mapsforge:vtm:0.9.2'
+    implementation 'org.mapsforge:vtm-android:0.9.2'
+    implementation 'org.mapsforge:vtm-android:0.9.2:natives-armeabi'
+    implementation 'org.mapsforge:vtm-android:0.9.2:natives-armeabi-v7a'
+    implementation 'org.mapsforge:vtm-android:0.9.2:natives-arm64-v8a'
+    implementation 'org.mapsforge:vtm-android:0.9.2:natives-x86'
+    implementation 'org.mapsforge:vtm-android:0.9.2:natives-x86_64'
+    implementation 'org.mapsforge:vtm-jts:0.9.2'
+    implementation 'org.mapsforge:vtm-themes:0.9.2'
     implementation 'com.caverock:androidsvg:1.2.2-beta-1'
 
     implementation 'org.slf4j:slf4j-api:1.7.25'
diff --git a/android/app/pom.xml b/android/app/pom.xml
index 92d1d2792..bc1c1679b 100644
--- a/android/app/pom.xml
+++ b/android/app/pom.xml
@@ -19,7 +19,7 @@
         <version>0.10-SNAPSHOT</version>
     </parent>
     <properties>
-        <vtm.version>0.9.0</vtm.version>
+        <vtm.version>0.9.2</vtm.version>
         <!-- do not put the properties here as it differs from dev to dev <android.sdk.path>/home/peterk/Programme/android-sdk-linux_x86</android.sdk.path>
         instead use your IDE to set it up or specify android sdk via command line
         using -Dandroid.sdk.path=... or by setting environment variable ANDROID_HOME
diff --git a/config-example.properties b/config-example.properties
index c3b206773..bf3f7d9ce 100644
--- a/config-example.properties
+++ b/config-example.properties
@@ -15,7 +15,7 @@ graph.flag_encoders=car
 
 
 # Per default GraphHopper doesn't use elevation data, you can enable elevation by setting graph.elevation.provider
-# to srtm, cgiar, gmted, or multi. See the corresponding classes at com.graphhopper.reader.dem for more information.
+# to srtm, cgiar, gmted, srtmgl1, or multi. See the corresponding classes at com.graphhopper.reader.dem for more information.
 # graph.elevation.provider=srtm
 
 
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index d108a0a8f..1683b2167 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -571,23 +571,25 @@ public class GraphHopper implements GraphHopperAPI {
         if (baseURL.isEmpty())
             args.get("graph.elevation.baseurl", "");
 
+        boolean removeTempElevationFiles = args.getBool("graph.elevation.cgiar.clear", true);
+        removeTempElevationFiles = args.getBool("graph.elevation.clear", removeTempElevationFiles);
+
         DAType elevationDAType = DAType.fromString(args.get("graph.elevation.dataaccess", "MMAP"));
         ElevationProvider tmpProvider = ElevationProvider.NOOP;
         if (eleProviderStr.equalsIgnoreCase("srtm")) {
-            tmpProvider = new SRTMProvider();
+            tmpProvider = new SRTMProvider(cacheDirStr);
         } else if (eleProviderStr.equalsIgnoreCase("cgiar")) {
-            CGIARProvider cgiarProvider = new CGIARProvider();
-            cgiarProvider.setAutoRemoveTemporaryFiles(args.getBool("graph.elevation.cgiar.clear", true));
-            tmpProvider = cgiarProvider;
+            tmpProvider = new CGIARProvider(cacheDirStr);
         } else if (eleProviderStr.equalsIgnoreCase("gmted")) {
-            tmpProvider = new GMTEDProvider();
+            tmpProvider = new GMTEDProvider(cacheDirStr);
+        } else if (eleProviderStr.equalsIgnoreCase("srtmgl1")) {
+            tmpProvider = new SRTMGL1Provider(cacheDirStr);
         } else if (eleProviderStr.equalsIgnoreCase("multi")) {
-            tmpProvider = new MultiSourceElevationProvider();
+            tmpProvider = new MultiSourceElevationProvider(cacheDirStr);
         }
 
+        tmpProvider.setAutoRemoveTemporaryFiles(removeTempElevationFiles);
         tmpProvider.setCalcMean(eleCalcMean);
-        if (!cacheDirStr.isEmpty())
-            tmpProvider.setCacheDir(new File(cacheDirStr));
         if (!baseURL.isEmpty())
             tmpProvider.setBaseURL(baseURL);
         tmpProvider.setDAType(elevationDAType);
diff --git a/core/src/main/java/com/graphhopper/reader/dem/AbstractElevationProvider.java b/core/src/main/java/com/graphhopper/reader/dem/AbstractElevationProvider.java
new file mode 100644
index 000000000..eda3e48b9
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/reader/dem/AbstractElevationProvider.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for 
+ *  additional information regarding copyright ownership.
+ * 
+ *  GraphHopper GmbH licenses this file to you 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.
+ */
+package com.graphhopper.reader.dem;
+
+import com.graphhopper.storage.DAType;
+import com.graphhopper.storage.Directory;
+import com.graphhopper.storage.GHDirectory;
+import com.graphhopper.util.Downloader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Provides basic methods that are usually used in an ElevationProvider.
+ *
+ * @author Robin Boldt
+ */
+public abstract class AbstractElevationProvider implements ElevationProvider {
+    final Logger logger = LoggerFactory.getLogger(getClass());
+    Downloader downloader;
+    final File cacheDir;
+    String baseUrl;
+    Directory dir;
+    DAType daType = DAType.MMAP;
+    boolean calcMean = false;
+    boolean autoRemoveTemporary = true;
+    long sleep = 2000;
+
+    protected AbstractElevationProvider(String cacheDirString) {
+        File cacheDir = new File(cacheDirString);
+        if (cacheDir.exists() && !cacheDir.isDirectory())
+            throw new IllegalArgumentException("Cache path has to be a directory");
+        try {
+            this.cacheDir = cacheDir.getCanonicalFile();
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    @Override
+    public void setCalcMean(boolean eleCalcMean) {
+        calcMean = eleCalcMean;
+    }
+
+    void setSleep(long sleep) {
+        this.sleep = sleep;
+    }
+
+    @Override
+    public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
+        this.autoRemoveTemporary = autoRemoveTemporary;
+    }
+
+    public void setDownloader(Downloader downloader) {
+        this.downloader = downloader;
+    }
+
+    protected File getCacheDir() {
+        return cacheDir;
+    }
+
+    @Override
+    public ElevationProvider setBaseURL(String baseUrl) {
+        if (baseUrl == null || baseUrl.isEmpty())
+            throw new IllegalArgumentException("baseUrl cannot be empty");
+
+        this.baseUrl = baseUrl;
+        return this;
+    }
+
+    @Override
+    public ElevationProvider setDAType(DAType daType) {
+        this.daType = daType;
+        return this;
+    }
+
+
+    protected Directory getDirectory() {
+        if (dir != null)
+            return dir;
+
+        logger.info(this.toString() + " Elevation Provider, from: " + baseUrl + ", to: " + cacheDir + ", as: " + daType +
+                " using calcmean: " + calcMean);
+        return dir = new GHDirectory(cacheDir.getAbsolutePath(), daType);
+    }
+
+    /**
+     * Return the local file name without file ending, has to be lower case, because DataAccess only supports lower case names.
+     */
+    abstract String getFileName(double lat, double lon);
+
+    /**
+     * Returns the complete URL to download the file
+     */
+    abstract String getDownloadURL(double lat, double lon);
+
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/AbstractSRTMElevationProvider.java b/core/src/main/java/com/graphhopper/reader/dem/AbstractSRTMElevationProvider.java
new file mode 100644
index 000000000..65419b8cb
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/reader/dem/AbstractSRTMElevationProvider.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for 
+ *  additional information regarding copyright ownership.
+ * 
+ *  GraphHopper GmbH licenses this file to you 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.
+ */
+package com.graphhopper.reader.dem;
+
+import com.graphhopper.coll.GHIntObjectHashMap;
+import com.graphhopper.storage.DataAccess;
+import com.graphhopper.util.BitUtil;
+import com.graphhopper.util.Downloader;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+
+/**
+ * Common functionality used when working with SRTM hgt data.
+ *
+ * @author Robin Boldt
+ */
+public abstract class AbstractSRTMElevationProvider extends AbstractElevationProvider {
+
+    private static final BitUtil BIT_UTIL = BitUtil.BIG;
+    private final int DEFAULT_WIDTH;
+    private final int WIDTH_BYTE_INDEX = 0;
+    private final int DEGREE = 1;
+    // use a map as an array is not quite useful if we want to hold only parts of the world
+    private final GHIntObjectHashMap<HeightTile> cacheData = new GHIntObjectHashMap<HeightTile>();
+    private final double precision = 1e7;
+    private final double invPrecision = 1 / precision;
+
+    public AbstractSRTMElevationProvider(String baseUrl, String cacheDir, String downloaderName, int defaultWidt) {
+        super(cacheDir);
+        this.baseUrl = baseUrl;
+        downloader = new Downloader(downloaderName).setTimeout(10000);
+        this.DEFAULT_WIDTH = defaultWidt;
+    }
+
+    // use int key instead of string for lower memory usage
+    int calcIntKey(double lat, double lon) {
+        // we could use LinearKeyAlgo but this is simpler as we only need integer precision:
+        return (down(lat) + 90) * 1000 + down(lon) + 180;
+    }
+
+    @Override
+    public void release() {
+        cacheData.clear();
+
+        // for memory mapped type we create temporary unpacked files which should be removed
+        if (autoRemoveTemporary && dir != null)
+            dir.clear();
+    }
+
+    /**
+     * Creating temporary files can take a long time to fill our DataAccess object, so this option
+     * can be used to disable the default clear mechanism via specifying 'false'.
+     */
+    public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
+        this.autoRemoveTemporary = autoRemoveTemporary;
+    }
+
+    int down(double val) {
+        int intVal = (int) val;
+        if (val >= 0 || intVal - val < invPrecision)
+            return intVal;
+        return intVal - 1;
+    }
+
+    @Override
+    public double getEle(double lat, double lon) {
+        // Return fast, if there is no data available
+        // See https://www2.jpl.nasa.gov/srtm/faq.html
+        if (lat >= 60 || lat <= -56)
+            return 0;
+
+        lat = (int) (lat * precision) / precision;
+        lon = (int) (lon * precision) / precision;
+        int intKey = calcIntKey(lat, lon);
+        HeightTile demProvider = cacheData.get(intKey);
+        if (demProvider == null) {
+            if (!cacheDir.exists())
+                cacheDir.mkdirs();
+
+            int minLat = down(lat);
+            int minLon = down(lon);
+
+            String fileName = getFileName(lat, lon);
+            if (fileName == null)
+                return 0;
+
+            DataAccess heights = getDirectory().find("dem" + intKey);
+            boolean loadExisting = false;
+            try {
+                loadExisting = heights.loadExisting();
+            } catch (Exception ex) {
+                logger.warn("cannot load dem" + intKey + ", error:" + ex.getMessage());
+            }
+
+            if (!loadExisting) {
+                try {
+                    updateHeightsFromFile(lat, lon, heights);
+                } catch (FileNotFoundException ex) {
+                    demProvider = new HeightTile(minLat, minLon, DEFAULT_WIDTH, DEFAULT_WIDTH, precision, DEGREE, DEGREE);
+                    cacheData.put(intKey, demProvider);
+                    demProvider.setHeights(heights);
+                    demProvider.setSeaLevel(true);
+                    // use small size on disc and in-memory
+                    heights.setSegmentSize(100).create(10).
+                            flush();
+                    return 0;
+                }
+            }
+
+            int width = (int) (Math.sqrt(heights.getHeader(WIDTH_BYTE_INDEX)) + 0.5);
+            if (width == 0)
+                width = DEFAULT_WIDTH;
+
+            demProvider = new HeightTile(minLat, minLon, width, width, precision, DEGREE, DEGREE);
+            cacheData.put(intKey, demProvider);
+            demProvider.setCalcMean(calcMean);
+            demProvider.setHeights(heights);
+        }
+
+        if (demProvider.isSeaLevel())
+            return 0;
+
+        return demProvider.getHeight(lat, lon);
+    }
+
+    private void updateHeightsFromFile(double lat, double lon, DataAccess heights) throws FileNotFoundException {
+        try {
+            byte[] bytes = getByteArrayFromFile(lat, lon);
+            heights.create(bytes.length);
+            for (int bytePos = 0; bytePos < bytes.length; bytePos += 2) {
+                short val = BIT_UTIL.toShort(bytes, bytePos);
+                if (val < -1000 || val > 12000)
+                    val = Short.MIN_VALUE;
+
+                heights.setShort(bytePos, val);
+            }
+            heights.setHeader(WIDTH_BYTE_INDEX, bytes.length / 2);
+            heights.flush();
+
+        } catch (FileNotFoundException ex) {
+            logger.warn("File not found for the coordinates for " + lat + "," + lon);
+            throw ex;
+        } catch (Exception ex) {
+            throw new RuntimeException("There was an issue looking up the coordinates for " + lat + "," + lon, ex);
+        }
+    }
+
+    private byte[] getByteArrayFromFile(double lat, double lon) throws InterruptedException, IOException {
+        String zippedURL = baseUrl + getDownloadURL(lat, lon);
+        File file = new File(cacheDir, new File(zippedURL).getName());
+        InputStream is;
+        // get zip file if not already in cacheDir
+        if (!file.exists())
+            for (int i = 0; i < 3; i++) {
+                try {
+                    downloader.downloadFile(zippedURL, file.getAbsolutePath());
+                    break;
+                } catch (SocketTimeoutException ex) {
+                    // just try again after a little nap
+                    Thread.sleep(2000);
+                }
+            }
+
+        return readFile(file);
+    }
+
+    abstract byte[] readFile(File file) throws IOException;
+
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/AbstractTiffElevationProvider.java b/core/src/main/java/com/graphhopper/reader/dem/AbstractTiffElevationProvider.java
index 2944228dc..1b63d9c45 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/AbstractTiffElevationProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/AbstractTiffElevationProvider.java
@@ -17,13 +17,8 @@
  */
 package com.graphhopper.reader.dem;
 
-import com.graphhopper.storage.DAType;
 import com.graphhopper.storage.DataAccess;
-import com.graphhopper.storage.Directory;
-import com.graphhopper.storage.GHDirectory;
 import com.graphhopper.util.Downloader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.awt.image.Raster;
 import java.io.File;
@@ -37,91 +32,122 @@ import java.util.Map;
  *
  * @author Robin Boldt
  */
-public abstract class AbstractTiffElevationProvider implements ElevationProvider {
-    final Logger logger = LoggerFactory.getLogger(getClass());
-    final Map<String, HeightTile> cacheData = new HashMap<String, HeightTile>();
-    protected Downloader downloader;
-    File cacheDir;
-    String baseUrl;
-    private Directory dir;
-    private DAType daType = DAType.MMAP;
-    boolean calcMean = false;
-    boolean autoRemoveTemporary = true;
-    long sleep = 2000;
-
-    public AbstractTiffElevationProvider(String baseUrl, String cacheDir, String downloaderName) {
+public abstract class AbstractTiffElevationProvider extends AbstractElevationProvider {
+    private final Map<String, HeightTile> cacheData = new HashMap<String, HeightTile>();
+    final double precision = 1e7;
+
+    private final int WIDTH;
+    private final int HEIGHT;
+
+    // Degrees of latitude covered by this tile
+    final int LAT_DEGREE;
+    // Degrees of longitude covered by this tile
+    final int LON_DEGREE;
+
+    public AbstractTiffElevationProvider(String baseUrl, String cacheDir, String downloaderName, int width, int height, int latDegree, int lonDegree) {
+        super(cacheDir);
         this.baseUrl = baseUrl;
-        this.cacheDir = new File(cacheDir);
-        downloader = new Downloader(downloaderName).setTimeout(10000);
+        this.downloader = new Downloader(downloaderName).setTimeout(10000);
+        this.WIDTH = width;
+        this.HEIGHT = height;
+        this.LAT_DEGREE = latDegree;
+        this.LON_DEGREE = lonDegree;
     }
 
     @Override
-    public void setCalcMean(boolean eleCalcMean) {
-        calcMean = eleCalcMean;
-    }
+    public void release() {
+        cacheData.clear();
 
-    void setSleep(long sleep) {
-        this.sleep = sleep;
+        // for memory mapped type we create temporary unpacked files which should be removed
+        if (autoRemoveTemporary && dir != null)
+            dir.clear();
     }
 
     /**
-     * Creating temporary files can take a long time as we need to unpack tiff as well as to fill
-     * our DataAccess object, so this option can be used to disable the default clear mechanism via
-     * specifying 'false'.
+     * Return true if the coordinates are outside of the supported area
      */
-    public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
-        this.autoRemoveTemporary = autoRemoveTemporary;
-    }
+    abstract boolean isOutsideSupportedArea(double lat, double lon);
 
-    public void setDownloader(Downloader downloader) {
-        this.downloader = downloader;
-    }
+    /**
+     * The smallest lat that is still in the HeightTile
+     */
+    abstract int getMinLatForTile(double lat);
 
-    @Override
-    public ElevationProvider setCacheDir(File cacheDir) {
-        if (cacheDir.exists() && !cacheDir.isDirectory())
-            throw new IllegalArgumentException("Cache path has to be a directory");
-        try {
-            this.cacheDir = cacheDir.getCanonicalFile();
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
-        }
-        return this;
-    }
+    /**
+     * The smallest lon that is still in the HeightTile
+     */
+    abstract int getMinLonForTile(double lon);
 
-    protected File getCacheDir() {
-        return cacheDir;
-    }
+    /**
+     * Specify the name of the file after downloading
+     */
+    abstract String getFileNameOfLocalFile(double lat, double lon);
 
     @Override
-    public ElevationProvider setBaseURL(String baseUrl) {
-        if (baseUrl == null || baseUrl.isEmpty())
-            throw new IllegalArgumentException("baseUrl cannot be empty");
+    public double getEle(double lat, double lon) {
+        // Return fast, if there is no data available
+        if (isOutsideSupportedArea(lat, lon))
+            return 0;
+
+        lat = (int) (lat * precision) / precision;
+        lon = (int) (lon * precision) / precision;
+        String name = getFileName(lat, lon);
+        HeightTile demProvider = cacheData.get(name);
+        if (demProvider == null) {
+            if (!cacheDir.exists())
+                cacheDir.mkdirs();
+
+            int minLat = getMinLatForTile(lat);
+            int minLon = getMinLonForTile(lon);
+            // less restrictive against boundary checking
+            demProvider = new HeightTile(minLat, minLon, WIDTH, HEIGHT, LON_DEGREE * precision, LON_DEGREE, LAT_DEGREE);
+            demProvider.setCalcMean(calcMean);
+
+            cacheData.put(name, demProvider);
+            DataAccess heights = getDirectory().find(name + ".gh");
+            demProvider.setHeights(heights);
+            boolean loadExisting = false;
+            try {
+                loadExisting = heights.loadExisting();
+            } catch (Exception ex) {
+                logger.warn("cannot load " + name + ", error: " + ex.getMessage());
+            }
 
-        this.baseUrl = baseUrl;
-        return this;
-    }
+            if (!loadExisting) {
+                String zippedURL = getDownloadURL(lat, lon);
+                File file = new File(cacheDir, new File(getFileNameOfLocalFile(lat, lon)).getName());
 
-    @Override
-    public ElevationProvider setDAType(DAType daType) {
-        this.daType = daType;
-        return this;
-    }
+                try {
+                    downloadFile(file, zippedURL);
+                } catch (IOException e) {
+                    demProvider.setSeaLevel(true);
+                    // use small size on disc and in-memory
+                    heights.setSegmentSize(100).create(10).
+                            flush();
+                    return 0;
+                }
 
+                // short == 2 bytes
+                heights.create(2 * WIDTH * HEIGHT);
 
-    @Override
-    public void release() {
-        cacheData.clear();
+                Raster raster = generateRasterFromFile(file, name + ".tif");
+                fillDataAccessWithElevationData(raster, heights, WIDTH);
 
-        // for memory mapped type we create temporary unpacked files which should be removed
-        if (autoRemoveTemporary && dir != null)
-            dir.clear();
+            } // loadExisting
+        }
+
+        if (demProvider.isSeaLevel())
+            return 0;
+
+        return demProvider.getHeight(lat, lon);
     }
 
+    abstract Raster generateRasterFromFile(File file, String tifName);
+
     /**
      * Download a file at the provided url and save it as the given downloadFile if the downloadFile does not exist.
      */
-    protected void downloadFile(File downloadFile, String url) throws IOException {
+    private void downloadFile(File downloadFile, String url) throws IOException {
         if (!downloadFile.exists()) {
             int max = 3;
             for (int trial = 0; trial < max; trial++) {
@@ -140,7 +166,7 @@ public abstract class AbstractTiffElevationProvider implements ElevationProvider
         }
     }
 
-    protected void fillDataAccessWithElevationData(Raster raster, DataAccess heights, int dataAccessWidth) {
+    private void fillDataAccessWithElevationData(Raster raster, DataAccess heights, int dataAccessWidth) {
         final int height = raster.getHeight();
         final int width = raster.getWidth();
         int x = 0;
@@ -156,18 +182,18 @@ public abstract class AbstractTiffElevationProvider implements ElevationProvider
                 }
             }
             heights.flush();
-
-            // TODO remove tifName and zip?
         } catch (Exception ex) {
             throw new RuntimeException("Problem at x:" + x + ", y:" + y, ex);
         }
     }
 
-    protected Directory getDirectory() {
-        if (dir != null)
-            return dir;
-
-        logger.info(this.toString() + " Elevation Provider, from: " + baseUrl + ", to: " + cacheDir + ", as: " + daType);
-        return dir = new GHDirectory(cacheDir.getAbsolutePath(), daType);
+    /**
+     * Creating temporary files can take a long time as we need to unpack tiff as well as to fill
+     * our DataAccess object, so this option can be used to disable the default clear mechanism via
+     * specifying 'false'.
+     */
+    public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
+        this.autoRemoveTemporary = autoRemoveTemporary;
     }
-}
\ No newline at end of file
+
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/CGIARProvider.java b/core/src/main/java/com/graphhopper/reader/dem/CGIARProvider.java
index e1d527400..e9d9a9a58 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/CGIARProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/CGIARProvider.java
@@ -17,7 +17,6 @@
  */
 package com.graphhopper.reader.dem;
 
-import com.graphhopper.storage.DataAccess;
 import com.graphhopper.util.Helper;
 import org.apache.xmlgraphics.image.codec.tiff.TIFFDecodeParam;
 import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
@@ -26,7 +25,6 @@ import org.apache.xmlgraphics.image.codec.util.SeekableStream;
 import java.awt.image.Raster;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
@@ -48,15 +46,19 @@ import java.util.zip.ZipInputStream;
  * @author Peter Karich
  */
 public class CGIARProvider extends AbstractTiffElevationProvider {
-    private static final int WIDTH = 6000;
-    private final double precision = 1e7;
     private final double invPrecision = 1 / precision;
-    private final int degree = 5;
 
     public CGIARProvider() {
+        this("");
+    }
+
+    public CGIARProvider(String cacheDir) {
+        // Alternative URLs for the CGIAR data can be found in #346
         super("http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff",
-                "/tmp/cgiar",
-                "GraphHopper CGIARReader");
+                cacheDir.isEmpty() ? "/tmp/cgiar" : cacheDir,
+                "GraphHopper CGIARReader",
+                6000, 6000,
+                5, 5);
     }
 
     public static void main(String[] args) {
@@ -86,107 +88,55 @@ public class CGIARProvider extends AbstractTiffElevationProvider {
 
         // 0
         System.out.println(provider.getEle(29.840644, -42.890625));
+
+        // 841
+        System.out.println(provider.getEle(48.469123, 9.576393));
     }
 
     @Override
-    public double getEle(double lat, double lon) {
-        // Return fast, if there is no data available
-        // See https://www2.jpl.nasa.gov/srtm/faq.html
-        if (lat >= 60 || lat <= -56)
-            return 0;
-
-        lat = (int) (lat * precision) / precision;
-        lon = (int) (lon * precision) / precision;
-        String name = getFileName(lat, lon);
-        HeightTile demProvider = cacheData.get(name);
-        if (demProvider == null) {
-            if (!cacheDir.exists())
-                cacheDir.mkdirs();
-
-            int minLat = down(lat);
-            int minLon = down(lon);
-            // less restrictive against boundary checking
-            demProvider = new HeightTile(minLat, minLon, WIDTH, WIDTH, degree * precision, degree, degree);
-            demProvider.setCalcMean(calcMean);
-
-            cacheData.put(name, demProvider);
-            DataAccess heights = getDirectory().find(name + ".gh");
-            demProvider.setHeights(heights);
-            boolean loadExisting = false;
-            try {
-                loadExisting = heights.loadExisting();
-            } catch (Exception ex) {
-                logger.warn("cannot load " + name + ", error: " + ex.getMessage());
+    Raster generateRasterFromFile(File file, String tifName) {
+        SeekableStream ss = null;
+        try {
+            InputStream is = new FileInputStream(file);
+            ZipInputStream zis = new ZipInputStream(is);
+            // find tif file in zip
+            ZipEntry entry = zis.getNextEntry();
+            while (entry != null && !entry.getName().equals(tifName)) {
+                entry = zis.getNextEntry();
             }
 
-            if (!loadExisting) {
-                String tifName = name + ".tif";
-                String zippedURL = baseUrl + "/" + name + ".zip";
-                File file = new File(cacheDir, new File(zippedURL).getName());
-
-                try {
-                    downloadFile(file, zippedURL);
-                } catch (IOException e) {
-                    demProvider.setSeaLevel(true);
-                    // use small size on disc and in-memory
-                    heights.setSegmentSize(100).create(10).
-                            flush();
-                    return 0;
-                }
-
-                // short == 2 bytes
-                heights.create(2 * WIDTH * WIDTH);
-
-                // logger.info("start decoding");
-                // decode tiff data
-                Raster raster;
-                SeekableStream ss = null;
-                try {
-                    InputStream is = new FileInputStream(file);
-                    ZipInputStream zis = new ZipInputStream(is);
-                    // find tif file in zip
-                    ZipEntry entry = zis.getNextEntry();
-                    while (entry != null && !entry.getName().equals(tifName)) {
-                        entry = zis.getNextEntry();
-                    }
-
-                    ss = SeekableStream.wrapInputStream(zis, true);
-                    TIFFImageDecoder imageDecoder = new TIFFImageDecoder(ss, new TIFFDecodeParam());
-                    raster = imageDecoder.decodeAsRaster();
-                } catch (Exception e) {
-                    throw new RuntimeException("Can't decode " + tifName, e);
-                } finally {
-                    if (ss != null)
-                        Helper.close(ss);
-                }
-
-                fillDataAccessWithElevationData(raster, heights, WIDTH);
-
-            } // loadExisting
+            ss = SeekableStream.wrapInputStream(zis, true);
+            TIFFImageDecoder imageDecoder = new TIFFImageDecoder(ss, new TIFFDecodeParam());
+            return imageDecoder.decodeAsRaster();
+        } catch (Exception e) {
+            throw new RuntimeException("Can't decode " + tifName, e);
+        } finally {
+            if (ss != null)
+                Helper.close(ss);
         }
-
-        if (demProvider.isSeaLevel())
-            return 0;
-
-        return demProvider.getHeight(lat, lon);
     }
 
     int down(double val) {
         // 'rounding' to closest 5
-        int intVal = (int) (val / degree) * degree;
+        int intVal = (int) (val / LAT_DEGREE) * LAT_DEGREE;
         if (!(val >= 0 || intVal - val < invPrecision))
-            intVal = intVal - degree;
+            intVal = intVal - LAT_DEGREE;
 
         return intVal;
     }
 
+    @Override
+    boolean isOutsideSupportedArea(double lat, double lon) {
+        return lat >= 60 || lat <= -56;
+    }
+
     protected String getFileName(double lat, double lon) {
-        lon = 1 + (180 + lon) / degree;
+        lon = 1 + (180 + lon) / LAT_DEGREE;
         int lonInt = (int) lon;
-        lat = 1 + (60 - lat) / degree;
+        lat = 1 + (60 - lat) / LAT_DEGREE;
         int latInt = (int) lat;
 
-        if (Math.abs(latInt - lat) < invPrecision / degree)
+        if (Math.abs(latInt - lat) < invPrecision / LAT_DEGREE)
             latInt--;
 
         // replace String.format as it seems to be slow
@@ -200,8 +150,28 @@ public class CGIARProvider extends AbstractTiffElevationProvider {
         return str;
     }
 
+    @Override
+    int getMinLatForTile(double lat) {
+        return down(lat);
+    }
+
+    @Override
+    int getMinLonForTile(double lon) {
+        return down(lon);
+    }
+
+    @Override
+    String getDownloadURL(double lat, double lon) {
+        return baseUrl + "/" + getFileName(lat, lon) + ".zip";
+    }
+
+    @Override
+    String getFileNameOfLocalFile(double lat, double lon) {
+        return getDownloadURL(lat, lon);
+    }
+
     @Override
     public String toString() {
-        return "CGIAR";
+        return "cgiar";
     }
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/ElevationProvider.java b/core/src/main/java/com/graphhopper/reader/dem/ElevationProvider.java
index 5c8726cf2..d38142d06 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/ElevationProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/ElevationProvider.java
@@ -19,8 +19,6 @@ package com.graphhopper.reader.dem;
 
 import com.graphhopper.storage.DAType;
 
-import java.io.File;
-
 /**
  * @author Peter Karich
  */
@@ -31,11 +29,6 @@ public interface ElevationProvider {
             return Double.NaN;
         }
 
-        @Override
-        public ElevationProvider setCacheDir(File cacheDir) {
-            return this;
-        }
-
         @Override
         public ElevationProvider setBaseURL(String baseURL) {
             return this;
@@ -50,6 +43,10 @@ public interface ElevationProvider {
         public void release() {
         }
 
+        @Override
+        public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
+        }
+
         @Override
         public void setCalcMean(boolean eleCalcMean) {
         }
@@ -66,12 +63,6 @@ public interface ElevationProvider {
      */
     ElevationProvider setBaseURL(String baseURL);
 
-    /**
-     * Specifies the directory where to temporarily store the elevation data after fetched from base
-     * URL. Default is a custom provider-dependent subdirectory in '/tmp'
-     */
-    ElevationProvider setCacheDir(File cacheDir);
-
     /**
      * Set to true if you have a small area and need high speed access. Default is DAType.MMAP
      */
@@ -87,4 +78,11 @@ public interface ElevationProvider {
      * Release resources.
      */
     void release();
+
+    /**
+     * Creating temporary files can take a long time as we need to unpack them as well as to fill
+     * our DataAccess object, so this option can be used to disable the default clear mechanism via
+     * specifying 'false'.
+     */
+    void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary);
 }
diff --git a/core/src/main/java/com/graphhopper/reader/dem/GMTEDProvider.java b/core/src/main/java/com/graphhopper/reader/dem/GMTEDProvider.java
index 5cb498c38..a9f5031d4 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/GMTEDProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/GMTEDProvider.java
@@ -17,7 +17,6 @@
  */
 package com.graphhopper.reader.dem;
 
-import com.graphhopper.storage.DataAccess;
 import com.graphhopper.util.Helper;
 import org.apache.xmlgraphics.image.codec.tiff.TIFFDecodeParam;
 import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
@@ -26,9 +25,7 @@ import org.apache.xmlgraphics.image.codec.util.SeekableStream;
 import java.awt.image.Raster;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.InputStream;
-import java.util.Locale;
 
 import static com.graphhopper.util.Helper.*;
 
@@ -82,19 +79,19 @@ import static com.graphhopper.util.Helper.*;
  * @author Robin Boldt
  */
 public class GMTEDProvider extends AbstractTiffElevationProvider {
-    private static final int WIDTH = 14400;
-    private static final int HEIGHT = 9600;
-    // TODO is the precision correct?
-    private final double precision = 1e7;
-    private final int latDegree = 20;
-    private final int lonDegree = 30;
     // for alternatives see #346
     private final String FILE_NAME_END = "_20101117_gmted_mea075";
 
     public GMTEDProvider() {
+        this("");
+    }
+
+    public GMTEDProvider(String cacheDir) {
         super("https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/topo/downloads/GMTED/Global_tiles_GMTED/075darcsec/mea/",
-                "/tmp/gmted",
-                "GraphHopper GMTEDReader");
+                cacheDir.isEmpty() ? "/tmp/gmted" : cacheDir,
+                "GraphHopper GMTEDReader",
+                14400, 9600,
+                20, 30);
     }
 
     public static void main(String[] args) {
@@ -143,103 +140,67 @@ public class GMTEDProvider extends AbstractTiffElevationProvider {
     }
 
     @Override
-    public double getEle(double lat, double lon) {
-        // Return fast, if there is no data available
-        if (lat > 84 || lat < -70)
-            return 0;
-
-        lat = (int) (lat * precision) / precision;
-        lon = (int) (lon * precision) / precision;
-        String name = getFileName(lat, lon);
-        // To lowercase and remove the directory and file ending so it works with the DataAccess
-        HeightTile demProvider = cacheData.get(name);
-        if (demProvider == null) {
-            if (!cacheDir.exists())
-                cacheDir.mkdirs();
-
-            int minLat = getMinLatForTile(lat);
-            int minLon = getMinLonForTile(lon);
-            // less restrictive against boundary checking
-            demProvider = new HeightTile(minLat, minLon, WIDTH, HEIGHT, lonDegree * precision, lonDegree, latDegree);
-            demProvider.setCalcMean(calcMean);
-
-            cacheData.put(name, demProvider);
-            DataAccess heights = getDirectory().find(name + ".gh");
-            demProvider.setHeights(heights);
-            boolean loadExisting = false;
-            try {
-                loadExisting = heights.loadExisting();
-            } catch (Exception ex) {
-                logger.warn("cannot load " + name + ", error: " + ex.getMessage());
-            }
-
-            if (!loadExisting) {
-                String zippedURL = baseUrl + "/" + getDownloadURL(lat, lon);
-                File file = new File(cacheDir, new File(name + ".tif").getName());
-
-                try {
-                    downloadFile(file, zippedURL);
-                } catch (IOException e) {
-                    demProvider.setSeaLevel(true);
-                    // use small size on disc and in-memory
-                    heights.setSegmentSize(100).create(10).
-                            flush();
-                    return 0;
-                }
-
-                // short == 2 bytes
-                heights.create(2 * WIDTH * HEIGHT);
-
-                Raster raster;
-                SeekableStream ss = null;
-                try {
-                    InputStream is = new FileInputStream(file);
-                    ss = SeekableStream.wrapInputStream(is, true);
-                    TIFFImageDecoder imageDecoder = new TIFFImageDecoder(ss, new TIFFDecodeParam());
-                    raster = imageDecoder.decodeAsRaster();
-                } catch (Exception e) {
-                    throw new RuntimeException("Can't decode " + file.getName(), e);
-                } finally {
-                    if (ss != null)
-                        close(ss);
-                }
-
-                fillDataAccessWithElevationData(raster, heights, WIDTH);
-
-            } // loadExisting
+    Raster generateRasterFromFile(File file, String tifName) {
+        SeekableStream ss = null;
+        try {
+            InputStream is = new FileInputStream(file);
+            ss = SeekableStream.wrapInputStream(is, true);
+            TIFFImageDecoder imageDecoder = new TIFFImageDecoder(ss, new TIFFDecodeParam());
+            return imageDecoder.decodeAsRaster();
+        } catch (Exception e) {
+            throw new RuntimeException("Can't decode " + file.getName(), e);
+        } finally {
+            if (ss != null)
+                close(ss);
         }
-
-        if (demProvider.isSeaLevel())
-            return 0;
-
-        return demProvider.getHeight(lat, lon);
     }
 
     int getMinLatForTile(double lat) {
-        return (int) (Math.floor((90 + lat) / latDegree) * latDegree) - 90;
+        return (int) (Math.floor((90 + lat) / LAT_DEGREE) * LAT_DEGREE) - 90;
     }
 
     int getMinLonForTile(double lon) {
-        return (int) (Math.floor((180 + lon) / lonDegree) * lonDegree) - 180;
+        return (int) (Math.floor((180 + lon) / LON_DEGREE) * LON_DEGREE) - 180;
+    }
+
+    private String getLonString(int lonInt) {
+        lonInt = Math.abs(lonInt);
+        String lonString = lonInt < 100 ? "0" : "";
+        if (lonInt < 10)
+            lonString += "0";
+        lonString += lonInt;
+        return lonString;
+    }
+
+    private String getLatString(int latInt) {
+        latInt = Math.abs(latInt);
+        String latString = latInt < 10 ? "0" : "";
+        latString += latInt;
+        return latString;
+    }
+
+    @Override
+    boolean isOutsideSupportedArea(double lat, double lon) {
+        return lat > 84 || lat < -70;
     }
 
-    // TODO it is a bit ugly that we have to duplicate the code with getDownloadURL, but since the DataAccess only allows lower case strings, but the files on the server are uppper cases, this creates too many issues
     String getFileName(double lat, double lon) {
         int lonInt = getMinLonForTile(lon);
         int latInt = getMinLatForTile(lat);
-        String north = getNorthString(latInt);
-        String east = getEastString(lonInt);
-        String lonString = String.format(Locale.ROOT, "%03d", Math.abs(lonInt));
-        return toLowerCase(String.format(Locale.ROOT, "%02d", Math.abs(latInt)) + north + lonString + east + FILE_NAME_END);
+        return toLowerCase(getLatString(latInt) + getNorthString(latInt) + getLonString(lonInt) + getEastString(lonInt) + FILE_NAME_END);
     }
 
     String getDownloadURL(double lat, double lon) {
         int lonInt = getMinLonForTile(lon);
         int latInt = getMinLatForTile(lat);
-        String north = getNorthString(latInt);
         String east = getEastString(lonInt);
-        String lonString = String.format(Locale.ROOT, "%03d", Math.abs(lonInt));
-        return east + lonString + "/" + String.format(Locale.ROOT, "%02d", Math.abs(latInt)) + north + lonString + east + FILE_NAME_END + ".tif";
+        String lonString = getLonString(lonInt);
+        return baseUrl + "/" + east + lonString + "/" + getLatString(latInt) + getNorthString(latInt) + lonString + east + FILE_NAME_END + ".tif";
+    }
+
+    @Override
+    String getFileNameOfLocalFile(double lat, double lon) {
+        return getFileName(lat, lon) + ".tif";
     }
 
     private String getNorthString(int lat) {
@@ -261,4 +222,4 @@ public class GMTEDProvider extends AbstractTiffElevationProvider {
         return "gmted";
     }
 
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/MultiSourceElevationProvider.java b/core/src/main/java/com/graphhopper/reader/dem/MultiSourceElevationProvider.java
index 6b7e2e13d..080cc0f38 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/MultiSourceElevationProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/MultiSourceElevationProvider.java
@@ -18,17 +18,6 @@
 package com.graphhopper.reader.dem;
 
 import com.graphhopper.storage.DAType;
-import com.graphhopper.storage.DataAccess;
-import com.graphhopper.util.Helper;
-import org.apache.xmlgraphics.image.codec.tiff.TIFFDecodeParam;
-import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
-import org.apache.xmlgraphics.image.codec.util.SeekableStream;
-
-import java.awt.image.Raster;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
 
 /**
  * The MultiSourceElevationProvider mixes different elevation providers to provide the best available elevation data
@@ -38,25 +27,31 @@ import java.io.InputStream;
  */
 public class MultiSourceElevationProvider implements ElevationProvider {
 
-    private CGIARProvider cgiarProvider;
-    private GMTEDProvider gmtedProvider;
+    // Usually a high resolution provider in the SRTM area
+    private ElevationProvider srtmProvider;
+    // The fallback provider that provides elevation data globally
+    private ElevationProvider globalProvider;
 
-    public MultiSourceElevationProvider(CGIARProvider cgiarProvider, GMTEDProvider gmtedProvider) {
-        this.cgiarProvider = cgiarProvider;
-        this.gmtedProvider = gmtedProvider;
+    public MultiSourceElevationProvider(ElevationProvider srtmProvider, ElevationProvider globalProvider) {
+        this.srtmProvider = srtmProvider;
+        this.globalProvider = globalProvider;
     }
 
     public MultiSourceElevationProvider() {
         this(new CGIARProvider(), new GMTEDProvider());
     }
 
+    public MultiSourceElevationProvider(String cacheDir) {
+        this(new CGIARProvider(cacheDir), new GMTEDProvider(cacheDir));
+    }
+
     @Override
     public double getEle(double lat, double lon) {
         // Sometimes the cgiar data north of 59.999 equals 0
         if (lat < 59.999 && lat > -56) {
-            return cgiarProvider.getEle(lat, lon);
+            return srtmProvider.getEle(lat, lon);
         }
-        return gmtedProvider.getEle(lat, lon);
+        return globalProvider.getEle(lat, lon);
     }
 
     /**
@@ -69,35 +64,34 @@ public class MultiSourceElevationProvider implements ElevationProvider {
         if (urls.length != 2) {
             throw new IllegalArgumentException("The base url must consist of two urls separated by a ';'. The first for cgiar, the second for gmted");
         }
-        cgiarProvider.setBaseURL(urls[0]);
-        gmtedProvider.setBaseURL(urls[1]);
-        return this;
-    }
-
-    @Override
-    public ElevationProvider setCacheDir(File cacheDir) {
-        cgiarProvider.setCacheDir(cacheDir);
-        gmtedProvider.setCacheDir(cacheDir);
+        srtmProvider.setBaseURL(urls[0]);
+        globalProvider.setBaseURL(urls[1]);
         return this;
     }
 
     @Override
     public ElevationProvider setDAType(DAType daType) {
-        cgiarProvider.setDAType(daType);
-        gmtedProvider.setDAType(daType);
+        srtmProvider.setDAType(daType);
+        globalProvider.setDAType(daType);
         return this;
     }
 
     @Override
     public void setCalcMean(boolean calcMean) {
-        cgiarProvider.setCalcMean(calcMean);
-        gmtedProvider.setCalcMean(calcMean);
+        srtmProvider.setCalcMean(calcMean);
+        globalProvider.setCalcMean(calcMean);
     }
 
     @Override
     public void release() {
-        cgiarProvider.release();
-        gmtedProvider.release();
+        srtmProvider.release();
+        globalProvider.release();
+    }
+
+    @Override
+    public void setAutoRemoveTemporaryFiles(boolean autoRemoveTemporary) {
+        srtmProvider.setAutoRemoveTemporaryFiles(autoRemoveTemporary);
+        globalProvider.setAutoRemoveTemporaryFiles(autoRemoveTemporary);
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/reader/dem/SRTMGL1Provider.java b/core/src/main/java/com/graphhopper/reader/dem/SRTMGL1Provider.java
new file mode 100644
index 000000000..f351e9243
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/reader/dem/SRTMGL1Provider.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for 
+ *  additional information regarding copyright ownership.
+ * 
+ *  GraphHopper GmbH licenses this file to you 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.
+ */
+package com.graphhopper.reader.dem;
+
+import com.graphhopper.util.Helper;
+
+import java.io.*;
+
+import static com.graphhopper.util.Helper.*;
+
+/**
+ * SRTMGL1 contains elevation data for most of the world with 1 arc second (~30m) accuracy.
+ * We use the mirror of OpenTopography, as the official SRTMGL1 download requires authentication.
+ * http://opentopo.sdsc.edu/raster?opentopoID=OTSRTM.082015.4326.1
+ * <p>
+ * TODO: In addition, NSF requires oral acknowledgment during all news media interviews.
+ * TODO: This is weird, we have to check if really want to use OpenTopography then, see: http://www.opentopography.org/citations
+ * <p>
+ * When using this data we have to acknowledge:
+ * This material is based on data services provided by the OpenTopography Facility with support from the
+ * National Science Foundation under NSF Award Numbers 1226353 & 1225810
+ * National Geospatial-Intelligence Agency (NGA) and the National Aeronautics and Space Administration (NASA), 2013,
+ * SRTMGL1: NASA Shuttle Radar Topography Mission Global 1 arc second V003. [Version]. NASA EOSDIS Land Processes DAAC,
+ * USGS Earth Resources Observation and Science (EROS) Center, Sioux Falls, South Dakota (https://lpdaac.usgs.gov),
+ * accessed 11 29, 2017, at https://doi.org/10.5067/measures/srtm/srtmgl1.003
+ * <p>
+ * Detailed information can be found here: https://lpdaac.usgs.gov/sites/default/files/public/measures/docs/NASA_SRTM_V3.pdf
+ *
+ * @author Robin Boldt
+ */
+public class SRTMGL1Provider extends AbstractSRTMElevationProvider {
+
+    private final int latDegree = 1;
+    private final int lonDegree = 1;
+
+    public SRTMGL1Provider() {
+        this("");
+    }
+
+    public SRTMGL1Provider(String cacheDir) {
+        super("https://cloud.sdsc.edu/v1/AUTH_opentopography/Raster/SRTM_GL1/SRTM_GL1_srtm/",
+                cacheDir.isEmpty() ? "/tmp/srtmgl1" : cacheDir,
+                "GraphHopper SRTMReader",
+                3601
+        );
+    }
+
+    public static void main(String[] args) throws IOException {
+        SRTMGL1Provider provider = new SRTMGL1Provider();
+        // 338
+        System.out.println(provider.getEle(49.949784, 11.57517));
+        // 468
+        System.out.println(provider.getEle(49.968668, 11.575127));
+        // 467
+        System.out.println(provider.getEle(49.968682, 11.574842));
+        // 3110
+        System.out.println(provider.getEle(-22.532854, -65.110474));
+        // 120
+        System.out.println(provider.getEle(38.065392, -87.099609));
+        // 1617
+        System.out.println(provider.getEle(40, -105.2277023));
+        System.out.println(provider.getEle(39.99999999, -105.2277023));
+        System.out.println(provider.getEle(39.9999999, -105.2277023));
+        System.out.println(provider.getEle(39.999999, -105.2277023));
+        // 1015
+        System.out.println(provider.getEle(47.468668, 14.575127));
+        // 1107
+        System.out.println(provider.getEle(47.467753, 14.573911));
+        // 1930
+        System.out.println(provider.getEle(46.468835, 12.578777));
+        // 844
+        System.out.println(provider.getEle(48.469123, 9.576393));
+    }
+
+    @Override
+    byte[] readFile(File file) throws IOException {
+        InputStream is = new FileInputStream(file);
+        BufferedInputStream buff = new BufferedInputStream(is);
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        byte[] buffer = new byte[0xFFFF];
+        int len;
+        while ((len = buff.read(buffer)) > 0) {
+            os.write(buffer, 0, len);
+        }
+        os.flush();
+        close(buff);
+        return os.toByteArray();
+    }
+
+    int getMinLatForTile(double lat) {
+        return (int) (Math.floor((90 + lat) / latDegree) * latDegree) - 90;
+    }
+
+    int getMinLonForTile(double lon) {
+        return (int) (Math.floor((180 + lon) / lonDegree) * lonDegree) - 180;
+    }
+
+    private String getLonString(int lonInt) {
+        lonInt = Math.abs(lonInt);
+        String lonString = lonInt < 100 ? "0" : "";
+        if (lonInt < 10)
+            lonString += "0";
+        lonString += lonInt;
+        return lonString;
+    }
+
+    private String getLatString(int latInt) {
+        latInt = Math.abs(latInt);
+        String latString = latInt < 10 ? "0" : "";
+        latString += latInt;
+        return latString;
+    }
+
+    String getFileName(double lat, double lon) {
+        int lonInt = getMinLonForTile(lon);
+        int latInt = getMinLatForTile(lat);
+        return toLowerCase(getNorthString(latInt) + getLatString(latInt) + getEastString(lonInt) + getLonString(lonInt));
+    }
+
+    String getDownloadURL(double lat, double lon) {
+        int lonInt = getMinLonForTile(lon);
+        int latInt = getMinLatForTile(lat);
+        String north = getNorthString(latInt);
+        String dir;
+        if (north.equals("N")) {
+            dir = "North/";
+            if (lat >= 30)
+                dir += "North_30_60/";
+            else
+                dir += "North_0_29/";
+        } else {
+            dir = "South/";
+        }
+
+        return dir + north + getLatString(latInt) + getEastString(lonInt) + getLonString(lonInt) + ".hgt";
+    }
+
+    private String getNorthString(int lat) {
+        if (lat < 0) {
+            return "S";
+        }
+        return "N";
+    }
+
+    private String getEastString(int lon) {
+        if (lon < 0) {
+            return "W";
+        }
+        return "E";
+    }
+
+    @Override
+    public String toString() {
+        return "srtmgl1";
+    }
+
+}
diff --git a/core/src/main/java/com/graphhopper/reader/dem/SRTMProvider.java b/core/src/main/java/com/graphhopper/reader/dem/SRTMProvider.java
index 74adffd0f..50a9fdb9d 100644
--- a/core/src/main/java/com/graphhopper/reader/dem/SRTMProvider.java
+++ b/core/src/main/java/com/graphhopper/reader/dem/SRTMProvider.java
@@ -18,18 +18,9 @@
 package com.graphhopper.reader.dem;
 
 import com.graphhopper.coll.GHIntObjectHashMap;
-import com.graphhopper.storage.DAType;
-import com.graphhopper.storage.DataAccess;
-import com.graphhopper.storage.Directory;
-import com.graphhopper.storage.GHDirectory;
-import com.graphhopper.util.BitUtil;
-import com.graphhopper.util.Downloader;
 import com.graphhopper.util.Helper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.*;
-import java.net.SocketTimeoutException;
 import java.util.zip.ZipInputStream;
 
 /**
@@ -43,52 +34,49 @@ import java.util.zip.ZipInputStream;
  *
  * @author Peter Karich
  */
-public class SRTMProvider implements ElevationProvider {
-    private static final BitUtil BIT_UTIL = BitUtil.BIG;
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-    private final int DEFAULT_WIDTH = 1201;
-    private final int WIDTH_BYTE_INDEX = 0;
-    // use a map as an array is not quite useful if we want to hold only parts of the world
-    private final GHIntObjectHashMap<HeightTile> cacheData = new GHIntObjectHashMap<HeightTile>();
+public class SRTMProvider extends AbstractSRTMElevationProvider {
     private final GHIntObjectHashMap<String> areas = new GHIntObjectHashMap<String>();
-    private final double precision = 1e7;
-    private final double invPrecision = 1 / precision;
-    private Directory dir;
-    private DAType daType = DAType.MMAP;
-    private Downloader downloader = new Downloader("GraphHopper SRTMReader").setTimeout(10000);
-    private File cacheDir = new File("/tmp/srtm");
-    // possible alternatives see #451
-    // http://mirror.ufs.ac.za/datasets/SRTM3/
-    //"http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/"
-    private String baseUrl = "https://srtm.kurviger.de/SRTM3/";
-    private boolean calcMean = false;
 
     public SRTMProvider() {
+        this("");
+    }
+
+    public SRTMProvider(String cacheDir) {
+        super(
+                "https://srtm.kurviger.de/SRTM3/",
+                cacheDir.isEmpty()? "/tmp/srtm": cacheDir,
+                "GraphHopper SRTMReader",
+                1201
+        );
         // move to explicit calls?
         init();
     }
 
     public static void main(String[] args) throws IOException {
         SRTMProvider provider = new SRTMProvider();
+        // 337
+        System.out.println(provider.getEle(49.949784, 11.57517));
+        // 466
+        System.out.println(provider.getEle(49.968668, 11.575127));
+        // 466
+        System.out.println(provider.getEle(49.968682, 11.574842));
+        // 3100
+        System.out.println(provider.getEle(-22.532854, -65.110474));
+        // 122
+        System.out.println(provider.getEle(38.065392, -87.099609));
+        // 1617
+        System.out.println(provider.getEle(40, -105.2277023));
+        System.out.println(provider.getEle(39.99999999, -105.2277023));
+        System.out.println(provider.getEle(39.9999999, -105.2277023));
+        System.out.println(provider.getEle(39.999999, -105.2277023));
         // 1046
         System.out.println(provider.getEle(47.468668, 14.575127));
         // 1113
         System.out.println(provider.getEle(47.467753, 14.573911));
-
         // 1946
         System.out.println(provider.getEle(46.468835, 12.578777));
-
         // 845
         System.out.println(provider.getEle(48.469123, 9.576393));
-
-        // 1113 vs new:
-        provider.setCalcMean(true);
-        System.out.println(provider.getEle(47.467753, 14.573911));
-    }
-
-    @Override
-    public void setCalcMean(boolean calcMean) {
-        this.calcMean = calcMean;
     }
 
     /**
@@ -121,52 +109,30 @@ public class SRTMProvider implements ElevationProvider {
         }
     }
 
-    // use int key instead of string for lower memory usage
-    private int calcIntKey(double lat, double lon) {
-        // we could use LinearKeyAlgo but this is simpler as we only need integer precision:
-        return (down(lat) + 90) * 1000 + down(lon) + 180;
-    }
-
-    public void setDownloader(Downloader downloader) {
-        this.downloader = downloader;
-    }
-
     @Override
-    public ElevationProvider setCacheDir(File cacheDir) {
-        if (cacheDir.exists() && !cacheDir.isDirectory())
-            throw new IllegalArgumentException("Cache path has to be a directory");
-
-        try {
-            this.cacheDir = cacheDir.getCanonicalFile();
-        } catch (IOException ex) {
-            throw new RuntimeException(ex);
-        }
-        return this;
+    public String toString() {
+        return "srtm";
     }
 
     @Override
-    public ElevationProvider setBaseURL(String baseUrl) {
-        if (baseUrl == null || baseUrl.isEmpty())
-            throw new IllegalArgumentException("baseUrl cannot be empty");
-
-        this.baseUrl = baseUrl;
-        return this;
+    byte[] readFile(File file) throws IOException {
+        InputStream is = new FileInputStream(file);
+        ZipInputStream zis = new ZipInputStream(is);
+        zis.getNextEntry();
+        BufferedInputStream buff = new BufferedInputStream(zis);
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        byte[] buffer = new byte[0xFFFF];
+        int len;
+        while ((len = buff.read(buffer)) > 0) {
+            os.write(buffer, 0, len);
+        }
+        os.flush();
+        Helper.close(buff);
+        return os.toByteArray();
     }
 
     @Override
-    public ElevationProvider setDAType(DAType daType) {
-        this.daType = daType;
-        return this;
-    }
-
-    int down(double val) {
-        int intVal = (int) val;
-        if (val >= 0 || intVal - val < invPrecision)
-            return intVal;
-        return intVal - 1;
-    }
-
-    String getFileString(double lat, double lon) {
+    String getFileName(double lat, double lon) {
         int intKey = calcIntKey(lat, lon);
         String str = areas.get(intKey);
         if (str == null)
@@ -198,118 +164,7 @@ public class SRTMProvider implements ElevationProvider {
     }
 
     @Override
-    public double getEle(double lat, double lon) {
-        // Return fast, if there is no data available
-        // See https://www2.jpl.nasa.gov/srtm/faq.html
-        if (lat >= 60 || lat <= -56)
-            return 0;
-
-        lat = (int) (lat * precision) / precision;
-        lon = (int) (lon * precision) / precision;
-        int intKey = calcIntKey(lat, lon);
-        HeightTile demProvider = cacheData.get(intKey);
-        if (demProvider != null)
-            return demProvider.getHeight(lat, lon);
-
-        if (!cacheDir.exists())
-            cacheDir.mkdirs();
-
-        String fileDetails = getFileString(lat, lon);
-        if (fileDetails == null)
-            return 0;
-
-        DataAccess heights = getDirectory().find("dem" + intKey);
-        boolean loadExisting = false;
-        try {
-            loadExisting = heights.loadExisting();
-        } catch (Exception ex) {
-            logger.warn("cannot load dem" + intKey + ", error:" + ex.getMessage());
-        }
-
-        if (!loadExisting)
-            updateHeightsFromZipFile(fileDetails, heights);
-
-        int width = (int) (Math.sqrt(heights.getHeader(WIDTH_BYTE_INDEX)) + 0.5);
-        if (width == 0)
-            width = DEFAULT_WIDTH;
-
-        demProvider = new HeightTile(down(lat), down(lon), width, width, precision, 1, 1);
-        cacheData.put(intKey, demProvider);
-        demProvider.setCalcMean(calcMean);
-        demProvider.setHeights(heights);
-        return demProvider.getHeight(lat, lon);
-    }
-
-    private void updateHeightsFromZipFile(String fileDetails, DataAccess heights) throws RuntimeException {
-        try {
-            byte[] bytes = getByteArrayFromZipFile(fileDetails);
-            heights.create(bytes.length);
-            for (int bytePos = 0; bytePos < bytes.length; bytePos += 2) {
-                short val = BIT_UTIL.toShort(bytes, bytePos);
-                if (val < -1000 || val > 12000)
-                    val = Short.MIN_VALUE;
-
-                heights.setShort(bytePos, val);
-            }
-            heights.setHeader(WIDTH_BYTE_INDEX, bytes.length / 2);
-            heights.flush();
-
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    private byte[] getByteArrayFromZipFile(String fileDetails) throws InterruptedException, FileNotFoundException, IOException {
-        String zippedURL = baseUrl + "/" + fileDetails + ".hgt.zip";
-        File file = new File(cacheDir, new File(zippedURL).getName());
-        InputStream is;
-        // get zip file if not already in cacheDir
-        if (!file.exists())
-            for (int i = 0; i < 3; i++) {
-                try {
-                    downloader.downloadFile(zippedURL, file.getAbsolutePath());
-                    break;
-                } catch (SocketTimeoutException ex) {
-                    // just try again after a little nap
-                    Thread.sleep(2000);
-                    continue;
-                }
-            }
-
-        is = new FileInputStream(file);
-        ZipInputStream zis = new ZipInputStream(is);
-        zis.getNextEntry();
-        BufferedInputStream buff = new BufferedInputStream(zis);
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        byte[] buffer = new byte[0xFFFF];
-        int len;
-        while ((len = buff.read(buffer)) > 0) {
-            os.write(buffer, 0, len);
-        }
-        os.flush();
-        Helper.close(buff);
-        return os.toByteArray();
-    }
-
-    @Override
-    public void release() {
-        cacheData.clear();
-
-        // for memory mapped type we create temporary unpacked files which should be removed
-        if (dir != null)
-            dir.clear();
-    }
-
-    @Override
-    public String toString() {
-        return "SRTM";
-    }
-
-    private Directory getDirectory() {
-        if (dir != null)
-            return dir;
-
-        logger.info(this.toString() + " Elevation Provider, from: " + baseUrl + ", to: " + cacheDir + ", as: " + daType);
-        return dir = new GHDirectory(cacheDir.getAbsolutePath(), daType);
+    String getDownloadURL(double lat, double lon) {
+        return getFileName(lat, lon) + ".hgt.zip";
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
index 4384b64b0..42ee44989 100644
--- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
@@ -453,10 +453,10 @@ public abstract class AbstractFlagEncoder implements FlagEncoder, TurnCostEncode
         }
         // seconds to hours
         double durationInHours = duration / 60d / 60d;
+        // Check if our graphhopper specific artificially created estimated_distance way tag is present
+        Number estimatedLength = way.getTag("estimated_distance", null);
         if (durationInHours > 0)
             try {
-                // Check if our graphhopper specific artificially created estimated_distance way tag is present
-                Number estimatedLength = way.getTag("estimated_distance", null);
                 if (estimatedLength != null) {
                     double estimatedLengthInKm = estimatedLength.doubleValue() / 1000;
                     // If duration AND distance is available we can calculate the speed more precisely
@@ -487,6 +487,8 @@ public abstract class AbstractFlagEncoder implements FlagEncoder, TurnCostEncode
             }
 
         if (durationInHours == 0) {
+            if(estimatedLength != null && estimatedLength.doubleValue() <= 300)
+                return speedEncoder.factor / 2;
             // unknown speed -> put penalty on ferry transport
             return UNKNOWN_DURATION_FERRY_SPEED;
         } else if (durationInHours > 1) {


Test patch:
diff --git a/core/src/test/java/com/graphhopper/reader/dem/CGIARProviderTest.java b/core/src/test/java/com/graphhopper/reader/dem/CGIARProviderTest.java
index d39bc7647..bfa55fc27 100644
--- a/core/src/test/java/com/graphhopper/reader/dem/CGIARProviderTest.java
+++ b/core/src/test/java/com/graphhopper/reader/dem/CGIARProviderTest.java
@@ -18,7 +18,9 @@
 package com.graphhopper.reader.dem;
 
 import com.graphhopper.util.Downloader;
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.io.File;
@@ -33,6 +35,7 @@ import static org.junit.Assert.assertTrue;
  * @author Peter Karich
  */
 public class CGIARProviderTest {
+    private double precision = .1;
     CGIARProvider instance;
 
     @Before
@@ -40,6 +43,11 @@ public class CGIARProviderTest {
         instance = new CGIARProvider();
     }
 
+    @After
+    public void tearDown() {
+        instance.release();
+    }
+
     @Test
     public void testDown() {
         assertEquals(50, instance.down(52.5));
@@ -103,4 +111,45 @@ public class CGIARProviderTest {
         file.delete();
         zipFile.delete();
     }
+
+    @Ignore
+    public void testGetEle() {
+        assertEquals(337, instance.getEle(49.949784, 11.57517), precision);
+        assertEquals(466, instance.getEle(49.968668, 11.575127), precision);
+        assertEquals(455, instance.getEle(49.968682, 11.574842), precision);
+        assertEquals(3134, instance.getEle(-22.532854, -65.110474), precision);
+        assertEquals(120, instance.getEle(38.065392, -87.099609), precision);
+        assertEquals(1615, instance.getEle(40, -105.2277023), precision);
+        assertEquals(1615, instance.getEle(39.99999999, -105.2277023), precision);
+        assertEquals(1615, instance.getEle(39.9999999, -105.2277023), precision);
+        assertEquals(1616, instance.getEle(39.999999, -105.2277023), precision);
+        assertEquals(986, instance.getEle(47.468668, 14.575127), precision);
+        assertEquals(1091, instance.getEle(47.467753, 14.573911), precision);
+        assertEquals(1951, instance.getEle(46.468835, 12.578777), precision);
+        assertEquals(841, instance.getEle(48.469123, 9.576393), precision);
+        assertEquals(Double.NaN, instance.getEle(56.4787319, 17.6118363), precision);
+        // Outside of SRTM covered area
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 19), precision);
+        assertEquals(0, instance.getEle(60.251, 18.805), precision);
+    }
+
+    @Ignore
+    public void testGetEleVerticalBorder() {
+        // Border between the tiles srtm_39_04 and srtm_39_03
+        assertEquals("srtm_39_04", instance.getFileName(44.999999, 11.5));
+        assertEquals(5, instance.getEle(44.999999, 11.5), precision);
+        assertEquals("srtm_39_03", instance.getFileName(45.000001, 11.5));
+        assertEquals(6, instance.getEle(45.000001, 11.5), precision);
+    }
+
+    @Ignore
+    public void testGetEleHorizontalBorder() {
+        // Border between the tiles N42E011 and N42E012
+        assertEquals("srtm_38_04", instance.getFileName(44.94, 9.999999));
+        assertEquals(48, instance.getEle(44.94, 9.999999), precision);
+        assertEquals("srtm_39_04", instance.getFileName(44.94, 10.000001));
+        assertEquals(48, instance.getEle(44.94, 10.000001), precision);
+    }
 }
diff --git a/core/src/test/java/com/graphhopper/reader/dem/GMTEDProviderTest.java b/core/src/test/java/com/graphhopper/reader/dem/GMTEDProviderTest.java
index 6c72cae7c..99ca59d90 100644
--- a/core/src/test/java/com/graphhopper/reader/dem/GMTEDProviderTest.java
+++ b/core/src/test/java/com/graphhopper/reader/dem/GMTEDProviderTest.java
@@ -18,7 +18,9 @@
 package com.graphhopper.reader.dem;
 
 import com.graphhopper.util.Downloader;
+import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.io.File;
@@ -33,6 +35,7 @@ import static org.junit.Assert.assertTrue;
  * @author Robin Boldt
  */
 public class GMTEDProviderTest {
+    private double precision = .1;
     GMTEDProvider instance;
 
     @Before
@@ -40,6 +43,11 @@ public class GMTEDProviderTest {
         instance = new GMTEDProvider();
     }
 
+    @After
+    public void tearDown() {
+        instance.release();
+    }
+
     @Test
     public void testMinLat() {
         assertEquals(50, instance.getMinLatForTile(52.5));
@@ -56,12 +64,12 @@ public class GMTEDProviderTest {
     @Test
     public void testGetDownloadUrl() {
         // Created a couple of random tests and compared to https://topotools.cr.usgs.gov/gmted_viewer/viewer.htm
-        assertEquals("E000/30N000E_20101117_gmted_mea075.tif", instance.getDownloadURL(42.940339, 11.953125));
-        assertEquals("W090/30N090W_20101117_gmted_mea075.tif", instance.getDownloadURL(38.548165, -77.167969));
-        assertEquals("W180/70N180W_20101117_gmted_mea075.tif", instance.getDownloadURL(74.116047, -169.277344));
-        assertEquals("W180/70S180W_20101117_gmted_mea075.tif", instance.getDownloadURL(-61.015725, -156.621094));
-        assertEquals("E150/70N150E_20101117_gmted_mea075.tif", instance.getDownloadURL(74.590108, 166.640625));
-        assertEquals("E150/70S150E_20101117_gmted_mea075.tif", instance.getDownloadURL(-61.015725, 162.949219));
+        assertTrue(instance.getDownloadURL(42.940339, 11.953125).contains("E000/30N000E_20101117_gmted_mea075.tif"));
+        assertTrue(instance.getDownloadURL(38.548165, -77.167969).contains("W090/30N090W_20101117_gmted_mea075.tif"));
+        assertTrue(instance.getDownloadURL(74.116047, -169.277344).contains("W180/70N180W_20101117_gmted_mea075.tif"));
+        assertTrue(instance.getDownloadURL(-61.015725, -156.621094).contains("W180/70S180W_20101117_gmted_mea075.tif"));
+        assertTrue(instance.getDownloadURL(74.590108, 166.640625).contains("E150/70N150E_20101117_gmted_mea075.tif"));
+        assertTrue(instance.getDownloadURL(-61.015725, 162.949219).contains("E150/70S150E_20101117_gmted_mea075.tif"));
     }
 
     @Test
@@ -110,4 +118,57 @@ public class GMTEDProviderTest {
         file.delete();
         zipFile.delete();
     }
-}
\ No newline at end of file
+
+    /*
+    Enabling this test requires you to change the pom.xml and increase the memory limit for running tests.
+    Change to: <argLine>-Xmx500m -Xms500m</argLine>
+    This test will download about 2gb of data.
+     */
+    @Ignore
+    public void testGetEle() {
+        assertEquals(339, instance.getEle(49.949784, 11.57517), precision);
+        assertEquals(438, instance.getEle(49.968668, 11.575127), precision);
+        assertEquals(432, instance.getEle(49.968682, 11.574842), precision);
+        assertEquals(3169, instance.getEle(-22.532854, -65.110474), precision);
+        assertEquals(124, instance.getEle(38.065392, -87.099609), precision);
+        assertEquals(1615, instance.getEle(40, -105.2277023), precision);
+        assertEquals(1618, instance.getEle(39.99999999, -105.2277023), precision);
+        assertEquals(1618, instance.getEle(39.9999999, -105.2277023), precision);
+        assertEquals(1618, instance.getEle(39.999999, -105.2277023), precision);
+        assertEquals(1070, instance.getEle(47.468668, 14.575127), precision);
+        assertEquals(1115, instance.getEle(47.467753, 14.573911), precision);
+        assertEquals(1990, instance.getEle(46.468835, 12.578777), precision);
+        assertEquals(841, instance.getEle(48.469123, 9.576393), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        // Outside of SRTM covered area
+        assertEquals(108, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 19), precision);
+        // Stor Roten
+        assertEquals(14, instance.getEle(60.251, 18.805), precision);
+
+    }
+
+    @Ignore
+    public void testGetEleVerticalBorder() {
+        // Border between the tiles 50n000e and 70n000e
+        assertEquals("50n000e_20101117_gmted_mea075", instance.getFileName(69.999999, 19.493));
+        assertEquals(268, instance.getEle(69.999999, 19.5249), precision);
+        assertEquals("70n000e_20101117_gmted_mea075", instance.getFileName(70, 19.493));
+        assertEquals(298, instance.getEle(70, 19.5249), precision);
+        // Second location at the border
+        assertEquals("50n000e_20101117_gmted_mea075", instance.getFileName(69.999999, 19.236));
+        assertEquals(245, instance.getEle(69.999999, 19.236), precision);
+        assertEquals("70n000e_20101117_gmted_mea075", instance.getFileName(70, 19.236));
+        assertEquals(241, instance.getEle(70, 19.236), precision);
+    }
+
+    @Ignore
+    public void testGetEleHorizontalBorder() {
+        // Border between the tiles 50n000e and 50n030e
+        assertEquals("50n000e_20101117_gmted_mea075", instance.getFileName(53, 29.999999));
+        assertEquals(143, instance.getEle(53, 29.999999), precision);
+        assertEquals("50n030e_20101117_gmted_mea075", instance.getFileName(53, 30.000001));
+        assertEquals(142, instance.getEle(53, 30.000001), precision);
+    }
+}
diff --git a/core/src/test/java/com/graphhopper/reader/dem/MultiSourceElevationProviderTest.java b/core/src/test/java/com/graphhopper/reader/dem/MultiSourceElevationProviderTest.java
index e8158db64..3e67de36e 100644
--- a/core/src/test/java/com/graphhopper/reader/dem/MultiSourceElevationProviderTest.java
+++ b/core/src/test/java/com/graphhopper/reader/dem/MultiSourceElevationProviderTest.java
@@ -17,7 +17,8 @@
  */
 package com.graphhopper.reader.dem;
 
-import org.junit.Before;
+import org.junit.After;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
@@ -28,8 +29,13 @@ import static org.junit.Assert.assertEquals;
 public class MultiSourceElevationProviderTest {
     MultiSourceElevationProvider instance;
 
-    @Before
-    public void setUp() {
+    @After
+    public void tearDown() {
+        instance.release();
+    }
+
+    @Test
+    public void testGetEleMocked() {
         instance = new MultiSourceElevationProvider(
                 new CGIARProvider() {
                     @Override
@@ -44,12 +50,42 @@ public class MultiSourceElevationProviderTest {
                     }
                 }
         );
-    }
 
-    @Test
-    public void testGetEle() {
         assertEquals(1, instance.getEle(0, 0), .1);
         assertEquals(2, instance.getEle(60.0001, 0), .1);
         assertEquals(2, instance.getEle(-56.0001, 0), .1);
     }
-}
\ No newline at end of file
+
+    /*
+    Enabling this test requires you to change the pom.xml and increase the memory limit for running tests.
+    Change to: <argLine>-Xmx500m -Xms500m</argLine>
+    */
+    @Ignore
+    public void testGetEle() {
+        instance = new MultiSourceElevationProvider();
+        double precision = .1;
+        // The first part is copied from the SRTMGL1ProviderTest
+        assertEquals(338, instance.getEle(49.949784, 11.57517), precision);
+        assertEquals(468, instance.getEle(49.968668, 11.575127), precision);
+        assertEquals(467, instance.getEle(49.968682, 11.574842), precision);
+        assertEquals(3110, instance.getEle(-22.532854, -65.110474), precision);
+        assertEquals(120, instance.getEle(38.065392, -87.099609), precision);
+        assertEquals(1617, instance.getEle(40, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.99999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.9999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.999999, -105.2277023), precision);
+        assertEquals(1015, instance.getEle(47.468668, 14.575127), precision);
+        assertEquals(1107, instance.getEle(47.467753, 14.573911), precision);
+        assertEquals(1930, instance.getEle(46.468835, 12.578777), precision);
+        assertEquals(844, instance.getEle(48.469123, 9.576393), precision);
+        // The file for this coordinate does not exist, but there is a ferry tagged in OSM
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        // The second part is copied from the GMTEDProviderTest
+        // Outside of SRTM covered area
+        assertEquals(108, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 19), precision);
+        // Stor Roten
+        assertEquals(14, instance.getEle(60.251, 18.805), precision);
+    }
+}
diff --git a/core/src/test/java/com/graphhopper/reader/dem/SRTMGL1ProviderTest.java b/core/src/test/java/com/graphhopper/reader/dem/SRTMGL1ProviderTest.java
new file mode 100644
index 000000000..8510fb59d
--- /dev/null
+++ b/core/src/test/java/com/graphhopper/reader/dem/SRTMGL1ProviderTest.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for 
+ *  additional information regarding copyright ownership.
+ * 
+ *  GraphHopper GmbH licenses this file to you 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.
+ */
+package com.graphhopper.reader.dem;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author Robin Boldt
+ */
+public class SRTMGL1ProviderTest {
+    private double precision = .1;
+    SRTMGL1Provider instance;
+
+    @Before
+    public void setUp() {
+        instance = new SRTMGL1Provider();
+    }
+
+    @After
+    public void tearDown() {
+        instance.release();
+    }
+
+    @Test
+    public void testMinLat() {
+        assertEquals(52, instance.getMinLatForTile(52.5));
+        assertEquals(29, instance.getMinLatForTile(29.9));
+        assertEquals(-60, instance.getMinLatForTile(-59.9));
+    }
+
+    @Test
+    public void testMinLon() {
+        assertEquals(-60, instance.getMinLonForTile(-59.9));
+        assertEquals(0, instance.getMinLonForTile(0.9));
+    }
+
+    @Test
+    public void testGetDownloadUrl() {
+        // Created a couple of random tests and compared to https://topotools.cr.usgs.gov/gmted_viewer/viewer.htm
+        assertEquals("North/North_30_60/N42E011.hgt", instance.getDownloadURL(42.940339, 11.953125));
+        assertEquals("North/North_30_60/N38W078.hgt", instance.getDownloadURL(38.548165, -77.167969));
+        assertEquals("North/North_0_29/N14W005.hgt", instance.getDownloadURL(14.116047, -4.277344));
+        assertEquals("South/S52W058.hgt", instance.getDownloadURL(-51.015725, -57.621094));
+        assertEquals("North/North_0_29/N24E120.hgt", instance.getDownloadURL(24.590108, 120.640625));
+        assertEquals("South/S42W063.hgt", instance.getDownloadURL(-41.015725, -62.949219));
+    }
+
+    @Test
+    public void testGetFileName() {
+        assertEquals("n42e011", instance.getFileName(42.940339, 11.953125));
+        assertEquals("n38w078", instance.getFileName(38.548165, -77.167969));
+        assertEquals("n14w005", instance.getFileName(14.116047, -4.277344));
+        assertEquals("s52w058", instance.getFileName(-51.015725, -57.621094));
+        assertEquals("n24e120", instance.getFileName(24.590108, 120.640625));
+        assertEquals("s42w063", instance.getFileName(-41.015725, -62.949219));
+    }
+
+    @Ignore
+    public void testGetEle() {
+        assertEquals(338, instance.getEle(49.949784, 11.57517), precision);
+        assertEquals(468, instance.getEle(49.968668, 11.575127), precision);
+        assertEquals(467, instance.getEle(49.968682, 11.574842), precision);
+        assertEquals(3110, instance.getEle(-22.532854, -65.110474), precision);
+        assertEquals(120, instance.getEle(38.065392, -87.099609), precision);
+        assertEquals(1617, instance.getEle(40, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.99999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.9999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.999999, -105.2277023), precision);
+        assertEquals(1015, instance.getEle(47.468668, 14.575127), precision);
+        assertEquals(1107, instance.getEle(47.467753, 14.573911), precision);
+        assertEquals(1930, instance.getEle(46.468835, 12.578777), precision);
+        assertEquals(844, instance.getEle(48.469123, 9.576393), precision);
+        // The file for this coordinate does not exist, but there is a ferry tagged in OSM
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        // Outside of SRTM covered area
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 19), precision);
+        assertEquals(0, instance.getEle(60.251, 18.805), precision);
+    }
+
+    @Ignore
+    public void testGetEleVerticalBorder() {
+        // Border between the tiles n42e011 and n43e011
+        assertEquals("n42e011", instance.getFileName(42.999999, 11.48));
+        assertEquals(420, instance.getEle(42.999999, 11.48), precision);
+        assertEquals("n43e011", instance.getFileName(43.000001, 11.48));
+        assertEquals(420, instance.getEle(43.000001, 11.48), precision);
+    }
+
+    @Ignore
+    public void testGetEleHorizontalBorder() {
+        // Border between the tiles n42e011 and n42e012
+        assertEquals("n42e011", instance.getFileName(42.1, 11.999999));
+        assertEquals(324, instance.getEle(42.1, 11.999999), precision);
+        assertEquals("n42e012", instance.getFileName(42.1, 12.000001));
+        assertEquals(324, instance.getEle(42.1, 12.000001), precision);
+    }
+
+}
diff --git a/core/src/test/java/com/graphhopper/reader/dem/SRTMProviderTest.java b/core/src/test/java/com/graphhopper/reader/dem/SRTMProviderTest.java
index 83fd21588..0352f7f1d 100644
--- a/core/src/test/java/com/graphhopper/reader/dem/SRTMProviderTest.java
+++ b/core/src/test/java/com/graphhopper/reader/dem/SRTMProviderTest.java
@@ -17,13 +17,11 @@
  */
 package com.graphhopper.reader.dem;
 
-import com.graphhopper.storage.DAType;
-import com.graphhopper.util.Constants;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
-import java.io.File;
 import java.io.IOException;
 
 import static org.junit.Assert.assertEquals;
@@ -32,6 +30,7 @@ import static org.junit.Assert.assertEquals;
  * @author Peter Karich
  */
 public class SRTMProviderTest {
+    private double precision = .1;
     SRTMProvider instance;
 
     @Before
@@ -46,20 +45,20 @@ public class SRTMProviderTest {
 
     @Test
     public void testGetFileString() {
-        assertEquals("Eurasia/N49E011", instance.getFileString(49, 11));
-        assertEquals("Eurasia/N52W002", instance.getFileString(52.268157, -1.230469));
-        assertEquals("Africa/S06E034", instance.getFileString(-5.965754, 34.804687));
-        assertEquals("Australia/S29E131", instance.getFileString(-28.304381, 131.484375));
-        assertEquals("South_America/S09W045", instance.getFileString(-9, -45));
-        assertEquals("South_America/S10W046", instance.getFileString(-9.1, -45.1));
-        assertEquals("South_America/S10W045", instance.getFileString(-9.6, -45));
-        assertEquals("South_America/S28W071", instance.getFileString(-28, -71));
-        assertEquals("South_America/S29W072", instance.getFileString(-28.88316, -71.070557));
+        assertEquals("Eurasia/N49E011", instance.getFileName(49, 11));
+        assertEquals("Eurasia/N52W002", instance.getFileName(52.268157, -1.230469));
+        assertEquals("Africa/S06E034", instance.getFileName(-5.965754, 34.804687));
+        assertEquals("Australia/S29E131", instance.getFileName(-28.304381, 131.484375));
+        assertEquals("South_America/S09W045", instance.getFileName(-9, -45));
+        assertEquals("South_America/S10W046", instance.getFileName(-9.1, -45.1));
+        assertEquals("South_America/S10W045", instance.getFileName(-9.6, -45));
+        assertEquals("South_America/S28W071", instance.getFileName(-28, -71));
+        assertEquals("South_America/S29W072", instance.getFileName(-28.88316, -71.070557));
     }
 
     @Test
     public void testGetHeight() throws IOException {
-        instance.setCacheDir(new File("./files/"));
+        instance = new SRTMProvider("./files/");
         // easy to verify orientation of tile:
 //        instance.getEle(43, 13);
 
@@ -88,7 +87,7 @@ public class SRTMProviderTest {
 
     @Test
     public void testGetHeight_issue545() throws IOException {
-        instance.setCacheDir(new File("./files/"));
+        instance = new SRTMProvider("./files/");
 
         // test different precision of the elevation file (3600)
         assertEquals(84, instance.getEle(48.003878, -124.660492), 1e-1);
@@ -96,7 +95,53 @@ public class SRTMProviderTest {
 
     @Test
     public void testGetHeightMMap() throws IOException {
-        instance.setCacheDir(new File("./files/"));
+        instance = new SRTMProvider("./files/");
         assertEquals(161, instance.getEle(55.8943144, -3), 1e-1);
     }
+
+    @Ignore
+    public void testGetEle() {
+        instance = new SRTMProvider();
+        assertEquals(337, instance.getEle(49.949784, 11.57517), precision);
+        assertEquals(466, instance.getEle(49.968668, 11.575127), precision);
+        assertEquals(466, instance.getEle(49.968682, 11.574842), precision);
+        assertEquals(3100, instance.getEle(-22.532854, -65.110474), precision);
+        assertEquals(122, instance.getEle(38.065392, -87.099609), precision);
+        assertEquals(1617, instance.getEle(40, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.99999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.9999999, -105.2277023), precision);
+        assertEquals(1617, instance.getEle(39.999999, -105.2277023), precision);
+        assertEquals(1046, instance.getEle(47.468668, 14.575127), precision);
+        assertEquals(1113, instance.getEle(47.467753, 14.573911), precision);
+        assertEquals(1946, instance.getEle(46.468835, 12.578777), precision);
+        assertEquals(845, instance.getEle(48.469123, 9.576393), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        assertEquals(0, instance.getEle(56.4787319, 17.6118363), precision);
+        // Outside of SRTM covered area
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 16), precision);
+        assertEquals(0, instance.getEle(60.0000001, 19), precision);
+        assertEquals(0, instance.getEle(60.251, 18.805), precision);
+    }
+
+    @Ignore
+    public void testGetEleVerticalBorder() {
+        instance = new SRTMProvider();
+        // Border between the tiles N42E011 and N43E011
+        assertEquals("Eurasia/N42E011", instance.getFileName(42.999999, 11.48));
+        assertEquals(419, instance.getEle(42.999999, 11.48), precision);
+        assertEquals("Eurasia/N43E011", instance.getFileName(43.000001, 11.48));
+        assertEquals(419, instance.getEle(43.000001, 11.48), precision);
+    }
+
+    @Ignore
+    public void testGetEleHorizontalBorder() {
+        instance = new SRTMProvider();
+        // Border between the tiles N42E011 and N42E012
+        assertEquals("Eurasia/N42E011", instance.getFileName(42.1, 11.999999));
+        assertEquals(324, instance.getEle(42.1, 11.999999), precision);
+        assertEquals("Eurasia/N42E012", instance.getFileName(42.1, 12.000001));
+        assertEquals(324, instance.getEle(42.1, 12.000001), precision);
+    }
+
 }
diff --git a/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
index 43f2b7aee..ae01cd3d9 100644
--- a/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
@@ -447,7 +447,7 @@ public class CarFlagEncoderTest {
         // accept
         assertTrue(encoder.acceptWay(way) > 0);
         // We have ignored the unrealisitc long duration and take the unknown speed
-        assertEquals(5, encoder.getFerrySpeed(way), 1e-1);
+        assertEquals(2.5, encoder.getFerrySpeed(way), 1e-1);
     }
 
     @Test
@@ -619,4 +619,16 @@ public class CarFlagEncoderTest {
         assertEquals(30, encoder.applyBadSurfaceSpeed(way, 90), 1e-1);
 
     }
+
+    @Test
+    public void testIssue_1256() {
+        ReaderWay way = new ReaderWay(1);
+        way.setTag("route", "ferry");
+        way.setTag("estimated_distance", 257);
+
+        CarFlagEncoder lowFactorCar = new CarFlagEncoder(10, 1, 0);
+        lowFactorCar.defineWayBits(0,0);
+        assertEquals(2.5, encoder.getFerrySpeed(way), .1);
+        assertEquals(.5, lowFactorCar.getFerrySpeed(way), .1);
+    }
 }
diff --git a/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java b/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
index f8f929795..4f47b7a04 100644
--- a/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
+++ b/reader-gtfs/src/test/java/com/graphhopper/RealtimeIT.java
@@ -374,4 +374,4 @@ public class RealtimeIT {
     }
 
 
-}
+}
\ No newline at end of file
diff --git a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
index e1ca2b6d7..ae39ec15c 100644
--- a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
@@ -561,7 +561,7 @@ public class GraphHopperIT {
                 setGraphHopperLocation(tmpGraphFile).
                 setEncodingManager(new EncodingManager(importVehicles));
 
-        tmpHopper.setElevationProvider(new SRTMProvider().setCacheDir(new File(DIR)));
+        tmpHopper.setElevationProvider(new SRTMProvider(DIR));
         tmpHopper.importOrLoad();
 
         GHResponse rsp = tmpHopper.route(new GHRequest(43.730729, 7.421288, 43.727697, 7.419199).
@@ -611,7 +611,7 @@ public class GraphHopperIT {
                 .setCHEnabled(false).setGraphHopperLocation(tmpGraphFile)
                 .setEncodingManager(new EncodingManager(importVehicles, 8));
 
-        tmpHopper.setElevationProvider(new SRTMProvider().setCacheDir(new File(DIR)));
+        tmpHopper.setElevationProvider(new SRTMProvider(DIR));
         tmpHopper.importOrLoad();
 
         GHResponse rsp = tmpHopper.route(new GHRequest(43.74056471749763, 7.4299266210693755,
@@ -637,7 +637,7 @@ public class GraphHopperIT {
                 .setCHEnabled(false).setGraphHopperLocation(tmpGraphFile)
                 .setEncodingManager(new EncodingManager(genericImportVehicles, 8));
 
-        tmpHopper.setElevationProvider(new SRTMProvider().setCacheDir(new File(DIR)));
+        tmpHopper.setElevationProvider(new SRTMProvider(DIR));
         tmpHopper.importOrLoad();
 
         GHResponse rsp = tmpHopper.route(new GHRequest(43.74056471749763, 7.4299266210693755,
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
index 61efc5217..be7a6d001 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
@@ -647,8 +647,7 @@ public class OSMReaderTest {
     public void testReadEleFromDataProvider() {
         GraphHopper hopper = new GraphHopperFacade("test-osm5.xml");
         // get N10E046.hgt.zip
-        ElevationProvider provider = new SRTMProvider();
-        provider.setCacheDir(new File(GraphHopperIT.DIR));
+        ElevationProvider provider = new SRTMProvider(GraphHopperIT.DIR);
         hopper.setElevationProvider(provider);
         hopper.importOrLoad();
 
diff --git a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
index 359476b86..1f53faf8c 100644
--- a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
@@ -536,7 +536,7 @@ public class RoutingAlgorithmWithOSMIT {
                         setEnabled(true).setDisablingAllowed(true);
 
             if (is3D)
-                hopper.setElevationProvider(new SRTMProvider().setCacheDir(new File(DIR)));
+                hopper.setElevationProvider(new SRTMProvider(DIR));
 
             hopper.importOrLoad();