Skip to content

Commit b7a7995

Browse files
committed
adding spaceball mouse support; use the json preferences file
1 parent fbedcd3 commit b7a7995

File tree

16 files changed

+325
-196
lines changed

16 files changed

+325
-196
lines changed

pyNastran/bdf/bdf.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@
195195
from .bdf_interface.stats import get_bdf_stats
196196

197197
from .errors import (CrossReferenceError, DuplicateIDsError,
198-
CardParseSyntaxError, UnsupportedCard, DisabledCardError,
199-
SuperelementFlagError, ReplicationError)
198+
CardParseSyntaxError, UnsupportedCard, DisabledCardError,
199+
SuperelementFlagError, ReplicationError)
200200
from .bdf_interface.pybdf import (
201201
BDFInputPy, _clean_comment, _clean_comment_bulk, _check_for_spaces,
202202
add_superelements_from_deck_lines,
@@ -206,6 +206,45 @@
206206
if TYPE_CHECKING: # pragma: no cover
207207
from cpylog import SimpleLogger
208208

209+
Element = (
210+
CELAS1 | CELAS2 | CELAS3 | CELAS4 |
211+
CDAMP1 | CDAMP2 | CDAMP3 | CDAMP4 | CDAMP5 |
212+
CVISC | CBUSH | CBUSH1D | CBUSH2D | CFAST | #CWELD
213+
CGAP | GENEL | CCONEAX |
214+
CROD | CTUBE | CONROD |
215+
CBAR | CBEAM | CBEAM3 | CBEND | CSHEAR |
216+
CTRIA3 | CTRIA6 | CTRIAR |
217+
CQUAD4 | CQUAD8 | CQUADR | CQUAD |
218+
CTRIAX | CTRIAX6 |
219+
CQUADX | CQUADX4 | CQUADX8 |
220+
CRAC2D | CRAC3D |
221+
CPLSTN3 | CPLSTN4 | CPLSTN6 | CPLSTN8 |
222+
CPLSTS3 | #CPLSTS4 | CPLSTS6 | CPLSTS8 |
223+
CTETRA4 | CTETRA10 | CPENTA6 | CPENTA15 |
224+
CHEXA8 | CHEXA20 | CPYRAM5 | CPYRAM13 |
225+
CTRAX3 | CTRAX6 |
226+
# thermal
227+
CHBDYE |CHBDYG | CHBDYP |
228+
# Nastran 95
229+
CIHEX1 | CIHEX2 |
230+
CHEXA1 | CHEXA2)
231+
Property = (
232+
PELAS | PELAST | PDAMP | PDAMPT | PDAMP5 | PMASS |
233+
PROD | PTUBE | PVISC |
234+
PBUSH | PBUSH1D | PBUSH2D | PGAP |
235+
PRAC2D | PRAC3D | PCONEAX |
236+
PBAR | PBARL | PBEAM | PBRSECT |
237+
PBEAML | PBCOMP | PBMSECT |
238+
PBEND | PBEAM3 |
239+
PSHEAR | PPLANE |
240+
PSHELL | PCOMP | PCOMPG |
241+
PSOLID | PLSOLID | PIHEX | PCOMPS | PCOMPLS |
242+
PTRSHL #| PWELD
243+
)
244+
Material = (
245+
MAT1 | MAT2 | MAT3 | MAT8 | MAT9 | MAT10 | MAT11 |
246+
MAT3D | EQUIV | MATG)
247+
ThermalMaterial = MAT4 | MAT5
209248
CORD = CORD1R | CORD1C | CORD1S | CORD2R | CORD2C | CORD2S
210249

211250
REMOVED_CARDS = {

pyNastran/bdf/bdf_interface/add_methods.py

Lines changed: 92 additions & 115 deletions
Large diffs are not rendered by default.

pyNastran/bdf/bdf_interface/get_methods.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pyNastran.bdf.bdf_interface.attributes import BDFAttributes
99
from pyNastran.utils.numpy_utils import integer_types
1010
if TYPE_CHECKING: # pragma: no cover
11-
from pyNastran.bdf.bdf import BDF
11+
from pyNastran.bdf.bdf import BDF, Element, Property, Material, ThermalMaterial
1212
from pyNastran.bdf.cards.coordinate_systems import Coord
1313
from pyNastran.bdf.cards.nodes import POINT, GRID, SPOINT, EPOINT # , SPOINTs, EPOINTs, SEQGP, GRIDB
1414
from pyNastran.bdf.cards.aero.aero import (
@@ -261,7 +261,7 @@ def RigidElement(self, eid: int, msg: str='') -> Union[RBAR, RBE1, RBE2, RBE3, R
261261

262262
#--------------------
263263
# PROPERTY CARDS
264-
def Property(self, pid: int, msg: str='') -> Any:
264+
def Property(self, pid: int, msg: str='') -> Property:
265265
"""
266266
gets an elemental property (e.g. PSOLID, PLSOLID, PCOMP, PSHELL, PSHEAR);
267267
not mass property (PMASS)
@@ -321,7 +321,7 @@ def get_thermal_material_ids(self) -> Iterable[int]:
321321
"""gets the thermal material ids"""
322322
return self.thermal_materials.keys()
323323

324-
def Material(self, mid: int, msg: str='') -> Union[MAT1, MAT2, MAT3, MAT4, MAT5, MAT8, MAT9, MAT10, MAT11, MAT3D, EQUIV, MATG]:
324+
def Material(self, mid: int, msg: str='') -> Material | ThermalMaterial:
325325
"""gets a structural or thermal material"""
326326
if mid in self.materials:
327327
return self.materials[mid]
@@ -336,7 +336,7 @@ def Material(self, mid: int, msg: str='') -> Union[MAT1, MAT2, MAT3, MAT4, MAT5,
336336
)
337337
raise KeyError(msg2)
338338

339-
def StructuralMaterial(self, mid, msg='') -> Union[MAT1, MAT2, MAT3, MAT8, MAT9, MAT10, MAT11, MAT3D, EQUIV, MATG]:
339+
def StructuralMaterial(self, mid, msg='') -> Material:
340340
"""gets a structural material"""
341341
try:
342342
mat = self.materials[mid]
@@ -363,7 +363,7 @@ def HyperelasticMaterial(self, mid: int, msg: str='') -> Union[MATHE, MATHP]:
363363
raise KeyError('Invalid Hyperelastic Material ID: mid=%s%s' % (mid, msg))
364364
return mat
365365

366-
def Materials(self, mids, msg='') -> list[Union[MAT1, MAT2, MAT3, MAT8, MAT9, MAT10, MAT11, MAT3D, EQUIV, MATG]]:
366+
def Materials(self, mids, msg='') -> list[Material]:
367367
"""gets one or more Materials"""
368368
if isinstance(mids, integer_types):
369369
mids = [mids]

pyNastran/bdf/bdf_interface/safe_cross_reference.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
Safe cross-referencing skips failed xref's
55
66
"""
7+
from __future__ import annotations
78
from collections import defaultdict
8-
from typing import Any
9+
from typing import Any, TYPE_CHECKING
910

1011
import numpy as np
1112
from numpy import zeros, argsort, arange, array_equal
1213
from pyNastran.bdf.bdf_interface.cross_reference import XrefMesh
13-
14+
if TYPE_CHECKING:
15+
from pyNastran.bdf.bdf import Element, Property #, GRID
16+
from pyNastran.bdf.cards.nodes import GRID
1417

1518
class SafeXrefMesh(XrefMesh):
1619
"""
@@ -28,21 +31,21 @@ def __init__(self) -> None:
2831
# for elem in model.elements:
2932
# elem.check_unique_nodes()
3033

31-
def safe_cross_reference(self, xref=True,
32-
xref_nodes=True,
33-
xref_elements=True,
34-
xref_nodes_with_elements=False,
35-
xref_properties=True,
36-
xref_masses=True,
37-
xref_materials=True,
38-
xref_loads=True,
39-
xref_constraints=True,
40-
xref_aero=True,
41-
xref_sets=True,
42-
xref_optimization=True,
43-
create_superelement_geometry=False,
34+
def safe_cross_reference(self, xref: bool=True,
35+
xref_nodes: bool=True,
36+
xref_elements: bool=True,
37+
xref_nodes_with_elements: bool=False,
38+
xref_properties: bool=True,
39+
xref_masses: bool=True,
40+
xref_materials: bool=True,
41+
xref_loads: bool=True,
42+
xref_constraints: bool=True,
43+
xref_aero: bool=True,
44+
xref_sets: bool=True,
45+
xref_optimization: bool=True,
46+
create_superelement_geometry: bool=False,
4447
debug=True,
45-
word=''):
48+
word: str='') -> None:
4649
"""
4750
Performs cross referencing in a way that skips data gracefully.
4851
@@ -85,7 +88,7 @@ def safe_cross_reference(self, xref=True,
8588
self.pop_xref_errors()
8689
for superelement_tuple, superelement in sorted(self.superelement_models.items()):
8790
if isinstance(superelement_tuple, int):
88-
word = f' (Superelement {super_tuple:d})'
91+
word = f' (Superelement {superelement_tuple:d})'
8992
else:
9093
wordi, value, label = superelement_tuple
9194
if label:
@@ -382,7 +385,7 @@ def _safe_cross_reference_optimization(self) -> None:
382385
for unused_key, topvar in self.topvar.items():
383386
topvar.safe_cross_reference(self)
384387

385-
def safe_empty_nodes(self, nids, msg=''):
388+
def safe_empty_nodes(self, nids: list[int], msg: str='') -> tuple[list[GRID], list[int]]:
386389
"""safe xref version of self.Nodes(nid, msg='')"""
387390
nodes = []
388391
missing_nodes = []
@@ -398,7 +401,7 @@ def safe_empty_nodes(self, nids, msg=''):
398401
self.log.warning('Nodes %s are missing%s' % (str(missing_nodes), msg))
399402
return nodes, missing_nodes
400403

401-
def safe_get_nodes(self, nids: list[int], msg: str='') -> tuple[list[Any], str]:
404+
def safe_get_nodes(self, nids: list[int], msg: str='') -> tuple[list[GRID], str]:
402405
"""safe xref version of self.Nodes(nid, msg='')"""
403406
nodes = []
404407
error_nodes = []
@@ -414,7 +417,7 @@ def safe_get_nodes(self, nids: list[int], msg: str='') -> tuple[list[Any], str]:
414417
msgi += 'Could not find nodes %s%s\n' % (', '.join(error_nodes), msg)
415418
return nodes, msgi
416419

417-
def safe_get_points(self, point_ids, msg=''):
420+
def safe_get_points(self, point_ids: list[int], msg: str=''):
418421
"""safe xref version of self.Points(point_ids, msg='')"""
419422
points = []
420423
error_points = []
@@ -430,7 +433,7 @@ def safe_get_points(self, point_ids, msg=''):
430433
msgi += 'Could not find POINTs %s%s\n' % (', '.join(error_points), msg)
431434
return points, msgi
432435

433-
def safe_get_elements(self, eids, msg=''):
436+
def safe_get_elements(self, eids: list[int], msg: str=''):
434437
"""safe xref version of self.Elements(eid, msg='')"""
435438
elements = []
436439
msgi = ''
@@ -443,7 +446,7 @@ def safe_get_elements(self, eids, msg=''):
443446
elements.append(element)
444447
return elements, msgi
445448

446-
def safe_element(self, eid, ref_id, xref_errors, msg=''):
449+
def safe_element(self, eid: int, ref_id: int, xref_errors, msg: str='') -> ELement:
447450
"""
448451
Gets an element card
449452
@@ -466,8 +469,9 @@ def safe_element(self, eid, ref_id, xref_errors, msg=''):
466469
xref_errors['eid'].append((ref_id, eid))
467470
return eid_ref
468471

469-
def safe_elements(self, eids, ref_id: int,
470-
xref_errors: dict[str, tuple[int, int]], msg=''):
472+
def safe_elements(self, eids: list[int], ref_id: int,
473+
xref_errors: dict[str, tuple[int, int]],
474+
msg: str='') -> list[Element]:
471475
"""
472476
Gets an series of elements
473477
@@ -497,7 +501,7 @@ def safe_elements(self, eids, ref_id: int,
497501
#raise KeyError(msg)
498502
return elements
499503

500-
def safe_property(self, pid, ref_id, xref_errors, msg=''):
504+
def safe_property(self, pid: int, ref_id: int, xref_errors, msg: str='') -> Property:
501505
"""
502506
Parameters
503507
----------

pyNastran/bdf/cards/elements/mass.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def safe_cross_reference(self, model: BDF, xref_errors):
200200
self.nodes_ref, missing_nodes = model.safe_empty_nodes(self.node_ids, msg=msg)
201201
self.pid_ref = model.safe_property_mass(self.pid, self.eid, xref_errors, msg=msg)
202202
if missing_nodes:
203-
model.log.warning(missing_nodes)
203+
model.log.warning(str(missing_nodes))
204204

205205
def uncross_reference(self) -> None:
206206
"""Removes cross-reference links"""
@@ -500,7 +500,7 @@ def safe_cross_reference(self, model: BDF, xref_errors):
500500
msg = ', which is required by CMASS2 eid=%s' % self.eid
501501
self.nodes_ref, missing_nodes = model.safe_empty_nodes(self.node_ids, msg=msg)
502502
if missing_nodes:
503-
model.log.warning(missing_nodes)
503+
model.log.warning(str(missing_nodes))
504504

505505
def uncross_reference(self) -> None:
506506
"""Removes cross-reference links"""

pyNastran/bdf/mesh_utils/mass_properties.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
CHECK_MASS = False # should additional checks be done
2222

2323
if TYPE_CHECKING: # pragma: no cover
24-
from pyNastran.bdf.bdf import BDF, NSM1, CQUAD4, CBAR, CBEAM, CROD, CONROD, CTRIA3
25-
Element = CQUAD4 | CBAR | CBEAM | CROD | CONROD | CTRIA3
24+
from pyNastran.bdf.bdf import BDF, NSM1, CQUAD4, CBAR, CBEAM, CROD, CONROD, CTRIA3, Element
2625

2726
NO_MASS = {
2827
# has mass

pyNastran/gui/dev/gui2/vtk_interface.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
from vtkmodules.vtkRenderingCore import vtkRenderer
55
from pyNastran.gui.qt_files.colors import BLACK_FLOAT
66
from pyNastran.gui.qt_files.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
7-
from pyNastran.gui.styles.trackball_style_camera import TrackballStyleCamera
7+
from pyNastran.gui.styles.trackball_style_camera import TrackballStyleCamera, JoystickStyleCamera
88

99
if TYPE_CHECKING: # pragma: no cover
1010
import numpy as np
11+
from cpylog import SimpleLogger
1112
from pyNastran.gui.dev.gui2.gui2 import MainWindow2
13+
from vtkmodules.vtkInteractionStyle import vtkInteractor
1214

1315

1416
class ScalarBar:
@@ -30,6 +32,7 @@ def __init__(self, gui: MainWindow2, parent):
3032

3133
self.vtk_interactor = QVTKRenderWindowInteractor(parent=parent)
3234
self.set_style_as_trackball()
35+
#self.set_style_as_joystick()
3336

3437
self.rend = vtkRenderer()
3538
#self.vtk_interactor.GetRenderWindow().AddRenderer(self.rend)
@@ -46,15 +49,23 @@ def settings(self) -> Settings:
4649
return self.gui.settings
4750

4851
@property
49-
def log(self):
52+
def log(self) -> SimpleLogger:
5053
return self.gui.log
5154

52-
def set_style_as_trackball(self):
55+
def set_style(self):
56+
#self.mouse_actions.set_style_as_trackball()
57+
self.mouse_actions.set_style_as_joystick()
58+
59+
def set_style_as_trackball(self) -> None:
5360
"""sets the default rotation style"""
5461
#self._simulate_key_press('t') # change mouse style to trackball
5562
self.style = TrackballStyleCamera(self.vtk_interactor, self)
5663
self.vtk_interactor.SetInteractorStyle(self.style)
5764

65+
def set_style_as_joystick(self) -> None:
66+
self.style = JoystickStyleCamera(self.vtk_interactor, self)
67+
self.vtk_interactor.SetInteractorStyle(self.style)
68+
5869
def set_quad_grid(self, box_name: str,
5970
nodes: np.ndarray, elements: np.ndarray,
6071
color: Optional[list[float]]=None,
@@ -67,7 +78,7 @@ def create_global_axes(self, dim_max: float) -> None:
6778
self.log.warning('create_global_axes')
6879

6980

70-
def fill_render_window(vtk_interactor,
81+
def fill_render_window(vtk_interactor: vtkInteractor,
7182
rend: vtkRenderer,
7283
nframes: int=1) -> list[vtkRenderer]:
7384
assert nframes in [1, 2, 4], nframes
@@ -126,4 +137,3 @@ def fill_render_window(vtk_interactor,
126137
render_window.AddRenderer(rend4)
127138
return [rend, rend2, rend3, rend4]
128139
raise ValueError(nframes)
129-

pyNastran/gui/gui_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ def build_vtk_frame(self):
10521052
#self.rend.SetBackground2(*self.background_color2)
10531053

10541054
rend.ResetCamera()
1055-
self.mouse_actions.set_style_as_trackball()
1055+
self.mouse_actions.set_style()
10561056
self._build_vtk_frame_post()
10571057

10581058
def on_reset_camera(self):

pyNastran/gui/gui_objects/settings.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
LINE_WIDTH_MIN = 0.1
6969
LINE_WIDTH_MAX = 2000.
7070

71+
IS_TRACKBALL_CAMERA = True
7172
USE_PARALLEL_PROJECTION = True
7273
DEFAULT_COLORMAP = 'jet'
7374
NFILES_TO_SAVE = 9
@@ -325,6 +326,7 @@ def reset_settings(self, resize: bool=True,
325326
self.shear_moment_torque_point_size = SHEAR_MOMENT_TORQUE_POINT_SIZE # float
326327
self.shear_moment_torque_line_width = SHEAR_MOMENT_TORQUE_LINE_WIDTH # float
327328

329+
self.is_trackball_camera = IS_TRACKBALL_CAMERA
328330
self.use_parallel_projection = USE_PARALLEL_PROJECTION
329331
self.displacement_model_scale = DISPLACEMENT_MODEL_SCALE
330332
self.show_info = True
@@ -398,6 +400,9 @@ def load(self, settings: QSettings) -> bool:
398400
self.font_size, min_value=FONT_SIZE_MIN, max_value=None)
399401

400402
# parallel/perspective
403+
self._set_setting(settings, setting_keys, ['is_trackball_camera'],
404+
default=self.is_trackball_camera,
405+
save=True, auto_type=bool)
401406
self._set_setting(settings, setting_keys, ['use_parallel_projection'],
402407
default=self.use_parallel_projection,
403408
save=True, auto_type=bool)
@@ -695,6 +700,7 @@ def save(self, settings, is_testing: bool=False) -> None:
695700
settings.setValue('main_window_state', parent.saveState())
696701

697702
# booleans
703+
settings.setValue('is_trackball_camera', self.is_trackball_camera)
698704
settings.setValue('use_parallel_projection', self.use_parallel_projection)
699705
settings.setValue('use_gradient_background', self.use_gradient_background)
700706

@@ -1112,6 +1118,14 @@ def set_magnify(self, magnify: int=5) -> None:
11121118
"""sets the screenshot magnification factor"""
11131119
self.magnify = magnify
11141120

1121+
def set_trackball_camera(self, is_trackball_camera: bool,
1122+
render: bool=True) -> None:
1123+
"""sets the parallel_projection flag"""
1124+
self.is_trackball_camera = is_trackball_camera
1125+
self.parent.mouse_settings.set_style()
1126+
if render:
1127+
self.parent.vtk_interactor.Render()
1128+
11151129
def set_parallel_projection(self, parallel_projection: bool,
11161130
render: bool=True) -> None:
11171131
"""sets the parallel_projection flag"""

0 commit comments

Comments
 (0)