Merge branch 'mesh_tab' into dev_dylan

new_design_pol
Dylan Jeannin 2026-08-31 10:26:20 +02:00
commit 68e4dfb598
23 changed files with 672 additions and 86 deletions

View File

@ -229,7 +229,11 @@ for each reach"
gls = [] gls = []
for edge in edges: for edge in edges:
comp, incomp = edge.reach.compute_guidelines() profiles = edge.reach.enabled_profiles
comp, incomp = edge.reach.compute_guidelines(
profiles=profiles,
update_cache=False
)
if len(incomp) != 0: if len(incomp) != 0:
self._status = STATUS.WARNING self._status = STATUS.WARNING
self._summary = "incomplete_guideline" self._summary = "incomplete_guideline"
@ -237,7 +241,6 @@ for each reach"
gls.append(comp) gls.append(comp)
profiles = edge.reach.profiles
for profile in profiles: for profile in profiles:
if not profile.has_standard_named_points(): if not profile.has_standard_named_points():
self._status = STATUS.WARNING self._status = STATUS.WARNING

View File

@ -87,7 +87,7 @@ class StudyGeometryChecker(AbstractModelChecker):
return False return False
for edge in edges: for edge in edges:
if len(edge.reach.profiles) < 2: if len(edge.reach.enabled_profiles) < 2:
summary = "no_geometry_defined" summary = "no_geometry_defined"
status = STATUS.ERROR status = STATUS.ERROR
ok = False ok = False
@ -132,8 +132,12 @@ class StudyInitialConditionsChecker(AbstractModelChecker):
return ok return ok
ic = river.initial_conditions[reach] ic = river.initial_conditions[reach]
len_ic = len(ic) enabled_profiles = set(reach.enabled_profiles)
len_reach = len(reach) len_ic = sum(
data["section"] in enabled_profiles
for data in ic.data
)
len_reach = len(enabled_profiles)
if len_ic < len_reach: if len_ic < len_reach:
self._summary = "initial_condition_missing_profile" self._summary = "initial_condition_missing_profile"

View File

@ -58,7 +58,8 @@ 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, owner_scenario=-1): status=None, owner_scenario=-1,
enabled=True):
"""ProfileXYZ constructor """ProfileXYZ constructor
Args: Args:
@ -90,6 +91,7 @@ class ProfileXYZ(Profile, SQLSubModel):
self.time_l = 0.0 self.time_l = 0.0
self._station = [] self._station = []
self.station_up_to_date = False self.station_up_to_date = False
self._enabled = bool(enabled)
self._get_water_limits_cache = {} self._get_water_limits_cache = {}
self._get_water_limits_ac_cache = {} self._get_water_limits_ac_cache = {}
@ -108,6 +110,7 @@ class ProfileXYZ(Profile, SQLSubModel):
code1 INTEGER NOT NULL, code1 INTEGER NOT NULL,
code2 INTEGER NOT NULL, code2 INTEGER NOT NULL,
sl INTEGER, sl INTEGER,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
{Scenario.create_db_add_scenario()}, {Scenario.create_db_add_scenario()},
{Scenario.create_db_add_scenario_fk()}, {Scenario.create_db_add_scenario_fk()},
FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id), FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id),
@ -152,6 +155,13 @@ class ProfileXYZ(Profile, SQLSubModel):
"ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE" "ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE"
) )
if major == "0" and int(minor) <= 2:
if int(release) < 9:
execute(
"ALTER TABLE geometry_profileXYZ " +
"ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT TRUE"
)
return cls._update_submodel(execute, version, data) return cls._update_submodel(execute, version, data)
@classmethod @classmethod
@ -237,7 +247,7 @@ class ProfileXYZ(Profile, SQLSubModel):
table = execute( table = execute(
"SELECT pamhyr_id, ind, deleted, name, rk, num, " + "SELECT pamhyr_id, ind, deleted, name, rk, num, " +
"code1, code2, sl, scenario " + "code1, code2, sl, scenario, enabled " +
"FROM geometry_profileXYZ " + "FROM geometry_profileXYZ " +
f"WHERE reach = {reach.id} " + f"WHERE reach = {reach.id} " +
f"AND scenario = {scenario.id} " + f"AND scenario = {scenario.id} " +
@ -258,6 +268,7 @@ class ProfileXYZ(Profile, SQLSubModel):
code2 = next(it) code2 = next(it)
sl = next(it) sl = next(it)
owner_scenario = next(it) owner_scenario = next(it)
enabled = (next(it) == 1)
profile = cls( profile = cls(
id=pid, ind=ind, num=num, id=pid, ind=ind, num=num,
@ -265,7 +276,8 @@ class ProfileXYZ(Profile, SQLSubModel):
code1=code1, code2=code2, code1=code1, code2=code2,
reach=reach, reach=reach,
status=status, status=status,
owner_scenario=owner_scenario owner_scenario=owner_scenario,
enabled=enabled
) )
if deleted: if deleted:
profile.set_as_deleted() profile.set_as_deleted()
@ -318,12 +330,13 @@ class ProfileXYZ(Profile, SQLSubModel):
execute( execute(
"INSERT OR REPLACE INTO " + "INSERT OR REPLACE INTO " +
"geometry_profileXYZ(pamhyr_id, deleted, ind, name, reach, " + "geometry_profileXYZ(pamhyr_id, deleted, ind, name, reach, " +
"rk, num, code1, code2, sl, scenario) " + "rk, num, code1, code2, sl, scenario, enabled) " +
"VALUES (" + "VALUES (" +
f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " + f"{self.pamhyr_id}, {self._db_format(self.is_deleted())}, " +
f"{ind}, '{self._db_format(self._name)}', " + 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}, {self._status.scenario_id}" + f"{self.code1}, {self.code1}, {sl}, {self._status.scenario_id}, " +
f"{self._db_format(self._enabled)}" +
")" ")"
) )
@ -390,7 +403,8 @@ class ProfileXYZ(Profile, SQLSubModel):
name=self.name, name=self.name,
rk=self.rk, rk=self.rk,
reach=self.reach, reach=self.reach,
status=self._status status=self._status,
enabled=self.is_enabled
) )
if self.is_deleted(): if self.is_deleted():
new_p.set_as_deleted() new_p.set_as_deleted()
@ -410,7 +424,8 @@ class ProfileXYZ(Profile, SQLSubModel):
name=self.name, name=self.name,
rk=self.rk, rk=self.rk,
reach=new_reach, reach=new_reach,
status=self._status status=self._status,
enabled=self.is_enabled
) )
if self.is_deleted(): if self.is_deleted():
new_p.set_as_deleted() new_p.set_as_deleted()
@ -1131,7 +1146,8 @@ class ProfileXYZ(Profile, SQLSubModel):
p = ProfileXYZ(name=self.name, p = ProfileXYZ(name=self.name,
rk=self.rk, rk=self.rk,
reach=self.reach, reach=self.reach,
status=self._status) status=self._status,
enabled=self.is_enabled)
for i, k in enumerate(self.points): for i, k in enumerate(self.points):
p.insert_point(i, k.copy()) p.insert_point(i, k.copy())
@ -1165,3 +1181,16 @@ class ProfileXYZ(Profile, SQLSubModel):
break break
self._points = points self._points = points
self.modified() self.modified()
@property
def is_enabled(self):
return self._enabled
@property
def enabled(self):
return self._enabled
@enabled.setter
def enabled(self, value):
self._enabled = bool(value)
self.modified()

View File

@ -157,6 +157,14 @@ class Reach(SQLSubModel):
def profiles(self, profiles): def profiles(self, profiles):
self._profiles = profiles self._profiles = profiles
@property
def enabled_profiles(self):
return list(filter(lambda p: p.is_enabled, self.profiles))
@property
def number_enabled_profiles(self):
return len(self.enabled_profiles)
def get_profiles_from_rk(self, rk): def get_profiles_from_rk(self, rk):
return list( return list(
filter( filter(
@ -367,6 +375,28 @@ class Reach(SQLSubModel):
) )
) )
def get_z_min_enabled_profiles(self):
return list(
map(
lambda profile: profile.z_min(),
filter(
lambda profile: len(profile) > 0 and profile.is_enabled,
self.profiles
)
)
)
def get_z_max_enabled_profiles(self):
return list(
map(
lambda profile: profile.z_max(),
filter(
lambda profile: len(profile) > 0 and profile.is_enabled,
self.profiles
)
)
)
def get_rk(self): def get_rk(self):
"""List of profiles rk """List of profiles rk
@ -375,6 +405,17 @@ class Reach(SQLSubModel):
""" """
return [profile.rk for profile in self.profiles] return [profile.rk for profile in self.profiles]
def get_rk_enabled_profiles(self):
return list(
map(
lambda profile: profile.rk,
filter(
lambda profile: len(profile) > 0 and profile.is_enabled,
self.profiles
)
)
)
def get_rk_complete_profiles(self): def get_rk_complete_profiles(self):
return list( return list(
map( map(
@ -486,14 +527,22 @@ class Reach(SQLSubModel):
) )
@timer @timer
def compute_guidelines(self): def compute_guidelines(self, profiles=None, update_cache=True):
"""Compute reach guidelines """Compute reach guidelines
Args:
profiles: Profiles used to compute the guidelines. If omitted,
all non-deleted profiles of the reach are used.
update_cache: Whether to update the reach guidelines cache.
Returns: Returns:
Tuple of complete and incomplete guidelines name. Tuple of complete and incomplete guidelines name.
""" """
if profiles is None:
profiles = self.profiles
# Get all point contained into a guideline # Get all point contained into a guideline
named_points = [profile.named_points() for profile in self.profiles] named_points = [profile.named_points() for profile in profiles]
points_name = list( points_name = list(
map( map(
lambda lst: list(map(lambda p: p.name, lst)), lambda lst: list(map(lambda p: p.name, lst)),
@ -524,11 +573,13 @@ class Reach(SQLSubModel):
complete = guide_set - incomplete complete = guide_set - incomplete
# Compute guideline and put data in cache if update_cache:
self._compute_guidelines_cache(guide_set, named_points, # Compute guideline and put data in cache
complete, incomplete) self._compute_guidelines_cache(
guide_set, named_points, complete, incomplete
)
self.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):

View File

@ -167,7 +167,11 @@ class InitialConditionsTemperature(SQLSubModel):
return True return True
def __len__(self): def __len__(self):
return len(self._data) return len(self.data)
@property
def data(self):
return list(filter(lambda item: not item.is_deleted(), self._data))
@property @property
def name(self): def name(self):

View File

@ -522,7 +522,7 @@ class Results(SQLSubModel):
i = 0 i = 0
for reach in new_results._river.reachs: for reach in new_results._river.reachs:
nb = len(reach.profiles) nb = len(reach.profiles)
reach.set_global_index(range(i, i + nb + 1)) reach.set_global_index(range(i, i + nb))
i += nb i += nb
if "Z" in table_data: if "Z" in table_data:

View File

@ -154,6 +154,7 @@ class Profile(SQLSubModel):
"len_data, data, scenario " + "len_data, data, scenario " +
"FROM results_data " + "FROM results_data " +
f"WHERE scenario = {scenario.id} " + f"WHERE scenario = {scenario.id} " +
f"AND result = {data['result_pid']} " +
f"AND reach = {reach.pamhyr_id} " + f"AND reach = {reach.pamhyr_id} " +
f"AND section = {profile.pamhyr_id}" f"AND section = {profile.pamhyr_id}"
) )
@ -276,7 +277,7 @@ class Profile(SQLSubModel):
class Reach(SQLSubModel): class Reach(SQLSubModel):
_sub_classes = [Profile] _sub_classes = [Profile]
def __init__(self, reach, study, parent, with_init=True): def __init__(self, reach, study, parent, with_init=True, profiles=None):
super(Reach, self).__init__( super(Reach, self).__init__(
id=-1, status=study.status, id=-1, status=study.status,
owner_scenario=study.status.scenario.id owner_scenario=study.status.scenario.id
@ -287,10 +288,12 @@ class Reach(SQLSubModel):
self._reach = reach # Source reach in the study self._reach = reach # Source reach in the study
self._profiles = [] self._profiles = []
if with_init: if with_init:
if profiles is None:
profiles = reach.profiles
self._profiles = list( self._profiles = list(
map( map(
lambda p: Profile(p, self._study, self._parent), lambda p: Profile(p, self._study, self._parent),
reach.profiles profiles
) )
) )
@ -379,7 +382,14 @@ class Reach(SQLSubModel):
for i, profile in enumerate(reach.profiles): for i, profile in enumerate(reach.profiles):
data["profile"] = profile data["profile"] = profile
new_reach._profiles += [Profile._db_load(execute, data)] result_profile = Profile._db_load(execute, data)
if len(result_profile) > 0:
new_reach._profiles.append(result_profile)
new_reach._profile_mask = [
profile.name[0:8] != 'interpol'
for profile in new_reach._profiles
]
return new_reach return new_reach
@ -418,10 +428,13 @@ class River(SQLSubModel):
def has_reach(self, id): def has_reach(self, id):
return 0 <= id < len(self._reachs) return 0 <= id < len(self._reachs)
def add(self, reach_id): def add(self, reach_id, profiles=None):
reachs = self._study.river.enable_edges() reachs = self._study.river.enable_edges()
new = Reach(reachs[reach_id].reach, self._study, self._parent) new = Reach(
reachs[reach_id].reach, self._study, self._parent,
profiles=profiles
)
self._reachs.append(new) self._reachs.append(new)
return new return new
@ -460,9 +473,9 @@ class River(SQLSubModel):
for reach in study.river.reachs(): for reach in study.river.reachs():
data["reach"] = reach.reach data["reach"] = reach.reach
new_river._reachs.append( result_reach = Reach._db_load(execute, data)
Reach._db_load(execute, data) if len(result_reach) > 0:
) new_river._reachs.append(result_reach)
return new_river return new_river

View File

@ -907,6 +907,63 @@ Last export at: @date."""
def weather_parameters(self): def weather_parameters(self):
return self._WeatherParameters return self._WeatherParameters
def profile_dependencies(self, profile):
"""Return model data which directly reference *profile*.
PK-based intervals are deliberately not included: only explicit
references to the profile object prevent it from being disabled.
"""
dependencies = []
def add(kind, item, association):
dependencies.append({
"kind": kind,
"item": item,
"association": association,
})
for reach in list(self._initial_conditions._dict):
initial_conditions = self._initial_conditions.get(reach)
for data in initial_conditions.data:
if data["section"] is profile:
add("initial_condition", data, "section")
for structure in self._hydraulic_structures.lst:
if structure.input_section is profile:
add("hydraulic_structure", structure, "input_section")
if structure.output_section is profile:
add("hydraulic_structure", structure, "output_section")
for tab in self._lateral_contribution._tabs_list:
for contribution in self._lateral_contribution.get_tab(tab):
if contribution.begin_section is profile:
add("lateral_contribution", contribution, "begin_section")
if contribution.end_section is profile:
add("lateral_contribution", contribution, "end_section")
for parameter in self._WeatherParameters.lst:
if parameter.begin_section is profile:
add("weather_parameter", parameter, "begin_section")
if parameter.end_section is profile:
add("weather_parameter", parameter, "end_section")
reach_id = profile.reach.pamhyr_id
for initial_condition in self._InitialConditionsTemperature.lst:
for specification in initial_condition.data:
same_reach = specification.reach == reach_id
same_rk = (
specification.start_rk == profile.rk or
specification.end_rk == profile.rk
)
if same_reach and same_rk:
add(
"initial_condition_temperature",
specification,
"cross_section_pk",
)
return dependencies
def get_params(self, solver): def get_params(self, solver):
if solver in self._parameters: if solver in self._parameters:
return self._parameters[solver] return self._parameters[solver]

View File

@ -46,7 +46,7 @@ logger = logging.getLogger()
class Study(SQLModel): class Study(SQLModel):
_version = "0.2.7" _version = "0.2.9"
_sub_classes = [ _sub_classes = [
Scenario, Scenario,

View File

@ -180,7 +180,7 @@ class AdisTS(CommandLineSolver):
files.append(str(os.path.join("net", f"{name}.ST"))) files.append(str(os.path.join("net", f"{name}.ST")))
cnt_num = 1 cnt_num = 1
for profile in edge.reach.profiles: for profile in edge.reach.enabled_profiles:
self._export_ST_profile_header( self._export_ST_profile_header(
f, files, profile, cnt_num f, files, profile, cnt_num
) )
@ -335,7 +335,7 @@ class AdisTS(CommandLineSolver):
return coeff.minor, coeff.medium return coeff.minor, coeff.medium
for j, profile in enumerate(edge.reach.profiles): for j, profile in enumerate(edge.reach.enabled_profiles):
coef_min, coef_moy = get_stricklers_from_rk(profile.rk, coef_min, coef_moy = get_stricklers_from_rk(profile.rk,
lst) lst)
f.write( f.write(
@ -861,7 +861,10 @@ class AdisTSwc(AdisTS):
for i in range(ibmax): for i in range(ibmax):
# Add results reach to reach list # Add results reach to reach list
r = results.river.add(i) geometry_reach = study.river.enable_edges()[i].reach
r = results.river.add(
i, profiles=geometry_reach.enabled_profiles
)
reachs.append(r) reachs.append(r)
is1[i] = data[2 * i] - 1 # first section of reach i is1[i] = data[2 * i] - 1 # first section of reach i

View File

@ -187,7 +187,7 @@ class AdisTT(CommandLineSolver):
files.append(str(os.path.join("net", f"{name}.ST"))) files.append(str(os.path.join("net", f"{name}.ST")))
cnt_num = 1 cnt_num = 1
for profile in edge.reach.profiles: for profile in edge.reach.enabled_profiles:
self._export_ST_profile_header( self._export_ST_profile_header(
f, files, profile, cnt_num f, files, profile, cnt_num
) )
@ -310,7 +310,7 @@ class AdisTT(CommandLineSolver):
return coeff.minor, coeff.medium return coeff.minor, coeff.medium
for j, profile in enumerate(edge.reach.profiles): for j, profile in enumerate(edge.reach.enabled_profiles):
coef_min, coef_moy = get_stricklers_from_rk(profile.rk, coef_min, coef_moy = get_stricklers_from_rk(profile.rk,
lst) lst)
f.write( f.write(
@ -647,7 +647,10 @@ class AdisTTwc(AdisTT):
for i in range(ibmax): for i in range(ibmax):
# Add results reach to reach list # Add results reach to reach list
r = results.river.add(i) geometry_reach = study.river.enable_edges()[i].reach
r = results.river.add(
i, profiles=geometry_reach.enabled_profiles
)
reachs.append(r) reachs.append(r)
is1[i] = data[2 * i] - 1 # first section of reach i is1[i] = data[2 * i] - 1 # first section of reach i

View File

@ -224,7 +224,7 @@ class Mage(CommandLineSolver):
files.append(str(os.path.join("net", f"{name}.ST"))) files.append(str(os.path.join("net", f"{name}.ST")))
cnt_num = 1 cnt_num = 1
for profile in edge.reach.profiles: for profile in edge.reach.enabled_profiles:
self._export_ST_profile_header( self._export_ST_profile_header(
f, files, profile, cnt_num f, files, profile, cnt_num
) )
@ -489,7 +489,12 @@ class Mage(CommandLineSolver):
if cond.is_deleted(): if cond.is_deleted():
continue continue
data = cond.data enabled_profiles = set(reach.reach.enabled_profiles)
data = [
item for item in cond.data
if not item.is_deleted()
and item["section"] in enabled_profiles
]
if len(data) == 0: if len(data) == 0:
continue continue
@ -497,9 +502,6 @@ class Mage(CommandLineSolver):
id_sec = 1 id_sec = 1
for d in data: for d in data:
if d.is_deleted():
continue
IR = f"{id}" IR = f"{id}"
IS = f"{id_sec}" IS = f"{id_sec}"
discharge = f"{d['discharge']:>10.5f}" discharge = f"{d['discharge']:>10.5f}"
@ -1097,7 +1099,10 @@ class Mage8(Mage):
for i in range(nb_reach): for i in range(nb_reach):
# Add results reach to reach list # Add results reach to reach list
r = results.river.add(i) geometry_reach = study.river.enable_edges()[i].reach
r = results.river.add(
i, profiles=geometry_reach.enabled_profiles
)
reachs.append(r) reachs.append(r)
# ID of first and last reach profiles # ID of first and last reach profiles
@ -1402,7 +1407,10 @@ class Mage8(Mage):
zfd_lst = [] zfd_lst = []
for r in reachs: for r in reachs:
z_min = r.geometry.get_z_min() z_min = [
profile.geometry.z_min()
for profile in r.profiles
]
sls = map( sls = map(
lambda p: p.get_ts_key(ts_list[0], "sl")[0], lambda p: p.get_ts_key(ts_list[0], "sl")[0],
r.profiles r.profiles

View File

@ -128,6 +128,15 @@ class ProfileWindow(PamhyrWindow):
self._tablemodel.blockSignals(False) self._tablemodel.blockSignals(False)
def setup_connections(self): def setup_connections(self):
navigation_actions = {
"action_previous_profile": self.previous_profile,
"action_next_profile": self.next_profile,
}
for action in navigation_actions:
self.find(QAction, action)\
.triggered.connect(navigation_actions[action])
if self._study.is_read_only(): if self._study.is_read_only():
actions = {} actions = {}
else: else:
@ -152,6 +161,74 @@ class ProfileWindow(PamhyrWindow):
.connect(self.update_points_selection) .connect(self.update_points_selection)
self._tablemodel.dataChanged.connect(self.update) self._tablemodel.dataChanged.connect(self.update)
self.update_navigation_actions()
def previous_profile(self):
self.navigate_profile(-1)
def next_profile(self):
self.navigate_profile(1)
def profiles(self):
"""Return profiles from the geometry model owning this profile."""
return self._profile.reach.reach.profiles
def navigate_profile(self, offset):
profiles = self.profiles()
try:
index = profiles.index(self._profile)
except ValueError:
self.update_navigation_actions()
return
target_index = index + offset
if not 0 <= target_index < len(profiles):
self.update_navigation_actions()
return
target = profiles[target_index]
if self._parent is not None and self._parent.sub_window_exists(
ProfileWindow,
data=[self._study, self._config, target]
):
self.close()
return
self.set_profile(target)
def set_profile(self, profile):
self._profile = profile
self._hash_data[-1] = profile
self._undo_stack.clear()
self._tablemodel.beginResetModel()
self._tablemodel._data = profile
self._tablemodel._setup_lst()
self._tablemodel.endResetModel()
self._plot.data = profile
self._plot.highlight = None
self._plot.draw()
self._title = (
self._trad[self._pamhyr_name] +
f" - {profile.name} {profile.rk}"
)
self._set_title()
self.update_navigation_actions()
def update_navigation_actions(self):
profiles = self.profiles()
try:
index = profiles.index(self._profile)
except ValueError:
index = -1
self.find(QAction, "action_previous_profile")\
.setEnabled(index > 0)
self.find(QAction, "action_next_profile")\
.setEnabled(0 <= index < len(profiles) - 1)
def update_points_selection(self): def update_points_selection(self):
rows = self.index_selected_rows() rows = self.index_selected_rows()

View File

@ -64,15 +64,20 @@ class GeometryReachTableModel(PamhyrTableModel):
if not index.isValid(): if not index.isValid():
return QVariant() return QVariant()
profile = self._data.profile(index.row())
if role == Qt.BackgroundRole and not profile.is_enabled:
return QColor(190, 190, 190)
if role == Qt.DisplayRole and index.column() == 0: if role == Qt.DisplayRole and index.column() == 0:
return self._data.profile(index.row()).name return profile.name
if role == Qt.DisplayRole and index.column() == 1: if role == Qt.DisplayRole and index.column() == 1:
rk = self._data.profile(index.row()).rk rk = profile.rk
return f"{rk:.4f}" return f"{rk:.4f}"
if role == Qt.DisplayRole and index.column() == 2: if role == Qt.DisplayRole and index.column() == 2:
return str(self._data.profile(index.row()).nb_points) return str(profile.nb_points)
if role == Qt.TextAlignmentRole: if role == Qt.TextAlignmentRole:
return Qt.AlignHCenter | Qt.AlignVCenter return Qt.AlignHCenter | Qt.AlignVCenter
@ -155,6 +160,14 @@ class GeometryReachTableModel(PamhyrTableModel):
self.endRemoveRows() self.endRemoveRows()
self.layoutChanged.emit() self.layoutChanged.emit()
def enabled(self, rows, enabled):
self._undo.push(
SetEnabledCommand(
self._data, rows, enabled
)
)
self.layoutChanged.emit()
def sort_profiles(self, _reverse): def sort_profiles(self, _reverse):
self.layoutAboutToBeChanged.emit() self.layoutAboutToBeChanged.emit()

View File

@ -19,6 +19,7 @@
from PyQt5.QtCore import QCoreApplication from PyQt5.QtCore import QCoreApplication
from View.Translate import MainTranslate from View.Translate import MainTranslate
from View.WeatherParameters.translate import WeatherParametersTranslate
_translate = QCoreApplication.translate _translate = QCoreApplication.translate
@ -44,6 +45,66 @@ class GeometryTranslate(MainTranslate):
self._dict["cross_sections"] = _translate("Geometry", "cross-sections") self._dict["cross_sections"] = _translate("Geometry", "cross-sections")
self._dict["profile"] = _translate("Geometry", "cross-section") self._dict["profile"] = _translate("Geometry", "cross-section")
self._dict["profiles"] = _translate("Geometry", "cross-sections") self._dict["profiles"] = _translate("Geometry", "cross-sections")
self._dict["cross_section_enabled_count"] = _translate(
"Geometry", "Cross-section enabled ({count} disabled)"
)
self._dict["profile_disable_blocked"] = _translate(
"Geometry", "The cross-section cannot be disabled."
)
self._dict["profile_disable_blocked_info"] = _translate(
"Geometry",
"It is referenced by the following data:\n{dependencies}\n\n"
"Change or remove these associations before disabling it."
)
self._dict["profile_dependency"] = _translate(
"Geometry", "{kind}{name}” ({association})"
)
self._dict["initial_condition"] = _translate(
"Geometry", "Initial condition"
)
self._dict["initial_condition_temperature"] = _translate(
"Geometry", "Initial condition temperature"
)
self._dict["hydraulic_structure"] = _translate(
"Geometry", "Hydraulic structure"
)
self._dict["lateral_contribution"] = _translate(
"Geometry", "Lateral contribution"
)
self._dict["weather_parameter"] = _translate(
"Geometry", "Weather parameter"
)
self._dict["section"] = _translate("Geometry", "cross-section")
self._dict["input_section"] = _translate(
"Geometry", "input cross-section"
)
self._dict["output_section"] = _translate(
"Geometry", "output cross-section"
)
self._dict["begin_section"] = _translate(
"Geometry", "first cross-section"
)
self._dict["end_section"] = _translate(
"Geometry", "last cross-section"
)
self._dict["cross_section_pk"] = _translate(
"Geometry", "cross-section PK"
)
weather_parameters = WeatherParametersTranslate().get_dict(
"weather_parameters"
)
self._sub_dict["weather_parameter_types"] = {
"AT": weather_parameters["air_temperature"],
"SH": weather_parameters["specific_humidity"],
"GR": weather_parameters["global_radiation"],
"RWS": weather_parameters["reference_wind_speed"],
"GT": weather_parameters["surface_temperature"],
"GFR": weather_parameters["surface_flow_rate"],
"ALB": weather_parameters["albedo"],
"SC": weather_parameters["shading_coefficient"],
"CCF": weather_parameters["cloud_cover_fraction"],
}
self._dict["transverse_abscissa"] = _translate( self._dict["transverse_abscissa"] = _translate(
"Geometry", "Transverse abscissa (m)" "Geometry", "Transverse abscissa (m)"
@ -97,6 +158,15 @@ class GeometryTranslate(MainTranslate):
self._dict["format_not_exportable"] = _translate( self._dict["format_not_exportable"] = _translate(
"Geometry", "The format of the file is not exportable." "Geometry", "The format of the file is not exportable."
) )
self._dict["export_options"] = _translate(
"Geometry", "Export options"
)
self._dict["export_options_text"] = _translate(
"Geometry", "Choose which cross-sections to export."
)
self._dict["export_interpolated_profiles"] = _translate(
"Geometry", "Export interpolated cross-sections"
)
self._dict["update_rk_error"] = _translate( self._dict["update_rk_error"] = _translate(
"Geometry", "Geometry",
"RK update can't be executed." "RK update can't be executed."

View File

@ -68,6 +68,27 @@ class SetRKCommand(SetDataCommand):
self._reach.profile(self._index).rk = self._new self._reach.profile(self._index).rk = self._new
class SetEnabledCommand(QUndoCommand):
def __init__(self, reach, rows, enabled):
QUndoCommand.__init__(self)
self._profiles = [reach.profile(row) for row in rows]
self._old = [profile.is_enabled for profile in self._profiles]
self._new = bool(enabled)
@staticmethod
def _set_enabled(profile, enabled):
profile.enabled = enabled
def undo(self):
for profile, enabled in zip(self._profiles, self._old):
self._set_enabled(profile, enabled)
def redo(self):
for profile in self._profiles:
self._set_enabled(profile, self._new)
class AddCommand(QUndoCommand): class AddCommand(QUndoCommand):
def __init__(self, reach, index): def __init__(self, reach, index):
QUndoCommand.__init__(self) QUndoCommand.__init__(self)

View File

@ -99,6 +99,7 @@ class GeometryWindow(PamhyrWindow):
self._profile_window = [] self._profile_window = []
self.setup_table() self.setup_table()
self.setup_checkbox()
self.setup_plots() self.setup_plots()
self.setup_statusbar() self.setup_statusbar()
self.setup_connections() self.setup_connections()
@ -124,6 +125,10 @@ class GeometryWindow(PamhyrWindow):
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True) table.setAlternatingRowColors(True)
def setup_checkbox(self):
self._checkbox = self.find(QCheckBox, "checkBox_enabled")
self._set_checkbox_state()
def setup_plots(self): def setup_plots(self):
self.setup_plots_xy() self.setup_plots_xy()
self.setup_plots_rkc() self.setup_plots_rkc()
@ -223,6 +228,9 @@ class GeometryWindow(PamhyrWindow):
.selectionChanged\ .selectionChanged\
.connect(self.select_current_profile) .connect(self.select_current_profile)
if not self._study.is_read_only():
self._checkbox.clicked.connect(self._set_profiles_state)
self._table.layoutChanged.connect(self.update_redraw) self._table.layoutChanged.connect(self.update_redraw)
def update(self): def update(self):
@ -287,13 +295,14 @@ class GeometryWindow(PamhyrWindow):
if self.sub_window_exists( if self.sub_window_exists(
ProfileWindow, ProfileWindow,
data=[None, None, profile] data=[self._study, self._config, profile]
): ):
continue continue
win = ProfileWindow( win = ProfileWindow(
profile=profile, profile=profile,
study=self._study, study=self._study,
config=self._config,
parent=self, parent=self,
) )
self._profile_window.append(win) self._profile_window.append(win)
@ -314,6 +323,10 @@ class GeometryWindow(PamhyrWindow):
trad=self._trad, trad=self._trad,
parent=self parent=self
) )
dlg.adjustSize()
dialog_geometry = dlg.frameGeometry()
dialog_geometry.moveCenter(self.frameGeometry().center())
dlg.move(dialog_geometry.topLeft())
if dlg.exec(): if dlg.exec():
data = { data = {
"step": dlg.space_step, "step": dlg.space_step,
@ -520,6 +533,92 @@ class GeometryWindow(PamhyrWindow):
self._plot_ac.draw() self._plot_ac.draw()
self.tableView.model().blockSignals(False) self.tableView.model().blockSignals(False)
self._set_checkbox_state()
def index_selected_rows(self):
return [
index.row()
for index in self.tableView.selectionModel().selectedRows()
]
def _set_checkbox_state(self):
rows = self.index_selected_rows()
editable = not self._study.is_read_only()
disabled_count = (self._reach.number_profiles -
self._reach.number_enabled_profiles)
self._checkbox.setText(
self._trad["cross_section_enabled_count"].format(
count=disabled_count
)
)
self._checkbox.setEnabled(editable and len(rows) > 0)
if len(rows) == 0:
self._checkbox.setTristate(False)
self._checkbox.setChecked(False)
return
states = {
self._reach.profile(row).is_enabled
for row in rows
}
if len(states) == 1:
self._checkbox.setTristate(False)
self._checkbox.setChecked(states.pop())
else:
self._checkbox.setTristate(True)
self._checkbox.setCheckState(Qt.PartiallyChecked)
def _set_profiles_state(self, enabled):
rows = self.index_selected_rows()
if len(rows) == 0:
return
if not enabled:
blocked = []
for row in rows:
profile = self._reach.profile(row)
dependencies = self._study.river.profile_dependencies(profile)
if len(dependencies) != 0:
blocked.append((profile, dependencies))
if len(blocked) != 0:
details = []
for profile, dependencies in blocked:
details.append(f"{profile.name}:")
for dependency in dependencies:
item = dependency["item"]
if dependency["kind"] == "weather_parameter":
name = self._trad.get_dict(
"weather_parameter_types"
).get(item.type, item.type)
else:
name = getattr(item, "name", "")
if name == "":
name = self._trad[dependency["kind"]]
details.append(
" - " +
self._trad["profile_dependency"].format(
kind=self._trad[dependency["kind"]],
name=name,
association=self._trad[
dependency["association"]
],
)
)
self._set_checkbox_state()
self.message_box(
self._trad["profile_disable_blocked"],
self._trad["profile_disable_blocked_info"].format(
dependencies="\n".join(details)
),
window_title=self._trad["warning"],
)
return
self._checkbox.setTristate(False)
self._table.enabled(rows, enabled)
def add(self): def add(self):
if len(self.tableView.selectedIndexes()) == 0: if len(self.tableView.selectedIndexes()) == 0:
@ -735,7 +834,11 @@ class GeometryWindow(PamhyrWindow):
suffix = Path(filename).suffix suffix = Path(filename).suffix
if suffix != "": if suffix != "":
if suffix == ".st" or suffix == ".ST": if suffix == ".st" or suffix == ".ST":
self._export_to_file_st(filename[:-3]) export_interpolated = self._ask_export_options()
if export_interpolated is not None:
self._export_to_file_st(
filename[:-3], export_interpolated
)
else: else:
# Warning popup when the format is not exportable # Warning popup when the format is not exportable
win = QtWidgets.QMessageBox() win = QtWidgets.QMessageBox()
@ -746,16 +849,45 @@ class GeometryWindow(PamhyrWindow):
pass pass
else: else:
self._export_to_file_st(filename) export_interpolated = self._ask_export_options()
if export_interpolated is not None:
self._export_to_file_st(filename, export_interpolated)
def _export_to_file_st(self, filename): def _ask_export_options(self):
win = QtWidgets.QMessageBox(self)
win.setIcon(QtWidgets.QMessageBox.Question)
win.setWindowTitle(self._trad["export_options"])
win.setText(self._trad["export_options_text"])
win.setStandardButtons(
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel
)
export_interpolated = QCheckBox(
self._trad["export_interpolated_profiles"], win
)
export_interpolated.setChecked(True)
win.setCheckBox(export_interpolated)
if win.exec() != QtWidgets.QMessageBox.Ok:
return None
return export_interpolated.isChecked()
def _export_to_file_st(self, filename, export_interpolated=True):
with open(filename+".st", "w+") as f: with open(filename+".st", "w+") as f:
f.write("# Exported from Pamhyr2\n") f.write("# Exported from Pamhyr2\n")
self._export_to_file_st_reach(f, self._reach) self._export_to_file_st_reach(
f, self._reach, export_interpolated
)
def _export_to_file_st_reach(self, wfile, reach): def _export_to_file_st_reach(self, wfile, reach,
export_interpolated=True):
pid = 0 pid = 0
for profile in reach.profiles: for profile in reach.profiles:
is_interpolated = profile.name.lower().startswith("interpol")
if is_interpolated and not export_interpolated:
continue
self._export_to_file_st_profile(wfile, profile, pid) self._export_to_file_st_profile(wfile, profile, pid)
pid += 1 pid += 1

View File

@ -158,6 +158,7 @@ other_model_action = [
define_model_action = [ define_model_action = [
# Toolbar # Toolbar
"action_toolBar_network", "action_toolBar_geometry", "action_toolBar_network", "action_toolBar_geometry",
"action_toolBar_meshing",
"action_toolBar_boundary_cond", "action_toolBar_lateral_contrib", "action_toolBar_boundary_cond", "action_toolBar_lateral_contrib",
"action_toolBar_frictions", "action_toolBar_initial_cond", "action_toolBar_frictions", "action_toolBar_initial_cond",
# Menu # Menu
@ -175,6 +176,7 @@ define_model_action = [
"action_menu_rep_additional_lines", "action_menu_rep_additional_lines",
"action_menu_run_adists", "action_menu_pollutants", "action_menu_run_adists", "action_menu_pollutants",
"action_menu_d90", "action_menu_dif", "action_menu_edit_geotiff", "action_menu_d90", "action_menu_dif", "action_menu_edit_geotiff",
"action_menu_meshing",
"action_menu_boundary_conditions_temperature", "action_menu_boundary_conditions_temperature",
"action_menu_initial_conditions_temperature", "action_menu_initial_conditions_temperature",
"action_menu_weather_parameters", "action_menu_run_adistt", "action_menu_weather_parameters", "action_menu_run_adistt",
@ -310,6 +312,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_menu_edit_scenarios": self.open_scenarios, "action_menu_edit_scenarios": self.open_scenarios,
"action_menu_edit_network": self.open_network, "action_menu_edit_network": self.open_network,
"action_menu_edit_geometry": self.open_geometry, "action_menu_edit_geometry": self.open_geometry,
"action_menu_meshing": self.open_meshing,
"action_menu_boundary_conditions": self.open_boundary_cond, "action_menu_boundary_conditions": self.open_boundary_cond,
"action_menu_boundary_conditions_sediment": "action_menu_boundary_conditions_sediment":
self.open_boundary_cond_sed, self.open_boundary_cond_sed,
@ -351,6 +354,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
# Current actions # Current actions
"action_toolBar_network": self.open_network, "action_toolBar_network": self.open_network,
"action_toolBar_geometry": self.open_geometry, "action_toolBar_geometry": self.open_geometry,
"action_toolBar_meshing": self.open_meshing,
"action_toolBar_boundary_cond": self.open_boundary_cond, "action_toolBar_boundary_cond": self.open_boundary_cond,
"action_toolBar_lateral_contrib": self.open_lateral_contrib, "action_toolBar_lateral_contrib": self.open_lateral_contrib,
"action_toolBar_frictions": self.open_frictions, "action_toolBar_frictions": self.open_frictions,
@ -1339,7 +1343,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
GeometryWindow, GeometryWindow,
data=[self._study, self.conf, reach] data=[self._study, self.conf, reach]
): ):
return return self.get_sub_window(
GeometryWindow,
data=[self._study, self.conf, reach]
)
geometry = GeometryWindow( geometry = GeometryWindow(
study=self._study, study=self._study,
@ -1348,8 +1355,21 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
parent=self parent=self
) )
geometry.show() geometry.show()
return geometry
else: else:
self.msg_select_reach() self.msg_select_reach()
return None
def open_meshing(self):
"""Open the current reach geometry and its meshing dialog."""
geometry = self.open_geometry()
if geometry is None or self._study.is_read_only():
return
geometry.raise_()
geometry.activateWindow()
QApplication.processEvents()
geometry.edit_meshing()
def open_boundary_cond_sed(self): def open_boundary_cond_sed(self):
self.open_boundary_cond(tab=1) self.open_boundary_cond(tab=1)

View File

@ -64,6 +64,7 @@ class SelectProfileDialog(PamhyrDialog):
self._reach = reach self._reach = reach
self._profile = None self._profile = None
self._profiles = self._reach.reach.enabled_profiles
self.setup_combobox() self.setup_combobox()
@ -73,20 +74,19 @@ class SelectProfileDialog(PamhyrDialog):
list( list(
map( map(
lambda p: p.display_name(), lambda p: p.display_name(),
self._reach.reach.profiles[1:-1] self._profiles)))
)
) if len(self._profiles) == 0:
) self.find(QDialogButtonBox, "buttonBox")\
.button(QDialogButtonBox.Ok)\
.setEnabled(False)
def accept(self): def accept(self):
profile = self.get_combobox_text("comboBox") index = self.find(QComboBox, "comboBox").currentIndex()
if not 0 <= index < len(self._profiles):
return
self._profile = next( self._profile = self._profiles[index]
filter(
lambda p: p.display_name() == profile,
self._reach.reach.profiles[1:-1]
)
)
super(SelectProfileDialog, self).accept() super(SelectProfileDialog, self).accept()

View File

@ -62,6 +62,8 @@ class PlotRKC(PamhyrPlot):
self._auto_relim_update = True self._auto_relim_update = True
self._autoscale_update = False self._autoscale_update = False
self.profile = None
@property @property
def results(self): def results(self):
return self.data return self.data
@ -71,9 +73,19 @@ class PlotRKC(PamhyrPlot):
self.data = results self.data = results
self._current_timestamp = max(self._timestamps) self._current_timestamp = max(self._timestamps)
@staticmethod
def reach_geometry(reach):
"""Return geometry values for profiles present in the results."""
return (
reach.geometry.get_rk_enabled_profiles(),
reach.geometry.get_z_min_enabled_profiles(),
reach.geometry.get_z_max_enabled_profiles()
)
@timer @timer
def draw(self, highlight=None): def draw(self, highlight=None):
self.init_axes() self.init_axes()
self.profile = None
if self.results is None: if self.results is None:
return return
@ -104,7 +116,7 @@ class PlotRKC(PamhyrPlot):
def draw_bottom_with_bedload(self, reach): def draw_bottom_with_bedload(self, reach):
results = self.results[self._current_res_id] results = self.results[self._current_res_id]
rk = reach.geometry.get_rk() rk, _, _ = self.reach_geometry(reach)
table = results.get("table")["zfd"] table = results.get("table")["zfd"]
ts = results.get_timestamp_id(self._current_timestamp) ts = results.get_timestamp_id(self._current_timestamp)
@ -136,8 +148,7 @@ class PlotRKC(PamhyrPlot):
for hs in lhs: for hs in lhs:
x = hs.input_section.rk x = hs.input_section.rk
z_min = reach.geometry.get_z_min() _, z_min, z_max = self.reach_geometry(reach)
z_max = reach.geometry.get_z_max()
self.canvas.axes.plot( self.canvas.axes.plot(
[x, x], [x, x],
@ -157,9 +168,7 @@ class PlotRKC(PamhyrPlot):
) )
def draw_bottom_geometry(self, reach): def draw_bottom_geometry(self, reach):
rk = reach.geometry.get_rk() rk, z_min, _ = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
z_max = reach.geometry.get_z_max()
self.line_rk_zmin = self.canvas.axes.plot( self.line_rk_zmin = self.canvas.axes.plot(
rk, z_min, rk, z_min,
@ -170,10 +179,9 @@ class PlotRKC(PamhyrPlot):
self._river_bottom = z_min self._river_bottom = z_min
def draw_water_elevation(self, reach): def draw_water_elevation(self, reach):
if len(reach.geometry.profiles) != 0: if len(reach.profiles) != 0:
result = self.results[self._current_res_id] result = self.results[self._current_res_id]
rk = reach.geometry.get_rk() rk, _, _ = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
table = result.get("table")["Z"] table = result.get("table")["Z"]
ts = result.get_timestamp_id(self._current_timestamp) ts = result.get_timestamp_id(self._current_timestamp)
@ -201,10 +209,9 @@ class PlotRKC(PamhyrPlot):
) )
def draw_water_elevation_max(self, reach): def draw_water_elevation_max(self, reach):
if len(reach.geometry.profiles) != 0: if len(reach.profiles) != 0:
result = self.results[self._current_res_id] result = self.results[self._current_res_id]
rk = reach.geometry.get_rk() rk, _, _ = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
table = result.get("table")["Z"] table = result.get("table")["Z"]
ts = result.get_timestamp_id(self._current_timestamp) ts = result.get_timestamp_id(self._current_timestamp)
@ -250,9 +257,7 @@ class PlotRKC(PamhyrPlot):
self.canvas.draw_idle() self.canvas.draw_idle()
def draw_current(self, reach): def draw_current(self, reach):
rk = reach.geometry.get_rk() rk, z_min, z_max = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
z_max = reach.geometry.get_z_max()
self.profile, = self.canvas.axes.plot( self.profile, = self.canvas.axes.plot(
[ [
@ -349,8 +354,7 @@ class PlotRKC(PamhyrPlot):
def update_water_elevation(self): def update_water_elevation(self):
result = self.results[self._current_res_id] result = self.results[self._current_res_id]
reach = result.river.reach(self._current_reach_id) reach = result.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk() rk, _, _ = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
table = result.get("table")["Z"] table = result.get("table")["Z"]
ts = result.get_timestamp_id(self._current_timestamp) ts = result.get_timestamp_id(self._current_timestamp)
@ -380,11 +384,13 @@ class PlotRKC(PamhyrPlot):
self.update_idle() self.update_idle()
def update_current(self): def update_current(self):
if not self._init or self.profile is None:
self.draw()
return
results = self.results[self._current_res_id] results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id) reach = results.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk() rk, z_min, z_max = self.reach_geometry(reach)
z_min = reach.geometry.get_z_min()
z_max = reach.geometry.get_z_max()
cid = self._current_profile_id cid = self._current_profile_id
self.profile.set_data( self.profile.set_data(
@ -396,7 +402,7 @@ class PlotRKC(PamhyrPlot):
def update_bottom_with_bedload(self): def update_bottom_with_bedload(self):
results = self.results[self._current_res_id] results = self.results[self._current_res_id]
reach = results.river.reach(self._current_reach_id) reach = results.river.reach(self._current_reach_id)
rk = reach.geometry.get_rk() rk, _, _ = self.reach_geometry(reach)
# z = self.sl_compute_current_z(reach) # z = self.sl_compute_current_z(reach)
table = results.get("table")["zfd"] table = results.get("table")["zfd"]

View File

@ -52,6 +52,9 @@
<attribute name="toolBarBreak"> <attribute name="toolBarBreak">
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<addaction name="action_previous_profile"/>
<addaction name="action_next_profile"/>
<addaction name="separator"/>
<addaction name="action_add"/> <addaction name="action_add"/>
<addaction name="action_delete"/> <addaction name="action_delete"/>
<addaction name="action_sort_asc"/> <addaction name="action_sort_asc"/>
@ -61,6 +64,30 @@
<addaction name="action_purge"/> <addaction name="action_purge"/>
<addaction name="action_reverse"/> <addaction name="action_reverse"/>
</widget> </widget>
<action name="action_previous_profile">
<property name="icon">
<iconset>
<normaloff>ressources/left.png</normaloff>ressources/left.png</iconset>
</property>
<property name="text">
<string>Previous profile</string>
</property>
<property name="toolTip">
<string>Open the previous profile</string>
</property>
</action>
<action name="action_next_profile">
<property name="icon">
<iconset>
<normaloff>ressources/right.png</normaloff>ressources/right.png</iconset>
</property>
<property name="text">
<string>Next profile</string>
</property>
<property name="toolTip">
<string>Open the next profile</string>
</property>
</action>
<action name="action_add"> <action name="action_add">
<property name="icon"> <property name="icon">
<iconset> <iconset>

View File

@ -24,10 +24,20 @@
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<widget class="QWidget" name="horizontalLayoutWidget"> <widget class="QWidget" name="horizontalLayoutWidget">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QTableView" name="tableView"/> <widget class="QTableView" name="tableView"/>
</item> </item>
<item>
<widget class="QCheckBox" name="checkBox_enabled">
<property name="text">
<string>Cross-section enabled (0 disabled)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QSplitter" name="splitter_2"> <widget class="QSplitter" name="splitter_2">

View File

@ -19,6 +19,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Serif</family> <family>Serif</family>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
<kerning>false</kerning> <kerning>false</kerning>
</font> </font>
@ -64,6 +65,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Ubuntu</family> <family>Ubuntu</family>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
<kerning>false</kerning> <kerning>false</kerning>
</font> </font>
@ -87,6 +89,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Sans Serif</family> <family>Sans Serif</family>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
<kerning>false</kerning> <kerning>false</kerning>
</font> </font>
@ -126,6 +129,7 @@
<string>&amp;Geometry</string> <string>&amp;Geometry</string>
</property> </property>
<addaction name="action_menu_edit_geometry"/> <addaction name="action_menu_edit_geometry"/>
<addaction name="action_menu_meshing"/>
<addaction name="action_menu_edit_geotiff"/> <addaction name="action_menu_edit_geotiff"/>
</widget> </widget>
<widget class="QMenu" name="menu_run"> <widget class="QMenu" name="menu_run">
@ -257,6 +261,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Ubuntu</family> <family>Ubuntu</family>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
<kerning>false</kerning> <kerning>false</kerning>
</font> </font>
@ -275,6 +280,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Sans Serif</family> <family>Sans Serif</family>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
<kerning>true</kerning> <kerning>true</kerning>
</font> </font>
@ -325,6 +331,7 @@
<property name="font"> <property name="font">
<font> <font>
<family>Ubuntu</family> <family>Ubuntu</family>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
<kerning>false</kerning> <kerning>false</kerning>
</font> </font>
@ -346,6 +353,7 @@
</attribute> </attribute>
<addaction name="action_toolBar_network"/> <addaction name="action_toolBar_network"/>
<addaction name="action_toolBar_geometry"/> <addaction name="action_toolBar_geometry"/>
<addaction name="action_toolBar_meshing"/>
<addaction name="action_toolBar_boundary_cond"/> <addaction name="action_toolBar_boundary_cond"/>
<addaction name="action_toolBar_lateral_contrib"/> <addaction name="action_toolBar_lateral_contrib"/>
<addaction name="action_toolBar_frictions"/> <addaction name="action_toolBar_frictions"/>
@ -866,6 +874,33 @@
<string>Open results temperature</string> <string>Open results temperature</string>
</property> </property>
</action> </action>
<action name="action_menu_meshing">
<property name="icon">
<iconset>
<normaloff>ressources/meshing.png</normaloff>ressources/meshing.png</iconset>
</property>
<property name="text">
<string>Meshing</string>
</property>
</action>
<action name="action_toolBar_meshing">
<property name="enabled">
<bool>false</bool>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset>
<normaloff>ressources/meshing.png</normaloff>ressources/meshing.png</iconset>
</property>
<property name="text">
<string>Meshing</string>
</property>
<property name="toolTip">
<string>Mesh geometry</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections> <connections>