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.
Files changed (170) hide show
  1. common_widgets/__init__.py +6 -0
  2. common_widgets/animated_toggle.py +141 -0
  3. common_widgets/color.py +17 -0
  4. common_widgets/data_entry_widget.py +337 -0
  5. common_widgets/image_widget.py +21 -0
  6. common_widgets/unit_picker_widget.py +48 -0
  7. main.py +168 -0
  8. rcaide_gui-1.0.0.dist-info/METADATA +96 -0
  9. rcaide_gui-1.0.0.dist-info/RECORD +170 -0
  10. rcaide_gui-1.0.0.dist-info/WHEEL +5 -0
  11. rcaide_gui-1.0.0.dist-info/entry_points.txt +2 -0
  12. rcaide_gui-1.0.0.dist-info/top_level.txt +5 -0
  13. rcaide_io.py +818 -0
  14. tabs/__init__.py +10 -0
  15. tabs/aircraft_configs/__init__.py +3 -0
  16. tabs/aircraft_configs/aircraft_configs.py +301 -0
  17. tabs/analysis/__init__.py +4 -0
  18. tabs/analysis/analysis.py +92 -0
  19. tabs/analysis/widgets/__init__.py +13 -0
  20. tabs/analysis/widgets/aeroacoustics_widget.py +158 -0
  21. tabs/analysis/widgets/aerodynamics_widget.py +108 -0
  22. tabs/analysis/widgets/analysis_data_widget.py +29 -0
  23. tabs/analysis/widgets/atmosphere_widget.py +49 -0
  24. tabs/analysis/widgets/costs_widget.py +35 -0
  25. tabs/analysis/widgets/energy_widget.py +32 -0
  26. tabs/analysis/widgets/geometry_widget.py +55 -0
  27. tabs/analysis/widgets/planets_widget.py +34 -0
  28. tabs/analysis/widgets/propulsion_widget.py +53 -0
  29. tabs/analysis/widgets/stability_widget.py +34 -0
  30. tabs/analysis/widgets/weights_widget.py +94 -0
  31. tabs/geometry/__init__.py +6 -0
  32. tabs/geometry/aircraft_configs.py +232 -0
  33. tabs/geometry/frames/__init__.py +15 -0
  34. tabs/geometry/frames/booms/__init__.py +5 -0
  35. tabs/geometry/frames/booms/boom_frame.py +238 -0
  36. tabs/geometry/frames/cargo_bays/__init__.py +5 -0
  37. tabs/geometry/frames/cargo_bays/cargo_bay_frame.py +159 -0
  38. tabs/geometry/frames/default_frame.py +23 -0
  39. tabs/geometry/frames/energy_network/__init__.py +2 -0
  40. tabs/geometry/frames/energy_network/turbofan_network/__init__.py +3 -0
  41. tabs/geometry/frames/energy_network/turbofan_network/frames/__init__.py +1 -0
  42. tabs/geometry/frames/energy_network/turbofan_network/widgets/__init__.py +1 -0
  43. tabs/geometry/frames/fuselages/__init__.py +5 -0
  44. tabs/geometry/frames/fuselages/fuselage_frame.py +294 -0
  45. tabs/geometry/frames/geometry_frame.py +91 -0
  46. tabs/geometry/frames/landing_gears/__init__.py +5 -0
  47. tabs/geometry/frames/landing_gears/landing_gear_frame.py +189 -0
  48. tabs/geometry/frames/nacelles/__init__.py +1 -0
  49. tabs/geometry/frames/powertrain/__init__.py +6 -0
  50. tabs/geometry/frames/powertrain/converters/__init__.py +5 -0
  51. tabs/geometry/frames/powertrain/converters/converter_frame.py +137 -0
  52. tabs/geometry/frames/powertrain/distributors/__init__.py +5 -0
  53. tabs/geometry/frames/powertrain/distributors/distributor_frame.py +143 -0
  54. tabs/geometry/frames/powertrain/nacelles/__init__.py +5 -0
  55. tabs/geometry/frames/powertrain/nacelles/nacelle_frame.py +283 -0
  56. tabs/geometry/frames/powertrain/powertrain_frame.py +259 -0
  57. tabs/geometry/frames/powertrain/propulsors/__init__.py +5 -0
  58. tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py +146 -0
  59. tabs/geometry/frames/powertrain/sources/__init__.py +6 -0
  60. tabs/geometry/frames/powertrain/sources/energy_source_frame.py +147 -0
  61. tabs/geometry/frames/vehicle_frame.py +171 -0
  62. tabs/geometry/frames/wings/__init__.py +5 -0
  63. tabs/geometry/frames/wings/wings_frame.py +457 -0
  64. tabs/geometry/geometry.py +513 -0
  65. tabs/geometry/widgets/__init__.py +12 -0
  66. tabs/geometry/widgets/booms/__init__.py +6 -0
  67. tabs/geometry/widgets/booms/boom_section_widget.py +109 -0
  68. tabs/geometry/widgets/cargo_bays/__init__.py +1 -0
  69. tabs/geometry/widgets/fuselages/__init__.py +8 -0
  70. tabs/geometry/widgets/fuselages/cabin_class_widget.py +188 -0
  71. tabs/geometry/widgets/fuselages/cabin_widget.py +217 -0
  72. tabs/geometry/widgets/fuselages/fuselage_section_widget.py +190 -0
  73. tabs/geometry/widgets/geometry_data_widget.py +25 -0
  74. tabs/geometry/widgets/landing_gears/__init__.py +6 -0
  75. tabs/geometry/widgets/nacelles/__init__.py +1 -0
  76. tabs/geometry/widgets/powertrain/__init__.py +9 -0
  77. tabs/geometry/widgets/powertrain/converters/__init__.py +5 -0
  78. tabs/geometry/widgets/powertrain/converters/turboelectric_generator_widget.py +74 -0
  79. tabs/geometry/widgets/powertrain/distributors/__init__.py +5 -0
  80. tabs/geometry/widgets/powertrain/distributors/fuel_line_widget.py +81 -0
  81. tabs/geometry/widgets/powertrain/modulators/__init__.py +5 -0
  82. tabs/geometry/widgets/powertrain/modulators/esc_widget.py +58 -0
  83. tabs/geometry/widgets/powertrain/nacelles/__init__.py +5 -0
  84. tabs/geometry/widgets/powertrain/nacelles/nacelle_section_widget.py +115 -0
  85. tabs/geometry/widgets/powertrain/powertrain_connector_widget.py +136 -0
  86. tabs/geometry/widgets/powertrain/powertrain_widget.py +206 -0
  87. tabs/geometry/widgets/powertrain/propulsors/__init__.py +5 -0
  88. tabs/geometry/widgets/powertrain/propulsors/turbofan_widget.py +462 -0
  89. tabs/geometry/widgets/powertrain/sources/__init__.py +6 -0
  90. tabs/geometry/widgets/powertrain/sources/fuel_tank_widget.py +103 -0
  91. tabs/geometry/widgets/powertrain/sources/source_selector_widget.py +35 -0
  92. tabs/geometry/widgets/wings/__init__.py +7 -0
  93. tabs/geometry/widgets/wings/wing_cs_widget.py +198 -0
  94. tabs/geometry/widgets/wings/wing_section_widget.py +298 -0
  95. tabs/home/__init__.py +3 -0
  96. tabs/home/home.py +585 -0
  97. tabs/mission/__init__.py +4 -0
  98. tabs/mission/mission.py +1124 -0
  99. tabs/mission/widgets/__init__.py +3 -0
  100. tabs/mission/widgets/flight_controls_widget.py +186 -0
  101. tabs/mission/widgets/mission_analysis_widget.py +166 -0
  102. tabs/mission/widgets/mission_segment_helper.py +358 -0
  103. tabs/mission/widgets/mission_segment_widget.py +358 -0
  104. tabs/solve/__init__.py +4 -0
  105. tabs/solve/plots/__init__.py +12 -0
  106. tabs/solve/plots/aeroacoustics/__init__.py +6 -0
  107. tabs/solve/plots/aeroacoustics/plot_2D_noise_contour.py +184 -0
  108. tabs/solve/plots/aeroacoustics/plot_3D_noise_contour.py +219 -0
  109. tabs/solve/plots/aeroacoustics/plot_noise_certification_contour.py +115 -0
  110. tabs/solve/plots/aeroacoustics/plot_noise_level.py +118 -0
  111. tabs/solve/plots/aerodynamics/__init__.py +10 -0
  112. tabs/solve/plots/aerodynamics/plot_aerodynamic_coefficients.py +156 -0
  113. tabs/solve/plots/aerodynamics/plot_aerodynamic_forces.py +155 -0
  114. tabs/solve/plots/aerodynamics/plot_aircraft_aerodynamics.py +136 -0
  115. tabs/solve/plots/aerodynamics/plot_drag_components.py +157 -0
  116. tabs/solve/plots/aerodynamics/plot_lift_distribution.py +107 -0
  117. tabs/solve/plots/aerodynamics/plot_rotor_conditions.py +255 -0
  118. tabs/solve/plots/aerodynamics/plot_rotor_disc_performance.py +144 -0
  119. tabs/solve/plots/aerodynamics/plot_rotor_performance.py +124 -0
  120. tabs/solve/plots/common/__init__.py +4 -0
  121. tabs/solve/plots/common/plot_style.py +71 -0
  122. tabs/solve/plots/common/set_axes.py +55 -0
  123. tabs/solve/plots/create_plot_widgets.py +34 -0
  124. tabs/solve/plots/emissions/__init__.py +3 -0
  125. tabs/solve/plots/emissions/plot_emissions.py +167 -0
  126. tabs/solve/plots/energy/__init__.py +12 -0
  127. tabs/solve/plots/energy/plot_altitude_sfc_weight.py +134 -0
  128. tabs/solve/plots/energy/plot_battery_cell_conditions.py +154 -0
  129. tabs/solve/plots/energy/plot_battery_degradation.py +157 -0
  130. tabs/solve/plots/energy/plot_battery_module_C_rates.py +139 -0
  131. tabs/solve/plots/energy/plot_battery_module_conditions.py +157 -0
  132. tabs/solve/plots/energy/plot_battery_pack_conditions.py +164 -0
  133. tabs/solve/plots/energy/plot_battery_ragone_diagram.py +97 -0
  134. tabs/solve/plots/energy/plot_battery_temperature.py +136 -0
  135. tabs/solve/plots/energy/plot_electric_propulsor_efficiencies.py +136 -0
  136. tabs/solve/plots/energy/plot_propulsor_throttles.py +119 -0
  137. tabs/solve/plots/mission/__init__.py +5 -0
  138. tabs/solve/plots/mission/plot_aircraft_velocities.py +145 -0
  139. tabs/solve/plots/mission/plot_flight_conditions.py +236 -0
  140. tabs/solve/plots/mission/plot_flight_trajectory.py +172 -0
  141. tabs/solve/plots/stability/__init__.py +5 -0
  142. tabs/solve/plots/stability/plot_flight_forces_and_moments.py +163 -0
  143. tabs/solve/plots/stability/plot_lateral_stability.py +151 -0
  144. tabs/solve/plots/stability/plot_longitudinal_stability.py +173 -0
  145. tabs/solve/plots/thermal_management/__init__.py +7 -0
  146. tabs/solve/plots/thermal_management/plot_air_cooled_conditions.py +152 -0
  147. tabs/solve/plots/thermal_management/plot_cross_flow_heat_exchanger_conditions.py +185 -0
  148. tabs/solve/plots/thermal_management/plot_reservoir_conditions.py +141 -0
  149. tabs/solve/plots/thermal_management/plot_thermal_management_performance.py +105 -0
  150. tabs/solve/plots/thermal_management/plot_wavy_channel_conditions.py +161 -0
  151. tabs/solve/plots/weights/__init__.py +4 -0
  152. tabs/solve/plots/weights/plot_load_diagram.py +163 -0
  153. tabs/solve/plots/weights/plot_weight_breakdown.py +164 -0
  154. tabs/solve/solve.py +1498 -0
  155. tabs/style_sheet.py +114 -0
  156. tabs/tab_widget.py +14 -0
  157. tabs/visualize_geometry/__init__.py +4 -0
  158. tabs/visualize_geometry/core_3d_viewer.py +253 -0
  159. tabs/visualize_geometry/features/__init__.py +10 -0
  160. tabs/visualize_geometry/features/axes_gizmo.py +173 -0
  161. tabs/visualize_geometry/features/background.py +161 -0
  162. tabs/visualize_geometry/features/blueprint.py +685 -0
  163. tabs/visualize_geometry/features/camera.py +364 -0
  164. tabs/visualize_geometry/features/drag_aircraft.py +219 -0
  165. tabs/visualize_geometry/features/grid.py +194 -0
  166. tabs/visualize_geometry/features/measurement.py +367 -0
  167. tabs/visualize_geometry/features/screenshot.py +91 -0
  168. tabs/visualize_geometry/geometry_helper_functions.py +3 -0
  169. tabs/visualize_geometry/visualize_geometry.py +731 -0
  170. 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