mirror of https://gitlab.com/pamhyr/pamhyr2
Compare commits
4 Commits
c58620fdc2
...
1b70e22a58
| Author | SHA1 | Date |
|---|---|---|
|
|
1b70e22a58 | |
|
|
22aeda105e | |
|
|
7181122a3a | |
|
|
76ce34c4ea |
|
|
@ -58,7 +58,7 @@ class Point(SQLSubModel):
|
||||||
self._name = name
|
self._name = name
|
||||||
self.modified()
|
self.modified()
|
||||||
|
|
||||||
def point_is_named(self):
|
def is_named(self):
|
||||||
"""
|
"""
|
||||||
Returns:
|
Returns:
|
||||||
True if the point is named.
|
True if the point is named.
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,9 @@ class PointXYZ(Point):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
return f"({self._x}, {self._y}, {self._z}, {self._name})"
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.y > other.y
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def x(self):
|
def x(self):
|
||||||
return self._x
|
return self._x
|
||||||
|
|
@ -368,5 +371,10 @@ class PointXYZ(Point):
|
||||||
a = PointXYZ.distance(p1, p2)
|
a = PointXYZ.distance(p1, p2)
|
||||||
b = PointXYZ.distance(p2, p3)
|
b = PointXYZ.distance(p2, p3)
|
||||||
c = PointXYZ.distance(p3, p1)
|
c = PointXYZ.distance(p3, p1)
|
||||||
s = (a + b + c) / 2
|
|
||||||
return (s*(s-a) * (s-b)*(s-c)) ** 0.5
|
s = float((a + b + c) / 2)
|
||||||
|
res = (
|
||||||
|
s * abs(s - a) * abs(s - b) * abs(s - c)
|
||||||
|
) ** 0.5
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ class Profile(object):
|
||||||
The list of named point
|
The list of named point
|
||||||
"""
|
"""
|
||||||
return [point for point in self.points
|
return [point for point in self.points
|
||||||
if point.point_is_named()]
|
if point.is_named()]
|
||||||
|
|
||||||
def insert_point(self, index: int, point: Point):
|
def insert_point(self, index: int, point: Point):
|
||||||
"""Insert point at index.
|
"""Insert point at index.
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import queue
|
||||||
|
import random
|
||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
@ -929,13 +931,13 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
last_point_not_nan = self._last_point_not_nan(points)
|
last_point_not_nan = self._last_point_not_nan(points)
|
||||||
|
|
||||||
for index, point in enumerate(points):
|
for index, point in enumerate(points):
|
||||||
if point.point_is_named():
|
if point.is_named():
|
||||||
index_first_named_point = index
|
index_first_named_point = index
|
||||||
first_named_point = point
|
first_named_point = point
|
||||||
break
|
break
|
||||||
|
|
||||||
for point in reversed(points):
|
for point in reversed(points):
|
||||||
if point.point_is_named():
|
if point.is_named():
|
||||||
last_named_point = point
|
last_named_point = point
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -1009,46 +1011,46 @@ class ProfileXYZ(Profile, SQLSubModel):
|
||||||
if (self.nb_points <= np_purge):
|
if (self.nb_points <= np_purge):
|
||||||
return
|
return
|
||||||
|
|
||||||
nb_named = 2 # we consider the first and last point as named
|
q_area = queue.PriorityQueue()
|
||||||
area = [0.0]
|
deleted = []
|
||||||
|
|
||||||
for i in range(1, self.nb_points-1):
|
for ind, point in enumerate(self.points):
|
||||||
if self.point(i).point_is_named():
|
if (ind == 0) or (ind == self.nb_points - 1):
|
||||||
area.append(9999999.999)
|
continue
|
||||||
nb_named += 1
|
|
||||||
else:
|
if not point.is_named():
|
||||||
area.append(
|
q_area.put((
|
||||||
PointXYZ.areatriangle3d(
|
PointXYZ.areatriangle3d(
|
||||||
self.point(i-1),
|
self.point(ind - 1),
|
||||||
self.point(i),
|
point,
|
||||||
self.point(i+1))
|
self.point(ind + 1)
|
||||||
)
|
),
|
||||||
|
ind, point
|
||||||
|
))
|
||||||
|
|
||||||
area.append(0.0)
|
while self.nb_points > np_purge and not q_area.empty():
|
||||||
|
area, ind, point = q_area.get()
|
||||||
|
|
||||||
while self.nb_points > max(np_purge, nb_named):
|
self.delete_points([point])
|
||||||
to_rm = np.argmin(area[1:self.nb_points - 1]) + 1
|
deleted.append(point)
|
||||||
|
|
||||||
self.delete_i([to_rm])
|
# Recompute point neighbourhood
|
||||||
area.pop(to_rm)
|
for i in [ind-1, ind]:
|
||||||
|
if (i <= 0) or (i >= self.nb_points - 1):
|
||||||
for i in [to_rm-1, to_rm]:
|
|
||||||
if (i == 0):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (i == self.nb_points - 1):
|
point = self.point(i)
|
||||||
continue
|
if not point.is_named():
|
||||||
|
q_area.put((
|
||||||
if self.point(i).point_is_named():
|
PointXYZ.areatriangle3d(
|
||||||
area[i] = 9999999.999
|
self.point(i-1),
|
||||||
else:
|
point,
|
||||||
area[i] = PointXYZ.areatriangle3d(
|
self.point(i+1)
|
||||||
self.point(i-1),
|
), i, point
|
||||||
self.point(i),
|
))
|
||||||
self.point(i+1)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.modified()
|
self.modified()
|
||||||
|
return deleted
|
||||||
|
|
||||||
def shift(self, x, y, z):
|
def shift(self, x, y, z):
|
||||||
for p in self._points:
|
for p in self._points:
|
||||||
|
|
|
||||||
|
|
@ -375,7 +375,7 @@ class InitialConditions(SQLSubModel):
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._data)
|
return len(self.data)
|
||||||
|
|
||||||
def lst(self):
|
def lst(self):
|
||||||
return self._data
|
return self._data
|
||||||
|
|
@ -403,7 +403,7 @@ class InitialConditions(SQLSubModel):
|
||||||
self._data = data
|
self._data = data
|
||||||
|
|
||||||
def get(self, index):
|
def get(self, index):
|
||||||
return self._data[index]
|
return self.data[index]
|
||||||
|
|
||||||
def set(self, index, data):
|
def set(self, index, data):
|
||||||
self._data.insert(index, data)
|
self._data.insert(index, data)
|
||||||
|
|
@ -441,9 +441,12 @@ class InitialConditions(SQLSubModel):
|
||||||
|
|
||||||
def delete(self, data):
|
def delete(self, data):
|
||||||
list(
|
list(
|
||||||
filter(
|
map(
|
||||||
lambda x: x.set_as_deleted(),
|
lambda x: x.set_as_deleted(),
|
||||||
self._data
|
filter(
|
||||||
|
lambda x: x in data,
|
||||||
|
self._data
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.modified()
|
self.modified()
|
||||||
|
|
@ -468,7 +471,7 @@ class InitialConditions(SQLSubModel):
|
||||||
return list(
|
return list(
|
||||||
map(
|
map(
|
||||||
lambda d: d[key],
|
lambda d: d[key],
|
||||||
self._data
|
self.data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -476,7 +479,7 @@ class InitialConditions(SQLSubModel):
|
||||||
return list(
|
return list(
|
||||||
map(
|
map(
|
||||||
lambda d: d["rk"].rk,
|
lambda d: d["rk"].rk,
|
||||||
self._data
|
self.data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -486,6 +489,10 @@ class InitialConditions(SQLSubModel):
|
||||||
def get_discharge(self):
|
def get_discharge(self):
|
||||||
return self._data_get("discharge")
|
return self._data_get("discharge")
|
||||||
|
|
||||||
|
def clear_data(self):
|
||||||
|
for data in self._data:
|
||||||
|
data.set_as_deleted()
|
||||||
|
|
||||||
def generate_growing_constant_depth(self, height: float,
|
def generate_growing_constant_depth(self, height: float,
|
||||||
compute_discharge: bool):
|
compute_discharge: bool):
|
||||||
profiles = self._reach.reach.profiles.copy()
|
profiles = self._reach.reach.profiles.copy()
|
||||||
|
|
@ -502,7 +509,9 @@ class InitialConditions(SQLSubModel):
|
||||||
|
|
||||||
incline = self._reach.reach.get_incline_median_mean()
|
incline = self._reach.reach.get_incline_median_mean()
|
||||||
logger.debug(f"incline = {incline}")
|
logger.debug(f"incline = {incline}")
|
||||||
self._data = []
|
|
||||||
|
self.clear_data()
|
||||||
|
|
||||||
for profile in reversed(profiles):
|
for profile in reversed(profiles):
|
||||||
width = profile.wet_width(profile.z_min() + height)
|
width = profile.wet_width(profile.z_min() + height)
|
||||||
area = profile.wet_area(profile.z_min() + height)
|
area = profile.wet_area(profile.z_min() + height)
|
||||||
|
|
@ -568,7 +577,9 @@ class InitialConditions(SQLSubModel):
|
||||||
|
|
||||||
incline = self._reach.reach.get_incline_median_mean()
|
incline = self._reach.reach.get_incline_median_mean()
|
||||||
logger.debug(f"incline = {incline}")
|
logger.debug(f"incline = {incline}")
|
||||||
self._data = []
|
|
||||||
|
self.clear_data()
|
||||||
|
|
||||||
for profile in reversed(profiles):
|
for profile in reversed(profiles):
|
||||||
width = profile.width_approximation()
|
width = profile.width_approximation()
|
||||||
frictions = self._reach.frictions.frictions
|
frictions = self._reach.frictions.frictions
|
||||||
|
|
@ -631,7 +642,7 @@ class InitialConditions(SQLSubModel):
|
||||||
for data in self._data:
|
for data in self._data:
|
||||||
data_discharge[data["rk"].rk] = data["discharge"]
|
data_discharge[data["rk"].rk] = data["discharge"]
|
||||||
|
|
||||||
self._data = []
|
self.clear_data()
|
||||||
for profile in profiles:
|
for profile in profiles:
|
||||||
|
|
||||||
if not compute_discharge:
|
if not compute_discharge:
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
||||||
DelCommand(
|
DelCommand(
|
||||||
self._data, list(
|
self._data, list(
|
||||||
map(
|
map(
|
||||||
lambda r: self.get_true_data_row(r),
|
lambda r: self._data.point(r),
|
||||||
rows
|
rows
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -285,6 +285,8 @@ class GeometryProfileTableModel(PamhyrTableModel):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
PasteCommand(
|
PasteCommand(
|
||||||
self._data, row, points
|
self._data, row, points
|
||||||
|
|
|
||||||
|
|
@ -116,23 +116,19 @@ class AddCommand(QUndoCommand):
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
def __init__(self, profile, rows):
|
def __init__(self, profile, points):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._profile = profile
|
self._profile = profile
|
||||||
self._rows = rows
|
self._points = points
|
||||||
|
|
||||||
self._points = []
|
|
||||||
for row in rows:
|
|
||||||
self._points.append(self._profile.point(row))
|
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for row, point in zip(self._rows, self._points):
|
for point in self._points:
|
||||||
self._profile.insert_point(row, point)
|
point.set_as_not_deleted()
|
||||||
self._profile.modified()
|
self._profile.modified()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
self._profile.delete_i(self._rows)
|
self._profile.delete_points(self._points)
|
||||||
self._profile.modified()
|
self._profile.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -206,16 +202,17 @@ class PurgeCommand(QUndoCommand):
|
||||||
def __init__(self, profile, np_purge):
|
def __init__(self, profile, np_purge):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
|
self._deleted = []
|
||||||
self._profile = profile
|
self._profile = profile
|
||||||
self._old = self._profile.points.copy()
|
|
||||||
self._np_purge = np_purge
|
self._np_purge = np_purge
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
self._profile._points = self._old.copy()
|
for point in self._deleted:
|
||||||
|
point.set_as_not_deleted()
|
||||||
self._profile.modified()
|
self._profile.modified()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
self._profile.purge(self._np_purge)
|
self._deleted = self._profile.purge(self._np_purge)
|
||||||
self._profile.modified()
|
self._profile.modified()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -230,8 +227,7 @@ class PasteCommand(QUndoCommand):
|
||||||
self._points.reverse()
|
self._points.reverse()
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for ind in range(len(self._points)):
|
self._profile.delete_points(self._points)
|
||||||
self._profile.delete_i([self._row])
|
|
||||||
self._profile.modified()
|
self._profile.modified()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
|
|
|
||||||
|
|
@ -277,18 +277,17 @@ class PurgeCommand(QUndoCommand):
|
||||||
|
|
||||||
self._reach = reach
|
self._reach = reach
|
||||||
self._np_purge = np_purge
|
self._np_purge = np_purge
|
||||||
|
self._deleted = {}
|
||||||
self._old = []
|
|
||||||
for profile in self._reach.profiles:
|
|
||||||
self._old.append(profile.points.copy())
|
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for i in range(self._reach.number_profiles):
|
for profile in self._deleted:
|
||||||
self._reach.profiles[i]._points = self._old[i].copy()
|
for point in self._deleted[profile]:
|
||||||
|
point.set_as_not_deleted()
|
||||||
|
profile.modified()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
for profile in self._reach._profiles:
|
for profile in self._reach._profiles:
|
||||||
profile.purge(self._np_purge)
|
self._deleted[profile] = profile.purge(self._np_purge)
|
||||||
|
|
||||||
|
|
||||||
class ChangeReachCommand(QUndoCommand):
|
class ChangeReachCommand(QUndoCommand):
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,19 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
def _setup_lst(self):
|
def _setup_lst(self):
|
||||||
self._lst = self._data.river.initial_conditions.get(self._reach)
|
self._lst = self._data.river.initial_conditions.get(self._reach)
|
||||||
|
|
||||||
|
def get_true_data_row(self, row):
|
||||||
|
data = self._lst.get(row)
|
||||||
|
|
||||||
|
return next(
|
||||||
|
map(
|
||||||
|
lambda e: e[0],
|
||||||
|
filter(
|
||||||
|
lambda e: e[1] == data,
|
||||||
|
enumerate(self._lst._data)
|
||||||
|
)
|
||||||
|
), 0
|
||||||
|
)
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
if role != Qt.ItemDataRole.DisplayRole:
|
if role != Qt.ItemDataRole.DisplayRole:
|
||||||
return QVariant()
|
return QVariant()
|
||||||
|
|
@ -122,8 +135,11 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
return f"{velocity:.4f}"
|
return f"{velocity:.4f}"
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
if self._headers[column] == "rk":
|
if self._headers[column] == "rk":
|
||||||
p = self._lst.get(row)[self._headers[column]]
|
p = self._lst.get(row)[self._headers[column]]
|
||||||
|
if p is None:
|
||||||
|
return ""
|
||||||
return f"{p.rk:.4f}"
|
return f"{p.rk:.4f}"
|
||||||
elif self._headers[column] not in ["name", "comment"]:
|
elif self._headers[column] not in ["name", "comment"]:
|
||||||
v = self._lst.get(row)[self._headers[column]]
|
v = self._lst.get(row)[self._headers[column]]
|
||||||
|
|
@ -157,6 +173,8 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
def add(self, row, parent=QModelIndex()):
|
def add(self, row, parent=QModelIndex()):
|
||||||
self.beginInsertRows(parent, row, row - 1)
|
self.beginInsertRows(parent, row, row - 1)
|
||||||
|
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
AddCommand(
|
AddCommand(
|
||||||
self._lst, row
|
self._lst, row
|
||||||
|
|
@ -171,7 +189,12 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
DelCommand(
|
DelCommand(
|
||||||
self._lst, rows
|
self._lst, list(
|
||||||
|
map(
|
||||||
|
lambda row: self._lst.get(row),
|
||||||
|
rows
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -194,10 +217,11 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
if row <= 0:
|
if row <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
target = row + 2
|
target = row + 1
|
||||||
|
|
||||||
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
self.beginMoveRows(parent, row - 1, row - 1, parent, target)
|
||||||
|
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._lst, "up", row
|
self._lst, "up", row
|
||||||
|
|
@ -215,6 +239,8 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
|
|
||||||
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
self.beginMoveRows(parent, row + 1, row + 1, parent, target)
|
||||||
|
|
||||||
|
row = self.get_true_data_row(row)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
MoveCommand(
|
MoveCommand(
|
||||||
self._lst, "down", row
|
self._lst, "down", row
|
||||||
|
|
@ -239,6 +265,8 @@ class InitialConditionTableModel(PamhyrTableModel):
|
||||||
|
|
||||||
self.layoutAboutToBeChanged.emit()
|
self.layoutAboutToBeChanged.emit()
|
||||||
|
|
||||||
|
index = self.get_true_data_row(index)
|
||||||
|
|
||||||
self._undo.push(
|
self._undo.push(
|
||||||
InsertCommand(
|
InsertCommand(
|
||||||
self._lst, index,
|
self._lst, index,
|
||||||
|
|
|
||||||
|
|
@ -75,23 +75,18 @@ class AddCommand(QUndoCommand):
|
||||||
|
|
||||||
|
|
||||||
class DelCommand(QUndoCommand):
|
class DelCommand(QUndoCommand):
|
||||||
def __init__(self, ics, rows):
|
def __init__(self, ics, data):
|
||||||
QUndoCommand.__init__(self)
|
QUndoCommand.__init__(self)
|
||||||
|
|
||||||
self._ics = ics
|
self._ics = ics
|
||||||
self._rows = rows
|
self._data = data
|
||||||
|
|
||||||
self._ic = []
|
|
||||||
for row in rows:
|
|
||||||
self._ic.append((row, self._ics.get(row)))
|
|
||||||
self._ic.sort()
|
|
||||||
|
|
||||||
def undo(self):
|
def undo(self):
|
||||||
for row, el in self._ic:
|
for ic in self._data:
|
||||||
self._ics.insert(row, el)
|
ic.set_as_not_deleted()
|
||||||
|
|
||||||
def redo(self):
|
def redo(self):
|
||||||
self._ics.delete_i(self._rows)
|
self._ics.delete(self._data)
|
||||||
|
|
||||||
|
|
||||||
class SortCommand(QUndoCommand):
|
class SortCommand(QUndoCommand):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue