Geometry: Add scenario support.

scenarios
Pierre-Antoine Rouby 2024-09-20 16:10:00 +02:00
parent 02c6430ed2
commit 4199eb6ac5
6 changed files with 133 additions and 114 deletions

View File

@ -203,7 +203,7 @@ class PointXYZ(Point, SQLSubModel):
owner_scenario=owner_scenario owner_scenario=owner_scenario
) )
if deleted: if deleted:
nd.set_as_deleted() new.set_as_deleted()
if sl == -1 or sl is None: if sl == -1 or sl is None:
new._sl = None new._sl = None

View File

@ -32,10 +32,11 @@ class Profile(object):
rk: float = 0.0, name: str = "", rk: float = 0.0, name: str = "",
code1: int = 0, code2: int = 0, code1: int = 0, code2: int = 0,
_type: str = "", reach=None, _type: str = "", reach=None,
status=None): status=None, owner_scenario=-1):
super(Profile, self).__init__(id) super(Profile, self).__init__(
id=id, status=status,
self._status = status owner_scenario=owner_scenario
)
self._num = int(num) self._num = int(num)
self._code1 = int(code1) self._code1 = int(code1)
@ -64,7 +65,12 @@ class Profile(object):
if not isinstance(self._points, list): if not isinstance(self._points, list):
self._points = self._get_points_list() self._points = self._get_points_list()
return self._points return list(
filter(
lambda p: not p.is_deleted(),
self._points
)
)
def point(self, index): def point(self, index):
return self.points[index] return self.points[index]
@ -84,7 +90,7 @@ class Profile(object):
@num.setter @num.setter
def num(self, value: int): def num(self, value: int):
self._num = int(value) self._num = int(value)
self._status.modified() self.modified()
@property @property
def code1(self): def code1(self):
@ -97,7 +103,7 @@ class Profile(object):
@code1.setter @code1.setter
def code1(self, value: int): def code1(self, value: int):
self._code1 = int(value) self._code1 = int(value)
self._status.modified() self.modified()
@property @property
def code2(self): def code2(self):
@ -110,7 +116,7 @@ class Profile(object):
@code2.setter @code2.setter
def code2(self, value: int): def code2(self, value: int):
self._code2 = int(value) self._code2 = int(value)
self._status.modified() self.modified()
@property @property
def nb_points(self): def nb_points(self):
@ -127,7 +133,7 @@ class Profile(object):
@rk.setter @rk.setter
def rk(self, value: float): def rk(self, value: float):
self._rk = float(value) self._rk = float(value)
self._status.modified() self.modified()
@property @property
def name(self): def name(self):
@ -140,7 +146,7 @@ class Profile(object):
@name.setter @name.setter
def name(self, value: str): def name(self, value: str):
self._name = value.strip() self._name = value.strip()
self._status.modified() self.modified()
@property @property
def sl(self): def sl(self):
@ -153,7 +159,7 @@ class Profile(object):
@sl.setter @sl.setter
def sl(self, value): def sl(self, value):
self._sl = value self._sl = value
self._status.modified() self.modified()
@property @property
def profile_type(self): def profile_type(self):
@ -166,7 +172,7 @@ class Profile(object):
@profile_type.setter @profile_type.setter
def profile_type(self, value: str): def profile_type(self, value: str):
self._profile_type = value self._profile_type = value
self._status.modified() self.modified()
def point(self, i: int): def point(self, i: int):
if i < len(self.points): if i < len(self.points):
@ -193,21 +199,25 @@ class Profile(object):
Returns: Returns:
Nothing. Nothing.
""" """
self.points.insert(index, point) if point in self._points:
self._status.modified() point.set_as_not_deleted()
else:
self.points.insert(index, point)
self.modified()
def delete_i(self, indexes: list): def delete_i(self, indexes: list):
self._points = list( list(
map( map(
lambda e: e[1], lambda e: e[1].set_as_deleted(),
filter( filter(
lambda e: e[0] not in indexes, lambda e: e[0] in indexes,
enumerate(self.points) enumerate(self.points)
) )
) )
) )
self._status.modified() self.modified()
def delete_points(self, points): def delete_points(self, points):
"""Delete some elements in profile list """Delete some elements in profile list
@ -218,13 +228,13 @@ class Profile(object):
Returns: Returns:
Nothing. Nothing.
""" """
self._points = list( list(
filter( map(
lambda p: p not in points, lambda p: p.set_as_deleted(),
self.points points
) )
) )
self._status.modified() self.modified()
# Move # Move
@ -234,7 +244,7 @@ class Profile(object):
p = self.points p = self.points
p[index], p[next] = p[next], p[index] p[index], p[next] = p[next], p[index]
self._status.modified() self.modified()
def move_down_point(self, index: int): def move_down_point(self, index: int):
if index >= 0: if index >= 0:
@ -242,7 +252,7 @@ class Profile(object):
p = self.points p = self.points
p[index], p[prev] = p[prev], p[index] p[index], p[prev] = p[prev], p[index]
self._status.modified() self.modified()
# Sort # Sort
@ -259,7 +269,7 @@ class Profile(object):
key=predicate, key=predicate,
reverse=is_reversed reverse=is_reversed
) )
self._status.modified() self.modified()
@timer @timer
def sort_with_indexes(self, indexes: list): def sort_with_indexes(self, indexes: list):
@ -275,12 +285,12 @@ class Profile(object):
) )
) )
) )
self._status.modified() self.modified()
@timer @timer
def reverse(self): def reverse(self):
self._points.reverse() self._points.reverse()
self._status.modified() self.modified()
# Sediment Layers # Sediment Layers

View File

@ -47,7 +47,7 @@ class ProfileXYZ(Profile, SQLSubModel):
num=0, num=0,
nb_point: int = 0, nb_point: int = 0,
code1: int = 0, code2: int = 0, code1: int = 0, code2: int = 0,
status=None): status=None, owner_scenario=-1):
"""ProfileXYZ constructor """ProfileXYZ constructor
Args: Args:
@ -69,6 +69,7 @@ class ProfileXYZ(Profile, SQLSubModel):
_type="XYZ", _type="XYZ",
reach=reach, reach=reach,
status=status, status=status,
owner_scenario=owner_scenario
) )
@classmethod @classmethod
@ -76,6 +77,7 @@ class ProfileXYZ(Profile, SQLSubModel):
execute(f""" execute(f"""
CREATE TABLE geometry_profileXYZ{ext} ( CREATE TABLE geometry_profileXYZ{ext} (
{cls.create_db_add_pamhyr_id()}, {cls.create_db_add_pamhyr_id()},
deleted BOOLEAN NOT NULL DEFAULT FALSE,
ind INTEGER NOT NULL, ind INTEGER NOT NULL,
name TEXT, name TEXT,
reach INTEGER NOT NULL, reach INTEGER NOT NULL,
@ -121,6 +123,13 @@ class ProfileXYZ(Profile, SQLSubModel):
cls._db_update_to_0_1_0(execute, data) cls._db_update_to_0_1_0(execute, data)
if major == "0" and minor == "1":
if int(release) < 2:
execute(
"ALTER TABLE geometry_profileXYZ " +
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
)
return cls._update_submodel(execute, version, data) return cls._update_submodel(execute, version, data)
@classmethod @classmethod
@ -194,35 +203,47 @@ class ProfileXYZ(Profile, SQLSubModel):
@classmethod @classmethod
def _db_load(cls, execute, data=None): def _db_load(cls, execute, data=None):
profiles = []
status = data["status"] status = data["status"]
scenario = data["scenario"]
loaded = data['loaded_pid']
reach = data["reach"] reach = data["reach"]
if scenario is None:
return
table = execute( table = execute(
"SELECT pamhyr_id, name, rk, num, code1, code2, sl " + "SELECT pamhyr_id, deleted, name, rk, num, " +
"code1, code2, sl, scenario " +
"FROM geometry_profileXYZ " + "FROM geometry_profileXYZ " +
f"WHERE reach = {reach.id} " + f"WHERE reach = {reach.id} " +
f"AND scenario = {scenario.id} " +
f"AND pamhyr_id NOT IN ({', '.join(map(str, loaded))}) " +
"ORDER BY ind ASC" "ORDER BY ind ASC"
) )
for row in table: for row in table:
it = iter(row) it = iter(row)
id = next(it) pid = next(it)
deleted = (next(it) == 1)
name = next(it) name = next(it)
rk = next(it) rk = next(it)
num = next(it) num = next(it)
code1 = next(it) code1 = next(it)
code2 = next(it) code2 = next(it)
sl = next(it) sl = next(it)
owner_scenario = next(it)
new = cls( new = cls(
id=id, num=num, id=pid, num=num,
name=name, rk=rk, name=name, rk=rk,
code1=code1, code2=code2, code1=code1, code2=code2,
reach=reach, reach=reach,
status=status status=status,
owner_scenario=owner_scenario
) )
if deleted:
new.set_as_deleted()
if sl == -1 or sl is None: if sl == -1 or sl is None:
new._sl = None new._sl = None
@ -237,9 +258,17 @@ class ProfileXYZ(Profile, SQLSubModel):
data["profile"] = new data["profile"] = new
new._points = PointXYZ._db_load(execute, data.copy()) new._points = PointXYZ._db_load(execute, data.copy())
loaded.add(pid)
yield new yield new
data["scenario"] = scenario.parent
yield from cls._db_load(execute, data)
data["scenario"] = scenario
def _db_save(self, execute, data=None): def _db_save(self, execute, data=None):
if not self.must_be_saved():
return True
ok = True ok = True
ind = data["ind"] ind = data["ind"]
@ -247,25 +276,25 @@ class ProfileXYZ(Profile, SQLSubModel):
execute( execute(
"INSERT OR REPLACE INTO " + "INSERT OR REPLACE INTO " +
"geometry_profileXYZ(pamhyr_id, ind, name, reach, " + "geometry_profileXYZ(pamhyr_id, deleted, ind, name, reach, " +
"rk, num, code1, code2, sl) " + "rk, num, code1, code2, sl, scenario) " +
"VALUES (" + "VALUES (" +
f"{self.pamhyr_id}, {ind}, '{self._db_format(self._name)}', " + f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
f"{ind}, '{self._db_format(self._name)}', " +
f"{self.reach.pamhyr_id}, {self.rk}, {self.num}, " + f"{self.reach.pamhyr_id}, {self.rk}, {self.num}, " +
f"{self.code1}, {self.code1}, {sl}" + f"{self.code1}, {self.code1}, {sl}, {self._status.scenario_id}" +
")" ")"
) )
points = self.points
data["profile"] = self data["profile"] = self
execute( execute(
"DELETE FROM geometry_pointXYZ " + "DELETE FROM geometry_pointXYZ " +
f"WHERE profile = {self.pamhyr_id}" f"WHERE profile = {self.pamhyr_id} " +
f"AND scenario = {self._status.scenario_id}"
) )
ind = 0 ind = 0
for point in points: for point in self._points:
data["ind"] = ind data["ind"] = ind
ok &= point._db_save(execute, data) ok &= point._db_save(execute, data)
ind += 1 ind += 1
@ -380,7 +409,7 @@ class ProfileXYZ(Profile, SQLSubModel):
for point in list_points: for point in list_points:
pt = PointXYZ(*point, profile=self, status=self._status) pt = PointXYZ(*point, profile=self, status=self._status)
self.points.append(pt) self.points.append(pt)
self._status.modified() self.modified()
def get_point_i(self, index: int) -> PointXYZ: def get_point_i(self, index: int) -> PointXYZ:
"""Get point at index. """Get point at index.
@ -441,7 +470,7 @@ class ProfileXYZ(Profile, SQLSubModel):
""" """
point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status) point_xyz = PointXYZ(0., 0., 0., profile=self, status=self._status)
self.points.append(point_xyz) self.points.append(point_xyz)
self._status.modified() self.modified()
def insert(self, index: int): def insert(self, index: int):
"""Insert a new point at index. """Insert a new point at index.
@ -454,7 +483,7 @@ class ProfileXYZ(Profile, SQLSubModel):
""" """
point = PointXYZ(0., 0., 0., profile=self, status=self._status) point = PointXYZ(0., 0., 0., profile=self, status=self._status)
self.points.insert(index, point) self.points.insert(index, point)
self._status.modified() self.modified()
return point return point
def filter_isnan(self, lst): def filter_isnan(self, lst):

View File

@ -80,15 +80,14 @@ class Reach(SQLSubModel):
return new return new
def _db_save(self, execute, data=None): def _db_save(self, execute, data=None):
profiles = self.profiles
execute( execute(
"DELETE FROM geometry_profileXYZ " + "DELETE FROM geometry_profileXYZ " +
f"WHERE reach = {self.pamhyr_id}" f"WHERE reach = {self.pamhyr_id} " +
f"AND scenario = {self._status.scenario_id}"
) )
ind = 0 ind = 0
for profile in profiles: for profile in self._profiles:
data["ind"] = ind data["ind"] = ind
profile._db_save(execute, data) profile._db_save(execute, data)
ind += 1 ind += 1
@ -121,17 +120,14 @@ class Reach(SQLSubModel):
return list(self._profiles) return list(self._profiles)
def __len__(self): def __len__(self):
if not isinstance(self._profiles, list): return len(self.profiles)
self._profiles = self._get_profiles_list()
return len(self._profiles)
@property @property
def profiles(self): def profiles(self):
if not isinstance(self._profiles, list): if not isinstance(self._profiles, list):
self._profiles = self._get_profiles_list() self._profiles = self._get_profiles_list()
return self._profiles return list(filter(lambda p: not p.is_deleted(), self._profiles))
@profiles.setter @profiles.setter
def profiles(self, profiles): def profiles(self, profiles):
@ -159,15 +155,6 @@ class Reach(SQLSubModel):
""" """
return self.profiles return self.profiles
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): def insert(self, index: int):
"""Insert new profile in list """Insert new profile in list
@ -180,9 +167,8 @@ class Reach(SQLSubModel):
profile = ProfileXYZ(reach=self, status=self._status) profile = ProfileXYZ(reach=self, status=self._status)
self.profiles.insert(index, profile) self.profiles.insert(index, profile)
self._update_profile_numbers()
self._status.modified() self.modified()
return profile return profile
@ -195,9 +181,12 @@ class Reach(SQLSubModel):
Returns: Returns:
Nothing. Nothing.
""" """
self.profiles.insert(index, profile) if profile in self._profiles:
self._update_profile_numbers() self.undelete([profile])
self._status.modified() else:
self.profiles.insert(index, profile)
self.modified()
def delete(self, indexes): def delete(self, indexes):
"""Delete some elements in profile list """Delete some elements in profile list
@ -208,24 +197,16 @@ class Reach(SQLSubModel):
Returns: Returns:
Nothing. Nothing.
""" """
profiles = set( list(
map( map(
lambda e: e[1], lambda p: p[1].set_as_deleted(),
filter( filter(
lambda e: e[0] in indexes, lambda e: e[0] in indexes,
enumerate(self.profiles) enumerate(self.profiles)
) )
) )
) )
self.modified()
self._profiles = list(
filter(
lambda p: p not in profiles,
self.profiles
)
)
self._update_profile_numbers()
self._status.modified()
def delete_profiles(self, profiles): def delete_profiles(self, profiles):
"""Delete some elements in profile list """Delete some elements in profile list
@ -236,19 +217,24 @@ class Reach(SQLSubModel):
Returns: Returns:
Nothing. Nothing.
""" """
self._profiles = list( list(
filter( map(
lambda p: p not in profiles, lambda p: p.set_as_deleted(),
self.profiles profiles
) )
) )
self._update_profile_numbers() self.modified()
self._status.modified()
def undelete(self, lst):
for el in lst:
el.set_as_not_deleted()
self.modified()
def purge(self): def purge(self):
self._profiles = [] for el in self._profiles:
self._update_profile_numbers() el.set_as_deleted()
self._status.modified() self.modified()
def move_up_profile(self, index: int): def move_up_profile(self, index: int):
if index < len(self.profiles): if index < len(self.profiles):
@ -256,7 +242,7 @@ class Reach(SQLSubModel):
p = self.profiles p = self.profiles
p[index], p[next] = p[next], p[index] p[index], p[next] = p[next], p[index]
self._status.modified() self.modified()
def move_down_profile(self, index: int): def move_down_profile(self, index: int):
if index >= 0: if index >= 0:
@ -264,7 +250,7 @@ class Reach(SQLSubModel):
p = self.profiles p = self.profiles
p[index], p[prev] = p[prev], p[index] p[index], p[prev] = p[prev], p[index]
self._status.modified() self.modified()
def get_x(self): def get_x(self):
return list( return list(
@ -489,7 +475,7 @@ class Reach(SQLSubModel):
self._compute_guidelines_cache(guide_set, named_points, self._compute_guidelines_cache(guide_set, named_points,
complete, incomplete) complete, incomplete)
self._status.modified() self.modified()
return (complete, incomplete) return (complete, incomplete)
def _map_guidelines_points(self, func, full=False): def _map_guidelines_points(self, func, full=False):
@ -535,7 +521,7 @@ class Reach(SQLSubModel):
key=lambda profile: profile.rk, key=lambda profile: profile.rk,
reverse=is_reversed reverse=is_reversed
) )
self._status.modified() self.modified()
@timer @timer
def sort_with_indexes(self, indexes: list): def sort_with_indexes(self, indexes: list):
@ -551,7 +537,7 @@ class Reach(SQLSubModel):
) )
) )
) )
self._status.modified() self.modified()
# Import/Export # Import/Export
@ -608,7 +594,6 @@ class Reach(SQLSubModel):
profiles.append(prof) profiles.append(prof)
self.profiles = profiles + self.profiles self.profiles = profiles + self.profiles
self._update_profile_numbers()
self._recompute_rk() self._recompute_rk()
return profiles return profiles
@ -643,7 +628,7 @@ class Reach(SQLSubModel):
prof.import_points(profile) prof.import_points(profile)
imported_profiles.append(prof) imported_profiles.append(prof)
self._status.modified() self.modified()
except FileNotFoundError as e: except FileNotFoundError as e:
logger.error(e) logger.error(e)
exception_message_box(e) exception_message_box(e)
@ -653,7 +638,6 @@ class Reach(SQLSubModel):
finally: finally:
self.profiles = imported_profiles + self.profiles self.profiles = imported_profiles + self.profiles
self._update_profile_numbers()
return imported_profiles return imported_profiles
@timer @timer

View File

@ -93,7 +93,7 @@ class AddCommand(QUndoCommand):
self._point = None self._point = None
def undo(self): def undo(self):
self._profile.delete_i([self._index]) self._profile.delete_point([self._point])
def redo(self): def redo(self):
if self._point is None: if self._point is None:
@ -111,15 +111,13 @@ class DelCommand(QUndoCommand):
self._points = [] self._points = []
for row in rows: for row in rows:
self._points.append((row, self._profile.point(row))) self._points.append(self._profile.point(row))
self._points.sort() # Sort by row index
def undo(self): def undo(self):
for row, point in self._points: self._profile.undelete(self._points)
self._profile.insert_point(row, point)
def redo(self): def redo(self):
self._profile.delete_i(self._rows) self._profile.delete(self._points)
class SortCommand(QUndoCommand): class SortCommand(QUndoCommand):

View File

@ -95,15 +95,13 @@ class DelCommand(QUndoCommand):
self._profiles = [] self._profiles = []
for row in rows: for row in rows:
self._profiles.append((row, self._reach.profile(row))) self._profiles.append(self._reach.profile(row))
self._profiles.sort()
def undo(self): def undo(self):
for row, profile in self._profiles: self._reach.undelete(self._profiles)
self._reach.insert_profile(row, profile)
def redo(self): def redo(self):
self._reach.delete(self._rows) self._reach.delete_profiles(self._profiles)
class SortCommand(QUndoCommand): class SortCommand(QUndoCommand):
@ -300,13 +298,13 @@ class ShiftCommand(QUndoCommand):
def undo(self): def undo(self):
for i in self._rows: for i in self._rows:
profile = self._reach.profiles[i] profile = self._reach.profiles[i]
self._reach.profiles[i].shift(-self._dx, self._reach.profiles[i].shift(
-self._dy, -self._dx, -self._dy, -self._dz
-self._dz) )
def redo(self): def redo(self):
for i in self._rows: for i in self._rows:
profile = self._reach.profiles[i] profile = self._reach.profiles[i]
self._reach.profiles[i].shift(self._dx, self._reach.profiles[i].shift(
self._dy, self._dx, self._dy, self._dz
self._dz) )