Creating Terrain Map with SRTM HGT File

1.9k views Asked by At

I am working on an iOS application. Where I show the Elevation and Topography map of a certain area. I have managed to download the .hgt file within app from here.

So far I am able to extract the Elevation from the hgt file. Now I have to also show the Terrain Map for that area. I have been searching about it and I think I can't create terrain map directly with hgt file within iOS application. I have to use GRASS GIS, SRTM2OSM or TileMill to create terrain map and then use it in application.

Can please anyone direct me what I can do here and how to proceed.

EDIT:

I have asked to not to use any kind of map for this. So basically I have to create the map by using core drawing, and I have no idea about it.

Something Like this without the text:

enter image description here

2

There are 2 answers

4
Alessandro Ornano On BEST ANSWER

With iOS you have access to Maps through MapKit framework to display map or satellite imagery directly from your app's interface, you can use also Google Maps through Google Maps SDK for iOS but both (iOS Maps and Google Maps) don't have a terrain level.

So to avoid to re-create something that already exist you can take a look to the OpenStreetMaps frameworks, here you can find many available frameworks, one of them is called MapBox and you can download the latest sources and example here

As you can read from wiki pages we have also the terrain level: enter image description here

I think it's a really useful library, updated and working with swift 4 , here you can find an easy tutorial to start:

import Mapbox
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let mapView = MGLMapView(frame: view.bounds)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.setCenter(CLLocationCoordinate2D(latitude: 40.74699, longitude: -73.98742), zoomLevel: 9, animated: false)
        view.addSubview(mapView)
        // to show the terrain level 
        mapView.styleURL = MGLStyle.outdoorsStyleURL()
    }
}
0
AudioBubble On

I have to create the map by using core drawing

  • You can draw an Map object from SRTM HGT file [1]

  • For reading interpolated height from SRTM HGT files [2]

  • Below is code working with .cpp file you can get some idea for how to draw it from SRTM [3]

#include "generator/srtm_parser.hpp"

#include "coding/endianness.hpp"
#include "coding/zip_reader.hpp"

#include "base/logging.hpp"

#include <iomanip>
#include <sstream>

namespace generator
{
namespace
{
size_t constexpr kArcSecondsInDegree = 60 * 60;
size_t constexpr kSrtmTileSize = (kArcSecondsInDegree + 1) * (kArcSecondsInDegree + 1) * 2;

struct UnzipMemDelegate : public ZipFileReader::Delegate
{
  UnzipMemDelegate(std::string & buffer) : m_buffer(buffer), m_completed(false) {}

  // ZipFileReader::Delegate overrides:
  void OnBlockUnzipped(size_t size, char const * data) override { m_buffer.append(data, size); }

  void OnStarted() override
  {
    m_buffer.clear();
    m_completed = false;
  }

  void OnCompleted() override { m_completed = true; }

  std::string & m_buffer;
  bool m_completed;
};
}  // namespace

// SrtmTile ----------------------------------------------------------------------------------------
SrtmTile::SrtmTile()
{
  Invalidate();
}

SrtmTile::SrtmTile(SrtmTile && rhs) : m_data(move(rhs.m_data)), m_valid(rhs.m_valid)
{
  rhs.Invalidate();
}

void SrtmTile::Init(std::string const & dir, ms::LatLon const & coord)
{
  Invalidate();

  std::string const base = GetBase(coord);
  std::string const cont = dir + base + ".SRTMGL1.hgt.zip";
  std::string file = base + ".hgt";

  UnzipMemDelegate delegate(m_data);
  try
  {
    ZipFileReader::UnzipFile(cont, file, delegate);
  }
  catch (ZipFileReader::LocateZipException const & e)
  {
    // Sometimes packed file has different name. See N39E051 measure.
    file = base + ".SRTMGL1.hgt";

    ZipFileReader::UnzipFile(cont, file, delegate);
  }

  if (!delegate.m_completed)
  {
    LOG(LWARNING, ("Can't decompress SRTM file:", cont));
    Invalidate();
    return;
  }

  if (m_data.size() != kSrtmTileSize)
  {
    LOG(LWARNING, ("Bad decompressed SRTM file size:", cont, m_data.size()));
    Invalidate();
    return;
  }

  m_valid = true;
}

feature::TAltitude SrtmTile::GetHeight(ms::LatLon const & coord)
{
  if (!IsValid())
    return feature::kInvalidAltitude;

  double ln = coord.lon - static_cast<int>(coord.lon);
  if (ln < 0)
    ln += 1;
  double lt = coord.lat - static_cast<int>(coord.lat);
  if (lt < 0)
    lt += 1;
  lt = 1 - lt;  // from North to South

  size_t const row = kArcSecondsInDegree * lt;
  size_t const col = kArcSecondsInDegree * ln;

  size_t const ix = row * (kArcSecondsInDegree + 1) + col;

  if (ix >= Size())
    return feature::kInvalidAltitude;
  return ReverseByteOrder(Data()[ix]);
}

std::string SrtmTile::GetBase(ms::LatLon coord)
{
  std::ostringstream ss;
  if (coord.lat < 0)
  {
    ss << "S";
    coord.lat *= -1;
    coord.lat += 1;
  }
  else
  {
    ss << "N";
  }
  ss << std::setw(2) << std::setfill('0') << static_cast<int>(coord.lat);

  if (coord.lon < 0)
  {
    ss << "W";
    coord.lon *= -1;
    coord.lon += 1;
  }
  else
  {
    ss << "E";
  }
  ss << std::setw(3) << static_cast<int>(coord.lon);
  return ss.str();
}

void SrtmTile::Invalidate()
{
  m_data.clear();
  m_data.shrink_to_fit();
  m_valid = false;
}

// SrtmTileManager ---------------------------------------------------------------------------------
SrtmTileManager::SrtmTileManager(std::string const & dir) : m_dir(dir) {}
feature::TAltitude SrtmTileManager::GetHeight(ms::LatLon const & coord)
{
  std::string const base = SrtmTile::GetBase(coord);
  auto it = m_tiles.find(base);
  if (it == m_tiles.end())
  {
    SrtmTile tile;
    try
    {
      tile.Init(m_dir, coord);
    }
    catch (RootException const & e)
    {
      LOG(LINFO, ("Can't init SRTM tile:", base, "reason:", e.Msg()));
    }

    // It's OK to store even invalid tiles and return invalid height
    // for them later.
    it = m_tiles.emplace(base, std::move(tile)).first;
  }

  return it->second.GetHeight(coord);
}
}  // namespace generator