pyopenrivercam 0.8.7__py3-none-any.whl → 0.8.9__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.
- {pyopenrivercam-0.8.7.dist-info → pyopenrivercam-0.8.9.dist-info}/METADATA +1 -1
- {pyopenrivercam-0.8.7.dist-info → pyopenrivercam-0.8.9.dist-info}/RECORD +12 -12
- pyorc/__init__.py +1 -1
- pyorc/api/cross_section.py +81 -26
- pyorc/api/plot.py +27 -9
- pyorc/cli/cli_utils.py +2 -14
- pyorc/helpers.py +23 -0
- pyorc/plot_helpers.py +21 -6
- pyorc/service/velocimetry.py +2 -2
- {pyopenrivercam-0.8.7.dist-info → pyopenrivercam-0.8.9.dist-info}/WHEEL +0 -0
- {pyopenrivercam-0.8.7.dist-info → pyopenrivercam-0.8.9.dist-info}/entry_points.txt +0 -0
- {pyopenrivercam-0.8.7.dist-info → pyopenrivercam-0.8.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
pyorc/__init__.py,sha256=
|
|
1
|
+
pyorc/__init__.py,sha256=mvuksjtx7rr3dGsP3AIlI2DOsT-dK-WNkLnRv2hBqSA,523
|
|
2
2
|
pyorc/const.py,sha256=Ia0KRkm-E1lJk4NxQVPDIfN38EBB7BKvxmwIHJrGPUY,2597
|
|
3
3
|
pyorc/cv.py,sha256=CTv0TbbcKeSQmKsX8mdVDXpSkhKZmr8SgT20YXMvZ0s,49156
|
|
4
|
-
pyorc/helpers.py,sha256=
|
|
5
|
-
pyorc/plot_helpers.py,sha256=
|
|
4
|
+
pyorc/helpers.py,sha256=90TDtka0ydAydv3g5Dfc8MgtuSt0_9D9-HOtffpcBds,30636
|
|
5
|
+
pyorc/plot_helpers.py,sha256=gLKslspsF_Z4jib5jkBv2wRjKnHTbuRFgkp_PCmv-uU,1803
|
|
6
6
|
pyorc/project.py,sha256=CGKfICkQEpFRmh_ZeDEfbQ-wefJt7teWJd6B5IPF038,7747
|
|
7
7
|
pyorc/pyorc.sh,sha256=-xOSUNnMAwVbdNkjKNKMZMaBljWsGLhadG-j0DNlJP4,5
|
|
8
8
|
pyorc/sample_data.py,sha256=53NVnVmEksDw8ilbfhFFCiFJiGAIpxdgREbA_xt8P3o,2508
|
|
9
9
|
pyorc/api/__init__.py,sha256=k2OQQH4NrtXTuVm23d0g_SX6H5DhnKC9_kDyzJ4dWdk,428
|
|
10
10
|
pyorc/api/cameraconfig.py,sha256=NP9F7LhPO3aO6FRWkrGl6XpX8O3K59zfTtaYR3Kujqw,65419
|
|
11
|
-
pyorc/api/cross_section.py,sha256=
|
|
11
|
+
pyorc/api/cross_section.py,sha256=un7_VFHMOpBM8FE7lQnZIsaxidnABzFWlyaDHIUfzoA,52039
|
|
12
12
|
pyorc/api/frames.py,sha256=QJfcftmh47nClw5yGsMULdJXEsAVzucseiLb4LbpVJU,23671
|
|
13
13
|
pyorc/api/mask.py,sha256=HVag3RkMu4ZYQg_pIZFhiJYkBGYLVBxeefdmWvFTR-4,14371
|
|
14
14
|
pyorc/api/orcbase.py,sha256=C23QTKOyxHUafyJsq_t7xn_BzAEvf4DDfzlYAopons8,4189
|
|
15
|
-
pyorc/api/plot.py,sha256
|
|
15
|
+
pyorc/api/plot.py,sha256=-rDmEccwpJXojCyBEKFCd8NpBwLhcZ8tsOq62n26zu4,30898
|
|
16
16
|
pyorc/api/transect.py,sha256=KU0ZW_0NqYD4jeDxvuWJi7X06KqrcgO9afP7QmWuixA,14162
|
|
17
17
|
pyorc/api/velocimetry.py,sha256=bfU_XPbUbrdBI2XGprzh_3YADbGHfy4OuS1oBlbLEEI,12047
|
|
18
18
|
pyorc/api/video.py,sha256=lGD6bcV6Uu2u3zuGF_m3KxX2Cyp9k-YHUiXA42TOE3E,22458
|
|
19
19
|
pyorc/cli/__init__.py,sha256=A7hOQV26vIccPnDc8L2KqoJOSpMpf2PiMOXS18pAsWg,32
|
|
20
20
|
pyorc/cli/cli_elements.py,sha256=zX9wv9-1KWC_E3cInGMm3g9jh4uXmT2NqooAMhhXR9s,22165
|
|
21
|
-
pyorc/cli/cli_utils.py,sha256=
|
|
21
|
+
pyorc/cli/cli_utils.py,sha256=S7qOO4bintxXDSUl26u3Ujqu4JHb_TNhw5d6psyDrFo,15085
|
|
22
22
|
pyorc/cli/log.py,sha256=Vg8GznmrEPqijfW6wv4OCl8R00Ld_fVt-ULTitaDijY,2824
|
|
23
23
|
pyorc/cli/main.py,sha256=qhAZkUuAViCpHh9c19tpcpbs_xoZJkYHhOsEXJBFXfM,12742
|
|
24
24
|
pyorc/service/__init__.py,sha256=vPrzFlZ4e_GjnibwW6-k8KDz3b7WpgmGcwSDk0mr13Y,55
|
|
25
25
|
pyorc/service/camera_config.py,sha256=OsRLpe5jd-lu6HT4Vx5wEg554CMS-IKz-q62ir4VbPo,2375
|
|
26
|
-
pyorc/service/velocimetry.py,sha256=
|
|
26
|
+
pyorc/service/velocimetry.py,sha256=UFjxmq5Uhk8wnBLScAyTaVWTPTCnH9hJdKOYBFrGZ_Y,33288
|
|
27
27
|
pyorc/velocimetry/__init__.py,sha256=lYM7oJZWxgJ2SpE22xhy7pBYcgkKFHMBHYmDvvMbtZk,148
|
|
28
28
|
pyorc/velocimetry/ffpiv.py,sha256=MW_6fQ0vxRTA-HYwncgeWHGWiUQFSmM4unYxT7EfnEI,7372
|
|
29
29
|
pyorc/velocimetry/openpiv.py,sha256=6BxsbXLzT4iEq7v08G4sOhVlYFodUpY6sIm3jdCxNMs,13149
|
|
30
|
-
pyopenrivercam-0.8.
|
|
31
|
-
pyopenrivercam-0.8.
|
|
32
|
-
pyopenrivercam-0.8.
|
|
33
|
-
pyopenrivercam-0.8.
|
|
34
|
-
pyopenrivercam-0.8.
|
|
30
|
+
pyopenrivercam-0.8.9.dist-info/entry_points.txt,sha256=Cv_WI2Y6QLnPiNCXGli0gS4WAOAeMoprha1rAR3vdRE,44
|
|
31
|
+
pyopenrivercam-0.8.9.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
32
|
+
pyopenrivercam-0.8.9.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
33
|
+
pyopenrivercam-0.8.9.dist-info/METADATA,sha256=8NK4zolq3oMRgMuTKCWZTypoLjzPcev_-it5frg8aac,11633
|
|
34
|
+
pyopenrivercam-0.8.9.dist-info/RECORD,,
|
pyorc/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""pyorc: free and open-source image-based surface velocity and discharge."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.8.
|
|
3
|
+
__version__ = "0.8.9"
|
|
4
4
|
|
|
5
5
|
from .api import CameraConfig, CrossSection, Frames, Transect, Velocimetry, Video, get_camera_config, load_camera_config # noqa
|
|
6
6
|
from .project import * # noqa
|
pyorc/api/cross_section.py
CHANGED
|
@@ -146,9 +146,11 @@ class CrossSection:
|
|
|
146
146
|
"""
|
|
147
147
|
# if cross_section is a GeoDataFrame, check if it has a CRS, if yes, convert coordinates to crs of CameraConfig
|
|
148
148
|
if isinstance(cross_section, gpd.GeoDataFrame):
|
|
149
|
-
|
|
149
|
+
crs_cs = getattr(cross_section, "crs", None)
|
|
150
|
+
crs_cam = getattr(camera_config, "crs", None)
|
|
151
|
+
if crs_cs is not None and crs_cam is not None:
|
|
150
152
|
cross_section.to_crs(camera_config.crs, inplace=True)
|
|
151
|
-
elif
|
|
153
|
+
elif crs_cs is not None or crs_cam is not None:
|
|
152
154
|
raise ValueError("if a CRS is used, then both camera_config and cross_section must have a CRS.")
|
|
153
155
|
g = cross_section.geometry
|
|
154
156
|
x, y, z = g.x.values, g.y.values, g.z.values
|
|
@@ -270,7 +272,7 @@ class CrossSection:
|
|
|
270
272
|
# check if there are any points within the image objective and return result
|
|
271
273
|
return bool(np.any(within_image))
|
|
272
274
|
|
|
273
|
-
def get_cs_waterlevel(self, h: float, sz=False) -> geometry.LineString:
|
|
275
|
+
def get_cs_waterlevel(self, h: float, sz=False, extend_by=None) -> geometry.LineString:
|
|
274
276
|
"""Retrieve LineString of water surface at cross-section at a given water level.
|
|
275
277
|
|
|
276
278
|
Parameters
|
|
@@ -279,18 +281,44 @@ class CrossSection:
|
|
|
279
281
|
water level [m]
|
|
280
282
|
sz : bool, optional
|
|
281
283
|
If set, return water level line in y-z projection, by default False.
|
|
284
|
+
extend_by : float, optional
|
|
285
|
+
If set, the line will be extended left and right using the defined float in meters
|
|
282
286
|
|
|
283
287
|
Returns
|
|
284
288
|
-------
|
|
285
289
|
geometry.LineString
|
|
286
|
-
horizontal line at water level (2d if sz
|
|
290
|
+
horizontal line at water level (2d if `sz`=True, 3d if `yz`=False)
|
|
287
291
|
|
|
288
292
|
"""
|
|
289
293
|
# get water level in camera config vertical datum
|
|
290
294
|
z = self.camera_config.h_to_z(h)
|
|
291
295
|
if sz:
|
|
292
|
-
|
|
293
|
-
|
|
296
|
+
if extend_by is None:
|
|
297
|
+
s_coords = self.s
|
|
298
|
+
else:
|
|
299
|
+
s_coords = np.concatenate([[-np.abs(extend_by)], self.s, [self.s[-1] + np.abs(extend_by)]])
|
|
300
|
+
return geometry.LineString(zip(s_coords, [z] * len(s_coords)))
|
|
301
|
+
if extend_by is not None:
|
|
302
|
+
alpha = np.arctan((self.x[1] - self.x[0]) / (self.y[1] - self.y[0]))
|
|
303
|
+
x_coords = np.concatenate(
|
|
304
|
+
[
|
|
305
|
+
[self.x[0] - np.cos(alpha) * np.abs(extend_by)],
|
|
306
|
+
self.x,
|
|
307
|
+
[self.x[-1] + np.cos(alpha) * np.abs(extend_by)],
|
|
308
|
+
]
|
|
309
|
+
)
|
|
310
|
+
y_coords = np.concatenate(
|
|
311
|
+
[
|
|
312
|
+
[self.y[0] - np.sin(alpha) * np.abs(extend_by)],
|
|
313
|
+
self.y,
|
|
314
|
+
[self.y[-1] + np.sin(alpha) * np.abs(extend_by)],
|
|
315
|
+
]
|
|
316
|
+
)
|
|
317
|
+
else:
|
|
318
|
+
x_coords = self.x
|
|
319
|
+
y_coords = self.y
|
|
320
|
+
|
|
321
|
+
return geometry.LineString(zip(x_coords, y_coords, [z] * len(x_coords)))
|
|
294
322
|
|
|
295
323
|
def get_csl_point(
|
|
296
324
|
self, h: Optional[float] = None, l: Optional[float] = None, camera: bool = False, swap_y_coords: bool = False
|
|
@@ -602,16 +630,32 @@ class CrossSection:
|
|
|
602
630
|
Wetted surface as a polygon, in Y-Z projection.
|
|
603
631
|
|
|
604
632
|
"""
|
|
605
|
-
wl = self.get_cs_waterlevel(
|
|
633
|
+
wl = self.get_cs_waterlevel(
|
|
634
|
+
h=h, sz=True, extend_by=0.1
|
|
635
|
+
) # extend a small bit to guarantee crossing with the bottom coordinates
|
|
636
|
+
zl = wl.xy[1][0]
|
|
606
637
|
# create polygon by making a union
|
|
607
|
-
|
|
638
|
+
bottom_points = self.cs_points_sz
|
|
639
|
+
# add a point left and right slightly above the level if the level is below the water level
|
|
640
|
+
if bottom_points[0].y < zl:
|
|
641
|
+
bottom_points.insert(0, geometry.Point(bottom_points[0].x, zl + 0.1))
|
|
642
|
+
if bottom_points[-1].y < zl:
|
|
643
|
+
bottom_points.append(geometry.Point(bottom_points[-1].x, zl + 0.1))
|
|
644
|
+
bottom_line = geometry.LineString(bottom_points)
|
|
645
|
+
pol = list(polygonize(wl.union(bottom_line)))
|
|
608
646
|
if len(pol) == 0:
|
|
609
|
-
|
|
647
|
+
# create infinitely small polygon at lowest z coordinate
|
|
648
|
+
lowest_z = min(self.z)
|
|
649
|
+
lowest_s = self.s[list(self.z).index(lowest_z)]
|
|
650
|
+
# make an infinitely small polygon around the lowest point in the cross section
|
|
651
|
+
pol = [geometry.Polygon([(lowest_s, lowest_z)] * 3)]
|
|
610
652
|
elif len(pol) > 1:
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
653
|
+
# detect which polygons have their average z coordinate below the defined water level
|
|
654
|
+
pol = [p for p in pol if p.centroid.xy[1][0] < zl]
|
|
655
|
+
# raise ValueError("Water level is crossed by multiple polygons.")
|
|
656
|
+
# else:
|
|
657
|
+
# pol = pol[0]
|
|
658
|
+
return geometry.MultiPolygon(pol)
|
|
615
659
|
|
|
616
660
|
def get_wetted_surface(self, h: float, camera: bool = False, swap_y_coords=False) -> geometry.Polygon:
|
|
617
661
|
"""Retrieve a wetted surface for a given water level, as a geometry.Polygon.
|
|
@@ -633,13 +677,16 @@ class CrossSection:
|
|
|
633
677
|
|
|
634
678
|
|
|
635
679
|
"""
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
680
|
+
pols = self.get_wetted_surface_sz(h=h)
|
|
681
|
+
pols_proj = []
|
|
682
|
+
for pol in pols.geoms:
|
|
683
|
+
coords = [[self.interp_x_from_s(p[0]), self.interp_y_from_s(p[0]), p[1]] for p in pol.exterior.coords]
|
|
684
|
+
if camera:
|
|
685
|
+
coords_proj = self.camera_config.project_points(coords, swap_y_coords=swap_y_coords)
|
|
686
|
+
pols_proj.append(geometry.Polygon(coords_proj))
|
|
687
|
+
else:
|
|
688
|
+
pols_proj.append(geometry.Polygon(coords))
|
|
689
|
+
return geometry.MultiPolygon(pols_proj)
|
|
643
690
|
|
|
644
691
|
def get_line_of_interest(self, bank: BANK_OPTIONS = "far") -> List[float]:
|
|
645
692
|
"""Retrieve the points of interest within the cross-section for water level detection.
|
|
@@ -881,12 +928,20 @@ class CrossSection:
|
|
|
881
928
|
plt.axes
|
|
882
929
|
|
|
883
930
|
"""
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
931
|
+
try:
|
|
932
|
+
surf = self.get_planar_surface(
|
|
933
|
+
h=h, length=length, offset=offset, swap_y_coords=swap_y_coords, camera=camera
|
|
934
|
+
)
|
|
935
|
+
if camera:
|
|
936
|
+
p = plot_helpers.plot_polygon(surf, ax=ax, label="surface", **kwargs)
|
|
937
|
+
else:
|
|
938
|
+
p = plot_helpers.plot_3d_polygon(surf, ax=ax, label="surface", **kwargs)
|
|
939
|
+
return p.axes
|
|
940
|
+
except Exception:
|
|
941
|
+
warnings.warn(
|
|
942
|
+
"Cannot plot planar surface as there are too many crossings",
|
|
943
|
+
stacklevel=2,
|
|
944
|
+
)
|
|
890
945
|
|
|
891
946
|
def plot_bottom_surface(
|
|
892
947
|
self, length: float = 2.0, offset: float = 0.0, camera: bool = False, ax=None, swap_y_coords=False, **kwargs
|
pyorc/api/plot.py
CHANGED
|
@@ -6,6 +6,8 @@ import functools
|
|
|
6
6
|
import matplotlib.pyplot as plt
|
|
7
7
|
import matplotlib.ticker as mticker
|
|
8
8
|
import numpy as np
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
9
11
|
from matplotlib import colors, patheffects
|
|
10
12
|
|
|
11
13
|
from pyorc import helpers
|
|
@@ -184,16 +186,32 @@ def _base_plot(plot_func):
|
|
|
184
186
|
planar=False,
|
|
185
187
|
bottom=False,
|
|
186
188
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
label="water level",
|
|
189
|
+
# check if water level is above the lowest level
|
|
190
|
+
check_low = (
|
|
191
|
+
ref._obj.transect.camera_config.h_to_z(ref._obj.transect.h_a)
|
|
192
|
+
> ref._obj.transect.cross_section.z.min()
|
|
193
|
+
)
|
|
194
|
+
check_high = (
|
|
195
|
+
ref._obj.transect.camera_config.h_to_z(ref._obj.transect.h_a)
|
|
196
|
+
< ref._obj.transect.cross_section.z.max()
|
|
196
197
|
)
|
|
198
|
+
if check_low and check_high:
|
|
199
|
+
try:
|
|
200
|
+
ref._obj.transect.cross_section.plot_water_level(
|
|
201
|
+
h=ref._obj.transect.h_a,
|
|
202
|
+
length=2.0,
|
|
203
|
+
linewidth=3.0,
|
|
204
|
+
ax=ax,
|
|
205
|
+
camera=True,
|
|
206
|
+
swap_y_coords=True,
|
|
207
|
+
color="r",
|
|
208
|
+
label="water level",
|
|
209
|
+
)
|
|
210
|
+
except:
|
|
211
|
+
warnings.warn(
|
|
212
|
+
"Not able to find a unique location for plotting of water level",
|
|
213
|
+
stacklevel=2
|
|
214
|
+
)
|
|
197
215
|
|
|
198
216
|
# draw some depth lines for better visual interpretation.
|
|
199
217
|
depth_lines = ref._obj.transect.get_depth_perspective(h=ref._obj.transect.h_a)
|
pyorc/cli/cli_utils.py
CHANGED
|
@@ -329,20 +329,8 @@ def read_shape_as_gdf(fn=None, geojson=None, gdf=None):
|
|
|
329
329
|
crs = None
|
|
330
330
|
gdf = gpd.GeoDataFrame().from_features(geojson, crs=crs)
|
|
331
331
|
else:
|
|
332
|
-
gdf =
|
|
333
|
-
crs = gdf.crs
|
|
334
|
-
# also read raw json, and check if crs attribute exists
|
|
335
|
-
if isinstance(fn, str):
|
|
336
|
-
with open(fn, "r") as f:
|
|
337
|
-
raw_json = json.load(f)
|
|
338
|
-
else:
|
|
339
|
-
# apparently a file object was provided
|
|
340
|
-
fn.seek(0)
|
|
341
|
-
raw_json = json.load(fn)
|
|
342
|
-
if "crs" not in raw_json:
|
|
343
|
-
# override the crs
|
|
344
|
-
crs = None
|
|
345
|
-
gdf = gdf.set_crs(None, allow_override=True)
|
|
332
|
+
gdf = helpers.read_shape_safe_crs(fn)
|
|
333
|
+
crs = gdf.crs
|
|
346
334
|
# check if all geometries are points
|
|
347
335
|
assert all([isinstance(geom, Point) for geom in gdf.geometry]), (
|
|
348
336
|
"shapefile may only contain geometries of type " '"Point"'
|
pyorc/helpers.py
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import importlib.util
|
|
5
|
+
import json
|
|
5
6
|
|
|
6
7
|
import cv2
|
|
8
|
+
import geopandas as gpd
|
|
7
9
|
import matplotlib.pyplot as plt
|
|
8
10
|
import numpy as np
|
|
9
11
|
import xarray as xr
|
|
@@ -582,6 +584,27 @@ def optimize_log_profile(
|
|
|
582
584
|
return {"z0": z0, "k_max": k_max, "s0": s0, "s1": s1}
|
|
583
585
|
|
|
584
586
|
|
|
587
|
+
def read_shape_safe_crs(fn):
|
|
588
|
+
"""Read a shapefile with geopandas, but ensure that CRS is set to None when not available.
|
|
589
|
+
|
|
590
|
+
This function is required in cases where geometries must be read that do not have a specified CRS. Geopandas
|
|
591
|
+
defaults to WGS84 EPSG 4326 if the CRS is not specified.
|
|
592
|
+
"""
|
|
593
|
+
gdf = gpd.read_file(fn)
|
|
594
|
+
# also read raw json, and check if crs attribute exists
|
|
595
|
+
if isinstance(fn, str):
|
|
596
|
+
with open(fn, "r") as f:
|
|
597
|
+
raw_json = json.load(f)
|
|
598
|
+
else:
|
|
599
|
+
# apparently a file object was provided
|
|
600
|
+
fn.seek(0)
|
|
601
|
+
raw_json = json.load(fn)
|
|
602
|
+
if "crs" not in raw_json:
|
|
603
|
+
# override the crs
|
|
604
|
+
gdf = gdf.set_crs(None, allow_override=True)
|
|
605
|
+
return gdf
|
|
606
|
+
|
|
607
|
+
|
|
585
608
|
def rotate_u_v(u, v, theta, deg=False):
|
|
586
609
|
"""Rotate u and v components of vector counterclockwise by an amount of rotation.
|
|
587
610
|
|
pyorc/plot_helpers.py
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import matplotlib.pyplot as plt
|
|
4
4
|
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
|
|
5
|
+
from shapely import geometry
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
def
|
|
8
|
-
"""Plot
|
|
8
|
+
def _plot_3d_pol(polygon, ax=None, **kwargs):
|
|
9
|
+
"""Plot single polygon on matplotlib 3d ax."""
|
|
9
10
|
x, y, z = zip(*polygon.exterior.coords)
|
|
10
11
|
verts = [list(zip(x, y, z))]
|
|
11
12
|
|
|
@@ -17,13 +18,27 @@ def plot_3d_polygon(polygon, ax=None, **kwargs):
|
|
|
17
18
|
return p
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
def plot_3d_polygon(polygon, ax=None, **kwargs):
|
|
22
|
+
"""Plot a shapely.geometry.Polygon or MultiPolygon on matplotlib 3d ax."""
|
|
23
|
+
if isinstance(polygon, geometry.MultiPolygon):
|
|
24
|
+
for pol in polygon.geoms:
|
|
25
|
+
p = _plot_3d_pol(pol, ax=ax, **kwargs)
|
|
26
|
+
else:
|
|
27
|
+
p = _plot_3d_pol(polygon, ax=ax, **kwargs)
|
|
28
|
+
return p
|
|
29
|
+
|
|
30
|
+
|
|
20
31
|
def plot_polygon(polygon, ax=None, **kwargs):
|
|
21
|
-
"""Plot a shapely.geometry.Polygon on matplotlib ax."""
|
|
22
|
-
# x, y = zip(*polygon.exterior.coords)
|
|
32
|
+
"""Plot a shapely.geometry.Polygon or MultiPolygon on matplotlib ax."""
|
|
23
33
|
if ax is None:
|
|
24
34
|
ax = plt.axes()
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
if isinstance(polygon, geometry.MultiPolygon):
|
|
36
|
+
for pol in polygon.geoms:
|
|
37
|
+
patch = plt.Polygon(pol.exterior.coords, **kwargs)
|
|
38
|
+
p = ax.add_patch(patch)
|
|
39
|
+
else:
|
|
40
|
+
patch = plt.Polygon(polygon.exterior.coords, **kwargs)
|
|
41
|
+
p = ax.add_patch(patch)
|
|
27
42
|
return p
|
|
28
43
|
|
|
29
44
|
|
pyorc/service/velocimetry.py
CHANGED
|
@@ -9,7 +9,6 @@ import subprocess
|
|
|
9
9
|
from typing import Dict, Optional
|
|
10
10
|
|
|
11
11
|
import click
|
|
12
|
-
import geopandas as gpd
|
|
13
12
|
import numpy as np
|
|
14
13
|
import xarray as xr
|
|
15
14
|
import yaml
|
|
@@ -19,6 +18,7 @@ from matplotlib.colors import Normalize
|
|
|
19
18
|
import pyorc
|
|
20
19
|
from pyorc import CameraConfig, CrossSection, Video, const
|
|
21
20
|
from pyorc.cli import cli_utils
|
|
21
|
+
from pyorc.helpers import read_shape_safe_crs
|
|
22
22
|
|
|
23
23
|
__all__ = ["velocity_flow", "velocity_flow_subprocess"]
|
|
24
24
|
|
|
@@ -287,7 +287,7 @@ class VelocityFlowProcessor(object):
|
|
|
287
287
|
"Cross section for water level detection provided, and no water level set, "
|
|
288
288
|
" water level will be estimated optically."
|
|
289
289
|
)
|
|
290
|
-
gdf =
|
|
290
|
+
gdf = read_shape_safe_crs(cross_wl)
|
|
291
291
|
cross_section_wl = pyorc.CrossSection(camera_config=camera_config, cross_section=gdf)
|
|
292
292
|
if "water_level" not in recipe:
|
|
293
293
|
# make sure water_level is represented
|
|
File without changes
|
|
File without changes
|
|
File without changes
|