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,731 @@
|
|
|
1
|
+
# RCAIDE_GUI/tabs/visualize_geometry/core_3d_viewer.py
|
|
2
|
+
|
|
3
|
+
# RCAIDE Imports
|
|
4
|
+
import RCAIDE
|
|
5
|
+
from RCAIDE.Framework.Core import Units
|
|
6
|
+
from RCAIDE.Library.Components.Airfoils import Airfoil
|
|
7
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_wing_points import *
|
|
8
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_fuselage_points import *
|
|
9
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_fuel_tank_points import *
|
|
10
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_nacelle_points import *
|
|
11
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_cargo_bay_points import generate_3d_cargo_bay_points
|
|
12
|
+
from RCAIDE.Library.Plots.Geometry.generate_3d_lopa_points import generate_3d_lopa_points
|
|
13
|
+
from RCAIDE.Library.Plots.Geometry.plot_3d_rotor import generate_3d_blade_points, generate_vtk_object
|
|
14
|
+
from RCAIDE.Library.Plots.Geometry.plot_3d_vehicle import add_lopa_seats
|
|
15
|
+
from RCAIDE.Library.Methods.Geometry.Planform import fuselage_planform, wing_planform, compute_fuel_volume
|
|
16
|
+
from RCAIDE.Library.Methods.Geometry.LOPA import compute_layout_of_passenger_accommodations
|
|
17
|
+
|
|
18
|
+
# PyQt imports
|
|
19
|
+
from PyQt6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QTreeWidget, QPushButton, QTreeWidgetItem, QHeaderView, QLabel, QToolBar, QColorDialog, QSpacerItem, QSizePolicy, QFrame, QLineEdit
|
|
20
|
+
from PyQt6.QtCore import Qt
|
|
21
|
+
from tabs import TabWidget
|
|
22
|
+
from pyvistaqt import QtInteractor
|
|
23
|
+
from PyQt6.QtGui import QIcon
|
|
24
|
+
|
|
25
|
+
# Python imports
|
|
26
|
+
import matplotlib.colors as mcolors
|
|
27
|
+
import pyvista as pv
|
|
28
|
+
import numpy as np
|
|
29
|
+
import rcaide_io
|
|
30
|
+
import os
|
|
31
|
+
from copy import deepcopy
|
|
32
|
+
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
|
|
33
|
+
|
|
34
|
+
# ------------------------------------------------------------------------------
|
|
35
|
+
# make_object
|
|
36
|
+
# ------------------------------------------------------------------------------
|
|
37
|
+
class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
38
|
+
def __init__(self, parent=None):
|
|
39
|
+
super().__init__()
|
|
40
|
+
self.AddObserver("KeyPressEvent", self.on_key_press) # type: ignore
|
|
41
|
+
|
|
42
|
+
def on_key_press(self, obj, event):
|
|
43
|
+
key = self.GetInteractor().GetKeySym()
|
|
44
|
+
camera = self.GetInteractor().GetRenderWindow(
|
|
45
|
+
).GetRenderers().GetFirstRenderer().GetActiveCamera()
|
|
46
|
+
|
|
47
|
+
# Example custom camera controls
|
|
48
|
+
if key == "Down":
|
|
49
|
+
camera.Pitch(10) # Pitch up by 10 degrees
|
|
50
|
+
elif key == "Up":
|
|
51
|
+
camera.Pitch(-10) # Pitch down by 10 degrees
|
|
52
|
+
elif key == "Left":
|
|
53
|
+
camera.Yaw(-10) # Yaw left by 10 degrees
|
|
54
|
+
elif key == "Right":
|
|
55
|
+
camera.Yaw(10) # Yaw right by 10 degrees
|
|
56
|
+
|
|
57
|
+
self.GetInteractor().GetRenderWindow().Render() # Render the changes
|
|
58
|
+
|
|
59
|
+
_DEFAULT_OPACITY = {
|
|
60
|
+
"Fuselages": 0.5,
|
|
61
|
+
"Wings": 0.5,
|
|
62
|
+
"Nacelles": 1.0,
|
|
63
|
+
"Rotors": 0.6,
|
|
64
|
+
"Booms": 1.0,
|
|
65
|
+
"Fuel Tanks": 0.5,
|
|
66
|
+
"Cargo Bays": 0.6,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class ColorBar(QWidget):
|
|
70
|
+
def __init__(self, parts_dict, color_changed):
|
|
71
|
+
super().__init__()
|
|
72
|
+
self.setFixedWidth(180)
|
|
73
|
+
|
|
74
|
+
self.layout = QVBoxLayout()
|
|
75
|
+
self.layout.setContentsMargins(0, 5, 5, 0)
|
|
76
|
+
self.layout.setSpacing(10)
|
|
77
|
+
self.setLayout(self.layout)
|
|
78
|
+
|
|
79
|
+
self.part_controls = {}
|
|
80
|
+
self.color_changed = color_changed
|
|
81
|
+
|
|
82
|
+
for index, part_name in enumerate(parts_dict):
|
|
83
|
+
# Set colorbar label
|
|
84
|
+
title = QLabel(part_name)
|
|
85
|
+
self.layout.addWidget(title)
|
|
86
|
+
|
|
87
|
+
# Set Transparency
|
|
88
|
+
opacity_row = QHBoxLayout()
|
|
89
|
+
opacity_label = QLabel("Transparency:")
|
|
90
|
+
default_opacity = _DEFAULT_OPACITY.get(part_name, 1.0)
|
|
91
|
+
opacity_input = QLineEdit(f"{default_opacity:.2f}")
|
|
92
|
+
opacity_input.setFixedWidth(50)
|
|
93
|
+
opacity_input.setStyleSheet("background-color: white; color: black;")
|
|
94
|
+
opacity_input.editingFinished.connect(
|
|
95
|
+
lambda name=part_name, box=opacity_input: self.opacity_changed(name, box)
|
|
96
|
+
)
|
|
97
|
+
opacity_row.addWidget(opacity_label)
|
|
98
|
+
opacity_row.addWidget(opacity_input)
|
|
99
|
+
self.layout.addLayout(opacity_row)
|
|
100
|
+
|
|
101
|
+
# Set color
|
|
102
|
+
color_row = QHBoxLayout()
|
|
103
|
+
color_label = QLabel("Color:")
|
|
104
|
+
color_label.setStyleSheet("color: white;")
|
|
105
|
+
color_buttom = QPushButton()
|
|
106
|
+
color_buttom.setFixedSize(30, 20)
|
|
107
|
+
color_buttom.setStyleSheet("background-color: #d3d3d3; border: 1px solid #888;")
|
|
108
|
+
color_buttom.clicked.connect(lambda _, name=part_name: self.pick_color(name))
|
|
109
|
+
color_row.addWidget(color_label)
|
|
110
|
+
color_row.addWidget(color_buttom)
|
|
111
|
+
self.layout.addLayout(color_row)
|
|
112
|
+
|
|
113
|
+
#Put all buttom and opacity variable in part_controls make it easy to find
|
|
114
|
+
self.part_controls[part_name] = {
|
|
115
|
+
"opacity_input": opacity_input,
|
|
116
|
+
"color_buttom": color_buttom
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#add separate line
|
|
120
|
+
if index < len(parts_dict)-1:
|
|
121
|
+
line = QFrame()
|
|
122
|
+
line.setFrameShape(QFrame.Shape.HLine)
|
|
123
|
+
line.setFrameShadow(QFrame.Shadow.Sunken)
|
|
124
|
+
self.layout.addWidget(line)
|
|
125
|
+
|
|
126
|
+
# Spacer to push everything up
|
|
127
|
+
self.layout.addSpacerItem(QSpacerItem(10, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding))
|
|
128
|
+
|
|
129
|
+
def pick_color(self, part_name):
|
|
130
|
+
color = QColorDialog.getColor(options=QColorDialog.ColorDialogOption.ShowAlphaChannel)
|
|
131
|
+
buttom = self.part_controls[part_name]["color_buttom"]
|
|
132
|
+
buttom.setStyleSheet(f"background-color: {color.name()}; border: 1px solid #888;")
|
|
133
|
+
self.color_changed(part_name, color=color)
|
|
134
|
+
|
|
135
|
+
def opacity_changed(self, part_name, edit_val):
|
|
136
|
+
if edit_val:
|
|
137
|
+
val = float(edit_val.text())
|
|
138
|
+
val = max(0.0, min(1.0, val))
|
|
139
|
+
else:
|
|
140
|
+
val = 1.0
|
|
141
|
+
edit_val.setText(f"{val:.2f}")
|
|
142
|
+
self.color_changed(part_name, opacity=val)
|
|
143
|
+
|
|
144
|
+
def update_parts(self, new_parts_dict):
|
|
145
|
+
# After load the geometry, upload the color buttom and opacity value
|
|
146
|
+
for part_name, actors in new_parts_dict.items():
|
|
147
|
+
enabled = bool(actors)
|
|
148
|
+
controls = self.part_controls.get(part_name, {})
|
|
149
|
+
if controls:
|
|
150
|
+
# Make the function work
|
|
151
|
+
controls["opacity_input"].setEnabled(enabled)
|
|
152
|
+
controls["color_buttom"].setEnabled(enabled)
|
|
153
|
+
# Reset to per-component default
|
|
154
|
+
controls["opacity_input"].setText(f"{_DEFAULT_OPACITY.get(part_name, 1.0):.2f}")
|
|
155
|
+
if part_name == "Fuselage":
|
|
156
|
+
controls["color_buttom"].setStyleSheet("background-color: #648eee; border: 1px solid #888;")
|
|
157
|
+
else:
|
|
158
|
+
controls["color_buttom"].setStyleSheet("background-color: #d3d3d3; border: 1px solid #888;")
|
|
159
|
+
|
|
160
|
+
class CustomPanInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
161
|
+
def __init__(self, parent=None):
|
|
162
|
+
super().__init__()
|
|
163
|
+
self.AddObserver("MouseMoveEvent", self.on_mouse_move) # moniter the mouse move
|
|
164
|
+
self.AddObserver("LeftButtonPressEvent", self.on_left_button_down)
|
|
165
|
+
self.AddObserver("LeftButtonReleaseEvent", self.on_left_button_up)
|
|
166
|
+
self.is_panning = False
|
|
167
|
+
self.last_x = None
|
|
168
|
+
self.last_y = None
|
|
169
|
+
|
|
170
|
+
def on_left_button_down(self, obj, event):
|
|
171
|
+
interactor = self.GetInteractor()
|
|
172
|
+
self.last_x, self.last_y = interactor.GetEventPosition()
|
|
173
|
+
self.is_panning = True
|
|
174
|
+
self.OnLeftButtonDown()
|
|
175
|
+
|
|
176
|
+
def on_left_button_up(self, obj, event):
|
|
177
|
+
self.is_panning = False
|
|
178
|
+
self.OnLeftButtonUp()
|
|
179
|
+
|
|
180
|
+
def on_mouse_move(self, obj, event):
|
|
181
|
+
if not self.is_panning:
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
interactor = self.GetInteractor()
|
|
185
|
+
current_x, current_y = interactor.GetEventPosition()
|
|
186
|
+
|
|
187
|
+
dx = current_x - self.last_x
|
|
188
|
+
dy = current_y - self.last_y
|
|
189
|
+
|
|
190
|
+
renderer = self.GetDefaultRenderer()
|
|
191
|
+
camera = renderer.GetActiveCamera()
|
|
192
|
+
|
|
193
|
+
step_size = 0.02
|
|
194
|
+
focal_point = list(camera.GetFocalPoint())
|
|
195
|
+
|
|
196
|
+
focal_point[0] -= dx * step_size
|
|
197
|
+
focal_point[1] += dy * step_size
|
|
198
|
+
|
|
199
|
+
camera.SetFocalPoint(focal_point)
|
|
200
|
+
|
|
201
|
+
self.last_x = current_x
|
|
202
|
+
self.last_y = current_y
|
|
203
|
+
|
|
204
|
+
interactor.GetRenderWindow().Render()
|
|
205
|
+
|
|
206
|
+
class VisualizeGeometryWidget(TabWidget):
|
|
207
|
+
def __init__(self, show_lopa=True, show_fuel_tanks=True, show_cargo_bays=True, start_interactor=True):
|
|
208
|
+
super(VisualizeGeometryWidget, self).__init__()
|
|
209
|
+
self._show_lopa = show_lopa
|
|
210
|
+
self._show_fuel_tanks = show_fuel_tanks
|
|
211
|
+
self._show_cargo_bays = show_cargo_bays
|
|
212
|
+
# Embedded previews should not start their own VTK event loop.
|
|
213
|
+
self._start_interactor = start_interactor
|
|
214
|
+
|
|
215
|
+
base_layout = QHBoxLayout()
|
|
216
|
+
tree_layout = QVBoxLayout()
|
|
217
|
+
main_layout = QVBoxLayout()
|
|
218
|
+
graph_layout = QHBoxLayout()
|
|
219
|
+
|
|
220
|
+
# self.label = QLabel("Click Display Button to View VTK")
|
|
221
|
+
# main_layout.addWidget(self.label)
|
|
222
|
+
|
|
223
|
+
self.render_window_interactor = None
|
|
224
|
+
self.renderer = None
|
|
225
|
+
self.get_camera = None
|
|
226
|
+
self.pen_style = False
|
|
227
|
+
|
|
228
|
+
self.wing_actors = []
|
|
229
|
+
self.fuselage_actors = []
|
|
230
|
+
self.nacelle_actors = []
|
|
231
|
+
self.rotor_actors = []
|
|
232
|
+
self.boom_actors = []
|
|
233
|
+
self.fuel_tank_actors = []
|
|
234
|
+
self.cargo_bay_actors = []
|
|
235
|
+
|
|
236
|
+
solve_button = QPushButton("Display")
|
|
237
|
+
solve_button.clicked.connect(self.run_solve)
|
|
238
|
+
|
|
239
|
+
self.tree = QTreeWidget()
|
|
240
|
+
self.init_tree()
|
|
241
|
+
tree_layout.addWidget(solve_button)
|
|
242
|
+
tree_layout.addWidget(self.tree)
|
|
243
|
+
|
|
244
|
+
# base_layout.addLayout(tree_layout, 3)
|
|
245
|
+
base_layout.addLayout(main_layout)
|
|
246
|
+
|
|
247
|
+
# add toolbar
|
|
248
|
+
main_layout.addWidget(self.add_toolbar())
|
|
249
|
+
|
|
250
|
+
# Creating PyVista Qt widget
|
|
251
|
+
self.plotter = QtInteractor(self)
|
|
252
|
+
self.vtkWidget = self.plotter # alias so feature files keep working
|
|
253
|
+
|
|
254
|
+
self.colorbar_widget = None
|
|
255
|
+
graph_layout.addWidget(self.colorbar())
|
|
256
|
+
graph_layout.addWidget(self.plotter)
|
|
257
|
+
|
|
258
|
+
graph_widget = QWidget()
|
|
259
|
+
graph_widget.setLayout(graph_layout)
|
|
260
|
+
main_layout.addWidget(graph_widget)
|
|
261
|
+
|
|
262
|
+
base_widget = QWidget()
|
|
263
|
+
base_widget.setLayout(base_layout)
|
|
264
|
+
|
|
265
|
+
self.setLayout(base_layout)
|
|
266
|
+
|
|
267
|
+
# Store selected option
|
|
268
|
+
self.selected_option = None
|
|
269
|
+
|
|
270
|
+
def colorbar(self):
|
|
271
|
+
self.part_actors = {
|
|
272
|
+
"Fuselages": self.fuselage_actors,
|
|
273
|
+
"Wings": self.wing_actors,
|
|
274
|
+
"Nacelles": self.nacelle_actors,
|
|
275
|
+
"Rotors": self.rotor_actors,
|
|
276
|
+
"Booms": self.boom_actors,
|
|
277
|
+
"Fuel Tanks": self.fuel_tank_actors,
|
|
278
|
+
"Cargo Bays": self.cargo_bay_actors,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
def color_changed(part_name, color=None, opacity=None):
|
|
282
|
+
for actor in self.part_actors.get(part_name, []):
|
|
283
|
+
temp = actor.GetProperty()
|
|
284
|
+
if color:
|
|
285
|
+
temp.SetColor(color.redF(), color.greenF(), color.blueF())
|
|
286
|
+
temp.SetOpacity(color.alphaF())
|
|
287
|
+
if opacity is not None:
|
|
288
|
+
temp.SetOpacity(opacity)
|
|
289
|
+
self.vtkWidget.GetRenderWindow().Render()
|
|
290
|
+
|
|
291
|
+
self.colorbar_widget = ColorBar(self.part_actors, color_changed)
|
|
292
|
+
self.colorbar_widget.setFixedWidth(180)
|
|
293
|
+
return self.colorbar_widget
|
|
294
|
+
|
|
295
|
+
def add_toolbar(self):
|
|
296
|
+
self.toolbar = QToolBar("Tools")
|
|
297
|
+
|
|
298
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
299
|
+
|
|
300
|
+
self.pan_button = QPushButton("Pan")
|
|
301
|
+
self.pan_button.setToolTip("Pan Mode")
|
|
302
|
+
|
|
303
|
+
self.zoom_in_button = QPushButton("Zoom In")
|
|
304
|
+
self.zoom_in_button.setToolTip("Zoom In")
|
|
305
|
+
|
|
306
|
+
self.zoom_out_button = QPushButton("Zoom Out")
|
|
307
|
+
self.zoom_out_button.setToolTip("Zoom Out")
|
|
308
|
+
|
|
309
|
+
self.front_button = QPushButton("Front")
|
|
310
|
+
self.front_button.setToolTip("Front")
|
|
311
|
+
|
|
312
|
+
self.side_button = QPushButton("Side")
|
|
313
|
+
self.side_button.setToolTip("Side")
|
|
314
|
+
|
|
315
|
+
self.top_button = QPushButton("Top")
|
|
316
|
+
self.top_button.setToolTip("Top")
|
|
317
|
+
|
|
318
|
+
self.isometric_button = QPushButton("Isometric")
|
|
319
|
+
self.isometric_button.setToolTip("Isometric")
|
|
320
|
+
|
|
321
|
+
# Add buttons to toolbar
|
|
322
|
+
self.toolbar.addWidget(self.pan_button)
|
|
323
|
+
self.toolbar.addWidget(self.zoom_in_button)
|
|
324
|
+
self.toolbar.addWidget(self.zoom_out_button)
|
|
325
|
+
self.toolbar.addWidget(self.front_button)
|
|
326
|
+
self.toolbar.addWidget(self.side_button)
|
|
327
|
+
self.toolbar.addWidget(self.top_button)
|
|
328
|
+
self.toolbar.addWidget(self.isometric_button)
|
|
329
|
+
|
|
330
|
+
return self.toolbar
|
|
331
|
+
|
|
332
|
+
def enable_pan_mode(self):
|
|
333
|
+
if self.pen_style:
|
|
334
|
+
custom_style = CustomInteractorStyle()
|
|
335
|
+
self.render_window_interactor.SetInteractorStyle(custom_style)
|
|
336
|
+
self.reset_camera_focus_to_center()
|
|
337
|
+
self.pen_style = False
|
|
338
|
+
else:
|
|
339
|
+
pan_style = CustomPanInteractorStyle()
|
|
340
|
+
pan_style.SetDefaultRenderer(self.renderer)
|
|
341
|
+
self.render_window_interactor.SetInteractorStyle(pan_style)
|
|
342
|
+
self.pen_style = True
|
|
343
|
+
self.render_window_interactor.Initialize()
|
|
344
|
+
self.render_window_interactor.Render()
|
|
345
|
+
|
|
346
|
+
def reset_camera_focus_to_center(self):
|
|
347
|
+
# Gets the boundaries of all objects in the scene
|
|
348
|
+
bounds = self.renderer.ComputeVisiblePropBounds()
|
|
349
|
+
|
|
350
|
+
center_x = (bounds[0] + bounds[1]) / 2
|
|
351
|
+
center_y = (bounds[2] + bounds[3]) / 2
|
|
352
|
+
center_z = (bounds[4] + bounds[5]) / 2
|
|
353
|
+
|
|
354
|
+
camera = self.renderer.GetActiveCamera()
|
|
355
|
+
camera.SetFocalPoint(center_x, center_y, center_z)
|
|
356
|
+
|
|
357
|
+
def zoom_in(self):
|
|
358
|
+
self.get_camera.Zoom(1.2)
|
|
359
|
+
self.vtkWidget.GetRenderWindow().Render()
|
|
360
|
+
|
|
361
|
+
def zoom_out(self):
|
|
362
|
+
self.get_camera.Zoom(0.8)
|
|
363
|
+
self.vtkWidget.GetRenderWindow().Render()
|
|
364
|
+
|
|
365
|
+
def set_view_function(self, Postion, Videup):
|
|
366
|
+
self.get_camera.SetFocalPoint(0, 0, 0)
|
|
367
|
+
self.get_camera.SetPosition(*Postion)
|
|
368
|
+
self.get_camera.SetViewUp(*Videup)
|
|
369
|
+
self.renderer.ResetCamera()
|
|
370
|
+
self.get_camera.Zoom(1.5)
|
|
371
|
+
self.reset_camera_focus_to_center()
|
|
372
|
+
self.vtkWidget.GetRenderWindow().Render()
|
|
373
|
+
|
|
374
|
+
def front_function(self):
|
|
375
|
+
bounds = self.renderer.ComputeVisiblePropBounds()
|
|
376
|
+
self.set_view_function((-(bounds[1]-bounds[0])/2, 0, 0),(0, 0, 1))
|
|
377
|
+
|
|
378
|
+
def side_function(self):
|
|
379
|
+
bounds = self.renderer.ComputeVisiblePropBounds()
|
|
380
|
+
self.set_view_function((0, -(bounds[3]-bounds[2]), 0),(0, 0, 1))
|
|
381
|
+
|
|
382
|
+
def top_function(self):
|
|
383
|
+
bounds = self.renderer.ComputeVisiblePropBounds()
|
|
384
|
+
self.set_view_function((0, 0, (bounds[3]-bounds[2])),(0, 1, 0))
|
|
385
|
+
|
|
386
|
+
def isometric_function(self):
|
|
387
|
+
bounds = self.renderer.ComputeVisiblePropBounds()
|
|
388
|
+
self.set_view_function((-bounds[5], -bounds[5], bounds[5]),(0, 0, 1))
|
|
389
|
+
|
|
390
|
+
def init_tree(self):
|
|
391
|
+
self.tree.setColumnCount(1)
|
|
392
|
+
self.tree.setHeaderLabels(["Plot Options"])
|
|
393
|
+
|
|
394
|
+
header = self.tree.header()
|
|
395
|
+
assert header is not None
|
|
396
|
+
header.setSectionResizeMode(
|
|
397
|
+
0, QHeaderView.ResizeMode.ResizeToContents)
|
|
398
|
+
|
|
399
|
+
for category, options in self.plot_options.items():
|
|
400
|
+
category_item = QTreeWidgetItem([category])
|
|
401
|
+
self.tree.addTopLevelItem(category_item)
|
|
402
|
+
for option in options:
|
|
403
|
+
option_item = QTreeWidgetItem([option])
|
|
404
|
+
category_item.addChild(option_item)
|
|
405
|
+
|
|
406
|
+
# Connect signal for item selection
|
|
407
|
+
self.tree.itemClicked.connect(self.on_item_clicked)
|
|
408
|
+
|
|
409
|
+
def on_item_clicked(self, item, column):
|
|
410
|
+
# Ensure only one selection at a time
|
|
411
|
+
parent = item.parent()
|
|
412
|
+
if parent:
|
|
413
|
+
for i in range(parent.childCount()):
|
|
414
|
+
parent.child(i).setSelected(False)
|
|
415
|
+
item.setSelected(True)
|
|
416
|
+
self.selected_option = item.text(0)
|
|
417
|
+
|
|
418
|
+
def run_solve(self):
|
|
419
|
+
wing_color = 'grey'
|
|
420
|
+
fuselage_color = 'grey'
|
|
421
|
+
nacelle_color = 'grey'
|
|
422
|
+
boom_color = 'grey'
|
|
423
|
+
fuel_tank_color = 'orange'
|
|
424
|
+
rotor_color = 'black'
|
|
425
|
+
cargo_bay_color = 'blue'
|
|
426
|
+
wing_opacity = 0.5
|
|
427
|
+
fuselage_opacity = 0.5
|
|
428
|
+
nacelle_opacity = 1.0
|
|
429
|
+
fuel_tank_opacity = 0.5
|
|
430
|
+
rotor_opacity = 0.6
|
|
431
|
+
number_of_airfoil_points = 101
|
|
432
|
+
tessellation = 96
|
|
433
|
+
boom_opacity = 1.0
|
|
434
|
+
cargo_bay_opacity = 0.6
|
|
435
|
+
lopa_opacity = 1.0
|
|
436
|
+
camera_eye_x = -1
|
|
437
|
+
camera_eye_y = -1
|
|
438
|
+
camera_eye_z = 0.35
|
|
439
|
+
|
|
440
|
+
fuel_tank_rgb_color = mcolors.to_rgb(fuel_tank_color)
|
|
441
|
+
wing_rgb_color = mcolors.to_rgb(wing_color)
|
|
442
|
+
fuselage_rgb_color = mcolors.to_rgb(fuselage_color)
|
|
443
|
+
nacelle_rgb_color = mcolors.to_rgb(nacelle_color)
|
|
444
|
+
rotor_rgb_color = mcolors.to_rgb(rotor_color)
|
|
445
|
+
boom_rgb_color = mcolors.to_rgb(boom_color)
|
|
446
|
+
cargo_bay_rgb_color = mcolors.to_rgb(cargo_bay_color)
|
|
447
|
+
|
|
448
|
+
# Clear previous scene and actor lists
|
|
449
|
+
if self.renderer is not None:
|
|
450
|
+
self.renderer.RemoveAllViewProps()
|
|
451
|
+
self.wing_actors.clear()
|
|
452
|
+
self.fuselage_actors.clear()
|
|
453
|
+
self.nacelle_actors.clear()
|
|
454
|
+
self.rotor_actors.clear()
|
|
455
|
+
self.boom_actors.clear()
|
|
456
|
+
self.fuel_tank_actors.clear()
|
|
457
|
+
self.cargo_bay_actors.clear()
|
|
458
|
+
|
|
459
|
+
self.renderer = self.plotter.renderer
|
|
460
|
+
self.render_window_interactor = self.vtkWidget.GetRenderWindow().GetInteractor()
|
|
461
|
+
|
|
462
|
+
# Number of points for airfoil
|
|
463
|
+
geometry = deepcopy(rcaide_io.vehicle)
|
|
464
|
+
|
|
465
|
+
# -------------------------------------------------------------------------
|
|
466
|
+
# Run Geoemtry Analysis Functions
|
|
467
|
+
# -------------------------------------------------------------------------
|
|
468
|
+
for wing in geometry.wings:
|
|
469
|
+
if isinstance(wing, RCAIDE.Library.Components.Wings.Blended_Wing_Body):
|
|
470
|
+
wing_planform(wing)
|
|
471
|
+
if self._show_lopa:
|
|
472
|
+
compute_layout_of_passenger_accommodations(wing)
|
|
473
|
+
else:
|
|
474
|
+
wing_planform(wing)
|
|
475
|
+
|
|
476
|
+
if self._show_fuel_tanks:
|
|
477
|
+
compute_fuel_volume(geometry)
|
|
478
|
+
|
|
479
|
+
for fuselage in geometry.fuselages:
|
|
480
|
+
if self._show_lopa:
|
|
481
|
+
compute_layout_of_passenger_accommodations(fuselage)
|
|
482
|
+
fuselage_planform(fuselage)
|
|
483
|
+
|
|
484
|
+
# -------------------------------------------------------------------------
|
|
485
|
+
# Plot wings
|
|
486
|
+
# -------------------------------------------------------------------------
|
|
487
|
+
for wing in geometry.wings:
|
|
488
|
+
n_segments = len(wing.segments)
|
|
489
|
+
dim = n_segments if n_segments > 0 else 2
|
|
490
|
+
GEOM = generate_3d_wing_points(wing, number_of_airfoil_points, dim)
|
|
491
|
+
make_object(self.plotter, self.wing_actors, GEOM, wing_rgb_color, wing_opacity)
|
|
492
|
+
if wing.yz_plane_symmetric:
|
|
493
|
+
GEOM.PTS[:, :, 0] = -GEOM.PTS[:, :, 0]
|
|
494
|
+
make_object(self.plotter, self.wing_actors, GEOM, wing_rgb_color, wing_opacity)
|
|
495
|
+
if wing.xz_plane_symmetric:
|
|
496
|
+
GEOM.PTS[:, :, 1] = -GEOM.PTS[:, :, 1]
|
|
497
|
+
make_object(self.plotter, self.wing_actors, GEOM, wing_rgb_color, wing_opacity)
|
|
498
|
+
if wing.xy_plane_symmetric:
|
|
499
|
+
GEOM.PTS[:, :, 2] = -GEOM.PTS[:, :, 2]
|
|
500
|
+
make_object(self.plotter, self.wing_actors, GEOM, wing_rgb_color, wing_opacity)
|
|
501
|
+
if self._show_lopa and isinstance(wing, RCAIDE.Library.Components.Wings.Blended_Wing_Body):
|
|
502
|
+
lopa_geom = generate_3d_lopa_points(wing)
|
|
503
|
+
add_lopa_seats(self.plotter, lopa_geom, lopa_opacity)
|
|
504
|
+
|
|
505
|
+
# -------------------------------------------------------------------------
|
|
506
|
+
# Plot fuselage
|
|
507
|
+
# -------------------------------------------------------------------------
|
|
508
|
+
for fuselage in geometry.fuselages:
|
|
509
|
+
GEOM = generate_3d_fuselage_points(fuselage, tessellation)
|
|
510
|
+
make_object(self.plotter, self.fuselage_actors, GEOM, fuselage_rgb_color, fuselage_opacity)
|
|
511
|
+
if self._show_lopa:
|
|
512
|
+
lopa_geom = generate_3d_lopa_points(fuselage)
|
|
513
|
+
add_lopa_seats(self.plotter, lopa_geom, lopa_opacity)
|
|
514
|
+
|
|
515
|
+
# -------------------------------------------------------------------------
|
|
516
|
+
# Plot cargo bays
|
|
517
|
+
# -------------------------------------------------------------------------
|
|
518
|
+
if self._show_cargo_bays:
|
|
519
|
+
for cargo_bay in geometry.cargo_bays:
|
|
520
|
+
GEOM = generate_3d_cargo_bay_points(cargo_bay)
|
|
521
|
+
make_object(self.plotter, self.cargo_bay_actors, GEOM, cargo_bay_rgb_color, cargo_bay_opacity)
|
|
522
|
+
|
|
523
|
+
# -------------------------------------------------------------------------
|
|
524
|
+
# Plot boom
|
|
525
|
+
# -------------------------------------------------------------------------
|
|
526
|
+
for boom in geometry.booms:
|
|
527
|
+
GEOM = generate_3d_fuselage_points(boom, tessellation)
|
|
528
|
+
make_object(self.plotter, self.boom_actors, GEOM, boom_rgb_color, boom_opacity)
|
|
529
|
+
|
|
530
|
+
# -------------------------------------------------------------------------
|
|
531
|
+
# Plot Nacelle, Rotors and Fuel Tanks
|
|
532
|
+
# -------------------------------------------------------------------------
|
|
533
|
+
# print(geometry.networks)
|
|
534
|
+
|
|
535
|
+
#plotting top-level nacelles (not attached to propulsors)
|
|
536
|
+
for nacelle in geometry.nacelles:
|
|
537
|
+
# if type(nacelle) == RCAIDE.Library.Components.Nacelles.Stack_Nacelle:
|
|
538
|
+
# GEOM = generate_3d_stack_nacelle_points(nacelle, tessellation=tessellation, number_of_airfoil_points=number_of_airfoil_points)
|
|
539
|
+
# elif type(nacelle) == RCAIDE.Library.Components.Nacelles.Body_of_Revolution_Nacelle:
|
|
540
|
+
GEOM = generate_3d_BOR_nacelle_points(nacelle, tessellation=tessellation, number_of_airfoil_points=number_of_airfoil_points)
|
|
541
|
+
# else:
|
|
542
|
+
# GEOM = generate_3d_basic_nacelle_points(nacelle, tessellation=tessellation, number_of_airfoil_points=number_of_airfoil_points)
|
|
543
|
+
make_object(self.plotter, self.nacelle_actors, GEOM, nacelle_rgb_color, nacelle_opacity)
|
|
544
|
+
|
|
545
|
+
for network in geometry.networks:
|
|
546
|
+
for propulsor in network.propulsors:
|
|
547
|
+
if getattr(propulsor, "nacelle", None) is not None:
|
|
548
|
+
if propulsor.nacelle != None:
|
|
549
|
+
|
|
550
|
+
if type(propulsor.nacelle) == RCAIDE.Library.Components.Nacelles.Stack_Nacelle:
|
|
551
|
+
GEOM = generate_3d_stack_nacelle_points(propulsor.nacelle,tessellation = tessellation,number_of_airfoil_points = number_of_airfoil_points)
|
|
552
|
+
elif type(propulsor.nacelle) == RCAIDE.Library.Components.Nacelles.Body_of_Revolution_Nacelle:
|
|
553
|
+
GEOM = generate_3d_BOR_nacelle_points(propulsor.nacelle,tessellation = tessellation,number_of_airfoil_points = number_of_airfoil_points)
|
|
554
|
+
else:
|
|
555
|
+
GEOM= generate_3d_basic_nacelle_points(propulsor.nacelle,tessellation = tessellation,number_of_airfoil_points = number_of_airfoil_points)
|
|
556
|
+
make_object(self.plotter,self.nacelle_actors, GEOM, nacelle_rgb_color,nacelle_opacity)
|
|
557
|
+
|
|
558
|
+
if 'rotor' in propulsor:
|
|
559
|
+
rot = propulsor.rotor
|
|
560
|
+
rot_x = rot.orientation_euler_angles[0]
|
|
561
|
+
rot_y = rot.orientation_euler_angles[1]
|
|
562
|
+
rot_z = rot.orientation_euler_angles[2]
|
|
563
|
+
num_B = int(rot.number_of_blades)
|
|
564
|
+
if rot.radius_distribution is None:
|
|
565
|
+
make_actuator_disc(self.plotter, rot.hub_radius, rot.tip_radius, rot.origin, rot_x,rot_y,rot_z, rotor_rgb_color,rotor_opacity)
|
|
566
|
+
else:
|
|
567
|
+
dim = len(rot.radius_distribution)
|
|
568
|
+
for i in range(num_B):
|
|
569
|
+
GEOM = generate_3d_blade_points(rot,number_of_airfoil_points,dim,i)
|
|
570
|
+
make_object(self.plotter,self.rotor_actors, GEOM, rotor_rgb_color,rotor_opacity)
|
|
571
|
+
|
|
572
|
+
if 'propeller' in propulsor:
|
|
573
|
+
prop = propulsor.propeller
|
|
574
|
+
rot_x = prop.orientation_euler_angles[0]
|
|
575
|
+
rot_y = np.pi / 2 + prop.orientation_euler_angles[1]
|
|
576
|
+
rot_z = prop.orientation_euler_angles[2]
|
|
577
|
+
num_B = int(prop.number_of_blades)
|
|
578
|
+
if prop.radius_distribution is None:
|
|
579
|
+
make_actuator_disc(self.plotter, prop.hub_radius, prop.tip_radius, prop.origin, rot_x,rot_y,rot_z,rotor_rgb_color,rotor_opacity)
|
|
580
|
+
else:
|
|
581
|
+
dim = len(prop.radius_distribution)
|
|
582
|
+
for i in range(num_B):
|
|
583
|
+
GEOM = generate_3d_blade_points(prop,number_of_airfoil_points,dim,i)
|
|
584
|
+
make_object(self.plotter,self.rotor_actors, GEOM, rotor_rgb_color,rotor_opacity)
|
|
585
|
+
|
|
586
|
+
if self._show_fuel_tanks:
|
|
587
|
+
for fuel_line in network.fuel_lines:
|
|
588
|
+
for fuel_tank in fuel_line.fuel_tanks:
|
|
589
|
+
if fuel_tank.wing_tag != None:
|
|
590
|
+
wing = geometry.wings[fuel_tank.wing_tag]
|
|
591
|
+
|
|
592
|
+
if issubclass(type(fuel_tank), RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Non_Integral_Tank):
|
|
593
|
+
LH2 = RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Liquid_Hydrogen_Tank
|
|
594
|
+
if issubclass(type(fuel_tank), LH2) and getattr(fuel_tank, 'geometry_type', None) == 'conformal' and getattr(fuel_tank, 'bwb_aft_tank', False):
|
|
595
|
+
seg_bounds = fuel_tank.aft_tank_root_chord_bounds
|
|
596
|
+
GEOM = generate_aft_integral_wing_tank_points(wing, 5, seg_bounds, fuel_tank)
|
|
597
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
598
|
+
elif issubclass(type(fuel_tank), LH2) and getattr(fuel_tank, 'geometry_type', None) == 'conformal':
|
|
599
|
+
seg_bounds = fuel_tank.segments_bounding_tank
|
|
600
|
+
GEOM = generate_integral_wing_tank_points(wing, 5, seg_bounds, fuel_tank)
|
|
601
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
602
|
+
if wing.xz_plane_symmetric:
|
|
603
|
+
GEOM.PTS[:, :, 1] = -GEOM.PTS[:, :, 1]
|
|
604
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
605
|
+
else:
|
|
606
|
+
GEOM = generate_non_integral_fuel_tank_points(fuel_tank, tessellation)
|
|
607
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
608
|
+
if wing.xz_plane_symmetric:
|
|
609
|
+
GEOM.PTS[:, :, 1] = -GEOM.PTS[:, :, 1]
|
|
610
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
611
|
+
|
|
612
|
+
if type(fuel_tank) == RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Integral_Tank:
|
|
613
|
+
seg_bounds = fuel_tank.segments_bounding_tank
|
|
614
|
+
GEOM = generate_integral_wing_tank_points(wing, 5, seg_bounds, fuel_tank)
|
|
615
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
616
|
+
if wing.xz_plane_symmetric:
|
|
617
|
+
GEOM.PTS[:, :, 1] = -GEOM.PTS[:, :, 1]
|
|
618
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
619
|
+
|
|
620
|
+
elif fuel_tank.fuselage_tag != None:
|
|
621
|
+
fuselage = geometry.fuselages[fuel_tank.fuselage_tag]
|
|
622
|
+
if type(fuel_tank) == RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Integral_Tank:
|
|
623
|
+
seg_bounds = fuel_tank.segments_bounding_tank
|
|
624
|
+
GEOM = generate_integral_fuel_tank_points(fuselage, fuel_tank, seg_bounds, tessellation)
|
|
625
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
626
|
+
|
|
627
|
+
elif issubclass(type(fuel_tank), RCAIDE.Library.Components.Powertrain.Sources.Fuel_Tanks.Non_Integral_Tank):
|
|
628
|
+
GEOM = generate_non_integral_fuel_tank_points(fuel_tank, tessellation)
|
|
629
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
630
|
+
if wing.xz_plane_symmetric:
|
|
631
|
+
GEOM.PTS[:, :, 1] = -GEOM.PTS[:, :, 1]
|
|
632
|
+
make_object(self.plotter, self.fuel_tank_actors, GEOM, fuel_tank_rgb_color, fuel_tank_opacity)
|
|
633
|
+
|
|
634
|
+
# Set camera and background
|
|
635
|
+
cam = self.renderer.GetActiveCamera()
|
|
636
|
+
cam.SetPosition(camera_eye_x, camera_eye_y, camera_eye_z)
|
|
637
|
+
cam.SetFocalPoint(0, 0, 0)
|
|
638
|
+
cam.SetViewUp(0, 0, 1)
|
|
639
|
+
self.renderer.ResetCamera()
|
|
640
|
+
self.renderer.SetBackground(1.0, 1.0, 1.0)
|
|
641
|
+
|
|
642
|
+
# Use the custom interactor style
|
|
643
|
+
custom_style = CustomInteractorStyle()
|
|
644
|
+
self.render_window_interactor.SetInteractorStyle(custom_style)
|
|
645
|
+
|
|
646
|
+
# self.vtkWidget.show()
|
|
647
|
+
# Start the VTK interactor
|
|
648
|
+
self.render_window_interactor.Initialize()
|
|
649
|
+
# Skip Start() for embedded previews.
|
|
650
|
+
# Full visualization starts VTK; embedded previews only render.
|
|
651
|
+
if self._start_interactor:
|
|
652
|
+
self.render_window_interactor.Start()
|
|
653
|
+
self.get_camera=self.renderer.GetActiveCamera()
|
|
654
|
+
self.update_toolbar()
|
|
655
|
+
if rcaide_io.vehicle.wings:
|
|
656
|
+
self.colorbar_widget.update_parts(self.part_actors)
|
|
657
|
+
self.isometric_function()
|
|
658
|
+
|
|
659
|
+
def update_toolbar(self):
|
|
660
|
+
self.zoom_out_button.clicked.connect(self.zoom_out)
|
|
661
|
+
self.zoom_in_button.clicked.connect(self.zoom_in)
|
|
662
|
+
self.pan_button.clicked.connect(self.enable_pan_mode)
|
|
663
|
+
self.front_button.clicked.connect(self.front_function)
|
|
664
|
+
self.top_button.clicked.connect(self.top_function)
|
|
665
|
+
self.side_button.clicked.connect(self.side_function)
|
|
666
|
+
self.isometric_button.clicked.connect(self.isometric_function)
|
|
667
|
+
|
|
668
|
+
def update_layout(self):
|
|
669
|
+
self.run_solve()
|
|
670
|
+
|
|
671
|
+
plot_options = {
|
|
672
|
+
"Pre Built": [
|
|
673
|
+
"Concorde",
|
|
674
|
+
],
|
|
675
|
+
}
|
|
676
|
+
def get_widget() -> QWidget:
|
|
677
|
+
return VisualizeGeometryWidget()
|
|
678
|
+
|
|
679
|
+
def make_object(plotter, actor_group, GEOM, rgb_color, opacity):
|
|
680
|
+
mesh = generate_vtk_object(GEOM.PTS)
|
|
681
|
+
|
|
682
|
+
bright = tuple(min(1.0, c * 1.2) for c in rgb_color)
|
|
683
|
+
actor = plotter.add_mesh(
|
|
684
|
+
mesh,
|
|
685
|
+
color=bright,
|
|
686
|
+
opacity=opacity,
|
|
687
|
+
show_scalar_bar=False,
|
|
688
|
+
smooth_shading=True,
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
prop = actor.GetProperty()
|
|
692
|
+
prop.SetDiffuse(0.8)
|
|
693
|
+
prop.SetAmbient(0.4)
|
|
694
|
+
prop.SetSpecular(0.3)
|
|
695
|
+
prop.SetSpecularPower(20)
|
|
696
|
+
|
|
697
|
+
actor_group.append(actor)
|
|
698
|
+
return
|
|
699
|
+
|
|
700
|
+
def make_actuator_disc(plotter, inner_radius, outer_radius, origin, rot_x, rot_y, rot_z, rgb_color, opacity):
|
|
701
|
+
disc = pv.Disc(
|
|
702
|
+
center=(0, 0, 0),
|
|
703
|
+
normal=(0, 0, 1),
|
|
704
|
+
inner=inner_radius,
|
|
705
|
+
outer=outer_radius,
|
|
706
|
+
r_res=50,
|
|
707
|
+
c_res=50,
|
|
708
|
+
)
|
|
709
|
+
disc.rotate_x(rot_x / Units.degrees, inplace=True)
|
|
710
|
+
disc.rotate_y(rot_y / Units.degrees, inplace=True)
|
|
711
|
+
disc.rotate_z(rot_z / Units.degrees, inplace=True)
|
|
712
|
+
disc.translate([origin[0][0], origin[0][1], origin[0][2]], inplace=True)
|
|
713
|
+
|
|
714
|
+
actor = plotter.add_mesh(disc, color=rgb_color, opacity=opacity, show_scalar_bar=False)
|
|
715
|
+
prop = actor.GetProperty()
|
|
716
|
+
prop.SetDiffuse(1.0)
|
|
717
|
+
prop.SetSpecular(0.0)
|
|
718
|
+
return
|
|
719
|
+
|
|
720
|
+
# ---------------------------------------
|
|
721
|
+
# Load Visualize Geometry feature plugins
|
|
722
|
+
# ---------------------------------------
|
|
723
|
+
|
|
724
|
+
from tabs.visualize_geometry.features import camera
|
|
725
|
+
from tabs.visualize_geometry.features import grid
|
|
726
|
+
from tabs.visualize_geometry.features import axes_gizmo
|
|
727
|
+
from tabs.visualize_geometry.features import background
|
|
728
|
+
from tabs.visualize_geometry.features import blueprint
|
|
729
|
+
from tabs.visualize_geometry.features import measurement
|
|
730
|
+
from tabs.visualize_geometry.features import screenshot
|
|
731
|
+
from tabs.visualize_geometry.features import drag_aircraft
|