Model: Profile: Add speed computation methode.

setup.py
Pierre-Antoine Rouby 2024-04-08 11:40:12 +02:00
parent fead93f0b9
commit 4c927eb7c7
2 changed files with 152 additions and 93 deletions

View File

@ -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)

View File

@ -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