mirror of https://gitlab.com/pamhyr/pamhyr2
Model: Profile: Add speed computation methode.
parent
fead93f0b9
commit
4c927eb7c7
|
|
@ -19,6 +19,7 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
|
from shapely import geometry
|
||||||
|
|
||||||
from Model.Geometry.Point import Point
|
from Model.Geometry.Point import Point
|
||||||
from Model.Except import NotImplementedMethodeError
|
from Model.Except import NotImplementedMethodeError
|
||||||
|
|
@ -341,3 +342,12 @@ class Profile(object):
|
||||||
# Abstract method for width approximation
|
# Abstract method for width approximation
|
||||||
def get_water_limits(self, z):
|
def get_water_limits(self, z):
|
||||||
raise NotImplementedMethodeError(self, self.get_water_limits)
|
raise NotImplementedMethodeError(self, self.get_water_limits)
|
||||||
|
|
||||||
|
def wet_points(self, z):
|
||||||
|
raise NotImplementedMethodeError(self, self.wet_point)
|
||||||
|
|
||||||
|
def wet_perimeter(self, z):
|
||||||
|
raise NotImplementedMethodeError(self, self.wet_perimeter)
|
||||||
|
|
||||||
|
def wet_area(self, z):
|
||||||
|
raise NotImplementedMethodeError(self, self.wet_area)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ from typing import List
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from tools import timer
|
from tools import timer
|
||||||
|
from shapely import geometry
|
||||||
|
|
||||||
from Model.Tools.PamhyrDB import SQLSubModel
|
from Model.Tools.PamhyrDB import SQLSubModel
|
||||||
from Model.Except import ClipboardFormatError
|
from Model.Except import ClipboardFormatError
|
||||||
|
|
@ -373,99 +374,13 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
"""
|
"""
|
||||||
return [x for x in lst if not np.isnan(x)]
|
return [x for x in lst if not np.isnan(x)]
|
||||||
|
|
||||||
def _first_point_not_nan(self):
|
def speed(self, q, z):
|
||||||
first_point = self.points[0]
|
area = self.wet_area(z)
|
||||||
|
|
||||||
for point in self.points:
|
if area == 0:
|
||||||
if not point.is_nan():
|
return 0
|
||||||
first_point = point
|
|
||||||
break
|
|
||||||
|
|
||||||
return first_point
|
return q / area
|
||||||
|
|
||||||
def _last_point_not_nan(self):
|
|
||||||
last_point = self.points[-1]
|
|
||||||
|
|
||||||
for point in self.points[::-1]:
|
|
||||||
if not point.is_nan():
|
|
||||||
last_point = point
|
|
||||||
break
|
|
||||||
|
|
||||||
return last_point
|
|
||||||
|
|
||||||
@timer
|
|
||||||
def get_station(self) -> np.ndarray:
|
|
||||||
"""Projection of the points of the profile on a plane.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
profile: The profile
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Projection of the points of the profile on a plane.
|
|
||||||
"""
|
|
||||||
if self.nb_points < 3:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
first_named_point = None
|
|
||||||
index_first_named_point = None
|
|
||||||
last_named_point = None
|
|
||||||
|
|
||||||
first_point_not_nan = self._first_point_not_nan()
|
|
||||||
last_point_not_nan = self._last_point_not_nan()
|
|
||||||
|
|
||||||
for index, point in enumerate(self.points):
|
|
||||||
if point.point_is_named():
|
|
||||||
index_first_named_point = index
|
|
||||||
first_named_point = point
|
|
||||||
break
|
|
||||||
|
|
||||||
for point in reversed(self.points):
|
|
||||||
if point.point_is_named():
|
|
||||||
last_named_point = point
|
|
||||||
break
|
|
||||||
|
|
||||||
station = []
|
|
||||||
constant = 0.0
|
|
||||||
|
|
||||||
if (first_named_point is not None and
|
|
||||||
last_named_point is not None):
|
|
||||||
if (first_named_point != last_named_point and
|
|
||||||
first_named_point.x != last_named_point.x):
|
|
||||||
vector = Vector1d(first_named_point, last_named_point)
|
|
||||||
norm_dir_vec = vector.normalized_direction_vector()
|
|
||||||
else:
|
|
||||||
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
|
||||||
norm_dir_vec = vector.normalized_direction_vector()
|
|
||||||
|
|
||||||
for point in self.points:
|
|
||||||
xi = point.x - first_named_point.x
|
|
||||||
yi = point.y - first_named_point.y
|
|
||||||
station_i = (norm_dir_vec[0] * xi +
|
|
||||||
norm_dir_vec[1] * yi)
|
|
||||||
station.append(station_i)
|
|
||||||
|
|
||||||
constant = station[index_first_named_point]
|
|
||||||
elif first_named_point is None:
|
|
||||||
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
|
||||||
norm_dir_vec = vector.normalized_direction_vector()
|
|
||||||
|
|
||||||
for point in self.points:
|
|
||||||
xi = point.x - first_point_not_nan.x
|
|
||||||
yi = point.y - first_point_not_nan.y
|
|
||||||
station_i = (norm_dir_vec[0] * xi +
|
|
||||||
norm_dir_vec[1] * yi)
|
|
||||||
station.append(station_i)
|
|
||||||
|
|
||||||
z_min = self.z_min()
|
|
||||||
index_profile_z_min = list(
|
|
||||||
filter(
|
|
||||||
lambda z: z[1] == z_min,
|
|
||||||
enumerate(self.z())
|
|
||||||
)
|
|
||||||
)[0]
|
|
||||||
constant = station[index_profile_z_min[0]]
|
|
||||||
|
|
||||||
return list(map(lambda s: s - constant, station))
|
|
||||||
|
|
||||||
def width_approximation(self):
|
def width_approximation(self):
|
||||||
if self.has_standard_named_points():
|
if self.has_standard_named_points():
|
||||||
|
|
@ -477,6 +392,43 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
|
|
||||||
return abs(rg.dist(rd))
|
return abs(rg.dist(rd))
|
||||||
|
|
||||||
|
def wet_perimeter(self, z):
|
||||||
|
poly = self.wet_polygon(z)
|
||||||
|
|
||||||
|
if poly is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return poly.length
|
||||||
|
|
||||||
|
def wet_area(self, z):
|
||||||
|
poly = self.wet_polygon(z)
|
||||||
|
|
||||||
|
if poly is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return poly.area
|
||||||
|
|
||||||
|
def wet_polygon(self, z):
|
||||||
|
points = self.wet_points(z)
|
||||||
|
if len(points) < 3:
|
||||||
|
return None
|
||||||
|
|
||||||
|
z = map(lambda p: p.z, points)
|
||||||
|
station = self._get_station(points)
|
||||||
|
|
||||||
|
poly = geometry.Polygon(list(zip(station, z)))
|
||||||
|
|
||||||
|
return poly
|
||||||
|
|
||||||
|
def wet_points(self, z):
|
||||||
|
left, right = self.get_water_limits(z)
|
||||||
|
|
||||||
|
points = list(filter(lambda p: p.z < z, self._points))
|
||||||
|
points = [left] + points + [right]
|
||||||
|
points = sorted(points, key=lambda p: p.x)
|
||||||
|
|
||||||
|
return points
|
||||||
|
|
||||||
def get_water_limits(self, z):
|
def get_water_limits(self, z):
|
||||||
"""
|
"""
|
||||||
Determine left and right limits of water elevation.
|
Determine left and right limits of water elevation.
|
||||||
|
|
@ -509,7 +461,7 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
[self.point(i_left).z, self.point(i_left - 1).z],
|
[self.point(i_left).z, self.point(i_left - 1).z],
|
||||||
[self.point(i_left).y, self.point(i_left - 1).y]
|
[self.point(i_left).y, self.point(i_left - 1).y]
|
||||||
)
|
)
|
||||||
pt_left = PointXYZ(x, y, z)
|
pt_left = PointXYZ(x, y, z, name="wl_left")
|
||||||
else:
|
else:
|
||||||
pt_left = self.point(0)
|
pt_left = self.point(0)
|
||||||
|
|
||||||
|
|
@ -525,8 +477,105 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
[self.point(i_right).z, self.point(i_right + 1).z],
|
[self.point(i_right).z, self.point(i_right + 1).z],
|
||||||
[self.point(i_right).y, self.point(i_right + 1).y]
|
[self.point(i_right).y, self.point(i_right + 1).y]
|
||||||
)
|
)
|
||||||
pt_right = PointXYZ(x, y, z)
|
pt_right = PointXYZ(x, y, z, name="wl_right")
|
||||||
else:
|
else:
|
||||||
pt_right = self.point(self.number_points - 1)
|
pt_right = self.point(self.number_points - 1)
|
||||||
|
|
||||||
return pt_left, pt_right
|
return pt_left, pt_right
|
||||||
|
|
||||||
|
def get_station(self):
|
||||||
|
"""Projection of the points of the profile on a plane.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
self: The profile
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Projection of the points of the profile on a plane.
|
||||||
|
"""
|
||||||
|
if self.nb_points < 3:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return self._get_station(self.points)
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def _get_station(self, points):
|
||||||
|
first_named_point = None
|
||||||
|
index_first_named_point = None
|
||||||
|
last_named_point = None
|
||||||
|
|
||||||
|
first_point_not_nan = self._first_point_not_nan(points)
|
||||||
|
last_point_not_nan = self._last_point_not_nan(points)
|
||||||
|
|
||||||
|
for index, point in enumerate(points):
|
||||||
|
if point.point_is_named():
|
||||||
|
index_first_named_point = index
|
||||||
|
first_named_point = point
|
||||||
|
break
|
||||||
|
|
||||||
|
for point in reversed(points):
|
||||||
|
if point.point_is_named():
|
||||||
|
last_named_point = point
|
||||||
|
break
|
||||||
|
|
||||||
|
station = []
|
||||||
|
constant = 0.0
|
||||||
|
|
||||||
|
if (first_named_point is not None and
|
||||||
|
last_named_point is not None):
|
||||||
|
if (first_named_point != last_named_point and
|
||||||
|
first_named_point.x != last_named_point.x):
|
||||||
|
vector = Vector1d(first_named_point, last_named_point)
|
||||||
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
|
else:
|
||||||
|
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
||||||
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
xi = point.x - first_named_point.x
|
||||||
|
yi = point.y - first_named_point.y
|
||||||
|
station_i = (norm_dir_vec[0] * xi +
|
||||||
|
norm_dir_vec[1] * yi)
|
||||||
|
station.append(station_i)
|
||||||
|
|
||||||
|
constant = station[index_first_named_point]
|
||||||
|
elif first_named_point is None:
|
||||||
|
vector = Vector1d(first_point_not_nan, last_point_not_nan)
|
||||||
|
norm_dir_vec = vector.normalized_direction_vector()
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
xi = point.x - first_point_not_nan.x
|
||||||
|
yi = point.y - first_point_not_nan.y
|
||||||
|
station_i = (norm_dir_vec[0] * xi +
|
||||||
|
norm_dir_vec[1] * yi)
|
||||||
|
station.append(station_i)
|
||||||
|
|
||||||
|
z_min = self.z_min()
|
||||||
|
index_profile_z_min = list(
|
||||||
|
filter(
|
||||||
|
lambda z: z[1] == z_min,
|
||||||
|
enumerate(self.z())
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
|
constant = station[index_profile_z_min[0]]
|
||||||
|
|
||||||
|
return list(map(lambda s: s - constant, station))
|
||||||
|
|
||||||
|
def _first_point_not_nan(self, points):
|
||||||
|
first_point = None
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
if not point.is_nan():
|
||||||
|
first_point = point
|
||||||
|
break
|
||||||
|
|
||||||
|
return first_point
|
||||||
|
|
||||||
|
def _last_point_not_nan(self, points):
|
||||||
|
last_point = None
|
||||||
|
|
||||||
|
for point in reversed(points):
|
||||||
|
if not point.is_nan():
|
||||||
|
last_point = point
|
||||||
|
break
|
||||||
|
|
||||||
|
return last_point
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue