Module gdalhelpers.classes.DEM
Expand source code
import gdal
from gdal import osr, ogr
from typing import List, Union
from numpy import floor, array
import os
import math
import warnings
import gdalhelpers.helpers.math_helpers as math_helpers
from gdalhelpers.checks import geometry_checks
class DEM:
"""
Class representing digital elevation model. Based on `gdal.Dataset` with additional functions.
Various checks are performed at creation time to ensure usability of the data. `DEM` can only have one band with
values and the raster has to projected.
Attributes
----------
path : str
Path to the stored dataset.
ds : gdal.Dataset
Raster dataset in `gdal`.
projection : osr.SpatialReference
`osr.SpatialReference` for from `ds`.
gt
Result of `ds.GetGeoTransform()` function.
nx, ny : int
Raster size in x and y direction in cells.
no_data : float
Value from functions `ds.GetRasterBand(1).GetNoDataValue()`.
np_array : np.array
Two dimensional numpy array of values from `ds`.
"""
__band_number = 1
__gdal_nodata_default = -3.4028e+38
def __init__(self, path: str, epsg: int = None):
"""
Construct function.
Parameters
----------
path : str
Path to load the data from.
epsg : int, optional
EPSG code of raster projection.
"""
if not os.path.isfile(path):
raise IOError("File at specified path `{0}` does not exist.".format(path))
self.path = path
self.ds = gdal.Open(self.path)
if self.ds.RasterCount > 1:
raise ValueError("DEM is only allowed to have one band. The raster has `{}` bands."
.format(self.ds.RasterCount))
projection = self.ds.GetProjection()
projection = osr.SpatialReference(wkt=projection)
if projection.ExportToWkt() == "" and epsg is None:
raise ValueError("Cannot obtain projection from raster `{0}` and epsg argument is not set."
.format(path))
if projection != "" and epsg is not None:
epsg = None
warnings.warn(
"Raster has specified projection and epsg is set. Using projection from raster!",
SyntaxWarning)
if epsg is None:
if projection.IsProjected() != 1:
raise ValueError("DEM has to be projected, the given projection is not projected: \n `{0}`."
.format(projection.ExportToWkt()))
else:
projection = osr.SpatialReference()
projection.ImportFromEPSG(epsg)
if projection.IsProjected() != 1:
raise ValueError("DEM has to be projected, the definition of provided EPSG is not projected: \n `{0}`.".
format(projection.ExportToProj4()))
else:
self.ds.SetProjection(projection.ExportToWkt())
self.gt = self.ds.GetGeoTransform()
self.nx = self.ds.RasterXSize
self.ny = self.ds.RasterYSize
self.no_data = self.ds.GetRasterBand(self.__band_number).GetNoDataValue()
self.np_array = None
@classmethod
def from_gdal_raster(cls, gdal_raster: gdal.Dataset):
"""
Class method to build `DEM` from `gdal.Dataset`.
Parameters
----------
gdal_raster : gdal.Dataset
Build `DEM` based on allready loaded raster data.
Returns
-------
None
"""
if not isinstance(gdal_raster, gdal.Dataset):
raise TypeError("`gdal_raster` has to be of type `gdal.Dataset`. "
"But it is type `{0}`".format(type(gdal_raster).__name__))
return cls(path=gdal_raster.GetDescription())
def __str__(self):
"""
String representation of class `DEM`.
Returns
-------
str
Represetation of DEM.
"""
return "Raster from `{0}` with sizes(`{1}`, `{2}`) using projection `{3}`.".format(self.path,
self.nx,
self.ny,
self.ds.GetProjection())
def __del__(self):
"""
Upon deletion of the object close connection and clear array.
Returns
-------
None
"""
self.ds = None
self.destroy_array()
def get_min_pixel_size(self) -> float:
"""
Get minimal pixel size in either row or column direction.
Returns
-------
float
Minimal pixel size in either row or column direction.
"""
return abs(min(self.gt[1], self.gt[5]))
def __check_value_is_nodata(self, value: Union[int, float]) -> bool:
return (value < self.__gdal_nodata_default) or math_helpers.is_almost_equal(value, self.no_data)
def load_array(self) -> None:
"""
Read raster values into numpy array.
Returns
-------
None
"""
self.np_array = self.ds.GetRasterBand(self.__band_number).ReadAsArray()
def destroy_array(self) -> None:
"""
Clear numpy array with raster values.
Returns
-------
None
"""
self.np_array = None
def get_nodata_value(self) -> float:
"""
Get no data value of the raster.
Returns
-------
float
No data value of the raster.
"""
return self.no_data
def get_max_size(self) -> float:
"""
Get larger size of the raster in map units. Calculated as pixel width/height times raster width/height.
Returns
-------
float
Maximal raster size.
"""
return max(self.gt[1] * self.nx, self.gt[5] * self.ny)
def get_diagonal_size(self) -> float:
"""
Get diagonal size of the raster in map units.
Returns
-------
float
Raster size in diagonal direction.
"""
size = math.sqrt(math.pow(self.gt[1] * self.nx, 2) + math.pow(self.gt[5] * self.ny, 2))
return size
def get_bounding_box(self) -> ogr.Geometry:
"""
Get bounding box of the raster.
Returns
-------
ogr.Geometry
Bounding box of the raster.
"""
x1 = self.gt[0]
x2 = self.gt[0] + self.nx * self.gt[1]
y1 = self.gt[3]
y2 = self.gt[3] + self.ny * self.gt[5]
ring = ogr.Geometry(ogr.wkbLinearRing)
ring.AddPoint(min(x1, x2), min(y1, y2))
ring.AddPoint(max(x1, x2), min(y1, y2))
ring.AddPoint(max(x1, x2), max(y1, y2))
ring.AddPoint(min(x1, x2), max(y1, y2))
ring.AddPoint(min(x1, x2), min(y1, y2))
bbox = ogr.Geometry(ogr.wkbPolygon)
bbox.AddGeometry(ring)
return bbox
# code from http://gis.stackexchange.com/questions/7611/bilinear-interpolation-of-point-data-on-a-raster-in-python
def get_value_bilinear(self, px: float, py: float) -> float:
"""
Get bilinear interpolated value from the raster at point (px, py).
Parameters
----------
px, py : float
Point coordinates in raster units.
Returns
-------
float
Interpolated value of the raster at specified location.
"""
if not isinstance(px, (int, float)):
raise TypeError("px must be number. The variable is of `{}`.".format(type(px)))
if not isinstance(py, (int, float)):
raise TypeError("py must be number. The variable is of `{}`.".format(type(py)))
if self.np_array is None:
self.load_array()
ny, nx = self.np_array.shape
# Half raster cell widths
hx = self.gt[1] / 2.0
hy = self.gt[5] / 2.0
# Calculate raster lower bound indices from point
fx = (px - (self.gt[0] + hx)) / self.gt[1]
fy = (py - (self.gt[3] + hy)) / self.gt[5]
ix1 = int(floor(fx))
iy1 = int(floor(fy))
# Special case where point is on upper bounds
if fx == float(nx - 1):
ix1 -= 1
if fy == float(ny - 1):
iy1 -= 1
# Upper bound indices on raster
ix2 = ix1 + 1
iy2 = iy1 + 1
# Test array bounds to ensure point is within raster midpoints
if (ix1 < 0) or (iy1 < 0) or (ix2 > nx - 1) or (iy2 > ny - 1):
return self.no_data
# Calculate differences from point to bounding raster midpoints
dx1 = px - (self.gt[0] + ix1 * self.gt[1] + hx)
dy1 = py - (self.gt[3] + iy1 * self.gt[5] + hy)
dx2 = (self.gt[0] + ix2 * self.gt[1] + hx) - px
dy2 = (self.gt[3] + iy2 * self.gt[5] + hy) - py
# Use the differences to weigh the four raster values
div = self.gt[1] * self.gt[5]
# if any value is nodata then everything is nodata
if (self.__check_value_is_nodata(self.np_array[iy1, ix1]) or
self.__check_value_is_nodata(self.np_array[iy1, ix2]) or
self.__check_value_is_nodata(self.np_array[iy2, ix1]) or
self.__check_value_is_nodata(self.np_array[iy2, ix2])):
return self.no_data
return ((self.np_array[iy1, ix1] * dx2 * dy2) / div +
(self.np_array[iy1, ix2] * dx1 * dy2) / div +
(self.np_array[iy2, ix1] * dx2 * dy1) / div +
(self.np_array[iy2, ix2] * dx1 * dy1) / div)
def get_values_bilinear(self, positions: List[List[float]]) -> List[float]:
"""
The same function as `get_value_bilinear()` on vectorized for list definition of locations.
Parameters
----------
positions : list of list of float
Position for interpolation of raster values. The format should be
`positions=[[px1,py1],[px2,py2],[px3,py3]]`.
Returns
-------
list of float
For every element of list of `positions` one element in list.
Raises
------
ValueError
If element of positions is not list with `len() == 2`.
See Also
--------
get_value_bilinear : Get value bilinear
"""
values: list = [None] * len(positions)
i: int = 0
for position in positions:
if len(position) != 2:
pos_str = [str(x) for x in position]
raise ValueError("Every element of list of positions must be of length `2`. "
"Element `{0}`, has `{1}` elements (values: `{2}`)".format(i,
len(position),
", ".join(pos_str)))
values[i] = self.get_value_bilinear(position[0], position[1])
i += 1
return values
def get_values_points_bilinear(self, points: List[ogr.Geometry]) -> List[float]:
"""
The same function as `get_values_bilinear()` but with different parameter.
Parameters
----------
points : list of ogr.Geometry
List of `ogr.Geometry` points (`ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM, ogr.wkbPointZM`) to get raster
value at.
Returns
-------
list of float
For every element of list of `points` one element in list.
Raises
------
ValueError
If element of `points` is not `ogr.Geometry` with type `ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM or
ogr.wkbPointZM`.
See Also
--------
get_value_bilinear : Get value bilinear
get_values_bilinear : Get values bilinear
"""
values: list = [None] * len(points)
i: int = 0
for p in points:
geometry_checks.check_variable_expected_geometry(p, "point[{}]".format(i), [ogr.wkbPoint, ogr.wkbPoint25D,
ogr.wkbPointM, ogr.wkbPointZM])
values[i] = self.get_value_bilinear(p.GetX(), p.GetY())
i += 1
return values
Classes
class DEM (path, epsg=None)-
Class representing digital elevation model. Based on
gdal.Datasetwith additional functions. Various checks are performed at creation time to ensure usability of the data.DEMcan only have one band with values and the raster has to projected.Attributes
path:str- Path to the stored dataset.
ds:gdal.Dataset- Raster dataset in
gdal. projection:osr.SpatialReferenceosr.SpatialReferencefor fromds.gt- Result of
ds.GetGeoTransform()function. nx,ny:int- Raster size in x and y direction in cells.
no_data:float- Value from functions
ds.GetRasterBand(1).GetNoDataValue(). np_array:np.array- Two dimensional numpy array of values from
ds.
Construct function.
Parameters
path:str- Path to load the data from.
epsg:int, optional- EPSG code of raster projection.
Expand source code
class DEM: """ Class representing digital elevation model. Based on `gdal.Dataset` with additional functions. Various checks are performed at creation time to ensure usability of the data. `DEM` can only have one band with values and the raster has to projected. Attributes ---------- path : str Path to the stored dataset. ds : gdal.Dataset Raster dataset in `gdal`. projection : osr.SpatialReference `osr.SpatialReference` for from `ds`. gt Result of `ds.GetGeoTransform()` function. nx, ny : int Raster size in x and y direction in cells. no_data : float Value from functions `ds.GetRasterBand(1).GetNoDataValue()`. np_array : np.array Two dimensional numpy array of values from `ds`. """ __band_number = 1 __gdal_nodata_default = -3.4028e+38 def __init__(self, path: str, epsg: int = None): """ Construct function. Parameters ---------- path : str Path to load the data from. epsg : int, optional EPSG code of raster projection. """ if not os.path.isfile(path): raise IOError("File at specified path `{0}` does not exist.".format(path)) self.path = path self.ds = gdal.Open(self.path) if self.ds.RasterCount > 1: raise ValueError("DEM is only allowed to have one band. The raster has `{}` bands." .format(self.ds.RasterCount)) projection = self.ds.GetProjection() projection = osr.SpatialReference(wkt=projection) if projection.ExportToWkt() == "" and epsg is None: raise ValueError("Cannot obtain projection from raster `{0}` and epsg argument is not set." .format(path)) if projection != "" and epsg is not None: epsg = None warnings.warn( "Raster has specified projection and epsg is set. Using projection from raster!", SyntaxWarning) if epsg is None: if projection.IsProjected() != 1: raise ValueError("DEM has to be projected, the given projection is not projected: \n `{0}`." .format(projection.ExportToWkt())) else: projection = osr.SpatialReference() projection.ImportFromEPSG(epsg) if projection.IsProjected() != 1: raise ValueError("DEM has to be projected, the definition of provided EPSG is not projected: \n `{0}`.". format(projection.ExportToProj4())) else: self.ds.SetProjection(projection.ExportToWkt()) self.gt = self.ds.GetGeoTransform() self.nx = self.ds.RasterXSize self.ny = self.ds.RasterYSize self.no_data = self.ds.GetRasterBand(self.__band_number).GetNoDataValue() self.np_array = None @classmethod def from_gdal_raster(cls, gdal_raster: gdal.Dataset): """ Class method to build `DEM` from `gdal.Dataset`. Parameters ---------- gdal_raster : gdal.Dataset Build `DEM` based on allready loaded raster data. Returns ------- None """ if not isinstance(gdal_raster, gdal.Dataset): raise TypeError("`gdal_raster` has to be of type `gdal.Dataset`. " "But it is type `{0}`".format(type(gdal_raster).__name__)) return cls(path=gdal_raster.GetDescription()) def __str__(self): """ String representation of class `DEM`. Returns ------- str Represetation of DEM. """ return "Raster from `{0}` with sizes(`{1}`, `{2}`) using projection `{3}`.".format(self.path, self.nx, self.ny, self.ds.GetProjection()) def __del__(self): """ Upon deletion of the object close connection and clear array. Returns ------- None """ self.ds = None self.destroy_array() def get_min_pixel_size(self) -> float: """ Get minimal pixel size in either row or column direction. Returns ------- float Minimal pixel size in either row or column direction. """ return abs(min(self.gt[1], self.gt[5])) def __check_value_is_nodata(self, value: Union[int, float]) -> bool: return (value < self.__gdal_nodata_default) or math_helpers.is_almost_equal(value, self.no_data) def load_array(self) -> None: """ Read raster values into numpy array. Returns ------- None """ self.np_array = self.ds.GetRasterBand(self.__band_number).ReadAsArray() def destroy_array(self) -> None: """ Clear numpy array with raster values. Returns ------- None """ self.np_array = None def get_nodata_value(self) -> float: """ Get no data value of the raster. Returns ------- float No data value of the raster. """ return self.no_data def get_max_size(self) -> float: """ Get larger size of the raster in map units. Calculated as pixel width/height times raster width/height. Returns ------- float Maximal raster size. """ return max(self.gt[1] * self.nx, self.gt[5] * self.ny) def get_diagonal_size(self) -> float: """ Get diagonal size of the raster in map units. Returns ------- float Raster size in diagonal direction. """ size = math.sqrt(math.pow(self.gt[1] * self.nx, 2) + math.pow(self.gt[5] * self.ny, 2)) return size def get_bounding_box(self) -> ogr.Geometry: """ Get bounding box of the raster. Returns ------- ogr.Geometry Bounding box of the raster. """ x1 = self.gt[0] x2 = self.gt[0] + self.nx * self.gt[1] y1 = self.gt[3] y2 = self.gt[3] + self.ny * self.gt[5] ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(min(x1, x2), min(y1, y2)) ring.AddPoint(max(x1, x2), min(y1, y2)) ring.AddPoint(max(x1, x2), max(y1, y2)) ring.AddPoint(min(x1, x2), max(y1, y2)) ring.AddPoint(min(x1, x2), min(y1, y2)) bbox = ogr.Geometry(ogr.wkbPolygon) bbox.AddGeometry(ring) return bbox # code from http://gis.stackexchange.com/questions/7611/bilinear-interpolation-of-point-data-on-a-raster-in-python def get_value_bilinear(self, px: float, py: float) -> float: """ Get bilinear interpolated value from the raster at point (px, py). Parameters ---------- px, py : float Point coordinates in raster units. Returns ------- float Interpolated value of the raster at specified location. """ if not isinstance(px, (int, float)): raise TypeError("px must be number. The variable is of `{}`.".format(type(px))) if not isinstance(py, (int, float)): raise TypeError("py must be number. The variable is of `{}`.".format(type(py))) if self.np_array is None: self.load_array() ny, nx = self.np_array.shape # Half raster cell widths hx = self.gt[1] / 2.0 hy = self.gt[5] / 2.0 # Calculate raster lower bound indices from point fx = (px - (self.gt[0] + hx)) / self.gt[1] fy = (py - (self.gt[3] + hy)) / self.gt[5] ix1 = int(floor(fx)) iy1 = int(floor(fy)) # Special case where point is on upper bounds if fx == float(nx - 1): ix1 -= 1 if fy == float(ny - 1): iy1 -= 1 # Upper bound indices on raster ix2 = ix1 + 1 iy2 = iy1 + 1 # Test array bounds to ensure point is within raster midpoints if (ix1 < 0) or (iy1 < 0) or (ix2 > nx - 1) or (iy2 > ny - 1): return self.no_data # Calculate differences from point to bounding raster midpoints dx1 = px - (self.gt[0] + ix1 * self.gt[1] + hx) dy1 = py - (self.gt[3] + iy1 * self.gt[5] + hy) dx2 = (self.gt[0] + ix2 * self.gt[1] + hx) - px dy2 = (self.gt[3] + iy2 * self.gt[5] + hy) - py # Use the differences to weigh the four raster values div = self.gt[1] * self.gt[5] # if any value is nodata then everything is nodata if (self.__check_value_is_nodata(self.np_array[iy1, ix1]) or self.__check_value_is_nodata(self.np_array[iy1, ix2]) or self.__check_value_is_nodata(self.np_array[iy2, ix1]) or self.__check_value_is_nodata(self.np_array[iy2, ix2])): return self.no_data return ((self.np_array[iy1, ix1] * dx2 * dy2) / div + (self.np_array[iy1, ix2] * dx1 * dy2) / div + (self.np_array[iy2, ix1] * dx2 * dy1) / div + (self.np_array[iy2, ix2] * dx1 * dy1) / div) def get_values_bilinear(self, positions: List[List[float]]) -> List[float]: """ The same function as `get_value_bilinear()` on vectorized for list definition of locations. Parameters ---------- positions : list of list of float Position for interpolation of raster values. The format should be `positions=[[px1,py1],[px2,py2],[px3,py3]]`. Returns ------- list of float For every element of list of `positions` one element in list. Raises ------ ValueError If element of positions is not list with `len() == 2`. See Also -------- get_value_bilinear : Get value bilinear """ values: list = [None] * len(positions) i: int = 0 for position in positions: if len(position) != 2: pos_str = [str(x) for x in position] raise ValueError("Every element of list of positions must be of length `2`. " "Element `{0}`, has `{1}` elements (values: `{2}`)".format(i, len(position), ", ".join(pos_str))) values[i] = self.get_value_bilinear(position[0], position[1]) i += 1 return values def get_values_points_bilinear(self, points: List[ogr.Geometry]) -> List[float]: """ The same function as `get_values_bilinear()` but with different parameter. Parameters ---------- points : list of ogr.Geometry List of `ogr.Geometry` points (`ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM, ogr.wkbPointZM`) to get raster value at. Returns ------- list of float For every element of list of `points` one element in list. Raises ------ ValueError If element of `points` is not `ogr.Geometry` with type `ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM or ogr.wkbPointZM`. See Also -------- get_value_bilinear : Get value bilinear get_values_bilinear : Get values bilinear """ values: list = [None] * len(points) i: int = 0 for p in points: geometry_checks.check_variable_expected_geometry(p, "point[{}]".format(i), [ogr.wkbPoint, ogr.wkbPoint25D, ogr.wkbPointM, ogr.wkbPointZM]) values[i] = self.get_value_bilinear(p.GetX(), p.GetY()) i += 1 return valuesStatic methods
def from_gdal_raster(gdal_raster)-
Class method to build
DEMfromgdal.Dataset.Parameters
gdal_raster:gdal.Dataset- Build
DEMbased on allready loaded raster data.
Returns
None
Expand source code
@classmethod def from_gdal_raster(cls, gdal_raster: gdal.Dataset): """ Class method to build `DEM` from `gdal.Dataset`. Parameters ---------- gdal_raster : gdal.Dataset Build `DEM` based on allready loaded raster data. Returns ------- None """ if not isinstance(gdal_raster, gdal.Dataset): raise TypeError("`gdal_raster` has to be of type `gdal.Dataset`. " "But it is type `{0}`".format(type(gdal_raster).__name__)) return cls(path=gdal_raster.GetDescription())
Methods
def destroy_array(self)-
Clear numpy array with raster values.
Returns
None
Expand source code
def destroy_array(self) -> None: """ Clear numpy array with raster values. Returns ------- None """ self.np_array = None def get_bounding_box(self)-
Get bounding box of the raster.
Returns
ogr.Geometry- Bounding box of the raster.
Expand source code
def get_bounding_box(self) -> ogr.Geometry: """ Get bounding box of the raster. Returns ------- ogr.Geometry Bounding box of the raster. """ x1 = self.gt[0] x2 = self.gt[0] + self.nx * self.gt[1] y1 = self.gt[3] y2 = self.gt[3] + self.ny * self.gt[5] ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(min(x1, x2), min(y1, y2)) ring.AddPoint(max(x1, x2), min(y1, y2)) ring.AddPoint(max(x1, x2), max(y1, y2)) ring.AddPoint(min(x1, x2), max(y1, y2)) ring.AddPoint(min(x1, x2), min(y1, y2)) bbox = ogr.Geometry(ogr.wkbPolygon) bbox.AddGeometry(ring) return bbox def get_diagonal_size(self)-
Get diagonal size of the raster in map units.
Returns
float- Raster size in diagonal direction.
Expand source code
def get_diagonal_size(self) -> float: """ Get diagonal size of the raster in map units. Returns ------- float Raster size in diagonal direction. """ size = math.sqrt(math.pow(self.gt[1] * self.nx, 2) + math.pow(self.gt[5] * self.ny, 2)) return size def get_max_size(self)-
Get larger size of the raster in map units. Calculated as pixel width/height times raster width/height.
Returns
float- Maximal raster size.
Expand source code
def get_max_size(self) -> float: """ Get larger size of the raster in map units. Calculated as pixel width/height times raster width/height. Returns ------- float Maximal raster size. """ return max(self.gt[1] * self.nx, self.gt[5] * self.ny) def get_min_pixel_size(self)-
Get minimal pixel size in either row or column direction.
Returns
float- Minimal pixel size in either row or column direction.
Expand source code
def get_min_pixel_size(self) -> float: """ Get minimal pixel size in either row or column direction. Returns ------- float Minimal pixel size in either row or column direction. """ return abs(min(self.gt[1], self.gt[5])) def get_nodata_value(self)-
Get no data value of the raster.
Returns
float- No data value of the raster.
Expand source code
def get_nodata_value(self) -> float: """ Get no data value of the raster. Returns ------- float No data value of the raster. """ return self.no_data def get_value_bilinear(self, px, py)-
Get bilinear interpolated value from the raster at point (px, py).
Parameters
px,py:float- Point coordinates in raster units.
Returns
float- Interpolated value of the raster at specified location.
Expand source code
def get_value_bilinear(self, px: float, py: float) -> float: """ Get bilinear interpolated value from the raster at point (px, py). Parameters ---------- px, py : float Point coordinates in raster units. Returns ------- float Interpolated value of the raster at specified location. """ if not isinstance(px, (int, float)): raise TypeError("px must be number. The variable is of `{}`.".format(type(px))) if not isinstance(py, (int, float)): raise TypeError("py must be number. The variable is of `{}`.".format(type(py))) if self.np_array is None: self.load_array() ny, nx = self.np_array.shape # Half raster cell widths hx = self.gt[1] / 2.0 hy = self.gt[5] / 2.0 # Calculate raster lower bound indices from point fx = (px - (self.gt[0] + hx)) / self.gt[1] fy = (py - (self.gt[3] + hy)) / self.gt[5] ix1 = int(floor(fx)) iy1 = int(floor(fy)) # Special case where point is on upper bounds if fx == float(nx - 1): ix1 -= 1 if fy == float(ny - 1): iy1 -= 1 # Upper bound indices on raster ix2 = ix1 + 1 iy2 = iy1 + 1 # Test array bounds to ensure point is within raster midpoints if (ix1 < 0) or (iy1 < 0) or (ix2 > nx - 1) or (iy2 > ny - 1): return self.no_data # Calculate differences from point to bounding raster midpoints dx1 = px - (self.gt[0] + ix1 * self.gt[1] + hx) dy1 = py - (self.gt[3] + iy1 * self.gt[5] + hy) dx2 = (self.gt[0] + ix2 * self.gt[1] + hx) - px dy2 = (self.gt[3] + iy2 * self.gt[5] + hy) - py # Use the differences to weigh the four raster values div = self.gt[1] * self.gt[5] # if any value is nodata then everything is nodata if (self.__check_value_is_nodata(self.np_array[iy1, ix1]) or self.__check_value_is_nodata(self.np_array[iy1, ix2]) or self.__check_value_is_nodata(self.np_array[iy2, ix1]) or self.__check_value_is_nodata(self.np_array[iy2, ix2])): return self.no_data return ((self.np_array[iy1, ix1] * dx2 * dy2) / div + (self.np_array[iy1, ix2] * dx1 * dy2) / div + (self.np_array[iy2, ix1] * dx2 * dy1) / div + (self.np_array[iy2, ix2] * dx1 * dy1) / div) def get_values_bilinear(self, positions)-
The same function as
get_value_bilinear()on vectorized for list definition of locations.Parameters
positions:listoflistoffloat- Position for interpolation of raster values. The format should be
positions=[[px1,py1],[px2,py2],[px3,py3]].
Returns
listoffloat- For every element of list of
positionsone element in list.
Raises
ValueError- If element of positions is not list with
len() == 2.
See Also
get_value_bilinear- Get value bilinear
Expand source code
def get_values_bilinear(self, positions: List[List[float]]) -> List[float]: """ The same function as `get_value_bilinear()` on vectorized for list definition of locations. Parameters ---------- positions : list of list of float Position for interpolation of raster values. The format should be `positions=[[px1,py1],[px2,py2],[px3,py3]]`. Returns ------- list of float For every element of list of `positions` one element in list. Raises ------ ValueError If element of positions is not list with `len() == 2`. See Also -------- get_value_bilinear : Get value bilinear """ values: list = [None] * len(positions) i: int = 0 for position in positions: if len(position) != 2: pos_str = [str(x) for x in position] raise ValueError("Every element of list of positions must be of length `2`. " "Element `{0}`, has `{1}` elements (values: `{2}`)".format(i, len(position), ", ".join(pos_str))) values[i] = self.get_value_bilinear(position[0], position[1]) i += 1 return values def get_values_points_bilinear(self, points)-
The same function as
get_values_bilinear()but with different parameter.Parameters
points:listofogr.Geometry- List of
ogr.Geometrypoints (ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM, ogr.wkbPointZM) to get raster value at.
Returns
listoffloat- For every element of list of
pointsone element in list.
Raises
ValueError- If element of
pointsis notogr.Geometrywith typeogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM or ogr.wkbPointZM.
See Also
get_value_bilinear- Get value bilinear
get_values_bilinear- Get values bilinear
Expand source code
def get_values_points_bilinear(self, points: List[ogr.Geometry]) -> List[float]: """ The same function as `get_values_bilinear()` but with different parameter. Parameters ---------- points : list of ogr.Geometry List of `ogr.Geometry` points (`ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM, ogr.wkbPointZM`) to get raster value at. Returns ------- list of float For every element of list of `points` one element in list. Raises ------ ValueError If element of `points` is not `ogr.Geometry` with type `ogr.wkbPoint, ogr.wkbPoint25D, gr.wkbPointM or ogr.wkbPointZM`. See Also -------- get_value_bilinear : Get value bilinear get_values_bilinear : Get values bilinear """ values: list = [None] * len(points) i: int = 0 for p in points: geometry_checks.check_variable_expected_geometry(p, "point[{}]".format(i), [ogr.wkbPoint, ogr.wkbPoint25D, ogr.wkbPointM, ogr.wkbPointZM]) values[i] = self.get_value_bilinear(p.GetX(), p.GetY()) i += 1 return values def load_array(self)-
Read raster values into numpy array.
Returns
None
Expand source code
def load_array(self) -> None: """ Read raster values into numpy array. Returns ------- None """ self.np_array = self.ds.GetRasterBand(self.__band_number).ReadAsArray()