Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java	(revision 35966)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java	(revision 35967)
@@ -20,5 +20,4 @@
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.coor.ILatLon;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
@@ -83,5 +82,5 @@
     }
 
-    public static Bounds read(File file) throws FileNotFoundException, IOException {
+    public static Bounds read(File file) throws IOException {
         String location = file.getName();
         for (String ext : COMPRESSION_EXT) {
@@ -91,9 +90,9 @@
         // Overwrite the cache file (assume that is desired)
         cache.put(location, sb);
-        Pattern pattern = Pattern.compile("(N|S)([0-9]{2})(E|W)([0-9]{3})");
+        Pattern pattern = Pattern.compile("([NS])(\\d{2})([EW])(\\d{3})");
         Matcher matcher = pattern.matcher(location);
         if (matcher.lookingAt()) {
-            int lat = (matcher.group(1) == "S" ? -1 : 1) * Integer.parseInt(matcher.group(2));
-            int lon = (matcher.group(3) == "W" ? -1 : 1) * Integer.parseInt(matcher.group(4));
+            int lat = ("S".equals(matcher.group(1)) ? -1 : 1) * Integer.parseInt(matcher.group(2));
+            int lon = ("W".equals(matcher.group(3)) ? -1 : 1) * Integer.parseInt(matcher.group(4));
             return new Bounds(lat, lon, lat + 1, lon + 1);
         }
@@ -101,5 +100,5 @@
     }
 
-    private static short[][] readHgtFile(String file) throws FileNotFoundException, IOException {
+    private static short[][] readHgtFile(String file) throws IOException {
         CheckParameterUtil.ensureParameterNotNull(file);
 
@@ -135,5 +134,5 @@
      * @return the elevation value or <code>Double.NaN</code>, if no value is present
      */
-    public static double readElevation(LatLon coor) {
+    public static double readElevation(ILatLon coor) {
         String tag = getHgtFileName(coor);
         return readElevation(coor, tag);
@@ -205,14 +204,14 @@
         double lonDegrees = latLon.lon();
 
-        float fraction = ((float) SRTM_EXTENT) / mapSize;
-        int latitude = (int) Math.floor(Math.abs(latDegrees - (int) latDegrees) / fraction);
-        int longitude = (int) Math.floor(Math.abs(lonDegrees - (int) lonDegrees) / fraction);
+        float fraction = ((float) SRTM_EXTENT) / (mapSize - 1);
+        int latitude = (int) Math.round(frac(latDegrees) / fraction);
+        int longitude = (int) Math.round(frac(lonDegrees) / fraction);
         if (latDegrees >= 0)
         {
-            latitude = mapSize - 1 - latitude;
+            latitude = mapSize - latitude - 1;
         }
         if (lonDegrees < 0)
         {
-            longitude = mapSize - 1 - longitude;
+            longitude = mapSize - longitude - 1;
         }
         return new int[] { latitude, longitude };
@@ -243,5 +242,5 @@
         }
 
-        return latPref + lat + lonPref + lon + HGT_EXT;
+        return String.format("%s%2d%s%03d" + HGT_EXT, latPref, lat, lonPref, lon);
     }
 
Index: applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/EleVertexTest.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/EleVertexTest.java	(revision 35967)
+++ applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/EleVertexTest.java	(revision 35967)
@@ -0,0 +1,115 @@
+package org.openstreetmap.josm.plugins.elevation;// License: GPL. For details, see LICENSE file.
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.awt.Color;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.plugins.elevation.grid.EleCoordinate;
+import org.openstreetmap.josm.plugins.elevation.grid.EleVertex;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.tools.Logging;
+
+@BasicPreferences
+class EleVertexTest {
+
+    private static final double EPS = 1e-10;
+
+    @Test
+    void testDivide() {
+        EleCoordinate p1 = new EleCoordinate(30.0, 30.0, 100.0);
+        EleCoordinate p2 = new EleCoordinate(35.0, 30.0, 120.0);
+        EleCoordinate p3 = new EleCoordinate(35.0, 40.0, 110.0);
+        EleVertex ev = new EleVertex(p1, p2, p3);
+
+        List<EleVertex> list = ev.divide();
+
+        assertEquals(2, list.size());
+
+        // 1st vertex (p1, p2, pN  105m)
+        EleVertex v1 = list.get(0);
+        assertEquals(325 / 3D, v1.getEle(), EPS);
+        assertCoorEq(v1, 30D, 30D, 0);
+        assertCoorEq(v1, 30D, 35D, 1);
+        assertCoorEq(v1, 35D, 32.5D, 2);
+
+        // 2nd vertex (p3, p2, pN = 105m)
+        EleVertex v2 = list.get(1);
+
+        assertEquals(335/3D, v2.getEle(), EPS);
+        assertCoorEq(v2, 40D, 35D, 0);
+        assertCoorEq(v2, 30D, 35D, 1);
+        assertCoorEq(v2, 35D, 32.5D, 2);
+    }
+
+    @Test
+    void testSimpleRecurse() {
+        EleCoordinate c1 = new EleCoordinate(new LatLon(50.8328, 8.1337), 300);
+        EleCoordinate c2 = new EleCoordinate(new LatLon(50.8328, 7.9217), 200);
+        EleCoordinate c3 = new EleCoordinate(new LatLon(50.9558, 7.9217), 400);
+        /*EleCoordinate c4 =*/ new EleCoordinate(new LatLon(50.5767627, 9.1938483), 100);
+
+        EleVertex v1 = new EleVertex(c1, c2, c3);
+        Logging.debug("Start recurse");
+        recurse(v1, 0);
+    }
+
+    private void recurse(EleVertex v, int depth) {
+        if (!v.isFinished() && depth < 100) {
+            Logging.trace("\tDivide: " + v);
+            List<EleVertex> list = v.divide();
+            assertNotNull(list);
+            assertEquals(2, list.size());
+            assertTrue(depth < 50); //, "Too many recursions?");
+            for (EleVertex eleVertex : list) {
+                //System.out.println("\t\tRecurse: " + eleVertex);
+                assertTrue(eleVertex.getArea() < v.getArea(), "Area is larger " + v.getArea() + " > " + eleVertex.getArea());
+                recurse(eleVertex, depth + 1);
+            }
+        } else {
+            Logging.debug("Finished: " + depth);
+        }
+    }
+    /*
+    public void testRenderer() {
+
+    // Staufenberg, Hessen
+    // Ulrichstein, Hessen
+    GridRenderer er = new GridRenderer("Ele", new Bounds(
+        new LatLon(50.6607106, 8.7337029),
+        new LatLon(50.5767627, 9.1938483)), null);
+
+    er.run();
+    }*/
+
+    @Test
+    public void testColorMap() {
+        ColorMap testMap = ColorMap.create("Test", new Color[]{Color.white, Color.black}, new int[]{0, 1000});
+
+        // range test
+        Color c1 = testMap.getColor(-100);
+        assertEquals(Color.white, c1);
+        // range test
+        Color c2 = testMap.getColor(1100);
+        assertEquals(Color.black, c2);
+        // test mid (RGB 128, 128, 128)
+        Color c3 = testMap.getColor(500);
+        assertEquals(Color.gray, c3);
+
+        // test 0.75 (RGB 64 x 3)
+        Color c4 = testMap.getColor(749);
+        assertEquals(Color.darkGray, c4);
+        // test 0.25 (RGB 192 x 3)
+        Color c5 = testMap.getColor(249);
+        assertEquals(Color.lightGray, c5);
+    }
+
+    private void assertCoorEq(EleVertex v1, double x, double y, int n) {
+        assertEquals(x, v1.get(n).getX(), EPS);
+        assertEquals(y, v1.get(n).getY(), EPS);
+    }
+}
Index: applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/HgtReaderTest.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/HgtReaderTest.java	(revision 35967)
+++ applications/editors/josm/plugins/ElevationProfile/test/unit/org/openstreetmap/josm/plugins/elevation/HgtReaderTest.java	(revision 35967)
@@ -0,0 +1,81 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.plugins.elevation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.tools.Logging;
+
+@BasicPreferences
+class HgtReaderTest {
+
+    /**
+     * Setup test.
+     * @throws IOException if SRTM files cannot be installed
+     */
+    @BeforeEach
+    void setUp() throws IOException {
+        // Install SRTM files to plugin directory
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(TestUtils.getTestDataRoot()), "*.hgt")) {
+            Path dir = Config.getDirs().getUserDataDirectory(true).toPath().resolve("elevation");
+
+            if (!Files.exists(dir)) {
+                Files.createDirectory(dir);
+            }
+            for (Path src: stream) {
+                Path dst = dir.resolve(src.getFileName());
+                if (!Files.exists(dst)) {
+                    Files.copy(src, dst);
+                }
+            }
+        } catch (DirectoryIteratorException ex) {
+            // I/O error encounted during the iteration, the cause is an IOException
+            throw ex.getCause();
+        }
+    }
+    static Stream<Arguments> testHgtData() {
+        return Stream.of(
+            // Staufenberg, Hessen
+            Arguments.of(50.6607106, 8.7337029, "N50E008.hgt", 199),
+            // Ulrichstein, Hessen
+            Arguments.of(50.5767627, 9.1938483, "N50E009.hgt", 560),
+            // Fujijama
+            //testHgtData(35.360555, 138.727777, "N35E138.hgt", 3741),
+            // Some random location in the middle of a file
+            Arguments.of(50.5, 8.5, "N50E008.hgt", 274),
+            Arguments.of(50.0000001, 8.999999, "N50E008.hgt", 132)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void testHgtData(final double lat, final double lon,
+            final String expTag, final int expHeight) {
+        LatLon l = new LatLon(lat, lon);
+        String text = HgtReader.getHgtFileName(l);
+
+        assertEquals(expTag, text);
+
+        double d = HgtReader.getElevationFromHgt(l);
+        Logging.trace(Double.toString(d));
+        assertFalse(Double.isNaN(d), "Data missing or void for coor " + l);
+
+        assertEquals(expHeight, (int) d);
+    }
+}
