Commit 2a005933 authored by Pierre-Antoine Rouby's avatar Pierre-Antoine Rouby
Browse files

Model: Add Geomerty model from previous work.

Showing with 538 additions and 0 deletions
+538 -0
# -*- coding: utf-8 -*-
import numpy as np
from time import time
from typing import List
from copy import deepcopy
from operator import itemgetter
from Model.Geometry.PointXYZ import PointXYZ
from Model.Geometry.ProfileXYZ import ProfileXYZ
# TypeProfileXYZ = List[ProfileXYZ]
class Geometry:
"""
Reach geometry
"""
def __init__(self, parent=None):
self.parent = parent
self._list_profiles: List[ProfileXYZ] = []
self.file_st = ""
self.__list_copied_profiles = []
def __repr__(self):
return f"\n===== Début liste des profils ======> {np.array(self._list_profiles)}" \
f"\n<====== Fin liste des profils ====="
@property
def number_profiles(self):
"""
Returns:
Number of profiles
"""
return len(self._list_profiles)
def get_geometry(self) -> List[ProfileXYZ]:
"""
Returns:
The profiles list.
"""
return self._list_profiles
def get_profile_i(self, i: int) -> ProfileXYZ:
"""
Args:
i: Index
Returns:
The profile at index i.
"""
try:
return self._list_profiles[i]
except IndexError:
raise IndexError(f"Le bief a moins de {i} profil(s)")
def import_geometry(self, file_path_name: str):
"""Import a geometry from file (.ST or .st)
Args:
file_path_name: The absolute path of geometry file (.ST or .st) to import.
Returns:
Nothing.
"""
self.file_st = str(file_path_name)
list_profile, list_header = self.read_file_st()
# print(list_profile, "\n", list_header)
if list_profile and list_header:
for ind, profile in enumerate(list_profile):
prof = ProfileXYZ(*list_header[ind])
prof.import_points(profile)
self._list_profiles.append(prof)
self._update_profile_numbers()
else:
print("Fichier introuvable ou non conforme !")
def add(self):
"""Add a new profile at the end of profiles list
Returns:
Nothing.
"""
nb_profile = self.number_profiles
profile = ProfileXYZ()
profile.num = nb_profile + 1
self._list_profiles.append(profile)
def _update_profile_numbers(self):
"""Update profiles index
Returns:
Nothing.
"""
for ind, profile in enumerate(self.get_geometry()):
profile.num = ind + 1
def insert(self, index: int):
"""Insert new profile in list
Args:
index: The position of the new profile.
Returns:
Nothing.
"""
profile = ProfileXYZ()
self._list_profiles.insert(index, profile)
self._update_profile_numbers()
def delete(self, list_index: list):
"""Delete some elements in profile list
Args:
list_index: The list of element index
Returns:
Nothing.
"""
try:
if list_index:
indices = sorted(list(set(list_index)), reverse=True)
for idx in indices:
# if idx < len(self._list_profiles) :
try:
self._list_profiles.pop(idx)
self._update_profile_numbers()
except IndexError:
print("Liste vide, rien à supprimer !")
except TypeError:
if isinstance(list_index, int):
self._list_profiles.pop(list_index)
self._update_profile_numbers()
print(f"\nSuppression --> attention !!!!\nL'argument {list_index} doit être une liste!\n")
else:
raise TypeError(f"L'argument {list_index} fourni est de type incorrect")
def _sort(self, is_reversed: bool = False):
self._list_profiles = sorted(
self._list_profiles,
key=lambda profile: profile.pk,
reverse=is_reversed
)
def sort_ascending(self):
"""Sort profiles by increasing KP
Returns:
Nothing.
"""
self._sort(is_reversed=False)
def sort_descending(self):
"""Sort profiles by decreasing KP
Returns:
Nothing.
"""
self._sort(is_reversed=True)
def copy(self, index_list: List[int]):
self.__list_copied_profiles.clear()
index_list = list(set(index_list)) # delete duplicate index
for index in index_list:
try:
self.__list_copied_profiles.append(deepcopy(self.get_profile_i(index)))
except IndexError:
raise IndexError(f"Echec de la copie, l'indice {index} n'existe pas !")
def paste(self):
if self.__list_copied_profiles:
for profile in self.__list_copied_profiles:
self._list_profiles.append(profile)
print("self.__list_copied_profiles", self.__list_copied_profiles, "\n *****")
def read_file_st(self):
"""Read the ST file
Returns:
List of profiles and list of headers.
"""
t0 = time()
line_is_header = True
list_point_profile = []
list_profile = []
list_header = []
stop_code = "999.999"
try:
with open(self.file_st, encoding="utf-8") as file_st:
for line in file_st:
if not (line.startswith("#") or line.startswith("*")):
line = line.split()
if line_is_header:
if len(line) >= 6:
list_header.append(line[:6])
elif len(line) == 5:
line.append("")
list_header.append(line)
else:
print(f"Point {line} invalide ==> pas pris en compte")
line_is_header = False
else:
# Read until "999.9990 999.9990" as found
if len(line) == 3:
x, y, z = line
if stop_code in x and stop_code in y:
line_is_header = True
list_profile.append(list_point_profile)
list_point_profile = []
else:
line.append("")
list_point_profile.append(line)
elif len(line) == 4:
x, y, z, ld = line
if stop_code in x and stop_code in y:
list_profile.append(list_point_profile)
list_point_profile = []
line_is_header = True
else:
list_point_profile.append(line)
else:
pass
except FileNotFoundError:
print(f"\n \n %%%%%% Fichier : {self.file_st} introuvable !! %%%%%%")
print("****** Fichier {} lu et traité en {} secondes *******".format(self.file_st, time() - t0))
return list_profile, list_header
# -*- coding: utf-8 -*-
from math import dist
from pandas import isna as pd_is_na
class PointXYZ:
def __init__(self, x: float, y: float, z: float, point_name: str = ""):
self.x = float(x)
self.y = float(y)
self.z = float(z)
self.name = point_name
self.points = [self.x, self.y, self.z, self.name]
def __repr__(self):
point_xyz_name = f"({self.x}, {self.y},{self.z}, {self.name})"
return point_xyz_name
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = float(value)
@property
def y(self):
return self._y
@y.setter
def y(self, value):
self._y = float(value)
# self.points[1] = self._y
@property
def z(self):
return self._z
@z.setter
def z(self, value):
self._z = float(value)
@property
def name(self):
return self._name
@name.setter
def name(self, point_name):
self._name = point_name
def point_is_named(self):
"""
Returns:
True if the point is named.
"""
return len(self.name.strip()) != 0
@property
def is_nan(self):
"""
Returns:
True if at least one coordinate is as np.nan
"""
return pd_is_na(self.x) or pd_is_na(self.y) or pd_is_na(self.z)
@staticmethod
def distance(p1, p2):
"""Euclidean distance between p1 and p2.
Args:
p1: A XYZ Point
p2: A XYZ Point
Returns:
Euclidean distance between the two points
"""
return dist((p1.x, p1.y, p1.z), (p2.x, p2.y, p2.z))
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
from typing import List
from Model.Geometry.PointXYZ import PointXYZ
class ProfileXYZ:
def __init__(self, num: int = 0, code1: int = 0, code2: int = 0,
nb_points: int = 0, kp: float = 0., name: str = ""):
"""ProfileXYZ constructor
Args:
num: The number of this profile
code1: The interpolation code 1
code2: The interpolation code 2
nb_points: Number of points
kp: Kilometer point
name: The name of profile
Returns:
Nothing.
"""
self._num = int(num)
self._code1 = int(code1)
self._code2 = int(code2)
self._nb_points = int(nb_points)
self._kp = float(kp)
self._name = str(name)
self._list_points: List[PointXYZ] = []
def __repr__(self):
df = pd.DataFrame(columns=["X", "Y", "Z", "Name"],
data=[[p.x, p.y, p.z, p.name] for p in self._list_points])
return f"\n{self.header}\n{df}"
@property
def num(self):
"""
Returns:
Number of profile.
"""
return self._num
@num.setter
def num(self, value: int):
self._num = int(value)
@property
def code1(self):
"""
Returns:
Interpolation code 1.
"""
return self._code1
@code1.setter
def code1(self, value: int):
self._code1 = int(value)
@property
def code2(self):
"""
Returns:
Interpolation code 2.
"""
return self._code2
@code2.setter
def code2(self, value: int):
self._code2 = int(value)
@property
def nb_points(self):
return self._nb_points
# @nb_points.setter
# def nb_points(self, nb: int):
# self._nb_points = int(nb)
@property
def kp(self):
"""
Returns:
Kilometer point.
"""
return self._kp
@kp.setter
def kp(self, value: float):
self._kp = float(value)
@property
def name(self):
"""
Returns:
Profile name.
"""
return self._name
@name.setter
def name(self, other: str):
self._name = other
@property
def header(self):
"""
Returns:
Profile header.
"""
return np.array([self._num, self._code1, self._code2, self._nb_points, self.kp, self._name])
def import_points(self, list_points: list):
"""Import a list of points to profile
Args:
list_points: Liste of PointXYZ
Returns:
Nothing.
"""
for point in list_points:
pt = PointXYZ(*point)
self._list_points.append(pt)
def get_point_i(self, index: int) -> PointXYZ:
"""Get point at index.
Args:
index: Index of point.
Returns:
The point.
"""
try:
return self._list_points[index]
except IndexError:
raise IndexError(f"Le profil a moins de {index} points !")
def add(self):
"""Add a new PointXYZ to profile.
Returns:
Nothing.
"""
point_xyz = PointXYZ(0., 0., 0.)
self._list_points.append(point_xyz)
def delete(self, index: int):
"""Delete the point at index
Args:
index: Index of point.
Returns:
Nothing.
"""
try:
self._list_points.pop(index)
except IndexError:
raise IndexError(f"Suppression échouée, l'indice {index} n'existe pas !")
def insert(self, index: int):
"""Insert a new profile at index.
Args:
index: The index of new profile.
Returns:
Nothing.
"""
profile = ProfileXYZ()
self._list_points.insert(index, profile)
def delete1(self, list_index: list):
"""Delete a list of points
Args:
list_index: Indexes list.
Returns:
Nothing.
"""
try:
if list_index:
indices = sorted(list(set(list_index)), reverse=True)
for idx in indices:
# if idx < len(self._list_profiles) :
try:
self._list_points.pop(idx)
except IndexError:
print("Liste vide, rien à supprimer !")
except TypeError:
if isinstance(list_index, int):
self._list_points.pop(list_index)
print(f"\nSuppression --> attention !!!!\nL'argument {list_index} doit être une liste!\n")
else:
raise TypeError(f"L'argument {list_index} fourni est de type incorrect")
# -*- coding: utf-8 -*-
from Model.Geometry.Geometry import Geometry
class Reach:
def __init__(self, name: str = "",
upstream_node: str = None,
downstream_node: str = None,
parent=None):
self._name = name
self._name_upstream_node = name_upstream_node
self._name_downstream_node = name_downstream_node
self.parent = parent
self._geometry = Geometry(parent=self)
def __repr__(self):
return f"Bief : {self._name}\n Nb de sections : {self._geometry.number_profiles}"
@property
def name(self):
return self._name
@property
def name_upstream_node(self):
return self._name_upstream_node
@property
def name_downstream_node(self):
return self._name_downstream_node
@property
def geometry(self):
return self._geometry
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment