Package org.osm2world.core.map_elevation.creation

Source Code of org.osm2world.core.map_elevation.creation.SRTMData

package org.osm2world.core.map_elevation.creation;

import static java.lang.Double.isNaN;
import static java.lang.Math.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import org.osm2world.core.map_data.creation.MapProjection;
import org.osm2world.core.map_data.data.MapData;
import org.osm2world.core.map_data.data.MapNode;
import org.osm2world.core.math.VectorXYZ;
import org.osm2world.core.math.VectorXZ;

/**
* SRTM data for a part of the planet
*/
public class SRTMData implements TerrainElevationData {
 
  private final File tileDirectory;
  private final MapProjection projection;
  private final SRTMTile[][] tiles;
 
  public SRTMData(File tileDirectory, MapProjection projection) {
    this.tileDirectory = tileDirectory;
    this.projection = projection;
    this.tiles = new SRTMTile[360][180];
  }
   
  @Override
  public Collection<VectorXYZ> getSites(double minLon, double minLat,
      double maxLon, double maxLat) throws IOException {
   
    Collection<VectorXYZ> result = new ArrayList<VectorXYZ>();
   
    int minLonInt = (int)floor(minLon);
    int minLatInt = (int)floor(minLat);
    int maxLonInt = (int)ceil(maxLon);
    int maxLatInt = (int)ceil(maxLat);
   
    for (int lon = minLonInt; lon < maxLonInt; lon++) {
      for (int lat = minLatInt; lat < maxLatInt; lat++) {
       
        loadTileIfNecessary(lon, lat);
       
        addTileSites(result, lon, lat,
            minLon, minLat, maxLon, maxLat);
       
      }
    }
   
    return result;
   
  }
 
  /**
   * variant of getSites which calculates minimum and maximum lat/lon
   * from the bounds of a {@link MapData} instance
   *
   * TODO: make projection reversible, then replace both getSites methods
   *       with a single getSite(AxisAlignedBoundingBox dataBounds) method
   */
  @Override
  public Collection<VectorXYZ> getSites(MapData mapData) throws IOException {
   
    double minLon = Double.POSITIVE_INFINITY;
    double minLat = Double.POSITIVE_INFINITY;
    double maxLon = Double.NEGATIVE_INFINITY;
    double maxLat = Double.NEGATIVE_INFINITY;
   
    /* find the minimum and maximum lat/lon in the data */
   
    for (MapNode mapNode : mapData.getMapNodes()) {
     
      double lon = mapNode.getOsmNode().lon;
      double lat = mapNode.getOsmNode().lat;
     
      if (!isNaN(lat) && !isNaN(lon)) {
        minLon = min(minLon, lon);
        minLat = min(minLat, lat);
        maxLon = max(maxLon, lon);
        maxLat = max(maxLat, lat);
      }
     
    }
   
    /* add a small seam for robustness */
   
    minLon -= 0.02; minLat -= 0.02;
    maxLon += 0.02; maxLat += 0.02;
   
    /* TODO: the seam could be smaller - such as this - if empty terrain nodes did have lat/lon
    minLon -= 0.005; minLat -= 0.005;
    maxLon += 0.005; maxLat += 0.005;
    */
   
    /* retrieve the sites for the query */
   
    return getSites(minLon, minLat, maxLon, maxLat);
   
  }

  private void loadTileIfNecessary(int lon, int lat) throws IOException {
   
    if (getTile(lon, lat) == null) {
     
      String fileName = tileDirectory.getPath() + File.separator;
     
      if (lat >= 0) {
        fileName += String.format("N%02d", lat);
      } else {
        fileName += String.format("S%02d", -lat);
      }

      if (lon >= 0) {
        fileName += String.format("E%03d", lon);
      } else {
        fileName += String.format("W%03d", -lon);
      }
     
      fileName += ".hgt";
     
      File file = new File(fileName);
     
      if (file.exists()) {
        setTile(lon, lat, new SRTMTile(file));
      } else {
        System.err.println("warning: missing SRTM tile " + file.getName());
      }
     
    }
   
  }
 
  private void addTileSites(Collection<VectorXYZ> result,
      int tileLon, int tileLat,
      double minLon, double minLat, double maxLon, double maxLat) {
   
    SRTMTile tile = getTile(tileLon, tileLat);
   
    if (tile == null) return;
   
    /* add a site for each SRTM pixel (except last line and column,
     * which is duplicated in adjacent tiles) */
   
    int minX = max(0,
        (int)ceil(SRTMTile.PIXELS * (minLon - tileLon)));
    int maxX = min(SRTMTile.PIXELS - 1,
        (int)floor(SRTMTile.PIXELS * (maxLon - tileLon)));

    int minY = max(0,
        (int)ceil(SRTMTile.PIXELS * (minLat - tileLat)));
    int maxY = min(SRTMTile.PIXELS - 1,
        (int)floor(SRTMTile.PIXELS * (maxLat - tileLat)));
   
    for (int x = minX; x < maxX; x++) {
      for (int y = minY; y < maxY; y++) {
       
        short value = tile.getData(x, y);
       
        double lat = tileLat + 1.0 / SRTMTile.PIXELS * (y + 0.5);
        double lon = tileLon + 1.0 / SRTMTile.PIXELS * (x + 0.5);
       
        VectorXZ pos = projection.calcPos(lat, lon);
       
        if (value != SRTMTile.BLANK_VALUE &&
            !Double.isNaN(pos.x) && !Double.isNaN(pos.z)) {
          result.add(pos.xyz(value));
        }
       
      }
    }
       
  }
 
  private SRTMTile getTile(int tileLon, int tileLat) {
    return tiles[tileLon+180][tileLat+90];
  }
 
  private void setTile(int tileLon, int tileLat, SRTMTile tile) {
    tiles[tileLon+180][tileLat+90] = tile;
  }
 
}
TOP

Related Classes of org.osm2world.core.map_elevation.creation.SRTMData

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.