# -*- coding: utf-8 -*-
#
# Geonum is a Python library for geographical calculations in 3D
# Copyright (C) 2017 Jonas Gliss (jonasgliss@gmail.com)
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License a
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Access and handling of topographic data
"""
import numpy as np
import os
from geonum.exceptions import InvalidTopoMode, TopoAccessError
from geonum.topoaccessbase import SRTMAccess, Etopo1Access
[docs]
class TopoDataAccess(object):
"""Factory class for accessing topographic data
This is a high-level factory class which handles the access of topography
data. Registered topographic datasets can be found in :attr:`REGISTERED`
Default access mode is SRTM (topographic dataset from NASA
`Shuttle Radar Topography Mission <https://www2.jpl.nasa.gov/srtm/>`__).
Example
-------
>>> acc = TopoDataAccess(mode='srtm')
>>> topo_data = acc.get_data(lat0=5, lon0=30, lat1=15, lon1=40)
Note
----
For developers: the registered access classes (such as
:class:`SRTMAccess`) should be based on (or follow the API of) template
base class :class:`TopoAccessBase`.
Attributes
----------
mode : str
current access mode (string specifying which topographic dataset is
supposed to be used for access).
local_path : str
local path to etopo data (only relevant for etopo1 mode)
Parameters
----------
mode : str
one of the supported data access types (cf. keys of :attr:`REGISTERED`)
local_path : str
local path to etopo data (only relevant for etopo1 mode)
"""
#: supported access modes (topographic datasets)
REGISTERED = dict(srtm = SRTMAccess,
etopo1 = Etopo1Access)
DEFAULT_MODE = 'srtm'
def __init__(self, mode=None, local_path=None):
if mode is None:
mode = self.DEFAULT_MODE
#mode and data access variables
if not mode in self.REGISTERED:
raise InvalidTopoMode(mode)
self.mode = mode
self.local_path = local_path
@property
def modes(self):
"""List of supported topographic datasets"""
return list(self.REGISTERED.keys())
@property
def supported(self):
"""List of supported datasets (wrapper for :attr:`modes`)"""
return self.modes
def __deepcopy__(self, memo):
return TopoDataAccess(self.mode, self.local_path)
[docs]
def get_data(self, lat0, lon0, lat1=None, lon1=None,
mode=None, local_path=None, check_allnan=True,
**access_opts):
"""Retrieve data from topography file
Parameters
----------
lat0 : float
start longitude for data extraction
lon0 : float
start latitude for data extraction
lat1 : float
stop longitude for data extraction (default: None). If None only
data around lon0, lat0 will be extracted.
lon1 : float
stop latitude for data extraction (default: None).
If None only data around lon0, lat0 will be extracted
mode : str, optional
mode specifying the topographic dataset that is supposed to be used
local_path : str, optional
local path where topography data is stored (can be dictionary or
filepath, is passed to corresponding access class and handled
as implemented there)
check_allnan : bool
if True and all retrieved values are NaN, then an error is thrown
**access_opts
additional access options that may be specific for the mode
specified (e.g. search_database in case of etopo1)
Returns
-------
TopoData
object containing the data
Raises
------
TopoAccessError
if access fails
"""
if mode is not None:
if not mode in self.REGISTERED:
raise InvalidTopoMode(mode)
self.mode = mode
if local_path is not None and os.path.exists(local_path):
self.local_path=local_path
access = self.REGISTERED[self.mode](local_path=self.local_path,
**access_opts)
data = access.get_data(lat0, lon0, lat1, lon1)
if check_allnan and np.isnan(data.data).all():
raise TopoAccessError('Failed to retrieve TopoData ({}): '
'all values are NaN'.format(self.mode))
return data