RCAIDE-GUI 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- common_widgets/__init__.py +6 -0
- common_widgets/animated_toggle.py +141 -0
- common_widgets/color.py +17 -0
- common_widgets/data_entry_widget.py +337 -0
- common_widgets/image_widget.py +21 -0
- common_widgets/unit_picker_widget.py +48 -0
- main.py +168 -0
- rcaide_gui-1.0.0.dist-info/METADATA +96 -0
- rcaide_gui-1.0.0.dist-info/RECORD +170 -0
- rcaide_gui-1.0.0.dist-info/WHEEL +5 -0
- rcaide_gui-1.0.0.dist-info/entry_points.txt +2 -0
- rcaide_gui-1.0.0.dist-info/top_level.txt +5 -0
- rcaide_io.py +818 -0
- tabs/__init__.py +10 -0
- tabs/aircraft_configs/__init__.py +3 -0
- tabs/aircraft_configs/aircraft_configs.py +301 -0
- tabs/analysis/__init__.py +4 -0
- tabs/analysis/analysis.py +92 -0
- tabs/analysis/widgets/__init__.py +13 -0
- tabs/analysis/widgets/aeroacoustics_widget.py +158 -0
- tabs/analysis/widgets/aerodynamics_widget.py +108 -0
- tabs/analysis/widgets/analysis_data_widget.py +29 -0
- tabs/analysis/widgets/atmosphere_widget.py +49 -0
- tabs/analysis/widgets/costs_widget.py +35 -0
- tabs/analysis/widgets/energy_widget.py +32 -0
- tabs/analysis/widgets/geometry_widget.py +55 -0
- tabs/analysis/widgets/planets_widget.py +34 -0
- tabs/analysis/widgets/propulsion_widget.py +53 -0
- tabs/analysis/widgets/stability_widget.py +34 -0
- tabs/analysis/widgets/weights_widget.py +94 -0
- tabs/geometry/__init__.py +6 -0
- tabs/geometry/aircraft_configs.py +232 -0
- tabs/geometry/frames/__init__.py +15 -0
- tabs/geometry/frames/booms/__init__.py +5 -0
- tabs/geometry/frames/booms/boom_frame.py +238 -0
- tabs/geometry/frames/cargo_bays/__init__.py +5 -0
- tabs/geometry/frames/cargo_bays/cargo_bay_frame.py +159 -0
- tabs/geometry/frames/default_frame.py +23 -0
- tabs/geometry/frames/energy_network/__init__.py +2 -0
- tabs/geometry/frames/energy_network/turbofan_network/__init__.py +3 -0
- tabs/geometry/frames/energy_network/turbofan_network/frames/__init__.py +1 -0
- tabs/geometry/frames/energy_network/turbofan_network/widgets/__init__.py +1 -0
- tabs/geometry/frames/fuselages/__init__.py +5 -0
- tabs/geometry/frames/fuselages/fuselage_frame.py +294 -0
- tabs/geometry/frames/geometry_frame.py +91 -0
- tabs/geometry/frames/landing_gears/__init__.py +5 -0
- tabs/geometry/frames/landing_gears/landing_gear_frame.py +189 -0
- tabs/geometry/frames/nacelles/__init__.py +1 -0
- tabs/geometry/frames/powertrain/__init__.py +6 -0
- tabs/geometry/frames/powertrain/converters/__init__.py +5 -0
- tabs/geometry/frames/powertrain/converters/converter_frame.py +137 -0
- tabs/geometry/frames/powertrain/distributors/__init__.py +5 -0
- tabs/geometry/frames/powertrain/distributors/distributor_frame.py +143 -0
- tabs/geometry/frames/powertrain/nacelles/__init__.py +5 -0
- tabs/geometry/frames/powertrain/nacelles/nacelle_frame.py +283 -0
- tabs/geometry/frames/powertrain/powertrain_frame.py +259 -0
- tabs/geometry/frames/powertrain/propulsors/__init__.py +5 -0
- tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py +146 -0
- tabs/geometry/frames/powertrain/sources/__init__.py +6 -0
- tabs/geometry/frames/powertrain/sources/energy_source_frame.py +147 -0
- tabs/geometry/frames/vehicle_frame.py +171 -0
- tabs/geometry/frames/wings/__init__.py +5 -0
- tabs/geometry/frames/wings/wings_frame.py +457 -0
- tabs/geometry/geometry.py +513 -0
- tabs/geometry/widgets/__init__.py +12 -0
- tabs/geometry/widgets/booms/__init__.py +6 -0
- tabs/geometry/widgets/booms/boom_section_widget.py +109 -0
- tabs/geometry/widgets/cargo_bays/__init__.py +1 -0
- tabs/geometry/widgets/fuselages/__init__.py +8 -0
- tabs/geometry/widgets/fuselages/cabin_class_widget.py +188 -0
- tabs/geometry/widgets/fuselages/cabin_widget.py +217 -0
- tabs/geometry/widgets/fuselages/fuselage_section_widget.py +190 -0
- tabs/geometry/widgets/geometry_data_widget.py +25 -0
- tabs/geometry/widgets/landing_gears/__init__.py +6 -0
- tabs/geometry/widgets/nacelles/__init__.py +1 -0
- tabs/geometry/widgets/powertrain/__init__.py +9 -0
- tabs/geometry/widgets/powertrain/converters/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/converters/turboelectric_generator_widget.py +74 -0
- tabs/geometry/widgets/powertrain/distributors/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/distributors/fuel_line_widget.py +81 -0
- tabs/geometry/widgets/powertrain/modulators/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/modulators/esc_widget.py +58 -0
- tabs/geometry/widgets/powertrain/nacelles/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/nacelles/nacelle_section_widget.py +115 -0
- tabs/geometry/widgets/powertrain/powertrain_connector_widget.py +136 -0
- tabs/geometry/widgets/powertrain/powertrain_widget.py +206 -0
- tabs/geometry/widgets/powertrain/propulsors/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/propulsors/turbofan_widget.py +462 -0
- tabs/geometry/widgets/powertrain/sources/__init__.py +6 -0
- tabs/geometry/widgets/powertrain/sources/fuel_tank_widget.py +103 -0
- tabs/geometry/widgets/powertrain/sources/source_selector_widget.py +35 -0
- tabs/geometry/widgets/wings/__init__.py +7 -0
- tabs/geometry/widgets/wings/wing_cs_widget.py +198 -0
- tabs/geometry/widgets/wings/wing_section_widget.py +298 -0
- tabs/home/__init__.py +3 -0
- tabs/home/home.py +585 -0
- tabs/mission/__init__.py +4 -0
- tabs/mission/mission.py +1124 -0
- tabs/mission/widgets/__init__.py +3 -0
- tabs/mission/widgets/flight_controls_widget.py +186 -0
- tabs/mission/widgets/mission_analysis_widget.py +166 -0
- tabs/mission/widgets/mission_segment_helper.py +358 -0
- tabs/mission/widgets/mission_segment_widget.py +358 -0
- tabs/solve/__init__.py +4 -0
- tabs/solve/plots/__init__.py +12 -0
- tabs/solve/plots/aeroacoustics/__init__.py +6 -0
- tabs/solve/plots/aeroacoustics/plot_2D_noise_contour.py +184 -0
- tabs/solve/plots/aeroacoustics/plot_3D_noise_contour.py +219 -0
- tabs/solve/plots/aeroacoustics/plot_noise_certification_contour.py +115 -0
- tabs/solve/plots/aeroacoustics/plot_noise_level.py +118 -0
- tabs/solve/plots/aerodynamics/__init__.py +10 -0
- tabs/solve/plots/aerodynamics/plot_aerodynamic_coefficients.py +156 -0
- tabs/solve/plots/aerodynamics/plot_aerodynamic_forces.py +155 -0
- tabs/solve/plots/aerodynamics/plot_aircraft_aerodynamics.py +136 -0
- tabs/solve/plots/aerodynamics/plot_drag_components.py +157 -0
- tabs/solve/plots/aerodynamics/plot_lift_distribution.py +107 -0
- tabs/solve/plots/aerodynamics/plot_rotor_conditions.py +255 -0
- tabs/solve/plots/aerodynamics/plot_rotor_disc_performance.py +144 -0
- tabs/solve/plots/aerodynamics/plot_rotor_performance.py +124 -0
- tabs/solve/plots/common/__init__.py +4 -0
- tabs/solve/plots/common/plot_style.py +71 -0
- tabs/solve/plots/common/set_axes.py +55 -0
- tabs/solve/plots/create_plot_widgets.py +34 -0
- tabs/solve/plots/emissions/__init__.py +3 -0
- tabs/solve/plots/emissions/plot_emissions.py +167 -0
- tabs/solve/plots/energy/__init__.py +12 -0
- tabs/solve/plots/energy/plot_altitude_sfc_weight.py +134 -0
- tabs/solve/plots/energy/plot_battery_cell_conditions.py +154 -0
- tabs/solve/plots/energy/plot_battery_degradation.py +157 -0
- tabs/solve/plots/energy/plot_battery_module_C_rates.py +139 -0
- tabs/solve/plots/energy/plot_battery_module_conditions.py +157 -0
- tabs/solve/plots/energy/plot_battery_pack_conditions.py +164 -0
- tabs/solve/plots/energy/plot_battery_ragone_diagram.py +97 -0
- tabs/solve/plots/energy/plot_battery_temperature.py +136 -0
- tabs/solve/plots/energy/plot_electric_propulsor_efficiencies.py +136 -0
- tabs/solve/plots/energy/plot_propulsor_throttles.py +119 -0
- tabs/solve/plots/mission/__init__.py +5 -0
- tabs/solve/plots/mission/plot_aircraft_velocities.py +145 -0
- tabs/solve/plots/mission/plot_flight_conditions.py +236 -0
- tabs/solve/plots/mission/plot_flight_trajectory.py +172 -0
- tabs/solve/plots/stability/__init__.py +5 -0
- tabs/solve/plots/stability/plot_flight_forces_and_moments.py +163 -0
- tabs/solve/plots/stability/plot_lateral_stability.py +151 -0
- tabs/solve/plots/stability/plot_longitudinal_stability.py +173 -0
- tabs/solve/plots/thermal_management/__init__.py +7 -0
- tabs/solve/plots/thermal_management/plot_air_cooled_conditions.py +152 -0
- tabs/solve/plots/thermal_management/plot_cross_flow_heat_exchanger_conditions.py +185 -0
- tabs/solve/plots/thermal_management/plot_reservoir_conditions.py +141 -0
- tabs/solve/plots/thermal_management/plot_thermal_management_performance.py +105 -0
- tabs/solve/plots/thermal_management/plot_wavy_channel_conditions.py +161 -0
- tabs/solve/plots/weights/__init__.py +4 -0
- tabs/solve/plots/weights/plot_load_diagram.py +163 -0
- tabs/solve/plots/weights/plot_weight_breakdown.py +164 -0
- tabs/solve/solve.py +1498 -0
- tabs/style_sheet.py +114 -0
- tabs/tab_widget.py +14 -0
- tabs/visualize_geometry/__init__.py +4 -0
- tabs/visualize_geometry/core_3d_viewer.py +253 -0
- tabs/visualize_geometry/features/__init__.py +10 -0
- tabs/visualize_geometry/features/axes_gizmo.py +173 -0
- tabs/visualize_geometry/features/background.py +161 -0
- tabs/visualize_geometry/features/blueprint.py +685 -0
- tabs/visualize_geometry/features/camera.py +364 -0
- tabs/visualize_geometry/features/drag_aircraft.py +219 -0
- tabs/visualize_geometry/features/grid.py +194 -0
- tabs/visualize_geometry/features/measurement.py +367 -0
- tabs/visualize_geometry/features/screenshot.py +91 -0
- tabs/visualize_geometry/geometry_helper_functions.py +3 -0
- tabs/visualize_geometry/visualize_geometry.py +731 -0
- utilities.py +257 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/mission/widgets/flight_controls_widget.py
|
|
2
|
+
|
|
3
|
+
# Created: May 2023, M. Clarke
|
|
4
|
+
# ------------------------------------------------------------------------------
|
|
5
|
+
# Imports
|
|
6
|
+
# ------------------------------------------------------------------------------
|
|
7
|
+
from PyQt6.QtWidgets import (
|
|
8
|
+
QHBoxLayout,
|
|
9
|
+
QLabel,
|
|
10
|
+
QVBoxLayout,
|
|
11
|
+
QWidget,
|
|
12
|
+
QCheckBox,
|
|
13
|
+
QSizePolicy,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from utilities import Units, create_line_bar, set_data
|
|
17
|
+
from common_widgets import DataEntryWidget
|
|
18
|
+
import rcaide_io
|
|
19
|
+
|
|
20
|
+
# ------------------------------------------------------------------------------
|
|
21
|
+
# Flight Controls Widget
|
|
22
|
+
# ------------------------------------------------------------------------------
|
|
23
|
+
class FlightControlsWidget(QWidget):
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super().__init__()
|
|
26
|
+
|
|
27
|
+
base_layout = QVBoxLayout()
|
|
28
|
+
toggles_layout = QHBoxLayout()
|
|
29
|
+
|
|
30
|
+
self.data_entry_widgets = []
|
|
31
|
+
|
|
32
|
+
for key, toggles in self.fields.items():
|
|
33
|
+
sub_layout = QVBoxLayout()
|
|
34
|
+
|
|
35
|
+
header = QLabel("<b>" + key + "</b>")
|
|
36
|
+
header.setSizePolicy(
|
|
37
|
+
QSizePolicy.Policy.Minimum,
|
|
38
|
+
QSizePolicy.Policy.Minimum,
|
|
39
|
+
)
|
|
40
|
+
sub_layout.addWidget(header)
|
|
41
|
+
sub_layout.addWidget(create_line_bar())
|
|
42
|
+
|
|
43
|
+
self.data_entry_widgets.append(DataEntryWidget(toggles, 1))
|
|
44
|
+
sub_layout.addWidget(self.data_entry_widgets[-1])
|
|
45
|
+
|
|
46
|
+
toggles_layout.addLayout(sub_layout, 1)
|
|
47
|
+
|
|
48
|
+
base_layout.addLayout(toggles_layout)
|
|
49
|
+
|
|
50
|
+
# Propulsor assignment checkboxes
|
|
51
|
+
base_layout.addWidget(QLabel("<b>Assigned Propulsors</b>"))
|
|
52
|
+
base_layout.addWidget(create_line_bar())
|
|
53
|
+
|
|
54
|
+
self.propulsor_checkboxes = {}
|
|
55
|
+
self._prop_row = QHBoxLayout()
|
|
56
|
+
self._build_propulsor_checkboxes()
|
|
57
|
+
base_layout.addLayout(self._prop_row)
|
|
58
|
+
|
|
59
|
+
self.setLayout(base_layout)
|
|
60
|
+
|
|
61
|
+
# -------------------------------------------------------------------------
|
|
62
|
+
# Propulsor checkboxes
|
|
63
|
+
# -------------------------------------------------------------------------
|
|
64
|
+
def _build_propulsor_checkboxes(self):
|
|
65
|
+
while self._prop_row.count():
|
|
66
|
+
item = self._prop_row.takeAt(0)
|
|
67
|
+
if item.widget():
|
|
68
|
+
item.widget().deleteLater()
|
|
69
|
+
self.propulsor_checkboxes.clear()
|
|
70
|
+
|
|
71
|
+
names = []
|
|
72
|
+
try:
|
|
73
|
+
names = rcaide_io.propulsor_names[0] or []
|
|
74
|
+
except (AttributeError, IndexError, TypeError):
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
for name in names:
|
|
78
|
+
cb = QCheckBox(name)
|
|
79
|
+
cb.setChecked(True)
|
|
80
|
+
self.propulsor_checkboxes[name] = cb
|
|
81
|
+
self._prop_row.addWidget(cb)
|
|
82
|
+
|
|
83
|
+
self._prop_row.addStretch(1)
|
|
84
|
+
|
|
85
|
+
def refresh_propulsors(self):
|
|
86
|
+
"""Rebuild propulsor checkboxes from the current rcaide_io.propulsor_names."""
|
|
87
|
+
self._build_propulsor_checkboxes()
|
|
88
|
+
|
|
89
|
+
# -------------------------------------------------------------------------
|
|
90
|
+
# Data access
|
|
91
|
+
# -------------------------------------------------------------------------
|
|
92
|
+
def get_data(self):
|
|
93
|
+
data = {}
|
|
94
|
+
for widget in self.data_entry_widgets:
|
|
95
|
+
assert isinstance(widget, DataEntryWidget)
|
|
96
|
+
data.update(widget.get_values())
|
|
97
|
+
data["assigned_propulsors"] = [
|
|
98
|
+
name for name, cb in self.propulsor_checkboxes.items() if cb.isChecked()
|
|
99
|
+
]
|
|
100
|
+
return data
|
|
101
|
+
|
|
102
|
+
def load_data(self, data):
|
|
103
|
+
for widget in self.data_entry_widgets:
|
|
104
|
+
assert isinstance(widget, DataEntryWidget)
|
|
105
|
+
widget.load_data(data)
|
|
106
|
+
|
|
107
|
+
selected = data.get("assigned_propulsors", [])
|
|
108
|
+
# Handle [value, 0] unit-arg format that may appear when loading from RCAIDE JSON
|
|
109
|
+
if (isinstance(selected, list) and len(selected) == 2
|
|
110
|
+
and isinstance(selected[1], int) and not isinstance(selected[1], bool)):
|
|
111
|
+
selected = selected[0] if isinstance(selected[0], list) else []
|
|
112
|
+
|
|
113
|
+
for name, cb in self.propulsor_checkboxes.items():
|
|
114
|
+
cb.setChecked(not selected or name in selected)
|
|
115
|
+
|
|
116
|
+
def set_control_variables(self, segment):
|
|
117
|
+
for widget in self.data_entry_widgets:
|
|
118
|
+
assert isinstance(widget, DataEntryWidget)
|
|
119
|
+
data_units_labels = widget.data_units_labels
|
|
120
|
+
data = widget.get_values()
|
|
121
|
+
for data_unit_label in data_units_labels:
|
|
122
|
+
rcaide_label = data_unit_label[-1]
|
|
123
|
+
user_label = data_unit_label[0]
|
|
124
|
+
set_data(segment, rcaide_label, data[user_label][0])
|
|
125
|
+
|
|
126
|
+
# Use the propulsors the user checked; fall back to all available propulsors
|
|
127
|
+
selected = [name for name, cb in self.propulsor_checkboxes.items() if cb.isChecked()]
|
|
128
|
+
if not selected:
|
|
129
|
+
selected = list(self.propulsor_checkboxes.keys())
|
|
130
|
+
if not selected:
|
|
131
|
+
# Last-resort fallback: derive names from vehicle networks
|
|
132
|
+
try:
|
|
133
|
+
for network in rcaide_io.rcaide_vehicle.networks:
|
|
134
|
+
for prop in network.propulsors:
|
|
135
|
+
if prop.tag not in selected:
|
|
136
|
+
selected.append(prop.tag)
|
|
137
|
+
except Exception:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
segment.assigned_control_variables.throttle.assigned_propulsors = [selected]
|
|
141
|
+
|
|
142
|
+
if getattr(segment.assigned_control_variables.throttle, "active", False):
|
|
143
|
+
if hasattr(segment.assigned_control_variables.throttle, "initial_guess_values"):
|
|
144
|
+
if not segment.assigned_control_variables.throttle.initial_guess_values:
|
|
145
|
+
segment.assigned_control_variables.throttle.initial_guess_values = [[0.7]]
|
|
146
|
+
|
|
147
|
+
if getattr(segment.assigned_control_variables.body_angle, "active", False):
|
|
148
|
+
if hasattr(segment.assigned_control_variables.body_angle, "initial_guess_values"):
|
|
149
|
+
if not segment.assigned_control_variables.body_angle.initial_guess_values:
|
|
150
|
+
segment.assigned_control_variables.body_angle.initial_guess_values = [[0.0]]
|
|
151
|
+
|
|
152
|
+
def set_defaults(self, throttle=False, body_angle=False):
|
|
153
|
+
for widget in self.data_entry_widgets:
|
|
154
|
+
assert isinstance(widget, DataEntryWidget)
|
|
155
|
+
defaults = {}
|
|
156
|
+
for label, _, rcaide_label in widget.data_units_labels:
|
|
157
|
+
label_lower = rcaide_label.lower()
|
|
158
|
+
value = False
|
|
159
|
+
if "throttle.active" in label_lower:
|
|
160
|
+
value = throttle
|
|
161
|
+
elif "body_angle.active" in label_lower:
|
|
162
|
+
value = body_angle
|
|
163
|
+
defaults[label] = (value, 0)
|
|
164
|
+
widget.load_data(defaults)
|
|
165
|
+
|
|
166
|
+
fields = {
|
|
167
|
+
"Kinematics": [
|
|
168
|
+
("Body Angle", Units.Boolean, "assigned_control_variables.body_angle.active"),
|
|
169
|
+
("Bank Angle", Units.Boolean, "assigned_control_variables.bank_angle.active"),
|
|
170
|
+
("Wind Angle", Units.Boolean, "assigned_control_variables.wind_angle.active"),
|
|
171
|
+
("Velocity", Units.Boolean, "assigned_control_variables.velocity.active"),
|
|
172
|
+
("Acceleration", Units.Boolean, "assigned_control_variables.acceleration.active"),
|
|
173
|
+
("Altitude", Units.Boolean, "assigned_control_variables.altitude.active"),
|
|
174
|
+
],
|
|
175
|
+
"Control Surfaces": [
|
|
176
|
+
("Elevator Deflection", Units.Boolean, "assigned_control_variables.elevator_deflection.active"),
|
|
177
|
+
("Rudder Deflection", Units.Boolean, "assigned_control_variables.rudder_deflection.active"),
|
|
178
|
+
("Flap Deflection", Units.Boolean, "assigned_control_variables.flap_deflection.active"),
|
|
179
|
+
("Slat Deflection", Units.Boolean, "assigned_control_variables.slat_deflection.active"),
|
|
180
|
+
("Aileron Deflection", Units.Boolean, "assigned_control_variables.aileron_deflection.active"),
|
|
181
|
+
],
|
|
182
|
+
"Propulsion": [
|
|
183
|
+
("Throttle", Units.Boolean, "assigned_control_variables.throttle.active"),
|
|
184
|
+
("Thrust Vector Angle", Units.Boolean, "assigned_control_variables.thrust_vector_angle.active"),
|
|
185
|
+
],
|
|
186
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/mission/widgets/mission_analysis_widget.py
|
|
2
|
+
|
|
3
|
+
# Created: May 2023, M. Clarke
|
|
4
|
+
# ------------------------------------------------------------------------------
|
|
5
|
+
# Imports
|
|
6
|
+
# ------------------------------------------------------------------------------
|
|
7
|
+
from PyQt6.QtCore import Qt
|
|
8
|
+
from PyQt6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QTreeWidget, \
|
|
9
|
+
QTreeWidgetItem, QHeaderView, QPushButton, QLabel
|
|
10
|
+
|
|
11
|
+
from tabs.analysis.widgets import *
|
|
12
|
+
from tabs import TabWidget
|
|
13
|
+
from utilities import create_scroll_area
|
|
14
|
+
import rcaide_io
|
|
15
|
+
import RCAIDE
|
|
16
|
+
|
|
17
|
+
# ============================================================
|
|
18
|
+
# Full Functional Analysis Widget (used by Mission tab)
|
|
19
|
+
# ============================================================
|
|
20
|
+
class MissionAnalysisWidget(TabWidget):
|
|
21
|
+
def __init__(self):
|
|
22
|
+
super(MissionAnalysisWidget, self).__init__()
|
|
23
|
+
|
|
24
|
+
options = [
|
|
25
|
+
"Aerodynamics",
|
|
26
|
+
"Atmospheric",
|
|
27
|
+
"Planets",
|
|
28
|
+
"Weights",
|
|
29
|
+
"Geometry",
|
|
30
|
+
"Energy",
|
|
31
|
+
"Propulsion",
|
|
32
|
+
"Costs",
|
|
33
|
+
"Aeroacoustics",
|
|
34
|
+
"Stability",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
self.tree_frame_layout = QVBoxLayout()
|
|
38
|
+
self.tree_widget = QTreeWidget()
|
|
39
|
+
|
|
40
|
+
save_analysis_button = QPushButton("Save Analyses")
|
|
41
|
+
save_analysis_button.clicked.connect(self.save_analyses)
|
|
42
|
+
|
|
43
|
+
self.tree_frame_layout.addWidget(save_analysis_button)
|
|
44
|
+
self.tree_frame_layout.addWidget(self.tree_widget)
|
|
45
|
+
|
|
46
|
+
self.tree_widget.setColumnCount(2)
|
|
47
|
+
self.tree_widget.setHeaderLabels(["Analysis", "Enabled"])
|
|
48
|
+
header = self.tree_widget.header()
|
|
49
|
+
assert header is not None
|
|
50
|
+
header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
|
|
51
|
+
|
|
52
|
+
for index, option in enumerate(options):
|
|
53
|
+
item = QTreeWidgetItem([option])
|
|
54
|
+
if index > 5:
|
|
55
|
+
item.setCheckState(1, Qt.CheckState.Unchecked)
|
|
56
|
+
else:
|
|
57
|
+
item.setData(1, Qt.ItemDataRole.CheckStateRole, Qt.CheckState.Checked)
|
|
58
|
+
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsUserCheckable & ~Qt.ItemFlag.ItemIsEnabled)
|
|
59
|
+
|
|
60
|
+
self.tree_widget.addTopLevelItem(item)
|
|
61
|
+
|
|
62
|
+
self.tree_widget.itemChanged.connect(self.handleItemChanged)
|
|
63
|
+
|
|
64
|
+
self.base_layout = QHBoxLayout()
|
|
65
|
+
self.base_layout.addLayout(self.tree_frame_layout, 1)
|
|
66
|
+
|
|
67
|
+
self.main_layout = None
|
|
68
|
+
layout_scroll = create_scroll_area(self, False)
|
|
69
|
+
self.base_layout.addLayout(layout_scroll, 4)
|
|
70
|
+
|
|
71
|
+
assert self.main_layout is not None and isinstance(self.main_layout, QVBoxLayout)
|
|
72
|
+
|
|
73
|
+
self.analysis_widgets = [
|
|
74
|
+
AerodynamicsWidget,
|
|
75
|
+
AtmosphereWidget,
|
|
76
|
+
PlanetsWidget,
|
|
77
|
+
WeightsWidget,
|
|
78
|
+
GeometryWidget,
|
|
79
|
+
EnergyWidget,
|
|
80
|
+
PropulsionWidget,
|
|
81
|
+
CostsWidget,
|
|
82
|
+
AeroacousticsWidget,
|
|
83
|
+
StabilityWidget,
|
|
84
|
+
]
|
|
85
|
+
self.widgets = []
|
|
86
|
+
|
|
87
|
+
for index, analysis_widget in enumerate(self.analysis_widgets):
|
|
88
|
+
widget = analysis_widget()
|
|
89
|
+
assert isinstance(widget, AnalysisDataWidget)
|
|
90
|
+
if index >= 5:
|
|
91
|
+
widget.setVisible(False)
|
|
92
|
+
else:
|
|
93
|
+
widget.setVisible(True)
|
|
94
|
+
|
|
95
|
+
self.widgets.append(widget)
|
|
96
|
+
self.main_layout.addWidget(widget)
|
|
97
|
+
|
|
98
|
+
self.main_layout.addStretch()
|
|
99
|
+
self.main_layout.setSpacing(3)
|
|
100
|
+
self.base_layout.setSpacing(3)
|
|
101
|
+
self.setLayout(self.base_layout)
|
|
102
|
+
|
|
103
|
+
# ============================================================
|
|
104
|
+
# Logic for enabling/disabling sub-analyses
|
|
105
|
+
# ============================================================
|
|
106
|
+
def handleItemChanged(self, item, column):
|
|
107
|
+
if column != 1:
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
index = self.tree_widget.indexOfTopLevelItem(item)
|
|
111
|
+
layout_item = self.main_layout.itemAt(index)
|
|
112
|
+
assert layout_item is not None
|
|
113
|
+
widget = layout_item.widget()
|
|
114
|
+
assert widget is not None
|
|
115
|
+
widget.setVisible(item.checkState(1) == Qt.CheckState.Checked)
|
|
116
|
+
|
|
117
|
+
def load_from_values(self):
|
|
118
|
+
if not rcaide_io.analysis_data:
|
|
119
|
+
self.save_analyses()
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
for index, widget in enumerate(self.widgets):
|
|
123
|
+
assert isinstance(widget, AnalysisDataWidget)
|
|
124
|
+
widget.load_values(rcaide_io.analysis_data[index])
|
|
125
|
+
|
|
126
|
+
self.save_analyses()
|
|
127
|
+
|
|
128
|
+
def get_check_state(self, index) -> bool:
|
|
129
|
+
top_level_item = self.tree_widget.topLevelItem(index)
|
|
130
|
+
assert top_level_item is not None
|
|
131
|
+
return top_level_item.checkState(1) == Qt.CheckState.Checked
|
|
132
|
+
|
|
133
|
+
def save_analyses(self):
|
|
134
|
+
if (not getattr(values, "config_data", None) and
|
|
135
|
+
not getattr(values, "rcaide_configs", None)):
|
|
136
|
+
raise RuntimeError(
|
|
137
|
+
"No aircraft configuration data found. "
|
|
138
|
+
"Create a configuration in the Aircraft Configs tab."
|
|
139
|
+
)
|
|
140
|
+
if (not getattr(values, "rcaide_configs", None) or
|
|
141
|
+
not rcaide_io.rcaide_configs):
|
|
142
|
+
from tabs.aircraft_configs.aircraft_configs import build_rcaide_configs_from_geometry
|
|
143
|
+
try:
|
|
144
|
+
rcaide_io.rcaide_configs = build_rcaide_configs_from_geometry()
|
|
145
|
+
except Exception as exc:
|
|
146
|
+
raise RuntimeError(
|
|
147
|
+
"No RCAIDE configurations found. "
|
|
148
|
+
"Save a configuration in the Aircraft Configs tab."
|
|
149
|
+
) from exc
|
|
150
|
+
rcaide_io.analysis_data = []
|
|
151
|
+
rcaide_io.rcaide_analyses = {}
|
|
152
|
+
|
|
153
|
+
# Build and save one RCAIDE analysis container per aircraft configuration.
|
|
154
|
+
for tag, config in rcaide_io.rcaide_configs.items():
|
|
155
|
+
|
|
156
|
+
analyses = RCAIDE.Framework.Analyses.Vehicle()
|
|
157
|
+
analyses.vehicle = config
|
|
158
|
+
|
|
159
|
+
for index, widget in enumerate(self.widgets):
|
|
160
|
+
assert isinstance(widget, AnalysisDataWidget)
|
|
161
|
+
|
|
162
|
+
if self.get_check_state(index):
|
|
163
|
+
analyses.append(widget.create_analysis(config))
|
|
164
|
+
|
|
165
|
+
rcaide_io.rcaide_analyses[tag] = analyses
|
|
166
|
+
rcaide_io.analysis_data.append(analyses)
|