yirgacheffe 1.3.4__py3-none-any.whl → 1.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yirgacheffe might be problematic. Click here for more details.
- yirgacheffe/__init__.py +0 -3
- yirgacheffe/{backends → _backends}/__init__.py +1 -1
- yirgacheffe/{backends → _backends}/mlx.py +3 -2
- yirgacheffe/{backends → _backends}/numpy.py +2 -1
- yirgacheffe/layers/__init__.py +0 -29
- yirgacheffe/layers/base.py +20 -7
- yirgacheffe/layers/constant.py +1 -1
- yirgacheffe/layers/group.py +14 -11
- yirgacheffe/layers/h3layer.py +7 -2
- yirgacheffe/layers/rasters.py +27 -16
- yirgacheffe/layers/rescaled.py +3 -2
- yirgacheffe/layers/vectors.py +37 -30
- yirgacheffe/operators.py +15 -12
- yirgacheffe/window.py +93 -2
- {yirgacheffe-1.3.4.dist-info → yirgacheffe-1.4.1.dist-info}/METADATA +2 -1
- yirgacheffe-1.4.1.dist-info/RECORD +24 -0
- yirgacheffe/h3layer.py +0 -2
- yirgacheffe-1.3.4.dist-info/RECORD +0 -25
- /yirgacheffe/{backends → _backends}/enumeration.py +0 -0
- {yirgacheffe-1.3.4.dist-info → yirgacheffe-1.4.1.dist-info}/WHEEL +0 -0
- {yirgacheffe-1.3.4.dist-info → yirgacheffe-1.4.1.dist-info}/entry_points.txt +0 -0
- {yirgacheffe-1.3.4.dist-info → yirgacheffe-1.4.1.dist-info}/licenses/LICENSE +0 -0
- {yirgacheffe-1.3.4.dist-info → yirgacheffe-1.4.1.dist-info}/top_level.txt +0 -0
yirgacheffe/__init__.py
CHANGED
|
@@ -12,6 +12,3 @@ WGS_84_PROJECTION = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,
|
|
|
12
12
|
'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],'\
|
|
13
13
|
'UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],'\
|
|
14
14
|
'AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]'
|
|
15
|
-
|
|
16
|
-
# For legacy reasons [facepalm]
|
|
17
|
-
WSG_84_PROJECTION = WGS_84_PROJECTION
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from typing import Callable, Dict
|
|
1
2
|
|
|
2
3
|
import numpy as np
|
|
3
|
-
import mlx.core as mx #
|
|
4
|
+
import mlx.core as mx # type: ignore
|
|
4
5
|
import mlx.nn
|
|
5
6
|
|
|
6
7
|
from .enumeration import operators as op
|
|
@@ -182,7 +183,7 @@ def backend_to_dtype(val):
|
|
|
182
183
|
def astype_op(data, datatype):
|
|
183
184
|
return data.astype(dtype_to_backed(datatype))
|
|
184
185
|
|
|
185
|
-
operator_map = {
|
|
186
|
+
operator_map : Dict[op,Callable] = {
|
|
186
187
|
op.ADD: mx.array.__add__,
|
|
187
188
|
op.SUB: mx.array.__sub__,
|
|
188
189
|
op.MUL: mul_op,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from typing import Callable, Dict
|
|
1
2
|
|
|
2
3
|
import numpy as np
|
|
3
4
|
import torch
|
|
@@ -120,7 +121,7 @@ def backend_to_dtype(val):
|
|
|
120
121
|
def astype_op(data, datatype):
|
|
121
122
|
return data.astype(dtype_to_backed(datatype))
|
|
122
123
|
|
|
123
|
-
operator_map = {
|
|
124
|
+
operator_map : Dict[op,Callable] = {
|
|
124
125
|
op.ADD: np.ndarray.__add__,
|
|
125
126
|
op.SUB: np.ndarray.__sub__,
|
|
126
127
|
op.MUL: np.ndarray.__mul__,
|
yirgacheffe/layers/__init__.py
CHANGED
|
@@ -12,32 +12,3 @@ try:
|
|
|
12
12
|
from .h3layer import H3CellLayer
|
|
13
13
|
except ModuleNotFoundError:
|
|
14
14
|
pass
|
|
15
|
-
|
|
16
|
-
class Layer(RasterLayer):
|
|
17
|
-
"""A place holder for now, at some point I want to replace Layer with RasterLayer."""
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class VectorRangeLayer(RasteredVectorLayer):
|
|
21
|
-
"""Deprecated older name for VectorLayer"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, range_vectors: str, where_filter: str, scale: PixelScale, projection: str):
|
|
24
|
-
vectors = ogr.Open(range_vectors)
|
|
25
|
-
if vectors is None:
|
|
26
|
-
raise FileNotFoundError(range_vectors)
|
|
27
|
-
layer = vectors.GetLayer()
|
|
28
|
-
if where_filter is not None:
|
|
29
|
-
layer.SetAttributeFilter(where_filter)
|
|
30
|
-
super().__init__(layer, scale, projection)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class DynamicVectorRangeLayer(VectorLayer):
|
|
34
|
-
"""Deprecated older name DynamicVectorLayer"""
|
|
35
|
-
|
|
36
|
-
def __init__(self, range_vectors: str, where_filter: str, scale: PixelScale, projection: str):
|
|
37
|
-
vectors = ogr.Open(range_vectors)
|
|
38
|
-
if vectors is None:
|
|
39
|
-
raise FileNotFoundError(range_vectors)
|
|
40
|
-
layer = vectors.GetLayer()
|
|
41
|
-
if where_filter is not None:
|
|
42
|
-
layer.SetAttributeFilter(where_filter)
|
|
43
|
-
super().__init__(layer, scale, projection)
|
yirgacheffe/layers/base.py
CHANGED
|
@@ -25,7 +25,7 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
25
25
|
|
|
26
26
|
self.reset_window()
|
|
27
27
|
|
|
28
|
-
def close(self):
|
|
28
|
+
def close(self) -> None:
|
|
29
29
|
pass
|
|
30
30
|
|
|
31
31
|
def __enter__(self):
|
|
@@ -34,6 +34,16 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
34
34
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
35
35
|
self.close()
|
|
36
36
|
|
|
37
|
+
def _park(self) -> None:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
def _unpark(self) -> None:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def _raster_dimensions(self) -> Tuple[int,int]:
|
|
45
|
+
raise AttributeError("Does not have raster")
|
|
46
|
+
|
|
37
47
|
@property
|
|
38
48
|
def datatype(self) -> DataType:
|
|
39
49
|
raise NotImplementedError("Must be overridden by subclass")
|
|
@@ -131,9 +141,10 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
131
141
|
raise ValueError('Window has negative offset')
|
|
132
142
|
# If there is an underlying raster for this layer, do a sanity check
|
|
133
143
|
try:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
raster_xsize, raster_ysize = self._raster_dimensions
|
|
145
|
+
if ((new_window.xoff + new_window.xsize) > raster_xsize) or \
|
|
146
|
+
((new_window.yoff + new_window.ysize) > raster_ysize):
|
|
147
|
+
raise ValueError(f'Window is bigger than dataset: raster is {raster_xsize}x{raster_ysize}'\
|
|
137
148
|
f', new window is {new_window.xsize - new_window.xoff}x{new_window.ysize - new_window.yoff}')
|
|
138
149
|
except AttributeError:
|
|
139
150
|
pass
|
|
@@ -162,9 +173,10 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
162
173
|
raise ValueError('Window has positive offset')
|
|
163
174
|
# If there is an underlying raster for this layer, do a sanity check
|
|
164
175
|
try:
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
176
|
+
raster_xsize, raster_ysize = self._raster_dimensions
|
|
177
|
+
if ((new_window.xsize - new_window.xoff) < raster_xsize) or \
|
|
178
|
+
((new_window.ysize - new_window.yoff) <raster_ysize):
|
|
179
|
+
raise ValueError(f'Window is smaller than dataset: raster is {raster_xsize}x{raster_ysize}'\
|
|
168
180
|
f', new window is {new_window.xsize - new_window.xoff}x{new_window.ysize - new_window.yoff}')
|
|
169
181
|
except AttributeError:
|
|
170
182
|
pass
|
|
@@ -219,6 +231,7 @@ class YirgacheffeLayer(LayerMathMixin):
|
|
|
219
231
|
raise NotImplementedError("Must be overridden by subclass")
|
|
220
232
|
|
|
221
233
|
def read_array_for_area(self, target_area: Area, x: int, y: int, width: int, height: int) -> Any:
|
|
234
|
+
assert self._pixel_scale is not None
|
|
222
235
|
|
|
223
236
|
target_window = Window(
|
|
224
237
|
xoff=round_down_pixels((target_area.left - self._underlying_area.left) / self._pixel_scale.xstep,
|
yirgacheffe/layers/constant.py
CHANGED
yirgacheffe/layers/group.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import copy
|
|
2
3
|
import glob
|
|
3
4
|
import os
|
|
4
|
-
from typing import Any, List, Optional
|
|
5
|
+
from typing import Any, List, Optional
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
7
8
|
from yirgacheffe.operators import DataType
|
|
@@ -10,9 +11,8 @@ from ..rounding import are_pixel_scales_equal_enough, round_down_pixels
|
|
|
10
11
|
from ..window import Area, Window
|
|
11
12
|
from .base import YirgacheffeLayer
|
|
12
13
|
from .rasters import RasterLayer
|
|
13
|
-
from ..
|
|
14
|
+
from .._backends import backend
|
|
14
15
|
|
|
15
|
-
GroupLayerT = TypeVar("GroupLayerT", bound="GroupLayer")
|
|
16
16
|
|
|
17
17
|
class GroupLayerEmpty(ValueError):
|
|
18
18
|
def __init__(self, msg):
|
|
@@ -26,7 +26,7 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
26
26
|
directory_path: str,
|
|
27
27
|
name: Optional[str] = None,
|
|
28
28
|
matching: str = "*.tif"
|
|
29
|
-
) ->
|
|
29
|
+
) -> GroupLayer:
|
|
30
30
|
if directory_path is None:
|
|
31
31
|
raise ValueError("Directory path is None")
|
|
32
32
|
files = [os.path.join(directory_path, x) for x in glob.glob(matching, root_dir=directory_path)]
|
|
@@ -35,12 +35,12 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
35
35
|
return cls.layer_from_files(files, name)
|
|
36
36
|
|
|
37
37
|
@classmethod
|
|
38
|
-
def layer_from_files(cls, filenames: List[str], name: Optional[str] = None) ->
|
|
38
|
+
def layer_from_files(cls, filenames: List[str], name: Optional[str] = None) -> GroupLayer:
|
|
39
39
|
if filenames is None:
|
|
40
40
|
raise ValueError("filenames argument is None")
|
|
41
41
|
if len(filenames) < 1:
|
|
42
42
|
raise GroupLayerEmpty("No files found")
|
|
43
|
-
rasters = [RasterLayer.layer_from_file(x) for x in filenames]
|
|
43
|
+
rasters: List[YirgacheffeLayer] = [RasterLayer.layer_from_file(x) for x in filenames]
|
|
44
44
|
return cls(rasters, name)
|
|
45
45
|
|
|
46
46
|
def __init__(self, layers: List[YirgacheffeLayer], name: Optional[str] = None) -> None:
|
|
@@ -65,7 +65,7 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
65
65
|
self._underlying_layers.reverse()
|
|
66
66
|
self.layers = self._underlying_layers
|
|
67
67
|
|
|
68
|
-
def _park(self):
|
|
68
|
+
def _park(self) -> None:
|
|
69
69
|
for layer in self.layers:
|
|
70
70
|
try:
|
|
71
71
|
layer._park()
|
|
@@ -157,7 +157,7 @@ class GroupLayer(YirgacheffeLayer):
|
|
|
157
157
|
class TileData:
|
|
158
158
|
"""This class exists just to let me sort the tiles into the correct order for processing."""
|
|
159
159
|
|
|
160
|
-
def __init__(self, data, x, y):
|
|
160
|
+
def __init__(self, data: Any, x: int, y: int):
|
|
161
161
|
self.data = data
|
|
162
162
|
self.x = x
|
|
163
163
|
self.y = y
|
|
@@ -219,7 +219,7 @@ class TiledGroupLayer(GroupLayer):
|
|
|
219
219
|
ysize
|
|
220
220
|
)
|
|
221
221
|
|
|
222
|
-
partials = []
|
|
222
|
+
partials: List[TileData] = []
|
|
223
223
|
for layer in self.layers:
|
|
224
224
|
# Normally this is hidden with set_window_for_...
|
|
225
225
|
adjusted_layer_window = Window(
|
|
@@ -251,7 +251,7 @@ class TiledGroupLayer(GroupLayer):
|
|
|
251
251
|
# the "obvious" tile. In which case, we should reject the smaller section. If we have
|
|
252
252
|
# two tiles at the same offset and one is not a perfect subset of the other then the
|
|
253
253
|
# tile set we were given is not regularly shaped, and so we should give up.
|
|
254
|
-
combed_partials = []
|
|
254
|
+
combed_partials: List[TileData] = []
|
|
255
255
|
previous_tile = None
|
|
256
256
|
for tile in sorted_partials:
|
|
257
257
|
if previous_tile is None:
|
|
@@ -276,7 +276,7 @@ class TiledGroupLayer(GroupLayer):
|
|
|
276
276
|
expected_next_x = 0
|
|
277
277
|
expected_next_y = 0
|
|
278
278
|
data = None
|
|
279
|
-
row_chunk = None
|
|
279
|
+
row_chunk: Optional[np.ndarray] = None
|
|
280
280
|
|
|
281
281
|
# Allow for reading off top
|
|
282
282
|
if combed_partials:
|
|
@@ -337,6 +337,7 @@ class TiledGroupLayer(GroupLayer):
|
|
|
337
337
|
data = np.vstack((data, row_chunk))
|
|
338
338
|
expected_next_y += last_y_height
|
|
339
339
|
else:
|
|
340
|
+
assert last_y_offset is not None
|
|
340
341
|
diff = expected_next_y - last_y_offset
|
|
341
342
|
assert diff > 0, f"{expected_next_y} - {last_y_offset} <= 0 (aka {diff})"
|
|
342
343
|
subdata = np.delete(row_chunk, np.s_[0:diff], 0)
|
|
@@ -351,8 +352,10 @@ class TiledGroupLayer(GroupLayer):
|
|
|
351
352
|
last_y_height = tile.data.shape[0]
|
|
352
353
|
expected_next_x = tile.data.shape[1] + tile.x
|
|
353
354
|
|
|
355
|
+
assert last_y_offset is not None
|
|
354
356
|
if (last_y_offset + last_y_height) < ysize:
|
|
355
357
|
data = np.vstack((data, np.zeros((ysize - (last_y_offset + last_y_height), xsize))))
|
|
356
358
|
|
|
359
|
+
assert data is not None
|
|
357
360
|
assert data.shape == (ysize, xsize)
|
|
358
361
|
return backend.promote(data)
|
yirgacheffe/layers/h3layer.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from math import ceil, floor
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any, Tuple
|
|
3
3
|
|
|
4
4
|
import h3
|
|
5
5
|
import numpy as np
|
|
@@ -8,7 +8,7 @@ from yirgacheffe.operators import DataType
|
|
|
8
8
|
from ..rounding import round_up_pixels
|
|
9
9
|
from ..window import Area, PixelScale, Window
|
|
10
10
|
from .base import YirgacheffeLayer
|
|
11
|
-
from ..
|
|
11
|
+
from .._backends import backend
|
|
12
12
|
|
|
13
13
|
class H3CellLayer(YirgacheffeLayer):
|
|
14
14
|
|
|
@@ -74,12 +74,17 @@ class H3CellLayer(YirgacheffeLayer):
|
|
|
74
74
|
(sorted_lats[1] / abs_ystep) * abs_ystep,
|
|
75
75
|
)
|
|
76
76
|
|
|
77
|
+
@property
|
|
78
|
+
def _raster_dimensions(self) -> Tuple[int,int]:
|
|
79
|
+
return (self._raster_xsize, self._raster_ysize)
|
|
77
80
|
|
|
78
81
|
@property
|
|
79
82
|
def datatype(self) -> DataType:
|
|
80
83
|
return DataType.Float64
|
|
81
84
|
|
|
82
85
|
def read_array_with_window(self, xoffset: int, yoffset: int, xsize: int, ysize: int, window: Window) -> Any:
|
|
86
|
+
assert self._pixel_scale is not None
|
|
87
|
+
|
|
83
88
|
if (xsize <= 0) or (ysize <= 0):
|
|
84
89
|
raise ValueError("Request dimensions must be positive and non-zero")
|
|
85
90
|
|
yirgacheffe/layers/rasters.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import math
|
|
2
3
|
import os
|
|
3
|
-
from typing import Any, Optional,
|
|
4
|
+
from typing import Any, Optional, Tuple, Union
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
7
|
from osgeo import gdal
|
|
@@ -10,10 +11,7 @@ from ..window import Area, PixelScale, Window
|
|
|
10
11
|
from ..rounding import round_up_pixels
|
|
11
12
|
from .base import YirgacheffeLayer
|
|
12
13
|
from ..operators import DataType
|
|
13
|
-
from ..
|
|
14
|
-
|
|
15
|
-
# Still to early to require Python 3.11 :/
|
|
16
|
-
RasterLayerT = TypeVar("RasterLayerT", bound="RasterLayer")
|
|
14
|
+
from .._backends import backend
|
|
17
15
|
|
|
18
16
|
class InvalidRasterBand(Exception):
|
|
19
17
|
def __init__ (self, band):
|
|
@@ -37,7 +35,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
37
35
|
nbits: Optional[int]=None,
|
|
38
36
|
threads: Optional[int]=None,
|
|
39
37
|
bands: int=1
|
|
40
|
-
) ->
|
|
38
|
+
) -> RasterLayer:
|
|
41
39
|
abs_xstep, abs_ystep = abs(scale.xstep), abs(scale.ystep)
|
|
42
40
|
|
|
43
41
|
# We treat the provided area as aspirational, and we need to align it to pixel boundaries
|
|
@@ -50,7 +48,9 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
50
48
|
|
|
51
49
|
# This used to the the GDAL type, so we support that for legacy reasons
|
|
52
50
|
if isinstance(datatype, int):
|
|
53
|
-
|
|
51
|
+
datatype_arg = DataType.of_gdal(datatype)
|
|
52
|
+
else:
|
|
53
|
+
datatype_arg = datatype
|
|
54
54
|
|
|
55
55
|
options = []
|
|
56
56
|
if threads is not None:
|
|
@@ -74,7 +74,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
74
74
|
round_up_pixels((pixel_friendly_area.right - pixel_friendly_area.left) / abs_xstep, abs_xstep),
|
|
75
75
|
round_up_pixels((pixel_friendly_area.top - pixel_friendly_area.bottom) / abs_ystep, abs_ystep),
|
|
76
76
|
bands,
|
|
77
|
-
|
|
77
|
+
datatype_arg.to_gdal(),
|
|
78
78
|
options
|
|
79
79
|
)
|
|
80
80
|
dataset.SetGeoTransform([
|
|
@@ -96,7 +96,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
96
96
|
nbits: Optional[int]=None,
|
|
97
97
|
threads: Optional[int]=None,
|
|
98
98
|
bands: int=1
|
|
99
|
-
) ->
|
|
99
|
+
) -> RasterLayer:
|
|
100
100
|
width = layer.window.xsize
|
|
101
101
|
height = layer.window.ysize
|
|
102
102
|
if area is None:
|
|
@@ -117,6 +117,13 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
117
117
|
area.left, scale.xstep, 0.0, area.top, 0.0, scale.ystep
|
|
118
118
|
)
|
|
119
119
|
|
|
120
|
+
if datatype is None:
|
|
121
|
+
datatype_arg = layer.datatype
|
|
122
|
+
elif isinstance(datatype, int):
|
|
123
|
+
datatype_arg = DataType.of_gdal(datatype)
|
|
124
|
+
else:
|
|
125
|
+
datatype_arg = datatype
|
|
126
|
+
|
|
120
127
|
options = []
|
|
121
128
|
if threads is not None:
|
|
122
129
|
options.append(f"NUM_THREADS={threads}")
|
|
@@ -139,7 +146,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
139
146
|
width,
|
|
140
147
|
height,
|
|
141
148
|
bands,
|
|
142
|
-
(
|
|
149
|
+
(datatype_arg).to_gdal(),
|
|
143
150
|
options,
|
|
144
151
|
)
|
|
145
152
|
dataset.SetGeoTransform(geo_transform)
|
|
@@ -152,13 +159,15 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
152
159
|
@classmethod
|
|
153
160
|
def scaled_raster_from_raster(
|
|
154
161
|
cls,
|
|
155
|
-
source:
|
|
162
|
+
source: RasterLayer,
|
|
156
163
|
new_pixel_scale: PixelScale,
|
|
157
164
|
filename: Optional[str]=None,
|
|
158
165
|
compress: bool=True,
|
|
159
166
|
algorithm: int=gdal.GRA_NearestNeighbour,
|
|
160
|
-
) ->
|
|
167
|
+
) -> RasterLayer:
|
|
161
168
|
source_dataset = source._dataset
|
|
169
|
+
assert source_dataset is not None
|
|
170
|
+
|
|
162
171
|
old_pixel_scale = source.pixel_scale
|
|
163
172
|
assert old_pixel_scale
|
|
164
173
|
|
|
@@ -205,7 +214,7 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
205
214
|
return RasterLayer(dataset)
|
|
206
215
|
|
|
207
216
|
@classmethod
|
|
208
|
-
def layer_from_file(cls, filename: str, band: int = 1) ->
|
|
217
|
+
def layer_from_file(cls, filename: str, band: int = 1) -> RasterLayer:
|
|
209
218
|
try:
|
|
210
219
|
dataset = gdal.Open(filename, gdal.GA_ReadOnly)
|
|
211
220
|
except RuntimeError as exc:
|
|
@@ -248,6 +257,10 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
248
257
|
self._raster_xsize = dataset.RasterXSize
|
|
249
258
|
self._raster_ysize = dataset.RasterYSize
|
|
250
259
|
|
|
260
|
+
@property
|
|
261
|
+
def _raster_dimensions(self) -> Tuple[int,int]:
|
|
262
|
+
return (self._raster_xsize, self._raster_ysize)
|
|
263
|
+
|
|
251
264
|
def close(self):
|
|
252
265
|
try:
|
|
253
266
|
if self._dataset:
|
|
@@ -274,10 +287,8 @@ class RasterLayer(YirgacheffeLayer):
|
|
|
274
287
|
self._unpark()
|
|
275
288
|
|
|
276
289
|
def _park(self):
|
|
277
|
-
|
|
290
|
+
if self._dataset is not None:
|
|
278
291
|
self._dataset.Close()
|
|
279
|
-
except AttributeError:
|
|
280
|
-
pass
|
|
281
292
|
self._dataset = None
|
|
282
293
|
|
|
283
294
|
def _unpark(self):
|
yirgacheffe/layers/rescaled.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from math import floor, ceil
|
|
2
3
|
from typing import Any, Optional
|
|
3
4
|
|
|
@@ -6,7 +7,7 @@ from yirgacheffe.operators import DataType
|
|
|
6
7
|
|
|
7
8
|
from ..window import PixelScale, Window
|
|
8
9
|
from .rasters import RasterLayer, YirgacheffeLayer
|
|
9
|
-
from ..
|
|
10
|
+
from .._backends import backend
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class RescaledRasterLayer(YirgacheffeLayer):
|
|
@@ -20,7 +21,7 @@ class RescaledRasterLayer(YirgacheffeLayer):
|
|
|
20
21
|
pixel_scale: PixelScale,
|
|
21
22
|
band: int = 1,
|
|
22
23
|
nearest_neighbour: bool = True,
|
|
23
|
-
):
|
|
24
|
+
) -> RescaledRasterLayer:
|
|
24
25
|
src = RasterLayer.layer_from_file(filename, band=band)
|
|
25
26
|
return RescaledRasterLayer(src, pixel_scale, nearest_neighbour, src.name)
|
|
26
27
|
|
yirgacheffe/layers/vectors.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import os
|
|
2
3
|
from math import ceil, floor
|
|
3
4
|
from typing import Any, Optional, Tuple, Union
|
|
@@ -9,9 +10,9 @@ from ..operators import DataType
|
|
|
9
10
|
from ..window import Area, PixelScale
|
|
10
11
|
from .base import YirgacheffeLayer
|
|
11
12
|
from .rasters import RasterLayer
|
|
12
|
-
from ..
|
|
13
|
+
from .._backends import backend
|
|
13
14
|
|
|
14
|
-
def _validate_burn_value(burn_value: Any, layer: ogr.Layer) ->
|
|
15
|
+
def _validate_burn_value(burn_value: Any, layer: ogr.Layer) -> DataType: # pylint: disable=R0911
|
|
15
16
|
if isinstance(burn_value, str):
|
|
16
17
|
# burn value is field name, so validate it
|
|
17
18
|
index = layer.FindFieldIndex(burn_value, True)
|
|
@@ -23,32 +24,32 @@ def _validate_burn_value(burn_value: Any, layer: ogr.Layer) -> int: # pylint: di
|
|
|
23
24
|
field = definition.GetFieldDefn(index)
|
|
24
25
|
typename = field.GetTypeName()
|
|
25
26
|
if typename == "Integer":
|
|
26
|
-
return
|
|
27
|
+
return DataType.Int64
|
|
27
28
|
elif typename == "Real":
|
|
28
|
-
return
|
|
29
|
+
return DataType.Float64
|
|
29
30
|
else:
|
|
30
31
|
raise ValueError(f"Can't set datatype {typename} for burn value {burn_value}")
|
|
31
32
|
elif isinstance(burn_value, int):
|
|
32
33
|
if 0 <= burn_value <= 255:
|
|
33
|
-
return
|
|
34
|
+
return DataType.Byte
|
|
34
35
|
else:
|
|
35
36
|
unsigned = burn_value > 0
|
|
36
37
|
if unsigned:
|
|
37
38
|
if burn_value < (pow(2, 16)):
|
|
38
|
-
return
|
|
39
|
+
return DataType.UInt16
|
|
39
40
|
elif burn_value < (pow(2, 32)):
|
|
40
|
-
return
|
|
41
|
+
return DataType.UInt32
|
|
41
42
|
else:
|
|
42
|
-
return
|
|
43
|
+
return DataType.UInt64
|
|
43
44
|
else:
|
|
44
45
|
if abs(burn_value) < (pow(2, 15)):
|
|
45
|
-
return
|
|
46
|
+
return DataType.Int16
|
|
46
47
|
elif abs(burn_value) < (pow(2, 31)):
|
|
47
|
-
return
|
|
48
|
+
return DataType.Int32
|
|
48
49
|
else:
|
|
49
|
-
return
|
|
50
|
+
return DataType.Int64
|
|
50
51
|
elif isinstance(burn_value, float):
|
|
51
|
-
return
|
|
52
|
+
return DataType.Float64
|
|
52
53
|
else:
|
|
53
54
|
raise ValueError(f"data type of burn value {burn_value} not supported")
|
|
54
55
|
|
|
@@ -59,7 +60,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
59
60
|
VectorLayer."""
|
|
60
61
|
|
|
61
62
|
@classmethod
|
|
62
|
-
def layer_from_file(
|
|
63
|
+
def layer_from_file( # type: ignore[override] # pylint: disable=W0221
|
|
63
64
|
cls,
|
|
64
65
|
filename: str,
|
|
65
66
|
where_filter: Optional[str],
|
|
@@ -67,7 +68,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
67
68
|
projection: str,
|
|
68
69
|
datatype: Optional[Union[int, DataType]] = None,
|
|
69
70
|
burn_value: Union[int,float,str] = 1,
|
|
70
|
-
)
|
|
71
|
+
) -> RasteredVectorLayer:
|
|
71
72
|
vectors = ogr.Open(filename)
|
|
72
73
|
if vectors is None:
|
|
73
74
|
raise FileNotFoundError(filename)
|
|
@@ -77,16 +78,17 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
77
78
|
|
|
78
79
|
estimated_datatype = _validate_burn_value(burn_value, layer)
|
|
79
80
|
if datatype is None:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
datatype_arg: DataType = estimated_datatype
|
|
82
|
+
elif isinstance(datatype, int):
|
|
83
|
+
datatype_arg = DataType.of_gdal(datatype)
|
|
84
|
+
else:
|
|
85
|
+
datatype_arg = datatype
|
|
84
86
|
|
|
85
87
|
vector_layer = RasteredVectorLayer(
|
|
86
88
|
layer,
|
|
87
89
|
scale,
|
|
88
90
|
projection,
|
|
89
|
-
datatype=
|
|
91
|
+
datatype=datatype_arg,
|
|
90
92
|
burn_value=burn_value
|
|
91
93
|
)
|
|
92
94
|
|
|
@@ -108,10 +110,12 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
108
110
|
raise ValueError('No layer provided')
|
|
109
111
|
self.layer = layer
|
|
110
112
|
|
|
111
|
-
self._original = None
|
|
113
|
+
self._original: Optional[Any] = None
|
|
112
114
|
|
|
113
115
|
if isinstance(datatype, int):
|
|
114
|
-
|
|
116
|
+
datatype_arg = DataType.of_gdal(datatype)
|
|
117
|
+
else:
|
|
118
|
+
datatype_arg = datatype
|
|
115
119
|
|
|
116
120
|
# work out region for mask
|
|
117
121
|
envelopes = []
|
|
@@ -142,7 +146,7 @@ class RasteredVectorLayer(RasterLayer):
|
|
|
142
146
|
round((area.right - area.left) / abs_xstep),
|
|
143
147
|
round((area.top - area.bottom) / abs_ystep),
|
|
144
148
|
1,
|
|
145
|
-
|
|
149
|
+
datatype_arg.to_gdal(),
|
|
146
150
|
[]
|
|
147
151
|
)
|
|
148
152
|
if not dataset:
|
|
@@ -173,7 +177,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
173
177
|
where_filter: Optional[str]=None,
|
|
174
178
|
datatype: Optional[Union[int, DataType]] = None,
|
|
175
179
|
burn_value: Union[int,float,str] = 1,
|
|
176
|
-
):
|
|
180
|
+
) -> VectorLayer:
|
|
177
181
|
if other_layer is None:
|
|
178
182
|
raise ValueError("like layer can not be None")
|
|
179
183
|
if other_layer.pixel_scale is None:
|
|
@@ -208,7 +212,6 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
208
212
|
vector_layer._filter = where_filter
|
|
209
213
|
return vector_layer
|
|
210
214
|
|
|
211
|
-
|
|
212
215
|
@classmethod
|
|
213
216
|
def layer_from_file(
|
|
214
217
|
cls,
|
|
@@ -219,7 +222,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
219
222
|
datatype: Optional[Union[int, DataType]] = None,
|
|
220
223
|
burn_value: Union[int,float,str] = 1,
|
|
221
224
|
anchor: Tuple[float,float] = (0.0, 0.0)
|
|
222
|
-
):
|
|
225
|
+
) -> VectorLayer:
|
|
223
226
|
vectors = ogr.Open(filename)
|
|
224
227
|
if vectors is None:
|
|
225
228
|
raise FileNotFoundError(filename)
|
|
@@ -232,14 +235,16 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
232
235
|
datatype = estimated_datatype
|
|
233
236
|
|
|
234
237
|
if isinstance(datatype, int):
|
|
235
|
-
|
|
238
|
+
datatype_arg = DataType.of_gdal(datatype)
|
|
239
|
+
else:
|
|
240
|
+
datatype_arg = datatype
|
|
236
241
|
|
|
237
242
|
vector_layer = VectorLayer(
|
|
238
243
|
layer,
|
|
239
244
|
scale,
|
|
240
245
|
projection,
|
|
241
246
|
name=filename,
|
|
242
|
-
datatype=
|
|
247
|
+
datatype=datatype_arg,
|
|
243
248
|
burn_value=burn_value,
|
|
244
249
|
anchor=anchor
|
|
245
250
|
)
|
|
@@ -277,8 +282,8 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
277
282
|
self.burn_value = burn_value
|
|
278
283
|
|
|
279
284
|
self._original = None
|
|
280
|
-
self._dataset_path = None
|
|
281
|
-
self._filter = None
|
|
285
|
+
self._dataset_path: Optional[str] = None
|
|
286
|
+
self._filter: Optional[str] = None
|
|
282
287
|
|
|
283
288
|
# work out region for mask
|
|
284
289
|
envelopes = []
|
|
@@ -318,7 +323,7 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
318
323
|
|
|
319
324
|
def __getstate__(self) -> object:
|
|
320
325
|
# Only support pickling on file backed layers (ideally read only ones...)
|
|
321
|
-
if not os.path.isfile(self._dataset_path):
|
|
326
|
+
if self._dataset_path is None or not os.path.isfile(self._dataset_path):
|
|
322
327
|
raise ValueError("Can not pickle layer that is not file backed.")
|
|
323
328
|
odict = self.__dict__.copy()
|
|
324
329
|
del odict['_original']
|
|
@@ -353,6 +358,8 @@ class VectorLayer(YirgacheffeLayer):
|
|
|
353
358
|
return self._datatype
|
|
354
359
|
|
|
355
360
|
def read_array_for_area(self, target_area: Area, x: int, y: int, width: int, height: int) -> Any:
|
|
361
|
+
assert self._pixel_scale is not None
|
|
362
|
+
|
|
356
363
|
if self._original is None:
|
|
357
364
|
self._unpark()
|
|
358
365
|
if (width <= 0) or (height <= 0):
|
yirgacheffe/operators.py
CHANGED
|
@@ -7,18 +7,18 @@ import types
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from multiprocessing import Semaphore, Process
|
|
9
9
|
from multiprocessing.managers import SharedMemoryManager
|
|
10
|
-
from typing import Optional
|
|
10
|
+
from typing import Callable, Optional
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
from osgeo import gdal
|
|
14
|
-
from dill import dumps, loads
|
|
14
|
+
from dill import dumps, loads # type: ignore
|
|
15
15
|
|
|
16
16
|
from . import constants
|
|
17
17
|
from .rounding import are_pixel_scales_equal_enough, round_up_pixels, round_down_pixels
|
|
18
18
|
from .window import Area, PixelScale, Window
|
|
19
|
-
from .
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
19
|
+
from ._backends import backend
|
|
20
|
+
from ._backends.enumeration import operators as op
|
|
21
|
+
from ._backends.enumeration import dtype as DataType
|
|
22
22
|
|
|
23
23
|
logger = logging.getLogger(__name__)
|
|
24
24
|
logger.setLevel(logging.WARNING)
|
|
@@ -320,7 +320,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
320
320
|
else:
|
|
321
321
|
self.other = None
|
|
322
322
|
|
|
323
|
-
def __str__(self):
|
|
323
|
+
def __str__(self) -> str:
|
|
324
324
|
try:
|
|
325
325
|
return f"({self.lhs} {self.operator} {self.rhs})"
|
|
326
326
|
except AttributeError:
|
|
@@ -329,7 +329,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
329
329
|
except AttributeError:
|
|
330
330
|
return str(self.lhs)
|
|
331
331
|
|
|
332
|
-
def __len__(self):
|
|
332
|
+
def __len__(self) -> int:
|
|
333
333
|
return len(self.lhs)
|
|
334
334
|
|
|
335
335
|
def __getstate__(self) -> object:
|
|
@@ -339,22 +339,22 @@ class LayerOperation(LayerMathMixin):
|
|
|
339
339
|
del odict['operator']
|
|
340
340
|
return odict
|
|
341
341
|
|
|
342
|
-
def __setstate__(self, state):
|
|
342
|
+
def __setstate__(self, state) -> None:
|
|
343
343
|
if 'operator_dill' in state:
|
|
344
344
|
state['operator'] = loads(state['operator_dill'])
|
|
345
345
|
del state['operator_dill']
|
|
346
346
|
self.__dict__.update(state)
|
|
347
347
|
|
|
348
348
|
@property
|
|
349
|
-
def area(self) -> Area:
|
|
349
|
+
def area(self) -> Optional[Area]:
|
|
350
350
|
# The type().__name__ here is to avoid a circular import dependancy
|
|
351
351
|
lhs_area = self.lhs.area if not type(self.lhs).__name__ == "ConstantLayer" else None
|
|
352
352
|
try:
|
|
353
|
-
rhs_area = self.rhs.area if not type(self.rhs).__name__ == "ConstantLayer" else None
|
|
353
|
+
rhs_area = self.rhs.area if not type(self.rhs).__name__ == "ConstantLayer" else None # type: ignore[return-value] # pylint: disable=C0301
|
|
354
354
|
except AttributeError:
|
|
355
355
|
rhs_area = None
|
|
356
356
|
try:
|
|
357
|
-
other_area = self.other.area if not type(self.other).__name__ == "ConstantLayer" else None
|
|
357
|
+
other_area = self.other.area if not type(self.other).__name__ == "ConstantLayer" else None # type: ignore[return-value] # pylint: disable=C0301
|
|
358
358
|
except AttributeError:
|
|
359
359
|
other_area = None
|
|
360
360
|
|
|
@@ -391,6 +391,8 @@ class LayerOperation(LayerMathMixin):
|
|
|
391
391
|
right=max(x.right for x in all_areas),
|
|
392
392
|
bottom=min(x.bottom for x in all_areas)
|
|
393
393
|
)
|
|
394
|
+
case _:
|
|
395
|
+
assert False, "Should not be reached"
|
|
394
396
|
|
|
395
397
|
@property
|
|
396
398
|
def pixel_scale(self) -> PixelScale:
|
|
@@ -409,6 +411,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
409
411
|
def window(self) -> Window:
|
|
410
412
|
pixel_scale = self.pixel_scale
|
|
411
413
|
area = self.area
|
|
414
|
+
assert area is not None
|
|
412
415
|
|
|
413
416
|
return Window(
|
|
414
417
|
xoff=round_down_pixels(area.left / pixel_scale.xstep, pixel_scale.xstep),
|
|
@@ -450,7 +453,7 @@ class LayerOperation(LayerMathMixin):
|
|
|
450
453
|
return lhs_data
|
|
451
454
|
|
|
452
455
|
try:
|
|
453
|
-
operator = backend.operator_map[self.operator]
|
|
456
|
+
operator: Callable = backend.operator_map[self.operator]
|
|
454
457
|
except KeyError:
|
|
455
458
|
# Handles things like `numpy_apply` where a custom operator is provided
|
|
456
459
|
operator = self.operator
|
yirgacheffe/window.py
CHANGED
|
@@ -2,12 +2,36 @@ import math
|
|
|
2
2
|
import sys
|
|
3
3
|
from collections import namedtuple
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import List, Optional
|
|
5
|
+
from typing import List, Optional, Tuple
|
|
6
6
|
|
|
7
7
|
PixelScale = namedtuple('PixelScale', ['xstep', 'ystep'])
|
|
8
8
|
|
|
9
9
|
@dataclass
|
|
10
10
|
class Area:
|
|
11
|
+
"""Class to hold a geospatial area of data in the given projection.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
left : float
|
|
16
|
+
Left most point in the projection space
|
|
17
|
+
top : float
|
|
18
|
+
Top most point in the projection space
|
|
19
|
+
right : float
|
|
20
|
+
Right most point in the projection space
|
|
21
|
+
bottom : float
|
|
22
|
+
Bottom most point in the projection space
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
left : float
|
|
27
|
+
Left most point in the projection space
|
|
28
|
+
top : float
|
|
29
|
+
Top most point in the projection space
|
|
30
|
+
right : float
|
|
31
|
+
Right most point in the projection space
|
|
32
|
+
bottom : float
|
|
33
|
+
Bottom most point in the projection space
|
|
34
|
+
"""
|
|
11
35
|
left: float
|
|
12
36
|
top: float
|
|
13
37
|
right: float
|
|
@@ -23,6 +47,21 @@ class Area:
|
|
|
23
47
|
math.isclose(self.bottom, other.bottom, abs_tol=1e-09)
|
|
24
48
|
|
|
25
49
|
def grow(self, offset: float):
|
|
50
|
+
"""Expand the area in all directions by the given amount.
|
|
51
|
+
|
|
52
|
+
Generates a new area that is an expanded version of the current area.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
offset : float
|
|
57
|
+
The amount by which to grow the area
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
Area
|
|
62
|
+
A new area of the expanded size.
|
|
63
|
+
|
|
64
|
+
"""
|
|
26
65
|
return Area(
|
|
27
66
|
left=self.left - offset,
|
|
28
67
|
top=self.top + offset,
|
|
@@ -31,6 +70,18 @@ class Area:
|
|
|
31
70
|
)
|
|
32
71
|
|
|
33
72
|
def overlaps(self, other) -> bool:
|
|
73
|
+
"""Check if this area overlaps with another area.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
other : Area
|
|
78
|
+
The other area to compare this area with
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
bool
|
|
83
|
+
True if the two areas intersect, otherwise false.
|
|
84
|
+
"""
|
|
34
85
|
return (
|
|
35
86
|
(self.left <= other.left <= self.right) or
|
|
36
87
|
(self.left <= other.right <= self.right) or
|
|
@@ -45,13 +96,38 @@ class Area:
|
|
|
45
96
|
|
|
46
97
|
@dataclass
|
|
47
98
|
class Window:
|
|
99
|
+
"""Class to hold the pixel dimensions of data in the given projection.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
xoff : int
|
|
104
|
+
X axis offset
|
|
105
|
+
yoff : int
|
|
106
|
+
Y axis offset
|
|
107
|
+
xsize : int
|
|
108
|
+
Width of data in pixels
|
|
109
|
+
bottom : float
|
|
110
|
+
Height of data in pixels
|
|
111
|
+
|
|
112
|
+
Attributes
|
|
113
|
+
----------
|
|
114
|
+
xoff : int
|
|
115
|
+
X axis offset
|
|
116
|
+
yoff : int
|
|
117
|
+
Y axis offset
|
|
118
|
+
xsize : int
|
|
119
|
+
Width of data in pixels
|
|
120
|
+
bottom : float
|
|
121
|
+
Height of data in pixels
|
|
122
|
+
"""
|
|
48
123
|
xoff: int
|
|
49
124
|
yoff: int
|
|
50
125
|
xsize: int
|
|
51
126
|
ysize: int
|
|
52
127
|
|
|
53
128
|
@property
|
|
54
|
-
def as_array_args(self):
|
|
129
|
+
def as_array_args(self) -> Tuple[int,...]:
|
|
130
|
+
"""A tuple containing xoff, yoff, xsize, and ysize."""
|
|
55
131
|
return (self.xoff, self.yoff, self.xsize, self.ysize)
|
|
56
132
|
|
|
57
133
|
def __lt__(self, other) -> bool:
|
|
@@ -87,6 +163,21 @@ class Window:
|
|
|
87
163
|
((self.yoff + self.ysize) >= (other.yoff + other.ysize))
|
|
88
164
|
|
|
89
165
|
def grow(self, pixels: int):
|
|
166
|
+
"""Expand the area in all directions by the given amount.
|
|
167
|
+
|
|
168
|
+
Generates a new window that is an expanded version of the current window.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
pixels : int
|
|
173
|
+
The amount by which to grow the window in pixels
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
Window
|
|
178
|
+
A new window of the expanded size.
|
|
179
|
+
|
|
180
|
+
"""
|
|
90
181
|
return Window(
|
|
91
182
|
xoff=self.xoff - pixels,
|
|
92
183
|
yoff=self.xoff - pixels,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yirgacheffe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: Abstraction of gdal datasets for doing basic math operations
|
|
5
5
|
Author-email: Michael Dales <mwd24@cam.ac.uk>
|
|
6
6
|
License-Expression: ISC
|
|
@@ -13,6 +13,7 @@ Requires-Dist: numpy
|
|
|
13
13
|
Requires-Dist: gdal[numpy]
|
|
14
14
|
Requires-Dist: scikit-image
|
|
15
15
|
Requires-Dist: torch
|
|
16
|
+
Requires-Dist: dill
|
|
16
17
|
Provides-Extra: dev
|
|
17
18
|
Requires-Dist: mypy; extra == "dev"
|
|
18
19
|
Requires-Dist: pylint; extra == "dev"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
yirgacheffe/__init__.py,sha256=nrVZPE_4DgReqmqEOfUaXJiRtxjOt-OJSIVi51Z5k98,587
|
|
2
|
+
yirgacheffe/constants.py,sha256=WccPcISG1FqL_Kw1tI72BJGjHy6RvEcGEx_I9RK776U,42
|
|
3
|
+
yirgacheffe/operators.py,sha256=j5Ts9dxqcxq_bL7Mw-n6vTg0SP5rKpqseVcJTD8PaAY,29363
|
|
4
|
+
yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
|
|
5
|
+
yirgacheffe/window.py,sha256=PVh9EIg1PMcUENjC2yahmrolGWaJP4OeM44uKqQ6I0U,7504
|
|
6
|
+
yirgacheffe/_backends/__init__.py,sha256=jN-2iRrHStnPI6cNL7XhwhsROtI0EaGfIrbF5c-ECV0,334
|
|
7
|
+
yirgacheffe/_backends/enumeration.py,sha256=pADawllxpW_hW-IVVvZpHWIKzvEMs9aaqfkZRD1zjnY,1003
|
|
8
|
+
yirgacheffe/_backends/mlx.py,sha256=2vOTMqHbQbeqt81Eq_8hxWDXZHaPsDpbXkALRVGEnnw,6130
|
|
9
|
+
yirgacheffe/_backends/numpy.py,sha256=cYO628s4-5K_-Bp3CrnHegzYSZfkt2QC8iE9oOOMtvA,4069
|
|
10
|
+
yirgacheffe/layers/__init__.py,sha256=mYKjw5YTcMNv_hMy7a6K4yRzIuNUbR8WuBTw4WIAmSk,435
|
|
11
|
+
yirgacheffe/layers/area.py,sha256=yIRXzeeLi3MMyuh4LG_VgZrKNWe5xwZgDGdgaoYRpP0,3805
|
|
12
|
+
yirgacheffe/layers/base.py,sha256=l2spGsDsv2DaUqkK-nuJCC97fw0kVWaLntvvLqZgJS4,11959
|
|
13
|
+
yirgacheffe/layers/constant.py,sha256=LWQuGGuUkJirLoQomZHs44oksmMKcvNGM8pOuRk9vHo,1427
|
|
14
|
+
yirgacheffe/layers/group.py,sha256=Fys5BvYmWRQMc95YE8Gy6bxxZRqvHUU7gILFE_X-CpY,15330
|
|
15
|
+
yirgacheffe/layers/h3layer.py,sha256=kWDqs6fIkHLR7gDL2E6F5y9-XxT6ws4M3Tj_7qF090U,9863
|
|
16
|
+
yirgacheffe/layers/rasters.py,sha256=I9bRuqb0W8EEvdSq3rAeKNmezIRK-yajFaHtDFR81sw,12630
|
|
17
|
+
yirgacheffe/layers/rescaled.py,sha256=v3ZXo3aNNDP4b8O6QnQHgrhBu0GslTgiZQmy6O8vb8k,3004
|
|
18
|
+
yirgacheffe/layers/vectors.py,sha256=3QWjg0E9deZyLIBp-BewgDGY90Ufqd6OcUA7jzJXJPo,15515
|
|
19
|
+
yirgacheffe-1.4.1.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
|
|
20
|
+
yirgacheffe-1.4.1.dist-info/METADATA,sha256=TZlmFtOF9UJXDm3jkJSWwb-pRjbKx2fF8Bh9kXK40Ns,20516
|
|
21
|
+
yirgacheffe-1.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
yirgacheffe-1.4.1.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
|
|
23
|
+
yirgacheffe-1.4.1.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
|
|
24
|
+
yirgacheffe-1.4.1.dist-info/RECORD,,
|
yirgacheffe/h3layer.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
yirgacheffe/__init__.py,sha256=U5AoPk_iWreSCexG2ID-tmSXiJz4_9Lvzbf42DMvT7k,658
|
|
2
|
-
yirgacheffe/constants.py,sha256=WccPcISG1FqL_Kw1tI72BJGjHy6RvEcGEx_I9RK776U,42
|
|
3
|
-
yirgacheffe/h3layer.py,sha256=MT2hm6n64hzHSeRPvjn-CwErru937ntKXbEU7CIlPSU,91
|
|
4
|
-
yirgacheffe/operators.py,sha256=KIMYmRl0uJG9LYnmX_uwHhGNfCNOEZlfaXZU7kD1aL4,29081
|
|
5
|
-
yirgacheffe/rounding.py,sha256=ggBG4lMyLMtHLW3dBxr3gBCcF2qhRrY5etZiFGlIoqA,2258
|
|
6
|
-
yirgacheffe/window.py,sha256=0XZdwD4mz0bRU9eBhFY1Xk1hQt6FqCKp3BnUgxZup3c,5224
|
|
7
|
-
yirgacheffe/backends/__init__.py,sha256=149-fg1PVXC36cgyuSZsU8SYOm65fzUmYN_MHZtEyrY,313
|
|
8
|
-
yirgacheffe/backends/enumeration.py,sha256=pADawllxpW_hW-IVVvZpHWIKzvEMs9aaqfkZRD1zjnY,1003
|
|
9
|
-
yirgacheffe/backends/mlx.py,sha256=3HSKU7ZU846trdxeVhPj2OPkFWrCxfbjB65-NpnmANQ,6097
|
|
10
|
-
yirgacheffe/backends/numpy.py,sha256=qQYvff1oHIuGUimV04rcFyPxnwEf0acvVd3ijeom4T4,4015
|
|
11
|
-
yirgacheffe/layers/__init__.py,sha256=GR_TJlhPKDK1212CG2T99X2FdBlNo_G8q2zQ6nJbiO4,1534
|
|
12
|
-
yirgacheffe/layers/area.py,sha256=yIRXzeeLi3MMyuh4LG_VgZrKNWe5xwZgDGdgaoYRpP0,3805
|
|
13
|
-
yirgacheffe/layers/base.py,sha256=vVxumZgFLTYXFtVxJEiBVV1QqtQWa5kwL10ckUF-ykE,11617
|
|
14
|
-
yirgacheffe/layers/constant.py,sha256=5YWSdr48Cw3DhryLBx45PNnPi4NzcVuQVin_YmOSWTg,1426
|
|
15
|
-
yirgacheffe/layers/group.py,sha256=2hRta24Mn5JwfDOB4-gJfroa_lVJSUFgSZ8FMeWy_FM,15127
|
|
16
|
-
yirgacheffe/layers/h3layer.py,sha256=Cyrw_6nXc1a_Twsb0FfexKhHAbegKXStL3J5LLk2AX8,9687
|
|
17
|
-
yirgacheffe/layers/rasters.py,sha256=8mAbH49RtKIoA3h9mxWNbPzo8NJWDSfoRPT7fpkTJ4I,12328
|
|
18
|
-
yirgacheffe/layers/rescaled.py,sha256=kWJlu7DuUB3nRDt3VtbJKiqBDQb2Ba8xzIIXTvOGdK8,2945
|
|
19
|
-
yirgacheffe/layers/vectors.py,sha256=JOqM7Ym53ZdxWKpBJac-opPp2N_ynMfet1Xtsi85dpM,15087
|
|
20
|
-
yirgacheffe-1.3.4.dist-info/licenses/LICENSE,sha256=dNSHwUCJr6axStTKDEdnJtfmDdFqlE3h1NPCveqPfnY,757
|
|
21
|
-
yirgacheffe-1.3.4.dist-info/METADATA,sha256=tKSbYq3ZonA4FTn9AeYFgAB9AcZOnMBdky7oZ_Vcz60,20496
|
|
22
|
-
yirgacheffe-1.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
-
yirgacheffe-1.3.4.dist-info/entry_points.txt,sha256=j4KgHXbVGbGyfTySc1ypBdERpfihO4WNjppvCdE9HjE,52
|
|
24
|
-
yirgacheffe-1.3.4.dist-info/top_level.txt,sha256=9DBFlKO2Ld3hG6TuE3qOTd3Tt8ugTiXil4AN4Wr9_y0,12
|
|
25
|
-
yirgacheffe-1.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|