Pamhyr2/src/Model/Geometry/Profile.py

280 lines
6.3 KiB
Python

# Profile.py -- Pamhyr
# Copyright (C) 2023 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
import logging
from tools import timer
from Model.Geometry.Point import Point
from Model.Except import NotImplementedMethodeError
logger = logging.getLogger()
class Profile(object):
_id_cnt = 0
def __init__(self, id:int = -1, num:int = 0,
kp:float = 0.0, name:str = "",
code1:int = 0, code2:int = 0,
_type:str = "", reach = None,
status = None):
super(Profile, self).__init__()
self._status = status
if id == -1:
self.id = Profile._id_cnt
else:
self.id = id
Profile._id_cnt = max(self.id, Profile._id_cnt+1)
self._num = int(num)
self._code1 = int(code1)
self._code2 = int(code2)
self._kp = float(kp)
self._name = str(name)
self._reach = reach
self._points: List[Point] = []
self._profile_type = _type
@property
def number_points(self):
return len(self._points)
@property
def points(self):
return self._points.copy()
@property
def reach(self):
return self._reach
@property
def num(self):
"""
Returns:
Number of profile.
"""
return self._num
@num.setter
def num(self, value: int):
self._num = int(value)
self._status.modified()
@property
def code1(self):
"""
Returns:
Interpolation code 1.
"""
return self._code1
@code1.setter
def code1(self, value: int):
self._code1 = int(value)
self._status.modified()
@property
def code2(self):
"""
Returns:
Interpolation code 2.
"""
return self._code2
@code2.setter
def code2(self, value: int):
self._code2 = int(value)
self._status.modified()
@property
def nb_points(self):
return len(self._points)
@property
def kp(self):
"""
Returns:
Kilometer point.
"""
return self._kp
@kp.setter
def kp(self, value: float):
self._kp = float(value)
self._status.modified()
@property
def name(self):
"""
Returns:
Profile name.
"""
return self._name
@name.setter
def name(self, value: str):
self._name = value.strip()
self._status.modified()
@property
def profile_type(self):
"""
Returns:
Profile type.
"""
return self._profile_type
@profile_type.setter
def profile_type(self, value: str):
self._profile_type = value
self._status.modified()
def point(self, i:int):
if i < len(self._points):
return self._points[i]
return None
def named_points(self):
"""List of named point
Returns:
The list of named point
"""
return [point for point in self._points
if point.point_is_named()]
def insert_point(self, index: int, point:Point):
"""Insert point at index.
Args:
index: The index of new profile.
point: The point.
Returns:
Nothing.
"""
self._points.insert(index, point)
self._status.modified()
def delete(self, indexes: int):
"""Delete points at index
Args:
indexes: List of index of points.
Returns:
Nothing.
"""
points = set(
map(
lambda e: e[1],
filter(
lambda e: e[0] in indexes,
enumerate(self.points)
)
)
)
self._points = list(
filter(
lambda p: p not in points,
self.points
)
)
self._status.modified()
def delete_points(self, points):
"""Delete some elements in profile list
Args:
points: The list of profile to delete
Returns:
Nothing.
"""
self._points = list(
filter(
lambda p: p not in points,
self.points
)
)
self._status.modified()
# Move
def move_up_point(self, index: int):
if index < len(self._points):
next = index - 1
p = self._points
p[index], p[next] = p[next], p[index]
self._status.modified()
def move_down_point(self, index: int):
if index >= 0:
prev = index + 1
p = self._points
p[index], p[prev] = p[prev], p[index]
self._status.modified()
# Sort
@timer
def sort(self, column, is_reversed: bool = False):
predicate = lambda p: p.x
if column == 'y':
predicate = lambda p: p.y
elif column == 'z':
predicate = lambda p: p.z
self._points = sorted(
self._points,
key=predicate,
reverse=is_reversed
)
self._status.modified()
@timer
def sort_with_indexes(self, indexes: list):
if len(self._points) != len(indexes):
logger.critical("Indexes list do not correspond to point list")
self._points = list(
map(
lambda x: x[1],
sorted(
enumerate(self.points),
key=lambda x: indexes[x[0]]
)
)
)
self._status.modified()
# Abstract method, must be implemented for in non abstract class
def get_station(self):
raise NotImplementedMethodeError(self, self.get_station)