psychopy 2024.2.5__py3-none-any.whl → 2025.1.1__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.
Potentially problematic release.
This version of psychopy might be problematic. Click here for more details.
- psychopy/CHANGELOG.txt +4 -4
- psychopy/GIT_SHA +1 -1
- psychopy/LICENSE.txt +1 -1
- psychopy/VERSION +1 -1
- psychopy/__init__.py +10 -7
- psychopy/alerts/__init__.py +1 -1
- psychopy/alerts/_alerts.py +53 -17
- psychopy/alerts/_errorHandler.py +3 -4
- psychopy/alerts/alertsCatalogue/3210.yaml +27 -0
- psychopy/alerts/alertsCatalogue/3610.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4130.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +8 -1
- psychopy/alerts/alertsCatalogue/alertmsg.py +1 -1
- psychopy/alerts/alerttools.py +0 -16
- psychopy/app/Resources/betasplash.png +0 -0
- psychopy/app/Resources/betasplash@2x.png +0 -0
- psychopy/app/Resources/classic/case.png +0 -0
- psychopy/app/Resources/classic/case@2x.png +0 -0
- psychopy/app/Resources/classic/fileaudio.png +0 -0
- psychopy/app/Resources/classic/fileaudio@2x.png +0 -0
- psychopy/app/Resources/classic/filecss.png +0 -0
- psychopy/app/Resources/classic/filecss@2x.png +0 -0
- psychopy/app/Resources/classic/filecsv.png +0 -0
- psychopy/app/Resources/classic/filecsv@2x.png +0 -0
- psychopy/app/Resources/classic/filedesign.png +0 -0
- psychopy/app/Resources/classic/filedesign@2x.png +0 -0
- psychopy/app/Resources/classic/filefont.png +0 -0
- psychopy/app/Resources/classic/filefont@2x.png +0 -0
- psychopy/app/Resources/classic/filegit.png +0 -0
- psychopy/app/Resources/classic/filegit@2x.png +0 -0
- psychopy/app/Resources/classic/filehtml.png +0 -0
- psychopy/app/Resources/classic/filehtml@2x.png +0 -0
- psychopy/app/Resources/classic/fileimage.png +0 -0
- psychopy/app/Resources/classic/fileimage@2x.png +0 -0
- psychopy/app/Resources/classic/fileinfo.png +0 -0
- psychopy/app/Resources/classic/fileinfo@2x.png +0 -0
- psychopy/app/Resources/classic/filejs.png +0 -0
- psychopy/app/Resources/classic/filejs@2x.png +0 -0
- psychopy/app/Resources/classic/filejson.png +0 -0
- psychopy/app/Resources/classic/filejson@2x.png +0 -0
- psychopy/app/Resources/classic/filepkg.png +0 -0
- psychopy/app/Resources/classic/filepkg@2x.png +0 -0
- psychopy/app/Resources/classic/filepsyexp.png +0 -0
- psychopy/app/Resources/classic/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/classic/filepy.png +0 -0
- psychopy/app/Resources/classic/filepy@2x.png +0 -0
- psychopy/app/Resources/classic/filetxt.png +0 -0
- psychopy/app/Resources/classic/filetxt@2x.png +0 -0
- psychopy/app/Resources/classic/fileunknown.png +0 -0
- psychopy/app/Resources/classic/fileunknown@2x.png +0 -0
- psychopy/app/Resources/classic/filevideo.png +0 -0
- psychopy/app/Resources/classic/filevideo@2x.png +0 -0
- psychopy/app/Resources/classic/find.png +0 -0
- psychopy/app/Resources/classic/find@2x.png +0 -0
- psychopy/app/Resources/classic/loop.png +0 -0
- psychopy/app/Resources/classic/loop@2x.png +0 -0
- psychopy/app/Resources/classic/regex.png +0 -0
- psychopy/app/Resources/classic/regex@2x.png +0 -0
- psychopy/app/Resources/dark/case.png +0 -0
- psychopy/app/Resources/dark/case@2x.png +0 -0
- psychopy/app/Resources/dark/fileaudio.png +0 -0
- psychopy/app/Resources/dark/fileaudio@2x.png +0 -0
- psychopy/app/Resources/dark/filecss.png +0 -0
- psychopy/app/Resources/dark/filecss@2x.png +0 -0
- psychopy/app/Resources/dark/filecsv.png +0 -0
- psychopy/app/Resources/dark/filecsv@2x.png +0 -0
- psychopy/app/Resources/dark/filedesign.png +0 -0
- psychopy/app/Resources/dark/filedesign@2x.png +0 -0
- psychopy/app/Resources/dark/filefont.png +0 -0
- psychopy/app/Resources/dark/filefont@2x.png +0 -0
- psychopy/app/Resources/dark/filegit.png +0 -0
- psychopy/app/Resources/dark/filegit@2x.png +0 -0
- psychopy/app/Resources/dark/filehtml.png +0 -0
- psychopy/app/Resources/dark/filehtml@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage.png +0 -0
- psychopy/app/Resources/dark/fileimage@2x.png +0 -0
- psychopy/app/Resources/dark/fileinfo.png +0 -0
- psychopy/app/Resources/dark/fileinfo@2x.png +0 -0
- psychopy/app/Resources/dark/filejs.png +0 -0
- psychopy/app/Resources/dark/filejs@2x.png +0 -0
- psychopy/app/Resources/dark/filejson.png +0 -0
- psychopy/app/Resources/dark/filejson@2x.png +0 -0
- psychopy/app/Resources/dark/filepkg.png +0 -0
- psychopy/app/Resources/dark/filepkg@2x.png +0 -0
- psychopy/app/Resources/dark/filepsyexp.png +0 -0
- psychopy/app/Resources/dark/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/dark/filepy.png +0 -0
- psychopy/app/Resources/dark/filepy@2x.png +0 -0
- psychopy/app/Resources/dark/filetxt.png +0 -0
- psychopy/app/Resources/dark/filetxt@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown.png +0 -0
- psychopy/app/Resources/dark/fileunknown@2x.png +0 -0
- psychopy/app/Resources/dark/filevideo.png +0 -0
- psychopy/app/Resources/dark/filevideo@2x.png +0 -0
- psychopy/app/Resources/dark/find.png +0 -0
- psychopy/app/Resources/dark/find@2x.png +0 -0
- psychopy/app/Resources/dark/loop.png +0 -0
- psychopy/app/Resources/dark/loop@2x.png +0 -0
- psychopy/app/Resources/dark/regex.png +0 -0
- psychopy/app/Resources/dark/regex@2x.png +0 -0
- psychopy/app/Resources/light/case.png +0 -0
- psychopy/app/Resources/light/case@2x.png +0 -0
- psychopy/app/Resources/light/fileaudio.png +0 -0
- psychopy/app/Resources/light/fileaudio@2x.png +0 -0
- psychopy/app/Resources/light/filecss.png +0 -0
- psychopy/app/Resources/light/filecss@2x.png +0 -0
- psychopy/app/Resources/light/filecsv.png +0 -0
- psychopy/app/Resources/light/filecsv@2x.png +0 -0
- psychopy/app/Resources/light/filedesign.png +0 -0
- psychopy/app/Resources/light/filedesign@2x.png +0 -0
- psychopy/app/Resources/light/filefont.png +0 -0
- psychopy/app/Resources/light/filefont@2x.png +0 -0
- psychopy/app/Resources/light/filegit.png +0 -0
- psychopy/app/Resources/light/filegit@2x.png +0 -0
- psychopy/app/Resources/light/filehtml.png +0 -0
- psychopy/app/Resources/light/filehtml@2x.png +0 -0
- psychopy/app/Resources/light/fileimage.png +0 -0
- psychopy/app/Resources/light/fileimage@2x.png +0 -0
- psychopy/app/Resources/light/fileinfo.png +0 -0
- psychopy/app/Resources/light/fileinfo@2x.png +0 -0
- psychopy/app/Resources/light/filejs.png +0 -0
- psychopy/app/Resources/light/filejs@2x.png +0 -0
- psychopy/app/Resources/light/filejson.png +0 -0
- psychopy/app/Resources/light/filejson@2x.png +0 -0
- psychopy/app/Resources/light/filepkg.png +0 -0
- psychopy/app/Resources/light/filepkg@2x.png +0 -0
- psychopy/app/Resources/light/filepsyexp.png +0 -0
- psychopy/app/Resources/light/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/light/filepy.png +0 -0
- psychopy/app/Resources/light/filepy@2x.png +0 -0
- psychopy/app/Resources/light/filetxt.png +0 -0
- psychopy/app/Resources/light/filetxt@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown.png +0 -0
- psychopy/app/Resources/light/fileunknown@2x.png +0 -0
- psychopy/app/Resources/light/filevideo.png +0 -0
- psychopy/app/Resources/light/filevideo@2x.png +0 -0
- psychopy/app/Resources/light/find.png +0 -0
- psychopy/app/Resources/light/find@2x.png +0 -0
- psychopy/app/Resources/light/loop.png +0 -0
- psychopy/app/Resources/light/loop@2x.png +0 -0
- psychopy/app/Resources/light/regex.png +0 -0
- psychopy/app/Resources/light/regex@2x.png +0 -0
- psychopy/app/Resources/routine_templates/Basic.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Misc.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Online.psyexp +0 -2
- psychopy/app/Resources/routine_templates/Trials.psyexp +0 -1
- psychopy/app/Resources/splash.png +0 -0
- psychopy/app/Resources/splash@2x.png +0 -0
- psychopy/app/__init__.py +49 -8
- psychopy/app/__main__.py +3 -0
- psychopy/app/_psychopyApp.py +134 -125
- psychopy/app/builder/builder.py +42 -22
- psychopy/app/builder/dialogs/__init__.py +44 -11
- psychopy/app/builder/dialogs/dlgsCode.py +1 -1
- psychopy/app/builder/dialogs/dlgsConditions.py +1 -1
- psychopy/app/builder/dialogs/findDlg.py +106 -20
- psychopy/app/builder/dialogs/paramCtrls.py +42 -1
- psychopy/app/builder/validators.py +1 -1
- psychopy/app/coder/codeEditorBase.py +8 -8
- psychopy/app/coder/coder.py +32 -29
- psychopy/app/coder/fileBrowser.py +68 -22
- psychopy/app/coder/folding.py +1 -1
- psychopy/app/coder/psychoParser.py +1 -1
- psychopy/app/coder/repl.py +1 -1
- psychopy/app/coder/sourceTree.py +1 -1
- psychopy/app/connections/__init__.py +1 -1
- psychopy/app/connections/news.py +1 -1
- psychopy/app/connections/sendusage.py +1 -1
- psychopy/app/connections/updates.py +1 -1
- psychopy/app/console.py +1 -1
- psychopy/app/errorDlg.py +1 -1
- psychopy/app/frametracker.py +1 -1
- psychopy/app/idle.py +1 -1
- psychopy/app/jobs.py +5 -2
- psychopy/app/linuxconfig/__init__.py +1 -1
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +1 -1
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +3421 -2396
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +2 -2
- psychopy/app/{builder/localizedStrings.py → localizedStrings.py} +173 -26
- psychopy/app/pavlovia_ui/__init__.py +1 -1
- psychopy/app/pavlovia_ui/_base.py +1 -1
- psychopy/app/pavlovia_ui/functions.py +1 -1
- psychopy/app/pavlovia_ui/menu.py +1 -1
- psychopy/app/pavlovia_ui/project.py +1 -1
- psychopy/app/pavlovia_ui/search.py +1 -1
- psychopy/app/pavlovia_ui/sync.py +1 -1
- psychopy/app/pavlovia_ui/user.py +1 -1
- psychopy/app/plugin_manager/dialog.py +34 -96
- psychopy/app/plugin_manager/packages.py +10 -14
- psychopy/app/plugin_manager/plugins.py +64 -4
- psychopy/app/preferencesDlg.py +12 -37
- psychopy/app/psychopyApp.py +130 -44
- psychopy/app/ribbon.py +1 -0
- psychopy/app/runner/runner.py +19 -7
- psychopy/app/runner/scriptProcess.py +11 -6
- psychopy/app/stdout/stdOutRich.py +9 -2
- psychopy/app/themes/fonts.py +1 -1
- psychopy/app/themes/icons.py +2 -38
- psychopy/app/ui/__init__.py +1 -1
- psychopy/app/utils.py +3 -3
- psychopy/assets/default.mp3 +0 -0
- psychopy/assets/fonts/NotoSans-Bold.ttf +0 -0
- psychopy/assets/fonts/NotoSans-BoldItalic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Italic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Regular.ttf +0 -0
- psychopy/assets/voicekeyThresholdStim.wav +0 -0
- psychopy/clock.py +4 -1
- psychopy/colors.py +12 -5
- psychopy/core.py +1 -1
- psychopy/data/base.py +1 -1
- psychopy/data/experiment.py +151 -46
- psychopy/data/routine.py +27 -1
- psychopy/data/staircase.py +2 -1
- psychopy/data/trial.py +62 -14
- psychopy/data/utils.py +2 -2
- psychopy/demos/builder/Design Templates/branchedExperiment/branchedExperiment.psyexp +333 -218
- psychopy/demos/builder/Design Templates/psychophysicsStaircase/psychophysicsStaircase.psyexp +261 -239
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/psychophysicsStaircaseInterleaved.psyexp +319 -180
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.psyexp +204 -116
- psychopy/demos/builder/Experiments/BART/assets/background.jpg +0 -0
- psychopy/demos/builder/Experiments/BART/assets/blueBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/greenBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/redBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/bart.psyexp +779 -866
- psychopy/demos/builder/Experiments/BigFiveInventory/BFI.psyexp +242 -180
- psychopy/demos/builder/Experiments/GoNoGo/gng.psyexp +419 -406
- psychopy/demos/builder/Experiments/dragAndDrop/README.md +2 -37
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +460 -1204
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/blank_grid.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/make_shapes.psyexp +221 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/readme.md +4 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/mentalRotation/MentalRotation.psyexp +583 -542
- psychopy/demos/builder/Experiments/navon/NavonTask.psyexp +458 -427
- psychopy/demos/builder/Experiments/sternberg/sternberg.psyexp +588 -550
- psychopy/demos/builder/Experiments/stroop/stroop.psyexp +303 -207
- psychopy/demos/builder/Experiments/stroopExtended/stroop.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopExtended/stroopReverse.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +357 -331
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -2
- psychopy/demos/builder/Feature Demos/counterbalance/counterbalance.psyexp +287 -277
- psychopy/demos/builder/Feature Demos/gratings/gratings.psyexp +370 -320
- psychopy/demos/builder/Feature Demos/noise/noise.psyexp +452 -399
- psychopy/demos/builder/Feature Demos/panorama/panorama.psyexp +168 -133
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +4 -3
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +420 -392
- psychopy/demos/builder/Feature Demos/sliders/sliders.psyexp +917 -871
- psychopy/demos/builder/Feature Demos/visualValidator/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +200 -0
- psychopy/demos/builder/Hardware/EEG_parallel_component/EEG_triggers_parallel_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EEG_serial_code/EEG_triggers_serial_code.psyexp +372 -361
- psychopy/demos/builder/Hardware/EEG_serial_component/EEG_triggers_serial_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EGI_netstation/stroop.psyexp +320 -235
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/visualSearch.psyexp +790 -651
- psychopy/demos/builder/Hardware/camera/camera.psyexp +326 -246
- psychopy/demos/builder/Hardware/eyetracking/eyetracking.psyexp +432 -327
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/eyetracking_custom_cal.psyexp +440 -321
- psychopy/demos/builder/Hardware/fMRI/fMRI_demo.psyexp +190 -181
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo.psyexp +323 -312
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy.psyexp +329 -273
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +450 -404
- psychopy/demos/builder/Hardware/pump/pump.psyexp +593 -329
- psychopy/demos/builder/Helper Tools/achorVSalignment/FlowCircular-Regular.ttf +0 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/anchorAlignment.psyexp +336 -274
- psychopy/demos/builder/Helper Tools/clockFace/clockFace.psyexp +200 -149
- psychopy/demos/builder/Helper Tools/colors/colors.psyexp +300 -279
- psychopy/demos/builder/Helper Tools/drawPolygon/drawPolygon.psyexp +677 -564
- psychopy/demos/builder/Helper Tools/keyNameFinder/keyNameFinder.psyexp +214 -158
- psychopy/demos/builder/Helper Tools/spatialUnits/unitDemo.psyexp +195 -146
- psychopy/demos/coder/experiment control/runtimeInfo.py +1 -1
- psychopy/devices/__init__.py +1 -1
- psychopy/event.py +1 -1
- psychopy/exceptions.py +1 -1
- psychopy/experiment/__init__.py +1 -1
- psychopy/experiment/_experiment.py +30 -9
- psychopy/experiment/components/__init__.py +1 -6
- psychopy/experiment/components/_base.py +44 -19
- psychopy/experiment/components/aperture/__init__.py +1 -1
- psychopy/experiment/components/brush/__init__.py +2 -2
- psychopy/experiment/components/button/__init__.py +24 -28
- psychopy/experiment/components/camera/__init__.py +38 -39
- psychopy/experiment/components/code/__init__.py +1 -1
- psychopy/experiment/components/dots/__init__.py +1 -1
- psychopy/experiment/components/eyetracker_record/__init__.py +7 -3
- psychopy/experiment/components/form/__init__.py +3 -3
- psychopy/experiment/components/grating/__init__.py +1 -1
- psychopy/experiment/components/image/__init__.py +1 -1
- psychopy/experiment/components/joyButtons/__init__.py +2 -2
- psychopy/experiment/components/joyButtons/virtualJoyButtons.py +1 -1
- psychopy/experiment/components/joystick/__init__.py +3 -3
- psychopy/experiment/components/joystick/virtualJoystick.py +1 -1
- psychopy/experiment/components/keyboard/__init__.py +98 -122
- psychopy/experiment/components/microphone/__init__.py +54 -98
- psychopy/experiment/components/mouse/__init__.py +92 -93
- psychopy/experiment/components/movie/__init__.py +28 -50
- psychopy/experiment/components/parallelOut/__init__.py +3 -3
- psychopy/experiment/components/polygon/__init__.py +2 -3
- psychopy/experiment/components/roi/__init__.py +2 -2
- psychopy/experiment/components/routineSettings/__init__.py +2 -0
- psychopy/experiment/components/serialOut/__init__.py +7 -7
- psychopy/experiment/components/settings/__init__.py +317 -313
- psychopy/experiment/components/settings/eyetracking.py +108 -0
- psychopy/experiment/components/slider/__init__.py +5 -5
- psychopy/experiment/components/sound/__init__.py +168 -78
- psychopy/experiment/components/soundsensor/__init__.py +361 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor@2x.png +0 -0
- psychopy/experiment/components/static/__init__.py +59 -33
- psychopy/experiment/components/text/__init__.py +2 -6
- psychopy/experiment/components/textbox/__init__.py +3 -7
- psychopy/experiment/components/unknown/__init__.py +2 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +2 -0
- psychopy/experiment/exports.py +1 -1
- psychopy/experiment/flow.py +2 -2
- psychopy/experiment/localization.py +1 -1
- psychopy/experiment/loops.py +43 -10
- psychopy/experiment/params.py +6 -4
- psychopy/experiment/plugins.py +8 -1
- psychopy/experiment/py2js.py +1 -1
- psychopy/experiment/py2js_transpiler.py +1 -1
- psychopy/experiment/routines/__init__.py +1 -1
- psychopy/experiment/routines/_base.py +23 -24
- psychopy/experiment/routines/audioValidator/__init__.py +343 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/__init__.py +76 -17
- psychopy/experiment/routines/eyetracker_validate/__init__.py +1 -1
- psychopy/experiment/routines/unknown/__init__.py +2 -0
- psychopy/experiment/routines/{photodiodeValidator → visualValidator}/__init__.py +89 -120
- psychopy/experiment/routines/visualValidator/classic/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/classic/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator@2x.png +0 -0
- psychopy/experiment/utils.py +1 -1
- psychopy/gui/__init__.py +1 -1
- psychopy/gui/qtgui.py +15 -6
- psychopy/gui/wxgui.py +1 -1
- psychopy/hardware/__init__.py +0 -1
- psychopy/hardware/base.py +147 -16
- psychopy/hardware/bbtk/__init__.py +10 -16
- psychopy/hardware/brainproducts.py +7 -13
- psychopy/hardware/button.py +21 -2
- psychopy/hardware/buttonbox/__init__.py +1 -1
- psychopy/hardware/camera/__init__.py +18 -5
- psychopy/hardware/cedrus.py +5 -16
- psychopy/hardware/crs/__init__.py +1 -1
- psychopy/hardware/crs/bits.py +36 -33
- psychopy/hardware/crs/colorcal.py +8 -11
- psychopy/hardware/crs/optical.py +7 -10
- psychopy/hardware/crs/shaders.py +18 -5
- psychopy/hardware/emotiv.py +1 -1
- psychopy/hardware/emulator.py +11 -5
- psychopy/hardware/exceptions.py +86 -0
- psychopy/hardware/forp.py +18 -23
- psychopy/hardware/gammasci.py +8 -3
- psychopy/hardware/iolab.py +8 -19
- psychopy/hardware/joystick/__init__.py +865 -266
- psychopy/hardware/joystick/_base.py +251 -0
- psychopy/hardware/joystick/backend_glfw.py +306 -0
- psychopy/hardware/joystick/backend_pyglet.py +309 -0
- psychopy/hardware/joystick/mappings.py +287 -0
- psychopy/hardware/keyboard.py +4 -2
- psychopy/hardware/labhackers.py +1 -1
- psychopy/hardware/labjacks.py +9 -13
- psychopy/hardware/{photodiode.py → lightsensor.py} +146 -203
- psychopy/hardware/listener.py +9 -8
- psychopy/hardware/manager.py +24 -35
- psychopy/hardware/microphone.py +535 -155
- psychopy/hardware/minolta.py +14 -4
- psychopy/hardware/mouse/__init__.py +1 -1
- psychopy/hardware/photometer/__init__.py +2 -2
- psychopy/hardware/pr.py +14 -4
- psychopy/hardware/qmix.py +18 -27
- psychopy/hardware/serialdevice.py +43 -12
- psychopy/hardware/soundsensor.py +473 -0
- psychopy/hardware/spatial/__init__.py +231 -0
- psychopy/hardware/speaker.py +298 -36
- psychopy/hardware/triggerbox/__init__.py +1 -1
- psychopy/hardware/triggerbox/base.py +1 -1
- psychopy/hardware/triggerbox/parallel.py +1 -1
- psychopy/info.py +1 -1
- psychopy/iohub/devices/eyetracker/__init__.py +10 -18
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +15 -33
- psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +2 -2
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/__init__.py +1 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/eyetracker.py +10 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/__init__.py +1 -0
- psychopy/iohub/devices/mouse/linux2.py +2 -1
- psychopy/layout.py +1 -1
- psychopy/liaison.py +91 -39
- psychopy/locale_setup.py +11 -1
- psychopy/localization/__init__.py +1 -1
- psychopy/localization/_localization.py +1 -1
- psychopy/localization/messages.pot +2 -2
- psychopy/logging.py +14 -12
- psychopy/microphone.py +4 -3
- psychopy/misc.py +1 -1
- psychopy/monitors/MonitorCenter.py +3 -3
- psychopy/monitors/__init__.py +1 -1
- psychopy/monitors/calibData.py +1 -1
- psychopy/monitors/calibTools.py +3 -2
- psychopy/platform_specific/__init__.py +1 -1
- psychopy/platform_specific/darwin.py +1 -1
- psychopy/platform_specific/linux.py +1 -1
- psychopy/platform_specific/win32.py +1 -1
- psychopy/plugins/__init__.py +26 -17
- psychopy/plugins/util.py +65 -0
- psychopy/preferences/Darwin.spec +11 -3
- psychopy/preferences/FreeBSD.spec +11 -3
- psychopy/preferences/Linux.spec +11 -3
- psychopy/preferences/Windows.spec +11 -3
- psychopy/preferences/__init__.py +1 -1
- psychopy/preferences/baseNoArch.spec +11 -3
- psychopy/preferences/hints.py +78 -61
- psychopy/preferences/preferences.py +82 -13
- psychopy/projects/__init__.py +1 -1
- psychopy/projects/pavlovia.py +29 -13
- psychopy/scripts/psyexpCompile.py +1 -1
- psychopy/session.py +81 -8
- psychopy/sound/__init__.py +25 -10
- psychopy/sound/_base.py +134 -34
- psychopy/sound/audioclip.py +38 -15
- psychopy/sound/audiodevice.py +1 -1
- psychopy/sound/backend_ptb.py +53 -321
- psychopy/sound/backend_pygame.py +7 -3
- psychopy/sound/backend_pyo.py +53 -22
- psychopy/sound/backend_pysound.py +10 -27
- psychopy/sound/backend_sounddevice.py +33 -21
- psychopy/sound/exceptions.py +1 -1
- psychopy/sound/microphone.py +83 -5
- psychopy/sound/transcribe.py +3 -3
- psychopy/tests/data/test_basic_run.py +1 -0
- psychopy/tests/data/test_sounds/default_16000.wav +0 -0
- psychopy/tests/data/test_sounds/default_192000.wav +0 -0
- psychopy/tests/data/test_sounds/default_22050.wav +0 -0
- psychopy/tests/data/test_sounds/default_32000.wav +0 -0
- psychopy/tests/data/test_sounds/default_44100.wav +0 -0
- psychopy/tests/data/test_sounds/default_48000.wav +0 -0
- psychopy/tests/data/test_sounds/default_8000.wav +0 -0
- psychopy/tests/data/test_sounds/default_96000.wav +0 -0
- psychopy/tests/test_alerts/test_alerttools.py +2 -1
- psychopy/tests/test_app/test_command_line.py +65 -0
- psychopy/tests/test_data/test_TrialHandler2.py +18 -7
- psychopy/tests/test_demos/test_builder_demos.py +1 -1
- psychopy/tests/test_experiment/needs_wx/componsTemplate.txt +5238 -4188
- psychopy/tests/test_experiment/needs_wx/test_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_RoutineSettingsComponent.py +16 -0
- psychopy/tests/test_experiment/test_components/test_all_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_base_components.py +26 -17
- psychopy/tests/test_experiment/test_loops.py +12 -4
- psychopy/tests/test_experiment/test_params.py +17 -4
- psychopy/tests/test_experiment/test_routines/test_PhotodiodeValidationRoutine.py +2 -2
- psychopy/tests/test_hardware/test_photodiode.py +66 -0
- psychopy/tests/test_liaison/test_Liaison.py +4 -4
- psychopy/tests/test_misc/test_clock.py +2 -0
- psychopy/tests/test_misc/test_color.py +2 -0
- psychopy/tests/test_misc/test_event.py +1 -0
- psychopy/tests/test_plugins/__init__.py +0 -0
- psychopy/tests/test_plugins/test_plugin_stubs.py +125 -0
- psychopy/tests/test_sound/test_sound.py +111 -40
- psychopy/tests/test_tools/test_colorspacetools.py +24 -23
- psychopy/tests/test_tools/test_mathtools.py +9 -9
- psychopy/tests/test_tools/test_viewtools.py +101 -0
- psychopy/tests/test_validators/__init__.py +0 -0
- psychopy/tests/test_validators/test_voicekeyValidator.py +95 -0
- psychopy/tests/test_visual/test_all_stimuli.py +2 -2
- psychopy/tests/test_visual/test_basevisual.py +37 -7
- psychopy/tests/test_visual/test_button.py +2 -2
- psychopy/tests/test_visual/test_circle.py +10 -2
- psychopy/tests/test_visual/test_dots.py +1 -1
- psychopy/tests/test_visual/test_form.py +13 -13
- psychopy/tests/test_visual/test_gamma.py +3 -3
- psychopy/tests/test_visual/test_image.py +2 -2
- psychopy/tests/test_visual/test_progress.py +2 -2
- psychopy/tests/test_visual/test_roi.py +8 -2
- psychopy/tests/test_visual/test_shape.py +2 -2
- psychopy/tests/test_visual/test_slider.py +2 -2
- psychopy/tests/test_visual/test_target.py +2 -2
- psychopy/tests/test_visual/test_textbox.py +6 -8
- psychopy/tests/test_visual/test_winScalePos.py +6 -5
- psychopy/tests/test_visual/test_window.py +17 -0
- psychopy/tests/utils.py +51 -1
- psychopy/tools/__init__.py +1 -1
- psychopy/tools/arraytools.py +2 -2
- psychopy/tools/attributetools.py +52 -1
- psychopy/tools/audiotools.py +4 -1
- psychopy/tools/colorspacetools.py +6 -4
- psychopy/tools/coordinatetools.py +1 -1
- psychopy/tools/fileerrortools.py +21 -9
- psychopy/tools/filetools.py +2 -2
- psychopy/tools/fontmanager.py +47 -28
- psychopy/tools/gltools.py +2967 -559
- psychopy/tools/imagetools.py +1 -1
- psychopy/tools/mathtools.py +997 -127
- psychopy/tools/monitorunittools.py +7 -1
- psychopy/tools/movietools.py +1 -2
- psychopy/tools/pkgtools.py +157 -127
- psychopy/tools/plottools.py +1 -1
- psychopy/tools/rifttools.py +1 -1
- psychopy/tools/stereotools.py +1 -1
- psychopy/tools/stimulustools.py +172 -2
- psychopy/tools/stringtools.py +22 -2
- psychopy/tools/systemtools.py +1 -1
- psychopy/tools/typetools.py +1 -1
- psychopy/tools/unittools.py +1 -1
- psychopy/tools/versionchooser.py +3 -1
- psychopy/tools/viewtools.py +54 -70
- psychopy/tools/wizard.py +2 -2
- psychopy/validation/__init__.py +6 -0
- psychopy/validation/audio.py +74 -0
- psychopy/validation/visual.py +115 -0
- psychopy/visual/__init__.py +1 -4
- psychopy/visual/aperture.py +9 -6
- psychopy/visual/backends/__init__.py +1 -1
- psychopy/visual/backends/_base.py +1 -1
- psychopy/visual/backends/gamma.py +1 -1
- psychopy/visual/backends/glfwbackend.py +8 -12
- psychopy/visual/backends/pygamebackend.py +1 -1
- psychopy/visual/backends/pygletbackend.py +32 -11
- psychopy/visual/basevisual.py +93 -13
- psychopy/visual/brush.py +1 -1
- psychopy/visual/bufferimage.py +90 -10
- psychopy/visual/button.py +1 -1
- psychopy/visual/circle.py +12 -20
- psychopy/visual/custommouse.py +1 -1
- psychopy/visual/dot.py +80 -14
- psychopy/visual/elementarray.py +84 -10
- psychopy/visual/filters.py +1 -1
- psychopy/visual/form.py +43 -28
- psychopy/visual/grating.py +105 -25
- psychopy/visual/helpers.py +4 -2
- psychopy/visual/image.py +98 -20
- psychopy/visual/line.py +15 -25
- psychopy/visual/movie.py +1 -1
- psychopy/visual/movie2.py +4 -3
- psychopy/visual/movie3.py +4 -3
- psychopy/visual/movies/__init__.py +1 -1
- psychopy/visual/movies/frame.py +1 -1
- psychopy/visual/movies/metadata.py +1 -1
- psychopy/visual/movies/players/__init__.py +1 -1
- psychopy/visual/movies/players/_base.py +1 -1
- psychopy/visual/movies/players/ffpyplayer_player.py +2 -3
- psychopy/visual/nnlvs.py +9 -6
- psychopy/visual/noise.py +4 -16
- psychopy/visual/patch.py +4 -3
- psychopy/visual/pie.py +3 -14
- psychopy/visual/polygon.py +21 -28
- psychopy/visual/radial.py +4 -18
- psychopy/visual/ratingscale.py +4 -3
- psychopy/visual/rect.py +16 -25
- psychopy/visual/rift.py +8 -2
- psychopy/visual/secondorder.py +4 -16
- psychopy/visual/shaders.py +620 -286
- psychopy/visual/shape.py +281 -90
- psychopy/visual/simpleimage.py +1 -1
- psychopy/visual/slider.py +78 -25
- psychopy/visual/stim3d.py +5 -608
- psychopy/visual/text.py +13 -3
- psychopy/visual/textbox2/textbox2.py +188 -56
- psychopy/visual/vlcmoviestim.py +1 -1
- psychopy/visual/window.py +374 -201
- psychopy/web.py +1 -1
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/METADATA +13 -12
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/RECORD +647 -624
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/WHEEL +1 -1
- psychopy/.DS_Store +0 -0
- psychopy/__init__.py.orig +0 -65
- psychopy/app/.DS_Store +0 -0
- psychopy/app/Resources/.DS_Store +0 -0
- psychopy/app/Resources/classic/filecsv16.png +0 -0
- psychopy/app/Resources/classic/fileimage16.png +0 -0
- psychopy/app/Resources/classic/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/filecsv16.png +0 -0
- psychopy/app/Resources/dark/filecsv16@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage16.png +0 -0
- psychopy/app/Resources/dark/fileimage16@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/fonts/OpenSans-Bold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-BoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Italic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Light.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-LightItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Regular.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBoldItalic.ttf +0 -0
- psychopy/app/Resources/light/filecsv16.png +0 -0
- psychopy/app/Resources/light/filecsv16@2x.png +0 -0
- psychopy/app/Resources/light/fileimage16.png +0 -0
- psychopy/app/Resources/light/fileimage16@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown16.png +0 -0
- psychopy/app/Resources/light/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/psychopySplash.png +0 -0
- psychopy/app/Resources/psychopySplash@2x.png +0 -0
- psychopy/app/builder/builder.py.orig +0 -3932
- psychopy/app/builder/dialogs/__init__.py.orig +0 -1679
- psychopy/app/builder/dialogs/paramCtrls.py.orig +0 -713
- psychopy/app/colorpicker/__init__.py.orig +0 -411
- psychopy/app/locale/ar_001/.DS_Store +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/.DS_Store +0 -0
- psychopy/core.py.orig +0 -169
- psychopy/demos/builder/.DS_Store +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +0 -330
- psychopy/demos/builder/Experiments/.DS_Store +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/archived_conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/draw grid stim.py +0 -61
- psychopy/demos/builder/Experiments/dragAndDrop/shapeMaker.psyexp +0 -91
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/updated_conditions.xlsx +0 -0
- psychopy/demos/builder/Tools/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +0 -38
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +0 -3418
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +0 -2
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +0 -15
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +0 -562
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
- psychopy/demos/coder/iohub/.iohpid +0 -1
- psychopy/demos/coder/iohub/eyetracking/.iohpid +0 -1
- psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/.DS_Store +0 -0
- psychopy/experiment/_experiment.py.orig +0 -1032
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/_base.py.orig +0 -823
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py.orig +0 -490
- psychopy/experiment/components/settings/__init__.py.orig +0 -1337
- psychopy/experiment/components/textbox/__init__.py.orig +0 -310
- psychopy/experiment/components/webcam/.DS_Store +0 -0
- psychopy/experiment/components/webcam/light/.DS_Store +0 -0
- psychopy/experiment/loops.py.orig +0 -829
- psychopy/experiment/params.py.orig +0 -408
- psychopy/experiment/routine.py.orig +0 -503
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator@2x.png +0 -0
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/brainproducts.py.orig +0 -680
- psychopy/hardware/iolab.py.orig +0 -238
- psychopy/iohub/datastore/__init__.py.orig +0 -443
- psychopy/iohub/datastore/util.py.orig +0 -692
- psychopy/iohub/devices/mouse/darwin.py.orig +0 -427
- psychopy/iohub/devices/mouse/linux2.py.orig +0 -198
- psychopy/preferences/.DS_Store +0 -0
- psychopy/projects/pavlovia.py.orig +0 -1295
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestCircle_fill_local.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
- psychopy/tests/data/aperture1_norm_local.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_height_local.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_norm_local.png +0 -0
- psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
- psychopy/tests/data/blend_add_height_local.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
- psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
- psychopy/tests/data/blend_add_norm_local.png +0 -0
- psychopy/tests/data/blend_add_stencil_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
- psychopy/tests/data/circleHex_height_local.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
- psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
- psychopy/tests/data/circleHex_norm_local.png +0 -0
- psychopy/tests/data/circleHex_stencil_local.png +0 -0
- psychopy/tests/data/color_comparison_local.png +0 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/dots_height_local.png +0 -0
- psychopy/tests/data/dots_normAddBlend_local.png +0 -0
- psychopy/tests/data/dots_normHexbackground_local.png +0 -0
- psychopy/tests/data/dots_normNoShade_local.png +0 -0
- psychopy/tests/data/dots_norm_local.png +0 -0
- psychopy/tests/data/dots_stencil_local.png +0 -0
- psychopy/tests/data/elarray1_height_local.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
- psychopy/tests/data/elarray1_norm_local.png +0 -0
- psychopy/tests/data/elarray1_stencil_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
- psychopy/tests/data/gabor1_height_local.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
- psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
- psychopy/tests/data/gabor1_norm_local.png +0 -0
- psychopy/tests/data/gabor1_stencil_local.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_height_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
- psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
- psychopy/tests/data/movFrame1_stencil_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/numpyImage_height_local.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
- psychopy/tests/data/numpyImage_norm_local.png +0 -0
- psychopy/tests/data/numpyImage_stencil_local.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
- psychopy/tests/data/shape2_1_norm_local.png +0 -0
- psychopy/tests/data/shape2_1_stencil_local.png +0 -0
- psychopy/tests/data/text1_height_local.png +0 -0
- psychopy/tests/data/text1_normAddBlend_local.png +0 -0
- psychopy/tests/data/text1_normHexbackground_local.png +0 -0
- psychopy/tests/data/text1_norm_local.png +0 -0
- psychopy/tests/data/text1_stencil_local.png +0 -0
- psychopy/tests/data/wedge1_height_local.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
- psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
- psychopy/tests/data/wedge1_norm_local.png +0 -0
- psychopy/tests/data/wedge1_stencil_local.png +0 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +0 -177
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +0 -168
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
- psychopy/tests/test_data/.DS_Store +0 -0
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py +0 -67
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +0 -68
- psychopy/tests/test_hardware/test_CRS_bitsShaders.py +0 -110
- psychopy/tests/test_visual/test_image.py.orig +0 -219
- psychopy/visual/basevisual.py.orig +0 -1723
- psychopy/visual/form.py.orig +0 -1181
- psychopy/visual/text.py.orig +0 -752
- psychopy/visual/textbox2/textbox2.py.orig +0 -1315
- psychopy/visual/windowwarp.py.orig +0 -463
- /psychopy/{app/cortex.log → alerts/alertsCatalogue/3600.yaml} +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Bold.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-BoldItalic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Italic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/DejaVuSerif.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/IndieFlower-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-VariableFont_wght.ttf +0 -0
- /psychopy/demos/builder/Experiments/{GoNoGo → goNoGo}/readme.md +0 -0
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/entry_points.txt +0 -0
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/licenses/LICENSE +0 -0
psychopy/tools/mathtools.py
CHANGED
|
@@ -1,80 +1,829 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
"""Various math functions for working with vectors, matrices, and quaternions.
|
|
5
|
+
"""
|
|
6
6
|
|
|
7
7
|
# Part of the PsychoPy library
|
|
8
|
-
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-
|
|
8
|
+
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2025 Open Science Tools Ltd.
|
|
9
9
|
# Distributed under the terms of the GNU General Public License (GPL).
|
|
10
10
|
|
|
11
|
-
__all__ = [
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
11
|
+
__all__ = [
|
|
12
|
+
'VEC_AXES', # constants
|
|
13
|
+
'VEC_AXIS_FORWARD',
|
|
14
|
+
'VEC_AXIS_BACKWARD',
|
|
15
|
+
'VEC_AXIS_UP',
|
|
16
|
+
'VEC_AXIS_DOWN',
|
|
17
|
+
'VEC_AXIS_RIGHT',
|
|
18
|
+
'VEC_AXIS_LEFT',
|
|
19
|
+
'VEC_AXIS_POS_X',
|
|
20
|
+
'VEC_AXIS_NEG_X',
|
|
21
|
+
'VEC_AXIS_POS_Y',
|
|
22
|
+
'VEC_AXIS_NEG_Y',
|
|
23
|
+
'VEC_AXIS_POS_Z',
|
|
24
|
+
'VEC_AXIS_NEG_Z',
|
|
25
|
+
'RigidBodyPose', # rigid body pose class
|
|
26
|
+
'BoundingBox',
|
|
27
|
+
'length', # vector functions
|
|
28
|
+
'normalize',
|
|
29
|
+
'orthogonalize',
|
|
30
|
+
'reflect',
|
|
31
|
+
'dot',
|
|
32
|
+
'cross',
|
|
33
|
+
'project',
|
|
34
|
+
'lerp',
|
|
35
|
+
'distance',
|
|
36
|
+
'perp',
|
|
37
|
+
'bisector',
|
|
38
|
+
'angleTo',
|
|
39
|
+
'sortClockwise',
|
|
40
|
+
'surfaceNormal',
|
|
41
|
+
'surfaceBitangent',
|
|
42
|
+
'surfaceTangent',
|
|
43
|
+
'vertexNormal',
|
|
44
|
+
'fixTangentHandedness',
|
|
45
|
+
'fitBBox',
|
|
46
|
+
'computeBBoxCorners',
|
|
47
|
+
'intersectRayPlane',
|
|
48
|
+
'intersectRaySphere',
|
|
49
|
+
'intersectRayAABB',
|
|
50
|
+
'intersectRayOBB',
|
|
51
|
+
'intersectRayTriangle',
|
|
52
|
+
'ortho3Dto2D',
|
|
53
|
+
'articulate',
|
|
54
|
+
'slerp', # quaternion functions
|
|
55
|
+
'quatToAxisAngle',
|
|
56
|
+
'quatFromAxisAngle',
|
|
57
|
+
'quatYawPitchRoll',
|
|
58
|
+
'quatMagnitude',
|
|
59
|
+
'multQuat',
|
|
60
|
+
'invertQuat',
|
|
61
|
+
'applyQuat',
|
|
62
|
+
'accumQuat',
|
|
63
|
+
'alignTo',
|
|
64
|
+
'matrixToQuat',
|
|
65
|
+
'identityMatrix', # matrix functions
|
|
66
|
+
'quatToMatrix',
|
|
67
|
+
'scaleMatrix',
|
|
68
|
+
'rotationMatrix',
|
|
69
|
+
'translationMatrix',
|
|
70
|
+
'invertMatrix',
|
|
71
|
+
'multMatrix',
|
|
72
|
+
'concatenate',
|
|
73
|
+
'matrixFromEulerAngles',
|
|
74
|
+
'isOrthogonal',
|
|
75
|
+
'isAffine',
|
|
76
|
+
'applyMatrix',
|
|
77
|
+
'posOriToMatrix',
|
|
78
|
+
'transform',
|
|
79
|
+
'scale',
|
|
80
|
+
'normalMatrix',
|
|
81
|
+
'forwardProject',
|
|
82
|
+
'reverseProject',
|
|
83
|
+
'lookAt',
|
|
84
|
+
'zeroFix', # misc functions
|
|
85
|
+
'lensCorrection',
|
|
86
|
+
'lensCorrectionSpherical',
|
|
87
|
+
'infrange',
|
|
88
|
+
'setDefaultPrecision'
|
|
89
|
+
]
|
|
68
90
|
|
|
69
91
|
|
|
70
92
|
import numpy as np
|
|
71
93
|
import functools
|
|
72
94
|
import itertools
|
|
73
95
|
|
|
96
|
+
VEC_AXES = { # mapping of axis names to vectors
|
|
97
|
+
'+x': (1, 0, 0), '-x': (-1, 0, 0),
|
|
98
|
+
'+y': (0, 1, 0), '-y': (0, -1, 0),
|
|
99
|
+
'+z': (0, 0, 1), '-z': (0, 0, -1)}
|
|
100
|
+
|
|
101
|
+
# vectors for common axes
|
|
102
|
+
VEC_AXIS_BACKWARD = VEC_AXIS_POS_Z = VEC_AXES['+z']
|
|
103
|
+
VEC_AXIS_FORWARD = VEC_AXIS_NEG_Z = VEC_AXES['-z']
|
|
104
|
+
VEC_AXIS_UP = VEC_AXIS_POS_Y = VEC_AXES['+y']
|
|
105
|
+
VEC_AXIS_DOWN = VEC_AXIS_NEG_Y = VEC_AXES['-y']
|
|
106
|
+
VEC_AXIS_RIGHT = VEC_AXIS_POS_X = VEC_AXES['+x']
|
|
107
|
+
VEC_AXIS_LEFT = VEC_AXIS_NEG_X = VEC_AXES['-x']
|
|
108
|
+
|
|
109
|
+
DEFAULT_DTYPE = float
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def setDefaultPrecision(dtype='float64'):
|
|
113
|
+
"""Set the default precision for math functions.
|
|
114
|
+
|
|
115
|
+
Once set, all math functions in this module will use the specified data type
|
|
116
|
+
for computations in successive calls. This is useful when you want to ensure
|
|
117
|
+
a specific precision for all math operations.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
dtype : dtype or str
|
|
122
|
+
Data type for computations can either be 'float32' or 'float64'.
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
global DEFAULT_DTYPE
|
|
126
|
+
DEFAULT_DTYPE = np.dtype(dtype).type
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ------------------------------------------------------------------------------
|
|
130
|
+
# Classes for working with rigid body poses
|
|
131
|
+
#
|
|
132
|
+
|
|
133
|
+
class RigidBodyPose:
|
|
134
|
+
"""Class for representing rigid body poses.
|
|
135
|
+
|
|
136
|
+
This class is an abstract representation of a rigid body pose, where the
|
|
137
|
+
position of the body in a scene is represented by a vector/coordinate and
|
|
138
|
+
the orientation with a quaternion. Pose can be manipulated and interacted
|
|
139
|
+
with using class methods and attributes. Rigid body poses assume a
|
|
140
|
+
right-handed coordinate system (-Z is forward and +Y is up).
|
|
141
|
+
|
|
142
|
+
Poses can be converted to 4x4 transformation matrices with `getModelMatrix`.
|
|
143
|
+
One can use these matrices when rendering to transform the vertices of a
|
|
144
|
+
model associated with the pose by passing them to OpenGL. Matrices are
|
|
145
|
+
cached internally to avoid recomputing them if `pos` and `ori` attributes
|
|
146
|
+
have not been updated.
|
|
147
|
+
|
|
148
|
+
Operators `*` and `~` can be used on `RigidBodyPose` objects to combine and
|
|
149
|
+
invert poses. For instance, you can multiply (`*`) poses to get a new pose
|
|
150
|
+
which is the combination of both orientations and translations by::
|
|
151
|
+
|
|
152
|
+
newPose = rb1 * rb2
|
|
153
|
+
|
|
154
|
+
Likewise, a pose can be inverted by using the `~` operator::
|
|
155
|
+
|
|
156
|
+
invPose = ~rb
|
|
157
|
+
|
|
158
|
+
Multiplying a pose by its inverse will result in an identity pose with no
|
|
159
|
+
translation and default orientation where `pos=[0, 0, 0]` and
|
|
160
|
+
`ori=[0, 0, 0, 1]`::
|
|
161
|
+
|
|
162
|
+
identityPose = ~rb * rb
|
|
163
|
+
|
|
164
|
+
Warnings
|
|
165
|
+
--------
|
|
166
|
+
This class is experimental and may result in undefined behavior.
|
|
167
|
+
|
|
168
|
+
"""
|
|
169
|
+
def __init__(self, pos=(0., 0., 0.), ori=(0., 0., 0., 1.), dtype=None):
|
|
170
|
+
"""
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
pos : array_like
|
|
174
|
+
Position vector `[x, y, z]` for the origin of the rigid body.
|
|
175
|
+
ori : array_like
|
|
176
|
+
Orientation quaternion `[x, y, z, w]` where `x`, `y`, `z` are
|
|
177
|
+
imaginary and `w` is real.
|
|
178
|
+
dtype : dtype or str, optional
|
|
179
|
+
Data type for computations can either be 'float32' or 'float64'.
|
|
180
|
+
Default is `None` which uses the default data configured by
|
|
181
|
+
`setDefaultPrecision`.
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
# set the data type for computations
|
|
185
|
+
self._dtype = \
|
|
186
|
+
np.dtype(dtype).type if dtype is not None else DEFAULT_DTYPE
|
|
187
|
+
|
|
188
|
+
# position and orientation
|
|
189
|
+
self._pos = np.ascontiguousarray(pos, dtype=self.dtype)
|
|
190
|
+
self._ori = np.ascontiguousarray(ori, dtype=self.dtype)
|
|
191
|
+
|
|
192
|
+
self._modelMatrix = posOriToMatrix(
|
|
193
|
+
self._pos, self._ori, dtype=self.dtype)
|
|
194
|
+
|
|
195
|
+
# computed only if needed
|
|
196
|
+
self._normalMatrix = np.zeros((4, 4), dtype=self.dtype, order='C')
|
|
197
|
+
self._invModelMatrix = np.zeros((4, 4), dtype=self.dtype, order='C')
|
|
198
|
+
self._viewMatrix = np.zeros((4, 4), dtype=self.dtype, order='C')
|
|
199
|
+
self._invViewMatrix = np.zeros((4, 4), dtype=self.dtype, order='C')
|
|
200
|
+
|
|
201
|
+
# additional useful vectors
|
|
202
|
+
self._at = np.zeros((3,), dtype=self.dtype, order='C')
|
|
203
|
+
self._up = np.zeros((3,), dtype=self.dtype, order='C')
|
|
204
|
+
self._viewAxes = np.array( # cache for view matrix calculations
|
|
205
|
+
[VEC_AXIS_FORWARD, VEC_AXIS_UP], dtype=self.dtype, order='C')
|
|
206
|
+
|
|
207
|
+
# compute matrices only if `pos` and `ori` attributes have been updated,
|
|
208
|
+
# we track the state of the matrices with these flags
|
|
209
|
+
self._cacheFlags = {
|
|
210
|
+
'model': True, # already computed
|
|
211
|
+
'imodel': False,
|
|
212
|
+
'normal': False,
|
|
213
|
+
'view': False,
|
|
214
|
+
'iview': False
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
self.pos = pos
|
|
218
|
+
self.ori = ori
|
|
219
|
+
|
|
220
|
+
self._bounds = None
|
|
221
|
+
|
|
222
|
+
def __repr__(self):
|
|
223
|
+
return 'RigidBodyPose(pos={}, ori={})'.format(self.pos, self.ori)
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def dtype(self):
|
|
227
|
+
"""Data type used for computations and arrays (`numpy.dtype`).
|
|
228
|
+
|
|
229
|
+
Cannot be changed after object creation.
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
return self._dtype
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def bounds(self):
|
|
236
|
+
"""Bounding box associated with this pose.
|
|
237
|
+
"""
|
|
238
|
+
return self._bounds
|
|
239
|
+
|
|
240
|
+
@bounds.setter
|
|
241
|
+
def bounds(self, value):
|
|
242
|
+
self._bounds = value
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def pos(self):
|
|
246
|
+
"""Position vector (X, Y, Z).
|
|
247
|
+
"""
|
|
248
|
+
return self._pos
|
|
249
|
+
|
|
250
|
+
@pos.setter
|
|
251
|
+
def pos(self, value):
|
|
252
|
+
self._pos = np.ascontiguousarray(value, dtype=self.dtype)
|
|
253
|
+
self._cacheFlags = dict.fromkeys(self._cacheFlags.keys(), True)
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def ori(self):
|
|
257
|
+
"""Orientation quaternion (X, Y, Z, W).
|
|
258
|
+
"""
|
|
259
|
+
return self._ori
|
|
260
|
+
|
|
261
|
+
@ori.setter
|
|
262
|
+
def ori(self, value):
|
|
263
|
+
self._ori = np.ascontiguousarray(value, dtype=self.dtype)
|
|
264
|
+
self._cacheFlags = dict.fromkeys(self._cacheFlags.keys(), True)
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def posOri(self):
|
|
268
|
+
"""The position (x, y, z) and orientation (x, y, z, w).
|
|
269
|
+
"""
|
|
270
|
+
return self._pos, self._ori
|
|
271
|
+
|
|
272
|
+
@posOri.setter
|
|
273
|
+
def posOri(self, value):
|
|
274
|
+
self._pos = np.ascontiguousarray(value[0], dtype=self.dtype)
|
|
275
|
+
self._ori = np.ascontiguousarray(value[1], dtype=self.dtype)
|
|
276
|
+
self._cacheFlags = dict.fromkeys(self._cacheFlags.keys(), True)
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def at(self):
|
|
280
|
+
"""Vector defining the forward direction (-Z) of this pose.
|
|
281
|
+
"""
|
|
282
|
+
# matrix needs update, this need to be too
|
|
283
|
+
if self._cacheFlags['model']:
|
|
284
|
+
self._at = applyQuat(
|
|
285
|
+
self.ori, self._viewAxes[0, :], out=self._at, dtype=self.dtype)
|
|
286
|
+
|
|
287
|
+
return self._at
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def up(self):
|
|
291
|
+
"""Vector defining the up direction (+Y) of this pose.
|
|
292
|
+
"""
|
|
293
|
+
if self._cacheFlags['model']:
|
|
294
|
+
self._up = applyQuat(
|
|
295
|
+
self.ori, self._viewAxes[1, :], out=self._up, dtype=self.dtype)
|
|
296
|
+
|
|
297
|
+
return self._up
|
|
298
|
+
|
|
299
|
+
def __mul__(self, other):
|
|
300
|
+
"""Multiply two poses, combining them to get a new pose.
|
|
301
|
+
"""
|
|
302
|
+
newOri = multQuat(self._ori, other.ori)
|
|
303
|
+
return RigidBodyPose(transform(other.pos, newOri, self._pos), newOri)
|
|
304
|
+
|
|
305
|
+
def __imul__(self, other):
|
|
306
|
+
"""Inplace multiplication. Transforms this pose by another.
|
|
307
|
+
"""
|
|
308
|
+
self._ori = multQuat(self._ori, other.ori)
|
|
309
|
+
self._pos = transform(other.pos, self._ori, self._pos)
|
|
310
|
+
|
|
311
|
+
def copy(self):
|
|
312
|
+
"""Get a new `RigidBodyPose` object which copies the position and
|
|
313
|
+
orientation of this one. Copies are independent and do not reference
|
|
314
|
+
each others data.
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
RigidBodyPose
|
|
319
|
+
Copy of this pose.
|
|
320
|
+
|
|
321
|
+
"""
|
|
322
|
+
return RigidBodyPose(self._pos, self._ori)
|
|
323
|
+
|
|
324
|
+
def isEqual(self, other):
|
|
325
|
+
"""Check if poses have similar orientation and position.
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
other : `RigidBodyPose`
|
|
330
|
+
Other pose to compare.
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
bool
|
|
335
|
+
Returns `True` is poses are effectively equal.
|
|
336
|
+
|
|
337
|
+
"""
|
|
338
|
+
return np.isclose(self._pos, other.pos) and \
|
|
339
|
+
np.isclose(self._ori, other.ori)
|
|
340
|
+
|
|
341
|
+
def clear(self):
|
|
342
|
+
"""Clear the pose, setting position and orientation to zero.
|
|
343
|
+
"""
|
|
344
|
+
self._pos.fill(0.0)
|
|
345
|
+
self._ori[:3] = 0.0
|
|
346
|
+
self._ori[3] = 1.0
|
|
347
|
+
self._cacheFlags = dict.fromkeys(a.keys(), True)
|
|
348
|
+
|
|
349
|
+
def setIdentity(self):
|
|
350
|
+
"""Clear rigid body transformations (alias for `clear`).
|
|
351
|
+
"""
|
|
352
|
+
self.clear()
|
|
353
|
+
|
|
354
|
+
def getOriAxisAngle(self, degrees=True):
|
|
355
|
+
"""Get the axis and angle of rotation for the rigid body. Converts the
|
|
356
|
+
orientation defined by the `ori` quaternion to and axis-angle
|
|
357
|
+
representation.
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
degrees : bool, optional
|
|
362
|
+
Specify ``True`` if `angle` is in degrees, or else it will be
|
|
363
|
+
treated as radians. Default is ``True``.
|
|
364
|
+
|
|
365
|
+
Returns
|
|
366
|
+
-------
|
|
367
|
+
tuple
|
|
368
|
+
Axis [rx, ry, rz] and angle.
|
|
369
|
+
|
|
370
|
+
"""
|
|
371
|
+
return quatToAxisAngle(self._ori, degrees, dtype=self.dtype)
|
|
372
|
+
|
|
373
|
+
def setOriAxisAngle(self, axis, angle, degrees=True):
|
|
374
|
+
"""Set the orientation of the rigid body using an `axis` and
|
|
375
|
+
`angle`. This sets the quaternion at `ori`.
|
|
376
|
+
|
|
377
|
+
Parameters
|
|
378
|
+
----------
|
|
379
|
+
axis : array_like
|
|
380
|
+
Axis of rotation [rx, ry, rz].
|
|
381
|
+
angle : float
|
|
382
|
+
Angle of rotation.
|
|
383
|
+
degrees : bool, optional
|
|
384
|
+
Specify ``True`` if `angle` is in degrees, or else it will be
|
|
385
|
+
treated as radians. Default is ``True``.
|
|
386
|
+
|
|
387
|
+
"""
|
|
388
|
+
self.ori = quatFromAxisAngle(axis, angle, degrees, dtype=self.dtype)
|
|
389
|
+
|
|
390
|
+
def getYawPitchRoll(self, degrees=True):
|
|
391
|
+
"""Get the yaw, pitch and roll angles for this pose relative to the -Z
|
|
392
|
+
world axis.
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
degrees : bool, optional
|
|
397
|
+
Specify ``True`` if `angle` is in degrees, or else it will be
|
|
398
|
+
treated as radians. Default is ``True``.
|
|
399
|
+
|
|
400
|
+
"""
|
|
401
|
+
return quatYawPitchRoll(self._ori, degrees, dtype=self.dtype)
|
|
402
|
+
|
|
403
|
+
@property
|
|
404
|
+
def modelMatrix(self):
|
|
405
|
+
"""Pose as a 4x4 model matrix (read-only)."""
|
|
406
|
+
if not self._cacheFlags['model']:
|
|
407
|
+
return self._modelMatrix
|
|
408
|
+
else:
|
|
409
|
+
return self.getModelMatrix()
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def inverseModelMatrix(self):
|
|
413
|
+
"""Inverse of the pose as a 4x4 model matrix (read-only)."""
|
|
414
|
+
if not self._cacheFlags['imodel']:
|
|
415
|
+
return self._invModelMatrix
|
|
416
|
+
else:
|
|
417
|
+
return self.getModelMatrix(inverse=True)
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
def normalMatrix(self):
|
|
421
|
+
"""The 4x4 normal transformation matrix (read-only)."""
|
|
422
|
+
if not self._cacheFlags['normal']:
|
|
423
|
+
return self._normalMatrix
|
|
424
|
+
else:
|
|
425
|
+
return self.getNormalMatrix()
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
def viewMatrix(self):
|
|
429
|
+
"""The 4x4 view matrix for this pose (read-only)."""
|
|
430
|
+
if not self._cacheFlags['view']:
|
|
431
|
+
return self._viewMatrix
|
|
432
|
+
else:
|
|
433
|
+
return self.getViewMatrix()
|
|
434
|
+
|
|
435
|
+
@property
|
|
436
|
+
def inverseViewMatrix(self):
|
|
437
|
+
"""The inverse of the 4x4 view matrix for this pose (read-only)."""
|
|
438
|
+
if not self._cacheFlags['iview']:
|
|
439
|
+
return self._invViewMatrix
|
|
440
|
+
else:
|
|
441
|
+
return self.getViewMatrix(inverse=True)
|
|
442
|
+
|
|
443
|
+
def getNormalMatrix(self, out=None):
|
|
444
|
+
"""Get the present normal matrix.
|
|
445
|
+
|
|
446
|
+
Parameters
|
|
447
|
+
----------
|
|
448
|
+
out : ndarray or None
|
|
449
|
+
Optional 4x4 array to write values to. Values written are computed
|
|
450
|
+
using 32-bit float precision regardless of the data type of `out`.
|
|
451
|
+
|
|
452
|
+
Returns
|
|
453
|
+
-------
|
|
454
|
+
ndarray
|
|
455
|
+
4x4 normal transformation matrix.
|
|
456
|
+
|
|
457
|
+
"""
|
|
458
|
+
if not self._cacheFlags['normal']:
|
|
459
|
+
return self._normalMatrix
|
|
460
|
+
|
|
461
|
+
self._normalMatrix[:, :] = np.linalg.inv(self.modelMatrix).T
|
|
462
|
+
self._cacheFlags['normal'] = False
|
|
463
|
+
|
|
464
|
+
if out is not None:
|
|
465
|
+
out[:, :] = self._normalMatrix[:, :]
|
|
466
|
+
return out
|
|
467
|
+
|
|
468
|
+
return self._normalMatrix
|
|
469
|
+
|
|
470
|
+
def getModelMatrix(self, inverse=False, out=None):
|
|
471
|
+
"""Get the present rigid body transformation as a 4x4 matrix.
|
|
472
|
+
|
|
473
|
+
Matrices are computed only if the `pos` and `ori` attributes have been
|
|
474
|
+
updated since the last call to `getModelMatrix`. The returned matrix is
|
|
475
|
+
an `ndarray` and row-major.
|
|
476
|
+
|
|
477
|
+
Parameters
|
|
478
|
+
----------
|
|
479
|
+
inverse : bool, optional
|
|
480
|
+
Return the inverse of the model matrix.
|
|
481
|
+
out : ndarray or None
|
|
482
|
+
Optional 4x4 array to write values to. Values written are computed
|
|
483
|
+
using 32-bit float precision regardless of the data type of `out`.
|
|
484
|
+
|
|
485
|
+
Returns
|
|
486
|
+
-------
|
|
487
|
+
ndarray
|
|
488
|
+
4x4 transformation matrix.
|
|
489
|
+
|
|
490
|
+
Examples
|
|
491
|
+
--------
|
|
492
|
+
Using a rigid body pose to transform something in OpenGL::
|
|
493
|
+
|
|
494
|
+
rb = RigidBodyPose((0, 0, -2)) # 2 meters away from origin
|
|
495
|
+
|
|
496
|
+
# Use `array2pointer` from `psychopy.tools.arraytools` to convert
|
|
497
|
+
# array to something OpenGL accepts.
|
|
498
|
+
mv = array2pointer(rb.modelMatrix)
|
|
499
|
+
|
|
500
|
+
# use the matrix to transform the scene
|
|
501
|
+
glMatrixMode(GL_MODELVIEW)
|
|
502
|
+
glPushMatrix()
|
|
503
|
+
glLoadIdentity()
|
|
504
|
+
glMultTransposeMatrixf(mv)
|
|
505
|
+
|
|
506
|
+
# draw the thing here ...
|
|
507
|
+
|
|
508
|
+
glPopMatrix()
|
|
509
|
+
|
|
510
|
+
"""
|
|
511
|
+
if self._cacheFlags['model']:
|
|
512
|
+
self._modelMatrix = posOriToMatrix(
|
|
513
|
+
self._pos, self._ori,
|
|
514
|
+
out=self._modelMatrix,
|
|
515
|
+
dtype=self.dtype)
|
|
516
|
+
|
|
517
|
+
# all other matrices need update when next accessed
|
|
518
|
+
self._cacheFlags['model'] = False
|
|
519
|
+
self._cacheFlags['imodel'] = True
|
|
520
|
+
self._cacheFlags['normal'] = True
|
|
521
|
+
self._cacheFlags['view'] = True
|
|
522
|
+
self._cacheFlags['iview'] = True
|
|
523
|
+
|
|
524
|
+
if not inverse:
|
|
525
|
+
toReturn = self._modelMatrix
|
|
526
|
+
else:
|
|
527
|
+
if self._cacheFlags['imodel']:
|
|
528
|
+
self._invModelMatrix = invertMatrix(
|
|
529
|
+
self._modelMatrix, out=self._invModelMatrix,
|
|
530
|
+
dtype=self.dtype)
|
|
531
|
+
self._cacheFlags['imodel'] = False
|
|
532
|
+
|
|
533
|
+
toReturn = self._invModelMatrix
|
|
534
|
+
|
|
535
|
+
if out is not None:
|
|
536
|
+
out[:, :] = toReturn[:, :]
|
|
537
|
+
return out
|
|
538
|
+
|
|
539
|
+
return toReturn
|
|
540
|
+
|
|
541
|
+
def getViewMatrix(self, inverse=False, out=None):
|
|
542
|
+
"""Convert this pose into a view matrix.
|
|
543
|
+
|
|
544
|
+
Creates a view matrix which transforms points into eye space using the
|
|
545
|
+
current pose as the eye position in the scene. Furthermore, you can use
|
|
546
|
+
view matrices for rendering shadows if light positions are defined
|
|
547
|
+
as `RigidBodyPose` objects.
|
|
548
|
+
|
|
549
|
+
Parameters
|
|
550
|
+
----------
|
|
551
|
+
inverse : bool
|
|
552
|
+
Return the inverse of the view matrix. Default is `False`.
|
|
553
|
+
out : ndarray or None
|
|
554
|
+
Optional 4x4 array to write values to. Values written are computed
|
|
555
|
+
using 32-bit float precision regardless of the data type of `out`.
|
|
556
|
+
|
|
557
|
+
Returns
|
|
558
|
+
-------
|
|
559
|
+
ndarray
|
|
560
|
+
4x4 transformation matrix.
|
|
561
|
+
|
|
562
|
+
"""
|
|
563
|
+
if self._cacheFlags['view']: # needs update?
|
|
564
|
+
# compute the view matrix
|
|
565
|
+
rotMatrix = quatToMatrix(self._ori, dtype=self.dtype)
|
|
566
|
+
transformedAxes = applyMatrix(
|
|
567
|
+
rotMatrix, self._viewAxes,
|
|
568
|
+
dtype=self.dtype)
|
|
569
|
+
|
|
570
|
+
fwdVec = transformedAxes[0, :] + self._pos
|
|
571
|
+
upVec = transformedAxes[1, :]
|
|
572
|
+
|
|
573
|
+
self._viewMatrix = lookAt(
|
|
574
|
+
self._pos, fwdVec, upVec,
|
|
575
|
+
out=self._viewMatrix,
|
|
576
|
+
dtype=self.dtype)
|
|
577
|
+
|
|
578
|
+
self._cacheFlags['view'] = False
|
|
579
|
+
self._cacheFlags['iview'] = True # inverse needs update
|
|
580
|
+
|
|
581
|
+
if not inverse:
|
|
582
|
+
toReturn = self._viewMatrix
|
|
583
|
+
else:
|
|
584
|
+
if self._cacheFlags['iview']:
|
|
585
|
+
self._invViewMatrix = invertMatrix(
|
|
586
|
+
self._viewMatrix,
|
|
587
|
+
out=self._invViewMatrix,
|
|
588
|
+
dtype=self.dtype)
|
|
589
|
+
self._cacheFlags['iview'] = False
|
|
590
|
+
|
|
591
|
+
toReturn = self._invViewMatrix
|
|
592
|
+
|
|
593
|
+
if out is not None:
|
|
594
|
+
out[:, :] = toReturn[:, :]
|
|
595
|
+
return out
|
|
596
|
+
|
|
597
|
+
return toReturn
|
|
598
|
+
|
|
599
|
+
def transform(self, v, out=None):
|
|
600
|
+
"""Transform a vector using this pose.
|
|
601
|
+
|
|
602
|
+
Parameters
|
|
603
|
+
----------
|
|
604
|
+
v : array_like
|
|
605
|
+
Vector to transform [x, y, z].
|
|
606
|
+
out : ndarray or None, optional
|
|
607
|
+
Optional array to write values to. Must have the same shape as
|
|
608
|
+
`v`.
|
|
609
|
+
|
|
610
|
+
Returns
|
|
611
|
+
-------
|
|
612
|
+
ndarray
|
|
613
|
+
Transformed points.
|
|
614
|
+
|
|
615
|
+
"""
|
|
616
|
+
return transform(
|
|
617
|
+
self._pos, self._ori, points=v, out=out, dtype=self.dtype)
|
|
618
|
+
|
|
619
|
+
def transformNormal(self, n):
|
|
620
|
+
"""Rotate a normal vector with respect to this pose.
|
|
621
|
+
|
|
622
|
+
Rotates a normal vector `n` using the orientation quaternion at `ori`.
|
|
623
|
+
|
|
624
|
+
Parameters
|
|
625
|
+
----------
|
|
626
|
+
n : array_like
|
|
627
|
+
Normal to rotate (1-D with length 3).
|
|
628
|
+
|
|
629
|
+
Returns
|
|
630
|
+
-------
|
|
631
|
+
ndarray
|
|
632
|
+
Rotated normal `n`.
|
|
633
|
+
|
|
634
|
+
"""
|
|
635
|
+
pout = np.zeros((3,), dtype=self.dtype)
|
|
636
|
+
pout[:] = n
|
|
637
|
+
t = np.cross(self._ori[:3], n[:3]) * 2.0
|
|
638
|
+
u = np.cross(self._ori[:3], t)
|
|
639
|
+
t *= self._ori[3]
|
|
640
|
+
pout[:3] += t
|
|
641
|
+
pout[:3] += u
|
|
642
|
+
|
|
643
|
+
return pout
|
|
644
|
+
|
|
645
|
+
def __invert__(self):
|
|
646
|
+
"""Operator `~` to invert the pose. Returns a `RigidBodyPose` object.
|
|
647
|
+
"""
|
|
648
|
+
return RigidBodyPose(
|
|
649
|
+
-self._pos, invertQuat(self._ori, dtype=self.dtype))
|
|
650
|
+
|
|
651
|
+
def invert(self):
|
|
652
|
+
"""Invert this pose.
|
|
653
|
+
"""
|
|
654
|
+
self._ori = invertQuat(self._ori, dtype=self.dtype)
|
|
655
|
+
self._pos *= -1.0
|
|
656
|
+
|
|
657
|
+
def inverted(self):
|
|
658
|
+
"""Get a pose which is the inverse of this one.
|
|
659
|
+
|
|
660
|
+
Returns
|
|
661
|
+
-------
|
|
662
|
+
RigidBodyPose
|
|
663
|
+
This pose inverted.
|
|
664
|
+
|
|
665
|
+
"""
|
|
666
|
+
return RigidBodyPose(
|
|
667
|
+
-self._pos, invertQuat(self._ori, dtype=self.dtype))
|
|
668
|
+
|
|
669
|
+
def distanceTo(self, v):
|
|
670
|
+
"""Get the distance to a pose or point in scene units.
|
|
671
|
+
|
|
672
|
+
Parameters
|
|
673
|
+
----------
|
|
674
|
+
v : RigidBodyPose or array_like
|
|
675
|
+
Pose or point [x, y, z] to compute distance to.
|
|
676
|
+
|
|
677
|
+
Returns
|
|
678
|
+
-------
|
|
679
|
+
float
|
|
680
|
+
Distance to `v` from this pose's origin.
|
|
681
|
+
|
|
682
|
+
"""
|
|
683
|
+
if hasattr(v, 'pos'): # v is pose-like object
|
|
684
|
+
targetPos = v.pos
|
|
685
|
+
else:
|
|
686
|
+
targetPos = np.asarray(v[:3])
|
|
687
|
+
|
|
688
|
+
return np.sqrt(np.sum(np.square(targetPos - self.pos)))
|
|
689
|
+
|
|
690
|
+
def interp(self, end, s):
|
|
691
|
+
"""Interpolate between poses.
|
|
692
|
+
|
|
693
|
+
Linear interpolation is used on position (Lerp) while the orientation
|
|
694
|
+
has spherical linear interpolation (Slerp) applied taking the shortest
|
|
695
|
+
arc on the hypersphere.
|
|
696
|
+
|
|
697
|
+
Parameters
|
|
698
|
+
----------
|
|
699
|
+
end : RigidBodyPose
|
|
700
|
+
End pose.
|
|
701
|
+
s : float
|
|
702
|
+
Interpolation factor between interval 0.0 and 1.0.
|
|
703
|
+
|
|
704
|
+
Returns
|
|
705
|
+
-------
|
|
706
|
+
RigidBodyPose
|
|
707
|
+
Rigid body pose whose position and orientation is at `s` between
|
|
708
|
+
this pose and `end`.
|
|
709
|
+
|
|
710
|
+
"""
|
|
711
|
+
if not (hasattr(end, 'pos') and hasattr(end, 'ori')):
|
|
712
|
+
raise TypeError("Object for `end` does not have attributes "
|
|
713
|
+
"`pos` and `ori`.")
|
|
714
|
+
|
|
715
|
+
interpPos = lerp(self._pos, end.pos, s, dtype=self.dtype)
|
|
716
|
+
interpOri = slerp(self._ori, end.ori, s, dtype=self.dtype)
|
|
717
|
+
|
|
718
|
+
return RigidBodyPose(interpPos, interpOri)
|
|
719
|
+
|
|
720
|
+
def alignTo(self, alignTo):
|
|
721
|
+
"""Align this pose to another point or pose.
|
|
722
|
+
|
|
723
|
+
This sets the orientation of this pose to one which orients the forward
|
|
724
|
+
axis towards `alignTo`.
|
|
725
|
+
|
|
726
|
+
Parameters
|
|
727
|
+
----------
|
|
728
|
+
alignTo : array_like or RigidBodyPose
|
|
729
|
+
Position vector [x, y, z] or pose to align to.
|
|
730
|
+
|
|
731
|
+
"""
|
|
732
|
+
if hasattr(alignTo, 'pos'): # v is pose-like object
|
|
733
|
+
targetPos = alignTo.pos
|
|
734
|
+
else:
|
|
735
|
+
targetPos = np.asarray(alignTo[:3]) # handle array_like
|
|
736
|
+
|
|
737
|
+
fwd = np.asarray([0, 0, -1], dtype=self.dtype)
|
|
738
|
+
toTarget = targetPos - self._pos
|
|
739
|
+
invOri = invertQuat(self._ori, dtype=self.dtype)
|
|
740
|
+
invPos = applyQuat(invOri, toTarget, dtype=self.dtype)
|
|
741
|
+
invPos = normalize(invPos, dtype=self.dtype)
|
|
742
|
+
|
|
743
|
+
self.ori = multQuat(
|
|
744
|
+
self._ori, alignTo(fwd, invPos, dtype=self.dtype))
|
|
74
745
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class BoundingBox:
|
|
749
|
+
"""Class for representing object bounding boxes.
|
|
750
|
+
|
|
751
|
+
A bounding box is a construct which represents a 3D rectangular volume about
|
|
752
|
+
some pose, defined by its minimum and maximum extents in the reference frame
|
|
753
|
+
of the pose. The axes of the bounding box are aligned to the axes of the
|
|
754
|
+
world or the associated pose.
|
|
755
|
+
|
|
756
|
+
Bounding boxes are primarily used for visibility testing; to determine if
|
|
757
|
+
the extents of an object associated with a pose (eg. the vertices of a
|
|
758
|
+
model) falls completely outside of the viewing frustum. If so, the model can
|
|
759
|
+
be culled during rendering to avoid wasting CPU/GPU resources on objects not
|
|
760
|
+
visible to the viewer.
|
|
761
|
+
|
|
762
|
+
"""
|
|
763
|
+
def __init__(self, extents=None, dtype=None):
|
|
764
|
+
self._dtype = np.dtype(dtype).type if dtype is not None else DEFAULT_DTYPE
|
|
765
|
+
|
|
766
|
+
self._extents = np.zeros((2, 3), self.dtype)
|
|
767
|
+
self._posCorners = np.zeros((8, 4), self.dtype)
|
|
768
|
+
|
|
769
|
+
if extents is not None:
|
|
770
|
+
self._extents[0, :] = extents[0]
|
|
771
|
+
self._extents[1, :] = extents[1]
|
|
772
|
+
else:
|
|
773
|
+
self.clear()
|
|
774
|
+
|
|
775
|
+
self._computeCorners()
|
|
776
|
+
|
|
777
|
+
def _computeCorners(self):
|
|
778
|
+
"""Compute the corners of the bounding box.
|
|
779
|
+
|
|
780
|
+
These values are cached to speed up computations if extents hasn't been
|
|
781
|
+
updated.
|
|
782
|
+
|
|
783
|
+
"""
|
|
784
|
+
for i in range(8):
|
|
785
|
+
self._posCorners[i, 0] = \
|
|
786
|
+
self._extents[1, 0] if (i & 1) else self._extents[0, 0]
|
|
787
|
+
self._posCorners[i, 1] = \
|
|
788
|
+
self._extents[1, 1] if (i & 2) else self._extents[0, 1]
|
|
789
|
+
self._posCorners[i, 2] = \
|
|
790
|
+
self._extents[1, 2] if (i & 4) else self._extents[0, 2]
|
|
791
|
+
self._posCorners[i, 3] = 1.0
|
|
792
|
+
|
|
793
|
+
@property
|
|
794
|
+
def dtype(self):
|
|
795
|
+
"""Data type used for computations and arrays (`numpy.dtype`).
|
|
796
|
+
"""
|
|
797
|
+
# we use 32-bit float precision for all computations, this will be
|
|
798
|
+
# settable in the future
|
|
799
|
+
return self._dtype
|
|
800
|
+
|
|
801
|
+
@property
|
|
802
|
+
def isValid(self):
|
|
803
|
+
"""`True` if the bounding box is valid."""
|
|
804
|
+
return np.all(self._extents[0, :] <= self._extents[1, :])
|
|
805
|
+
|
|
806
|
+
@property
|
|
807
|
+
def extents(self):
|
|
808
|
+
return self._extents
|
|
809
|
+
|
|
810
|
+
@extents.setter
|
|
811
|
+
def extents(self, value):
|
|
812
|
+
self._extents[0, :] = value[0]
|
|
813
|
+
self._extents[1, :] = value[1]
|
|
814
|
+
self._computeCorners()
|
|
815
|
+
|
|
816
|
+
def fit(self, verts):
|
|
817
|
+
"""Fit the bounding box to vertices."""
|
|
818
|
+
np.amin(verts, axis=0, out=self._extents[0])
|
|
819
|
+
np.amax(verts, axis=0, out=self._extents[1])
|
|
820
|
+
self._computeCorners()
|
|
821
|
+
|
|
822
|
+
def clear(self):
|
|
823
|
+
"""Clear a bounding box, invalidating it."""
|
|
824
|
+
self._extents[0, :] = np.finfo(self.dtype).max
|
|
825
|
+
self._extents[1, :] = np.finfo(self.dtype).min
|
|
826
|
+
self._computeCorners()
|
|
78
827
|
|
|
79
828
|
|
|
80
829
|
# ------------------------------------------------------------------------------
|
|
@@ -106,9 +855,10 @@ def length(v, squared=False, out=None, dtype=None):
|
|
|
106
855
|
|
|
107
856
|
"""
|
|
108
857
|
if out is None:
|
|
109
|
-
dtype =
|
|
858
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
859
|
+
toReturn = np.array(v, dtype=dtype)
|
|
110
860
|
else:
|
|
111
|
-
|
|
861
|
+
toReturn = out
|
|
112
862
|
|
|
113
863
|
v = np.asarray(v, dtype=dtype)
|
|
114
864
|
|
|
@@ -178,14 +928,14 @@ def normalize(v, out=None, dtype=None):
|
|
|
178
928
|
|
|
179
929
|
"""
|
|
180
930
|
if out is None:
|
|
181
|
-
dtype =
|
|
931
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
182
932
|
toReturn = np.array(v, dtype=dtype)
|
|
183
933
|
else:
|
|
184
934
|
toReturn = out
|
|
185
935
|
|
|
186
936
|
v2d = np.atleast_2d(toReturn) # 2d view of array
|
|
187
937
|
norm = np.linalg.norm(v2d, axis=1)
|
|
188
|
-
norm[norm == 0.0] = np.
|
|
938
|
+
norm[norm == 0.0] = np.nan # make sure if length==0 division succeeds
|
|
189
939
|
v2d /= norm[:, np.newaxis]
|
|
190
940
|
np.nan_to_num(v2d, copy=False) # fix NaNs
|
|
191
941
|
|
|
@@ -224,7 +974,7 @@ def orthogonalize(v, n, out=None, dtype=None):
|
|
|
224
974
|
|
|
225
975
|
"""
|
|
226
976
|
if out is None:
|
|
227
|
-
dtype =
|
|
977
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
228
978
|
else:
|
|
229
979
|
dtype = np.dtype(out.dtype).type
|
|
230
980
|
|
|
@@ -273,7 +1023,7 @@ def reflect(v, n, out=None, dtype=None):
|
|
|
273
1023
|
"""
|
|
274
1024
|
# based off https://github.com/glfw/glfw/blob/master/deps/linmath.h
|
|
275
1025
|
if out is None:
|
|
276
|
-
dtype =
|
|
1026
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
277
1027
|
else:
|
|
278
1028
|
dtype = np.dtype(out.dtype).type
|
|
279
1029
|
|
|
@@ -326,7 +1076,7 @@ def dot(v0, v1, out=None, dtype=None):
|
|
|
326
1076
|
|
|
327
1077
|
"""
|
|
328
1078
|
if out is None:
|
|
329
|
-
dtype =
|
|
1079
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
330
1080
|
else:
|
|
331
1081
|
dtype = np.dtype(out.dtype).type
|
|
332
1082
|
|
|
@@ -413,7 +1163,7 @@ def cross(v0, v1, out=None, dtype=None):
|
|
|
413
1163
|
|
|
414
1164
|
"""
|
|
415
1165
|
if out is None:
|
|
416
|
-
dtype =
|
|
1166
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
417
1167
|
else:
|
|
418
1168
|
dtype = np.dtype(out.dtype).type
|
|
419
1169
|
|
|
@@ -492,7 +1242,7 @@ def project(v0, v1, out=None, dtype=None):
|
|
|
492
1242
|
|
|
493
1243
|
"""
|
|
494
1244
|
if out is None:
|
|
495
|
-
dtype =
|
|
1245
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
496
1246
|
else:
|
|
497
1247
|
dtype = np.dtype(out.dtype).type
|
|
498
1248
|
|
|
@@ -550,7 +1300,7 @@ def lerp(v0, v1, t, out=None, dtype=None):
|
|
|
550
1300
|
|
|
551
1301
|
"""
|
|
552
1302
|
if out is None:
|
|
553
|
-
dtype =
|
|
1303
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
554
1304
|
else:
|
|
555
1305
|
dtype = np.dtype(out.dtype).type
|
|
556
1306
|
|
|
@@ -599,7 +1349,7 @@ def distance(v0, v1, out=None, dtype=None):
|
|
|
599
1349
|
|
|
600
1350
|
"""
|
|
601
1351
|
if out is None:
|
|
602
|
-
dtype =
|
|
1352
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
603
1353
|
else:
|
|
604
1354
|
dtype = np.dtype(out.dtype).type
|
|
605
1355
|
|
|
@@ -659,7 +1409,7 @@ def perp(v, n, norm=True, out=None, dtype=None):
|
|
|
659
1409
|
|
|
660
1410
|
"""
|
|
661
1411
|
if out is None:
|
|
662
|
-
dtype =
|
|
1412
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
663
1413
|
else:
|
|
664
1414
|
dtype = np.dtype(out.dtype).type
|
|
665
1415
|
|
|
@@ -709,7 +1459,7 @@ def bisector(v0, v1, norm=False, out=None, dtype=None):
|
|
|
709
1459
|
|
|
710
1460
|
"""
|
|
711
1461
|
if out is None:
|
|
712
|
-
dtype =
|
|
1462
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
713
1463
|
else:
|
|
714
1464
|
dtype = np.dtype(out.dtype).type
|
|
715
1465
|
|
|
@@ -767,7 +1517,7 @@ def angleTo(v, point, degrees=True, out=None, dtype=None):
|
|
|
767
1517
|
|
|
768
1518
|
"""
|
|
769
1519
|
if out is None:
|
|
770
|
-
dtype =
|
|
1520
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
771
1521
|
else:
|
|
772
1522
|
dtype = np.dtype(out.dtype).type
|
|
773
1523
|
|
|
@@ -795,13 +1545,18 @@ def angleTo(v, point, degrees=True, out=None, dtype=None):
|
|
|
795
1545
|
|
|
796
1546
|
|
|
797
1547
|
def sortClockwise(verts):
|
|
798
|
-
"""
|
|
799
|
-
Sort vertices clockwise from 12 O'Clock (aka vertex (0, 1)).
|
|
1548
|
+
"""Sort vertices clockwise from 12 O'Clock (aka vertex (0, 1)).
|
|
800
1549
|
|
|
801
1550
|
Parameters
|
|
802
|
-
|
|
1551
|
+
----------
|
|
803
1552
|
verts : array
|
|
804
|
-
Array of vertices to sort
|
|
1553
|
+
Array of vertices to sort.
|
|
1554
|
+
|
|
1555
|
+
Returns
|
|
1556
|
+
-------
|
|
1557
|
+
array
|
|
1558
|
+
Vertices sorted clockwise from 12 O'Clock.
|
|
1559
|
+
|
|
805
1560
|
"""
|
|
806
1561
|
# Blank array of angles
|
|
807
1562
|
angles = []
|
|
@@ -856,12 +1611,12 @@ def surfaceNormal(tri, norm=True, out=None, dtype=None):
|
|
|
856
1611
|
|
|
857
1612
|
vertices = [[[-1., 0., 0.], [0., 1., 0.], [1, 0, 0]], # 2x3x3
|
|
858
1613
|
[[1., 0., 0.], [0., 1., 0.], [-1, 0, 0]]]
|
|
859
|
-
normals = np.zeros((2, 3)) # normals
|
|
1614
|
+
normals = np.zeros((2, 3)) # normals for two triangles
|
|
860
1615
|
surfaceNormal(vertices, out=normals)
|
|
861
1616
|
|
|
862
1617
|
"""
|
|
863
1618
|
if out is None:
|
|
864
|
-
dtype =
|
|
1619
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
865
1620
|
else:
|
|
866
1621
|
dtype = np.dtype(out.dtype).type
|
|
867
1622
|
|
|
@@ -945,7 +1700,7 @@ def surfaceBitangent(tri, uv, norm=True, out=None, dtype=None):
|
|
|
945
1700
|
|
|
946
1701
|
"""
|
|
947
1702
|
if out is None:
|
|
948
|
-
dtype =
|
|
1703
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
949
1704
|
else:
|
|
950
1705
|
dtype = np.dtype(out.dtype).type
|
|
951
1706
|
|
|
@@ -1054,7 +1809,7 @@ def surfaceTangent(tri, uv, norm=True, out=None, dtype=None):
|
|
|
1054
1809
|
|
|
1055
1810
|
"""
|
|
1056
1811
|
if out is None:
|
|
1057
|
-
dtype =
|
|
1812
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1058
1813
|
else:
|
|
1059
1814
|
dtype = np.dtype(out.dtype).type
|
|
1060
1815
|
|
|
@@ -1135,7 +1890,7 @@ def vertexNormal(faceNorms, norm=True, out=None, dtype=None):
|
|
|
1135
1890
|
|
|
1136
1891
|
"""
|
|
1137
1892
|
if out is None:
|
|
1138
|
-
dtype =
|
|
1893
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1139
1894
|
else:
|
|
1140
1895
|
dtype = np.dtype(out.dtype).type
|
|
1141
1896
|
|
|
@@ -1188,7 +1943,7 @@ def fixTangentHandedness(tangents, normals, bitangents, out=None, dtype=None):
|
|
|
1188
1943
|
|
|
1189
1944
|
"""
|
|
1190
1945
|
if out is None:
|
|
1191
|
-
dtype =
|
|
1946
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1192
1947
|
else:
|
|
1193
1948
|
dtype = np.dtype(out.dtype).type
|
|
1194
1949
|
|
|
@@ -1236,7 +1991,7 @@ def fitBBox(points, dtype=None):
|
|
|
1236
1991
|
computeBBoxCorners : Convert bounding box extents to corners.
|
|
1237
1992
|
|
|
1238
1993
|
"""
|
|
1239
|
-
dtype =
|
|
1994
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1240
1995
|
|
|
1241
1996
|
points = np.asarray(points, dtype=dtype)
|
|
1242
1997
|
extents = np.zeros((2, 3), dtype=dtype)
|
|
@@ -1344,7 +2099,7 @@ def intersectRayPlane(rayOrig, rayDir, planeOrig, planeNormal, dtype=None):
|
|
|
1344
2099
|
pnt, dist = intersectRayPlane(rayOrigin, rayDir, planeOrigin, planeNormal)
|
|
1345
2100
|
|
|
1346
2101
|
"""
|
|
1347
|
-
dtype =
|
|
2102
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1348
2103
|
|
|
1349
2104
|
# based off the method from GLM
|
|
1350
2105
|
rayOrig = np.asarray(rayOrig, dtype=dtype)
|
|
@@ -1395,7 +2150,7 @@ def intersectRaySphere(rayOrig, rayDir, sphereOrig=(0., 0., 0.), sphereRadius=1.
|
|
|
1395
2150
|
|
|
1396
2151
|
"""
|
|
1397
2152
|
# based off example from https://antongerdelan.net/opengl/raycasting.html
|
|
1398
|
-
dtype =
|
|
2153
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1399
2154
|
|
|
1400
2155
|
rayOrig = np.asarray(rayOrig, dtype=dtype)
|
|
1401
2156
|
rayDir = np.asarray(rayDir, dtype=dtype)
|
|
@@ -1469,7 +2224,7 @@ def intersectRayAABB(rayOrig, rayDir, boundsOffset, boundsExtents, dtype=None):
|
|
|
1469
2224
|
# based of the example provided here:
|
|
1470
2225
|
# https://www.scratchapixel.com/lessons/3d-basic-rendering/
|
|
1471
2226
|
# minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
|
|
1472
|
-
dtype =
|
|
2227
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1473
2228
|
|
|
1474
2229
|
rayOrig = np.asarray(rayOrig, dtype=dtype)
|
|
1475
2230
|
rayDir = np.asarray(rayDir, dtype=dtype)
|
|
@@ -1562,7 +2317,7 @@ def intersectRayOBB(rayOrig, rayDir, modelMatrix, boundsExtents, dtype=None):
|
|
|
1562
2317
|
# based off algorithm:
|
|
1563
2318
|
# https://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/
|
|
1564
2319
|
# picking-with-custom-ray-obb-function/
|
|
1565
|
-
dtype =
|
|
2320
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1566
2321
|
|
|
1567
2322
|
rayOrig = np.asarray(rayOrig, dtype=dtype)
|
|
1568
2323
|
rayDir = np.asarray(rayDir, dtype=dtype)
|
|
@@ -1637,7 +2392,7 @@ def intersectRayTriangle(rayOrig, rayDir, tri, dtype=None):
|
|
|
1637
2392
|
|
|
1638
2393
|
"""
|
|
1639
2394
|
# based off `intersectRayTriangle` from GLM (https://glm.g-truc.net)
|
|
1640
|
-
dtype =
|
|
2395
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1641
2396
|
|
|
1642
2397
|
rayOrig = np.asarray(rayOrig, dtype=dtype)
|
|
1643
2398
|
rayDir = np.asarray(rayDir, dtype=dtype)
|
|
@@ -1739,7 +2494,7 @@ def ortho3Dto2D(p, orig, normal, up, right=None, dtype=None):
|
|
|
1739
2494
|
planeX, planeY = ortho3Dto2D(pnt, planeOrigin, planeNormal, planeUpAxis)
|
|
1740
2495
|
|
|
1741
2496
|
"""
|
|
1742
|
-
dtype =
|
|
2497
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1743
2498
|
|
|
1744
2499
|
p = np.asarray(p, dtype=dtype)
|
|
1745
2500
|
orig = np.asarray(orig, dtype=dtype)
|
|
@@ -1823,7 +2578,7 @@ def articulate(boneVecs, boneOris, dtype=None):
|
|
|
1823
2578
|
wristModel.thePose.posOri = (boxPos[2, :], boxOri[2, :])
|
|
1824
2579
|
|
|
1825
2580
|
"""
|
|
1826
|
-
dtype =
|
|
2581
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1827
2582
|
|
|
1828
2583
|
boneVecs = np.asarray(boneVecs, dtype=dtype)
|
|
1829
2584
|
boneOris = np.asarray(boneOris, dtype=dtype)
|
|
@@ -1914,7 +2669,7 @@ def slerp(q0, q1, t, shortest=True, out=None, dtype=None):
|
|
|
1914
2669
|
# https://en.wikipedia.org/wiki/Slerp
|
|
1915
2670
|
#
|
|
1916
2671
|
if out is None:
|
|
1917
|
-
dtype =
|
|
2672
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1918
2673
|
else:
|
|
1919
2674
|
dtype = np.dtype(out.dtype).type
|
|
1920
2675
|
|
|
@@ -1987,7 +2742,7 @@ def quatToAxisAngle(q, degrees=True, dtype=None):
|
|
|
1987
2742
|
myStim.draw()
|
|
1988
2743
|
|
|
1989
2744
|
"""
|
|
1990
|
-
dtype =
|
|
2745
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
1991
2746
|
q = normalize(q, dtype=dtype) # returns ndarray
|
|
1992
2747
|
v = np.sqrt(np.sum(np.square(q[:3])))
|
|
1993
2748
|
|
|
@@ -2039,7 +2794,7 @@ def quatFromAxisAngle(axis, angle, degrees=True, dtype=None):
|
|
|
2039
2794
|
ori = quatFromAxisAngle(axis, angle, degrees=True) # using degrees!
|
|
2040
2795
|
|
|
2041
2796
|
"""
|
|
2042
|
-
dtype =
|
|
2797
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2043
2798
|
toReturn = np.zeros((4,), dtype=dtype)
|
|
2044
2799
|
|
|
2045
2800
|
if degrees:
|
|
@@ -2097,7 +2852,7 @@ def quatYawPitchRoll(q, degrees=True, out=None, dtype=None):
|
|
|
2097
2852
|
# based off code found here:
|
|
2098
2853
|
# https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
|
|
2099
2854
|
# Yields the same results as PsychXR's LibOVRPose.getYawPitchRoll method.
|
|
2100
|
-
dtype =
|
|
2855
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2101
2856
|
q = np.asarray(q, dtype=dtype)
|
|
2102
2857
|
|
|
2103
2858
|
toReturn = np.zeros((3,), dtype=dtype) if out is None else out
|
|
@@ -2154,7 +2909,7 @@ def quatMagnitude(q, squared=False, out=None, dtype=None):
|
|
|
2154
2909
|
|
|
2155
2910
|
"""
|
|
2156
2911
|
if out is None:
|
|
2157
|
-
dtype =
|
|
2912
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2158
2913
|
else:
|
|
2159
2914
|
dtype = np.dtype(out.dtype).type
|
|
2160
2915
|
|
|
@@ -2217,7 +2972,7 @@ def multQuat(q0, q1, out=None, dtype=None):
|
|
|
2217
2972
|
|
|
2218
2973
|
"""
|
|
2219
2974
|
if out is None:
|
|
2220
|
-
dtype =
|
|
2975
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2221
2976
|
else:
|
|
2222
2977
|
dtype = np.dtype(out.dtype).type
|
|
2223
2978
|
|
|
@@ -2285,7 +3040,7 @@ def invertQuat(q, out=None, dtype=None):
|
|
|
2285
3040
|
|
|
2286
3041
|
"""
|
|
2287
3042
|
if out is None:
|
|
2288
|
-
dtype =
|
|
3043
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2289
3044
|
else:
|
|
2290
3045
|
dtype = np.dtype(out.dtype).type
|
|
2291
3046
|
|
|
@@ -2362,7 +3117,7 @@ def applyQuat(q, points, out=None, dtype=None):
|
|
|
2362
3117
|
"""
|
|
2363
3118
|
# based on 'quat_mul_vec3' implementation from linmath.h
|
|
2364
3119
|
if out is None:
|
|
2365
|
-
dtype =
|
|
3120
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2366
3121
|
else:
|
|
2367
3122
|
dtype = np.dtype(out.dtype).type
|
|
2368
3123
|
|
|
@@ -2437,7 +3192,7 @@ def accumQuat(qlist, out=None, dtype=None):
|
|
|
2437
3192
|
|
|
2438
3193
|
"""
|
|
2439
3194
|
if out is None:
|
|
2440
|
-
dtype =
|
|
3195
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2441
3196
|
else:
|
|
2442
3197
|
dtype = np.dtype(out.dtype).type
|
|
2443
3198
|
|
|
@@ -2501,7 +3256,7 @@ def alignTo(v, t, out=None, dtype=None):
|
|
|
2501
3256
|
"""
|
|
2502
3257
|
# based off Quaternion::align from Quaternion.hpp from OpenMP
|
|
2503
3258
|
if out is None:
|
|
2504
|
-
dtype =
|
|
3259
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2505
3260
|
else:
|
|
2506
3261
|
dtype = np.dtype(out.dtype).type
|
|
2507
3262
|
|
|
@@ -2610,7 +3365,7 @@ def matrixToQuat(m, out=None, dtype=None):
|
|
|
2610
3365
|
# based off example `Maths - Conversion Matrix to Quaternion` from
|
|
2611
3366
|
# https://www.euclideanspace.com/
|
|
2612
3367
|
if out is None:
|
|
2613
|
-
dtype =
|
|
3368
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2614
3369
|
else:
|
|
2615
3370
|
dtype = np.dtype(out.dtype).type
|
|
2616
3371
|
|
|
@@ -2658,6 +3413,42 @@ def matrixToQuat(m, out=None, dtype=None):
|
|
|
2658
3413
|
# Matrix Operations
|
|
2659
3414
|
#
|
|
2660
3415
|
|
|
3416
|
+
def identityMatrix(size=4, out=None, dtype=None):
|
|
3417
|
+
"""Create an sqaure identity matrix.
|
|
3418
|
+
|
|
3419
|
+
Parameters
|
|
3420
|
+
----------
|
|
3421
|
+
size : int, optional
|
|
3422
|
+
Size of the matrix. Default is `4` for a 4x4 identity matrix.
|
|
3423
|
+
out : ndarray, optional
|
|
3424
|
+
Optional output array. Must be same `shape` and `dtype` as the expected
|
|
3425
|
+
output if `out` was not specified.
|
|
3426
|
+
dtype : dtype or str, optional
|
|
3427
|
+
Data type for computations can either be 'float32' or 'float64'. If
|
|
3428
|
+
`out` is specified, the data type of `out` is used and this argument is
|
|
3429
|
+
ignored. If `out` is not provided, 'float64' is used by default.
|
|
3430
|
+
|
|
3431
|
+
Returns
|
|
3432
|
+
-------
|
|
3433
|
+
ndarray
|
|
3434
|
+
Identity matrix.
|
|
3435
|
+
|
|
3436
|
+
"""
|
|
3437
|
+
# this might seem overkill for creating an identity matrix, but it is
|
|
3438
|
+
# necessary to ensure the correct data type is used
|
|
3439
|
+
if out is None:
|
|
3440
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3441
|
+
ident = np.zeros((size, size), dtype=dtype)
|
|
3442
|
+
else:
|
|
3443
|
+
dtype = np.dtype(out.dtype).type
|
|
3444
|
+
ident = out
|
|
3445
|
+
ident.fill(0.0)
|
|
3446
|
+
|
|
3447
|
+
np.fill_diagonal(ident, 1.0)
|
|
3448
|
+
|
|
3449
|
+
return ident
|
|
3450
|
+
|
|
3451
|
+
|
|
2661
3452
|
def quatToMatrix(q, out=None, dtype=None):
|
|
2662
3453
|
"""Create a 4x4 rotation matrix from a quaternion.
|
|
2663
3454
|
|
|
@@ -2704,7 +3495,7 @@ def quatToMatrix(q, out=None, dtype=None):
|
|
|
2704
3495
|
# based off implementations from
|
|
2705
3496
|
# https://github.com/glfw/glfw/blob/master/deps/linmath.h
|
|
2706
3497
|
if out is None:
|
|
2707
|
-
dtype =
|
|
3498
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2708
3499
|
R = np.zeros((4, 4,), dtype=dtype)
|
|
2709
3500
|
else:
|
|
2710
3501
|
dtype = np.dtype(out.dtype).type
|
|
@@ -2761,7 +3552,7 @@ def scaleMatrix(s, out=None, dtype=None):
|
|
|
2761
3552
|
"""
|
|
2762
3553
|
# from glScale
|
|
2763
3554
|
if out is None:
|
|
2764
|
-
dtype =
|
|
3555
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2765
3556
|
S = np.zeros((4, 4,), dtype=dtype)
|
|
2766
3557
|
else:
|
|
2767
3558
|
dtype = np.dtype(out.dtype).type
|
|
@@ -2814,7 +3605,7 @@ def rotationMatrix(angle, axis=(0., 0., -1.), out=None, dtype=None):
|
|
|
2814
3605
|
|
|
2815
3606
|
"""
|
|
2816
3607
|
if out is None:
|
|
2817
|
-
dtype =
|
|
3608
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2818
3609
|
R = np.zeros((4, 4,), dtype=dtype)
|
|
2819
3610
|
else:
|
|
2820
3611
|
dtype = np.dtype(out.dtype).type
|
|
@@ -2884,7 +3675,7 @@ def translationMatrix(t, out=None, dtype=None):
|
|
|
2884
3675
|
|
|
2885
3676
|
"""
|
|
2886
3677
|
if out is None:
|
|
2887
|
-
dtype =
|
|
3678
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2888
3679
|
T = np.identity(4, dtype=dtype)
|
|
2889
3680
|
else:
|
|
2890
3681
|
dtype = np.dtype(out.dtype).type
|
|
@@ -2919,7 +3710,7 @@ def invertMatrix(m, out=None, dtype=None):
|
|
|
2919
3710
|
|
|
2920
3711
|
"""
|
|
2921
3712
|
if out is None:
|
|
2922
|
-
dtype =
|
|
3713
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
2923
3714
|
else:
|
|
2924
3715
|
dtype = out.dtype
|
|
2925
3716
|
|
|
@@ -3026,7 +3817,7 @@ def multMatrix(matrices, reverse=False, out=None, dtype=None):
|
|
|
3026
3817
|
|
|
3027
3818
|
"""
|
|
3028
3819
|
# convert matrix types
|
|
3029
|
-
dtype =
|
|
3820
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3030
3821
|
matrices = np.asarray(matrices, dtype=dtype) # convert to array
|
|
3031
3822
|
|
|
3032
3823
|
matrices = np.atleast_3d(matrices)
|
|
@@ -3199,7 +3990,7 @@ def matrixFromEulerAngles(rx, ry, rz, degrees=True, out=None, dtype=None):
|
|
|
3199
3990
|
"""
|
|
3200
3991
|
# from https://www.j3d.org/matrix_faq/matrfaq_latest.html
|
|
3201
3992
|
if out is None:
|
|
3202
|
-
dtype =
|
|
3993
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3203
3994
|
toReturn = np.zeros((4, 4,), dtype=dtype)
|
|
3204
3995
|
else:
|
|
3205
3996
|
dtype = np.dtype(dtype).type
|
|
@@ -3301,7 +4092,9 @@ def applyMatrix(m, points, out=None, dtype=None):
|
|
|
3301
4092
|
Matrix with dimensions 2x2, 3x3, 3x4 or 4x4.
|
|
3302
4093
|
points : array_like
|
|
3303
4094
|
2D array of points/coordinates to transform. Each row should have length
|
|
3304
|
-
appropriate for the matrix being used.
|
|
4095
|
+
appropriate for the matrix being used. If not, a square submatrix will
|
|
4096
|
+
be taken from the input matrix with dimensions equal to the number of
|
|
4097
|
+
columns in `points`.
|
|
3305
4098
|
out : ndarray, optional
|
|
3306
4099
|
Optional output array. Must be same `shape` and `dtype` as the expected
|
|
3307
4100
|
output if `out` was not specified.
|
|
@@ -3358,7 +4151,7 @@ def applyMatrix(m, points, out=None, dtype=None):
|
|
|
3358
4151
|
|
|
3359
4152
|
"""
|
|
3360
4153
|
if out is None:
|
|
3361
|
-
dtype =
|
|
4154
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3362
4155
|
else:
|
|
3363
4156
|
dtype = np.dtype(out.dtype).type
|
|
3364
4157
|
|
|
@@ -3374,7 +4167,14 @@ def applyMatrix(m, points, out=None, dtype=None):
|
|
|
3374
4167
|
|
|
3375
4168
|
pout, p = np.atleast_2d(toReturn, points)
|
|
3376
4169
|
|
|
3377
|
-
|
|
4170
|
+
nCols = p.shape[1]
|
|
4171
|
+
if m.shape[0] > nCols:
|
|
4172
|
+
if m.shape[1] < nCols:
|
|
4173
|
+
raise ValueError(
|
|
4174
|
+
'Input matrix dimensions are not compatible with input array.')
|
|
4175
|
+
m = m[:nCols, :nCols] # take sub matrix
|
|
4176
|
+
|
|
4177
|
+
if m.shape == (4, 4): # 4x4 matrix
|
|
3378
4178
|
if pout.shape[1] == 3: # Nx3
|
|
3379
4179
|
pout[:, :] = p.dot(m[:3, :3].T)
|
|
3380
4180
|
pout += m[:3, 3]
|
|
@@ -3392,7 +4192,7 @@ def applyMatrix(m, points, out=None, dtype=None):
|
|
|
3392
4192
|
raise ValueError(
|
|
3393
4193
|
'Input array dimensions invalid. Should be Nx3 or Nx4 when '
|
|
3394
4194
|
'input matrix is 4x4.')
|
|
3395
|
-
elif m.shape
|
|
4195
|
+
elif m.shape == (3, 4): # 3x4 matrix
|
|
3396
4196
|
if pout.shape[1] == 3: # Nx3
|
|
3397
4197
|
pout[:, :] = p.dot(m[:3, :3].T)
|
|
3398
4198
|
pout += m[:3, 3]
|
|
@@ -3400,14 +4200,14 @@ def applyMatrix(m, points, out=None, dtype=None):
|
|
|
3400
4200
|
raise ValueError(
|
|
3401
4201
|
'Input array dimensions invalid. Should be Nx3 when input '
|
|
3402
4202
|
'matrix is 3x4.')
|
|
3403
|
-
elif m.shape
|
|
4203
|
+
elif m.shape == (3, 3): # 3x3 matrix, e.g colors
|
|
3404
4204
|
if pout.shape[1] == 3: # Nx3
|
|
3405
4205
|
pout[:, :] = p.dot(m.T)
|
|
3406
4206
|
else:
|
|
3407
4207
|
raise ValueError(
|
|
3408
4208
|
'Input array dimensions invalid. Should be Nx3 when '
|
|
3409
4209
|
'input matrix is 3x3.')
|
|
3410
|
-
elif m.shape
|
|
4210
|
+
elif m.shape == (2, 2): # 2x2 matrix
|
|
3411
4211
|
if pout.shape[1] == 2: # Nx2
|
|
3412
4212
|
pout[:, :] = p.dot(m.T)
|
|
3413
4213
|
else:
|
|
@@ -3449,7 +4249,7 @@ def posOriToMatrix(pos, ori, out=None, dtype=None):
|
|
|
3449
4249
|
|
|
3450
4250
|
"""
|
|
3451
4251
|
if out is None:
|
|
3452
|
-
dtype =
|
|
4252
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3453
4253
|
toReturn = np.zeros((4, 4,), dtype=dtype)
|
|
3454
4254
|
else:
|
|
3455
4255
|
dtype = np.dtype(dtype).type
|
|
@@ -3520,7 +4320,7 @@ def transform(pos, ori, points, out=None, dtype=None):
|
|
|
3520
4320
|
|
|
3521
4321
|
"""
|
|
3522
4322
|
if out is None:
|
|
3523
|
-
dtype =
|
|
4323
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3524
4324
|
else:
|
|
3525
4325
|
dtype = np.dtype(dtype).type
|
|
3526
4326
|
|
|
@@ -3600,7 +4400,7 @@ def scale(sf, points, out=None, dtype=None):
|
|
|
3600
4400
|
|
|
3601
4401
|
"""
|
|
3602
4402
|
if out is None:
|
|
3603
|
-
dtype =
|
|
4403
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3604
4404
|
else:
|
|
3605
4405
|
dtype = np.dtype(dtype).type
|
|
3606
4406
|
|
|
@@ -3645,7 +4445,7 @@ def normalMatrix(modelMatrix, out=None, dtype=None):
|
|
|
3645
4445
|
|
|
3646
4446
|
"""
|
|
3647
4447
|
if out is None:
|
|
3648
|
-
dtype =
|
|
4448
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3649
4449
|
else:
|
|
3650
4450
|
dtype = np.dtype(dtype).type
|
|
3651
4451
|
|
|
@@ -3693,7 +4493,7 @@ def forwardProject(objPos, modelView, proj, viewport=None, out=None, dtype=None)
|
|
|
3693
4493
|
|
|
3694
4494
|
"""
|
|
3695
4495
|
if out is None:
|
|
3696
|
-
dtype =
|
|
4496
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3697
4497
|
else:
|
|
3698
4498
|
dtype = np.dtype(dtype).type
|
|
3699
4499
|
|
|
@@ -3769,7 +4569,7 @@ def reverseProject(winPos, modelView, proj, viewport=None, out=None, dtype=None)
|
|
|
3769
4569
|
|
|
3770
4570
|
"""
|
|
3771
4571
|
if out is None:
|
|
3772
|
-
dtype =
|
|
4572
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3773
4573
|
else:
|
|
3774
4574
|
dtype = np.dtype(dtype).type
|
|
3775
4575
|
|
|
@@ -3793,6 +4593,76 @@ def reverseProject(winPos, modelView, proj, viewport=None, out=None, dtype=None)
|
|
|
3793
4593
|
return toReturn # ref to objCoord
|
|
3794
4594
|
|
|
3795
4595
|
|
|
4596
|
+
def lookAt(eyePos, centerPos, upVec=(0.0, 1.0, 0.0), out=None, dtype=None):
|
|
4597
|
+
"""Create a transformation matrix to orient a view towards some point.
|
|
4598
|
+
|
|
4599
|
+
Based on the same algorithm as 'gluLookAt'. This does not generate a
|
|
4600
|
+
projection matrix, but rather the matrix to transform the observer's view in
|
|
4601
|
+
the scene.
|
|
4602
|
+
|
|
4603
|
+
For more information see:
|
|
4604
|
+
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml
|
|
4605
|
+
|
|
4606
|
+
Parameters
|
|
4607
|
+
----------
|
|
4608
|
+
eyePos : list of float or ndarray
|
|
4609
|
+
Eye position in the scene.
|
|
4610
|
+
centerPos : list of float or ndarray
|
|
4611
|
+
Position of the object center in the scene.
|
|
4612
|
+
upVec : list of float or ndarray, optional
|
|
4613
|
+
Vector defining the up vector. Default is +Y is up.
|
|
4614
|
+
out : ndarray, optional
|
|
4615
|
+
Optional output array. Must be same `shape` and `dtype` as the expected
|
|
4616
|
+
output if `out` was not specified.
|
|
4617
|
+
dtype : dtype or str, optional
|
|
4618
|
+
Data type for arrays, can either be 'float32' or 'float64'. If `None` is
|
|
4619
|
+
specified, the data type is inferred by `out`. If `out` is not provided,
|
|
4620
|
+
the default is 'float64'.
|
|
4621
|
+
|
|
4622
|
+
Returns
|
|
4623
|
+
-------
|
|
4624
|
+
ndarray
|
|
4625
|
+
4x4 view matrix
|
|
4626
|
+
|
|
4627
|
+
Notes
|
|
4628
|
+
-----
|
|
4629
|
+
* This function was moved from `viewtools` in version 2025.1.0.
|
|
4630
|
+
* The returned matrix is row-major. Values are floats with 32-bits of
|
|
4631
|
+
precision stored as a contiguous (C-order) array.
|
|
4632
|
+
|
|
4633
|
+
"""
|
|
4634
|
+
if out is None:
|
|
4635
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
4636
|
+
else:
|
|
4637
|
+
dtype = np.dtype(out.dtype).type
|
|
4638
|
+
|
|
4639
|
+
toReturn = np.zeros((4, 4,), dtype=dtype) if out is None else out
|
|
4640
|
+
if out is not None:
|
|
4641
|
+
toReturn.fill(0.0)
|
|
4642
|
+
|
|
4643
|
+
eyePos = np.asarray(eyePos, dtype=dtype)
|
|
4644
|
+
centerPos = np.asarray(centerPos, dtype=dtype)
|
|
4645
|
+
upVec = np.asarray(upVec, dtype=dtype)
|
|
4646
|
+
|
|
4647
|
+
f = centerPos - eyePos
|
|
4648
|
+
f /= np.linalg.norm(f)
|
|
4649
|
+
upVec /= np.linalg.norm(upVec)
|
|
4650
|
+
|
|
4651
|
+
s = np.cross(f, upVec)
|
|
4652
|
+
u = np.cross(s / np.linalg.norm(s), f)
|
|
4653
|
+
|
|
4654
|
+
rotMat = np.zeros((4, 4), dtype=dtype)
|
|
4655
|
+
rotMat[0, :3] = s
|
|
4656
|
+
rotMat[1, :3] = u
|
|
4657
|
+
rotMat[2, :3] = -f
|
|
4658
|
+
rotMat[3, 3] = 1.0
|
|
4659
|
+
|
|
4660
|
+
transMat = np.identity(4, dtype=dtype)
|
|
4661
|
+
transMat[:3, 3] = -eyePos
|
|
4662
|
+
|
|
4663
|
+
return np.matmul(rotMat, transMat, out=toReturn)
|
|
4664
|
+
|
|
4665
|
+
|
|
3796
4666
|
# ------------------------------------------------------------------------------
|
|
3797
4667
|
# Misc. Math Functions
|
|
3798
4668
|
#
|
|
@@ -3892,7 +4762,7 @@ def lensCorrection(xys, coefK=(1.0,), distCenter=(0., 0.), out=None,
|
|
|
3892
4762
|
|
|
3893
4763
|
"""
|
|
3894
4764
|
if out is None:
|
|
3895
|
-
dtype =
|
|
4765
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3896
4766
|
else:
|
|
3897
4767
|
dtype = np.dtype(dtype).type
|
|
3898
4768
|
|
|
@@ -3961,7 +4831,7 @@ def lensCorrectionSpherical(xys, coefK=1.0, aspect=1.0, out=None, dtype=None):
|
|
|
3961
4831
|
|
|
3962
4832
|
"""
|
|
3963
4833
|
if out is None:
|
|
3964
|
-
dtype =
|
|
4834
|
+
dtype = DEFAULT_DTYPE if dtype is None else np.dtype(dtype).type
|
|
3965
4835
|
else:
|
|
3966
4836
|
dtype = np.dtype(dtype).type
|
|
3967
4837
|
|