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,259 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/geometry/frames/powertrain/powertrain_frame.py
|
|
2
|
+
#
|
|
3
|
+
# Created: Dec 2025, M. Clarke
|
|
4
|
+
|
|
5
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
6
|
+
# IMPORT
|
|
7
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
8
|
+
import RCAIDE
|
|
9
|
+
from PyQt6.QtCore import Qt
|
|
10
|
+
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QScrollArea, QSpacerItem, QSizePolicy, \
|
|
11
|
+
QPushButton, QLineEdit, QComboBox
|
|
12
|
+
|
|
13
|
+
from tabs.geometry.frames import GeometryFrame
|
|
14
|
+
from tabs.geometry.widgets.powertrain.powertrain_widget import PowertrainWidget
|
|
15
|
+
from utilities import show_popup, clear_layout
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PowertrainFrame(GeometryFrame):
|
|
19
|
+
def __init__(self):
|
|
20
|
+
super(PowertrainFrame, self).__init__()
|
|
21
|
+
|
|
22
|
+
self.data_fields = {}
|
|
23
|
+
self.save_function = None
|
|
24
|
+
self.tab_index = -1
|
|
25
|
+
self.index = -1
|
|
26
|
+
|
|
27
|
+
# Create a scroll area
|
|
28
|
+
scroll_area = QScrollArea()
|
|
29
|
+
# Allow the widget inside to resize with the scroll area
|
|
30
|
+
scroll_area.setWidgetResizable(True)
|
|
31
|
+
|
|
32
|
+
# Create a widget to contain the layout
|
|
33
|
+
scroll_content = QWidget()
|
|
34
|
+
# Set the main layout inside the scroll content
|
|
35
|
+
layout = QVBoxLayout(scroll_content)
|
|
36
|
+
self.powertrain_layout = QVBoxLayout()
|
|
37
|
+
|
|
38
|
+
# Create a horizontal layout for the label and buttons
|
|
39
|
+
header_layout = QHBoxLayout()
|
|
40
|
+
header_layout.addWidget(QLabel("<b>Powertrain</b>"))
|
|
41
|
+
|
|
42
|
+
layout.addLayout(header_layout)
|
|
43
|
+
# Create a horizontal line
|
|
44
|
+
line_bar = QFrame()
|
|
45
|
+
line_bar.setFrameShape(QFrame.Shape.HLine)
|
|
46
|
+
line_bar.setFrameShadow(QFrame.Shadow.Sunken)
|
|
47
|
+
|
|
48
|
+
# Add the line bar to the main layout
|
|
49
|
+
layout.addWidget(line_bar)
|
|
50
|
+
|
|
51
|
+
self.main_powertrain_widget = self.make_powertrain_widget()
|
|
52
|
+
# Add the grid layout to the home layout
|
|
53
|
+
layout.addWidget(self.main_powertrain_widget)
|
|
54
|
+
|
|
55
|
+
layout.addWidget(line_bar)
|
|
56
|
+
layout.addLayout(self.powertrain_layout)
|
|
57
|
+
|
|
58
|
+
self.add_buttons_layout()
|
|
59
|
+
|
|
60
|
+
# Adds scroll function
|
|
61
|
+
layout.addItem(QSpacerItem(
|
|
62
|
+
20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
|
|
63
|
+
|
|
64
|
+
# Set the scroll content as the widget for the scroll area
|
|
65
|
+
scroll_area.setWidget(scroll_content)
|
|
66
|
+
|
|
67
|
+
# Set the main layout of the scroll area
|
|
68
|
+
layout_scroll = QVBoxLayout(self)
|
|
69
|
+
layout_scroll.addWidget(scroll_area)
|
|
70
|
+
|
|
71
|
+
# Set the layout to the main window/widget
|
|
72
|
+
self.setLayout(layout_scroll)
|
|
73
|
+
|
|
74
|
+
# noinspection PyUnresolvedReferences
|
|
75
|
+
def add_buttons_layout(self):
|
|
76
|
+
# define buttons
|
|
77
|
+
save_button = QPushButton("Save Energy Network Data", self)
|
|
78
|
+
# save_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
|
|
79
|
+
delete_button = QPushButton("Clear Energy Network", self)
|
|
80
|
+
delete_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
|
|
81
|
+
|
|
82
|
+
# define action of buttons
|
|
83
|
+
save_button.clicked.connect(self.save_data)
|
|
84
|
+
delete_button.clicked.connect(self.create_new_structure)
|
|
85
|
+
|
|
86
|
+
# Create a QHBoxLayout to contain the buttons
|
|
87
|
+
buttons_layout = QHBoxLayout()
|
|
88
|
+
buttons_layout.addWidget(save_button)
|
|
89
|
+
buttons_layout.addWidget(delete_button)
|
|
90
|
+
|
|
91
|
+
self.powertrain_layout.addLayout(buttons_layout)
|
|
92
|
+
|
|
93
|
+
def make_powertrain_widget(self):
|
|
94
|
+
"""Create a widget for the powertrain section.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
QWidget: The main powertrain widget."""
|
|
98
|
+
main_powertrain_widget = QWidget()
|
|
99
|
+
main_layout = QVBoxLayout()
|
|
100
|
+
name_layout = QHBoxLayout()
|
|
101
|
+
|
|
102
|
+
# add spacing
|
|
103
|
+
spacer_left = QSpacerItem(
|
|
104
|
+
50, 5, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
|
105
|
+
spacer_right = QSpacerItem(
|
|
106
|
+
200, 5, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
|
107
|
+
name_layout.addItem(spacer_left)
|
|
108
|
+
name_layout.addWidget(QLabel("Name: "))
|
|
109
|
+
self.name_line_edit = QLineEdit(self)
|
|
110
|
+
name_layout.addWidget(self.name_line_edit)
|
|
111
|
+
name_layout.addItem(spacer_right)
|
|
112
|
+
|
|
113
|
+
# Energy Network
|
|
114
|
+
energy_label = QLabel("Energy Network Type:")
|
|
115
|
+
energy_label.setFixedWidth(100) # Adjust width of label
|
|
116
|
+
name_layout.addWidget(energy_label)
|
|
117
|
+
self.powertrain_combo = QComboBox()
|
|
118
|
+
self.powertrain_combo.addItems(["Select Network Type", "Fuel", "Electric", "Hybrid", "Hydrogen"])
|
|
119
|
+
self.powertrain_combo.setFixedWidth(400) # Fix width of combo box
|
|
120
|
+
name_layout.addWidget(self.powertrain_combo, alignment=Qt.AlignmentFlag.AlignLeft)
|
|
121
|
+
|
|
122
|
+
# Connect signal
|
|
123
|
+
self.powertrain_combo.currentIndexChanged.connect(self.display_selected_network)
|
|
124
|
+
|
|
125
|
+
main_layout.addLayout(name_layout)
|
|
126
|
+
main_powertrain_widget.setLayout(main_layout)
|
|
127
|
+
return main_powertrain_widget
|
|
128
|
+
|
|
129
|
+
def set_save_function(self, function):
|
|
130
|
+
self.save_function = function
|
|
131
|
+
|
|
132
|
+
def set_tab_index(self, index):
|
|
133
|
+
self.tab_index = index
|
|
134
|
+
|
|
135
|
+
def get_data_values(self):
|
|
136
|
+
"""Retrieve the entered data values from the widgets."""
|
|
137
|
+
selected_network = self.powertrain_combo.currentText()
|
|
138
|
+
data = {"energy network selected": selected_network}
|
|
139
|
+
|
|
140
|
+
assert self.name_line_edit is not None
|
|
141
|
+
data["name"] = self.name_line_edit.text()
|
|
142
|
+
|
|
143
|
+
if selected_network == "Fuel":
|
|
144
|
+
# Add the data values from each fuel line widget to an array
|
|
145
|
+
item = self.powertrain_layout.itemAt(0)
|
|
146
|
+
assert item is not None
|
|
147
|
+
widget = item.widget()
|
|
148
|
+
assert widget is not None and isinstance(widget,PowertrainWidget)
|
|
149
|
+
data_values, net = widget.get_data_values()
|
|
150
|
+
|
|
151
|
+
if isinstance(data_values, bool):
|
|
152
|
+
return False, False
|
|
153
|
+
|
|
154
|
+
# add the fuel line data to the main data
|
|
155
|
+
data["powertrain"] = data_values
|
|
156
|
+
|
|
157
|
+
return data, net
|
|
158
|
+
|
|
159
|
+
def create_rcaide_structure(self):
|
|
160
|
+
selected_network = self.powertrain_combo.currentText()
|
|
161
|
+
if selected_network == "Fuel":
|
|
162
|
+
item = self.powertrain_layout.itemAt(0)
|
|
163
|
+
assert item is not None
|
|
164
|
+
widget = item.widget()
|
|
165
|
+
assert widget is not None and isinstance(widget, PowertrainWidget)
|
|
166
|
+
_, net = widget.get_data_values()
|
|
167
|
+
else:
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
return net
|
|
171
|
+
|
|
172
|
+
def save_data(self):
|
|
173
|
+
"""Call the save function and pass the entered data to it."""
|
|
174
|
+
entered_data, component = self.get_data_values()
|
|
175
|
+
if isinstance(entered_data, bool):
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
if self.save_function:
|
|
179
|
+
if self.index >= 0:
|
|
180
|
+
self.index = self.save_function(
|
|
181
|
+
tab_index=self.tab_index, index=self.index, data=entered_data)
|
|
182
|
+
return
|
|
183
|
+
else:
|
|
184
|
+
self.index = self.save_function(
|
|
185
|
+
tab_index=self.tab_index, vehicle_component=component, data=entered_data, new=True)
|
|
186
|
+
|
|
187
|
+
show_popup("Data Saved!", self)
|
|
188
|
+
|
|
189
|
+
def load_data(self, data, index):
|
|
190
|
+
"""Load the data into the widgets.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
data: The data to be loaded into the widgets.
|
|
194
|
+
index: The index of the data in the list.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
# Load the name into the name line edit
|
|
198
|
+
self.index = index
|
|
199
|
+
assert self.name_line_edit is not None
|
|
200
|
+
self.name_line_edit.setText(data["name"])
|
|
201
|
+
|
|
202
|
+
# Load the selected network into the combo box
|
|
203
|
+
selected_network = data.get("energy network selected", "")
|
|
204
|
+
network_index = self.powertrain_combo.findText(selected_network)
|
|
205
|
+
if network_index != -1:
|
|
206
|
+
self.powertrain_combo.setCurrentIndex(network_index)
|
|
207
|
+
|
|
208
|
+
# Clear existing sections before loading new ones
|
|
209
|
+
clear_layout(self.powertrain_layout)
|
|
210
|
+
|
|
211
|
+
# Load sections based on the selected network
|
|
212
|
+
if selected_network == "Fuel":
|
|
213
|
+
powertrain_widget = PowertrainWidget()
|
|
214
|
+
powertrain_widget.load_data_values(data["powertrain"])
|
|
215
|
+
self.powertrain_layout.addWidget(powertrain_widget)
|
|
216
|
+
|
|
217
|
+
self.add_buttons_layout()
|
|
218
|
+
|
|
219
|
+
def create_new_structure(self):
|
|
220
|
+
"""Create a new powertrain structure."""
|
|
221
|
+
|
|
222
|
+
# Clear the main data values
|
|
223
|
+
for data_field in self.data_fields.values():
|
|
224
|
+
line_edit, unit_picker = data_field
|
|
225
|
+
line_edit.clear()
|
|
226
|
+
unit_picker.set_index(0)
|
|
227
|
+
|
|
228
|
+
# Clear the name line edit
|
|
229
|
+
while self.powertrain_layout.count():
|
|
230
|
+
item = self.powertrain_layout.takeAt(0)
|
|
231
|
+
assert item is not None
|
|
232
|
+
|
|
233
|
+
widget = item.widget()
|
|
234
|
+
assert widget is not None
|
|
235
|
+
widget.deleteLater()
|
|
236
|
+
|
|
237
|
+
assert self.name_line_edit is not None
|
|
238
|
+
self.name_line_edit.clear()
|
|
239
|
+
self.index = -1
|
|
240
|
+
|
|
241
|
+
def delete_data(self):
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
def display_selected_network(self, index):
|
|
245
|
+
selected_network = self.powertrain_combo.currentText()
|
|
246
|
+
# Clear the layout first
|
|
247
|
+
clear_layout(self.powertrain_layout)
|
|
248
|
+
|
|
249
|
+
if selected_network == "Fuel":
|
|
250
|
+
self.main_powertrain_widget = PowertrainWidget()
|
|
251
|
+
self.powertrain_layout.addWidget(self.main_powertrain_widget)
|
|
252
|
+
elif selected_network == "None Selected":
|
|
253
|
+
# Do nothing or add blank widget
|
|
254
|
+
pass
|
|
255
|
+
else:
|
|
256
|
+
# Handle other energy network options here
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
self.add_buttons_layout()
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/geometry/frames/powertrain/propulsors/__init__.py
|
|
2
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
3
|
+
# IMPORT
|
|
4
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
5
|
+
from tabs.geometry.frames.powertrain.propulsors.propulsor_frame import PropulsorFrame
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py
|
|
2
|
+
#
|
|
3
|
+
# Created: Dec 2025, M. Clarke
|
|
4
|
+
|
|
5
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
6
|
+
# IMPORT
|
|
7
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
8
|
+
# RCAIDE imports
|
|
9
|
+
import RCAIDE
|
|
10
|
+
|
|
11
|
+
# PyQT Imports
|
|
12
|
+
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QLineEdit, QHBoxLayout, \
|
|
13
|
+
QSpacerItem, QSizePolicy, QScrollArea, QFrame
|
|
14
|
+
|
|
15
|
+
# RCAIDE GUI imports
|
|
16
|
+
from tabs.geometry.widgets.powertrain.propulsors.turbofan_widget import TurbofanWidget
|
|
17
|
+
from common_widgets import DataEntryWidget
|
|
18
|
+
from utilities import show_popup, create_line_bar, set_data, Units, create_scroll_area, clear_layout
|
|
19
|
+
import rcaide_io
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
|
22
|
+
# Propulsor Frame
|
|
23
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
24
|
+
class PropulsorFrame(QWidget):
|
|
25
|
+
def __init__(self):
|
|
26
|
+
super(PropulsorFrame, self).__init__()
|
|
27
|
+
self.data_entry_widget: DataEntryWidget | None = None
|
|
28
|
+
|
|
29
|
+
# List to store data values propulsor_ sections
|
|
30
|
+
self.propulsor_sections_layout = QVBoxLayout()
|
|
31
|
+
|
|
32
|
+
# Create a horizontal layout for the label and buttons
|
|
33
|
+
header_layout = QVBoxLayout()
|
|
34
|
+
# label = QLabel("<u><b>Propulsor Frame</b></u>")
|
|
35
|
+
|
|
36
|
+
layout = self.create_scroll_layout()
|
|
37
|
+
|
|
38
|
+
# header_layout.addWidget(label)
|
|
39
|
+
|
|
40
|
+
# Add propulsor_ Section Button
|
|
41
|
+
add_turbofan_button = QPushButton("Add Turbofan", self)
|
|
42
|
+
add_turbofan_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
|
|
43
|
+
add_turbofan_button.setMaximumWidth(200)
|
|
44
|
+
add_turbofan_button.clicked.connect(self.add_turbofan)
|
|
45
|
+
header_layout.addWidget(add_turbofan_button)
|
|
46
|
+
|
|
47
|
+
layout.addLayout(header_layout)
|
|
48
|
+
|
|
49
|
+
# Create a horizontal line
|
|
50
|
+
line_bar = QFrame()
|
|
51
|
+
line_bar.setFrameShape(QFrame.Shape.HLine)
|
|
52
|
+
line_bar.setFrameShadow(QFrame.Shadow.Sunken)
|
|
53
|
+
line_bar.setStyleSheet("background-color: light grey;")
|
|
54
|
+
|
|
55
|
+
# Add the line bar to the main layout
|
|
56
|
+
layout.addWidget(line_bar)
|
|
57
|
+
|
|
58
|
+
# Add the layout for additional propulsor_ sections to the main layout
|
|
59
|
+
layout.addLayout(self.propulsor_sections_layout)
|
|
60
|
+
|
|
61
|
+
# Create a QHBoxLayout to contain the buttons
|
|
62
|
+
button_layout = QHBoxLayout()
|
|
63
|
+
|
|
64
|
+
# Add the button layout to the main layout
|
|
65
|
+
layout.addLayout(button_layout)
|
|
66
|
+
|
|
67
|
+
# Adds scroll function
|
|
68
|
+
layout.addItem(QSpacerItem(20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
|
|
69
|
+
|
|
70
|
+
def get_data_values(self):
|
|
71
|
+
"""Retrieve the entered data values from the dictionary for the propulsor sections."""
|
|
72
|
+
|
|
73
|
+
# Collect data from additional fuselage_widget
|
|
74
|
+
data = []
|
|
75
|
+
propulsors = []
|
|
76
|
+
rcaide_io.propulsor_names = [[]]
|
|
77
|
+
for index in range(self.propulsor_sections_layout.count()):
|
|
78
|
+
item = self.propulsor_sections_layout.itemAt(index)
|
|
79
|
+
assert item is not None
|
|
80
|
+
widget = item.widget()
|
|
81
|
+
assert widget is not None and isinstance(widget, TurbofanWidget)
|
|
82
|
+
|
|
83
|
+
propulsor_data, propulsor = widget.get_data_values()
|
|
84
|
+
data.append(propulsor_data)
|
|
85
|
+
propulsors.append(propulsor)
|
|
86
|
+
|
|
87
|
+
return data, propulsors
|
|
88
|
+
|
|
89
|
+
def load_data(self, data):
|
|
90
|
+
while self.propulsor_sections_layout.count():
|
|
91
|
+
item = self.propulsor_sections_layout.takeAt(0)
|
|
92
|
+
assert item is not None
|
|
93
|
+
widget = item.widget()
|
|
94
|
+
assert widget is not None
|
|
95
|
+
|
|
96
|
+
self.propulsor_sections_layout.removeWidget(widget)
|
|
97
|
+
widget.deleteLater()
|
|
98
|
+
|
|
99
|
+
for propulsor_data in data:
|
|
100
|
+
self.propulsor_sections_layout.addWidget(TurbofanWidget(
|
|
101
|
+
self.propulsor_sections_layout.count(), self.on_delete_button_pressed, propulsor_data))
|
|
102
|
+
|
|
103
|
+
def delete_data(self):
|
|
104
|
+
"""Delete the entered data or perform any other action."""
|
|
105
|
+
# TODO: Implement proper deletion of data
|
|
106
|
+
|
|
107
|
+
def add_turbofan(self):
|
|
108
|
+
self.propulsor_sections_layout.addWidget(
|
|
109
|
+
TurbofanWidget(self.propulsor_sections_layout.count(), self.on_delete_button_pressed))
|
|
110
|
+
|
|
111
|
+
def on_delete_button_pressed(self, index):
|
|
112
|
+
propulsor = self.propulsor_sections_layout.itemAt(index)
|
|
113
|
+
if propulsor is None:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
widget = propulsor.widget()
|
|
117
|
+
if widget is None:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
widget.deleteLater()
|
|
121
|
+
self.propulsor_sections_layout.removeWidget(widget)
|
|
122
|
+
self.propulsor_sections_layout.update()
|
|
123
|
+
|
|
124
|
+
for i in range(index, self.propulsor_sections_layout.count()):
|
|
125
|
+
propulsor = self.propulsor_sections_layout.itemAt(i)
|
|
126
|
+
if propulsor is None:
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
widget = propulsor.widget()
|
|
130
|
+
if widget is None or not isinstance(widget, TurbofanWidget):
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
widget.index = i
|
|
134
|
+
|
|
135
|
+
def update_units(self, line_edit, unit_combobox):
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
def create_scroll_layout(self):
|
|
139
|
+
# Create a widget to contain the layout
|
|
140
|
+
scroll_content = QWidget()
|
|
141
|
+
layout = QVBoxLayout(scroll_content) # Set the main layout inside the scroll content
|
|
142
|
+
|
|
143
|
+
# Set the main layout of the widget
|
|
144
|
+
self.setLayout(layout)
|
|
145
|
+
|
|
146
|
+
return layout
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/geometry/frames/powertrain/sources/__init__.py
|
|
2
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
3
|
+
# IMPORT
|
|
4
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
from tabs.geometry.frames.powertrain.sources.energy_source_frame import EnergySourceFrame
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/geometry/frames/powertrain/sources/energy_source_frame.py
|
|
2
|
+
#
|
|
3
|
+
# Created: Dec 2025, M. Clarke
|
|
4
|
+
|
|
5
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
6
|
+
# IMPORT
|
|
7
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
8
|
+
# RCAIDE imports
|
|
9
|
+
import RCAIDE
|
|
10
|
+
|
|
11
|
+
# PyQT Imports
|
|
12
|
+
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QHBoxLayout, \
|
|
13
|
+
QSpacerItem, QSizePolicy, QFrame
|
|
14
|
+
|
|
15
|
+
# RCAIDE GUI imports
|
|
16
|
+
from tabs.geometry.widgets.powertrain.sources.fuel_tank_widget import FuelTankWidget
|
|
17
|
+
from common_widgets import DataEntryWidget
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
|
21
|
+
# Energy Source Frame
|
|
22
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
23
|
+
class EnergySourceFrame(QWidget):
|
|
24
|
+
def __init__(self):
|
|
25
|
+
super(EnergySourceFrame, self).__init__()
|
|
26
|
+
|
|
27
|
+
self.save_function = None
|
|
28
|
+
self.data_entry_widget: DataEntryWidget | None = None
|
|
29
|
+
|
|
30
|
+
# List to store data values source_ sections
|
|
31
|
+
self.source_sections_layout = QVBoxLayout()
|
|
32
|
+
|
|
33
|
+
# Create a horizontal layout for the label and buttons
|
|
34
|
+
header_layout = QVBoxLayout()
|
|
35
|
+
# label = QLabel("<u><b>source Frame</b></u>")
|
|
36
|
+
|
|
37
|
+
layout = self.create_scroll_layout()
|
|
38
|
+
|
|
39
|
+
# header_layout.addWidget(label)
|
|
40
|
+
|
|
41
|
+
# Add source_ Section Button
|
|
42
|
+
add_fuel_tank_button = QPushButton("Add Fuel Tank", self)
|
|
43
|
+
add_fuel_tank_button.setStyleSheet("color:#dbe7ff; font-weight:500; margin:0; padding:0;")
|
|
44
|
+
add_fuel_tank_button.setMaximumWidth(200)
|
|
45
|
+
add_fuel_tank_button.clicked.connect(self.add_fuel_tank)
|
|
46
|
+
|
|
47
|
+
header_layout.addWidget(add_fuel_tank_button)
|
|
48
|
+
|
|
49
|
+
layout.addLayout(header_layout)
|
|
50
|
+
|
|
51
|
+
# Create a horizontal line
|
|
52
|
+
line_bar = QFrame()
|
|
53
|
+
line_bar.setFrameShape(QFrame.Shape.HLine)
|
|
54
|
+
line_bar.setFrameShadow(QFrame.Shadow.Sunken)
|
|
55
|
+
line_bar.setStyleSheet("background-color: light grey;")
|
|
56
|
+
|
|
57
|
+
# Add the line bar to the main layout
|
|
58
|
+
layout.addWidget(line_bar)
|
|
59
|
+
|
|
60
|
+
# Add the layout for additional source_ sections to the main layout
|
|
61
|
+
layout.addLayout(self.source_sections_layout)
|
|
62
|
+
|
|
63
|
+
# Create a QHBoxLayout to contain the buttons
|
|
64
|
+
button_layout = QHBoxLayout()
|
|
65
|
+
|
|
66
|
+
# Add the button layout to the main layout
|
|
67
|
+
layout.addLayout(button_layout)
|
|
68
|
+
|
|
69
|
+
# Adds scroll function
|
|
70
|
+
layout.addItem(QSpacerItem(
|
|
71
|
+
20, 40, QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding))
|
|
72
|
+
|
|
73
|
+
def get_data_values(self):
|
|
74
|
+
data = []
|
|
75
|
+
sources = []
|
|
76
|
+
for index in range(self.source_sections_layout.count()):
|
|
77
|
+
item = self.source_sections_layout.itemAt(index)
|
|
78
|
+
assert item is not None
|
|
79
|
+
widget = item.widget()
|
|
80
|
+
assert widget is not None and isinstance(widget, FuelTankWidget)
|
|
81
|
+
|
|
82
|
+
source_data, fuel_tank = widget.get_data_values()
|
|
83
|
+
data.append(source_data)
|
|
84
|
+
sources.append(fuel_tank)
|
|
85
|
+
|
|
86
|
+
return data, sources
|
|
87
|
+
|
|
88
|
+
def load_data(self, data):
|
|
89
|
+
while self.source_sections_layout.count():
|
|
90
|
+
widget_item = self.source_sections_layout.itemAt(0)
|
|
91
|
+
assert widget_item is not None
|
|
92
|
+
widget = widget_item.widget()
|
|
93
|
+
assert widget is not None
|
|
94
|
+
|
|
95
|
+
self.source_sections_layout.removeWidget(widget)
|
|
96
|
+
widget.deleteLater()
|
|
97
|
+
|
|
98
|
+
for section_data in data:
|
|
99
|
+
self.source_sections_layout.addWidget(FuelTankWidget(
|
|
100
|
+
self.source_sections_layout.count(), self.on_delete_button_pressed, section_data))
|
|
101
|
+
|
|
102
|
+
def delete_data(self):
|
|
103
|
+
# TODO Implement proper deletion of data
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
def add_fuel_tank(self):
|
|
107
|
+
self.source_sections_layout.addWidget(
|
|
108
|
+
FuelTankWidget(self.source_sections_layout.count(), self.on_delete_button_pressed))
|
|
109
|
+
|
|
110
|
+
def on_delete_button_pressed(self, index):
|
|
111
|
+
tank = self.source_sections_layout.itemAt(index)
|
|
112
|
+
if tank is None:
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
widget = tank.widget()
|
|
116
|
+
if widget is None:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
widget.deleteLater()
|
|
120
|
+
self.source_sections_layout.removeWidget(widget)
|
|
121
|
+
self.source_sections_layout.update()
|
|
122
|
+
|
|
123
|
+
for i in range(index, self.source_sections_layout.count()):
|
|
124
|
+
tank = self.source_sections_layout.itemAt(i)
|
|
125
|
+
if tank is None:
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
widget = tank.widget()
|
|
129
|
+
if widget is None or not isinstance(widget, FuelTankWidget):
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
widget.index = i
|
|
133
|
+
|
|
134
|
+
def set_save_function(self, function):
|
|
135
|
+
self.save_function = function
|
|
136
|
+
|
|
137
|
+
def create_scroll_layout(self):
|
|
138
|
+
# Create a widget to contain the layout
|
|
139
|
+
scroll_content = QWidget()
|
|
140
|
+
|
|
141
|
+
# Set the main layout inside the scroll content
|
|
142
|
+
layout = QVBoxLayout(scroll_content)
|
|
143
|
+
|
|
144
|
+
# Set the main layout of the widget
|
|
145
|
+
self.setLayout(layout)
|
|
146
|
+
|
|
147
|
+
return layout
|