Package net.sourceforge.gpstools.dem

Source Code of net.sourceforge.gpstools.dem.HgtFile

package net.sourceforge.gpstools.dem;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

public class HgtFile implements ElevationModel {
    private static final int BUFFSIZE = 0x1000;
    private static final ByteOrder BYTEORDER = ByteOrder.BIG_ENDIAN;
    static final Pattern fileNamePattern = Pattern
            .compile("^([SN])(\\d{2})([WE])(\\d{3})\\.[hH][gG][tT](?:\\.[zZ][iI][pP])?$");
    private final ShortBuffer buffer;
    private final FileChannel channel;
    private final int minimumLatitude;
    private final int minimumLongitude;
    private final int linearResolution;
    private final URI sourceURI;
    private final File file;

    public HgtFile(URI hgtFile, File cacheDirectory) throws IOException {
        String scheme = hgtFile.getScheme();

        this.sourceURI = hgtFile;
        // make sure the file exists
        if ("file".equals(scheme)) {
            this.file = new File(hgtFile);
        } else {
            this.file = download(hgtFile.toURL(), cacheDirectory);
        }

        if (!this.file.isFile()) {
            throw new FileNotFoundException(this.file.getAbsolutePath());
        }

        // parse the file name
        Matcher m = fileNamePattern.matcher(this.file.getName());
        if (m.matches()) {
            int lat = Integer.parseInt(m.group(2));
            if (m.group(1).charAt(0) == 'S') {
                lat = -lat;
            }

            int lon = Integer.parseInt(m.group(4));
            if (m.group(3).charAt(0) == 'W') {
                lon = -lon;
            }

            this.minimumLatitude = lat;
            this.minimumLongitude = lon;
        } else {
            throw new IllegalArgumentException("File name " + file.getName()
                    + " cannot be parsed.");
        }

        // parse the file size
        double linRes = Math.sqrt(this.file.length() * 8 / Short.SIZE);
        this.linearResolution = (int) linRes;
        if (linRes != linearResolution) {
            throw new IOException(
                    "Hgt file is not a square array of 16 bit integers.");
        }

        this.channel = (new FileInputStream(this.file)).getChannel();
        try {
            ByteBuffer buff = channel.map(MapMode.READ_ONLY, 0, file.length());
            buff.order(BYTEORDER);
            this.buffer = buff.asShortBuffer();
        } catch (IOException ex) {
            this.channel.close();
            throw ex;
        }
    }

    private File download(URL hgtFile, File cacheDirectory) throws IOException {
        String filename = hgtFile.getFile();
        int j = filename.lastIndexOf('/');
        if (j != -1) {
            filename = filename.substring(j + 1);
        }

        boolean isZipped = filename.endsWith(".zip");

        final File downloadedFile = new File(cacheDirectory, filename)
        final File cachedFile;
        final File zippedFile;
        if (isZipped)
        {
            cachedFile = new File(cacheDirectory, filename.substring(0, filename.length() - 4));
            zippedFile = downloadedFile;
        }
        else
        {
            cachedFile = downloadedFile;
            zippedFile = null;
        }
       
        if (cachedFile.isFile())
        {
            return cachedFile;
        }
        else if (isZipped && zippedFile.isFile())
        {
            return unzip(zippedFile);
        }
        else
        {
            InputStream source = hgtFile.openStream();
            try {
                CopyBuffered(source, downloadedFile);
            } finally {
                source.close();
            }

            return isZipped ? unzip(downloadedFile) : downloadedFile;
        }
    }

    private static void CopyBuffered(InputStream source, File target)
            throws IOException {
        File tmp = File.createTempFile(target.getName(), "tmp");
        try {
            FileOutputStream sink = new FileOutputStream(tmp);
            try {

                BufferedInputStream bufferedSource = new BufferedInputStream(
                        source, BUFFSIZE);
                BufferedOutputStream bufferedSink = new BufferedOutputStream(
                        sink, BUFFSIZE);
                byte[] buffer = new byte[4096];

                for (int bytesRead = bufferedSource.read(buffer); bytesRead != -1; bytesRead = bufferedSource
                        .read(buffer)) {
                    bufferedSink.write(buffer, 0, bytesRead);
                }

                bufferedSink.flush();
            } finally {
                sink.close();
            }

            tmp.renameTo(target);
        } finally {
            if (tmp.exists()) {
                tmp.delete();
            }
        }
    }

    private static File unzip(File zippedFile) throws ZipException, IOException {
        File result;
        ZipFile zip = new ZipFile(zippedFile);
        try {
            for (ZipEntry entry : Collections.list(zip.entries())) {
                if (fileNamePattern.matcher(entry.getName()).matches()) {
                    InputStream source = zip.getInputStream(entry);
                    try {
                        result = new File(zippedFile.getParentFile(),
                                entry.getName());
                        CopyBuffered(source, result);

                        return result;
                    } finally {
                        source.close();
                    }
                }
            }

            throw new FileNotFoundException("No suitable entry found in "
                    + zippedFile);
        } finally {
            zip.close();
        }
    }

    @Override
    public void close() throws IOException {
        if (this.channel != null) {
            this.channel.close();
        }
    }

    @Override
    public BigDecimal getElevation(BigDecimal lat, BigDecimal lon)
            throws DEMException {
        float reducedLat = lat.floatValue() - this.minimumLatitude;
        float reducedLon = lon.floatValue() - this.minimumLongitude;

        if (reducedLat > 1 || reducedLat < 0) {
            throw new DEMException(lat, lon, "Latitude outside domain.");
        }

        if (reducedLon > 1 || reducedLon < 0) {
            throw new DEMException(lat, lon, "Longitude outside domain.");
        }

        final int linRes = this.linearResolution;
        final int maxIndex = linRes - 1;
        int columnIndex = Math.round(maxIndex * reducedLon);
        int rowIndex = maxIndex - Math.round(maxIndex * reducedLat);
        int offset = rowIndex * linRes + columnIndex;
        buffer.position(offset);
        short result = this.buffer.get();
        return (result == Short.MIN_VALUE) ? null : new BigDecimal(result);
    }

    @Override
    public String getInfo() {
        return this.sourceURI.toString() + " cached at " + this.file.getAbsolutePath();
    }
}
TOP

Related Classes of net.sourceforge.gpstools.dem.HgtFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.