Ignore:
Timestamp:
2022-04-27T21:18:31+02:00 (3 years ago)
Author:
taylor.smock
Message:

Fix #21575: Read compressed SRTM files

This also added an importer for HGT (SRTM) files, removed the arc-second
resolution limit, and updated deprecated methods.

As a result of updating the deprecated methods, this inadvertently fixed #21006.

Location:
applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java

    r35165 r35964  
    66import java.util.GregorianCalendar;
    77import java.util.List;
     8import java.util.Optional;
    89
    910import org.openstreetmap.josm.data.Bounds;
    1011import org.openstreetmap.josm.data.SystemOfMeasurement;
     12import org.openstreetmap.josm.data.coor.ILatLon;
    1113import org.openstreetmap.josm.data.coor.LatLon;
    1214import org.openstreetmap.josm.data.gpx.WayPoint;
     
    3436
    3537    private static GeoidCorrectionKind geoidKind = GeoidCorrectionKind.None;
    36 
    37     /** The HGT reader instance. */
    38     private static final HgtReader hgt = new HgtReader();
    3938
    4039    /**
     
    166165     *         not height attribute.
    167166     */
    168     public static double getSrtmElevation(LatLon ll) {
     167    public static double getSrtmElevation(ILatLon ll) {
    169168        if (ll != null) {
    170169            // Try to read data from SRTM file
    171170            // TODO: Option to switch this off
    172             double eleHgt = hgt.getElevationFromHgt(ll);
     171            double eleHgt = HgtReader.getElevationFromHgt(ll);
    173172
    174173            if (isValidElevation(eleHgt)) {
     
    177176        }
    178177        return NO_ELEVATION;
     178    }
     179
     180    /**
     181     * Get the bounds for the pixel elevation for the latitude
     182     * @param location The location to get
     183     * @return The bounds for the elevation area
     184     */
     185    public static Optional<Bounds> getBounds(ILatLon location) {
     186        if (location != null) {
     187            return HgtReader.getBounds(location);
     188        }
     189        return Optional.empty();
    179190    }
    180191
     
    252263
    253264        Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
    254         calendar.setTime(wpt.getDate());  // assigns calendar to given date
     265        calendar.setTimeInMillis(wpt.getTimeInMillis()); // assigns calendar to given date
    255266        return calendar.get(Calendar.HOUR_OF_DAY);
    256267    }
     
    263274
    264275        Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
    265         calendar.setTime(wpt.getDate());  // assigns calendar to given date
     276        calendar.setTimeInMillis(wpt.getTimeInMillis()); // assigns calendar to given date
    266277        return calendar.get(Calendar.MINUTE);
    267278    }
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationProfilePlugin.java

    r33815 r35964  
    66import java.awt.Color;
    77
     8import org.openstreetmap.josm.actions.ExtensionFileFilter;
    89import org.openstreetmap.josm.gui.IconToggleButton;
    910import org.openstreetmap.josm.gui.MainApplication;
     
    3334
    3435        createColorMaps();
     36        ExtensionFileFilter.addImporter(new HgtFileImporter());
    3537
    3638        // TODO: Disable this view as long as it is not stable
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java

    r35165 r35964  
    33
    44import java.io.File;
    5 import java.io.FileInputStream;
    65import java.io.FileNotFoundException;
     6import java.io.IOException;
     7import java.io.InputStream;
    78import java.nio.ByteBuffer;
    89import java.nio.ByteOrder;
    9 import java.nio.ShortBuffer;
    10 import java.nio.channels.FileChannel;
     10import java.nio.file.Paths;
     11import java.util.Arrays;
    1112import java.util.HashMap;
    12 
     13import java.util.List;
     14import java.util.Optional;
     15import java.util.regex.Matcher;
     16import java.util.regex.Pattern;
     17
     18import org.apache.commons.compress.utils.IOUtils;
     19import org.openstreetmap.josm.data.Bounds;
    1320import org.openstreetmap.josm.data.Preferences;
     21import org.openstreetmap.josm.data.coor.ILatLon;
    1422import org.openstreetmap.josm.data.coor.LatLon;
     23import org.openstreetmap.josm.io.Compression;
    1524import org.openstreetmap.josm.tools.CheckParameterUtil;
    1625import org.openstreetmap.josm.tools.Logging;
     
    2332 */
    2433public class HgtReader {
    25     private static final int SECONDS_PER_MINUTE = 60;
     34    private static final int SRTM_EXTENT = 1; // degree
     35    private static final List<String> COMPRESSION_EXT = Arrays.asList("xz", "gzip", "zip", "bz", "bz2");
    2636
    2737    public static final String HGT_EXT = ".hgt";
    2838
    2939    // alter these values for different SRTM resolutions
    30     public static final int HGT_RES = 3; // resolution in arc seconds
    31     public static final int HGT_ROW_LENGTH = 1201; // number of elevation values per line
    32     public static final int HGT_VOID = -32768; // magic number which indicates 'void data' in HGT file
    33 
    34     private final HashMap<String, ShortBuffer> cache = new HashMap<>();
    35 
    36     public double getElevationFromHgt(LatLon coor) {
     40    public static final int HGT_VOID = Short.MIN_VALUE; // magic number which indicates 'void data' in HGT file
     41
     42    private static final HashMap<String, short[][]> cache = new HashMap<>();
     43
     44    public static double getElevationFromHgt(ILatLon coor) {
    3745        try {
    3846            String file = getHgtFileName(coor);
     
    4856                    String fullPath = new File(location + File.separator + "elevation", file).getPath();
    4957                    File f = new File(fullPath);
     58                    if (!f.exists()) {
     59                        for (String ext : COMPRESSION_EXT) {
     60                            f = new File(fullPath + "." + ext);
     61                            if (f.exists()) break;
     62                        }
     63                    }
    5064                    if (f.exists()) {
    51                         // found something: read HGT file...
    52                         ShortBuffer data = readHgtFile(fullPath);
    53                         // ... and store result in cache
    54                         cache.put(file, data);
     65                        read(f);
    5566                        break;
    5667                    }
     
    5970
    6071            // read elevation value
    61             return readElevation(coor);
     72            return readElevation(coor, file);
    6273        } catch (FileNotFoundException e) {
    6374            Logging.error("Get elevation from HGT " + coor + " failed: => " + e.getMessage());
     
    7283    }
    7384
    74     @SuppressWarnings("resource")
    75     private ShortBuffer readHgtFile(String file) throws Exception {
     85    public static Bounds read(File file) throws FileNotFoundException, IOException {
     86        String location = file.getName();
     87        for (String ext : COMPRESSION_EXT) {
     88            location = location.replaceAll("\\." + ext + "$", "");
     89        }
     90        short[][] sb = readHgtFile(file.getPath());
     91        // Overwrite the cache file (assume that is desired)
     92        cache.put(location, sb);
     93        Pattern pattern = Pattern.compile("(N|S)([0-9]{2})(E|W)([0-9]{3})");
     94        Matcher matcher = pattern.matcher(location);
     95        if (matcher.lookingAt()) {
     96            int lat = (matcher.group(1) == "S" ? -1 : 1) * Integer.parseInt(matcher.group(2));
     97            int lon = (matcher.group(3) == "W" ? -1 : 1) * Integer.parseInt(matcher.group(4));
     98            return new Bounds(lat, lon, lat + 1, lon + 1);
     99        }
     100        return null;
     101    }
     102
     103    private static short[][] readHgtFile(String file) throws FileNotFoundException, IOException {
    76104        CheckParameterUtil.ensureParameterNotNull(file);
    77105
    78         FileChannel fc = null;
    79         ShortBuffer sb = null;
    80         try {
    81             // Eclipse complains here about resource leak on 'fc' - even with 'finally' clause???
    82             fc = new FileInputStream(file).getChannel();
     106        short[][] data = null;
     107
     108        try (InputStream fis = Compression.getUncompressedFileInputStream(Paths.get(file))) {
    83109            // choose the right endianness
    84 
    85             ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
    86             while (bb.remaining() > 0) fc.read(bb);
    87 
    88             bb.flip();
    89             sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
    90         } finally {
    91             if (fc != null) fc.close();
    92         }
    93 
    94         return sb;
     110            ByteBuffer bb = ByteBuffer.wrap(IOUtils.toByteArray(fis));
     111            //System.out.println(Arrays.toString(bb.array()));
     112            bb.order(ByteOrder.BIG_ENDIAN);
     113            int size = (int) Math.sqrt(bb.array().length / 2);
     114            data = new short[size][size];
     115            int x = 0;
     116            int y = 0;
     117            while (x < size) {
     118                while (y < size) {
     119                    data[x][y] = bb.getShort(2 * (x * size + y));
     120                    y++;
     121                }
     122                x++;
     123                y = 0;
     124            }
     125        }
     126
     127        return data;
    95128    }
    96129
     
    102135     * @return the elevation value or <code>Double.NaN</code>, if no value is present
    103136     */
    104     public double readElevation(LatLon coor) {
     137    public static double readElevation(LatLon coor) {
    105138        String tag = getHgtFileName(coor);
    106 
    107         ShortBuffer sb = cache.get(tag);
     139        return readElevation(coor, tag);
     140    }
     141
     142    /**
     143     * Reads the elevation value for the given coordinate.
     144     *
     145     * See also <a href="http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">stackexchange.com</a>
     146     * @param coor the coordinate to get the elevation data for
     147     * @param fileName The expected filename
     148     * @return the elevation value or <code>Double.NaN</code>, if no value is present
     149     */
     150    public static double readElevation(ILatLon coor, String fileName) {
     151
     152        short[][] sb = cache.get(fileName);
    108153
    109154        if (sb == null) {
     
    111156        }
    112157
    113         // see http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file
    114         double fLat = frac(coor.lat()) * SECONDS_PER_MINUTE;
    115         double fLon = frac(coor.lon()) * SECONDS_PER_MINUTE;
    116 
    117         // compute offset within HGT file
    118         int row = (int) Math.round(fLat * SECONDS_PER_MINUTE / HGT_RES);
    119         int col = (int) Math.round(fLon * SECONDS_PER_MINUTE / HGT_RES);
    120 
    121         row = HGT_ROW_LENGTH - row;
    122         int cell = (HGT_ROW_LENGTH * (row - 1)) + col;
    123 
    124         // valid position in buffer?
    125         if (cell < sb.limit()) {
    126             short ele = sb.get(cell);
    127             // check for data voids
    128             if (ele == HGT_VOID) {
    129                 return ElevationHelper.NO_ELEVATION;
    130             } else {
    131                 return ele;
    132             }
    133         } else {
    134             return ElevationHelper.NO_ELEVATION;
    135         }
     158        int[] index = getIndex(coor, sb.length);
     159        short ele = sb[index[0]][index[1]];
     160
     161        if (ele == HGT_VOID) {
     162            return ElevationHelper.NO_ELEVATION;
     163        }
     164        return ele;
     165    }
     166
     167    public static Optional<Bounds> getBounds(ILatLon location) {
     168        final String fileName = getHgtFileName(location);
     169        final short[][] sb = cache.get(fileName);
     170
     171        if (sb == null) {
     172            return Optional.empty();
     173        }
     174
     175        final double latDegrees = location.lat();
     176        final double lonDegrees = location.lon();
     177
     178        final float fraction = ((float) SRTM_EXTENT) / sb.length;
     179        final int latitude = (int) Math.floor(latDegrees) + (latDegrees < 0 ? 1 : 0);
     180        final int longitude = (int) Math.floor(lonDegrees) + (lonDegrees < 0 ? 1 : 0);
     181
     182        final int[] index = getIndex(location, sb.length);
     183        final int latSign = latitude > 0 ? 1 : -1;
     184        final int lonSign = longitude > 0 ? 1 : -1;
     185        final double minLat = latitude + latSign * fraction * index[0];
     186        final double maxLat = latitude + latSign * fraction * (index[0] + 1);
     187        final double minLon = longitude + lonSign * fraction * index[1];
     188        final double maxLon = longitude + lonSign * fraction * (index[1] + 1);
     189        return Optional.of(new Bounds(Math.min(minLat, maxLat), Math.min(minLon, maxLon),
     190                Math.max(minLat, maxLat), Math.max(minLon, maxLon)));
     191    }
     192
     193    /**
     194     * Get the index to use for a short[latitude][longitude] = height in meters array
     195     *
     196     * @param latLon
     197     *            The location to get the index for
     198     * @param mapSize
     199     *            The size of the map
     200     * @return A [latitude, longitude] = int (index) array.
     201     */
     202    private static int[] getIndex(ILatLon latLon, int mapSize)
     203    {
     204        double latDegrees = latLon.lat();
     205        double lonDegrees = latLon.lon();
     206
     207        float fraction = ((float) SRTM_EXTENT) / mapSize;
     208        int latitude = (int) Math.floor(Math.abs(latDegrees - (int) latDegrees) / fraction);
     209        int longitude = (int) Math.floor(Math.abs(lonDegrees - (int) lonDegrees) / fraction);
     210        if (latDegrees >= 0)
     211        {
     212            latitude = mapSize - 1 - latitude;
     213        }
     214        if (lonDegrees < 0)
     215        {
     216            longitude = mapSize - 1 - longitude;
     217        }
     218        return new int[] { latitude, longitude };
    136219    }
    137220
     
    144227     * @return the file name of the HGT file
    145228     */
    146     public String getHgtFileName(LatLon latLon) {
    147         int lat = (int) latLon.lat();
    148         int lon = (int) latLon.lon();
     229    public static String getHgtFileName(ILatLon latLon) {
     230        int lat = (int) Math.floor(latLon.lat());
     231        int lon = (int) Math.floor(latLon.lon());
    149232
    150233        String latPref = "N";
    151         if (lat < 0) latPref = "S";
     234        if (lat < 0) {
     235            latPref = "S";
     236            lat = Math.abs(lat);
     237        }
    152238
    153239        String lonPref = "E";
    154240        if (lon < 0) {
    155241            lonPref = "W";
    156         }
    157 
    158         return String.format("%s%02d%s%03d%s", latPref, lat, lonPref, lon, HGT_EXT);
     242            lon = Math.abs(lon);
     243        }
     244
     245        return latPref + lat + lonPref + lon + HGT_EXT;
    159246    }
    160247
     
    168255        return fPart;
    169256    }
     257
     258    public static void clearCache() {
     259        cache.clear();
     260    }
    170261}
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/IElevationProfile.java

    r32775 r35964  
    22package org.openstreetmap.josm.plugins.elevation;
    33
    4 import java.util.Date;
     4import java.time.Instant;
    55import java.util.List;
    66
     
    2121     * Gets the time stamp of first recorded track point.
    2222     */
    23     Date getStart();
     23    Instant getStart();
    2424
    2525    /**
    2626     * Gets the time stamp of last recorded track point.
    2727     */
    28     Date getEnd();
     28    Instant getEnd();
    2929
    3030    /**
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/actions/AddElevationLayerAction.java

    r33815 r35964  
    2828            currentLayer = new ElevationGridLayer(tr("Elevation Grid")); // TODO: Better name
    2929            MainApplication.getLayerManager().addLayer(currentLayer);
     30        } else if (!MainApplication.getLayerManager().containsLayer(currentLayer)) {
     31            currentLayer = null;
     32            actionPerformed(arg0);
    3033        }
    3134    }
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java

    r35465 r35964  
    22package org.openstreetmap.josm.plugins.elevation.gpx;
    33
     4import java.time.Instant;
    45import java.util.ArrayList;
    5 import java.util.Date;
    66import java.util.List;
    77
     
    4545    private int avrgHeight;
    4646    private double dist;
    47     private Date start = new Date();
    48     private Date end = new Date();
     47    private Instant start;
     48    private Instant end;
    4949    private final WayPoint[] importantWayPoints = new WayPoint[4];
    5050    private IElevationProfile parent;
     
    121121            return;
    122122
    123         start = new Date(0L);
    124         end = new Date();
     123        start = Instant.EPOCH;
     124        end = Instant.now();
    125125        this.minHeight = Integer.MAX_VALUE;
    126126        this.maxHeight = Integer.MIN_VALUE;
     
    196196    protected void setStart(WayPoint wp) {
    197197        importantWayPoints[WAYPOINT_START] = wp;
    198         if(wp.getDate() != null)
    199             this.start = wp.getDate();
     198        if(wp.getInstant() != null)
     199            this.start = wp.getInstant();
    200200    }
    201201
     
    205205    protected void setEnd(WayPoint wp) {
    206206        importantWayPoints[WAYPOINT_END] = wp;
    207         if(wp.getDate() != null)
    208             this.end = wp.getDate();
     207        if(wp.getInstant() != null)
     208            this.end = wp.getInstant();
    209209    }
    210210
     
    257257
    258258    @Override
    259     public Date getEnd() {
     259    public Instant getEnd() {
    260260        return end;
    261261    }
     
    308308
    309309        if (wp1 != null && wp2 != null) {
    310             Date wp1Date = wp1.getDate();
    311             Date wp2Date = wp2.getDate();
     310            Instant wp1Date = wp1.getInstant();
     311            Instant wp2Date = wp2.getInstant();
    312312            if (wp1Date != null && wp2Date != null) {
    313                 return wp2Date.getTime() - wp1Date.getTime();
     313                return wp2Date.toEpochMilli() - wp1Date.toEpochMilli();
    314314            } else {
    315315                Logging.warn("Waypoints without date: " + wp1 + " / " + wp2);
     
    326326
    327327    @Override
    328     public Date getStart() {
     328    public Instant getStart() {
    329329        return start;
    330330    }
     
    390390
    391391        if (wp.hasDate()) {
    392             if (wp.getDate().after(end)) {
     392            if (wp.getInstant().isAfter(this.end)) {
    393393                setEnd(wp);
    394394            }
    395395
    396             if (wp.getDate().before(start)) {
     396            if (wp.getInstant().isBefore(start)) {
    397397                setStart(wp);
    398398            }
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridLayer.java

    r35165 r35964  
    88import java.awt.Graphics2D;
    99import java.awt.Point;
     10import java.awt.Rectangle;
     11import java.awt.event.MouseEvent;
     12import java.awt.event.MouseListener;
    1013
    1114import javax.swing.Action;
    1215import javax.swing.Icon;
    1316
     17import org.apache.commons.jcs3.JCS;
    1418import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
    1519import org.openstreetmap.gui.jmapviewer.Tile;
     
    1923import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
    2024import org.openstreetmap.josm.data.Bounds;
     25import org.openstreetmap.josm.data.coor.ILatLon;
    2126import org.openstreetmap.josm.data.coor.LatLon;
    2227import org.openstreetmap.josm.data.imagery.CoordinateConversion;
     28import org.openstreetmap.josm.data.imagery.TileJobOptions;
     29import org.openstreetmap.josm.data.osm.BBox;
    2330import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     31import org.openstreetmap.josm.gui.MainApplication;
    2432import org.openstreetmap.josm.gui.MapView;
     33import org.openstreetmap.josm.gui.Notification;
    2534import org.openstreetmap.josm.gui.layer.Layer;
     35import org.openstreetmap.josm.gui.util.GuiHelper;
     36import org.openstreetmap.josm.plugins.elevation.ElevationHelper;
     37import org.openstreetmap.josm.plugins.elevation.HgtReader;
    2638import org.openstreetmap.josm.plugins.elevation.IVertexRenderer;
    2739import org.openstreetmap.josm.tools.ImageProvider;
     
    3244 *
    3345 */
    34 public class ElevationGridLayer extends Layer implements TileLoaderListener {
     46public class ElevationGridLayer extends Layer implements TileLoaderListener, MouseListener {
    3547    private static final int ELE_ZOOM_LEVEL = 13;
    3648    private final IVertexRenderer vertexRenderer;
     
    4052    protected TileController tileController;
    4153
     54    private ILatLon clickLocation;
     55
    4256    private Bounds lastBounds;
    4357    private TileSet tileSet;
     
    4559    public ElevationGridLayer(String name) {
    4660        super(name);
     61        HgtReader.clearCache();
     62        MainApplication.getMap().mapView.addMouseListener(this);
    4763
    4864        setOpacity(0.8);
     
    5369        tileCache.setCacheSize(500);
    5470        tileSource = new ElevationGridTileSource(name);
    55         tileLoader = new ElevationGridTileLoader(this);
     71        tileLoader = new ElevationGridTileLoader(this, JCS.getInstance("elevationgridlayer"), new TileJobOptions(20, 20, null, 3600));
    5672        tileController = new ElevationGridTileController(tileSource, tileCache, this, tileLoader);
    5773    }
     
    90106            }
    91107        }
     108        // Paint the current point area
     109        ElevationHelper.getBounds(this.clickLocation).ifPresent(bounds -> {
     110            final BBox bbox = bounds.toBBox();
     111            final Point upperLeft = mv.getPoint(bbox.getTopLeft());
     112            final Point bottomRight = mv.getPoint(bbox.getBottomRight());
     113            final Rectangle rectangle = new Rectangle(upperLeft.x, upperLeft.y,
     114                    bottomRight.x - upperLeft.x, bottomRight.y - upperLeft.y);
     115            g.setColor(Color.RED);
     116            g.draw(rectangle);
     117        });
    92118    }
    93119
     
    150176        g.setColor(oldColor);
    151177        g.drawString(text, x, y);
     178    }
     179
     180    @Override
     181    public void mouseClicked(MouseEvent e) {
     182        if (e.getButton() == MouseEvent.BUTTON1) {
     183            this.clickLocation = MainApplication.getMap().mapView.getLatLon(e.getX(), e.getY());
     184            final double elevation = ElevationHelper.getSrtmElevation(clickLocation);
     185            Notification notification = new Notification("Elevation is: " + elevation);
     186            notification.setDuration(Notification.TIME_SHORT);
     187            GuiHelper.runInEDT(notification::show);
     188            GuiHelper.runInEDT(this::invalidate);
     189        }
     190    }
     191
     192    @Override
     193    public void mousePressed(MouseEvent e) {
     194        // Do nothing
     195    }
     196
     197    @Override
     198    public void mouseReleased(MouseEvent e) {
     199        // Do nothing
     200    }
     201
     202    @Override
     203    public void mouseEntered(MouseEvent e) {
     204        // Do nothing
     205    }
     206
     207    @Override
     208    public void mouseExited(MouseEvent e) {
     209        // Do nothing
    152210    }
    153211
     
    224282        }
    225283    }
     284
     285    @Override
     286    public void destroy() {
     287        super.destroy();
     288        HgtReader.clearCache();
     289        MainApplication.getMap().mapView.removeMouseListener(this);
     290    }
    226291}
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java

    r35165 r35964  
    1010import java.io.IOException;
    1111import java.io.InputStream;
    12 import java.util.List;
    1312import java.util.concurrent.BlockingDeque;
    1413import java.util.concurrent.LinkedBlockingDeque;
     
    5554    /**
    5655     * Paints the vertices of this tile.
    57      *
    5856     * @param g the graphics context
    5957     * @param mv the map view
     
    6765            Point p2 = mv.getPoint(eleVertex.get(2));
    6866            Triangle shape = new Triangle(p0, p1, p2);
    69 
    7067            // obtain vertex color
    7168            g.setColor(vertexRenderer.getElevationColor(eleVertex));
     
    8380        // We abuse the loadImage method to render the vertices...
    8481        //
    85         while (toDo.size() > 0) {
     82        while (!toDo.isEmpty()) {
    8683            EleVertex vertex = toDo.poll();
    8784
     
    8986                vertices.add(vertex);
    9087            } else {
    91                 List<EleVertex> newV = vertex.divide();
    92                 for (EleVertex eleVertex : newV) {
    93                     toDo.add(eleVertex);
    94                 }
     88                toDo.addAll(vertex.divide());
    9589            }
    9690        }
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTileLoader.java

    r33214 r35964  
    22package org.openstreetmap.josm.plugins.elevation.grid;
    33
     4import java.io.IOException;
     5import java.net.URL;
     6import java.util.Optional;
     7import java.util.concurrent.ThreadPoolExecutor;
     8
     9import org.apache.commons.jcs3.access.behavior.ICacheAccess;
    410import org.openstreetmap.gui.jmapviewer.Tile;
    511import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
    6 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
    712import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
     13import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
     14import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
     15import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
     16import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
     17import org.openstreetmap.josm.data.imagery.TileJobOptions;
    818import org.openstreetmap.josm.tools.CheckParameterUtil;
    919
     
    1222 *
    1323 */
    14 public class ElevationGridTileLoader implements TileLoader {
    15     protected TileLoaderListener listener;
     24public class ElevationGridTileLoader extends TMSCachedTileLoader {
    1625
    17     public ElevationGridTileLoader(TileLoaderListener listener) {
    18         CheckParameterUtil.ensureParameterNotNull(listener);
    19         this.listener = listener;
     26    class ElevationGridTileJob extends JCSCachedTileLoaderJob<String, BufferedImageCacheEntry> implements TileJob {
     27
     28        private final Tile tile;
     29        private final TileLoaderListener listener;
     30        private final ICacheAccess<String, BufferedImageCacheEntry> cache;
     31
     32        protected ElevationGridTileJob(TileLoaderListener listener, Tile tile, ICacheAccess<String, BufferedImageCacheEntry> cache, TileJobOptions options,
     33                ThreadPoolExecutor downloadJobExecutor) {
     34            super(cache, options, downloadJobExecutor);
     35            this.cache = cache;
     36            this.tile = tile;
     37            this.listener = listener;
     38        }
     39
     40        @Override
     41        public void run() {
     42            synchronized (tile) {
     43                if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
     44                    return;
     45                tile.initLoading();
     46            }
     47            try {
     48                tile.loadImage(null);
     49                tile.setLoaded(true);
     50                listener.tileLoadingFinished(tile, true);
     51            } catch (Exception e) {
     52                tile.setError(e.getMessage());
     53                listener.tileLoadingFinished(tile, false);
     54            } finally {
     55                tile.finishLoading();
     56            }
     57        }
     58
     59        @Override
     60        public void submit() {
     61            run();
     62        }
     63
     64        @Override
     65        public void submit(boolean force) {
     66            submit();
     67        }
     68
     69        @Override
     70        public String getCacheKey() {
     71            if (tile != null) {
     72                TileSource tileSource = tile.getTileSource();
     73                return Optional.ofNullable(tileSource.getName()).orElse("").replace(':', '_') + ':'
     74                        + tileSource.getTileId(tile.getZoom(), tile.getXtile(), tile.getYtile());
     75            }
     76            return null;
     77        }
     78
     79        @Override
     80        public URL getUrl() throws IOException {
     81            return new URL(String.format("http://localhost/elevation/%d/%d", tile.getTileXY().getXIndex(), tile.getTileXY().getYIndex()));
     82        }
     83
     84        @Override
     85        protected BufferedImageCacheEntry createCacheEntry(byte[] content) {
     86            return new BufferedImageCacheEntry(content);
     87        }
     88    }
     89
     90    /**
     91     * Constructor
     92     * @param listener          called when tile loading has finished
     93     * @param cache             of the cache
     94     * @param options           tile job options
     95     */
     96    public ElevationGridTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
     97           TileJobOptions options) {
     98        super(listener, cache, options);
    2099    }
    21100
     
    24103        CheckParameterUtil.ensureParameterNotNull(tile);
    25104
    26         return new TileJob() {
    27 
    28             @Override
    29             public void run() {
    30                 synchronized (tile) {
    31                     if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
    32                         return;
    33                     tile.initLoading();
    34                 }
    35                 try {
    36                     tile.loadImage(null);
    37                     tile.setLoaded(true);
    38                     listener.tileLoadingFinished(tile, true);
    39                 } catch (Exception e) {
    40                     tile.setError(e.getMessage());
    41                     listener.tileLoadingFinished(tile, false);
    42                 } finally {
    43                     tile.finishLoading();
    44                 }
    45             }
    46 
    47             @Override
    48             public void submit() {
    49                 run();
    50             }
    51 
    52             @Override
    53             public void submit(boolean force) {
    54                 submit();
    55             }
    56         };
     105        return new ElevationGridTileJob(listener,
     106                tile,
     107                cache,
     108                options,
     109                getDownloadExecutor());
    57110    }
    58111
  • applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java

    r32775 r35964  
    1616import java.text.Format;
    1717import java.text.SimpleDateFormat;
     18import java.time.Instant;
    1819import java.util.ArrayList;
    19 import java.util.Date;
    2020import java.util.List;
    2121
     
    254254     * Formats the date in a predefined manner: "21. Oct 2010, 12:10".
    255255     */
    256     private String formatDate(Date date) {
     256    private String formatDate(Instant date) {
    257257        Format formatter = new SimpleDateFormat("d MMM yy, HH:mm");
    258 
    259         return formatter.format(date);
     258        return formatter.format(date.toEpochMilli());
    260259    }
    261260
Note: See TracChangeset for help on using the changeset viewer.