psychopy 2024.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of psychopy might be problematic. Click here for more details.

Files changed (2950) hide show
  1. psychopy/CHANGELOG.txt +3571 -0
  2. psychopy/LICENSE.txt +11 -0
  3. psychopy/LICENSES.txt +55 -0
  4. psychopy/__init__.py +74 -0
  5. psychopy/alerts/__init__.py +65 -0
  6. psychopy/alerts/_alerts.py +184 -0
  7. psychopy/alerts/_errorHandler.py +51 -0
  8. psychopy/alerts/alertsCatalogue/1000.yaml +0 -0
  9. psychopy/alerts/alertsCatalogue/1100.yaml +0 -0
  10. psychopy/alerts/alertsCatalogue/1500.yaml +0 -0
  11. psychopy/alerts/alertsCatalogue/2000.yaml +0 -0
  12. psychopy/alerts/alertsCatalogue/2100.yaml +0 -0
  13. psychopy/alerts/alertsCatalogue/2110.yaml +0 -0
  14. psychopy/alerts/alertsCatalogue/2115.yaml +21 -0
  15. psychopy/alerts/alertsCatalogue/2120.yaml +22 -0
  16. psychopy/alerts/alertsCatalogue/2150.yaml +0 -0
  17. psychopy/alerts/alertsCatalogue/2155.yaml +21 -0
  18. psychopy/alerts/alertsCatalogue/2300.yaml +0 -0
  19. psychopy/alerts/alertsCatalogue/2500.yaml +0 -0
  20. psychopy/alerts/alertsCatalogue/3000.yaml +0 -0
  21. psychopy/alerts/alertsCatalogue/3100.yaml +0 -0
  22. psychopy/alerts/alertsCatalogue/3110.yaml +25 -0
  23. psychopy/alerts/alertsCatalogue/3115.yaml +24 -0
  24. psychopy/alerts/alertsCatalogue/3200.yaml +0 -0
  25. psychopy/alerts/alertsCatalogue/3400.yaml +0 -0
  26. psychopy/alerts/alertsCatalogue/4000.yaml +0 -0
  27. psychopy/alerts/alertsCatalogue/4051.yaml +19 -0
  28. psychopy/alerts/alertsCatalogue/4052.yaml +19 -0
  29. psychopy/alerts/alertsCatalogue/4100.yaml +0 -0
  30. psychopy/alerts/alertsCatalogue/4105.yaml +18 -0
  31. psychopy/alerts/alertsCatalogue/4115.yaml +21 -0
  32. psychopy/alerts/alertsCatalogue/4120.yaml +19 -0
  33. psychopy/alerts/alertsCatalogue/4125.yaml +23 -0
  34. psychopy/alerts/alertsCatalogue/4200.yaml +0 -0
  35. psychopy/alerts/alertsCatalogue/4205.yaml +19 -0
  36. psychopy/alerts/alertsCatalogue/4210.yaml +19 -0
  37. psychopy/alerts/alertsCatalogue/4305.yaml +21 -0
  38. psychopy/alerts/alertsCatalogue/4310.yaml +21 -0
  39. psychopy/alerts/alertsCatalogue/4315.yaml +21 -0
  40. psychopy/alerts/alertsCatalogue/4320.yaml +19 -0
  41. psychopy/alerts/alertsCatalogue/4325.yaml +23 -0
  42. psychopy/alerts/alertsCatalogue/4330.yaml +19 -0
  43. psychopy/alerts/alertsCatalogue/4335.yaml +19 -0
  44. psychopy/alerts/alertsCatalogue/4340.yaml +19 -0
  45. psychopy/alerts/alertsCatalogue/4405.yaml +24 -0
  46. psychopy/alerts/alertsCatalogue/4505.yaml +22 -0
  47. psychopy/alerts/alertsCatalogue/4510.yaml +25 -0
  48. psychopy/alerts/alertsCatalogue/4520.yaml +26 -0
  49. psychopy/alerts/alertsCatalogue/4530.yaml +23 -0
  50. psychopy/alerts/alertsCatalogue/4540.yaml +19 -0
  51. psychopy/alerts/alertsCatalogue/4545.yaml +22 -0
  52. psychopy/alerts/alertsCatalogue/4550.yaml +19 -0
  53. psychopy/alerts/alertsCatalogue/4605.yaml +22 -0
  54. psychopy/alerts/alertsCatalogue/4610.yaml +22 -0
  55. psychopy/alerts/alertsCatalogue/4615.yaml +19 -0
  56. psychopy/alerts/alertsCatalogue/4705.yaml +19 -0
  57. psychopy/alerts/alertsCatalogue/4710.yaml +19 -0
  58. psychopy/alerts/alertsCatalogue/5000.yaml +0 -0
  59. psychopy/alerts/alertsCatalogue/5055.yaml +25 -0
  60. psychopy/alerts/alertsCatalogue/6000.yaml +0 -0
  61. psychopy/alerts/alertsCatalogue/6105.yaml +18 -0
  62. psychopy/alerts/alertsCatalogue/7105.yaml +19 -0
  63. psychopy/alerts/alertsCatalogue/8105.yaml +21 -0
  64. psychopy/alerts/alertsCatalogue/8110.yaml +21 -0
  65. psychopy/alerts/alertsCatalogue/9998.yaml +19 -0
  66. psychopy/alerts/alertsCatalogue/9999.yaml +19 -0
  67. psychopy/alerts/alertsCatalogue/alertCategories.yaml +109 -0
  68. psychopy/alerts/alertsCatalogue/alertTemplate.yaml +19 -0
  69. psychopy/alerts/alertsCatalogue/alertmsg.py +144 -0
  70. psychopy/alerts/alertsCatalogue/generateAlertmsg.py +34 -0
  71. psychopy/alerts/alerttools.py +338 -0
  72. psychopy/app/Resources/Psychopy Window Favicon@16w.png +0 -0
  73. psychopy/app/Resources/Psychopy Window Favicon@32w.png +0 -0
  74. psychopy/app/Resources/README.md +12 -0
  75. psychopy/app/Resources/USB-C.png +0 -0
  76. psychopy/app/Resources/USB.png +0 -0
  77. psychopy/app/Resources/__init__.py +0 -0
  78. psychopy/app/Resources/builder.ico +0 -0
  79. psychopy/app/Resources/classic/FlowBottom_CompLeft.png +0 -0
  80. psychopy/app/Resources/classic/FlowBottom_CompRight.png +0 -0
  81. psychopy/app/Resources/classic/FlowTop_CompLeft.png +0 -0
  82. psychopy/app/Resources/classic/FlowTop_CompRight.png +0 -0
  83. psychopy/app/Resources/classic/README.txt +9 -0
  84. psychopy/app/Resources/classic/__init__.py +0 -0
  85. psychopy/app/Resources/classic/_layouts.ai +1138 -1
  86. psychopy/app/Resources/classic/add.png +0 -0
  87. psychopy/app/Resources/classic/add@2x.png +0 -0
  88. psychopy/app/Resources/classic/addExp32.png +0 -0
  89. psychopy/app/Resources/classic/alerts.png +0 -0
  90. psychopy/app/Resources/classic/beta.png +0 -0
  91. psychopy/app/Resources/classic/browser.png +0 -0
  92. psychopy/app/Resources/classic/browser@2x.png +0 -0
  93. psychopy/app/Resources/classic/bug16.png +0 -0
  94. psychopy/app/Resources/classic/circle_mask.png +0 -0
  95. psychopy/app/Resources/classic/circle_mask@2x.png +0 -0
  96. psychopy/app/Resources/classic/clear.png +0 -0
  97. psychopy/app/Resources/classic/clear@2x.png +0 -0
  98. psychopy/app/Resources/classic/coderclass16.png +0 -0
  99. psychopy/app/Resources/classic/coderfunc16.png +0 -0
  100. psychopy/app/Resources/classic/coderimport16.png +0 -0
  101. psychopy/app/Resources/classic/coderjs16.png +0 -0
  102. psychopy/app/Resources/classic/coderpython16.png +0 -0
  103. psychopy/app/Resources/classic/codervar16.png +0 -0
  104. psychopy/app/Resources/classic/cogwindow32.png +0 -0
  105. psychopy/app/Resources/classic/color32.png +0 -0
  106. psychopy/app/Resources/classic/compile32.png +0 -0
  107. psychopy/app/Resources/classic/compile_js.png +0 -0
  108. psychopy/app/Resources/classic/compile_js@2x.png +0 -0
  109. psychopy/app/Resources/classic/compile_py.png +0 -0
  110. psychopy/app/Resources/classic/compile_py@2x.png +0 -0
  111. psychopy/app/Resources/classic/copy16.png +0 -0
  112. psychopy/app/Resources/classic/currentFile.png +0 -0
  113. psychopy/app/Resources/classic/currentFile@2x.png +0 -0
  114. psychopy/app/Resources/classic/delete16.png +0 -0
  115. psychopy/app/Resources/classic/desktop.png +0 -0
  116. psychopy/app/Resources/classic/desktop@2x.png +0 -0
  117. psychopy/app/Resources/classic/dirup16.png +0 -0
  118. psychopy/app/Resources/classic/docclose16.png +0 -0
  119. psychopy/app/Resources/classic/download.png +0 -0
  120. psychopy/app/Resources/classic/edit.png +0 -0
  121. psychopy/app/Resources/classic/edit@2x.png +0 -0
  122. psychopy/app/Resources/classic/editbtn.png +0 -0
  123. psychopy/app/Resources/classic/editbtn16.png +0 -0
  124. psychopy/app/Resources/classic/editbtn16@2x.png +0 -0
  125. psychopy/app/Resources/classic/editbtn@2x.png +0 -0
  126. psychopy/app/Resources/classic/email.png +0 -0
  127. psychopy/app/Resources/classic/email@2x.png +0 -0
  128. psychopy/app/Resources/classic/experiment.png +0 -0
  129. psychopy/app/Resources/classic/experiment@2x.png +0 -0
  130. psychopy/app/Resources/classic/expsettings.png +0 -0
  131. psychopy/app/Resources/classic/expsettings@2x.png +0 -0
  132. psychopy/app/Resources/classic/file.png +0 -0
  133. psychopy/app/Resources/classic/file@2x.png +0 -0
  134. psychopy/app/Resources/classic/filecsv16.png +0 -0
  135. psychopy/app/Resources/classic/fileimage16.png +0 -0
  136. psychopy/app/Resources/classic/filenew.png +0 -0
  137. psychopy/app/Resources/classic/filenew32.png +0 -0
  138. psychopy/app/Resources/classic/filenew@2x.png +0 -0
  139. psychopy/app/Resources/classic/fileopen.png +0 -0
  140. psychopy/app/Resources/classic/fileopen32.png +0 -0
  141. psychopy/app/Resources/classic/fileopen@2x.png +0 -0
  142. psychopy/app/Resources/classic/filesave.png +0 -0
  143. psychopy/app/Resources/classic/filesave32.png +0 -0
  144. psychopy/app/Resources/classic/filesave@2x.png +0 -0
  145. psychopy/app/Resources/classic/filesaveas.png +0 -0
  146. psychopy/app/Resources/classic/filesaveas32.png +0 -0
  147. psychopy/app/Resources/classic/filesaveas@2x.png +0 -0
  148. psychopy/app/Resources/classic/fileunknown16.png +0 -0
  149. psychopy/app/Resources/classic/filter.png +0 -0
  150. psychopy/app/Resources/classic/filter@2x.png +0 -0
  151. psychopy/app/Resources/classic/folder-open16.png +0 -0
  152. psychopy/app/Resources/classic/folder16.png +0 -0
  153. psychopy/app/Resources/classic/foldernew16.png +0 -0
  154. psychopy/app/Resources/classic/fork.png +0 -0
  155. psychopy/app/Resources/classic/fork@2x.png +0 -0
  156. psychopy/app/Resources/classic/github.png +0 -0
  157. psychopy/app/Resources/classic/github@2x.png +0 -0
  158. psychopy/app/Resources/classic/globe.png +0 -0
  159. psychopy/app/Resources/classic/globe@2x.png +0 -0
  160. psychopy/app/Resources/classic/globe_bug.png +0 -0
  161. psychopy/app/Resources/classic/globe_bug@2x.png +0 -0
  162. psychopy/app/Resources/classic/globe_greensync.png +0 -0
  163. psychopy/app/Resources/classic/globe_greensync@2x.png +0 -0
  164. psychopy/app/Resources/classic/globe_info.png +0 -0
  165. psychopy/app/Resources/classic/globe_info@2x.png +0 -0
  166. psychopy/app/Resources/classic/globe_magnifier.png +0 -0
  167. psychopy/app/Resources/classic/globe_magnifier@2x.png +0 -0
  168. psychopy/app/Resources/classic/globe_run.png +0 -0
  169. psychopy/app/Resources/classic/globe_run@2x.png +0 -0
  170. psychopy/app/Resources/classic/globe_user.png +0 -0
  171. psychopy/app/Resources/classic/globe_user@2x.png +0 -0
  172. psychopy/app/Resources/classic/goto16.png +0 -0
  173. psychopy/app/Resources/classic/greendot.png +0 -0
  174. psychopy/app/Resources/classic/greendot@2x.png +0 -0
  175. psychopy/app/Resources/classic/greenglobe.png +0 -0
  176. psychopy/app/Resources/classic/greenglobe@2x.png +0 -0
  177. psychopy/app/Resources/classic/greenglobe_bug.png +0 -0
  178. psychopy/app/Resources/classic/greenglobe_bug@2x.png +0 -0
  179. psychopy/app/Resources/classic/greenglobe_greensync.png +0 -0
  180. psychopy/app/Resources/classic/greenglobe_greensync@2x.png +0 -0
  181. psychopy/app/Resources/classic/greenglobe_info.png +0 -0
  182. psychopy/app/Resources/classic/greenglobe_info@2x.png +0 -0
  183. psychopy/app/Resources/classic/greenglobe_magnifier.png +0 -0
  184. psychopy/app/Resources/classic/greenglobe_magnifier@2x.png +0 -0
  185. psychopy/app/Resources/classic/greenglobe_run.png +0 -0
  186. psychopy/app/Resources/classic/greenglobe_run@2x.png +0 -0
  187. psychopy/app/Resources/classic/greenglobe_user.png +0 -0
  188. psychopy/app/Resources/classic/greenglobe_user@2x.png +0 -0
  189. psychopy/app/Resources/classic/greydot.png +0 -0
  190. psychopy/app/Resources/classic/greydot@2x.png +0 -0
  191. psychopy/app/Resources/classic/greytick.png +0 -0
  192. psychopy/app/Resources/classic/greytick@2x.png +0 -0
  193. psychopy/app/Resources/classic/invalid_img.png +0 -0
  194. psychopy/app/Resources/classic/jsPilot.png +0 -0
  195. psychopy/app/Resources/classic/jsPilot@2x.png +0 -0
  196. psychopy/app/Resources/classic/jsRun.png +0 -0
  197. psychopy/app/Resources/classic/jsRun@2x.png +0 -0
  198. psychopy/app/Resources/classic/libroot.png +0 -0
  199. psychopy/app/Resources/classic/libroot@2x.png +0 -0
  200. psychopy/app/Resources/classic/monitor16.png +0 -0
  201. psychopy/app/Resources/classic/monitors.png +0 -0
  202. psychopy/app/Resources/classic/monitors16.png +0 -0
  203. psychopy/app/Resources/classic/monitors32.png +0 -0
  204. psychopy/app/Resources/classic/monitors@2x.png +0 -0
  205. psychopy/app/Resources/classic/orangedot.png +0 -0
  206. psychopy/app/Resources/classic/orangedot@2x.png +0 -0
  207. psychopy/app/Resources/classic/pavlovia.png +0 -0
  208. psychopy/app/Resources/classic/pavlovia16.png +0 -0
  209. psychopy/app/Resources/classic/pavlovia16@2x.png +0 -0
  210. psychopy/app/Resources/classic/pavlovia@2x.png +0 -0
  211. psychopy/app/Resources/classic/pavsync.png +0 -0
  212. psychopy/app/Resources/classic/pavsync@2x.png +0 -0
  213. psychopy/app/Resources/classic/person_off.png +0 -0
  214. psychopy/app/Resources/classic/person_off@2x.png +0 -0
  215. psychopy/app/Resources/classic/person_on.png +0 -0
  216. psychopy/app/Resources/classic/person_on@2x.png +0 -0
  217. psychopy/app/Resources/classic/plugins32.png +0 -0
  218. psychopy/app/Resources/classic/plus.png +0 -0
  219. psychopy/app/Resources/classic/plus@2x.png +0 -0
  220. psychopy/app/Resources/classic/preferences-app.png +0 -0
  221. psychopy/app/Resources/classic/preferences-app48.png +0 -0
  222. psychopy/app/Resources/classic/preferences-app@2x.png +0 -0
  223. psychopy/app/Resources/classic/preferences-conn.png +0 -0
  224. psychopy/app/Resources/classic/preferences-conn48.png +0 -0
  225. psychopy/app/Resources/classic/preferences-conn@2x.png +0 -0
  226. psychopy/app/Resources/classic/preferences-debug.png +0 -0
  227. psychopy/app/Resources/classic/preferences-debug@2x.png +0 -0
  228. psychopy/app/Resources/classic/preferences-general.png +0 -0
  229. psychopy/app/Resources/classic/preferences-general48.png +0 -0
  230. psychopy/app/Resources/classic/preferences-general@2x.png +0 -0
  231. psychopy/app/Resources/classic/preferences-hardware.png +0 -0
  232. psychopy/app/Resources/classic/preferences-hardware48.png +0 -0
  233. psychopy/app/Resources/classic/preferences-hardware@2x.png +0 -0
  234. psychopy/app/Resources/classic/preferences-keyboard.png +0 -0
  235. psychopy/app/Resources/classic/preferences-keyboard48.png +0 -0
  236. psychopy/app/Resources/classic/preferences-keyboard@2x.png +0 -0
  237. psychopy/app/Resources/classic/preferences-pilot.png +0 -0
  238. psychopy/app/Resources/classic/preferences-pilot@2x.png +0 -0
  239. psychopy/app/Resources/classic/preferences32.png +0 -0
  240. psychopy/app/Resources/classic/pyPilot.png +0 -0
  241. psychopy/app/Resources/classic/pyPilot@2x.png +0 -0
  242. psychopy/app/Resources/classic/pyRun.png +0 -0
  243. psychopy/app/Resources/classic/pyRun@2x.png +0 -0
  244. psychopy/app/Resources/classic/reddot.png +0 -0
  245. psychopy/app/Resources/classic/reddot@2x.png +0 -0
  246. psychopy/app/Resources/classic/redglobe.png +0 -0
  247. psychopy/app/Resources/classic/redglobe@2x.png +0 -0
  248. psychopy/app/Resources/classic/redglobe_bug.png +0 -0
  249. psychopy/app/Resources/classic/redglobe_bug@2x.png +0 -0
  250. psychopy/app/Resources/classic/redglobe_greensync.png +0 -0
  251. psychopy/app/Resources/classic/redglobe_greensync@2x.png +0 -0
  252. psychopy/app/Resources/classic/redglobe_info.png +0 -0
  253. psychopy/app/Resources/classic/redglobe_info@2x.png +0 -0
  254. psychopy/app/Resources/classic/redglobe_magnifier.png +0 -0
  255. psychopy/app/Resources/classic/redglobe_magnifier@2x.png +0 -0
  256. psychopy/app/Resources/classic/redglobe_run.png +0 -0
  257. psychopy/app/Resources/classic/redglobe_run@2x.png +0 -0
  258. psychopy/app/Resources/classic/redglobe_user.png +0 -0
  259. psychopy/app/Resources/classic/redglobe_user@2x.png +0 -0
  260. psychopy/app/Resources/classic/redo.png +0 -0
  261. psychopy/app/Resources/classic/redo32.png +0 -0
  262. psychopy/app/Resources/classic/redo@2x.png +0 -0
  263. psychopy/app/Resources/classic/removeExp32.png +0 -0
  264. psychopy/app/Resources/classic/rename16.png +0 -0
  265. psychopy/app/Resources/classic/restart.png +0 -0
  266. psychopy/app/Resources/classic/restart@2x.png +0 -0
  267. psychopy/app/Resources/classic/run.png +0 -0
  268. psychopy/app/Resources/classic/run@2x.png +0 -0
  269. psychopy/app/Resources/classic/runner.png +0 -0
  270. psychopy/app/Resources/classic/runner@2x.png +0 -0
  271. psychopy/app/Resources/classic/runnerPilot.png +0 -0
  272. psychopy/app/Resources/classic/runnerPilot@2x.png +0 -0
  273. psychopy/app/Resources/classic/savebtn.png +0 -0
  274. psychopy/app/Resources/classic/savebtn16.png +0 -0
  275. psychopy/app/Resources/classic/savebtn16@2x.png +0 -0
  276. psychopy/app/Resources/classic/savebtn@2x.png +0 -0
  277. psychopy/app/Resources/classic/search.png +0 -0
  278. psychopy/app/Resources/classic/search@2x.png +0 -0
  279. psychopy/app/Resources/classic/showBuilder.png +0 -0
  280. psychopy/app/Resources/classic/showBuilder@2x.png +0 -0
  281. psychopy/app/Resources/classic/showCoder.png +0 -0
  282. psychopy/app/Resources/classic/showCoder@2x.png +0 -0
  283. psychopy/app/Resources/classic/showRunner.png +0 -0
  284. psychopy/app/Resources/classic/showRunner@2x.png +0 -0
  285. psychopy/app/Resources/classic/starred.png +0 -0
  286. psychopy/app/Resources/classic/starred@2x.png +0 -0
  287. psychopy/app/Resources/classic/start.png +0 -0
  288. psychopy/app/Resources/classic/start@2x.png +0 -0
  289. psychopy/app/Resources/classic/stdout.png +0 -0
  290. psychopy/app/Resources/classic/stop.png +0 -0
  291. psychopy/app/Resources/classic/stop32.png +0 -0
  292. psychopy/app/Resources/classic/stop@2x.png +0 -0
  293. psychopy/app/Resources/classic/switchCtrlBot.png +0 -0
  294. psychopy/app/Resources/classic/switchCtrlBot@2x.png +0 -0
  295. psychopy/app/Resources/classic/switchCtrlLeft.png +0 -0
  296. psychopy/app/Resources/classic/switchCtrlLeft@2x.png +0 -0
  297. psychopy/app/Resources/classic/switchCtrlRight.png +0 -0
  298. psychopy/app/Resources/classic/switchCtrlRight@2x.png +0 -0
  299. psychopy/app/Resources/classic/switchCtrlTop.png +0 -0
  300. psychopy/app/Resources/classic/switchCtrlTop@2x.png +0 -0
  301. psychopy/app/Resources/classic/tick.png +0 -0
  302. psychopy/app/Resources/classic/tick@2x.png +0 -0
  303. psychopy/app/Resources/classic/undo.png +0 -0
  304. psychopy/app/Resources/classic/undo32.png +0 -0
  305. psychopy/app/Resources/classic/undo@2x.png +0 -0
  306. psychopy/app/Resources/classic/unstarred.png +0 -0
  307. psychopy/app/Resources/classic/unstarred@2x.png +0 -0
  308. psychopy/app/Resources/classic/user_none.png +0 -0
  309. psychopy/app/Resources/classic/view-refresh16.png +0 -0
  310. psychopy/app/Resources/classic/viewbtn.png +0 -0
  311. psychopy/app/Resources/classic/viewbtn16.png +0 -0
  312. psychopy/app/Resources/classic/viewbtn16@2x.png +0 -0
  313. psychopy/app/Resources/classic/viewbtn@2x.png +0 -0
  314. psychopy/app/Resources/classic/windows16.png +0 -0
  315. psychopy/app/Resources/classic/windows16@2x.png +0 -0
  316. psychopy/app/Resources/click.png +0 -0
  317. psychopy/app/Resources/coder.ico +0 -0
  318. psychopy/app/Resources/creditCard.png +0 -0
  319. psychopy/app/Resources/dark/FlowBottom_CompLeft.png +0 -0
  320. psychopy/app/Resources/dark/FlowBottom_CompRight.png +0 -0
  321. psychopy/app/Resources/dark/FlowTop_CompLeft.png +0 -0
  322. psychopy/app/Resources/dark/FlowTop_CompRight.png +0 -0
  323. psychopy/app/Resources/dark/README.txt +3 -0
  324. psychopy/app/Resources/dark/__init__.py +0 -0
  325. psychopy/app/Resources/dark/add.png +0 -0
  326. psychopy/app/Resources/dark/add@2x.png +0 -0
  327. psychopy/app/Resources/dark/addExp32.png +0 -0
  328. psychopy/app/Resources/dark/addExp32@2x.png +0 -0
  329. psychopy/app/Resources/dark/alerts.png +0 -0
  330. psychopy/app/Resources/dark/alerts@2x.png +0 -0
  331. psychopy/app/Resources/dark/beta.png +0 -0
  332. psychopy/app/Resources/dark/beta@2x.png +0 -0
  333. psychopy/app/Resources/dark/browser.png +0 -0
  334. psychopy/app/Resources/dark/browser@2x.png +0 -0
  335. psychopy/app/Resources/dark/bug16.png +0 -0
  336. psychopy/app/Resources/dark/bug16@2x.png +0 -0
  337. psychopy/app/Resources/dark/circle_mask.png +0 -0
  338. psychopy/app/Resources/dark/circle_mask@2x.png +0 -0
  339. psychopy/app/Resources/dark/clear.png +0 -0
  340. psychopy/app/Resources/dark/clear@2x.png +0 -0
  341. psychopy/app/Resources/dark/coderclass16.png +0 -0
  342. psychopy/app/Resources/dark/coderclass16@2x.png +0 -0
  343. psychopy/app/Resources/dark/coderfunc16.png +0 -0
  344. psychopy/app/Resources/dark/coderfunc16@2x.png +0 -0
  345. psychopy/app/Resources/dark/coderimport16.png +0 -0
  346. psychopy/app/Resources/dark/coderimport16@2x.png +0 -0
  347. psychopy/app/Resources/dark/coderjs.png +0 -0
  348. psychopy/app/Resources/dark/coderjs@2x.png +0 -0
  349. psychopy/app/Resources/dark/coderpython.png +0 -0
  350. psychopy/app/Resources/dark/coderpython@2x.png +0 -0
  351. psychopy/app/Resources/dark/codervar16.png +0 -0
  352. psychopy/app/Resources/dark/codervar16@2x.png +0 -0
  353. psychopy/app/Resources/dark/cogwindow32.png +0 -0
  354. psychopy/app/Resources/dark/cogwindow32@2x.png +0 -0
  355. psychopy/app/Resources/dark/color32.png +0 -0
  356. psychopy/app/Resources/dark/color32@2x.png +0 -0
  357. psychopy/app/Resources/dark/compile_js.png +0 -0
  358. psychopy/app/Resources/dark/compile_js@2x.png +0 -0
  359. psychopy/app/Resources/dark/compile_py.png +0 -0
  360. psychopy/app/Resources/dark/compile_py@2x.png +0 -0
  361. psychopy/app/Resources/dark/copy16.png +0 -0
  362. psychopy/app/Resources/dark/copy16@2x.png +0 -0
  363. psychopy/app/Resources/dark/currentFile16.png +0 -0
  364. psychopy/app/Resources/dark/currentFile16@2x.png +0 -0
  365. psychopy/app/Resources/dark/delete16.png +0 -0
  366. psychopy/app/Resources/dark/delete16@2x.png +0 -0
  367. psychopy/app/Resources/dark/desktop.png +0 -0
  368. psychopy/app/Resources/dark/desktop@2x.png +0 -0
  369. psychopy/app/Resources/dark/dirup16.png +0 -0
  370. psychopy/app/Resources/dark/dirup16@2x.png +0 -0
  371. psychopy/app/Resources/dark/docclose16.png +0 -0
  372. psychopy/app/Resources/dark/docclose16@2x.png +0 -0
  373. psychopy/app/Resources/dark/download.png +0 -0
  374. psychopy/app/Resources/dark/download@2x.png +0 -0
  375. psychopy/app/Resources/dark/edit.png +0 -0
  376. psychopy/app/Resources/dark/edit@2x.png +0 -0
  377. psychopy/app/Resources/dark/editbtn16.png +0 -0
  378. psychopy/app/Resources/dark/editbtn16@2x.png +0 -0
  379. psychopy/app/Resources/dark/email.png +0 -0
  380. psychopy/app/Resources/dark/email@2x.png +0 -0
  381. psychopy/app/Resources/dark/experiment.png +0 -0
  382. psychopy/app/Resources/dark/experiment@2x.png +0 -0
  383. psychopy/app/Resources/dark/expsettings.png +0 -0
  384. psychopy/app/Resources/dark/expsettings@2x.png +0 -0
  385. psychopy/app/Resources/dark/file.png +0 -0
  386. psychopy/app/Resources/dark/file@16w.png +0 -0
  387. psychopy/app/Resources/dark/file@16w@2x.png +0 -0
  388. psychopy/app/Resources/dark/file@2x.png +0 -0
  389. psychopy/app/Resources/dark/filecsv16.png +0 -0
  390. psychopy/app/Resources/dark/filecsv16@2x.png +0 -0
  391. psychopy/app/Resources/dark/fileimage16.png +0 -0
  392. psychopy/app/Resources/dark/fileimage16@2x.png +0 -0
  393. psychopy/app/Resources/dark/filenew.png +0 -0
  394. psychopy/app/Resources/dark/filenew32.png +0 -0
  395. psychopy/app/Resources/dark/filenew32@2x.png +0 -0
  396. psychopy/app/Resources/dark/filenew@2x.png +0 -0
  397. psychopy/app/Resources/dark/fileopen.png +0 -0
  398. psychopy/app/Resources/dark/fileopen32.png +0 -0
  399. psychopy/app/Resources/dark/fileopen32@2x.png +0 -0
  400. psychopy/app/Resources/dark/fileopen@2x.png +0 -0
  401. psychopy/app/Resources/dark/filesave.png +0 -0
  402. psychopy/app/Resources/dark/filesave32.png +0 -0
  403. psychopy/app/Resources/dark/filesave32@2x.png +0 -0
  404. psychopy/app/Resources/dark/filesave@2x.png +0 -0
  405. psychopy/app/Resources/dark/filesaveas.png +0 -0
  406. psychopy/app/Resources/dark/filesaveas32.png +0 -0
  407. psychopy/app/Resources/dark/filesaveas32@2x.png +0 -0
  408. psychopy/app/Resources/dark/filesaveas@2x.png +0 -0
  409. psychopy/app/Resources/dark/fileunknown16.png +0 -0
  410. psychopy/app/Resources/dark/fileunknown16@2x.png +0 -0
  411. psychopy/app/Resources/dark/filter.png +0 -0
  412. psychopy/app/Resources/dark/filter@2x.png +0 -0
  413. psychopy/app/Resources/dark/folder-open16.png +0 -0
  414. psychopy/app/Resources/dark/folder-open16@2x.png +0 -0
  415. psychopy/app/Resources/dark/folder16.png +0 -0
  416. psychopy/app/Resources/dark/folder16@2x.png +0 -0
  417. psychopy/app/Resources/dark/foldernew16.png +0 -0
  418. psychopy/app/Resources/dark/foldernew16@2x.png +0 -0
  419. psychopy/app/Resources/dark/fork.png +0 -0
  420. psychopy/app/Resources/dark/fork@2x.png +0 -0
  421. psychopy/app/Resources/dark/github.png +0 -0
  422. psychopy/app/Resources/dark/github@2x.png +0 -0
  423. psychopy/app/Resources/dark/globe.png +0 -0
  424. psychopy/app/Resources/dark/globe@2x.png +0 -0
  425. psychopy/app/Resources/dark/globe_bug.png +0 -0
  426. psychopy/app/Resources/dark/globe_bug@2x.png +0 -0
  427. psychopy/app/Resources/dark/globe_greensync.png +0 -0
  428. psychopy/app/Resources/dark/globe_greensync@2x.png +0 -0
  429. psychopy/app/Resources/dark/globe_info.png +0 -0
  430. psychopy/app/Resources/dark/globe_info@2x.png +0 -0
  431. psychopy/app/Resources/dark/globe_magnifier.png +0 -0
  432. psychopy/app/Resources/dark/globe_magnifier@2x.png +0 -0
  433. psychopy/app/Resources/dark/globe_run.png +0 -0
  434. psychopy/app/Resources/dark/globe_run@2x.png +0 -0
  435. psychopy/app/Resources/dark/globe_user.png +0 -0
  436. psychopy/app/Resources/dark/globe_user@2x.png +0 -0
  437. psychopy/app/Resources/dark/goto.png +0 -0
  438. psychopy/app/Resources/dark/goto@2x.png +0 -0
  439. psychopy/app/Resources/dark/greendot.png +0 -0
  440. psychopy/app/Resources/dark/greendot@2x.png +0 -0
  441. psychopy/app/Resources/dark/greenglobe.png +0 -0
  442. psychopy/app/Resources/dark/greenglobe@2x.png +0 -0
  443. psychopy/app/Resources/dark/greenglobe_bug.png +0 -0
  444. psychopy/app/Resources/dark/greenglobe_bug@2x.png +0 -0
  445. psychopy/app/Resources/dark/greenglobe_greensync.png +0 -0
  446. psychopy/app/Resources/dark/greenglobe_greensync@2x.png +0 -0
  447. psychopy/app/Resources/dark/greenglobe_info.png +0 -0
  448. psychopy/app/Resources/dark/greenglobe_info@2x.png +0 -0
  449. psychopy/app/Resources/dark/greenglobe_magnifier.png +0 -0
  450. psychopy/app/Resources/dark/greenglobe_magnifier@2x.png +0 -0
  451. psychopy/app/Resources/dark/greenglobe_run.png +0 -0
  452. psychopy/app/Resources/dark/greenglobe_run@2x.png +0 -0
  453. psychopy/app/Resources/dark/greenglobe_user.png +0 -0
  454. psychopy/app/Resources/dark/greenglobe_user@2x.png +0 -0
  455. psychopy/app/Resources/dark/greydot.png +0 -0
  456. psychopy/app/Resources/dark/greydot@2x.png +0 -0
  457. psychopy/app/Resources/dark/greytick.png +0 -0
  458. psychopy/app/Resources/dark/greytick@2x.png +0 -0
  459. psychopy/app/Resources/dark/invalid_img.png +0 -0
  460. psychopy/app/Resources/dark/jsPilot.png +0 -0
  461. psychopy/app/Resources/dark/jsPilot@2x.png +0 -0
  462. psychopy/app/Resources/dark/jsRun.png +0 -0
  463. psychopy/app/Resources/dark/jsRun@2x.png +0 -0
  464. psychopy/app/Resources/dark/libroot16.png +0 -0
  465. psychopy/app/Resources/dark/libroot16@2x.png +0 -0
  466. psychopy/app/Resources/dark/monitor16.png +0 -0
  467. psychopy/app/Resources/dark/monitor16@2x.png +0 -0
  468. psychopy/app/Resources/dark/monitors.png +0 -0
  469. psychopy/app/Resources/dark/monitors32.png +0 -0
  470. psychopy/app/Resources/dark/monitors32@2x.png +0 -0
  471. psychopy/app/Resources/dark/monitors@2x.png +0 -0
  472. psychopy/app/Resources/dark/orangedot.png +0 -0
  473. psychopy/app/Resources/dark/orangedot@2x.png +0 -0
  474. psychopy/app/Resources/dark/pavlovia.png +0 -0
  475. psychopy/app/Resources/dark/pavlovia16.png +0 -0
  476. psychopy/app/Resources/dark/pavlovia16@2x.png +0 -0
  477. psychopy/app/Resources/dark/pavlovia@2x.png +0 -0
  478. psychopy/app/Resources/dark/pavsync.png +0 -0
  479. psychopy/app/Resources/dark/pavsync@2x.png +0 -0
  480. psychopy/app/Resources/dark/person_off.png +0 -0
  481. psychopy/app/Resources/dark/person_off@2x.png +0 -0
  482. psychopy/app/Resources/dark/person_on.png +0 -0
  483. psychopy/app/Resources/dark/person_on@2x.png +0 -0
  484. psychopy/app/Resources/dark/plugins32.png +0 -0
  485. psychopy/app/Resources/dark/plugins32@2x.png +0 -0
  486. psychopy/app/Resources/dark/plus.png +0 -0
  487. psychopy/app/Resources/dark/plus@2x.png +0 -0
  488. psychopy/app/Resources/dark/preferences-app.png +0 -0
  489. psychopy/app/Resources/dark/preferences-app48.png +0 -0
  490. psychopy/app/Resources/dark/preferences-app48@2x.png +0 -0
  491. psychopy/app/Resources/dark/preferences-app@2x.png +0 -0
  492. psychopy/app/Resources/dark/preferences-conn.png +0 -0
  493. psychopy/app/Resources/dark/preferences-conn48.png +0 -0
  494. psychopy/app/Resources/dark/preferences-conn48@2x.png +0 -0
  495. psychopy/app/Resources/dark/preferences-conn@2x.png +0 -0
  496. psychopy/app/Resources/dark/preferences-debug.png +0 -0
  497. psychopy/app/Resources/dark/preferences-debug@2x.png +0 -0
  498. psychopy/app/Resources/dark/preferences-general.png +0 -0
  499. psychopy/app/Resources/dark/preferences-general48.png +0 -0
  500. psychopy/app/Resources/dark/preferences-general48@2x.png +0 -0
  501. psychopy/app/Resources/dark/preferences-general@2x.png +0 -0
  502. psychopy/app/Resources/dark/preferences-hardware.png +0 -0
  503. psychopy/app/Resources/dark/preferences-hardware48.png +0 -0
  504. psychopy/app/Resources/dark/preferences-hardware48@2x.png +0 -0
  505. psychopy/app/Resources/dark/preferences-hardware@2x.png +0 -0
  506. psychopy/app/Resources/dark/preferences-keyboard.png +0 -0
  507. psychopy/app/Resources/dark/preferences-keyboard48.png +0 -0
  508. psychopy/app/Resources/dark/preferences-keyboard48@2x.png +0 -0
  509. psychopy/app/Resources/dark/preferences-keyboard@2x.png +0 -0
  510. psychopy/app/Resources/dark/preferences-pilot.png +0 -0
  511. psychopy/app/Resources/dark/preferences-pilot@2x.png +0 -0
  512. psychopy/app/Resources/dark/preferences32.png +0 -0
  513. psychopy/app/Resources/dark/preferences32@2x.png +0 -0
  514. psychopy/app/Resources/dark/pyPilot.png +0 -0
  515. psychopy/app/Resources/dark/pyPilot@2x.png +0 -0
  516. psychopy/app/Resources/dark/pyRun.png +0 -0
  517. psychopy/app/Resources/dark/pyRun@2x.png +0 -0
  518. psychopy/app/Resources/dark/reddot.png +0 -0
  519. psychopy/app/Resources/dark/reddot@2x.png +0 -0
  520. psychopy/app/Resources/dark/redglobe.png +0 -0
  521. psychopy/app/Resources/dark/redglobe@2x.png +0 -0
  522. psychopy/app/Resources/dark/redglobe_bug.png +0 -0
  523. psychopy/app/Resources/dark/redglobe_bug@2x.png +0 -0
  524. psychopy/app/Resources/dark/redglobe_greensync.png +0 -0
  525. psychopy/app/Resources/dark/redglobe_greensync@2x.png +0 -0
  526. psychopy/app/Resources/dark/redglobe_info.png +0 -0
  527. psychopy/app/Resources/dark/redglobe_info@2x.png +0 -0
  528. psychopy/app/Resources/dark/redglobe_magnifier.png +0 -0
  529. psychopy/app/Resources/dark/redglobe_magnifier@2x.png +0 -0
  530. psychopy/app/Resources/dark/redglobe_run.png +0 -0
  531. psychopy/app/Resources/dark/redglobe_run@2x.png +0 -0
  532. psychopy/app/Resources/dark/redglobe_user.png +0 -0
  533. psychopy/app/Resources/dark/redglobe_user@2x.png +0 -0
  534. psychopy/app/Resources/dark/redo.png +0 -0
  535. psychopy/app/Resources/dark/redo32.png +0 -0
  536. psychopy/app/Resources/dark/redo32@2x.png +0 -0
  537. psychopy/app/Resources/dark/redo@2x.png +0 -0
  538. psychopy/app/Resources/dark/removeExp32.png +0 -0
  539. psychopy/app/Resources/dark/removeExp32@2x.png +0 -0
  540. psychopy/app/Resources/dark/rename16.png +0 -0
  541. psychopy/app/Resources/dark/rename16@2x.png +0 -0
  542. psychopy/app/Resources/dark/restart.png +0 -0
  543. psychopy/app/Resources/dark/restart@2x.png +0 -0
  544. psychopy/app/Resources/dark/runner.png +0 -0
  545. psychopy/app/Resources/dark/runner@2x.png +0 -0
  546. psychopy/app/Resources/dark/runnerPilot.png +0 -0
  547. psychopy/app/Resources/dark/runnerPilot@2x.png +0 -0
  548. psychopy/app/Resources/dark/savebtn16.png +0 -0
  549. psychopy/app/Resources/dark/savebtn16@2x.png +0 -0
  550. psychopy/app/Resources/dark/search.png +0 -0
  551. psychopy/app/Resources/dark/search@2x.png +0 -0
  552. psychopy/app/Resources/dark/showBuilder.png +0 -0
  553. psychopy/app/Resources/dark/showBuilder@2x.png +0 -0
  554. psychopy/app/Resources/dark/showCoder.png +0 -0
  555. psychopy/app/Resources/dark/showCoder@2x.png +0 -0
  556. psychopy/app/Resources/dark/showRunner.png +0 -0
  557. psychopy/app/Resources/dark/showRunner@2x.png +0 -0
  558. psychopy/app/Resources/dark/starred.png +0 -0
  559. psychopy/app/Resources/dark/starred@2x.png +0 -0
  560. psychopy/app/Resources/dark/start.png +0 -0
  561. psychopy/app/Resources/dark/start@2x.png +0 -0
  562. psychopy/app/Resources/dark/stdout.png +0 -0
  563. psychopy/app/Resources/dark/stdout@2x.png +0 -0
  564. psychopy/app/Resources/dark/stop.png +0 -0
  565. psychopy/app/Resources/dark/stop32.png +0 -0
  566. psychopy/app/Resources/dark/stop32@2x.png +0 -0
  567. psychopy/app/Resources/dark/stop@2x.png +0 -0
  568. psychopy/app/Resources/dark/switchCtrlBot.png +0 -0
  569. psychopy/app/Resources/dark/switchCtrlBot@2x.png +0 -0
  570. psychopy/app/Resources/dark/switchCtrlLeft.png +0 -0
  571. psychopy/app/Resources/dark/switchCtrlLeft@2x.png +0 -0
  572. psychopy/app/Resources/dark/switchCtrlRight.png +0 -0
  573. psychopy/app/Resources/dark/switchCtrlRight@2x.png +0 -0
  574. psychopy/app/Resources/dark/switchCtrlTop.png +0 -0
  575. psychopy/app/Resources/dark/switchCtrlTop@2x.png +0 -0
  576. psychopy/app/Resources/dark/tick.png +0 -0
  577. psychopy/app/Resources/dark/tick@2x.png +0 -0
  578. psychopy/app/Resources/dark/undo.png +0 -0
  579. psychopy/app/Resources/dark/undo32.png +0 -0
  580. psychopy/app/Resources/dark/undo32@2x.png +0 -0
  581. psychopy/app/Resources/dark/undo@2x.png +0 -0
  582. psychopy/app/Resources/dark/unstarred.png +0 -0
  583. psychopy/app/Resources/dark/unstarred@2x.png +0 -0
  584. psychopy/app/Resources/dark/user_none.png +0 -0
  585. psychopy/app/Resources/dark/view-refresh16.png +0 -0
  586. psychopy/app/Resources/dark/view-refresh16@2x.png +0 -0
  587. psychopy/app/Resources/dark/viewbtn16.png +0 -0
  588. psychopy/app/Resources/dark/viewbtn16@2x.png +0 -0
  589. psychopy/app/Resources/dark/windows16.png +0 -0
  590. psychopy/app/Resources/dark/windows16@2x.png +0 -0
  591. psychopy/app/Resources/default.mp3 +0 -0
  592. psychopy/app/Resources/default.mp4 +0 -0
  593. psychopy/app/Resources/default.png +0 -0
  594. psychopy/app/Resources/fonts/Arvo-Bold.ttf +0 -0
  595. psychopy/app/Resources/fonts/Arvo-BoldItalic.ttf +0 -0
  596. psychopy/app/Resources/fonts/Arvo-Italic.ttf +0 -0
  597. psychopy/app/Resources/fonts/Arvo-Regular.ttf +0 -0
  598. psychopy/app/Resources/fonts/DejaVuSerif.ttf +0 -0
  599. psychopy/app/Resources/fonts/IndieFlower-Regular.ttf +0 -0
  600. psychopy/app/Resources/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
  601. psychopy/app/Resources/fonts/JetBrainsMono-VariableFont_wght.ttf +0 -0
  602. psychopy/app/Resources/fonts/OpenSans-Bold.ttf +0 -0
  603. psychopy/app/Resources/fonts/OpenSans-BoldItalic.ttf +0 -0
  604. psychopy/app/Resources/fonts/OpenSans-ExtraBold.ttf +0 -0
  605. psychopy/app/Resources/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
  606. psychopy/app/Resources/fonts/OpenSans-Italic.ttf +0 -0
  607. psychopy/app/Resources/fonts/OpenSans-Light.ttf +0 -0
  608. psychopy/app/Resources/fonts/OpenSans-LightItalic.ttf +0 -0
  609. psychopy/app/Resources/fonts/OpenSans-Regular.ttf +0 -0
  610. psychopy/app/Resources/fonts/OpenSans-SemiBold.ttf +0 -0
  611. psychopy/app/Resources/fonts/OpenSans-SemiBoldItalic.ttf +0 -0
  612. psychopy/app/Resources/instruct1.png +0 -0
  613. psychopy/app/Resources/instruct2.png +0 -0
  614. psychopy/app/Resources/light/FlowBottom_CompLeft.png +0 -0
  615. psychopy/app/Resources/light/FlowBottom_CompRight.png +0 -0
  616. psychopy/app/Resources/light/FlowTop_CompLeft.png +0 -0
  617. psychopy/app/Resources/light/FlowTop_CompRight.png +0 -0
  618. psychopy/app/Resources/light/README.txt +3 -0
  619. psychopy/app/Resources/light/__init__.py +0 -0
  620. psychopy/app/Resources/light/add.png +0 -0
  621. psychopy/app/Resources/light/add@2x.png +0 -0
  622. psychopy/app/Resources/light/addExp32.png +0 -0
  623. psychopy/app/Resources/light/addExp32@2x.png +0 -0
  624. psychopy/app/Resources/light/alerts.png +0 -0
  625. psychopy/app/Resources/light/alerts@2x.png +0 -0
  626. psychopy/app/Resources/light/beta.png +0 -0
  627. psychopy/app/Resources/light/beta@2x.png +0 -0
  628. psychopy/app/Resources/light/browser.png +0 -0
  629. psychopy/app/Resources/light/browser@2x.png +0 -0
  630. psychopy/app/Resources/light/bug16.png +0 -0
  631. psychopy/app/Resources/light/bug16@2x.png +0 -0
  632. psychopy/app/Resources/light/circle_mask.png +0 -0
  633. psychopy/app/Resources/light/circle_mask@2x.png +0 -0
  634. psychopy/app/Resources/light/clear.png +0 -0
  635. psychopy/app/Resources/light/clear@2x.png +0 -0
  636. psychopy/app/Resources/light/coderclass16.png +0 -0
  637. psychopy/app/Resources/light/coderclass16@2x.png +0 -0
  638. psychopy/app/Resources/light/coderfunc16.png +0 -0
  639. psychopy/app/Resources/light/coderfunc16@2x.png +0 -0
  640. psychopy/app/Resources/light/coderimport16.png +0 -0
  641. psychopy/app/Resources/light/coderimport16@2x.png +0 -0
  642. psychopy/app/Resources/light/coderjs.png +0 -0
  643. psychopy/app/Resources/light/coderjs@2x.png +0 -0
  644. psychopy/app/Resources/light/coderpython.png +0 -0
  645. psychopy/app/Resources/light/coderpython@2x.png +0 -0
  646. psychopy/app/Resources/light/codervar16.png +0 -0
  647. psychopy/app/Resources/light/codervar16@2x.png +0 -0
  648. psychopy/app/Resources/light/cogwindow32.png +0 -0
  649. psychopy/app/Resources/light/cogwindow32@2x.png +0 -0
  650. psychopy/app/Resources/light/color16.png +0 -0
  651. psychopy/app/Resources/light/color16@2x.png +0 -0
  652. psychopy/app/Resources/light/color32.png +0 -0
  653. psychopy/app/Resources/light/color32@2x.png +0 -0
  654. psychopy/app/Resources/light/compile_js.png +0 -0
  655. psychopy/app/Resources/light/compile_js@2x.png +0 -0
  656. psychopy/app/Resources/light/compile_py.png +0 -0
  657. psychopy/app/Resources/light/compile_py@2x.png +0 -0
  658. psychopy/app/Resources/light/copy16.png +0 -0
  659. psychopy/app/Resources/light/copy16@2x.png +0 -0
  660. psychopy/app/Resources/light/currentFile16.png +0 -0
  661. psychopy/app/Resources/light/currentFile16@2x.png +0 -0
  662. psychopy/app/Resources/light/delete16.png +0 -0
  663. psychopy/app/Resources/light/delete16@2x.png +0 -0
  664. psychopy/app/Resources/light/delete8.png +0 -0
  665. psychopy/app/Resources/light/desktop.png +0 -0
  666. psychopy/app/Resources/light/desktop@2x.png +0 -0
  667. psychopy/app/Resources/light/dirup16.png +0 -0
  668. psychopy/app/Resources/light/dirup16@2x.png +0 -0
  669. psychopy/app/Resources/light/docclose16.png +0 -0
  670. psychopy/app/Resources/light/docclose16@2x.png +0 -0
  671. psychopy/app/Resources/light/download.png +0 -0
  672. psychopy/app/Resources/light/download@2x.png +0 -0
  673. psychopy/app/Resources/light/edit.png +0 -0
  674. psychopy/app/Resources/light/edit@2x.png +0 -0
  675. psychopy/app/Resources/light/editbtn16.png +0 -0
  676. psychopy/app/Resources/light/editbtn16@2x.png +0 -0
  677. psychopy/app/Resources/light/email.png +0 -0
  678. psychopy/app/Resources/light/email@2x.png +0 -0
  679. psychopy/app/Resources/light/experiment.png +0 -0
  680. psychopy/app/Resources/light/experiment@2x.png +0 -0
  681. psychopy/app/Resources/light/expsettings.png +0 -0
  682. psychopy/app/Resources/light/expsettings@2x.png +0 -0
  683. psychopy/app/Resources/light/file.png +0 -0
  684. psychopy/app/Resources/light/file@2x.png +0 -0
  685. psychopy/app/Resources/light/filecsv16.png +0 -0
  686. psychopy/app/Resources/light/filecsv16@2x.png +0 -0
  687. psychopy/app/Resources/light/fileimage16.png +0 -0
  688. psychopy/app/Resources/light/fileimage16@2x.png +0 -0
  689. psychopy/app/Resources/light/filenew.png +0 -0
  690. psychopy/app/Resources/light/filenew32.png +0 -0
  691. psychopy/app/Resources/light/filenew32@2x.png +0 -0
  692. psychopy/app/Resources/light/filenew@2x.png +0 -0
  693. psychopy/app/Resources/light/fileopen.png +0 -0
  694. psychopy/app/Resources/light/fileopen32.png +0 -0
  695. psychopy/app/Resources/light/fileopen32@2x.png +0 -0
  696. psychopy/app/Resources/light/fileopen@2x.png +0 -0
  697. psychopy/app/Resources/light/filesave.png +0 -0
  698. psychopy/app/Resources/light/filesave32.png +0 -0
  699. psychopy/app/Resources/light/filesave32@2x.png +0 -0
  700. psychopy/app/Resources/light/filesave@2x.png +0 -0
  701. psychopy/app/Resources/light/filesaveas.png +0 -0
  702. psychopy/app/Resources/light/filesaveas32.png +0 -0
  703. psychopy/app/Resources/light/filesaveas32@2x.png +0 -0
  704. psychopy/app/Resources/light/filesaveas@2x.png +0 -0
  705. psychopy/app/Resources/light/fileunknown16.png +0 -0
  706. psychopy/app/Resources/light/fileunknown16@2x.png +0 -0
  707. psychopy/app/Resources/light/filter.png +0 -0
  708. psychopy/app/Resources/light/filter@2x.png +0 -0
  709. psychopy/app/Resources/light/folder-open16.png +0 -0
  710. psychopy/app/Resources/light/folder-open16@2x.png +0 -0
  711. psychopy/app/Resources/light/folder16.png +0 -0
  712. psychopy/app/Resources/light/folder16@2x.png +0 -0
  713. psychopy/app/Resources/light/foldernew16.png +0 -0
  714. psychopy/app/Resources/light/foldernew16@2x.png +0 -0
  715. psychopy/app/Resources/light/fork.png +0 -0
  716. psychopy/app/Resources/light/fork@2x.png +0 -0
  717. psychopy/app/Resources/light/github.png +0 -0
  718. psychopy/app/Resources/light/github@2x.png +0 -0
  719. psychopy/app/Resources/light/globe.png +0 -0
  720. psychopy/app/Resources/light/globe@2x.png +0 -0
  721. psychopy/app/Resources/light/globe_bug.png +0 -0
  722. psychopy/app/Resources/light/globe_bug@2x.png +0 -0
  723. psychopy/app/Resources/light/globe_greensync.png +0 -0
  724. psychopy/app/Resources/light/globe_greensync@2x.png +0 -0
  725. psychopy/app/Resources/light/globe_info.png +0 -0
  726. psychopy/app/Resources/light/globe_info@2x.png +0 -0
  727. psychopy/app/Resources/light/globe_magnifier.png +0 -0
  728. psychopy/app/Resources/light/globe_magnifier@2x.png +0 -0
  729. psychopy/app/Resources/light/globe_run.png +0 -0
  730. psychopy/app/Resources/light/globe_run@2x.png +0 -0
  731. psychopy/app/Resources/light/globe_user.png +0 -0
  732. psychopy/app/Resources/light/globe_user@2x.png +0 -0
  733. psychopy/app/Resources/light/goto16.png +0 -0
  734. psychopy/app/Resources/light/goto16@2x.png +0 -0
  735. psychopy/app/Resources/light/greendot.png +0 -0
  736. psychopy/app/Resources/light/greendot@2x.png +0 -0
  737. psychopy/app/Resources/light/greenglobe.png +0 -0
  738. psychopy/app/Resources/light/greenglobe@2x.png +0 -0
  739. psychopy/app/Resources/light/greenglobe_bug.png +0 -0
  740. psychopy/app/Resources/light/greenglobe_bug@2x.png +0 -0
  741. psychopy/app/Resources/light/greenglobe_greensync.png +0 -0
  742. psychopy/app/Resources/light/greenglobe_greensync@2x.png +0 -0
  743. psychopy/app/Resources/light/greenglobe_info.png +0 -0
  744. psychopy/app/Resources/light/greenglobe_info@2x.png +0 -0
  745. psychopy/app/Resources/light/greenglobe_magnifier.png +0 -0
  746. psychopy/app/Resources/light/greenglobe_magnifier@2x.png +0 -0
  747. psychopy/app/Resources/light/greenglobe_run.png +0 -0
  748. psychopy/app/Resources/light/greenglobe_run@2x.png +0 -0
  749. psychopy/app/Resources/light/greenglobe_user.png +0 -0
  750. psychopy/app/Resources/light/greenglobe_user@2x.png +0 -0
  751. psychopy/app/Resources/light/greydot.png +0 -0
  752. psychopy/app/Resources/light/greydot@2x.png +0 -0
  753. psychopy/app/Resources/light/greytick.png +0 -0
  754. psychopy/app/Resources/light/greytick@2x.png +0 -0
  755. psychopy/app/Resources/light/invalid_img.png +0 -0
  756. psychopy/app/Resources/light/jsPilot.png +0 -0
  757. psychopy/app/Resources/light/jsPilot@2x.png +0 -0
  758. psychopy/app/Resources/light/jsRun.png +0 -0
  759. psychopy/app/Resources/light/jsRun@2x.png +0 -0
  760. psychopy/app/Resources/light/libroot16.png +0 -0
  761. psychopy/app/Resources/light/libroot16@2x.png +0 -0
  762. psychopy/app/Resources/light/monitor16.png +0 -0
  763. psychopy/app/Resources/light/monitor16@2x.png +0 -0
  764. psychopy/app/Resources/light/monitors.png +0 -0
  765. psychopy/app/Resources/light/monitors32.png +0 -0
  766. psychopy/app/Resources/light/monitors32@2x.png +0 -0
  767. psychopy/app/Resources/light/monitors@2x.png +0 -0
  768. psychopy/app/Resources/light/orangedot.png +0 -0
  769. psychopy/app/Resources/light/orangedot@2x.png +0 -0
  770. psychopy/app/Resources/light/pavlovia.png +0 -0
  771. psychopy/app/Resources/light/pavlovia16.png +0 -0
  772. psychopy/app/Resources/light/pavlovia16@2x.png +0 -0
  773. psychopy/app/Resources/light/pavlovia@2x.png +0 -0
  774. psychopy/app/Resources/light/pavsync.png +0 -0
  775. psychopy/app/Resources/light/pavsync@2x.png +0 -0
  776. psychopy/app/Resources/light/person_off.png +0 -0
  777. psychopy/app/Resources/light/person_off@2x.png +0 -0
  778. psychopy/app/Resources/light/person_on.png +0 -0
  779. psychopy/app/Resources/light/person_on@2x.png +0 -0
  780. psychopy/app/Resources/light/plugins32.png +0 -0
  781. psychopy/app/Resources/light/plugins32@2x.png +0 -0
  782. psychopy/app/Resources/light/plus.png +0 -0
  783. psychopy/app/Resources/light/plus@2x.png +0 -0
  784. psychopy/app/Resources/light/preferences-app.png +0 -0
  785. psychopy/app/Resources/light/preferences-app48.png +0 -0
  786. psychopy/app/Resources/light/preferences-app48@2x.png +0 -0
  787. psychopy/app/Resources/light/preferences-app@2x.png +0 -0
  788. psychopy/app/Resources/light/preferences-conn.png +0 -0
  789. psychopy/app/Resources/light/preferences-conn48.png +0 -0
  790. psychopy/app/Resources/light/preferences-conn48@2x.png +0 -0
  791. psychopy/app/Resources/light/preferences-conn@2x.png +0 -0
  792. psychopy/app/Resources/light/preferences-general.png +0 -0
  793. psychopy/app/Resources/light/preferences-general48.png +0 -0
  794. psychopy/app/Resources/light/preferences-general48@2x.png +0 -0
  795. psychopy/app/Resources/light/preferences-general@2x.png +0 -0
  796. psychopy/app/Resources/light/preferences-hardware.png +0 -0
  797. psychopy/app/Resources/light/preferences-hardware48.png +0 -0
  798. psychopy/app/Resources/light/preferences-hardware48@2x.png +0 -0
  799. psychopy/app/Resources/light/preferences-hardware@2x.png +0 -0
  800. psychopy/app/Resources/light/preferences-keyboard.png +0 -0
  801. psychopy/app/Resources/light/preferences-keyboard48.png +0 -0
  802. psychopy/app/Resources/light/preferences-keyboard48@2x.png +0 -0
  803. psychopy/app/Resources/light/preferences-keyboard@2x.png +0 -0
  804. psychopy/app/Resources/light/preferences-pilot.png +0 -0
  805. psychopy/app/Resources/light/preferences-pilot@2x.png +0 -0
  806. psychopy/app/Resources/light/preferences32.png +0 -0
  807. psychopy/app/Resources/light/preferences32@2x.png +0 -0
  808. psychopy/app/Resources/light/pyPilot.png +0 -0
  809. psychopy/app/Resources/light/pyPilot@2x.png +0 -0
  810. psychopy/app/Resources/light/pyRun.png +0 -0
  811. psychopy/app/Resources/light/pyRun@2x.png +0 -0
  812. psychopy/app/Resources/light/reddot.png +0 -0
  813. psychopy/app/Resources/light/reddot@2x.png +0 -0
  814. psychopy/app/Resources/light/redglobe.png +0 -0
  815. psychopy/app/Resources/light/redglobe@2x.png +0 -0
  816. psychopy/app/Resources/light/redglobe_bug.png +0 -0
  817. psychopy/app/Resources/light/redglobe_bug@2x.png +0 -0
  818. psychopy/app/Resources/light/redglobe_greensync.png +0 -0
  819. psychopy/app/Resources/light/redglobe_greensync@2x.png +0 -0
  820. psychopy/app/Resources/light/redglobe_info.png +0 -0
  821. psychopy/app/Resources/light/redglobe_info@2x.png +0 -0
  822. psychopy/app/Resources/light/redglobe_magnifier.png +0 -0
  823. psychopy/app/Resources/light/redglobe_magnifier@2x.png +0 -0
  824. psychopy/app/Resources/light/redglobe_run.png +0 -0
  825. psychopy/app/Resources/light/redglobe_run@2x.png +0 -0
  826. psychopy/app/Resources/light/redglobe_user.png +0 -0
  827. psychopy/app/Resources/light/redglobe_user@2x.png +0 -0
  828. psychopy/app/Resources/light/redo.png +0 -0
  829. psychopy/app/Resources/light/redo32.png +0 -0
  830. psychopy/app/Resources/light/redo32@2x.png +0 -0
  831. psychopy/app/Resources/light/redo@2x.png +0 -0
  832. psychopy/app/Resources/light/removeExp32.png +0 -0
  833. psychopy/app/Resources/light/removeExp32@2x.png +0 -0
  834. psychopy/app/Resources/light/rename16.png +0 -0
  835. psychopy/app/Resources/light/rename16@2x.png +0 -0
  836. psychopy/app/Resources/light/restart.png +0 -0
  837. psychopy/app/Resources/light/restart@2x.png +0 -0
  838. psychopy/app/Resources/light/runner.png +0 -0
  839. psychopy/app/Resources/light/runner@2x.png +0 -0
  840. psychopy/app/Resources/light/runnerPilot.png +0 -0
  841. psychopy/app/Resources/light/runnerPilot@2x.png +0 -0
  842. psychopy/app/Resources/light/savebtn16.png +0 -0
  843. psychopy/app/Resources/light/savebtn16@2x.png +0 -0
  844. psychopy/app/Resources/light/search.png +0 -0
  845. psychopy/app/Resources/light/search@2x.png +0 -0
  846. psychopy/app/Resources/light/showBuilder.png +0 -0
  847. psychopy/app/Resources/light/showBuilder@2x.png +0 -0
  848. psychopy/app/Resources/light/showCoder.png +0 -0
  849. psychopy/app/Resources/light/showCoder@2x.png +0 -0
  850. psychopy/app/Resources/light/showRunner.png +0 -0
  851. psychopy/app/Resources/light/showRunner@2x.png +0 -0
  852. psychopy/app/Resources/light/starred.png +0 -0
  853. psychopy/app/Resources/light/starred@2x.png +0 -0
  854. psychopy/app/Resources/light/start.png +0 -0
  855. psychopy/app/Resources/light/start@2x.png +0 -0
  856. psychopy/app/Resources/light/stdout.png +0 -0
  857. psychopy/app/Resources/light/stdout@2x.png +0 -0
  858. psychopy/app/Resources/light/stop.png +0 -0
  859. psychopy/app/Resources/light/stop32.png +0 -0
  860. psychopy/app/Resources/light/stop32@2x.png +0 -0
  861. psychopy/app/Resources/light/stop@2x.png +0 -0
  862. psychopy/app/Resources/light/switchCtrlBot.png +0 -0
  863. psychopy/app/Resources/light/switchCtrlBot@2x.png +0 -0
  864. psychopy/app/Resources/light/switchCtrlLeft.png +0 -0
  865. psychopy/app/Resources/light/switchCtrlLeft@2x.png +0 -0
  866. psychopy/app/Resources/light/switchCtrlRight.png +0 -0
  867. psychopy/app/Resources/light/switchCtrlRight@2x.png +0 -0
  868. psychopy/app/Resources/light/switchCtrlTop.png +0 -0
  869. psychopy/app/Resources/light/switchCtrlTop@2x.png +0 -0
  870. psychopy/app/Resources/light/tick.png +0 -0
  871. psychopy/app/Resources/light/tick@2x.png +0 -0
  872. psychopy/app/Resources/light/undo.png +0 -0
  873. psychopy/app/Resources/light/undo32.png +0 -0
  874. psychopy/app/Resources/light/undo32@2x.png +0 -0
  875. psychopy/app/Resources/light/undo@2x.png +0 -0
  876. psychopy/app/Resources/light/unstarred.png +0 -0
  877. psychopy/app/Resources/light/unstarred@2x.png +0 -0
  878. psychopy/app/Resources/light/user_none.png +0 -0
  879. psychopy/app/Resources/light/view-refresh16.png +0 -0
  880. psychopy/app/Resources/light/view-refresh16@2x.png +0 -0
  881. psychopy/app/Resources/light/viewbtn16.png +0 -0
  882. psychopy/app/Resources/light/viewbtn16@2x.png +0 -0
  883. psychopy/app/Resources/light/windows16.png +0 -0
  884. psychopy/app/Resources/light/windows16@2x.png +0 -0
  885. psychopy/app/Resources/moveComponentIcons.py +50 -0
  886. psychopy/app/Resources/next.png +0 -0
  887. psychopy/app/Resources/psychopy.desktop +13 -0
  888. psychopy/app/Resources/psychopy.icns +0 -0
  889. psychopy/app/Resources/psychopy.ico +0 -0
  890. psychopy/app/Resources/psychopy.png +0 -0
  891. psychopy/app/Resources/psychopy.xml +9 -0
  892. psychopy/app/Resources/psychopy@2x.png +0 -0
  893. psychopy/app/Resources/psychopySplash.png +0 -0
  894. psychopy/app/Resources/psychopySplash@2x.png +0 -0
  895. psychopy/app/Resources/routine_templates/Basic.psyexp +345 -0
  896. psychopy/app/Resources/routine_templates/Misc.psyexp +229 -0
  897. psychopy/app/Resources/routine_templates/Online.psyexp +202 -0
  898. psychopy/app/Resources/routine_templates/Trials.psyexp +736 -0
  899. psychopy/app/Resources/routine_templates/readme.md +14 -0
  900. psychopy/app/Resources/runner.ico +0 -0
  901. psychopy/app/Resources/tips.txt +45 -0
  902. psychopy/app/Resources/tips_ar_001.txt +45 -0
  903. psychopy/app/Resources/tips_fr_FR.txt +45 -0
  904. psychopy/app/Resources/tips_ja_JP.txt +42 -0
  905. psychopy/app/Resources/tips_zh_CN.txt +45 -0
  906. psychopy/app/Resources/window.ico +0 -0
  907. psychopy/app/__init__.py +224 -0
  908. psychopy/app/_psychopyApp.py +1224 -0
  909. psychopy/app/appData.spec +58 -0
  910. psychopy/app/builder/__init__.py +5 -0
  911. psychopy/app/builder/builder.py +4658 -0
  912. psychopy/app/builder/dialogs/__init__.py +2014 -0
  913. psychopy/app/builder/dialogs/dlgsCode.py +610 -0
  914. psychopy/app/builder/dialogs/dlgsConditions.py +670 -0
  915. psychopy/app/builder/dialogs/findDlg.py +189 -0
  916. psychopy/app/builder/dialogs/paramCtrls.py +1213 -0
  917. psychopy/app/builder/localizedStrings.py +225 -0
  918. psychopy/app/builder/validators.py +581 -0
  919. psychopy/app/coder/__init__.py +8 -0
  920. psychopy/app/coder/codeEditorBase.py +460 -0
  921. psychopy/app/coder/coder.py +3086 -0
  922. psychopy/app/coder/fileBrowser.py +668 -0
  923. psychopy/app/coder/folding.py +128 -0
  924. psychopy/app/coder/psychoParser.py +139 -0
  925. psychopy/app/coder/repl.py +493 -0
  926. psychopy/app/coder/sourceTree.py +302 -0
  927. psychopy/app/colorpicker/__init__.py +594 -0
  928. psychopy/app/colorpicker/ui.py +336 -0
  929. psychopy/app/connections/__init__.py +10 -0
  930. psychopy/app/connections/news.py +104 -0
  931. psychopy/app/connections/sendusage.py +61 -0
  932. psychopy/app/connections/updates.py +642 -0
  933. psychopy/app/console.py +164 -0
  934. psychopy/app/dialogs.py +632 -0
  935. psychopy/app/errorDlg.py +238 -0
  936. psychopy/app/frametracker.py +8 -0
  937. psychopy/app/idle.py +143 -0
  938. psychopy/app/jobs.py +648 -0
  939. psychopy/app/linuxconfig/__init__.py +144 -0
  940. psychopy/app/linuxconfig/ui.py +88 -0
  941. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  942. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +9554 -0
  943. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
  944. psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.po +24 -0
  945. psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
  946. psychopy/app/locale/da_DK/LC_MESSAGE/messages.po +24 -0
  947. psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
  948. psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +9712 -0
  949. psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
  950. psychopy/app/locale/el_GR/LC_MESSAGE/messages.po +25 -0
  951. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
  952. psychopy/app/locale/en_NZ/LC_MESSAGE/messages.po +25 -0
  953. psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
  954. psychopy/app/locale/en_US/LC_MESSAGE/messages.po +18 -0
  955. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  956. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +9100 -0
  957. psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
  958. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +9094 -0
  959. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  960. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +9100 -0
  961. psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
  962. psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +9569 -0
  963. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
  964. psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +5806 -0
  965. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
  966. psychopy/app/locale/fi_FI/LC_MESSAGE/messages.po +24 -0
  967. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
  968. psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +9577 -0
  969. psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
  970. psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +9549 -0
  971. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
  972. psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +9559 -0
  973. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
  974. psychopy/app/locale/hu_HU/LC_MESSAGE/messages.po +25 -0
  975. psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
  976. psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +9560 -0
  977. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  978. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +11687 -0
  979. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
  980. psychopy/app/locale/ko_KR/LC_MESSAGE/messages.po +24 -0
  981. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
  982. psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +8757 -0
  983. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
  984. psychopy/app/locale/nl_NL/LC_MESSAGE/messages.po +25 -0
  985. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
  986. psychopy/app/locale/nn_NO/LC_MESSAGE/messages.po +25 -0
  987. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
  988. psychopy/app/locale/pl_PL/LC_MESSAGE/messages.po +25 -0
  989. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
  990. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +24 -0
  991. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
  992. psychopy/app/locale/ro_RO/LC_MESSAGE/messages.po +25 -0
  993. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
  994. psychopy/app/locale/ru_RU/LC_MESSAGE/messages.po +24 -0
  995. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
  996. psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +8747 -0
  997. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
  998. psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +9545 -0
  999. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
  1000. psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +8268 -0
  1001. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
  1002. psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +8022 -0
  1003. psychopy/app/pavlovia_ui/__init__.py +22 -0
  1004. psychopy/app/pavlovia_ui/_base.py +237 -0
  1005. psychopy/app/pavlovia_ui/functions.py +176 -0
  1006. psychopy/app/pavlovia_ui/menu.py +140 -0
  1007. psychopy/app/pavlovia_ui/project.py +943 -0
  1008. psychopy/app/pavlovia_ui/search.py +445 -0
  1009. psychopy/app/pavlovia_ui/sync.py +137 -0
  1010. psychopy/app/pavlovia_ui/user.py +264 -0
  1011. psychopy/app/plugin_manager/__init__.py +5 -0
  1012. psychopy/app/plugin_manager/dialog.py +400 -0
  1013. psychopy/app/plugin_manager/output.py +132 -0
  1014. psychopy/app/plugin_manager/packages.py +502 -0
  1015. psychopy/app/plugin_manager/plugins.py +1315 -0
  1016. psychopy/app/plugin_manager/utils.py +115 -0
  1017. psychopy/app/preferencesDlg.py +790 -0
  1018. psychopy/app/psychopyApp.py +103 -0
  1019. psychopy/app/ribbon.py +907 -0
  1020. psychopy/app/runner/__init__.py +1 -0
  1021. psychopy/app/runner/runner.py +1262 -0
  1022. psychopy/app/runner/scriptProcess.py +353 -0
  1023. psychopy/app/stdout/__init__.py +1 -0
  1024. psychopy/app/stdout/stdOutRich.py +380 -0
  1025. psychopy/app/sysInfoDlg.py +242 -0
  1026. psychopy/app/themes/__init__.py +78 -0
  1027. psychopy/app/themes/colors.py +201 -0
  1028. psychopy/app/themes/css/contrast_black.css +112 -0
  1029. psychopy/app/themes/css/contrast_white.css +115 -0
  1030. psychopy/app/themes/css/dark.css +112 -0
  1031. psychopy/app/themes/css/light.css +115 -0
  1032. psychopy/app/themes/fonts.py +629 -0
  1033. psychopy/app/themes/handlers.py +321 -0
  1034. psychopy/app/themes/icons.py +250 -0
  1035. psychopy/app/themes/spec/Classic.json +154 -0
  1036. psychopy/app/themes/spec/ClassicDark.json +154 -0
  1037. psychopy/app/themes/spec/GitHub.json +154 -0
  1038. psychopy/app/themes/spec/HiVisDark.json +153 -0
  1039. psychopy/app/themes/spec/HiVisLight.json +154 -0
  1040. psychopy/app/themes/spec/MinimalDark.json +154 -0
  1041. psychopy/app/themes/spec/MinimalLight.json +153 -0
  1042. psychopy/app/themes/spec/PsychopyDark.json +231 -0
  1043. psychopy/app/themes/spec/PsychopyLight.json +236 -0
  1044. psychopy/app/themes/ui.py +74 -0
  1045. psychopy/app/ui/__init__.py +184 -0
  1046. psychopy/app/urls.py +31 -0
  1047. psychopy/app/utils.py +1680 -0
  1048. psychopy/app/viewer/__init__.py +0 -0
  1049. psychopy/clock.py +612 -0
  1050. psychopy/colors.py +1050 -0
  1051. psychopy/compatibility.py +95 -0
  1052. psychopy/constants.py +87 -0
  1053. psychopy/contrib/__init__.py +0 -0
  1054. psychopy/contrib/configobj/LICENSE +39 -0
  1055. psychopy/contrib/configobj/__init__.py +2453 -0
  1056. psychopy/contrib/configobj/_version.py +2 -0
  1057. psychopy/contrib/configobj/validate.py +1458 -0
  1058. psychopy/contrib/lazy_import.py +402 -0
  1059. psychopy/contrib/mseq.py +273 -0
  1060. psychopy/contrib/mseqSearch.py +183 -0
  1061. psychopy/contrib/psi.py +100 -0
  1062. psychopy/contrib/quest.py +484 -0
  1063. psychopy/contrib/tesselate.py +188 -0
  1064. psychopy/core.py +167 -0
  1065. psychopy/data/__init__.py +44 -0
  1066. psychopy/data/base.py +566 -0
  1067. psychopy/data/counterbalance.py +210 -0
  1068. psychopy/data/experiment.py +708 -0
  1069. psychopy/data/fit.py +248 -0
  1070. psychopy/data/shelf.py +237 -0
  1071. psychopy/data/staircase.py +2247 -0
  1072. psychopy/data/trial.py +1978 -0
  1073. psychopy/data/utils.py +783 -0
  1074. psychopy/demos/__init__.py +0 -0
  1075. psychopy/demos/builder/Design Templates/branchedExperiment/README.md +5 -0
  1076. psychopy/demos/builder/Design Templates/branchedExperiment/branchedExperiment.psyexp +239 -0
  1077. psychopy/demos/builder/Design Templates/branchedExperiment/trialTypes.xlsx +0 -0
  1078. psychopy/demos/builder/Design Templates/psychophysicsStaircase/README.md +20 -0
  1079. psychopy/demos/builder/Design Templates/psychophysicsStaircase/psychophysicsStaircase.psyexp +264 -0
  1080. psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/README.md +14 -0
  1081. psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/psychophysicsStaircaseInterleaved.psyexp +201 -0
  1082. psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/stairDefinitions.xlsx +0 -0
  1083. psychopy/demos/builder/Design Templates/randomisedBlocks/README.md +18 -0
  1084. psychopy/demos/builder/Design Templates/randomisedBlocks/chooseBlock.xlsx +0 -0
  1085. psychopy/demos/builder/Design Templates/randomisedBlocks/facesBlock.xlsx +0 -0
  1086. psychopy/demos/builder/Design Templates/randomisedBlocks/housesBlock.xlsx +0 -0
  1087. psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.psyexp +131 -0
  1088. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face01.jpg +0 -0
  1089. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face02.jpg +0 -0
  1090. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/face03.jpg +0 -0
  1091. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house01.jpg +0 -0
  1092. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house02.jpg +0 -0
  1093. psychopy/demos/builder/Design Templates/randomisedBlocks/stims/house03.jpg +0 -0
  1094. psychopy/demos/builder/Experiments/BART/README.md +30 -0
  1095. psychopy/demos/builder/Experiments/BART/assets/background.png +0 -0
  1096. psychopy/demos/builder/Experiments/BART/assets/bang.mp3 +0 -0
  1097. psychopy/demos/builder/Experiments/BART/assets/bang.wav +0 -0
  1098. psychopy/demos/builder/Experiments/BART/assets/blueBalloon.png +0 -0
  1099. psychopy/demos/builder/Experiments/BART/assets/greenBalloon.png +0 -0
  1100. psychopy/demos/builder/Experiments/BART/assets/redBalloon.png +0 -0
  1101. psychopy/demos/builder/Experiments/BART/bart.psyexp +931 -0
  1102. psychopy/demos/builder/Experiments/BART/spreadsheets/conditions.xlsx +0 -0
  1103. psychopy/demos/builder/Experiments/BigFiveInventory/BFI.psyexp +193 -0
  1104. psychopy/demos/builder/Experiments/BigFiveInventory/README.md +23 -0
  1105. psychopy/demos/builder/Experiments/BigFiveInventory/TIPI.xlsx +0 -0
  1106. psychopy/demos/builder/Experiments/BigFiveInventory/bigFiveItems.xlsx +0 -0
  1107. psychopy/demos/builder/Experiments/BigFiveInventory/demographics.xlsx +0 -0
  1108. psychopy/demos/builder/Experiments/BigFiveInventory/mini_IPIP.xlsx +0 -0
  1109. psychopy/demos/builder/Experiments/dragAndDrop/README.md +40 -0
  1110. psychopy/demos/builder/Experiments/dragAndDrop/archived_conditions.xlsx +0 -0
  1111. psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +1221 -0
  1112. psychopy/demos/builder/Experiments/dragAndDrop/draw grid stim.py +61 -0
  1113. psychopy/demos/builder/Experiments/dragAndDrop/shapeMaker.psyexp +91 -0
  1114. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_1.png +0 -0
  1115. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_10.png +0 -0
  1116. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_2.png +0 -0
  1117. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_3.png +0 -0
  1118. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_4.png +0 -0
  1119. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_5.png +0 -0
  1120. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_6.png +0 -0
  1121. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_7.png +0 -0
  1122. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_8.png +0 -0
  1123. psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_9.png +0 -0
  1124. psychopy/demos/builder/Experiments/dragAndDrop/updated_conditions.xlsx +0 -0
  1125. psychopy/demos/builder/Experiments/goNoGo/conditions.xlsx +0 -0
  1126. psychopy/demos/builder/Experiments/goNoGo/gng.psyexp +449 -0
  1127. psychopy/demos/builder/Experiments/goNoGo/go.png +0 -0
  1128. psychopy/demos/builder/Experiments/goNoGo/nogo.png +0 -0
  1129. psychopy/demos/builder/Experiments/goNoGo/readme.md +14 -0
  1130. psychopy/demos/builder/Experiments/mentalRotation/F.png +0 -0
  1131. psychopy/demos/builder/Experiments/mentalRotation/FR.png +0 -0
  1132. psychopy/demos/builder/Experiments/mentalRotation/MentalRot.csv +33 -0
  1133. psychopy/demos/builder/Experiments/mentalRotation/MentalRotation.psyexp +605 -0
  1134. psychopy/demos/builder/Experiments/mentalRotation/README.md +23 -0
  1135. psychopy/demos/builder/Experiments/navon/NavonTask.psyexp +478 -0
  1136. psychopy/demos/builder/Experiments/navon/README.md +26 -0
  1137. psychopy/demos/builder/Experiments/navon/bigHsmallH.png +0 -0
  1138. psychopy/demos/builder/Experiments/navon/bigHsmallS.png +0 -0
  1139. psychopy/demos/builder/Experiments/navon/bigSsmallH.png +0 -0
  1140. psychopy/demos/builder/Experiments/navon/bigSsmallS.png +0 -0
  1141. psychopy/demos/builder/Experiments/navon/mask.png +0 -0
  1142. psychopy/demos/builder/Experiments/navon/stimuli.pptx +0 -0
  1143. psychopy/demos/builder/Experiments/navon/trialTypes.xlsx +0 -0
  1144. psychopy/demos/builder/Experiments/sternberg/README.md +14 -0
  1145. psychopy/demos/builder/Experiments/sternberg/mainTrials.xlsx +0 -0
  1146. psychopy/demos/builder/Experiments/sternberg/pracTrials.xlsx +0 -0
  1147. psychopy/demos/builder/Experiments/sternberg/sternberg.psyexp +611 -0
  1148. psychopy/demos/builder/Experiments/stroop/README.md +15 -0
  1149. psychopy/demos/builder/Experiments/stroop/stroop.psyexp +225 -0
  1150. psychopy/demos/builder/Experiments/stroop/trialTypes.csv +7 -0
  1151. psychopy/demos/builder/Experiments/stroopExtended/README.md +14 -0
  1152. psychopy/demos/builder/Experiments/stroopExtended/stroop.psyexp +243 -0
  1153. psychopy/demos/builder/Experiments/stroopExtended/stroopReverse.psyexp +243 -0
  1154. psychopy/demos/builder/Experiments/stroopExtended/trialTypes.xlsx +0 -0
  1155. psychopy/demos/builder/Experiments/stroopExtended/trialTypesReverse.xlsx +0 -0
  1156. psychopy/demos/builder/Experiments/stroopVoice/README.md +27 -0
  1157. psychopy/demos/builder/Experiments/stroopVoice/conditions.xlsx +0 -0
  1158. psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +366 -0
  1159. psychopy/demos/builder/Feature Demos/counterbalance/counterbalance.psyexp +298 -0
  1160. psychopy/demos/builder/Feature Demos/gratings/gratings.psyexp +341 -0
  1161. psychopy/demos/builder/Feature Demos/gratings/readme.md +8 -0
  1162. psychopy/demos/builder/Feature Demos/noise/face.jpg +0 -0
  1163. psychopy/demos/builder/Feature Demos/noise/noise.psyexp +424 -0
  1164. psychopy/demos/builder/Feature Demos/noise/readme.md +3 -0
  1165. psychopy/demos/builder/Feature Demos/panorama/panImg.jpg +0 -0
  1166. psychopy/demos/builder/Feature Demos/panorama/panorama.psyexp +142 -0
  1167. psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +423 -0
  1168. psychopy/demos/builder/Feature Demos/progress/readme.md +1 -0
  1169. psychopy/demos/builder/Feature Demos/sliders/README.md +8 -0
  1170. psychopy/demos/builder/Feature Demos/sliders/fruitConditions.xlsx +0 -0
  1171. psychopy/demos/builder/Feature Demos/sliders/sliders.psyexp +938 -0
  1172. psychopy/demos/builder/Hardware/EEG_parallel_component/EEG_triggers_parallel_comp.psyexp +621 -0
  1173. psychopy/demos/builder/Hardware/EEG_serial_code/EEG_triggers_serial_code.psyexp +404 -0
  1174. psychopy/demos/builder/Hardware/EEG_serial_component/EEG_triggers_serial_comp.psyexp +641 -0
  1175. psychopy/demos/builder/Hardware/EGI_netstation/README.md +17 -0
  1176. psychopy/demos/builder/Hardware/EGI_netstation/stroop.psyexp +254 -0
  1177. psychopy/demos/builder/Hardware/EGI_netstation/trialTypesEEG.csv +7 -0
  1178. psychopy/demos/builder/Hardware/Eyetracking_visual_search/readme.md +19 -0
  1179. psychopy/demos/builder/Hardware/Eyetracking_visual_search/trials_params.xlsx +0 -0
  1180. psychopy/demos/builder/Hardware/Eyetracking_visual_search/visualSearch.psyexp +691 -0
  1181. psychopy/demos/builder/Hardware/camera/camera.psyexp +263 -0
  1182. psychopy/demos/builder/Hardware/camera/readme.md +6 -0
  1183. psychopy/demos/builder/Hardware/eyetracking/eyetracking.psyexp +354 -0
  1184. psychopy/demos/builder/Hardware/eyetracking/readme.md +7 -0
  1185. psychopy/demos/builder/Hardware/eyetracking_custom_cal/Bullseye_grey.mov +0 -0
  1186. psychopy/demos/builder/Hardware/eyetracking_custom_cal/eyetracking_custom_cal.psyexp +349 -0
  1187. psychopy/demos/builder/Hardware/eyetracking_custom_cal/readme.md +7 -0
  1188. psychopy/demos/builder/Hardware/fMRI/fMRI_demo.psyexp +202 -0
  1189. psychopy/demos/builder/Hardware/fMRI/readme.md +7 -0
  1190. psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo.psyexp +349 -0
  1191. psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy.psyexp +304 -0
  1192. psychopy/demos/builder/Hardware/microphone/microphone.psyexp +451 -0
  1193. psychopy/demos/builder/Hardware/microphone/phrases.xlsx +0 -0
  1194. psychopy/demos/builder/Hardware/microphone/readme.md +9 -0
  1195. psychopy/demos/builder/Hardware/pump/README.md +19 -0
  1196. psychopy/demos/builder/Hardware/pump/pump.psyexp +382 -0
  1197. psychopy/demos/builder/Helper Tools/achorVSalignment/anchorAlignment.psyexp +288 -0
  1198. psychopy/demos/builder/Helper Tools/achorVSalignment/readme.md +5 -0
  1199. psychopy/demos/builder/Helper Tools/clockFace/README.md +3 -0
  1200. psychopy/demos/builder/Helper Tools/clockFace/clockFace.psyexp +160 -0
  1201. psychopy/demos/builder/Helper Tools/colors/README.md +5 -0
  1202. psychopy/demos/builder/Helper Tools/colors/colors.psyexp +300 -0
  1203. psychopy/demos/builder/Helper Tools/drawPolygon/README.md +5 -0
  1204. psychopy/demos/builder/Helper Tools/drawPolygon/drawPolygon.psyexp +591 -0
  1205. psychopy/demos/builder/Helper Tools/keyNameFinder/README.md +14 -0
  1206. psychopy/demos/builder/Helper Tools/keyNameFinder/keyNameFinder.psyexp +169 -0
  1207. psychopy/demos/builder/Helper Tools/spatialUnits/README.md +6 -0
  1208. psychopy/demos/builder/Helper Tools/spatialUnits/unitDemo.psyexp +157 -0
  1209. psychopy/demos/builder/README.txt +43 -0
  1210. psychopy/demos/builder/__init__.py +0 -0
  1211. psychopy/demos/coder/__init__.py +0 -0
  1212. psychopy/demos/coder/basic/hello_world.py +37 -0
  1213. psychopy/demos/coder/csvFromPsydat.py +29 -0
  1214. psychopy/demos/coder/experiment control/JND_staircase_analysis.py +85 -0
  1215. psychopy/demos/coder/experiment control/JND_staircase_exp.py +110 -0
  1216. psychopy/demos/coder/experiment control/TrialHandler.py +64 -0
  1217. psychopy/demos/coder/experiment control/TrialHandler2.py +42 -0
  1218. psychopy/demos/coder/experiment control/__init__.py +0 -0
  1219. psychopy/demos/coder/experiment control/autoDraw_autoLog.py +50 -0
  1220. psychopy/demos/coder/experiment control/experimentHandler.py +57 -0
  1221. psychopy/demos/coder/experiment control/fMRI_launchScan.py +74 -0
  1222. psychopy/demos/coder/experiment control/gammaMotionAnalysis.py +68 -0
  1223. psychopy/demos/coder/experiment control/gammaMotionNull.py +169 -0
  1224. psychopy/demos/coder/experiment control/logFiles.py +55 -0
  1225. psychopy/demos/coder/experiment control/piloting.py +65 -0
  1226. psychopy/demos/coder/experiment control/runtimeInfo.py +79 -0
  1227. psychopy/demos/coder/hardware/CRS_BitsBox.py +75 -0
  1228. psychopy/demos/coder/hardware/CRS_BitsPlusPlus.py +73 -0
  1229. psychopy/demos/coder/hardware/RiftHeadTrackingExample.py +95 -0
  1230. psychopy/demos/coder/hardware/RiftMinimal.py +44 -0
  1231. psychopy/demos/coder/hardware/VSHD_Distortion.py +49 -0
  1232. psychopy/demos/coder/hardware/__init__.py +0 -0
  1233. psychopy/demos/coder/hardware/camera.py +90 -0
  1234. psychopy/demos/coder/hardware/cedrusRB730.py +38 -0
  1235. psychopy/demos/coder/hardware/crsBitsAdvancedDemo.py +780 -0
  1236. psychopy/demos/coder/hardware/egi_netstation.py +45 -0
  1237. psychopy/demos/coder/hardware/ioLab_bbox.py +62 -0
  1238. psychopy/demos/coder/hardware/labjack_u3.py +61 -0
  1239. psychopy/demos/coder/hardware/monitorDemo.py +28 -0
  1240. psychopy/demos/coder/hardware/parallelPortOutput.py +49 -0
  1241. psychopy/demos/coder/hardware/qmixPump.py +79 -0
  1242. psychopy/demos/coder/hardware/testSoundLatency.py +127 -0
  1243. psychopy/demos/coder/input/GUI.py +52 -0
  1244. psychopy/demos/coder/input/__init__.py +0 -0
  1245. psychopy/demos/coder/input/customMouse.py +51 -0
  1246. psychopy/demos/coder/input/joystick_universal.py +84 -0
  1247. psychopy/demos/coder/input/keyNameFinder.py +39 -0
  1248. psychopy/demos/coder/input/mic.png +0 -0
  1249. psychopy/demos/coder/input/mouse.py +66 -0
  1250. psychopy/demos/coder/iohub/delaytest.py +231 -0
  1251. psychopy/demos/coder/iohub/eyetracking/gcCursor/images/canal.jpg +0 -0
  1252. psychopy/demos/coder/iohub/eyetracking/gcCursor/images/fall.jpg +0 -0
  1253. psychopy/demos/coder/iohub/eyetracking/gcCursor/images/lake.jpg +0 -0
  1254. psychopy/demos/coder/iohub/eyetracking/gcCursor/images/party.jpg +0 -0
  1255. psychopy/demos/coder/iohub/eyetracking/gcCursor/images/swimming.jpg +0 -0
  1256. psychopy/demos/coder/iohub/eyetracking/gcCursor/readTrialEventsByConditionVariables.py +67 -0
  1257. psychopy/demos/coder/iohub/eyetracking/gcCursor/readTrialEventsByMessages.py +34 -0
  1258. psychopy/demos/coder/iohub/eyetracking/gcCursor/run.py +323 -0
  1259. psychopy/demos/coder/iohub/eyetracking/gcCursor/trial_conditions.xlsx +0 -0
  1260. psychopy/demos/coder/iohub/eyetracking/simple.py +147 -0
  1261. psychopy/demos/coder/iohub/eyetracking/validation.py +251 -0
  1262. psychopy/demos/coder/iohub/iodatastore/saveEventReport.py +56 -0
  1263. psychopy/demos/coder/iohub/keyboard.py +189 -0
  1264. psychopy/demos/coder/iohub/keyboardreactiontime.py +88 -0
  1265. psychopy/demos/coder/iohub/launchHub.py +160 -0
  1266. psychopy/demos/coder/iohub/mouse.py +112 -0
  1267. psychopy/demos/coder/iohub/mouse_multi_window.py +124 -0
  1268. psychopy/demos/coder/iohub/serial/_parseserial.py +53 -0
  1269. psychopy/demos/coder/iohub/serial/customparser.py +84 -0
  1270. psychopy/demos/coder/iohub/serial/pstbox.py +166 -0
  1271. psychopy/demos/coder/iohub/wintab/_wintabgraphics.py +281 -0
  1272. psychopy/demos/coder/iohub/wintab/pen_demo.py +260 -0
  1273. psychopy/demos/coder/misc/encrypt_data.py +48 -0
  1274. psychopy/demos/coder/misc/makeMovie.py +28 -0
  1275. psychopy/demos/coder/misc/rigidBodyTransform.py +76 -0
  1276. psychopy/demos/coder/stimuli/Campaign.ttf +0 -0
  1277. psychopy/demos/coder/stimuli/MovieStim.py +65 -0
  1278. psychopy/demos/coder/stimuli/__init__.py +0 -0
  1279. psychopy/demos/coder/stimuli/aperture.py +37 -0
  1280. psychopy/demos/coder/stimuli/beach.jpg +0 -0
  1281. psychopy/demos/coder/stimuli/bufferImageStim.py +78 -0
  1282. psychopy/demos/coder/stimuli/clockface.py +43 -0
  1283. psychopy/demos/coder/stimuli/colorPalette.py +134 -0
  1284. psychopy/demos/coder/stimuli/compare_text_timing.py +193 -0
  1285. psychopy/demos/coder/stimuli/counterphase.py +43 -0
  1286. psychopy/demos/coder/stimuli/customTextures.py +57 -0
  1287. psychopy/demos/coder/stimuli/dot_gabors.py +35 -0
  1288. psychopy/demos/coder/stimuli/dots.py +35 -0
  1289. psychopy/demos/coder/stimuli/elementArrays.py +92 -0
  1290. psychopy/demos/coder/stimuli/embeddedOpenGL.py +35 -0
  1291. psychopy/demos/coder/stimuli/face.jpg +0 -0
  1292. psychopy/demos/coder/stimuli/face_jpg.py +48 -0
  1293. psychopy/demos/coder/stimuli/gabor.py +30 -0
  1294. psychopy/demos/coder/stimuli/imagesAndPatches.py +51 -0
  1295. psychopy/demos/coder/stimuli/jwpIntro.mp4 +0 -0
  1296. psychopy/demos/coder/stimuli/kanizsa.py +41 -0
  1297. psychopy/demos/coder/stimuli/maskReveal.py +63 -0
  1298. psychopy/demos/coder/stimuli/plaid.py +43 -0
  1299. psychopy/demos/coder/stimuli/ratingScale.py +183 -0
  1300. psychopy/demos/coder/stimuli/rotatingFlashingWedge.py +37 -0
  1301. psychopy/demos/coder/stimuli/screensAndWindows.py +58 -0
  1302. psychopy/demos/coder/stimuli/secondOrderGratings.py +66 -0
  1303. psychopy/demos/coder/stimuli/shapeContains.py +50 -0
  1304. psychopy/demos/coder/stimuli/shapes.py +63 -0
  1305. psychopy/demos/coder/stimuli/soundStimuli.py +49 -0
  1306. psychopy/demos/coder/stimuli/starField.py +48 -0
  1307. psychopy/demos/coder/stimuli/stim3d.py +107 -0
  1308. psychopy/demos/coder/stimuli/textBoxStim/textbox_glyph_placement.py +93 -0
  1309. psychopy/demos/coder/stimuli/textBoxStim/textbox_simple.py +71 -0
  1310. psychopy/demos/coder/stimuli/textStimuli.py +106 -0
  1311. psychopy/demos/coder/stimuli/textbox_editable.py +64 -0
  1312. psychopy/demos/coder/stimuli/variousVisualStims.py +47 -0
  1313. psychopy/demos/coder/stimuli/visual_noise.py +31 -0
  1314. psychopy/demos/coder/sysInfo.py +56 -0
  1315. psychopy/demos/coder/timing/__init__.py +0 -0
  1316. psychopy/demos/coder/timing/callOnFlip.py +39 -0
  1317. psychopy/demos/coder/timing/clocksAndTimers.py +46 -0
  1318. psychopy/demos/coder/timing/millikeyKeyboardTimingTest.py +323 -0
  1319. psychopy/demos/coder/timing/timeByFrames.py +74 -0
  1320. psychopy/demos/coder/timing/timeByFramesEx.py +107 -0
  1321. psychopy/demos/coder/understanding psychopy/colors.py +70 -0
  1322. psychopy/demos/coder/understanding psychopy/fontLayout.py +69 -0
  1323. psychopy/demos/demo_migration.py +214 -0
  1324. psychopy/demos/modernizeDemos.py +16 -0
  1325. psychopy/demos/test_demo_migration.py +155 -0
  1326. psychopy/devices/__init__.py +8 -0
  1327. psychopy/event.py +1333 -0
  1328. psychopy/exceptions.py +59 -0
  1329. psychopy/experiment/__init__.py +51 -0
  1330. psychopy/experiment/_experiment.py +1392 -0
  1331. psychopy/experiment/blankTemplate.xltx +0 -0
  1332. psychopy/experiment/components/__init__.py +411 -0
  1333. psychopy/experiment/components/_base.py +1351 -0
  1334. psychopy/experiment/components/aperture/__init__.py +149 -0
  1335. psychopy/experiment/components/aperture/classic/aperture.png +0 -0
  1336. psychopy/experiment/components/aperture/classic/aperture@2x.png +0 -0
  1337. psychopy/experiment/components/aperture/dark/aperture.png +0 -0
  1338. psychopy/experiment/components/aperture/dark/aperture@2x.png +0 -0
  1339. psychopy/experiment/components/aperture/light/aperture.png +0 -0
  1340. psychopy/experiment/components/aperture/light/aperture@2x.png +0 -0
  1341. psychopy/experiment/components/brush/__init__.py +163 -0
  1342. psychopy/experiment/components/brush/classic/brush.png +0 -0
  1343. psychopy/experiment/components/brush/classic/brush@2x.png +0 -0
  1344. psychopy/experiment/components/brush/dark/brush.png +0 -0
  1345. psychopy/experiment/components/brush/dark/brush@2x.png +0 -0
  1346. psychopy/experiment/components/brush/light/brush.png +0 -0
  1347. psychopy/experiment/components/brush/light/brush@2x.png +0 -0
  1348. psychopy/experiment/components/button/__init__.py +489 -0
  1349. psychopy/experiment/components/button/classic/button.png +0 -0
  1350. psychopy/experiment/components/button/classic/button@2x.png +0 -0
  1351. psychopy/experiment/components/button/dark/button.png +0 -0
  1352. psychopy/experiment/components/button/dark/button@2x.png +0 -0
  1353. psychopy/experiment/components/button/light/button.png +0 -0
  1354. psychopy/experiment/components/button/light/button@2x.png +0 -0
  1355. psychopy/experiment/components/buttonBox/__init__.py +316 -0
  1356. psychopy/experiment/components/buttonBox/classic/buttonBox.png +0 -0
  1357. psychopy/experiment/components/buttonBox/classic/buttonBox@2x.png +0 -0
  1358. psychopy/experiment/components/buttonBox/dark/buttonBox.png +0 -0
  1359. psychopy/experiment/components/buttonBox/dark/buttonBox@2x.png +0 -0
  1360. psychopy/experiment/components/buttonBox/light/buttonBox.png +0 -0
  1361. psychopy/experiment/components/buttonBox/light/buttonBox@2x.png +0 -0
  1362. psychopy/experiment/components/camera/__init__.py +591 -0
  1363. psychopy/experiment/components/camera/classic/webcam.png +0 -0
  1364. psychopy/experiment/components/camera/classic/webcam@2x.png +0 -0
  1365. psychopy/experiment/components/camera/dark/webcam.png +0 -0
  1366. psychopy/experiment/components/camera/dark/webcam@2x.png +0 -0
  1367. psychopy/experiment/components/camera/light/webcam.png +0 -0
  1368. psychopy/experiment/components/camera/light/webcam@2x.png +0 -0
  1369. psychopy/experiment/components/code/__init__.py +266 -0
  1370. psychopy/experiment/components/code/classic/code.png +0 -0
  1371. psychopy/experiment/components/code/classic/code@2x.png +0 -0
  1372. psychopy/experiment/components/code/dark/code.png +0 -0
  1373. psychopy/experiment/components/code/dark/code@2x.png +0 -0
  1374. psychopy/experiment/components/code/light/code.png +0 -0
  1375. psychopy/experiment/components/code/light/code@2x.png +0 -0
  1376. psychopy/experiment/components/dots/__init__.py +199 -0
  1377. psychopy/experiment/components/dots/classic/dots.png +0 -0
  1378. psychopy/experiment/components/dots/classic/dots@2x.png +0 -0
  1379. psychopy/experiment/components/dots/dark/dots.png +0 -0
  1380. psychopy/experiment/components/dots/dark/dots@2x.png +0 -0
  1381. psychopy/experiment/components/dots/dots.xcf +0 -0
  1382. psychopy/experiment/components/dots/light/dots.png +0 -0
  1383. psychopy/experiment/components/dots/light/dots@2x.png +0 -0
  1384. psychopy/experiment/components/eyetracker_record/__init__.py +128 -0
  1385. psychopy/experiment/components/eyetracker_record/classic/eyetracker_record.png +0 -0
  1386. psychopy/experiment/components/eyetracker_record/classic/eyetracker_record@2x.png +0 -0
  1387. psychopy/experiment/components/eyetracker_record/dark/eyetracker_record.png +0 -0
  1388. psychopy/experiment/components/eyetracker_record/dark/eyetracker_record@2x.png +0 -0
  1389. psychopy/experiment/components/eyetracker_record/light/eyetracker_record.png +0 -0
  1390. psychopy/experiment/components/eyetracker_record/light/eyetracker_record@2x.png +0 -0
  1391. psychopy/experiment/components/form/__init__.py +223 -0
  1392. psychopy/experiment/components/form/classic/form.png +0 -0
  1393. psychopy/experiment/components/form/classic/form@2x.png +0 -0
  1394. psychopy/experiment/components/form/dark/form.png +0 -0
  1395. psychopy/experiment/components/form/dark/form@2x.png +0 -0
  1396. psychopy/experiment/components/form/formItems.xltx +0 -0
  1397. psychopy/experiment/components/form/light/form.png +0 -0
  1398. psychopy/experiment/components/form/light/form@2x.png +0 -0
  1399. psychopy/experiment/components/grating/__init__.py +192 -0
  1400. psychopy/experiment/components/grating/classic/grating.png +0 -0
  1401. psychopy/experiment/components/grating/classic/grating@2x.png +0 -0
  1402. psychopy/experiment/components/grating/dark/grating.png +0 -0
  1403. psychopy/experiment/components/grating/dark/grating@2x.png +0 -0
  1404. psychopy/experiment/components/grating/light/grating.png +0 -0
  1405. psychopy/experiment/components/grating/light/grating@2x.png +0 -0
  1406. psychopy/experiment/components/image/__init__.py +184 -0
  1407. psychopy/experiment/components/image/classic/image.png +0 -0
  1408. psychopy/experiment/components/image/classic/image@2x.png +0 -0
  1409. psychopy/experiment/components/image/dark/image.png +0 -0
  1410. psychopy/experiment/components/image/dark/image@2x.png +0 -0
  1411. psychopy/experiment/components/image/light/image.png +0 -0
  1412. psychopy/experiment/components/image/light/image@2x.png +0 -0
  1413. psychopy/experiment/components/joyButtons/__init__.py +453 -0
  1414. psychopy/experiment/components/joyButtons/classic/joyButtons.png +0 -0
  1415. psychopy/experiment/components/joyButtons/classic/joybuttons@2x.png +0 -0
  1416. psychopy/experiment/components/joyButtons/dark/joyButtons.png +0 -0
  1417. psychopy/experiment/components/joyButtons/dark/joyButtons@2x.png +0 -0
  1418. psychopy/experiment/components/joyButtons/light/joyButtons.png +0 -0
  1419. psychopy/experiment/components/joyButtons/light/joyButtons@2x.png +0 -0
  1420. psychopy/experiment/components/joyButtons/virtualJoyButtons.py +34 -0
  1421. psychopy/experiment/components/joystick/__init__.py +572 -0
  1422. psychopy/experiment/components/joystick/classic/joystick.png +0 -0
  1423. psychopy/experiment/components/joystick/classic/joystick@2x.png +0 -0
  1424. psychopy/experiment/components/joystick/dark/joystick.png +0 -0
  1425. psychopy/experiment/components/joystick/dark/joystick@2x.png +0 -0
  1426. psychopy/experiment/components/joystick/light/joystick.png +0 -0
  1427. psychopy/experiment/components/joystick/light/joystick@2x.png +0 -0
  1428. psychopy/experiment/components/joystick/virtualJoystick.py +40 -0
  1429. psychopy/experiment/components/keyboard/__init__.py +587 -0
  1430. psychopy/experiment/components/keyboard/classic/keyboard.png +0 -0
  1431. psychopy/experiment/components/keyboard/classic/keyboard@2x.png +0 -0
  1432. psychopy/experiment/components/keyboard/dark/keyboard.png +0 -0
  1433. psychopy/experiment/components/keyboard/dark/keyboard@2x.png +0 -0
  1434. psychopy/experiment/components/keyboard/light/keyboard.png +0 -0
  1435. psychopy/experiment/components/keyboard/light/keyboard@2x.png +0 -0
  1436. psychopy/experiment/components/keyboard.xcf +0 -0
  1437. psychopy/experiment/components/microphone/__init__.py +664 -0
  1438. psychopy/experiment/components/microphone/classic/microphone.png +0 -0
  1439. psychopy/experiment/components/microphone/classic/microphone@2x.png +0 -0
  1440. psychopy/experiment/components/microphone/dark/microphone.png +0 -0
  1441. psychopy/experiment/components/microphone/dark/microphone@2x.png +0 -0
  1442. psychopy/experiment/components/microphone/light/microphone.png +0 -0
  1443. psychopy/experiment/components/microphone/light/microphone@2x.png +0 -0
  1444. psychopy/experiment/components/mouse/__init__.py +747 -0
  1445. psychopy/experiment/components/mouse/classic/mouse.png +0 -0
  1446. psychopy/experiment/components/mouse/classic/mouse@2x.png +0 -0
  1447. psychopy/experiment/components/mouse/dark/mouse.png +0 -0
  1448. psychopy/experiment/components/mouse/dark/mouse@2x.png +0 -0
  1449. psychopy/experiment/components/mouse/light/mouse.png +0 -0
  1450. psychopy/experiment/components/mouse/light/mouse@2x.png +0 -0
  1451. psychopy/experiment/components/movie/__init__.py +367 -0
  1452. psychopy/experiment/components/movie/classic/movie.png +0 -0
  1453. psychopy/experiment/components/movie/classic/movie@2x.png +0 -0
  1454. psychopy/experiment/components/movie/dark/movie.png +0 -0
  1455. psychopy/experiment/components/movie/dark/movie@2x.png +0 -0
  1456. psychopy/experiment/components/movie/light/movie.png +0 -0
  1457. psychopy/experiment/components/movie/light/movie@2x.png +0 -0
  1458. psychopy/experiment/components/panorama/__init__.py +456 -0
  1459. psychopy/experiment/components/panorama/classic/panorama.png +0 -0
  1460. psychopy/experiment/components/panorama/classic/panorama@2x.png +0 -0
  1461. psychopy/experiment/components/panorama/dark/panorama.png +0 -0
  1462. psychopy/experiment/components/panorama/dark/panorama@2x.png +0 -0
  1463. psychopy/experiment/components/panorama/light/panorama.png +0 -0
  1464. psychopy/experiment/components/panorama/light/panorama@2x.png +0 -0
  1465. psychopy/experiment/components/parallelOut/__init__.py +178 -0
  1466. psychopy/experiment/components/parallelOut/classic/parallel.png +0 -0
  1467. psychopy/experiment/components/parallelOut/classic/parallel@2x.png +0 -0
  1468. psychopy/experiment/components/parallelOut/dark/parallel.png +0 -0
  1469. psychopy/experiment/components/parallelOut/dark/parallel@2x.png +0 -0
  1470. psychopy/experiment/components/parallelOut/light/parallel.png +0 -0
  1471. psychopy/experiment/components/parallelOut/light/parallel@2x.png +0 -0
  1472. psychopy/experiment/components/patch/__init__.py +121 -0
  1473. psychopy/experiment/components/patch/classic/patch.png +0 -0
  1474. psychopy/experiment/components/patch/dark/patch.png +0 -0
  1475. psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
  1476. psychopy/experiment/components/patch/light/patch.png +0 -0
  1477. psychopy/experiment/components/patch/light/patch@2x.png +0 -0
  1478. psychopy/experiment/components/polygon/__init__.py +303 -0
  1479. psychopy/experiment/components/polygon/classic/polygon.png +0 -0
  1480. psychopy/experiment/components/polygon/classic/polygon@2x.png +0 -0
  1481. psychopy/experiment/components/polygon/dark/polygon.png +0 -0
  1482. psychopy/experiment/components/polygon/dark/polygon@2x.png +0 -0
  1483. psychopy/experiment/components/polygon/light/polygon.png +0 -0
  1484. psychopy/experiment/components/polygon/light/polygon@2x.png +0 -0
  1485. psychopy/experiment/components/progress/__init__.py +130 -0
  1486. psychopy/experiment/components/progress/classic/progress.png +0 -0
  1487. psychopy/experiment/components/progress/classic/progress@2x.png +0 -0
  1488. psychopy/experiment/components/progress/dark/progress.png +0 -0
  1489. psychopy/experiment/components/progress/dark/progress@2x.png +0 -0
  1490. psychopy/experiment/components/progress/light/progress.png +0 -0
  1491. psychopy/experiment/components/progress/light/progress@2x.png +0 -0
  1492. psychopy/experiment/components/ratingScale/__init__.py +337 -0
  1493. psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
  1494. psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
  1495. psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
  1496. psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
  1497. psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
  1498. psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
  1499. psychopy/experiment/components/resourceManager/__init__.py +176 -0
  1500. psychopy/experiment/components/resourceManager/classic/resource_manager.png +0 -0
  1501. psychopy/experiment/components/resourceManager/classic/resource_manager@2x.png +0 -0
  1502. psychopy/experiment/components/resourceManager/dark/resource_manager.png +0 -0
  1503. psychopy/experiment/components/resourceManager/dark/resource_manager@2x.png +0 -0
  1504. psychopy/experiment/components/resourceManager/light/resource_manager.png +0 -0
  1505. psychopy/experiment/components/resourceManager/light/resource_manager@2x.png +0 -0
  1506. psychopy/experiment/components/roi/__init__.py +311 -0
  1507. psychopy/experiment/components/roi/classic/eyetracker_roi.png +0 -0
  1508. psychopy/experiment/components/roi/classic/eyetracker_roi@2x.png +0 -0
  1509. psychopy/experiment/components/roi/dark/eyetracker_roi.png +0 -0
  1510. psychopy/experiment/components/roi/dark/eyetracker_roi@2X.png +0 -0
  1511. psychopy/experiment/components/roi/light/eyetracker_roi.png +0 -0
  1512. psychopy/experiment/components/roi/light/eyetracker_roi@2X.png +0 -0
  1513. psychopy/experiment/components/routineSettings/__init__.py +338 -0
  1514. psychopy/experiment/components/routineSettings/classic/routineSettings.png +0 -0
  1515. psychopy/experiment/components/routineSettings/classic/routineSettings@2x.png +0 -0
  1516. psychopy/experiment/components/routineSettings/dark/routineSettings.png +0 -0
  1517. psychopy/experiment/components/routineSettings/dark/routineSettings@2x.png +0 -0
  1518. psychopy/experiment/components/routineSettings/light/routineSettings.png +0 -0
  1519. psychopy/experiment/components/routineSettings/light/routineSettings@2x.png +0 -0
  1520. psychopy/experiment/components/serialOut/__init__.py +205 -0
  1521. psychopy/experiment/components/serialOut/classic/serial.png +0 -0
  1522. psychopy/experiment/components/serialOut/classic/serial@2x.png +0 -0
  1523. psychopy/experiment/components/serialOut/dark/serial.png +0 -0
  1524. psychopy/experiment/components/serialOut/dark/serial@2x.png +0 -0
  1525. psychopy/experiment/components/serialOut/light/serial.png +0 -0
  1526. psychopy/experiment/components/serialOut/light/serial@2x.png +0 -0
  1527. psychopy/experiment/components/settings/JS_htmlHeader.tmpl +23 -0
  1528. psychopy/experiment/components/settings/JS_setupExp.tmpl +28 -0
  1529. psychopy/experiment/components/settings/__init__.py +2155 -0
  1530. psychopy/experiment/components/settings/classic/settings.png +0 -0
  1531. psychopy/experiment/components/settings/classic/settings@2x.png +0 -0
  1532. psychopy/experiment/components/settings/dark/settings.png +0 -0
  1533. psychopy/experiment/components/settings/dark/settings@2x.png +0 -0
  1534. psychopy/experiment/components/settings/light/settings.png +0 -0
  1535. psychopy/experiment/components/settings/light/settings@2x.png +0 -0
  1536. psychopy/experiment/components/slider/__init__.py +410 -0
  1537. psychopy/experiment/components/slider/classic/slider.png +0 -0
  1538. psychopy/experiment/components/slider/classic/slider@2x.png +0 -0
  1539. psychopy/experiment/components/slider/dark/slider.png +0 -0
  1540. psychopy/experiment/components/slider/dark/slider@2x.png +0 -0
  1541. psychopy/experiment/components/slider/light/slider.png +0 -0
  1542. psychopy/experiment/components/slider/light/slider@2x.png +0 -0
  1543. psychopy/experiment/components/sound/__init__.py +307 -0
  1544. psychopy/experiment/components/sound/classic/sound.png +0 -0
  1545. psychopy/experiment/components/sound/classic/sound@2x.png +0 -0
  1546. psychopy/experiment/components/sound/dark/sound.png +0 -0
  1547. psychopy/experiment/components/sound/dark/sound@2x.png +0 -0
  1548. psychopy/experiment/components/sound/light/sound.png +0 -0
  1549. psychopy/experiment/components/sound/light/sound@2x.png +0 -0
  1550. psychopy/experiment/components/static/__init__.py +267 -0
  1551. psychopy/experiment/components/static/classic/static.png +0 -0
  1552. psychopy/experiment/components/static/classic/static@2x.png +0 -0
  1553. psychopy/experiment/components/static/dark/static.png +0 -0
  1554. psychopy/experiment/components/static/dark/static@2x.png +0 -0
  1555. psychopy/experiment/components/static/light/static.png +0 -0
  1556. psychopy/experiment/components/static/light/static@2x.png +0 -0
  1557. psychopy/experiment/components/text/__init__.py +169 -0
  1558. psychopy/experiment/components/text/classic/text.png +0 -0
  1559. psychopy/experiment/components/text/classic/text@2x.png +0 -0
  1560. psychopy/experiment/components/text/dark/text.png +0 -0
  1561. psychopy/experiment/components/text/dark/text@2x.png +0 -0
  1562. psychopy/experiment/components/text/light/text.png +0 -0
  1563. psychopy/experiment/components/text/light/text@2x.png +0 -0
  1564. psychopy/experiment/components/textbox/__init__.py +330 -0
  1565. psychopy/experiment/components/textbox/classic/textbox.png +0 -0
  1566. psychopy/experiment/components/textbox/classic/textbox@2x.png +0 -0
  1567. psychopy/experiment/components/textbox/dark/textbox.png +0 -0
  1568. psychopy/experiment/components/textbox/dark/textbox@2x.png +0 -0
  1569. psychopy/experiment/components/textbox/light/textbox.png +0 -0
  1570. psychopy/experiment/components/textbox/light/textbox@2x.png +0 -0
  1571. psychopy/experiment/components/unknown/__init__.py +86 -0
  1572. psychopy/experiment/components/unknown/classic/unknown.png +0 -0
  1573. psychopy/experiment/components/unknown/classic/unknown@2x.png +0 -0
  1574. psychopy/experiment/components/unknown/dark/unknown.png +0 -0
  1575. psychopy/experiment/components/unknown/dark/unknown@2x.png +0 -0
  1576. psychopy/experiment/components/unknown/light/unknown.png +0 -0
  1577. psychopy/experiment/components/unknown/light/unknown@2x.png +0 -0
  1578. psychopy/experiment/components/unknownPlugin/__init__.py +84 -0
  1579. psychopy/experiment/components/unknownPlugin/classic/unknownPlugin.png +0 -0
  1580. psychopy/experiment/components/unknownPlugin/classic/unknownPlugin@2x.png +0 -0
  1581. psychopy/experiment/components/unknownPlugin/dark/unknownPlugin.png +0 -0
  1582. psychopy/experiment/components/unknownPlugin/dark/unknownPlugin@2x.png +0 -0
  1583. psychopy/experiment/components/unknownPlugin/light/unknownPlugin.png +0 -0
  1584. psychopy/experiment/components/unknownPlugin/light/unknownPlugin@2x.png +0 -0
  1585. psychopy/experiment/components/utils.py +0 -0
  1586. psychopy/experiment/components/variable/__init__.py +184 -0
  1587. psychopy/experiment/components/variable/classic/variable.png +0 -0
  1588. psychopy/experiment/components/variable/classic/variable@2x.png +0 -0
  1589. psychopy/experiment/components/variable/dark/variable.png +0 -0
  1590. psychopy/experiment/components/variable/dark/variable@2x.png +0 -0
  1591. psychopy/experiment/components/variable/light/variable.png +0 -0
  1592. psychopy/experiment/components/variable/light/variable@2x.png +0 -0
  1593. psychopy/experiment/experiment.xsd +223 -0
  1594. psychopy/experiment/exports.py +388 -0
  1595. psychopy/experiment/flow.py +531 -0
  1596. psychopy/experiment/localization.py +11 -0
  1597. psychopy/experiment/loopTemplate.xltx +0 -0
  1598. psychopy/experiment/loops.py +952 -0
  1599. psychopy/experiment/params.py +437 -0
  1600. psychopy/experiment/plugins.py +115 -0
  1601. psychopy/experiment/py2js.py +183 -0
  1602. psychopy/experiment/py2js_transpiler.py +606 -0
  1603. psychopy/experiment/questPlusTemplate.xltx +0 -0
  1604. psychopy/experiment/questTemplate.xltx +0 -0
  1605. psychopy/experiment/routines/__init__.py +108 -0
  1606. psychopy/experiment/routines/_base.py +907 -0
  1607. psychopy/experiment/routines/counterbalance/__init__.py +315 -0
  1608. psychopy/experiment/routines/counterbalance/classic/counterbalance.png +0 -0
  1609. psychopy/experiment/routines/counterbalance/classic/counterbalance@2x.png +0 -0
  1610. psychopy/experiment/routines/counterbalance/counterbalanceItems.xltx +0 -0
  1611. psychopy/experiment/routines/counterbalance/dark/counterbalance.png +0 -0
  1612. psychopy/experiment/routines/counterbalance/dark/counterbalance@2x.png +0 -0
  1613. psychopy/experiment/routines/counterbalance/light/counterbalance.png +0 -0
  1614. psychopy/experiment/routines/counterbalance/light/counterbalance@2x.png +0 -0
  1615. psychopy/experiment/routines/eyetracker_calibrate/__init__.py +275 -0
  1616. psychopy/experiment/routines/eyetracker_calibrate/classic/eyetracker_calib.png +0 -0
  1617. psychopy/experiment/routines/eyetracker_calibrate/dark/eyetracker_calib.png +0 -0
  1618. psychopy/experiment/routines/eyetracker_calibrate/dark/eyetracker_calib@2x.png +0 -0
  1619. psychopy/experiment/routines/eyetracker_calibrate/light/eyetracker_calib.png +0 -0
  1620. psychopy/experiment/routines/eyetracker_calibrate/light/eyetracker_calib@2x.png +0 -0
  1621. psychopy/experiment/routines/eyetracker_validate/__init__.py +354 -0
  1622. psychopy/experiment/routines/eyetracker_validate/classic/eyetracker_valid.png +0 -0
  1623. psychopy/experiment/routines/eyetracker_validate/dark/eyetracker_valid.png +0 -0
  1624. psychopy/experiment/routines/eyetracker_validate/dark/eyetracker_valid@2x.png +0 -0
  1625. psychopy/experiment/routines/eyetracker_validate/light/eyetracker_valid.png +0 -0
  1626. psychopy/experiment/routines/eyetracker_validate/light/eyetracker_valid@2x.png +0 -0
  1627. psychopy/experiment/routines/pavlovia_survey/__init__.py +236 -0
  1628. psychopy/experiment/routines/pavlovia_survey/classic/survey.png +0 -0
  1629. psychopy/experiment/routines/pavlovia_survey/classic/survey@2x.png +0 -0
  1630. psychopy/experiment/routines/pavlovia_survey/dark/survey.png +0 -0
  1631. psychopy/experiment/routines/pavlovia_survey/dark/survey@2x.png +0 -0
  1632. psychopy/experiment/routines/pavlovia_survey/light/survey.png +0 -0
  1633. psychopy/experiment/routines/pavlovia_survey/light/survey@2x.png +0 -0
  1634. psychopy/experiment/routines/photodiodeValidator/__init__.py +429 -0
  1635. psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator.png +0 -0
  1636. psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator@2x.png +0 -0
  1637. psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator.png +0 -0
  1638. psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator@2x.png +0 -0
  1639. psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator.png +0 -0
  1640. psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator@2x.png +0 -0
  1641. psychopy/experiment/routines/unknown/__init__.py +28 -0
  1642. psychopy/experiment/routines/unknown/classic/eyetracker_record.png +0 -0
  1643. psychopy/experiment/routines/unknown/classic/unknown.png +0 -0
  1644. psychopy/experiment/routines/unknown/dark/eyetracker_record.png +0 -0
  1645. psychopy/experiment/routines/unknown/dark/eyetracker_record@2x.png +0 -0
  1646. psychopy/experiment/routines/unknown/dark/unknown.png +0 -0
  1647. psychopy/experiment/routines/unknown/dark/unknown@2x.png +0 -0
  1648. psychopy/experiment/routines/unknown/light/eyetracker_record.png +0 -0
  1649. psychopy/experiment/routines/unknown/light/eyetracker_record@2x.png +0 -0
  1650. psychopy/experiment/routines/unknown/light/unknown.png +0 -0
  1651. psychopy/experiment/routines/unknown/light/unknown@2x.png +0 -0
  1652. psychopy/experiment/routines/utils.py +0 -0
  1653. psychopy/experiment/staircaseTemplate.xltx +0 -0
  1654. psychopy/experiment/utils.py +44 -0
  1655. psychopy/filters.py +11 -0
  1656. psychopy/gamma.py +9 -0
  1657. psychopy/gui/__init__.py +47 -0
  1658. psychopy/gui/qtgui.py +866 -0
  1659. psychopy/gui/util.py +78 -0
  1660. psychopy/gui/wxgui.py +414 -0
  1661. psychopy/hardware/__init__.py +216 -0
  1662. psychopy/hardware/base.py +323 -0
  1663. psychopy/hardware/bbtk/__init__.py +30 -0
  1664. psychopy/hardware/brainproducts.py +31 -0
  1665. psychopy/hardware/button.py +205 -0
  1666. psychopy/hardware/buttonbox/__init__.py +122 -0
  1667. psychopy/hardware/camera/__init__.py +2809 -0
  1668. psychopy/hardware/cedrus.py +36 -0
  1669. psychopy/hardware/crs/__init__.py +46 -0
  1670. psychopy/hardware/crs/bits.py +34 -0
  1671. psychopy/hardware/crs/colorcal.py +30 -0
  1672. psychopy/hardware/crs/optical.py +46 -0
  1673. psychopy/hardware/crs/shaders.py +21 -0
  1674. psychopy/hardware/emotiv.py +33 -0
  1675. psychopy/hardware/emulator.py +37 -0
  1676. psychopy/hardware/eyetracker.py +208 -0
  1677. psychopy/hardware/forp.py +42 -0
  1678. psychopy/hardware/gammasci.py +32 -0
  1679. psychopy/hardware/iolab.py +35 -0
  1680. psychopy/hardware/joystick/__init__.py +597 -0
  1681. psychopy/hardware/keyboard.py +880 -0
  1682. psychopy/hardware/knownDevices.json +52 -0
  1683. psychopy/hardware/labhackers.py +27 -0
  1684. psychopy/hardware/labjacks.py +30 -0
  1685. psychopy/hardware/listener.py +323 -0
  1686. psychopy/hardware/manager.py +963 -0
  1687. psychopy/hardware/microphone.py +1074 -0
  1688. psychopy/hardware/minolta.py +30 -0
  1689. psychopy/hardware/mouse/__init__.py +885 -0
  1690. psychopy/hardware/photodiode.py +639 -0
  1691. psychopy/hardware/photometer/__init__.py +176 -0
  1692. psychopy/hardware/pr.py +30 -0
  1693. psychopy/hardware/qmix.py +41 -0
  1694. psychopy/hardware/serialdevice.py +342 -0
  1695. psychopy/hardware/speaker.py +54 -0
  1696. psychopy/hardware/triggerbox/__init__.py +56 -0
  1697. psychopy/hardware/triggerbox/base.py +170 -0
  1698. psychopy/hardware/triggerbox/parallel.py +362 -0
  1699. psychopy/info.py +790 -0
  1700. psychopy/iohub/__init__.py +45 -0
  1701. psychopy/iohub/client/__init__.py +1454 -0
  1702. psychopy/iohub/client/connect.py +260 -0
  1703. psychopy/iohub/client/eyetracker/__init__.py +4 -0
  1704. psychopy/iohub/client/eyetracker/validation/__init__.py +8 -0
  1705. psychopy/iohub/client/eyetracker/validation/posgrid.py +274 -0
  1706. psychopy/iohub/client/eyetracker/validation/procedure.py +1292 -0
  1707. psychopy/iohub/client/eyetracker/validation/trigger.py +240 -0
  1708. psychopy/iohub/client/keyboard.py +508 -0
  1709. psychopy/iohub/client/wintab.py +378 -0
  1710. psychopy/iohub/constants.py +1176 -0
  1711. psychopy/iohub/datastore/__init__.py +439 -0
  1712. psychopy/iohub/datastore/default_datastore.yaml +8 -0
  1713. psychopy/iohub/datastore/util.py +868 -0
  1714. psychopy/iohub/default_config.yaml +17 -0
  1715. psychopy/iohub/devices/__init__.py +960 -0
  1716. psychopy/iohub/devices/computer.py +607 -0
  1717. psychopy/iohub/devices/default_device.yaml +15 -0
  1718. psychopy/iohub/devices/deviceConfigValidation.py +517 -0
  1719. psychopy/iohub/devices/display/__init__.py +755 -0
  1720. psychopy/iohub/devices/display/default_display.yaml +118 -0
  1721. psychopy/iohub/devices/display/supported_config_settings.yaml +69 -0
  1722. psychopy/iohub/devices/eventfilters.py +3572 -0
  1723. psychopy/iohub/devices/experiment/__init__.py +316 -0
  1724. psychopy/iohub/devices/experiment/default_experiment.yaml +63 -0
  1725. psychopy/iohub/devices/experiment/supported_config_settings.yaml +22 -0
  1726. psychopy/iohub/devices/eyetracker/__init__.py +436 -0
  1727. psychopy/iohub/devices/eyetracker/calibration/__init__.py +1 -0
  1728. psychopy/iohub/devices/eyetracker/calibration/procedure.py +409 -0
  1729. psychopy/iohub/devices/eyetracker/default_eyetracker.yaml +18 -0
  1730. psychopy/iohub/devices/eyetracker/eye_events.py +1751 -0
  1731. psychopy/iohub/devices/eyetracker/filters/__init__.py +4 -0
  1732. psychopy/iohub/devices/eyetracker/filters/parser.py +913 -0
  1733. psychopy/iohub/devices/eyetracker/hw/__init__.py +4 -0
  1734. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +17 -0
  1735. psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/__init__.py +28 -0
  1736. psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/calibration.py +18 -0
  1737. psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/eyetracker.py +21 -0
  1738. psychopy/iohub/devices/eyetracker/hw/mouse/__init__.py +8 -0
  1739. psychopy/iohub/devices/eyetracker/hw/mouse/calibration.py +10 -0
  1740. psychopy/iohub/devices/eyetracker/hw/mouse/default_eyetracker.yaml +102 -0
  1741. psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +444 -0
  1742. psychopy/iohub/devices/eyetracker/hw/mouse/supported_config_settings.yaml +110 -0
  1743. psychopy/iohub/devices/eyetracker/hw/pupil_labs/__init__.py +4 -0
  1744. psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/__init__.py +26 -0
  1745. psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/eyetracker.py +18 -0
  1746. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/__init__.py +29 -0
  1747. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/bisector.py +20 -0
  1748. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/constants.py +19 -0
  1749. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/data_parse.py +22 -0
  1750. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/eyetracker.py +18 -0
  1751. psychopy/iohub/devices/eyetracker/hw/pupil_labs/pupil_core/pupil_remote.py +18 -0
  1752. psychopy/iohub/devices/eyetracker/hw/sr_research/__init__.py +4 -0
  1753. psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/__init__.py +28 -0
  1754. psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/calibration.py +22 -0
  1755. psychopy/iohub/devices/eyetracker/hw/sr_research/eyelink/eyetracker.py +38 -0
  1756. psychopy/iohub/devices/eyetracker/hw/tobii/__init__.py +29 -0
  1757. psychopy/iohub/devices/eyetracker/hw/tobii/calibration.py +19 -0
  1758. psychopy/iohub/devices/eyetracker/hw/tobii/eyetracker.py +17 -0
  1759. psychopy/iohub/devices/eyetracker/hw/tobii/tobiiwrapper.py +19 -0
  1760. psychopy/iohub/devices/eyetracker/supported_config_settings.yaml +44 -0
  1761. psychopy/iohub/devices/keyboard/__init__.py +309 -0
  1762. psychopy/iohub/devices/keyboard/darwin.py +428 -0
  1763. psychopy/iohub/devices/keyboard/darwinkey.py +94 -0
  1764. psychopy/iohub/devices/keyboard/default_keyboard.yaml +94 -0
  1765. psychopy/iohub/devices/keyboard/linux2.py +102 -0
  1766. psychopy/iohub/devices/keyboard/supported_config_settings.yaml +39 -0
  1767. psychopy/iohub/devices/keyboard/win32.py +356 -0
  1768. psychopy/iohub/devices/mouse/__init__.py +709 -0
  1769. psychopy/iohub/devices/mouse/darwin.py +414 -0
  1770. psychopy/iohub/devices/mouse/default_mouse.yaml +92 -0
  1771. psychopy/iohub/devices/mouse/linux2.py +167 -0
  1772. psychopy/iohub/devices/mouse/supported_config_settings.yaml +39 -0
  1773. psychopy/iohub/devices/mouse/win32.py +279 -0
  1774. psychopy/iohub/devices/pyXHook.py +619 -0
  1775. psychopy/iohub/devices/serial/__init__.py +779 -0
  1776. psychopy/iohub/devices/serial/default_pstbox.yaml +108 -0
  1777. psychopy/iohub/devices/serial/default_serial.yaml +108 -0
  1778. psychopy/iohub/devices/serial/supported_config_settings.yaml +85 -0
  1779. psychopy/iohub/devices/serial/supported_config_settings_pstbox.yaml +85 -0
  1780. psychopy/iohub/devices/supported_config_settings.yaml +36 -0
  1781. psychopy/iohub/devices/wintab/__init__.py +580 -0
  1782. psychopy/iohub/devices/wintab/default_wintab.yaml +89 -0
  1783. psychopy/iohub/devices/wintab/supported_config_settings.yaml +42 -0
  1784. psychopy/iohub/devices/wintab/win32.py +722 -0
  1785. psychopy/iohub/devices/xlib.py +6795 -0
  1786. psychopy/iohub/errors.py +61 -0
  1787. psychopy/iohub/lazy_import.py +582 -0
  1788. psychopy/iohub/net.py +349 -0
  1789. psychopy/iohub/server.py +1075 -0
  1790. psychopy/iohub/start_iohub_process.py +118 -0
  1791. psychopy/iohub/util/__init__.py +841 -0
  1792. psychopy/iohub/util/visualangle.py +126 -0
  1793. psychopy/layout.py +916 -0
  1794. psychopy/liaison.py +419 -0
  1795. psychopy/locale_setup.py +31 -0
  1796. psychopy/localization/__init__.py +22 -0
  1797. psychopy/localization/_localization.py +155 -0
  1798. psychopy/localization/generateTranslationTemplate.py +139 -0
  1799. psychopy/localization/mappings.txt +170 -0
  1800. psychopy/localization/messages.pot +7516 -0
  1801. psychopy/localization/readme.txt +68 -0
  1802. psychopy/logging.py +406 -0
  1803. psychopy/microphone.py +54 -0
  1804. psychopy/misc.py +40 -0
  1805. psychopy/monitors/MonitorCenter.py +1254 -0
  1806. psychopy/monitors/__init__.py +30 -0
  1807. psychopy/monitors/calibData.py +78 -0
  1808. psychopy/monitors/calibTools.py +1300 -0
  1809. psychopy/monitors/getLumSeries.py +50 -0
  1810. psychopy/monitors/psychopy-icon.svg +395 -0
  1811. psychopy/monitors/psychopy.ico +0 -0
  1812. psychopy/parallel/__init__.py +206 -0
  1813. psychopy/parallel/_dlportio.py +150 -0
  1814. psychopy/parallel/_inpout.py +120 -0
  1815. psychopy/parallel/_linux.py +105 -0
  1816. psychopy/piloting.py +61 -0
  1817. psychopy/platform_specific/__init__.py +48 -0
  1818. psychopy/platform_specific/darwin.py +328 -0
  1819. psychopy/platform_specific/linux.py +79 -0
  1820. psychopy/platform_specific/posix.py +16 -0
  1821. psychopy/platform_specific/win32.py +99 -0
  1822. psychopy/plugins/__init__.py +1354 -0
  1823. psychopy/preferences/Darwin.spec +282 -0
  1824. psychopy/preferences/FreeBSD.spec +282 -0
  1825. psychopy/preferences/Linux.spec +282 -0
  1826. psychopy/preferences/Windows.spec +282 -0
  1827. psychopy/preferences/__init__.py +20 -0
  1828. psychopy/preferences/baseNoArch.spec +278 -0
  1829. psychopy/preferences/generateHints.py +91 -0
  1830. psychopy/preferences/generateSpec.py +80 -0
  1831. psychopy/preferences/hints.py +329 -0
  1832. psychopy/preferences/preferences.py +332 -0
  1833. psychopy/projects/__init__.py +11 -0
  1834. psychopy/projects/gitignore.py +45 -0
  1835. psychopy/projects/pavlovia.py +1566 -0
  1836. psychopy/projects/sshkeys.py +107 -0
  1837. psychopy/psychojs.zip +0 -0
  1838. psychopy/pylintrc +69 -0
  1839. psychopy/scripts/__init__.py +0 -0
  1840. psychopy/scripts/psyexpCompile.py +233 -0
  1841. psychopy/session.py +1450 -0
  1842. psychopy/sound/__init__.py +279 -0
  1843. psychopy/sound/_base.py +282 -0
  1844. psychopy/sound/audioclip.py +851 -0
  1845. psychopy/sound/audiodevice.py +857 -0
  1846. psychopy/sound/backend_ptb.py +660 -0
  1847. psychopy/sound/backend_pygame.py +309 -0
  1848. psychopy/sound/backend_pyo.py +33 -0
  1849. psychopy/sound/backend_pysound.py +341 -0
  1850. psychopy/sound/backend_sounddevice.py +32 -0
  1851. psychopy/sound/exceptions.py +115 -0
  1852. psychopy/sound/microphone.py +274 -0
  1853. psychopy/sound/transcribe.py +1248 -0
  1854. psychopy/tests/.DS_Store +0 -0
  1855. psychopy/tests/README.md +344 -0
  1856. psychopy/tests/__init__.py +47 -0
  1857. psychopy/tests/data/Electronic_Chime-KevanGC-495939803.wav +0 -0
  1858. psychopy/tests/data/TestCircle_w128h128_bottom_left.png +0 -0
  1859. psychopy/tests/data/TestCircle_w128h128_bottom_right.png +0 -0
  1860. psychopy/tests/data/TestCircle_w128h128_center_center.png +0 -0
  1861. psychopy/tests/data/TestCircle_w128h128_top_left.png +0 -0
  1862. psychopy/tests/data/TestCircle_w128h128_top_right.png +0 -0
  1863. psychopy/tests/data/TestCircle_w128h64_bottom_left.png +0 -0
  1864. psychopy/tests/data/TestCircle_w128h64_bottom_right.png +0 -0
  1865. psychopy/tests/data/TestCircle_w128h64_center_center.png +0 -0
  1866. psychopy/tests/data/TestCircle_w128h64_top_left.png +0 -0
  1867. psychopy/tests/data/TestCircle_w128h64_top_right.png +0 -0
  1868. psychopy/tests/data/TestCircle_w64h128_bottom_left.png +0 -0
  1869. psychopy/tests/data/TestCircle_w64h128_bottom_right.png +0 -0
  1870. psychopy/tests/data/TestCircle_w64h128_center_center.png +0 -0
  1871. psychopy/tests/data/TestCircle_w64h128_top_left.png +0 -0
  1872. psychopy/tests/data/TestCircle_w64h128_top_right.png +0 -0
  1873. psychopy/tests/data/TestCircle_w64h64_bottom_left.png +0 -0
  1874. psychopy/tests/data/TestCircle_w64h64_bottom_right.png +0 -0
  1875. psychopy/tests/data/TestCircle_w64h64_center_center.png +0 -0
  1876. psychopy/tests/data/TestCircle_w64h64_top_left.png +0 -0
  1877. psychopy/tests/data/TestCircle_w64h64_top_right.png +0 -0
  1878. psychopy/tests/data/TestForm_scrolling_nq10_s0.5.png +0 -0
  1879. psychopy/tests/data/TestForm_scrolling_nq10_s0.png +0 -0
  1880. psychopy/tests/data/TestForm_scrolling_nq10_s1.png +0 -0
  1881. psychopy/tests/data/TestForm_scrolling_nq1_s0.5.png +0 -0
  1882. psychopy/tests/data/TestForm_scrolling_nq1_s0.png +0 -0
  1883. psychopy/tests/data/TestForm_scrolling_nq1_s1.png +0 -0
  1884. psychopy/tests/data/TestForm_scrolling_nq3_s0.5.png +0 -0
  1885. psychopy/tests/data/TestForm_scrolling_nq3_s0.png +0 -0
  1886. psychopy/tests/data/TestForm_scrolling_nq3_s1.png +0 -0
  1887. psychopy/tests/data/TestImage_w128h128_bottom_left.png +0 -0
  1888. psychopy/tests/data/TestImage_w128h128_bottom_right.png +0 -0
  1889. psychopy/tests/data/TestImage_w128h128_center_center.png +0 -0
  1890. psychopy/tests/data/TestImage_w128h128_top_left.png +0 -0
  1891. psychopy/tests/data/TestImage_w128h128_top_right.png +0 -0
  1892. psychopy/tests/data/TestImage_w128h64_bottom_left.png +0 -0
  1893. psychopy/tests/data/TestImage_w128h64_bottom_right.png +0 -0
  1894. psychopy/tests/data/TestImage_w128h64_center_center.png +0 -0
  1895. psychopy/tests/data/TestImage_w128h64_top_left.png +0 -0
  1896. psychopy/tests/data/TestImage_w128h64_top_right.png +0 -0
  1897. psychopy/tests/data/TestImage_w64h128_bottom_left.png +0 -0
  1898. psychopy/tests/data/TestImage_w64h128_bottom_right.png +0 -0
  1899. psychopy/tests/data/TestImage_w64h128_center_center.png +0 -0
  1900. psychopy/tests/data/TestImage_w64h128_top_left.png +0 -0
  1901. psychopy/tests/data/TestImage_w64h128_top_right.png +0 -0
  1902. psychopy/tests/data/TestImage_w64h64_bottom_left.png +0 -0
  1903. psychopy/tests/data/TestImage_w64h64_bottom_right.png +0 -0
  1904. psychopy/tests/data/TestImage_w64h64_center_center.png +0 -0
  1905. psychopy/tests/data/TestImage_w64h64_top_left.png +0 -0
  1906. psychopy/tests/data/TestImage_w64h64_top_right.png +0 -0
  1907. psychopy/tests/data/TestProgress_testValue_horizontal_center center_0.3.png +0 -0
  1908. psychopy/tests/data/TestProgress_testValue_horizontal_center center_0.6.png +0 -0
  1909. psychopy/tests/data/TestProgress_testValue_horizontal_left center_0.3.png +0 -0
  1910. psychopy/tests/data/TestProgress_testValue_horizontal_left center_0.6.png +0 -0
  1911. psychopy/tests/data/TestProgress_testValue_horizontal_right center_0.3.png +0 -0
  1912. psychopy/tests/data/TestProgress_testValue_horizontal_right center_0.6.png +0 -0
  1913. psychopy/tests/data/TestProgress_testValue_minmax_0.png +0 -0
  1914. psychopy/tests/data/TestProgress_testValue_minmax_1.png +0 -0
  1915. psychopy/tests/data/TestProgress_testValue_vertical_bottom center_0.3.png +0 -0
  1916. psychopy/tests/data/TestProgress_testValue_vertical_bottom center_0.6.png +0 -0
  1917. psychopy/tests/data/TestProgress_testValue_vertical_center center_0.3.png +0 -0
  1918. psychopy/tests/data/TestProgress_testValue_vertical_center center_0.6.png +0 -0
  1919. psychopy/tests/data/TestProgress_testValue_vertical_top center_0.3.png +0 -0
  1920. psychopy/tests/data/TestProgress_testValue_vertical_top center_0.6.png +0 -0
  1921. psychopy/tests/data/TestProgress_w128h128_bottom_left.png +0 -0
  1922. psychopy/tests/data/TestProgress_w128h128_bottom_right.png +0 -0
  1923. psychopy/tests/data/TestProgress_w128h128_center_center.png +0 -0
  1924. psychopy/tests/data/TestProgress_w128h128_top_left.png +0 -0
  1925. psychopy/tests/data/TestProgress_w128h128_top_right.png +0 -0
  1926. psychopy/tests/data/TestProgress_w128h64_bottom_left.png +0 -0
  1927. psychopy/tests/data/TestProgress_w128h64_bottom_right.png +0 -0
  1928. psychopy/tests/data/TestProgress_w128h64_center_center.png +0 -0
  1929. psychopy/tests/data/TestProgress_w128h64_top_left.png +0 -0
  1930. psychopy/tests/data/TestProgress_w128h64_top_right.png +0 -0
  1931. psychopy/tests/data/TestProgress_w64h128_bottom_left.png +0 -0
  1932. psychopy/tests/data/TestProgress_w64h128_bottom_right.png +0 -0
  1933. psychopy/tests/data/TestProgress_w64h128_center_center.png +0 -0
  1934. psychopy/tests/data/TestProgress_w64h128_top_left.png +0 -0
  1935. psychopy/tests/data/TestProgress_w64h128_top_right.png +0 -0
  1936. psychopy/tests/data/TestProgress_w64h64_bottom_left.png +0 -0
  1937. psychopy/tests/data/TestProgress_w64h64_bottom_right.png +0 -0
  1938. psychopy/tests/data/TestProgress_w64h64_center_center.png +0 -0
  1939. psychopy/tests/data/TestProgress_w64h64_top_left.png +0 -0
  1940. psychopy/tests/data/TestProgress_w64h64_top_right.png +0 -0
  1941. psychopy/tests/data/TestROI_w128h128_bottom_left.png +0 -0
  1942. psychopy/tests/data/TestROI_w128h128_bottom_right.png +0 -0
  1943. psychopy/tests/data/TestROI_w128h128_center_center.png +0 -0
  1944. psychopy/tests/data/TestROI_w128h128_top_left.png +0 -0
  1945. psychopy/tests/data/TestROI_w128h128_top_right.png +0 -0
  1946. psychopy/tests/data/TestROI_w128h64_bottom_left.png +0 -0
  1947. psychopy/tests/data/TestROI_w128h64_bottom_right.png +0 -0
  1948. psychopy/tests/data/TestROI_w128h64_center_center.png +0 -0
  1949. psychopy/tests/data/TestROI_w128h64_top_left.png +0 -0
  1950. psychopy/tests/data/TestROI_w128h64_top_right.png +0 -0
  1951. psychopy/tests/data/TestROI_w64h128_bottom_left.png +0 -0
  1952. psychopy/tests/data/TestROI_w64h128_bottom_right.png +0 -0
  1953. psychopy/tests/data/TestROI_w64h128_center_center.png +0 -0
  1954. psychopy/tests/data/TestROI_w64h128_top_left.png +0 -0
  1955. psychopy/tests/data/TestROI_w64h128_top_right.png +0 -0
  1956. psychopy/tests/data/TestROI_w64h64_bottom_left.png +0 -0
  1957. psychopy/tests/data/TestROI_w64h64_bottom_right.png +0 -0
  1958. psychopy/tests/data/TestROI_w64h64_center_center.png +0 -0
  1959. psychopy/tests/data/TestROI_w64h64_top_left.png +0 -0
  1960. psychopy/tests/data/TestROI_w64h64_top_right.png +0 -0
  1961. psychopy/tests/data/TestSession_exp1.png +0 -0
  1962. psychopy/tests/data/TestSession_exp2.png +0 -0
  1963. psychopy/tests/data/TestShape_w128h128_bottom_left.png +0 -0
  1964. psychopy/tests/data/TestShape_w128h128_bottom_right.png +0 -0
  1965. psychopy/tests/data/TestShape_w128h128_center_center.png +0 -0
  1966. psychopy/tests/data/TestShape_w128h128_top_left.png +0 -0
  1967. psychopy/tests/data/TestShape_w128h128_top_right.png +0 -0
  1968. psychopy/tests/data/TestShape_w128h64_bottom_left.png +0 -0
  1969. psychopy/tests/data/TestShape_w128h64_bottom_right.png +0 -0
  1970. psychopy/tests/data/TestShape_w128h64_center_center.png +0 -0
  1971. psychopy/tests/data/TestShape_w128h64_top_left.png +0 -0
  1972. psychopy/tests/data/TestShape_w128h64_top_right.png +0 -0
  1973. psychopy/tests/data/TestShape_w64h128_bottom_left.png +0 -0
  1974. psychopy/tests/data/TestShape_w64h128_bottom_right.png +0 -0
  1975. psychopy/tests/data/TestShape_w64h128_center_center.png +0 -0
  1976. psychopy/tests/data/TestShape_w64h128_top_left.png +0 -0
  1977. psychopy/tests/data/TestShape_w64h128_top_right.png +0 -0
  1978. psychopy/tests/data/TestShape_w64h64_bottom_left.png +0 -0
  1979. psychopy/tests/data/TestShape_w64h64_bottom_right.png +0 -0
  1980. psychopy/tests/data/TestShape_w64h64_center_center.png +0 -0
  1981. psychopy/tests/data/TestShape_w64h64_top_left.png +0 -0
  1982. psychopy/tests/data/TestShape_w64h64_top_right.png +0 -0
  1983. psychopy/tests/data/TestTarget_w128h128_bottom_left.png +0 -0
  1984. psychopy/tests/data/TestTarget_w128h128_bottom_right.png +0 -0
  1985. psychopy/tests/data/TestTarget_w128h128_center_center.png +0 -0
  1986. psychopy/tests/data/TestTarget_w128h128_top_left.png +0 -0
  1987. psychopy/tests/data/TestTarget_w128h128_top_right.png +0 -0
  1988. psychopy/tests/data/TestTarget_w128h64_bottom_left.png +0 -0
  1989. psychopy/tests/data/TestTarget_w128h64_bottom_right.png +0 -0
  1990. psychopy/tests/data/TestTarget_w128h64_center_center.png +0 -0
  1991. psychopy/tests/data/TestTarget_w128h64_top_left.png +0 -0
  1992. psychopy/tests/data/TestTarget_w128h64_top_right.png +0 -0
  1993. psychopy/tests/data/TestTarget_w64h128_bottom_left.png +0 -0
  1994. psychopy/tests/data/TestTarget_w64h128_bottom_right.png +0 -0
  1995. psychopy/tests/data/TestTarget_w64h128_center_center.png +0 -0
  1996. psychopy/tests/data/TestTarget_w64h128_top_left.png +0 -0
  1997. psychopy/tests/data/TestTarget_w64h128_top_right.png +0 -0
  1998. psychopy/tests/data/TestTarget_w64h64_bottom_left.png +0 -0
  1999. psychopy/tests/data/TestTarget_w64h64_bottom_right.png +0 -0
  2000. psychopy/tests/data/TestTarget_w64h64_center_center.png +0 -0
  2001. psychopy/tests/data/TestTarget_w64h64_top_left.png +0 -0
  2002. psychopy/tests/data/TestTarget_w64h64_top_right.png +0 -0
  2003. psychopy/tests/data/TestTextbox_testLetterSpacing_0p6.png +0 -0
  2004. psychopy/tests/data/TestTextbox_testLetterSpacing_0p8.png +0 -0
  2005. psychopy/tests/data/TestTextbox_testLetterSpacing_1.png +0 -0
  2006. psychopy/tests/data/TestTextbox_testLetterSpacing_1p2.png +0 -0
  2007. psychopy/tests/data/TestTextbox_testLetterSpacing_1p4.png +0 -0
  2008. psychopy/tests/data/TestTextbox_testLetterSpacing_1p6.png +0 -0
  2009. psychopy/tests/data/TestTextbox_testLetterSpacing_1p8.png +0 -0
  2010. psychopy/tests/data/TestTextbox_testLetterSpacing_2p0.png +0 -0
  2011. psychopy/tests/data/TestTextbox_testLetterSpacing_None.png +0 -0
  2012. psychopy/tests/data/Test_textbox_testSpeechpoint_-3ovr8_0ovr8.png +0 -0
  2013. psychopy/tests/data/Test_textbox_testSpeechpoint_0ovr8_-3ovr8.png +0 -0
  2014. psychopy/tests/data/Test_textbox_testSpeechpoint_0ovr8_3ovr8.png +0 -0
  2015. psychopy/tests/data/Test_textbox_testSpeechpoint_3ovr8_0ovr8.png +0 -0
  2016. psychopy/tests/data/Test_textbox_w128h128_bottom_left.png +0 -0
  2017. psychopy/tests/data/Test_textbox_w128h128_bottom_right.png +0 -0
  2018. psychopy/tests/data/Test_textbox_w128h128_center_center.png +0 -0
  2019. psychopy/tests/data/Test_textbox_w128h128_top_left.png +0 -0
  2020. psychopy/tests/data/Test_textbox_w128h128_top_right.png +0 -0
  2021. psychopy/tests/data/Test_textbox_w128h64_bottom_left.png +0 -0
  2022. psychopy/tests/data/Test_textbox_w128h64_bottom_right.png +0 -0
  2023. psychopy/tests/data/Test_textbox_w128h64_center_center.png +0 -0
  2024. psychopy/tests/data/Test_textbox_w128h64_top_left.png +0 -0
  2025. psychopy/tests/data/Test_textbox_w128h64_top_right.png +0 -0
  2026. psychopy/tests/data/Test_textbox_w64h128_bottom_left.png +0 -0
  2027. psychopy/tests/data/Test_textbox_w64h128_bottom_right.png +0 -0
  2028. psychopy/tests/data/Test_textbox_w64h128_center_center.png +0 -0
  2029. psychopy/tests/data/Test_textbox_w64h128_top_left.png +0 -0
  2030. psychopy/tests/data/Test_textbox_w64h128_top_right.png +0 -0
  2031. psychopy/tests/data/Test_textbox_w64h64_bottom_left.png +0 -0
  2032. psychopy/tests/data/Test_textbox_w64h64_bottom_right.png +0 -0
  2033. psychopy/tests/data/Test_textbox_w64h64_center_center.png +0 -0
  2034. psychopy/tests/data/Test_textbox_w64h64_top_left.png +0 -0
  2035. psychopy/tests/data/Test_textbox_w64h64_top_right.png +0 -0
  2036. psychopy/tests/data/Test_uax14_textbox_w128h128_bottom_left.png +0 -0
  2037. psychopy/tests/data/Test_uax14_textbox_w128h128_bottom_right.png +0 -0
  2038. psychopy/tests/data/Test_uax14_textbox_w128h128_center_center.png +0 -0
  2039. psychopy/tests/data/Test_uax14_textbox_w128h128_top_left.png +0 -0
  2040. psychopy/tests/data/Test_uax14_textbox_w128h128_top_right.png +0 -0
  2041. psychopy/tests/data/Test_uax14_textbox_w128h64_bottom_left.png +0 -0
  2042. psychopy/tests/data/Test_uax14_textbox_w128h64_bottom_right.png +0 -0
  2043. psychopy/tests/data/Test_uax14_textbox_w128h64_center_center.png +0 -0
  2044. psychopy/tests/data/Test_uax14_textbox_w128h64_top_left.png +0 -0
  2045. psychopy/tests/data/Test_uax14_textbox_w128h64_top_right.png +0 -0
  2046. psychopy/tests/data/Test_uax14_textbox_w64h128_bottom_left.png +0 -0
  2047. psychopy/tests/data/Test_uax14_textbox_w64h128_bottom_right.png +0 -0
  2048. psychopy/tests/data/Test_uax14_textbox_w64h128_center_center.png +0 -0
  2049. psychopy/tests/data/Test_uax14_textbox_w64h128_top_left.png +0 -0
  2050. psychopy/tests/data/Test_uax14_textbox_w64h128_top_right.png +0 -0
  2051. psychopy/tests/data/Test_uax14_textbox_w64h64_bottom_left.png +0 -0
  2052. psychopy/tests/data/Test_uax14_textbox_w64h64_bottom_right.png +0 -0
  2053. psychopy/tests/data/Test_uax14_textbox_w64h64_center_center.png +0 -0
  2054. psychopy/tests/data/Test_uax14_textbox_w64h64_top_left.png +0 -0
  2055. psychopy/tests/data/Test_uax14_textbox_w64h64_top_right.png +0 -0
  2056. psychopy/tests/data/TextComponent_disabled.psyexp +63 -0
  2057. psychopy/tests/data/TextComponent_not_disabled.psyexp +63 -0
  2058. psychopy/tests/data/aperture1_deg.png +0 -0
  2059. psychopy/tests/data/aperture1_degFlat.png +0 -0
  2060. psychopy/tests/data/aperture1_degFlatPos.png +0 -0
  2061. psychopy/tests/data/aperture1_norm.png +0 -0
  2062. psychopy/tests/data/aperture1_normHexbackground.png +0 -0
  2063. psychopy/tests/data/aperture1_normNoShade.png +0 -0
  2064. psychopy/tests/data/aperture1_pix.png +0 -0
  2065. psychopy/tests/data/aperture1_stencil.png +0 -0
  2066. psychopy/tests/data/aperture2_deg.png +0 -0
  2067. psychopy/tests/data/aperture2_degFlat.png +0 -0
  2068. psychopy/tests/data/aperture2_degFlatPos.png +0 -0
  2069. psychopy/tests/data/aperture2_norm.png +0 -0
  2070. psychopy/tests/data/aperture2_normHexbackground.png +0 -0
  2071. psychopy/tests/data/aperture2_normNoShade.png +0 -0
  2072. psychopy/tests/data/aperture2_pix.png +0 -0
  2073. psychopy/tests/data/aperture2_stencil.png +0 -0
  2074. psychopy/tests/data/beatandrcos_cm.png +0 -0
  2075. psychopy/tests/data/beatandrcos_deg.png +0 -0
  2076. psychopy/tests/data/beatandrcos_degFlat.png +0 -0
  2077. psychopy/tests/data/beatandrcos_degFlatPos.png +0 -0
  2078. psychopy/tests/data/beatandrcos_height.png +0 -0
  2079. psychopy/tests/data/beatandrcos_norm.png +0 -0
  2080. psychopy/tests/data/beatandrcos_normAddBlend.png +0 -0
  2081. psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
  2082. psychopy/tests/data/beatandrcos_normHexbackground.png +0 -0
  2083. psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
  2084. psychopy/tests/data/beatandrcos_norm_local.png +0 -0
  2085. psychopy/tests/data/beatandrcos_pix.png +0 -0
  2086. psychopy/tests/data/beatandrcos_stencil.png +0 -0
  2087. psychopy/tests/data/blend_add_cm.png +0 -0
  2088. psychopy/tests/data/blend_add_deg.png +0 -0
  2089. psychopy/tests/data/blend_add_degFlat.png +0 -0
  2090. psychopy/tests/data/blend_add_degFlatPos.png +0 -0
  2091. psychopy/tests/data/blend_add_height.png +0 -0
  2092. psychopy/tests/data/blend_add_norm.png +0 -0
  2093. psychopy/tests/data/blend_add_normAddBlend.png +0 -0
  2094. psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
  2095. psychopy/tests/data/blend_add_normHexbackground.png +0 -0
  2096. psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
  2097. psychopy/tests/data/blend_add_normNoShade.png +0 -0
  2098. psychopy/tests/data/blend_add_norm_local.png +0 -0
  2099. psychopy/tests/data/blend_add_pix.png +0 -0
  2100. psychopy/tests/data/blend_add_stencil.png +0 -0
  2101. psychopy/tests/data/broken2020_2_5_resources/broken_resources.psyexp +84 -0
  2102. psychopy/tests/data/broken2020_2_5_resources/psychopy72.png +0 -0
  2103. psychopy/tests/data/bufferimg_gabor_cm.png +0 -0
  2104. psychopy/tests/data/bufferimg_gabor_deg.png +0 -0
  2105. psychopy/tests/data/bufferimg_gabor_degFlat.png +0 -0
  2106. psychopy/tests/data/bufferimg_gabor_degFlatPos.png +0 -0
  2107. psychopy/tests/data/bufferimg_gabor_height.png +0 -0
  2108. psychopy/tests/data/bufferimg_gabor_norm.png +0 -0
  2109. psychopy/tests/data/bufferimg_gabor_normAddBlend.png +0 -0
  2110. psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
  2111. psychopy/tests/data/bufferimg_gabor_normHexbackground.png +0 -0
  2112. psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
  2113. psychopy/tests/data/bufferimg_gabor_normNoShade.png +0 -0
  2114. psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
  2115. psychopy/tests/data/bufferimg_gabor_pix.png +0 -0
  2116. psychopy/tests/data/bufferimg_gabor_stencil.png +0 -0
  2117. psychopy/tests/data/circleHex_cm.png +0 -0
  2118. psychopy/tests/data/circleHex_deg.png +0 -0
  2119. psychopy/tests/data/circleHex_degFlat.png +0 -0
  2120. psychopy/tests/data/circleHex_degFlatPos.png +0 -0
  2121. psychopy/tests/data/circleHex_height.png +0 -0
  2122. psychopy/tests/data/circleHex_norm.png +0 -0
  2123. psychopy/tests/data/circleHex_normAddBlend.png +0 -0
  2124. psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
  2125. psychopy/tests/data/circleHex_normHexbackground.png +0 -0
  2126. psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
  2127. psychopy/tests/data/circleHex_normNoShade.png +0 -0
  2128. psychopy/tests/data/circleHex_norm_local.png +0 -0
  2129. psychopy/tests/data/circleHex_pix.png +0 -0
  2130. psychopy/tests/data/circleHex_stencil.png +0 -0
  2131. psychopy/tests/data/corrFullRandom.csv +16 -0
  2132. psychopy/tests/data/corrFullRandom.tsv +6 -0
  2133. psychopy/tests/data/corrFullRandomTH2.csv +16 -0
  2134. psychopy/tests/data/corrMultiKeyExpWide.csv +3 -0
  2135. psychopy/tests/data/corrMultiKeyTrials.csv +8 -0
  2136. psychopy/tests/data/corrMultiKeyTrials.xlsx +0 -0
  2137. psychopy/tests/data/corrRandom.csv +16 -0
  2138. psychopy/tests/data/corrRandom.tsv +6 -0
  2139. psychopy/tests/data/corrRandomTH2.csv +16 -0
  2140. psychopy/tests/data/corrXlsx.xlsx +0 -0
  2141. psychopy/tests/data/correctScript/js/correctCodeComponent.js +181 -0
  2142. psychopy/tests/data/correctScript/js/correctImageComponent.js +204 -0
  2143. psychopy/tests/data/correctScript/js/correctKeyboardComponent.js +225 -0
  2144. psychopy/tests/data/correctScript/js/correctMouseComponent.js +221 -0
  2145. psychopy/tests/data/correctScript/js/correctMovieComponent.js +210 -0
  2146. psychopy/tests/data/correctScript/js/correctPolygonComponent.js +205 -0
  2147. psychopy/tests/data/correctScript/js/correctSliderComponent.js +209 -0
  2148. psychopy/tests/data/correctScript/js/correctSoundComponent.js +205 -0
  2149. psychopy/tests/data/correctScript/js/correctTextComponent.js +207 -0
  2150. psychopy/tests/data/correctScript/python/correctApertureComponent.py +157 -0
  2151. psychopy/tests/data/correctScript/python/correctCodeComponent.py +135 -0
  2152. psychopy/tests/data/correctScript/python/correctDotsComponent.py +161 -0
  2153. psychopy/tests/data/correctScript/python/correctEnvGratingComponent.py +167 -0
  2154. psychopy/tests/data/correctScript/python/correctFormComponent.py +150 -0
  2155. psychopy/tests/data/correctScript/python/correctGratingComponent.py +158 -0
  2156. psychopy/tests/data/correctScript/python/correctImageComponent.py +160 -0
  2157. psychopy/tests/data/correctScript/python/correctJoyButtonsComponent.py +204 -0
  2158. psychopy/tests/data/correctScript/python/correctJoystickComponent.py +214 -0
  2159. psychopy/tests/data/correctScript/python/correctKeyboardComponent.py +169 -0
  2160. psychopy/tests/data/correctScript/python/correctMicrophoneComponent.py +163 -0
  2161. psychopy/tests/data/correctScript/python/correctMouseComponent.py +174 -0
  2162. psychopy/tests/data/correctScript/python/correctMovieComponent.py +160 -0
  2163. psychopy/tests/data/correctScript/python/correctNoiseStimComponent.py +169 -0
  2164. psychopy/tests/data/correctScript/python/correctParallelOutComponent.py +156 -0
  2165. psychopy/tests/data/correctScript/python/correctPatchComponent.py +159 -0
  2166. psychopy/tests/data/correctScript/python/correctPolygonComponent.py +159 -0
  2167. psychopy/tests/data/correctScript/python/correctQmixPumpComponent.py +174 -0
  2168. psychopy/tests/data/correctScript/python/correctRatingScaleComponent.py +152 -0
  2169. psychopy/tests/data/correctScript/python/correctSliderComponent.py +159 -0
  2170. psychopy/tests/data/correctScript/python/correctSoundComponent.py +157 -0
  2171. psychopy/tests/data/correctScript/python/correctStaticComponent.py +176 -0
  2172. psychopy/tests/data/correctScript/python/correctTextComponent.py +159 -0
  2173. psychopy/tests/data/correctScript/python/correctVariableComponent.py +139 -0
  2174. psychopy/tests/data/correctScript/python/correctcedrusButtonBoxComponent.py +199 -0
  2175. psychopy/tests/data/correctScript/python/correctioLabsButtonBoxComponent.py +187 -0
  2176. psychopy/tests/data/dataTest.xlsx +0 -0
  2177. psychopy/tests/data/dots_cm.png +0 -0
  2178. psychopy/tests/data/dots_deg.png +0 -0
  2179. psychopy/tests/data/dots_degFlat.png +0 -0
  2180. psychopy/tests/data/dots_degFlatPos.png +0 -0
  2181. psychopy/tests/data/dots_height.png +0 -0
  2182. psychopy/tests/data/dots_norm.png +0 -0
  2183. psychopy/tests/data/dots_normAddBlend.png +0 -0
  2184. psychopy/tests/data/dots_normAddBlend_local.png +0 -0
  2185. psychopy/tests/data/dots_normHexbackground.png +0 -0
  2186. psychopy/tests/data/dots_normHexbackground_local.png +0 -0
  2187. psychopy/tests/data/dots_normNoShade.png +0 -0
  2188. psychopy/tests/data/dots_norm_local.png +0 -0
  2189. psychopy/tests/data/dots_pix.png +0 -0
  2190. psychopy/tests/data/dots_stencil.png +0 -0
  2191. psychopy/tests/data/elarray1_cm.png +0 -0
  2192. psychopy/tests/data/elarray1_deg.png +0 -0
  2193. psychopy/tests/data/elarray1_degFlat.png +0 -0
  2194. psychopy/tests/data/elarray1_degFlatPos.png +0 -0
  2195. psychopy/tests/data/elarray1_height.png +0 -0
  2196. psychopy/tests/data/elarray1_norm.png +0 -0
  2197. psychopy/tests/data/elarray1_normAddBlend.png +0 -0
  2198. psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
  2199. psychopy/tests/data/elarray1_normHexbackground.png +0 -0
  2200. psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
  2201. psychopy/tests/data/elarray1_norm_local.png +0 -0
  2202. psychopy/tests/data/elarray1_pix.png +0 -0
  2203. psychopy/tests/data/elarray1_stencil.png +0 -0
  2204. psychopy/tests/data/envelopeandrcos_cm.png +0 -0
  2205. psychopy/tests/data/envelopeandrcos_deg.png +0 -0
  2206. psychopy/tests/data/envelopeandrcos_degFlat.png +0 -0
  2207. psychopy/tests/data/envelopeandrcos_degFlatPos.png +0 -0
  2208. psychopy/tests/data/envelopeandrcos_height.png +0 -0
  2209. psychopy/tests/data/envelopeandrcos_norm.png +0 -0
  2210. psychopy/tests/data/envelopeandrcos_normAddBlend.png +0 -0
  2211. psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
  2212. psychopy/tests/data/envelopeandrcos_normHexbackground.png +0 -0
  2213. psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
  2214. psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
  2215. psychopy/tests/data/envelopeandrcos_pix.png +0 -0
  2216. psychopy/tests/data/envelopeandrcos_stencil.png +0 -0
  2217. psychopy/tests/data/envelopepowerandrcos_cm.png +0 -0
  2218. psychopy/tests/data/envelopepowerandrcos_deg.png +0 -0
  2219. psychopy/tests/data/envelopepowerandrcos_degFlat.png +0 -0
  2220. psychopy/tests/data/envelopepowerandrcos_degFlatPos.png +0 -0
  2221. psychopy/tests/data/envelopepowerandrcos_height.png +0 -0
  2222. psychopy/tests/data/envelopepowerandrcos_norm.png +0 -0
  2223. psychopy/tests/data/envelopepowerandrcos_normAddBlend.png +0 -0
  2224. psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
  2225. psychopy/tests/data/envelopepowerandrcos_normHexbackground.png +0 -0
  2226. psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
  2227. psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
  2228. psychopy/tests/data/envelopepowerandrcos_pix.png +0 -0
  2229. psychopy/tests/data/envelopepowerandrcos_stencil.png +0 -0
  2230. psychopy/tests/data/filltext.png +0 -0
  2231. psychopy/tests/data/form_font_demographics.png +0 -0
  2232. psychopy/tests/data/form_font_demographics.xlsx +0 -0
  2233. psychopy/tests/data/form_font_languages.png +0 -0
  2234. psychopy/tests/data/form_font_languages.xlsx +0 -0
  2235. psychopy/tests/data/form_font_nonstandard.png +0 -0
  2236. psychopy/tests/data/futureParams.psyexp +150 -0
  2237. psychopy/tests/data/gabor1_cm.png +0 -0
  2238. psychopy/tests/data/gabor1_deg.png +0 -0
  2239. psychopy/tests/data/gabor1_degFlat.png +0 -0
  2240. psychopy/tests/data/gabor1_degFlatPos.png +0 -0
  2241. psychopy/tests/data/gabor1_height.png +0 -0
  2242. psychopy/tests/data/gabor1_norm.png +0 -0
  2243. psychopy/tests/data/gabor1_normAddBlend.png +0 -0
  2244. psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
  2245. psychopy/tests/data/gabor1_normHexbackground.png +0 -0
  2246. psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
  2247. psychopy/tests/data/gabor1_normNoShade.png +0 -0
  2248. psychopy/tests/data/gabor1_norm_local.png +0 -0
  2249. psychopy/tests/data/gabor1_pix.png +0 -0
  2250. psychopy/tests/data/gabor1_stencil.png +0 -0
  2251. psychopy/tests/data/gabor2_cm.png +0 -0
  2252. psychopy/tests/data/gabor2_deg.png +0 -0
  2253. psychopy/tests/data/gabor2_degFlat.png +0 -0
  2254. psychopy/tests/data/gabor2_degFlatPos.png +0 -0
  2255. psychopy/tests/data/gabor2_height.png +0 -0
  2256. psychopy/tests/data/gabor2_norm.png +0 -0
  2257. psychopy/tests/data/gabor2_normAddBlend.png +0 -0
  2258. psychopy/tests/data/gabor2_normHexbackground.png +0 -0
  2259. psychopy/tests/data/gabor2_normNoShade.png +0 -0
  2260. psychopy/tests/data/gabor2_pix.png +0 -0
  2261. psychopy/tests/data/gabor2_stencil.png +0 -0
  2262. psychopy/tests/data/ghost_stroop.psyexp +131 -0
  2263. psychopy/tests/data/ghost_trialTypes.xlsx +0 -0
  2264. psychopy/tests/data/green_48000.flac.dist +0 -0
  2265. psychopy/tests/data/greyscale.jpg +0 -0
  2266. psychopy/tests/data/greyscale2.png +0 -0
  2267. psychopy/tests/data/greyscale2_cm.png +0 -0
  2268. psychopy/tests/data/greyscale2_deg.png +0 -0
  2269. psychopy/tests/data/greyscale2_degFlat.png +0 -0
  2270. psychopy/tests/data/greyscale2_degFlatPos.png +0 -0
  2271. psychopy/tests/data/greyscale2_height.png +0 -0
  2272. psychopy/tests/data/greyscale2_norm.png +0 -0
  2273. psychopy/tests/data/greyscale2_normAddBlend.png +0 -0
  2274. psychopy/tests/data/greyscale2_normHexbackground.png +0 -0
  2275. psychopy/tests/data/greyscale2_normNoShade.png +0 -0
  2276. psychopy/tests/data/greyscale2_pix.png +0 -0
  2277. psychopy/tests/data/greyscale2_stencil.png +0 -0
  2278. psychopy/tests/data/greyscaleLowContr_cm.png +0 -0
  2279. psychopy/tests/data/greyscaleLowContr_deg.png +0 -0
  2280. psychopy/tests/data/greyscaleLowContr_degFlat.png +0 -0
  2281. psychopy/tests/data/greyscaleLowContr_degFlatPos.png +0 -0
  2282. psychopy/tests/data/greyscaleLowContr_height.png +0 -0
  2283. psychopy/tests/data/greyscaleLowContr_norm.png +0 -0
  2284. psychopy/tests/data/greyscaleLowContr_normAddBlend.png +0 -0
  2285. psychopy/tests/data/greyscaleLowContr_normHexbackground.png +0 -0
  2286. psychopy/tests/data/greyscaleLowContr_normNoShade.png +0 -0
  2287. psychopy/tests/data/greyscaleLowContr_pix.png +0 -0
  2288. psychopy/tests/data/greyscaleLowContr_stencil.png +0 -0
  2289. psychopy/tests/data/greyscale_cm.png +0 -0
  2290. psychopy/tests/data/greyscale_deg.png +0 -0
  2291. psychopy/tests/data/greyscale_degFlat.png +0 -0
  2292. psychopy/tests/data/greyscale_degFlatPos.png +0 -0
  2293. psychopy/tests/data/greyscale_height.png +0 -0
  2294. psychopy/tests/data/greyscale_norm.png +0 -0
  2295. psychopy/tests/data/greyscale_normAddBlend.png +0 -0
  2296. psychopy/tests/data/greyscale_normHexbackground.png +0 -0
  2297. psychopy/tests/data/greyscale_normNoShade.png +0 -0
  2298. psychopy/tests/data/greyscale_pix.png +0 -0
  2299. psychopy/tests/data/greyscale_stencil.png +0 -0
  2300. psychopy/tests/data/imageAndGauss_cm.png +0 -0
  2301. psychopy/tests/data/imageAndGauss_deg.png +0 -0
  2302. psychopy/tests/data/imageAndGauss_degFlat.png +0 -0
  2303. psychopy/tests/data/imageAndGauss_degFlatPos.png +0 -0
  2304. psychopy/tests/data/imageAndGauss_height.png +0 -0
  2305. psychopy/tests/data/imageAndGauss_norm.png +0 -0
  2306. psychopy/tests/data/imageAndGauss_normAddBlend.png +0 -0
  2307. psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
  2308. psychopy/tests/data/imageAndGauss_normHexbackground.png +0 -0
  2309. psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
  2310. psychopy/tests/data/imageAndGauss_normNoShade.png +0 -0
  2311. psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
  2312. psychopy/tests/data/imageAndGauss_pix.png +0 -0
  2313. psychopy/tests/data/imageAndGauss_stencil.png +0 -0
  2314. psychopy/tests/data/movFrame1_cm.png +0 -0
  2315. psychopy/tests/data/movFrame1_deg.png +0 -0
  2316. psychopy/tests/data/movFrame1_degFlat.png +0 -0
  2317. psychopy/tests/data/movFrame1_degFlatPos.png +0 -0
  2318. psychopy/tests/data/movFrame1_height.png +0 -0
  2319. psychopy/tests/data/movFrame1_norm.png +0 -0
  2320. psychopy/tests/data/movFrame1_normAddBlend.png +0 -0
  2321. psychopy/tests/data/movFrame1_normHexbackground.png +0 -0
  2322. psychopy/tests/data/movFrame1_normNoShade.png +0 -0
  2323. psychopy/tests/data/movFrame1_pix.png +0 -0
  2324. psychopy/tests/data/movFrame1_stencil.png +0 -0
  2325. psychopy/tests/data/multiKeypressExperiment.psydat +357 -0
  2326. psychopy/tests/data/multiKeypressTrialhandler.psydat +252 -0
  2327. psychopy/tests/data/multiStairConds.xlsx +0 -0
  2328. psychopy/tests/data/multiStairQuestPlus.xlsx +0 -0
  2329. psychopy/tests/data/newstyle.psydat +6155 -0
  2330. psychopy/tests/data/noiseAndRcos_cm.png +0 -0
  2331. psychopy/tests/data/noiseAndRcos_deg.png +0 -0
  2332. psychopy/tests/data/noiseAndRcos_degFlat.png +0 -0
  2333. psychopy/tests/data/noiseAndRcos_degFlatPos.png +0 -0
  2334. psychopy/tests/data/noiseAndRcos_height.png +0 -0
  2335. psychopy/tests/data/noiseAndRcos_norm.png +0 -0
  2336. psychopy/tests/data/noiseAndRcos_normAddBlend.png +0 -0
  2337. psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
  2338. psychopy/tests/data/noiseAndRcos_normHexbackground.png +0 -0
  2339. psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
  2340. psychopy/tests/data/noiseAndRcos_normNoShade.png +0 -0
  2341. psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
  2342. psychopy/tests/data/noiseAndRcos_pix.png +0 -0
  2343. psychopy/tests/data/noiseAndRcos_stencil.png +0 -0
  2344. psychopy/tests/data/noiseFiltersAndRcos_cm.png +0 -0
  2345. psychopy/tests/data/noiseFiltersAndRcos_deg.png +0 -0
  2346. psychopy/tests/data/noiseFiltersAndRcos_degFlat.png +0 -0
  2347. psychopy/tests/data/noiseFiltersAndRcos_degFlatPos.png +0 -0
  2348. psychopy/tests/data/noiseFiltersAndRcos_height.png +0 -0
  2349. psychopy/tests/data/noiseFiltersAndRcos_norm.png +0 -0
  2350. psychopy/tests/data/noiseFiltersAndRcos_normAddBlend.png +0 -0
  2351. psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
  2352. psychopy/tests/data/noiseFiltersAndRcos_normHexbackground.png +0 -0
  2353. psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
  2354. psychopy/tests/data/noiseFiltersAndRcos_normNoShade.png +0 -0
  2355. psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
  2356. psychopy/tests/data/noiseFiltersAndRcos_pix.png +0 -0
  2357. psychopy/tests/data/noiseFiltersAndRcos_stencil.png +0 -0
  2358. psychopy/tests/data/numpyImage_cm.png +0 -0
  2359. psychopy/tests/data/numpyImage_deg.png +0 -0
  2360. psychopy/tests/data/numpyImage_degFlat.png +0 -0
  2361. psychopy/tests/data/numpyImage_degFlatPos.png +0 -0
  2362. psychopy/tests/data/numpyImage_height.png +0 -0
  2363. psychopy/tests/data/numpyImage_norm.png +0 -0
  2364. psychopy/tests/data/numpyImage_normAddBlend.png +0 -0
  2365. psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
  2366. psychopy/tests/data/numpyImage_normHexbackground.png +0 -0
  2367. psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
  2368. psychopy/tests/data/numpyImage_normNoShade.png +0 -0
  2369. psychopy/tests/data/numpyImage_norm_local.png +0 -0
  2370. psychopy/tests/data/numpyImage_pix.png +0 -0
  2371. psychopy/tests/data/numpyImage_stencil.png +0 -0
  2372. psychopy/tests/data/numpyLowContr_cm.png +0 -0
  2373. psychopy/tests/data/numpyLowContr_deg.png +0 -0
  2374. psychopy/tests/data/numpyLowContr_degFlat.png +0 -0
  2375. psychopy/tests/data/numpyLowContr_degFlatPos.png +0 -0
  2376. psychopy/tests/data/numpyLowContr_height.png +0 -0
  2377. psychopy/tests/data/numpyLowContr_norm.png +0 -0
  2378. psychopy/tests/data/numpyLowContr_normAddBlend.png +0 -0
  2379. psychopy/tests/data/numpyLowContr_normHexbackground.png +0 -0
  2380. psychopy/tests/data/numpyLowContr_normNoShade.png +0 -0
  2381. psychopy/tests/data/numpyLowContr_pix.png +0 -0
  2382. psychopy/tests/data/numpyLowContr_stencil.png +0 -0
  2383. psychopy/tests/data/oldstyle.psydat +1534 -0
  2384. psychopy/tests/data/oldstyle_stair.psydat +263 -0
  2385. psychopy/tests/data/ratingscale1_cm.png +0 -0
  2386. psychopy/tests/data/ratingscale1_deg.png +0 -0
  2387. psychopy/tests/data/ratingscale1_degFlat.png +0 -0
  2388. psychopy/tests/data/ratingscale1_degFlatPos.png +0 -0
  2389. psychopy/tests/data/ratingscale1_height.png +0 -0
  2390. psychopy/tests/data/ratingscale1_norm.png +0 -0
  2391. psychopy/tests/data/ratingscale1_normAddBlend.png +0 -0
  2392. psychopy/tests/data/ratingscale1_normHexbackground.png +0 -0
  2393. psychopy/tests/data/ratingscale1_normNoShade.png +0 -0
  2394. psychopy/tests/data/ratingscale1_pix.png +0 -0
  2395. psychopy/tests/data/ratingscale1_stencil.png +0 -0
  2396. psychopy/tests/data/red_16000.flac.dist +0 -0
  2397. psychopy/tests/data/retroListParam.psyexp +82 -0
  2398. psychopy/tests/data/right_to_left_unidcode.xlsx +0 -0
  2399. psychopy/tests/data/sample.meshwarp.data +11522 -0
  2400. psychopy/tests/data/shape2_1_cm.png +0 -0
  2401. psychopy/tests/data/shape2_1_deg.png +0 -0
  2402. psychopy/tests/data/shape2_1_degFlat.png +0 -0
  2403. psychopy/tests/data/shape2_1_degFlatPos.png +0 -0
  2404. psychopy/tests/data/shape2_1_height.png +0 -0
  2405. psychopy/tests/data/shape2_1_norm.png +0 -0
  2406. psychopy/tests/data/shape2_1_normAddBlend.png +0 -0
  2407. psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
  2408. psychopy/tests/data/shape2_1_normHexbackground.png +0 -0
  2409. psychopy/tests/data/shape2_1_normNoShade.png +0 -0
  2410. psychopy/tests/data/shape2_1_norm_local.png +0 -0
  2411. psychopy/tests/data/shape2_1_pix.png +0 -0
  2412. psychopy/tests/data/shape2_1_stencil.png +0 -0
  2413. psychopy/tests/data/shape2_2_cm.png +0 -0
  2414. psychopy/tests/data/shape2_2_deg.png +0 -0
  2415. psychopy/tests/data/shape2_2_degFlat.png +0 -0
  2416. psychopy/tests/data/shape2_2_degFlatPos.png +0 -0
  2417. psychopy/tests/data/shape2_2_height.png +0 -0
  2418. psychopy/tests/data/shape2_2_norm.png +0 -0
  2419. psychopy/tests/data/shape2_2_normAddBlend.png +0 -0
  2420. psychopy/tests/data/shape2_2_normHexbackground.png +0 -0
  2421. psychopy/tests/data/shape2_2_normNoShade.png +0 -0
  2422. psychopy/tests/data/shape2_2_pix.png +0 -0
  2423. psychopy/tests/data/shape2_2_stencil.png +0 -0
  2424. psychopy/tests/data/simpleimage1_cm.png +0 -0
  2425. psychopy/tests/data/simpleimage1_deg.png +0 -0
  2426. psychopy/tests/data/simpleimage1_degFlat.png +0 -0
  2427. psychopy/tests/data/simpleimage1_degFlatPos.png +0 -0
  2428. psychopy/tests/data/simpleimage1_height.png +0 -0
  2429. psychopy/tests/data/simpleimage1_norm.png +0 -0
  2430. psychopy/tests/data/simpleimage1_normAddBlend.png +0 -0
  2431. psychopy/tests/data/simpleimage1_normHexbackground.png +0 -0
  2432. psychopy/tests/data/simpleimage1_normNoShade.png +0 -0
  2433. psychopy/tests/data/simpleimage1_pix.png +0 -0
  2434. psychopy/tests/data/simpleimage1_stencil.png +0 -0
  2435. psychopy/tests/data/test001EntryImporting.psyexp +66 -0
  2436. psychopy/tests/data/testMovie.mp4 +0 -0
  2437. psychopy/tests/data/test_circle_radius_.1height.png +0 -0
  2438. psychopy/tests/data/test_circle_radius_.2height.png +0 -0
  2439. psychopy/tests/data/test_circle_radius_10pix.png +0 -0
  2440. psychopy/tests/data/test_circle_radius_20pix.png +0 -0
  2441. psychopy/tests/data/test_form_combinations_choice_bigItem.png +0 -0
  2442. psychopy/tests/data/test_form_combinations_choice_bigItemOverflow.png +0 -0
  2443. psychopy/tests/data/test_form_combinations_choice_bigResp.png +0 -0
  2444. psychopy/tests/data/test_form_combinations_choice_bigRespOverflow.png +0 -0
  2445. psychopy/tests/data/test_form_combinations_description_bigItem.png +0 -0
  2446. psychopy/tests/data/test_form_combinations_description_bigItemOverflow.png +0 -0
  2447. psychopy/tests/data/test_form_combinations_description_bigResp.png +0 -0
  2448. psychopy/tests/data/test_form_combinations_description_bigRespOverflow.png +0 -0
  2449. psychopy/tests/data/test_form_combinations_free text_bigItem.png +0 -0
  2450. psychopy/tests/data/test_form_combinations_free text_bigItemOverflow.png +0 -0
  2451. psychopy/tests/data/test_form_combinations_free text_bigResp.png +0 -0
  2452. psychopy/tests/data/test_form_combinations_free text_bigRespOverflow.png +0 -0
  2453. psychopy/tests/data/test_form_combinations_heading_bigItem.png +0 -0
  2454. psychopy/tests/data/test_form_combinations_heading_bigItemOverflow.png +0 -0
  2455. psychopy/tests/data/test_form_combinations_heading_bigResp.png +0 -0
  2456. psychopy/tests/data/test_form_combinations_heading_bigRespOverflow.png +0 -0
  2457. psychopy/tests/data/test_form_combinations_radio_bigItem.png +0 -0
  2458. psychopy/tests/data/test_form_combinations_radio_bigItemOverflow.png +0 -0
  2459. psychopy/tests/data/test_form_combinations_radio_bigResp.png +0 -0
  2460. psychopy/tests/data/test_form_combinations_radio_bigRespOverflow.png +0 -0
  2461. psychopy/tests/data/test_form_combinations_rating_bigItem.png +0 -0
  2462. psychopy/tests/data/test_form_combinations_rating_bigItemOverflow.png +0 -0
  2463. psychopy/tests/data/test_form_combinations_rating_bigResp.png +0 -0
  2464. psychopy/tests/data/test_form_combinations_rating_bigRespOverflow.png +0 -0
  2465. psychopy/tests/data/test_form_combinations_slider_bigItem.png +0 -0
  2466. psychopy/tests/data/test_form_combinations_slider_bigItemOverflow.png +0 -0
  2467. psychopy/tests/data/test_form_combinations_slider_bigResp.png +0 -0
  2468. psychopy/tests/data/test_form_combinations_slider_bigRespOverflow.png +0 -0
  2469. psychopy/tests/data/test_get_resources/blue.png +0 -0
  2470. psychopy/tests/data/test_get_resources/groupA.csv +3 -0
  2471. psychopy/tests/data/test_get_resources/groupB.csv +3 -0
  2472. psychopy/tests/data/test_get_resources/groups.csv +3 -0
  2473. psychopy/tests/data/test_get_resources/handledbyrm_constrloop.psyexp +143 -0
  2474. psychopy/tests/data/test_get_resources/handledbyrm_noloop.psyexp +114 -0
  2475. psychopy/tests/data/test_get_resources/handledbyrm_recurloop.psyexp +138 -0
  2476. psychopy/tests/data/test_get_resources/handledbyrm_strloop.psyexp +126 -0
  2477. psychopy/tests/data/test_get_resources/handledbystatic_constrloop.psyexp +141 -0
  2478. psychopy/tests/data/test_get_resources/handledbystatic_noloop.psyexp +112 -0
  2479. psychopy/tests/data/test_get_resources/handledbystatic_recurloop.psyexp +136 -0
  2480. psychopy/tests/data/test_get_resources/handledbystatic_strloop.psyexp +124 -0
  2481. psychopy/tests/data/test_get_resources/unhandled_constrloop.psyexp +128 -0
  2482. psychopy/tests/data/test_get_resources/unhandled_noloop.psyexp +99 -0
  2483. psychopy/tests/data/test_get_resources/unhandled_recurloop.psyexp +123 -0
  2484. psychopy/tests/data/test_get_resources/unhandled_strloop.psyexp +111 -0
  2485. psychopy/tests/data/test_get_resources/white.png +0 -0
  2486. psychopy/tests/data/test_get_resources/yellow.png +0 -0
  2487. psychopy/tests/data/test_image_aspect_default_None.png +0 -0
  2488. psychopy/tests/data/test_image_aspect_default_xFull_yNone.png +0 -0
  2489. psychopy/tests/data/test_image_aspect_default_xNone_yFull.png +0 -0
  2490. psychopy/tests/data/test_image_aspect_default_xNone_yNone.png +0 -0
  2491. psychopy/tests/data/test_image_flip_anchor_horiz.png +0 -0
  2492. psychopy/tests/data/test_image_flip_anchor_vert.png +0 -0
  2493. psychopy/tests/data/test_loops/testLoopsBlocks.psyexp +161 -0
  2494. psychopy/tests/data/test_loops/testStaircase.psyexp +105 -0
  2495. psychopy/tests/data/test_loops/test_current_loop_attr.psyexp +185 -0
  2496. psychopy/tests/data/test_panorama/panoramaTestImage.png +0 -0
  2497. psychopy/tests/data/test_panorama/panoramaTestImage.svg +1 -0
  2498. psychopy/tests/data/test_panorama/testPanorama_mvmt_-0.3_-0.3.png +0 -0
  2499. psychopy/tests/data/test_panorama/testPanorama_mvmt_-0.3_0.3.png +0 -0
  2500. psychopy/tests/data/test_panorama/testPanorama_mvmt_-1.0_-0.3.png +0 -0
  2501. psychopy/tests/data/test_panorama/testPanorama_mvmt_-1.0_0.3.png +0 -0
  2502. psychopy/tests/data/test_panorama/testPanorama_mvmt_0.0_-1.0.png +0 -0
  2503. psychopy/tests/data/test_panorama/testPanorama_mvmt_0.0_1.0.png +0 -0
  2504. psychopy/tests/data/test_panorama/testPanorama_mvmt_0.3_-0.3.png +0 -0
  2505. psychopy/tests/data/test_panorama/testPanorama_mvmt_0.3_0.3.png +0 -0
  2506. psychopy/tests/data/test_resources.psyexp +491 -0
  2507. psychopy/tests/data/test_session/outside_root/externalExp.psyexp +116 -0
  2508. psychopy/tests/data/test_session/root/annotation/annotation.psyexp +161 -0
  2509. psychopy/tests/data/test_session/root/error/error.psyexp +93 -0
  2510. psychopy/tests/data/test_session/root/exp1/exp1.psyexp +133 -0
  2511. psychopy/tests/data/test_session/root/exp2/exp2.psyexp +133 -0
  2512. psychopy/tests/data/test_session/root/frameRate/frameRate.psyexp +114 -0
  2513. psychopy/tests/data/test_session/root/invUseVersion/invUseVersion.psyexp +133 -0
  2514. psychopy/tests/data/test_session/root/testClockFormat/testClockFormat.psyexp +122 -0
  2515. psychopy/tests/data/test_session/root/testCtrls/testCtrls.psyexp +115 -0
  2516. psychopy/tests/data/test_session/root/testEditExpInfo/testEditExpInfo.psyexp +135 -0
  2517. psychopy/tests/data/test_session/root/testNamedButtonBox/testNamedButtonBox.psyexp +145 -0
  2518. psychopy/tests/data/test_slider_horiz_accute_horiz.png +0 -0
  2519. psychopy/tests/data/test_slider_horiz_accute_vert.png +0 -0
  2520. psychopy/tests/data/test_slider_horiz_horiz.png +0 -0
  2521. psychopy/tests/data/test_slider_horiz_obtuse_horiz.png +0 -0
  2522. psychopy/tests/data/test_slider_horiz_obtuse_vert.png +0 -0
  2523. psychopy/tests/data/test_slider_horiz_vert.png +0 -0
  2524. psychopy/tests/data/test_slider_ticklabelloc_blanks.png +0 -0
  2525. psychopy/tests/data/test_slider_ticklabelloc_clustered.png +0 -0
  2526. psychopy/tests/data/test_slider_ticklabelloc_morelabels.png +0 -0
  2527. psychopy/tests/data/test_slider_ticklabelloc_morelabelsclustered.png +0 -0
  2528. psychopy/tests/data/test_slider_ticklabelloc_moreticks.png +0 -0
  2529. psychopy/tests/data/test_slider_ticklabelloc_moreticksclustered.png +0 -0
  2530. psychopy/tests/data/test_slider_ticklabelloc_nolabels.png +0 -0
  2531. psychopy/tests/data/test_slider_ticklabelloc_noticks.png +0 -0
  2532. psychopy/tests/data/test_slider_ticklabelloc_simple.png +0 -0
  2533. psychopy/tests/data/test_slider_triangle_horiz_False_flip_False.png +0 -0
  2534. psychopy/tests/data/test_slider_triangle_horiz_False_flip_True.png +0 -0
  2535. psychopy/tests/data/test_slider_triangle_horiz_True_flip_False.png +0 -0
  2536. psychopy/tests/data/test_slider_triangle_horiz_True_flip_True.png +0 -0
  2537. psychopy/tests/data/test_static_component_script.psyexp +76 -0
  2538. psychopy/tests/data/test_win_bg_large_256_default.png +0 -0
  2539. psychopy/tests/data/test_win_bg_large_500_default.png +0 -0
  2540. psychopy/tests/data/test_win_bg_small_200_default.png +0 -0
  2541. psychopy/tests/data/test_win_bg_small_256_default.png +0 -0
  2542. psychopy/tests/data/test_win_bg_tall_200_default.png +0 -0
  2543. psychopy/tests/data/test_win_bg_tall_256_default.png +0 -0
  2544. psychopy/tests/data/test_win_bg_tall_500_default.png +0 -0
  2545. psychopy/tests/data/test_win_bg_tall_fill_default.png +0 -0
  2546. psychopy/tests/data/test_win_bg_wide_200_default.png +0 -0
  2547. psychopy/tests/data/test_win_bg_wide_256_default.png +0 -0
  2548. psychopy/tests/data/test_win_bg_wide_500_default.png +0 -0
  2549. psychopy/tests/data/test_win_bg_wide_fill_default.png +0 -0
  2550. psychopy/tests/data/test_win_bgcolor_blue.png +0 -0
  2551. psychopy/tests/data/test_win_bgcolor_green.png +0 -0
  2552. psychopy/tests/data/test_win_bgcolor_red.png +0 -0
  2553. psychopy/tests/data/testimage.jpg +0 -0
  2554. psychopy/tests/data/testimagegray.jpg +0 -0
  2555. psychopy/tests/data/testpixels.png +0 -0
  2556. psychopy/tests/data/testwedges.png +0 -0
  2557. psychopy/tests/data/text1_cm.png +0 -0
  2558. psychopy/tests/data/text1_deg.png +0 -0
  2559. psychopy/tests/data/text1_degFlat.png +0 -0
  2560. psychopy/tests/data/text1_degFlatPos.png +0 -0
  2561. psychopy/tests/data/text1_height.png +0 -0
  2562. psychopy/tests/data/text1_norm.png +0 -0
  2563. psychopy/tests/data/text1_normAddBlend.png +0 -0
  2564. psychopy/tests/data/text1_normAddBlend_local.png +0 -0
  2565. psychopy/tests/data/text1_normHexbackground.png +0 -0
  2566. psychopy/tests/data/text1_normHexbackground_local.png +0 -0
  2567. psychopy/tests/data/text1_normNoShade.png +0 -0
  2568. psychopy/tests/data/text1_norm_local.png +0 -0
  2569. psychopy/tests/data/text1_pix.png +0 -0
  2570. psychopy/tests/data/text1_stencil.png +0 -0
  2571. psychopy/tests/data/text2_cm.png +0 -0
  2572. psychopy/tests/data/text2_deg.png +0 -0
  2573. psychopy/tests/data/text2_degFlat.png +0 -0
  2574. psychopy/tests/data/text2_degFlatPos.png +0 -0
  2575. psychopy/tests/data/text2_height.png +0 -0
  2576. psychopy/tests/data/text2_norm.png +0 -0
  2577. psychopy/tests/data/text2_normNoShade.png +0 -0
  2578. psychopy/tests/data/text2_pix.png +0 -0
  2579. psychopy/tests/data/text2_stencil.png +0 -0
  2580. psychopy/tests/data/textbox_charcolors_default_roygbiv.png +0 -0
  2581. psychopy/tests/data/textbox_charcolors_default_white_hello_black_there.png +0 -0
  2582. psychopy/tests/data/textbox_default_align_bottom_center.png +0 -0
  2583. psychopy/tests/data/textbox_default_align_bottom_left.png +0 -0
  2584. psychopy/tests/data/textbox_default_align_bottom_right.png +0 -0
  2585. psychopy/tests/data/textbox_default_align_center.png +0 -0
  2586. psychopy/tests/data/textbox_default_align_center_center.png +0 -0
  2587. psychopy/tests/data/textbox_default_align_center_left.png +0 -0
  2588. psychopy/tests/data/textbox_default_align_center_right.png +0 -0
  2589. psychopy/tests/data/textbox_default_align_centre.png +0 -0
  2590. psychopy/tests/data/textbox_default_align_centre_centre.png +0 -0
  2591. psychopy/tests/data/textbox_default_align_more_than_two_words.png +0 -0
  2592. psychopy/tests/data/textbox_default_align_someword.png +0 -0
  2593. psychopy/tests/data/textbox_default_align_top_center.png +0 -0
  2594. psychopy/tests/data/textbox_default_align_top_left.png +0 -0
  2595. psychopy/tests/data/textbox_default_align_top_right.png +0 -0
  2596. psychopy/tests/data/textbox_default_colors_WOB.png +0 -0
  2597. psychopy/tests/data/textbox_default_colors_exemplar1.png +0 -0
  2598. psychopy/tests/data/textbox_default_colors_exemplar2.png +0 -0
  2599. psychopy/tests/data/textbox_default_colors_exemplar3.png +0 -0
  2600. psychopy/tests/data/textbox_default_colors_tyke1.png +0 -0
  2601. psychopy/tests/data/textbox_default_colors_tyke2.png +0 -0
  2602. psychopy/tests/data/textbox_default_colors_tyke3.png +0 -0
  2603. psychopy/tests/data/textbox_default_cutoff_top.png +0 -0
  2604. psychopy/tests/data/textbox_default_exemplar_1.png +0 -0
  2605. psychopy/tests/data/textbox_default_exemplar_2.png +0 -0
  2606. psychopy/tests/data/textbox_default_exemplar_3.png +0 -0
  2607. psychopy/tests/data/textbox_default_exemplar_4.png +0 -0
  2608. psychopy/tests/data/textbox_default_tyke_1.png +0 -0
  2609. psychopy/tests/data/textbox_default_tyke_2.png +0 -0
  2610. psychopy/tests/data/textbox_typing_blank.png +0 -0
  2611. psychopy/tests/data/textbox_typing_longKoeran.png +0 -0
  2612. psychopy/tests/data/textbox_typing_longWord.png +0 -0
  2613. psychopy/tests/data/textbox_typing_navDel.png +0 -0
  2614. psychopy/tests/data/textbox_typing_navLR.png +0 -0
  2615. psychopy/tests/data/textbox_typing_newline.png +0 -0
  2616. psychopy/tests/data/textbox_typing_pangram.png +0 -0
  2617. psychopy/tests/data/textbox_uax14_align_bottom_center.png +0 -0
  2618. psychopy/tests/data/textbox_uax14_align_bottom_left.png +0 -0
  2619. psychopy/tests/data/textbox_uax14_align_bottom_right.png +0 -0
  2620. psychopy/tests/data/textbox_uax14_align_center.png +0 -0
  2621. psychopy/tests/data/textbox_uax14_align_center_center.png +0 -0
  2622. psychopy/tests/data/textbox_uax14_align_center_left.png +0 -0
  2623. psychopy/tests/data/textbox_uax14_align_center_right.png +0 -0
  2624. psychopy/tests/data/textbox_uax14_align_centre.png +0 -0
  2625. psychopy/tests/data/textbox_uax14_align_centre_centre.png +0 -0
  2626. psychopy/tests/data/textbox_uax14_align_more_than_two_words.png +0 -0
  2627. psychopy/tests/data/textbox_uax14_align_someword.png +0 -0
  2628. psychopy/tests/data/textbox_uax14_align_top_center.png +0 -0
  2629. psychopy/tests/data/textbox_uax14_align_top_left.png +0 -0
  2630. psychopy/tests/data/textbox_uax14_align_top_right.png +0 -0
  2631. psychopy/tests/data/textbox_uax14_colors_WOB.png +0 -0
  2632. psychopy/tests/data/textbox_uax14_colors_exemplar1.png +0 -0
  2633. psychopy/tests/data/textbox_uax14_colors_exemplar2.png +0 -0
  2634. psychopy/tests/data/textbox_uax14_colors_exemplar3.png +0 -0
  2635. psychopy/tests/data/textbox_uax14_colors_tyke1.png +0 -0
  2636. psychopy/tests/data/textbox_uax14_colors_tyke2.png +0 -0
  2637. psychopy/tests/data/textbox_uax14_colors_tyke3.png +0 -0
  2638. psychopy/tests/data/textbox_uax14_cutoff_top.png +0 -0
  2639. psychopy/tests/data/textbox_uax14_exemplar_1.png +0 -0
  2640. psychopy/tests/data/textbox_uax14_exemplar_2.png +0 -0
  2641. psychopy/tests/data/textbox_uax14_exemplar_3.png +0 -0
  2642. psychopy/tests/data/textbox_uax14_exemplar_4.png +0 -0
  2643. psychopy/tests/data/textbox_uax14_tyke_1.png +0 -0
  2644. psychopy/tests/data/textbox_uax14_tyke_2.png +0 -0
  2645. psychopy/tests/data/trialTypes.csv +1 -0
  2646. psychopy/tests/data/trialTypes.docx +0 -0
  2647. psychopy/tests/data/trialTypes.pkl +0 -0
  2648. psychopy/tests/data/trialTypes.tsv +7 -0
  2649. psychopy/tests/data/trialTypes.xls +0 -0
  2650. psychopy/tests/data/trialTypes.xlsx +0 -0
  2651. psychopy/tests/data/trialTypes_eu.csv +7 -0
  2652. psychopy/tests/data/trialsBlankCols.xlsx +0 -0
  2653. psychopy/tests/data/wedge1_cm.png +0 -0
  2654. psychopy/tests/data/wedge1_deg.png +0 -0
  2655. psychopy/tests/data/wedge1_degFlat.png +0 -0
  2656. psychopy/tests/data/wedge1_degFlatPos.png +0 -0
  2657. psychopy/tests/data/wedge1_height.png +0 -0
  2658. psychopy/tests/data/wedge1_norm.png +0 -0
  2659. psychopy/tests/data/wedge1_normAddBlend.png +0 -0
  2660. psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
  2661. psychopy/tests/data/wedge1_normHexbackground.png +0 -0
  2662. psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
  2663. psychopy/tests/data/wedge1_normNoShade.png +0 -0
  2664. psychopy/tests/data/wedge1_norm_local.png +0 -0
  2665. psychopy/tests/data/wedge1_pix.png +0 -0
  2666. psychopy/tests/data/wedge1_stencil.png +0 -0
  2667. psychopy/tests/data/wedge2_cm.png +0 -0
  2668. psychopy/tests/data/wedge2_deg.png +0 -0
  2669. psychopy/tests/data/wedge2_degFlat.png +0 -0
  2670. psychopy/tests/data/wedge2_degFlatPos.png +0 -0
  2671. psychopy/tests/data/wedge2_height.png +0 -0
  2672. psychopy/tests/data/wedge2_norm.png +0 -0
  2673. psychopy/tests/data/wedge2_normAddBlend.png +0 -0
  2674. psychopy/tests/data/wedge2_normHexbackground.png +0 -0
  2675. psychopy/tests/data/wedge2_normNoShade.png +0 -0
  2676. psychopy/tests/data/wedge2_pix.png +0 -0
  2677. psychopy/tests/data/wedge2_stencil.png +0 -0
  2678. psychopy/tests/data/winScalePos_ori0_scale-1_-1_pos-0.4_0.png +0 -0
  2679. psychopy/tests/data/winScalePos_ori0_scale-1_-1_pos0_0.png +0 -0
  2680. psychopy/tests/data/winScalePos_ori0_scale-1_1_pos-0.4_0.png +0 -0
  2681. psychopy/tests/data/winScalePos_ori0_scale-1_1_pos0_0.png +0 -0
  2682. psychopy/tests/data/winScalePos_ori0_scale-2_-2_pos-0.4_0.png +0 -0
  2683. psychopy/tests/data/winScalePos_ori0_scale-2_-2_pos0_0.png +0 -0
  2684. psychopy/tests/data/winScalePos_ori0_scale-2_2_pos-0.4_0.png +0 -0
  2685. psychopy/tests/data/winScalePos_ori0_scale-2_2_pos0_0.png +0 -0
  2686. psychopy/tests/data/winScalePos_ori0_scale1_-1_pos-0.4_0.png +0 -0
  2687. psychopy/tests/data/winScalePos_ori0_scale1_-1_pos0_0.png +0 -0
  2688. psychopy/tests/data/winScalePos_ori0_scale1_1_pos-0.4_0.png +0 -0
  2689. psychopy/tests/data/winScalePos_ori0_scale1_1_pos0_0.png +0 -0
  2690. psychopy/tests/data/winScalePos_ori0_scale2_-2_pos-0.4_0.png +0 -0
  2691. psychopy/tests/data/winScalePos_ori0_scale2_-2_pos0_0.png +0 -0
  2692. psychopy/tests/data/winScalePos_ori0_scale2_2_pos-0.4_0.png +0 -0
  2693. psychopy/tests/data/winScalePos_ori0_scale2_2_pos0_0.png +0 -0
  2694. psychopy/tests/data/winScalePos_ori45_scale-1_-1_pos0_0.png +0 -0
  2695. psychopy/tests/data/winScalePos_ori45_scale-1_1_pos0_0.png +0 -0
  2696. psychopy/tests/data/winScalePos_ori45_scale-2_-2_pos0_0.png +0 -0
  2697. psychopy/tests/data/winScalePos_ori45_scale-2_2_pos0_0.png +0 -0
  2698. psychopy/tests/data/winScalePos_ori45_scale1_-1_pos0_0.png +0 -0
  2699. psychopy/tests/data/winScalePos_ori45_scale1_1_pos0_0.png +0 -0
  2700. psychopy/tests/data/winScalePos_ori45_scale2_-2_pos0_0.png +0 -0
  2701. psychopy/tests/data/winScalePos_ori45_scale2_2_pos0_0.png +0 -0
  2702. psychopy/tests/doc/run_btn.png +0 -0
  2703. psychopy/tests/doc/test-suite-bugs.jpg +0 -0
  2704. psychopy/tests/doc/user-bugs.jpg +0 -0
  2705. psychopy/tests/dummy_xorg.conf +21 -0
  2706. psychopy/tests/run.py +50 -0
  2707. psychopy/tests/test_Installation.py +38 -0
  2708. psychopy/tests/test_alerts/test_alerts.py +37 -0
  2709. psychopy/tests/test_alerts/test_alerttools.py +131 -0
  2710. psychopy/tests/test_app/__init__.py +0 -0
  2711. psychopy/tests/test_app/conftest.py +41 -0
  2712. psychopy/tests/test_app/test_builder/__init__.py +0 -0
  2713. psychopy/tests/test_app/test_builder/test_BuilderFrame.py +151 -0
  2714. psychopy/tests/test_app/test_builder/test_CompileFromBuilder.py +135 -0
  2715. psychopy/tests/test_app/test_builder/test_ComponentDialogs.py +98 -0
  2716. psychopy/tests/test_app/test_runner/__init__.py +0 -0
  2717. psychopy/tests/test_app/test_runner/test_RunnerFrame.py +166 -0
  2718. psychopy/tests/test_app/test_speed.py +144 -0
  2719. psychopy/tests/test_app/test_themes/test_icons.py +79 -0
  2720. psychopy/tests/test_codecov.py +29 -0
  2721. psychopy/tests/test_colors/test_Color.py +41 -0
  2722. psychopy/tests/test_data/dataPrev.xlsx +0 -0
  2723. psychopy/tests/test_data/test_ExperimentHandler.py +171 -0
  2724. psychopy/tests/test_data/test_MultiStairHandler.py +174 -0
  2725. psychopy/tests/test_data/test_StairHandlers.py +1241 -0
  2726. psychopy/tests/test_data/test_TrialHandler.py +335 -0
  2727. psychopy/tests/test_data/test_TrialHandler2.py +408 -0
  2728. psychopy/tests/test_data/test_TrialHandlerExt.py +359 -0
  2729. psychopy/tests/test_data/test_fitFunctions.py +101 -0
  2730. psychopy/tests/test_data/test_utils.py +169 -0
  2731. psychopy/tests/test_data/test_xlsx.py +92 -0
  2732. psychopy/tests/test_demos/test_builder_demos.py +52 -0
  2733. psychopy/tests/test_experiment/__init__.py +0 -0
  2734. psychopy/tests/test_experiment/known_py_diffs.txt +47 -0
  2735. psychopy/tests/test_experiment/needs_wx/__init__.py +0 -0
  2736. psychopy/tests/test_experiment/needs_wx/componsTemplate.txt +13730 -0
  2737. psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +130 -0
  2738. psychopy/tests/test_experiment/needs_wx/test_Experiment.py +406 -0
  2739. psychopy/tests/test_experiment/needs_wx/test_components.py +170 -0
  2740. psychopy/tests/test_experiment/test_component_compile_js.py +59 -0
  2741. psychopy/tests/test_experiment/test_component_compile_python.py +165 -0
  2742. psychopy/tests/test_experiment/test_components/__init__.py +1 -0
  2743. psychopy/tests/test_experiment/test_components/test_ButtonBox.py +216 -0
  2744. psychopy/tests/test_experiment/test_components/test_Code.py +82 -0
  2745. psychopy/tests/test_experiment/test_components/test_Image.py +24 -0
  2746. psychopy/tests/test_experiment/test_components/test_Mouse.py +149 -0
  2747. psychopy/tests/test_experiment/test_components/test_Polygon.py +81 -0
  2748. psychopy/tests/test_experiment/test_components/test_ResourceManager.py +60 -0
  2749. psychopy/tests/test_experiment/test_components/test_Settings.py +82 -0
  2750. psychopy/tests/test_experiment/test_components/test_Static.py +60 -0
  2751. psychopy/tests/test_experiment/test_components/test_all_components.py +162 -0
  2752. psychopy/tests/test_experiment/test_components/test_base_components.py +323 -0
  2753. psychopy/tests/test_experiment/test_experiment.py +103 -0
  2754. psychopy/tests/test_experiment/test_loops.py +95 -0
  2755. psychopy/tests/test_experiment/test_params.py +350 -0
  2756. psychopy/tests/test_experiment/test_py2js.py +230 -0
  2757. psychopy/tests/test_experiment/test_routines/__init__.py +1 -0
  2758. psychopy/tests/test_experiment/test_routines/test_EyetrackerCalibrationRoutine.py +9 -0
  2759. psychopy/tests/test_experiment/test_routines/test_PhotodiodeValidationRoutine.py +9 -0
  2760. psychopy/tests/test_experiment/test_routines/test_all_routines.py +23 -0
  2761. psychopy/tests/test_experiment/test_routines/test_base_routine.py +154 -0
  2762. psychopy/tests/test_experiment/test_routines/test_standalone_routines.py +36 -0
  2763. psychopy/tests/test_gui/test_DlgFromDictQt.py +82 -0
  2764. psychopy/tests/test_gui/test_DlgFromDictWx.py +82 -0
  2765. psychopy/tests/test_hardware/__init__.py +0 -0
  2766. psychopy/tests/test_hardware/test_CRS_BitsSharp.py +67 -0
  2767. psychopy/tests/test_hardware/test_CRS_bitsShaders.py +110 -0
  2768. psychopy/tests/test_hardware/test_device_manager.py +36 -0
  2769. psychopy/tests/test_hardware/test_emulator.py +106 -0
  2770. psychopy/tests/test_hardware/test_gammasci.py +35 -0
  2771. psychopy/tests/test_hardware/test_keyboard.py +73 -0
  2772. psychopy/tests/test_hardware/test_keyboard_events.py +362 -0
  2773. psychopy/tests/test_hardware/test_ports.py +151 -0
  2774. psychopy/tests/test_iohub/__init__.py +1 -0
  2775. psychopy/tests/test_iohub/test_computer.py +124 -0
  2776. psychopy/tests/test_iohub/test_event_get_and_clear.py +94 -0
  2777. psychopy/tests/test_iohub/test_keyboard.py +91 -0
  2778. psychopy/tests/test_iohub/test_launch.py +19 -0
  2779. psychopy/tests/test_iohub/testutil.py +54 -0
  2780. psychopy/tests/test_liaison/test_Liaison.py +228 -0
  2781. psychopy/tests/test_misc/__init__.py +0 -0
  2782. psychopy/tests/test_misc/memory_usage.py +164 -0
  2783. psychopy/tests/test_misc/test_GammaFun.py +15 -0
  2784. psychopy/tests/test_misc/test_clock.py +61 -0
  2785. psychopy/tests/test_misc/test_color.py +203 -0
  2786. psychopy/tests/test_misc/test_core.py +446 -0
  2787. psychopy/tests/test_misc/test_event.py +307 -0
  2788. psychopy/tests/test_misc/test_info.py +18 -0
  2789. psychopy/tests/test_misc/test_layout.py +49 -0
  2790. psychopy/tests/test_misc/test_locale.py +38 -0
  2791. psychopy/tests/test_misc/test_web.py +22 -0
  2792. psychopy/tests/test_monitors/test_monitors.py +91 -0
  2793. psychopy/tests/test_preferences/__init__.py +0 -0
  2794. psychopy/tests/test_preferences/test_prefs.py +28 -0
  2795. psychopy/tests/test_session/test_Session.py +253 -0
  2796. psychopy/tests/test_sound/__init__.py +0 -0
  2797. psychopy/tests/test_sound/test_audioclip.py +331 -0
  2798. psychopy/tests/test_sound/test_hamming.py +45 -0
  2799. psychopy/tests/test_sound/test_microphone.py +217 -0
  2800. psychopy/tests/test_sound/test_sound.py +67 -0
  2801. psychopy/tests/test_sound/test_sound_pygame.py +67 -0
  2802. psychopy/tests/test_tools/test_animationtools.py +51 -0
  2803. psychopy/tests/test_tools/test_arraytools.py +130 -0
  2804. psychopy/tests/test_tools/test_attributetools.py +257 -0
  2805. psychopy/tests/test_tools/test_colorspacetools.py +149 -0
  2806. psychopy/tests/test_tools/test_environmenttools.py +52 -0
  2807. psychopy/tests/test_tools/test_fileerrortools.py +97 -0
  2808. psychopy/tests/test_tools/test_filetools.py +104 -0
  2809. psychopy/tests/test_tools/test_imagetools.py +57 -0
  2810. psychopy/tests/test_tools/test_mathtools.py +688 -0
  2811. psychopy/tests/test_tools/test_stringtools.py +143 -0
  2812. psychopy/tests/test_tools/test_versionchooser.py +178 -0
  2813. psychopy/tests/test_tools/test_viewtools.py +67 -0
  2814. psychopy/tests/test_visual/__init__.py +0 -0
  2815. psychopy/tests/test_visual/measure_parity.py +243 -0
  2816. psychopy/tests/test_visual/test_all_stimuli.py +752 -0
  2817. psychopy/tests/test_visual/test_basevisual.py +534 -0
  2818. psychopy/tests/test_visual/test_brush.py +68 -0
  2819. psychopy/tests/test_visual/test_button.py +15 -0
  2820. psychopy/tests/test_visual/test_circle.py +66 -0
  2821. psychopy/tests/test_visual/test_contains_overlaps.py +242 -0
  2822. psychopy/tests/test_visual/test_custommouse.py +47 -0
  2823. psychopy/tests/test_visual/test_dots.py +155 -0
  2824. psychopy/tests/test_visual/test_form.py +414 -0
  2825. psychopy/tests/test_visual/test_framepacking.py +41 -0
  2826. psychopy/tests/test_visual/test_gamma.py +152 -0
  2827. psychopy/tests/test_visual/test_glfw_backend.py +14 -0
  2828. psychopy/tests/test_visual/test_image.py +218 -0
  2829. psychopy/tests/test_visual/test_panorama.py +41 -0
  2830. psychopy/tests/test_visual/test_progress.py +96 -0
  2831. psychopy/tests/test_visual/test_projections.py +215 -0
  2832. psychopy/tests/test_visual/test_projections_interactive.py +163 -0
  2833. psychopy/tests/test_visual/test_ratingScale.py +299 -0
  2834. psychopy/tests/test_visual/test_roi.py +99 -0
  2835. psychopy/tests/test_visual/test_shape.py +23 -0
  2836. psychopy/tests/test_visual/test_slider.py +328 -0
  2837. psychopy/tests/test_visual/test_target.py +35 -0
  2838. psychopy/tests/test_visual/test_textbox.py +474 -0
  2839. psychopy/tests/test_visual/test_winFlipTiming.py +95 -0
  2840. psychopy/tests/test_visual/test_winScalePos.py +77 -0
  2841. psychopy/tests/test_visual/test_window.py +107 -0
  2842. psychopy/tests/utils.py +318 -0
  2843. psychopy/tools/LineBreak.txt +3597 -0
  2844. psychopy/tools/__init__.py +9 -0
  2845. psychopy/tools/animationtools.py +49 -0
  2846. psychopy/tools/apptools.py +32 -0
  2847. psychopy/tools/arraytools.py +514 -0
  2848. psychopy/tools/attributetools.py +205 -0
  2849. psychopy/tools/audiotools.py +358 -0
  2850. psychopy/tools/colorspacetools.py +715 -0
  2851. psychopy/tools/coordinatetools.py +104 -0
  2852. psychopy/tools/environmenttools.py +62 -0
  2853. psychopy/tools/fileerrortools.py +54 -0
  2854. psychopy/tools/filetools.py +406 -0
  2855. psychopy/tools/fontmanager.py +1041 -0
  2856. psychopy/tools/gltools.py +4959 -0
  2857. psychopy/tools/imagetools.py +65 -0
  2858. psychopy/tools/linebreak.py +322 -0
  2859. psychopy/tools/mathtools.py +4040 -0
  2860. psychopy/tools/monitorunittools.py +270 -0
  2861. psychopy/tools/movietools.py +1071 -0
  2862. psychopy/tools/pkgtools.py +601 -0
  2863. psychopy/tools/plottools.py +25 -0
  2864. psychopy/tools/rifttools.py +76 -0
  2865. psychopy/tools/stereotools.py +9 -0
  2866. psychopy/tools/stimulustools.py +28 -0
  2867. psychopy/tools/stringtools.py +421 -0
  2868. psychopy/tools/systemtools.py +1331 -0
  2869. psychopy/tools/typetools.py +52 -0
  2870. psychopy/tools/unittools.py +16 -0
  2871. psychopy/tools/versionchooser.py +602 -0
  2872. psychopy/tools/viewtools.py +1084 -0
  2873. psychopy/tools/wizard.py +804 -0
  2874. psychopy/visual/__init__.py +124 -0
  2875. psychopy/visual/aperture.py +330 -0
  2876. psychopy/visual/backends/__init__.py +77 -0
  2877. psychopy/visual/backends/_base.py +481 -0
  2878. psychopy/visual/backends/gamma.py +349 -0
  2879. psychopy/visual/backends/glfwbackend.py +28 -0
  2880. psychopy/visual/backends/pygamebackend.py +343 -0
  2881. psychopy/visual/backends/pygletbackend.py +920 -0
  2882. psychopy/visual/basevisual.py +1952 -0
  2883. psychopy/visual/brush.py +204 -0
  2884. psychopy/visual/bufferimage.py +231 -0
  2885. psychopy/visual/button.py +206 -0
  2886. psychopy/visual/circle.py +173 -0
  2887. psychopy/visual/custommouse.py +263 -0
  2888. psychopy/visual/dot.py +668 -0
  2889. psychopy/visual/dropdown.py +165 -0
  2890. psychopy/visual/elementarray.py +728 -0
  2891. psychopy/visual/filters.py +419 -0
  2892. psychopy/visual/form.py +1180 -0
  2893. psychopy/visual/globalVars.py +24 -0
  2894. psychopy/visual/grating.py +501 -0
  2895. psychopy/visual/helpers.py +334 -0
  2896. psychopy/visual/image.py +440 -0
  2897. psychopy/visual/line.py +238 -0
  2898. psychopy/visual/movie.py +12 -0
  2899. psychopy/visual/movie2.py +829 -0
  2900. psychopy/visual/movie3.py +599 -0
  2901. psychopy/visual/movies/__init__.py +850 -0
  2902. psychopy/visual/movies/frame.py +255 -0
  2903. psychopy/visual/movies/metadata.py +242 -0
  2904. psychopy/visual/movies/players/__init__.py +62 -0
  2905. psychopy/visual/movies/players/_base.py +364 -0
  2906. psychopy/visual/movies/players/ffpyplayer_player.py +1399 -0
  2907. psychopy/visual/nnlvs.py +827 -0
  2908. psychopy/visual/noise.py +34 -0
  2909. psychopy/visual/panorama.py +313 -0
  2910. psychopy/visual/patch.py +29 -0
  2911. psychopy/visual/pie.py +248 -0
  2912. psychopy/visual/polygon.py +229 -0
  2913. psychopy/visual/progress.py +313 -0
  2914. psychopy/visual/radial.py +33 -0
  2915. psychopy/visual/ratingscale.py +1424 -0
  2916. psychopy/visual/rect.py +204 -0
  2917. psychopy/visual/rift.py +2654 -0
  2918. psychopy/visual/roi.py +141 -0
  2919. psychopy/visual/secondorder.py +29 -0
  2920. psychopy/visual/shaders.py +453 -0
  2921. psychopy/visual/shape.py +701 -0
  2922. psychopy/visual/simpleimage.py +303 -0
  2923. psychopy/visual/slider.py +1169 -0
  2924. psychopy/visual/stim3d.py +2712 -0
  2925. psychopy/visual/target.py +278 -0
  2926. psychopy/visual/text.py +759 -0
  2927. psychopy/visual/textbox/__init__.py +1280 -0
  2928. psychopy/visual/textbox/fontmanager.py +574 -0
  2929. psychopy/visual/textbox/parsedtext.py +317 -0
  2930. psychopy/visual/textbox/textgrid.py +278 -0
  2931. psychopy/visual/textbox/textureatlas.py +248 -0
  2932. psychopy/visual/textbox2/__init__.py +4 -0
  2933. psychopy/visual/textbox2/textbox2.py +1817 -0
  2934. psychopy/visual/vlcmoviestim.py +1294 -0
  2935. psychopy/visual/window.py +3706 -0
  2936. psychopy/visual/windowframepack.py +86 -0
  2937. psychopy/visual/windowwarp.py +457 -0
  2938. psychopy/voicekey/__init__.py +684 -0
  2939. psychopy/voicekey/demo_vks.py +12 -0
  2940. psychopy/voicekey/labjack_vks.py +50 -0
  2941. psychopy/voicekey/parallel_vks.py +44 -0
  2942. psychopy/voicekey/signal.py +42 -0
  2943. psychopy/voicekey/vk_tools.py +280 -0
  2944. psychopy/web.py +286 -0
  2945. psychopy-2024.1.0.dist-info/METADATA +154 -0
  2946. psychopy-2024.1.0.dist-info/RECORD +2950 -0
  2947. psychopy-2024.1.0.dist-info/WHEEL +4 -0
  2948. psychopy-2024.1.0.dist-info/entry_points.txt +3 -0
  2949. psychopy-2024.1.0.dist-info/licenses/AUTHORS.md +138 -0
  2950. psychopy-2024.1.0.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,4040 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Various math functions for working with vectors, matrices, and quaternions.
5
+ #
6
+
7
+ # Part of the PsychoPy library
8
+ # Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2024 Open Science Tools Ltd.
9
+ # Distributed under the terms of the GNU General Public License (GPL).
10
+
11
+ __all__ = ['normalize',
12
+ 'lerp',
13
+ 'slerp',
14
+ 'multQuat',
15
+ 'quatFromAxisAngle',
16
+ 'quatToMatrix',
17
+ 'scaleMatrix',
18
+ 'rotationMatrix',
19
+ 'transform',
20
+ 'translationMatrix',
21
+ 'concatenate',
22
+ 'applyMatrix',
23
+ 'invertQuat',
24
+ 'quatToAxisAngle',
25
+ 'posOriToMatrix',
26
+ 'applyQuat',
27
+ 'orthogonalize',
28
+ 'reflect',
29
+ 'cross',
30
+ 'distance',
31
+ 'dot',
32
+ 'quatMagnitude',
33
+ 'length',
34
+ 'project',
35
+ 'bisector',
36
+ 'surfaceNormal',
37
+ 'invertMatrix',
38
+ 'angleTo',
39
+ 'surfaceBitangent',
40
+ 'surfaceTangent',
41
+ 'vertexNormal',
42
+ 'isOrthogonal',
43
+ 'isAffine',
44
+ 'perp',
45
+ 'ortho3Dto2D',
46
+ 'intersectRayPlane',
47
+ 'matrixToQuat',
48
+ 'lensCorrection',
49
+ 'matrixFromEulerAngles',
50
+ 'alignTo',
51
+ 'quatYawPitchRoll',
52
+ 'intersectRaySphere',
53
+ 'intersectRayAABB',
54
+ 'intersectRayOBB',
55
+ 'intersectRayTriangle',
56
+ 'scale',
57
+ 'multMatrix',
58
+ 'normalMatrix',
59
+ 'fitBBox',
60
+ 'computeBBoxCorners',
61
+ 'zeroFix',
62
+ 'accumQuat',
63
+ 'fixTangentHandedness',
64
+ 'articulate',
65
+ 'forwardProject',
66
+ 'reverseProject',
67
+ 'lensCorrectionSpherical']
68
+
69
+
70
+ import numpy as np
71
+ import functools
72
+ import itertools
73
+
74
+
75
+ VEC_AXES = {'+x': (1, 0, 0), '-x': (-1, 0, 0),
76
+ '+y': (0, 1, 0), '-y': (0, -1, 0),
77
+ '+z': (0, 0, 1), '-z': (0, 0, -1)}
78
+
79
+
80
+ # ------------------------------------------------------------------------------
81
+ # Vector Operations
82
+ #
83
+
84
+ def length(v, squared=False, out=None, dtype=None):
85
+ """Get the length of a vector.
86
+
87
+ Parameters
88
+ ----------
89
+ v : array_like
90
+ Vector to normalize, can be Nx2, Nx3, or Nx4. If a 2D array is
91
+ specified, rows are treated as separate vectors.
92
+ squared : bool, optional
93
+ If ``True`` the squared length is returned. The default is ``False``.
94
+ out : ndarray, optional
95
+ Optional output array. Must be same `shape` and `dtype` as the expected
96
+ output if `out` was not specified.
97
+ dtype : dtype or str, optional
98
+ Data type for computations can either be 'float32' or 'float64'. If
99
+ `out` is specified, the data type of `out` is used and this argument is
100
+ ignored. If `out` is not provided, 'float64' is used by default.
101
+
102
+ Returns
103
+ -------
104
+ float or ndarray
105
+ Length of vector `v`.
106
+
107
+ """
108
+ if out is None:
109
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
110
+ else:
111
+ dtype = np.dtype(out.dtype).type
112
+
113
+ v = np.asarray(v, dtype=dtype)
114
+
115
+ if v.ndim == 2:
116
+ assert v.shape[1] <= 4
117
+ toReturn = np.zeros((v.shape[0],), dtype=dtype) if out is None else out
118
+ v2d, vr = np.atleast_2d(v, toReturn) # 2d view of array
119
+ if squared:
120
+ vr[:, :] = np.sum(np.square(v2d), axis=1)
121
+ else:
122
+ vr[:, :] = np.sqrt(np.sum(np.square(v2d), axis=1))
123
+ elif v.ndim == 1:
124
+ assert v.shape[0] <= 4
125
+ if squared:
126
+ toReturn = np.sum(np.square(v))
127
+ else:
128
+ toReturn = np.sqrt(np.sum(np.square(v)))
129
+ else:
130
+ raise ValueError("Input arguments have invalid dimensions.")
131
+
132
+ return toReturn
133
+
134
+
135
+ def normalize(v, out=None, dtype=None):
136
+ """Normalize a vector or quaternion.
137
+
138
+ v : array_like
139
+ Vector to normalize, can be Nx2, Nx3, or Nx4. If a 2D array is
140
+ specified, rows are treated as separate vectors. All vectors should have
141
+ nonzero length.
142
+ out : ndarray, optional
143
+ Optional output array. Must be same `shape` and `dtype` as the expected
144
+ output if `out` was not specified.
145
+ dtype : dtype or str, optional
146
+ Data type for computations can either be 'float32' or 'float64'. If
147
+ `out` is specified, the data type of `out` is used and this argument is
148
+ ignored. If `out` is not provided, 'float64' is used by default.
149
+
150
+ Returns
151
+ -------
152
+ ndarray
153
+ Normalized vector `v`.
154
+
155
+ Notes
156
+ -----
157
+ * If the vector has length is zero, a vector of all zeros is returned after
158
+ normalization.
159
+
160
+ Examples
161
+ --------
162
+ Normalize a vector::
163
+
164
+ v = [1., 2., 3., 4.]
165
+ vn = normalize(v)
166
+
167
+ The `normalize` function is vectorized. It's considerably faster to
168
+ normalize large arrays of vectors than to call `normalize` separately for
169
+ each one::
170
+
171
+ v = np.random.uniform(-1.0, 1.0, (1000, 4,)) # 1000 length 4 vectors
172
+ vn = np.zeros((1000, 4)) # place to write values
173
+ normalize(v, out=vn) # very fast!
174
+
175
+ # don't do this!
176
+ for i in range(1000):
177
+ vn[i, :] = normalize(v[i, :])
178
+
179
+ """
180
+ if out is None:
181
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
182
+ toReturn = np.array(v, dtype=dtype)
183
+ else:
184
+ toReturn = out
185
+
186
+ v2d = np.atleast_2d(toReturn) # 2d view of array
187
+ norm = np.linalg.norm(v2d, axis=1)
188
+ norm[norm == 0.0] = np.NaN # make sure if length==0 division succeeds
189
+ v2d /= norm[:, np.newaxis]
190
+ np.nan_to_num(v2d, copy=False) # fix NaNs
191
+
192
+ return toReturn
193
+
194
+
195
+ def orthogonalize(v, n, out=None, dtype=None):
196
+ """Orthogonalize a vector relative to a normal vector.
197
+
198
+ This function ensures that `v` is perpendicular (or orthogonal) to `n`.
199
+
200
+ Parameters
201
+ ----------
202
+ v : array_like
203
+ Vector to orthogonalize, can be Nx2, Nx3, or Nx4. If a 2D array is
204
+ specified, rows are treated as separate vectors.
205
+ n : array_like
206
+ Normal vector, must have same shape as `v`.
207
+ out : ndarray, optional
208
+ Optional output array. Must be same `shape` and `dtype` as the expected
209
+ output if `out` was not specified.
210
+ dtype : dtype or str, optional
211
+ Data type for computations can either be 'float32' or 'float64'. If
212
+ `out` is specified, the data type of `out` is used and this argument is
213
+ ignored. If `out` is not provided, 'float64' is used by default.
214
+
215
+ Returns
216
+ -------
217
+ ndarray
218
+ Orthogonalized vector `v` relative to normal vector `n`.
219
+
220
+ Warnings
221
+ --------
222
+ If `v` and `n` are the same, the direction of the perpendicular vector is
223
+ indeterminate. The resulting vector is degenerate (all zeros).
224
+
225
+ """
226
+ if out is None:
227
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
228
+ else:
229
+ dtype = np.dtype(out.dtype).type
230
+
231
+ v = np.asarray(v, dtype=dtype)
232
+ n = np.asarray(n, dtype=dtype)
233
+
234
+ if out is None:
235
+ toReturn = np.zeros_like(v, dtype=dtype)
236
+ else:
237
+ toReturn = out
238
+ toReturn.fill(0.0)
239
+
240
+ v, n, vr = np.atleast_2d(v, n, toReturn)
241
+ vr[:, :] = v
242
+ vr[:, :] -= n * np.sum(n * v, axis=1)[:, np.newaxis] # dot product
243
+ normalize(vr, out=vr)
244
+
245
+ return toReturn
246
+
247
+
248
+ def reflect(v, n, out=None, dtype=None):
249
+ """Reflection of a vector.
250
+
251
+ Get the reflection of `v` relative to normal `n`.
252
+
253
+ Parameters
254
+ ----------
255
+ v : array_like
256
+ Vector to reflect, can be Nx2, Nx3, or Nx4. If a 2D array is specified,
257
+ rows are treated as separate vectors.
258
+ n : array_like
259
+ Normal vector, must have same shape as `v`.
260
+ out : ndarray, optional
261
+ Optional output array. Must be same `shape` and `dtype` as the expected
262
+ output if `out` was not specified.
263
+ dtype : dtype or str, optional
264
+ Data type for computations can either be 'float32' or 'float64'. If
265
+ `out` is specified, the data type of `out` is used and this argument is
266
+ ignored. If `out` is not provided, 'float64' is used by default.
267
+
268
+ Returns
269
+ -------
270
+ ndarray
271
+ Reflected vector `v` off normal `n`.
272
+
273
+ """
274
+ # based off https://github.com/glfw/glfw/blob/master/deps/linmath.h
275
+ if out is None:
276
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
277
+ else:
278
+ dtype = np.dtype(out.dtype).type
279
+
280
+ v = np.asarray(v, dtype=dtype)
281
+ n = np.asarray(n, dtype=dtype)
282
+
283
+ if out is None:
284
+ toReturn = np.zeros_like(v, dtype=dtype)
285
+ else:
286
+ toReturn = out
287
+ toReturn.fill(0.0)
288
+
289
+ v, n, vr = np.atleast_2d(v, n, toReturn)
290
+
291
+ vr[:, :] = v
292
+ vr[:, :] -= (dtype(2.0) * np.sum(n * v, axis=1))[:, np.newaxis] * n
293
+
294
+ return toReturn
295
+
296
+
297
+ def dot(v0, v1, out=None, dtype=None):
298
+ """Dot product of two vectors.
299
+
300
+ The behaviour of this function depends on the format of the input arguments:
301
+
302
+ * If `v0` and `v1` are 1D, the dot product is returned as a scalar and `out`
303
+ is ignored.
304
+ * If `v0` and `v1` are 2D, a 1D array of dot products between corresponding
305
+ row vectors are returned.
306
+ * If either `v0` and `v1` are 1D and 2D, an array of dot products
307
+ between each row of the 2D vector and the 1D vector are returned.
308
+
309
+ Parameters
310
+ ----------
311
+ v0, v1 : array_like
312
+ Vector(s) to compute dot products of (e.g. [x, y, z]). `v0` must have
313
+ equal or fewer dimensions than `v1`.
314
+ out : ndarray, optional
315
+ Optional output array. Must be same `shape` and `dtype` as the expected
316
+ output if `out` was not specified.
317
+ dtype : dtype or str, optional
318
+ Data type for computations can either be 'float32' or 'float64'. If
319
+ `out` is specified, the data type of `out` is used and this argument is
320
+ ignored. If `out` is not provided, 'float64' is used by default.
321
+
322
+ Returns
323
+ -------
324
+ ndarray
325
+ Dot product(s) of `v0` and `v1`.
326
+
327
+ """
328
+ if out is None:
329
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
330
+ else:
331
+ dtype = np.dtype(out.dtype).type
332
+
333
+ v0 = np.asarray(v0, dtype=dtype)
334
+ v1 = np.asarray(v1, dtype=dtype)
335
+
336
+ if v0.ndim == v1.ndim == 2 or v0.ndim == 2 and v1.ndim == 1:
337
+ toReturn = np.zeros((v0.shape[0],), dtype=dtype) if out is None else out
338
+ vr = np.atleast_2d(toReturn) # make sure we have a 2d view
339
+ vr[:] = np.sum(v1 * v0, axis=1)
340
+ elif v0.ndim == v1.ndim == 1:
341
+ toReturn = np.sum(v1 * v0)
342
+ elif v0.ndim == 1 and v1.ndim == 2:
343
+ toReturn = np.zeros((v1.shape[0],), dtype=dtype) if out is None else out
344
+ vr = np.atleast_2d(toReturn) # make sure we have a 2d view
345
+ vr[:] = np.sum(v1 * v0, axis=1)
346
+ else:
347
+ raise ValueError("Input arguments have invalid dimensions.")
348
+
349
+ return toReturn
350
+
351
+
352
+ def cross(v0, v1, out=None, dtype=None):
353
+ """Cross product of 3D vectors.
354
+
355
+ The behavior of this function depends on the dimensions of the inputs:
356
+
357
+ * If `v0` and `v1` are 1D, the cross product is returned as 1D vector.
358
+ * If `v0` and `v1` are 2D, a 2D array of cross products between
359
+ corresponding row vectors are returned.
360
+ * If either `v0` and `v1` are 1D and 2D, an array of cross products
361
+ between each row of the 2D vector and the 1D vector are returned.
362
+
363
+ Parameters
364
+ ----------
365
+ v0, v1 : array_like
366
+ Vector(s) in form [x, y, z] or [x, y, z, 1].
367
+ out : ndarray, optional
368
+ Optional output array. Must be same `shape` and `dtype` as the expected
369
+ output if `out` was not specified.
370
+ dtype : dtype or str, optional
371
+ Data type for computations can either be 'float32' or 'float64'. If
372
+ `out` is specified, the data type of `out` is used and this argument is
373
+ ignored. If `out` is not provided, 'float64' is used by default.
374
+
375
+ Returns
376
+ -------
377
+ ndarray
378
+ Cross product of `v0` and `v1`.
379
+
380
+ Notes
381
+ -----
382
+ * If input vectors are 4D, the last value of cross product vectors is always
383
+ set to one.
384
+ * If input vectors `v0` and `v1` are Nx3 and `out` is Nx4, the cross product
385
+ is computed and the last column of `out` is filled with ones.
386
+
387
+ Examples
388
+ --------
389
+
390
+ Find the cross product of two vectors::
391
+
392
+ a = normalize([1, 2, 3])
393
+ b = normalize([3, 2, 1])
394
+ c = cross(a, b)
395
+
396
+ If input arguments are 2D, the function returns the cross products of
397
+ corresponding rows::
398
+
399
+ # create two 6x3 arrays with random numbers
400
+ shape = (6, 3,)
401
+ a = normalize(np.random.uniform(-1.0, 1.0, shape))
402
+ b = normalize(np.random.uniform(-1.0, 1.0, shape))
403
+ cprod = np.zeros(shape) # output has the same shape as inputs
404
+ cross(a, b, out=cprod)
405
+
406
+ If a 1D and 2D vector are specified, the cross product of each row of the
407
+ 2D array and the 1D array is returned as a 2D array::
408
+
409
+ a = normalize([1, 2, 3])
410
+ b = normalize(np.random.uniform(-1.0, 1.0, (6, 3,)))
411
+ cprod = np.zeros(a.shape)
412
+ cross(a, b, out=cprod)
413
+
414
+ """
415
+ if out is None:
416
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
417
+ else:
418
+ dtype = np.dtype(out.dtype).type
419
+
420
+ v0 = np.asarray(v0, dtype=dtype)
421
+ v1 = np.asarray(v1, dtype=dtype)
422
+
423
+ if v0.ndim == v1.ndim == 2: # 2D x 2D
424
+ assert v0.shape == v1.shape
425
+ toReturn = np.zeros(v0.shape, dtype=dtype) if out is None else out
426
+ vr = np.atleast_2d(toReturn)
427
+ vr[:, 0] = v0[:, 1] * v1[:, 2] - v0[:, 2] * v1[:, 1]
428
+ vr[:, 1] = v0[:, 2] * v1[:, 0] - v0[:, 0] * v1[:, 2]
429
+ vr[:, 2] = v0[:, 0] * v1[:, 1] - v0[:, 1] * v1[:, 0]
430
+
431
+ if vr.shape[1] == 4:
432
+ vr[:, 3] = dtype(1.0)
433
+
434
+ elif v0.ndim == v1.ndim == 1: # 1D x 1D
435
+ assert v0.shape == v1.shape
436
+ toReturn = np.zeros(v0.shape, dtype=dtype) if out is None else out
437
+ toReturn[0] = v0[1] * v1[2] - v0[2] * v1[1]
438
+ toReturn[1] = v0[2] * v1[0] - v0[0] * v1[2]
439
+ toReturn[2] = v0[0] * v1[1] - v0[1] * v1[0]
440
+
441
+ if toReturn.shape[0] == 4:
442
+ toReturn[3] = dtype(1.0)
443
+
444
+ elif v0.ndim == 2 and v1.ndim == 1: # 2D x 1D
445
+ toReturn = np.zeros(v0.shape, dtype=dtype) if out is None else out
446
+ vr = np.atleast_2d(toReturn)
447
+ vr[:, 0] = v0[:, 1] * v1[2] - v0[:, 2] * v1[1]
448
+ vr[:, 1] = v0[:, 2] * v1[0] - v0[:, 0] * v1[2]
449
+ vr[:, 2] = v0[:, 0] * v1[1] - v0[:, 1] * v1[0]
450
+
451
+ if vr.shape[1] == 4:
452
+ vr[:, 3] = dtype(1.0)
453
+
454
+ elif v0.ndim == 1 and v1.ndim == 2: # 1D x 2D
455
+ toReturn = np.zeros(v1.shape, dtype=dtype) if out is None else out
456
+ vr = np.atleast_2d(toReturn)
457
+ vr[:, 0] = v1[:, 2] * v0[1] - v1[:, 1] * v0[2]
458
+ vr[:, 1] = v1[:, 0] * v0[2] - v1[:, 2] * v0[0]
459
+ vr[:, 2] = v1[:, 1] * v0[0] - v1[:, 0] * v0[1]
460
+
461
+ if vr.shape[1] == 4:
462
+ vr[:, 3] = dtype(1.0)
463
+
464
+ else:
465
+ raise ValueError("Input arguments have incorrect dimensions.")
466
+
467
+ return toReturn
468
+
469
+
470
+ def project(v0, v1, out=None, dtype=None):
471
+ """Project a vector onto another.
472
+
473
+ Parameters
474
+ ----------
475
+ v0 : array_like
476
+ Vector can be Nx2, Nx3, or Nx4. If a 2D array is specified, rows are
477
+ treated as separate vectors.
478
+ v1 : array_like
479
+ Vector to project onto `v0`.
480
+ out : ndarray, optional
481
+ Optional output array. Must be same `shape` and `dtype` as the expected
482
+ output if `out` was not specified.
483
+ dtype : dtype or str, optional
484
+ Data type for computations can either be 'float32' or 'float64'. If
485
+ `out` is specified, the data type of `out` is used and this argument is
486
+ ignored. If `out` is not provided, 'float64' is used by default.
487
+
488
+ Returns
489
+ -------
490
+ ndarray or float
491
+ Projection of vector `v0` on `v1`.
492
+
493
+ """
494
+ if out is None:
495
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
496
+ else:
497
+ dtype = np.dtype(out.dtype).type
498
+
499
+ v0 = np.asarray(v0, dtype=dtype)
500
+ v1 = np.asarray(v1, dtype=dtype)
501
+
502
+ if v0.ndim == v1.ndim == 2 or v0.ndim == 1 and v1.ndim == 2:
503
+ toReturn = np.zeros_like(v1, dtype=dtype) if out is None else out
504
+ toReturn[:, :] = v1[:, :]
505
+ toReturn *= (dot(v0, v1, dtype=dtype) / length(v1))[:, np.newaxis]
506
+ elif v0.ndim == v1.ndim == 1:
507
+ toReturn = v1 * (dot(v0, v1, dtype=dtype) / np.sum(np.square(v1)))
508
+ elif v0.ndim == 2 and v1.ndim == 1:
509
+ toReturn = np.zeros_like(v0, dtype=dtype) if out is None else out
510
+ toReturn[:, :] = v1[:]
511
+ toReturn *= (dot(v0, v1, dtype=dtype) / length(v1))[:, np.newaxis]
512
+ else:
513
+ raise ValueError("Input arguments have invalid dimensions.")
514
+
515
+ toReturn += 0.0 # remove negative zeros
516
+ return toReturn
517
+
518
+
519
+ def lerp(v0, v1, t, out=None, dtype=None):
520
+ """Linear interpolation (LERP) between two vectors/coordinates.
521
+
522
+ Parameters
523
+ ----------
524
+ v0 : array_like
525
+ Initial vector/coordinate. Can be 2D where each row is a point.
526
+ v1 : array_like
527
+ Final vector/coordinate. Must be the same shape as `v0`.
528
+ t : float
529
+ Interpolation weight factor [0, 1].
530
+ out : ndarray, optional
531
+ Optional output array. Must be same `shape` and `dtype` as the expected
532
+ output if `out` was not specified.
533
+ dtype : dtype or str, optional
534
+ Data type for computations can either be 'float32' or 'float64'. If
535
+ `out` is specified, the data type of `out` is used and this argument is
536
+ ignored. If `out` is not provided, 'float64' is used by default.
537
+
538
+ Returns
539
+ -------
540
+ ndarray
541
+ Vector at `t` with same shape as `v0` and `v1`.
542
+
543
+ Examples
544
+ --------
545
+ Find the coordinate of the midpoint between two vectors::
546
+
547
+ u = [0., 0., 0.]
548
+ v = [0., 0., 1.]
549
+ midpoint = lerp(u, v, 0.5) # 0.5 to interpolate half-way between points
550
+
551
+ """
552
+ if out is None:
553
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
554
+ else:
555
+ dtype = np.dtype(out.dtype).type
556
+
557
+ t = dtype(t)
558
+ t0 = dtype(1.0) - t
559
+ v0 = np.asarray(v0, dtype=dtype)
560
+ v1 = np.asarray(v1, dtype=dtype)
561
+
562
+ toReturn = np.zeros_like(v0, dtype=dtype) if out is None else out
563
+
564
+ v0, v1, vr = np.atleast_2d(v0, v1, toReturn)
565
+ vr[:, :] = v0 * t0
566
+ vr[:, :] += v1 * t
567
+
568
+ return toReturn
569
+
570
+
571
+ def distance(v0, v1, out=None, dtype=None):
572
+ """Get the distance between vectors/coordinates.
573
+
574
+ The behaviour of this function depends on the format of the input arguments:
575
+
576
+ * If `v0` and `v1` are 1D, the distance is returned as a scalar and `out` is
577
+ ignored.
578
+ * If `v0` and `v1` are 2D, an array of distances between corresponding row
579
+ vectors are returned.
580
+ * If either `v0` and `v1` are 1D and 2D, an array of distances
581
+ between each row of the 2D vector and the 1D vector are returned.
582
+
583
+ Parameters
584
+ ----------
585
+ v0, v1 : array_like
586
+ Vectors to compute the distance between.
587
+ out : ndarray, optional
588
+ Optional output array. Must be same `shape` and `dtype` as the expected
589
+ output if `out` was not specified.
590
+ dtype : dtype or str, optional
591
+ Data type for computations can either be 'float32' or 'float64'. If
592
+ `out` is specified, the data type of `out` is used and this argument is
593
+ ignored. If `out` is not provided, 'float64' is used by default.
594
+
595
+ Returns
596
+ -------
597
+ ndarray
598
+ Distance between vectors `v0` and `v1`.
599
+
600
+ """
601
+ if out is None:
602
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
603
+ else:
604
+ dtype = np.dtype(out.dtype).type
605
+
606
+ v0 = np.asarray(v0, dtype=dtype)
607
+ v1 = np.asarray(v1, dtype=dtype)
608
+
609
+ if v0.ndim == v1.ndim == 2 or (v0.ndim == 2 and v1.ndim == 1):
610
+ dist = np.zeros((v1.shape[0],), dtype=dtype) if out is None else out
611
+ dist[:] = np.sqrt(np.sum(np.square(v1 - v0), axis=1))
612
+ elif v0.ndim == v1.ndim == 1:
613
+ dist = np.sqrt(np.sum(np.square(v1 - v0)))
614
+ elif v0.ndim == 1 and v1.ndim == 2:
615
+ dist = np.zeros((v1.shape[0],), dtype=dtype) if out is None else out
616
+ dist[:] = np.sqrt(np.sum(np.square(v0 - v1), axis=1))
617
+ else:
618
+ raise ValueError("Input arguments have invalid dimensions.")
619
+
620
+ return dist
621
+
622
+
623
+ def perp(v, n, norm=True, out=None, dtype=None):
624
+ """Project `v` to be a perpendicular axis of `n`.
625
+
626
+ Parameters
627
+ ----------
628
+ v : array_like
629
+ Vector to project [x, y, z], may be Nx3.
630
+ n : array_like
631
+ Normal vector [x, y, z], may be Nx3.
632
+ norm : bool
633
+ Normalize the resulting axis. Default is `True`.
634
+ out : ndarray, optional
635
+ Optional output array. Must be same `shape` and `dtype` as the expected
636
+ output if `out` was not specified.
637
+ dtype : dtype or str, optional
638
+ Data type for computations can either be 'float32' or 'float64'. If
639
+ `out` is specified, the data type of `out` is used and this argument is
640
+ ignored. If `out` is not provided, 'float64' is used by default.
641
+
642
+ Returns
643
+ -------
644
+ ndarray
645
+ Perpendicular axis of `n` from `v`.
646
+
647
+ Examples
648
+ --------
649
+ Determine the local `up` (y-axis) of a surface or plane given `normal`::
650
+
651
+ normal = [0., 0.70710678, 0.70710678]
652
+ up = [1., 0., 0.]
653
+
654
+ yaxis = perp(up, normal)
655
+
656
+ Do a cross product to get the x-axis perpendicular to both::
657
+
658
+ xaxis = cross(yaxis, normal)
659
+
660
+ """
661
+ if out is None:
662
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
663
+ else:
664
+ dtype = np.dtype(out.dtype).type
665
+
666
+ v = np.asarray(v, dtype=dtype)
667
+ n = np.asarray(n, dtype=dtype)
668
+
669
+ toReturn = np.zeros_like(v, dtype=dtype) if out is None else out
670
+ v2d, n2d, r2d = np.atleast_2d(v, n, toReturn)
671
+
672
+ # from GLM `glm/gtx/perpendicular.inl`
673
+ r2d[:, :] = v2d - project(v2d, n2d, dtype=dtype)
674
+
675
+ if norm:
676
+ normalize(toReturn, out=toReturn)
677
+
678
+ toReturn += 0.0 # clear negative zeros
679
+
680
+ return toReturn
681
+
682
+
683
+ def bisector(v0, v1, norm=False, out=None, dtype=None):
684
+ """Get the angle bisector.
685
+
686
+ Computes a vector which bisects the angle between `v0` and `v1`. Input
687
+ vectors `v0` and `v1` must be non-zero.
688
+
689
+ Parameters
690
+ ----------
691
+ v0, v1 : array_like
692
+ Vectors to bisect [x, y, z]. Must be non-zero in length and have the
693
+ same shape. Inputs can be Nx3 where the bisector for corresponding
694
+ rows will be returned.
695
+ norm : bool, optional
696
+ Normalize the resulting bisector. Default is `False`.
697
+ out : ndarray, optional
698
+ Optional output array. Must be same `shape` and `dtype` as the expected
699
+ output if `out` was not specified.
700
+ dtype : dtype or str, optional
701
+ Data type for computations can either be 'float32' or 'float64'. If
702
+ `out` is specified, the data type of `out` is used and this argument is
703
+ ignored. If `out` is not provided, 'float64' is used by default.
704
+
705
+ Returns
706
+ -------
707
+ ndarray
708
+ Bisecting vector [x, y, z].
709
+
710
+ """
711
+ if out is None:
712
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
713
+ else:
714
+ dtype = np.dtype(out.dtype).type
715
+
716
+ v0 = np.asarray(v0, dtype=dtype)
717
+ v1 = np.asarray(v1, dtype=dtype)
718
+
719
+ assert v0.shape == v1.shape
720
+
721
+ toReturn = np.zeros_like(v0, dtype=dtype) if out is None else out
722
+
723
+ v02d, v12d, r2d = np.atleast_2d(v0, v1, toReturn)
724
+
725
+ r2d[:, :] = v02d * length(v12d, dtype=dtype)[:, np.newaxis] + \
726
+ v12d * length(v02d, dtype=dtype)[:, np.newaxis]
727
+
728
+ if norm:
729
+ normalize(r2d, out=r2d)
730
+
731
+ return toReturn
732
+
733
+
734
+ def angleTo(v, point, degrees=True, out=None, dtype=None):
735
+ """Get the relative angle to a point from a vector.
736
+
737
+ The behaviour of this function depends on the format of the input arguments:
738
+
739
+ * If `v0` and `v1` are 1D, the angle is returned as a scalar and `out` is
740
+ ignored.
741
+ * If `v0` and `v1` are 2D, an array of angles between corresponding row
742
+ vectors are returned.
743
+ * If either `v0` and `v1` are 1D and 2D, an array of angles
744
+ between each row of the 2D vector and the 1D vector are returned.
745
+
746
+ Parameters
747
+ ----------
748
+ v : array_like
749
+ Direction vector [x, y, z].
750
+ point : array_like
751
+ Point(s) to compute angle to from vector `v`.
752
+ degrees : bool, optional
753
+ Return the resulting angles in degrees. If `False`, angles will be
754
+ returned in radians. Default is `True`.
755
+ out : ndarray, optional
756
+ Optional output array. Must be same `shape` and `dtype` as the expected
757
+ output if `out` was not specified.
758
+ dtype : dtype or str, optional
759
+ Data type for computations can either be 'float32' or 'float64'. If
760
+ `out` is specified, the data type of `out` is used and this argument is
761
+ ignored. If `out` is not provided, 'float64' is used by default.
762
+
763
+ Returns
764
+ -------
765
+ ndarray
766
+ Distance between vectors `v0` and `v1`.
767
+
768
+ """
769
+ if out is None:
770
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
771
+ else:
772
+ dtype = np.dtype(out.dtype).type
773
+
774
+ v = np.asarray(v, dtype=dtype)
775
+ point = np.asarray(point, dtype=dtype)
776
+
777
+ if v.ndim == point.ndim == 2 or (v.ndim == 2 and point.ndim == 1):
778
+ angle = np.zeros((v.shape[0],), dtype=dtype) if out is None else out
779
+ u = np.sqrt(length(v, squared=True, dtype=dtype) *
780
+ length(point, squared=True, dtype=dtype))
781
+ angle[:] = np.arccos(dot(v, point, dtype=dtype) / u)
782
+ elif v.ndim == 1 and point.ndim == 2:
783
+ angle = np.zeros((point.shape[0],), dtype=dtype) if out is None else out
784
+ u = np.sqrt(length(v, squared=True, dtype=dtype) *
785
+ length(point, squared=True, dtype=dtype))
786
+ angle[:] = np.arccos(dot(v, point, dtype=dtype) / u)
787
+ elif v.ndim == point.ndim == 1:
788
+ u = np.sqrt(length(v, squared=True, dtype=dtype) *
789
+ length(point, squared=True, dtype=dtype))
790
+ angle = np.arccos(dot(v, point, dtype=dtype) / u)
791
+ else:
792
+ raise ValueError("Input arguments have invalid dimensions.")
793
+
794
+ return np.degrees(angle) if degrees else angle
795
+
796
+
797
+ def sortClockwise(verts):
798
+ """
799
+ Sort vertices clockwise from 12 O'Clock (aka vertex (0, 1)).
800
+
801
+ Parameters
802
+ ==========
803
+ verts : array
804
+ Array of vertices to sort
805
+ """
806
+ # Blank array of angles
807
+ angles = []
808
+ # Calculate angle of each vertex
809
+ for vert in verts:
810
+ # Get angle
811
+ ang = angleTo(v=[0, 1], point=vert)
812
+ # Flip angle if we're past 6 O'clock
813
+ if vert[0] < 0:
814
+ ang = 360 - ang
815
+ # Append to angles array
816
+ angles.append(ang)
817
+ # Sort vertices by angles array values
818
+ verts = [x for _, x in sorted(zip(angles, verts), key=lambda pair: pair[0])]
819
+
820
+ return verts
821
+
822
+
823
+ def surfaceNormal(tri, norm=True, out=None, dtype=None):
824
+ """Compute the surface normal of a given triangle.
825
+
826
+ Parameters
827
+ ----------
828
+ tri : array_like
829
+ Triangle vertices as 2D (3x3) array [p0, p1, p2] where each vertex is a
830
+ length 3 array [vx, xy, vz]. The input array can be 3D (Nx3x3) to
831
+ specify multiple triangles.
832
+ norm : bool, optional
833
+ Normalize computed surface normals if ``True``, default is ``True``.
834
+ out : ndarray, optional
835
+ Optional output array. Must have one fewer dimensions than `tri`. The
836
+ shape of the last dimension must be 3.
837
+ dtype : dtype or str, optional
838
+ Data type for computations can either be 'float32' or 'float64'. If
839
+ `out` is specified, the data type of `out` is used and this argument is
840
+ ignored. If `out` is not provided, 'float64' is used by default.
841
+
842
+ Returns
843
+ -------
844
+ ndarray
845
+ Surface normal of triangle `tri`.
846
+
847
+ Examples
848
+ --------
849
+ Compute the surface normal of a triangle::
850
+
851
+ vertices = [[-1., 0., 0.], [0., 1., 0.], [1, 0, 0]]
852
+ norm = surfaceNormal(vertices)
853
+
854
+ Find the normals for multiple triangles, and put results in a pre-allocated
855
+ array::
856
+
857
+ vertices = [[[-1., 0., 0.], [0., 1., 0.], [1, 0, 0]], # 2x3x3
858
+ [[1., 0., 0.], [0., 1., 0.], [-1, 0, 0]]]
859
+ normals = np.zeros((2, 3)) # normals from two triangles triangles
860
+ surfaceNormal(vertices, out=normals)
861
+
862
+ """
863
+ if out is None:
864
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
865
+ else:
866
+ dtype = np.dtype(out.dtype).type
867
+
868
+ tris = np.asarray(tri, dtype=dtype)
869
+ if tris.ndim == 2:
870
+ tris = np.expand_dims(tri, axis=0)
871
+
872
+ if tris.shape[0] == 1:
873
+ toReturn = np.zeros((3,), dtype=dtype) if out is None else out
874
+ else:
875
+ if out is None:
876
+ toReturn = np.zeros((tris.shape[0], 3), dtype=dtype)
877
+ else:
878
+ toReturn = out
879
+
880
+ # from https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
881
+ nr = np.atleast_2d(toReturn)
882
+ u = tris[:, 1, :] - tris[:, 0, :]
883
+ v = tris[:, 2, :] - tris[:, 1, :]
884
+ nr[:, 0] = u[:, 1] * v[:, 2] - u[:, 2] * v[:, 1]
885
+ nr[:, 1] = u[:, 2] * v[:, 0] - u[:, 0] * v[:, 2]
886
+ nr[:, 2] = u[:, 0] * v[:, 1] - u[:, 1] * v[:, 0]
887
+
888
+ if norm:
889
+ normalize(nr, out=nr)
890
+
891
+ return toReturn
892
+
893
+
894
+ def surfaceBitangent(tri, uv, norm=True, out=None, dtype=None):
895
+ """Compute the bitangent vector of a given triangle.
896
+
897
+ This function can be used to generate bitangent vertex attributes for normal
898
+ mapping. After computing bitangents, one may orthogonalize them with vertex
899
+ normals using the :func:`orthogonalize` function, or within the fragment
900
+ shader. Uses texture coordinates at each triangle vertex to determine the
901
+ direction of the vector.
902
+
903
+ Parameters
904
+ ----------
905
+ tri : array_like
906
+ Triangle vertices as 2D (3x3) array [p0, p1, p2] where each vertex is a
907
+ length 3 array [vx, xy, vz]. The input array can be 3D (Nx3x3) to
908
+ specify multiple triangles.
909
+ uv : array_like
910
+ Texture coordinates associated with each face vertex as a 2D array (3x2)
911
+ where each texture coordinate is length 2 array [u, v]. The input array
912
+ can be 3D (Nx3x2) to specify multiple texture coordinates if multiple
913
+ triangles are specified.
914
+ norm : bool, optional
915
+ Normalize computed bitangents if ``True``, default is ``True``.
916
+ out : ndarray, optional
917
+ Optional output array. Must have one fewer dimensions than `tri`. The
918
+ shape of the last dimension must be 3.
919
+ dtype : dtype or str, optional
920
+ Data type for computations can either be 'float32' or 'float64'. If
921
+ `out` is specified, the data type of `out` is used and this argument is
922
+ ignored. If `out` is not provided, 'float64' is used by default.
923
+
924
+ Returns
925
+ -------
926
+ ndarray
927
+ Surface bitangent of triangle `tri`.
928
+
929
+ Examples
930
+ --------
931
+ Computing the bitangents for two triangles from vertex and texture
932
+ coordinates (UVs)::
933
+
934
+ # array of triangle vertices (2x3x3)
935
+ tri = np.asarray([
936
+ [(-1.0, 1.0, 0.0), (-1.0, -1.0, 0.0), (1.0, -1.0, 0.0)], # 1
937
+ [(-1.0, 1.0, 0.0), (-1.0, -1.0, 0.0), (1.0, -1.0, 0.0)]]) # 2
938
+
939
+ # array of triangle texture coordinates (2x3x2)
940
+ uv = np.asarray([
941
+ [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)], # 1
942
+ [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]]) # 2
943
+
944
+ bitangents = surfaceBitangent(tri, uv, norm=True) # bitangets (2x3)
945
+
946
+ """
947
+ if out is None:
948
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
949
+ else:
950
+ dtype = np.dtype(out.dtype).type
951
+
952
+ tris = np.asarray(tri, dtype=dtype)
953
+ if tris.ndim == 2:
954
+ tris = np.expand_dims(tri, axis=0)
955
+
956
+ if tris.shape[0] == 1:
957
+ toReturn = np.zeros((3,), dtype=dtype) if out is None else out
958
+ else:
959
+ if out is None:
960
+ toReturn = np.zeros((tris.shape[0], 3), dtype=dtype)
961
+ else:
962
+ toReturn = out
963
+
964
+ uvs = np.asarray(uv, dtype=dtype)
965
+ if uvs.ndim == 2:
966
+ uvs = np.expand_dims(uvs, axis=0)
967
+
968
+ # based off the implementation from
969
+ # https://learnopengl.com/Advanced-Lighting/Normal-Mapping
970
+ e1 = tris[:, 1, :] - tris[:, 0, :]
971
+ e2 = tris[:, 2, :] - tris[:, 0, :]
972
+ d1 = uvs[:, 1, :] - uvs[:, 0, :]
973
+ d2 = uvs[:, 2, :] - uvs[:, 0, :]
974
+
975
+ # compute the bitangent
976
+ nr = np.atleast_2d(toReturn)
977
+ nr[:, 0] = -d2[:, 0] * e1[:, 0] + d1[:, 0] * e2[:, 0]
978
+ nr[:, 1] = -d2[:, 0] * e1[:, 1] + d1[:, 0] * e2[:, 1]
979
+ nr[:, 2] = -d2[:, 0] * e1[:, 2] + d1[:, 0] * e2[:, 2]
980
+
981
+ f = dtype(1.0) / (d1[:, 0] * d2[:, 1] - d2[:, 0] * d1[:, 1])
982
+ nr *= f[:, np.newaxis]
983
+
984
+ if norm:
985
+ normalize(toReturn, out=toReturn, dtype=dtype)
986
+
987
+ return toReturn
988
+
989
+
990
+ def surfaceTangent(tri, uv, norm=True, out=None, dtype=None):
991
+ """Compute the tangent vector of a given triangle.
992
+
993
+ This function can be used to generate tangent vertex attributes for normal
994
+ mapping. After computing tangents, one may orthogonalize them with vertex
995
+ normals using the :func:`orthogonalize` function, or within the fragment
996
+ shader. Uses texture coordinates at each triangle vertex to determine the
997
+ direction of the vector.
998
+
999
+ Parameters
1000
+ ----------
1001
+ tri : array_like
1002
+ Triangle vertices as 2D (3x3) array [p0, p1, p2] where each vertex is a
1003
+ length 3 array [vx, xy, vz]. The input array can be 3D (Nx3x3) to
1004
+ specify multiple triangles.
1005
+ uv : array_like
1006
+ Texture coordinates associated with each face vertex as a 2D array (3x2)
1007
+ where each texture coordinate is length 2 array [u, v]. The input array
1008
+ can be 3D (Nx3x2) to specify multiple texture coordinates if multiple
1009
+ triangles are specified. If so `N` must be the same size as the first
1010
+ dimension of `tri`.
1011
+ norm : bool, optional
1012
+ Normalize computed tangents if ``True``, default is ``True``.
1013
+ out : ndarray, optional
1014
+ Optional output array. Must have one fewer dimensions than `tri`. The
1015
+ shape of the last dimension must be 3.
1016
+ dtype : dtype or str, optional
1017
+ Data type for computations can either be 'float32' or 'float64'. If
1018
+ `out` is specified, the data type of `out` is used and this argument is
1019
+ ignored. If `out` is not provided, 'float64' is used by default.
1020
+
1021
+ Returns
1022
+ -------
1023
+ ndarray
1024
+ Surface normal of triangle `tri`.
1025
+
1026
+ Examples
1027
+ --------
1028
+ Compute surface normals, tangents, and bitangents for a list of triangles::
1029
+
1030
+ # triangle vertices (2x3x3)
1031
+ vertices = [[[-1., 0., 0.], [0., 1., 0.], [1, 0, 0]],
1032
+ [[1., 0., 0.], [0., 1., 0.], [-1, 0, 0]]]
1033
+
1034
+ # array of triangle texture coordinates (2x3x2)
1035
+ uv = np.asarray([
1036
+ [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)], # 1
1037
+ [(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]]) # 2
1038
+
1039
+ normals = surfaceNormal(vertices)
1040
+ tangents = surfaceTangent(vertices, uv)
1041
+ bitangents = cross(normals, tangents) # or use `surfaceBitangent`
1042
+
1043
+ Orthogonalize a surface tangent with a vertex normal vector to get the
1044
+ vertex tangent and bitangent vectors::
1045
+
1046
+ vertexTangent = orthogonalize(faceTangent, vertexNormal)
1047
+ vertexBitangent = cross(vertexTangent, vertexNormal)
1048
+
1049
+ Ensure computed vectors have the same handedness, if not, flip the tangent
1050
+ vector (important for applications like normal mapping)::
1051
+
1052
+ # tangent, bitangent, and normal are 2D
1053
+ tangent[dot(cross(normal, tangent), bitangent) < 0.0, :] *= -1.0
1054
+
1055
+ """
1056
+ if out is None:
1057
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1058
+ else:
1059
+ dtype = np.dtype(out.dtype).type
1060
+
1061
+ tris = np.asarray(tri, dtype=dtype)
1062
+ if tris.ndim == 2:
1063
+ tris = np.expand_dims(tri, axis=0)
1064
+
1065
+ if tris.shape[0] == 1:
1066
+ toReturn = np.zeros((3,), dtype=dtype) if out is None else out
1067
+ else:
1068
+ if out is None:
1069
+ toReturn = np.zeros((tris.shape[0], 3), dtype=dtype)
1070
+ else:
1071
+ toReturn = out
1072
+
1073
+ uvs = np.asarray(uv, dtype=dtype)
1074
+ if uvs.ndim == 2:
1075
+ uvs = np.expand_dims(uvs, axis=0)
1076
+
1077
+ # based off the implementation from
1078
+ # https://learnopengl.com/Advanced-Lighting/Normal-Mapping
1079
+ e1 = tris[:, 1, :] - tris[:, 0, :]
1080
+ e2 = tris[:, 2, :] - tris[:, 0, :]
1081
+ d1 = uvs[:, 1, :] - uvs[:, 0, :]
1082
+ d2 = uvs[:, 2, :] - uvs[:, 0, :]
1083
+
1084
+ # compute the bitangent
1085
+ nr = np.atleast_2d(toReturn)
1086
+ nr[:, 0] = d2[:, 1] * e1[:, 0] - d1[:, 1] * e2[:, 0]
1087
+ nr[:, 1] = d2[:, 1] * e1[:, 1] - d1[:, 1] * e2[:, 1]
1088
+ nr[:, 2] = d2[:, 1] * e1[:, 2] - d1[:, 1] * e2[:, 2]
1089
+
1090
+ f = dtype(1.0) / (d1[:, 0] * d2[:, 1] - d2[:, 0] * d1[:, 1])
1091
+ nr *= f[:, np.newaxis]
1092
+
1093
+ if norm:
1094
+ normalize(toReturn, out=toReturn, dtype=dtype)
1095
+
1096
+ return toReturn
1097
+
1098
+
1099
+ def vertexNormal(faceNorms, norm=True, out=None, dtype=None):
1100
+ """Compute a vertex normal from shared triangles.
1101
+
1102
+ This function computes a vertex normal by averaging the surface normals of
1103
+ the triangles it belongs to. If model has no vertex normals, first use
1104
+ :func:`surfaceNormal` to compute them, then run :func:`vertexNormal` to
1105
+ compute vertex normal attributes.
1106
+
1107
+ While this function is mainly used to compute vertex normals, it can also
1108
+ be supplied triangle tangents and bitangents.
1109
+
1110
+ Parameters
1111
+ ----------
1112
+ faceNorms : array_like
1113
+ An array (Nx3) of surface normals.
1114
+ norm : bool, optional
1115
+ Normalize computed normals if ``True``, default is ``True``.
1116
+ out : ndarray, optional
1117
+ Optional output array.
1118
+ dtype : dtype or str, optional
1119
+ Data type for computations can either be 'float32' or 'float64'. If
1120
+ `out` is specified, the data type of `out` is used and this argument is
1121
+ ignored. If `out` is not provided, 'float64' is used by default.
1122
+
1123
+ Returns
1124
+ -------
1125
+ ndarray
1126
+ Vertex normal.
1127
+
1128
+ Examples
1129
+ --------
1130
+ Compute a vertex normal from the face normals of the triangles it belongs
1131
+ to::
1132
+
1133
+ normals = [[1., 0., 0.], [0., 1., 0.]] # adjacent face normals
1134
+ vertexNorm = vertexNormal(normals)
1135
+
1136
+ """
1137
+ if out is None:
1138
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1139
+ else:
1140
+ dtype = np.dtype(out.dtype).type
1141
+
1142
+ triNorms2d = np.atleast_2d(np.asarray(faceNorms, dtype=dtype))
1143
+ nFaces = triNorms2d.shape[0]
1144
+
1145
+ if out is None:
1146
+ toReturn = np.zeros((3,), dtype=dtype)
1147
+ else:
1148
+ toReturn = out
1149
+
1150
+ toReturn[0] = np.sum(triNorms2d[:, 0])
1151
+ toReturn[1] = np.sum(triNorms2d[:, 1])
1152
+ toReturn[2] = np.sum(triNorms2d[:, 2])
1153
+ toReturn /= nFaces
1154
+
1155
+ if norm:
1156
+ normalize(toReturn, out=toReturn, dtype=dtype)
1157
+
1158
+ return toReturn
1159
+
1160
+
1161
+ def fixTangentHandedness(tangents, normals, bitangents, out=None, dtype=None):
1162
+ """Ensure the handedness of tangent vectors are all the same.
1163
+
1164
+ Often 3D computed tangents may not have the same handedness due to how
1165
+ texture coordinates are specified. This function takes input surface vectors
1166
+ are ensures that tangents have the same handedness. Use this function if you
1167
+ notice that normal mapping shading appears reversed with respect to the
1168
+ incident light direction. The output array of corrected tangents can be used
1169
+ inplace of the original.
1170
+
1171
+ Parameters
1172
+ ----------
1173
+ tangents, normals, bitangents : array_like
1174
+ Input Nx3 arrays of triangle tangents, normals and bitangents. All
1175
+ arrays must have the same size.
1176
+ out : ndarray, optional
1177
+ Optional output array for tangents. If not specified, a new array of
1178
+ tangents will be allocated.
1179
+ dtype : dtype or str, optional
1180
+ Data type for computations can either be 'float32' or 'float64'. If
1181
+ `out` is specified, the data type of `out` is used and this argument is
1182
+ ignored. If `out` is not provided, 'float64' is used by default.
1183
+
1184
+ Returns
1185
+ -------
1186
+ ndarray
1187
+ Array of tangents with handedness corrected.
1188
+
1189
+ """
1190
+ if out is None:
1191
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1192
+ else:
1193
+ dtype = np.dtype(out.dtype).type
1194
+
1195
+ tangents = np.asarray(tangents, dtype=dtype)
1196
+ normals = np.asarray(normals, dtype=dtype)
1197
+ bitangents = np.asarray(bitangents, dtype=dtype)
1198
+
1199
+ toReturn = np.zeros_like(tangents, dtype=dtype) if out is None else out
1200
+ toReturn[:, :] = tangents
1201
+ toReturn[dot(cross(normals, tangents, dtype=dtype),
1202
+ bitangents, dtype=dtype) < 0.0, :] *= -1.0
1203
+
1204
+ return toReturn
1205
+
1206
+
1207
+ # ------------------------------------------------------------------------------
1208
+ # Collision Detection, Interaction and Kinematics
1209
+ #
1210
+ def fitBBox(points, dtype=None):
1211
+ """Fit an axis-aligned bounding box around points.
1212
+
1213
+ This computes the minimum and maximum extents for a bounding box to
1214
+ completely enclose `points`. Keep in mind the output in bounds are
1215
+ axis-aligned and may not optimally fits the points (i.e. fits the points
1216
+ with the minimum required volume). However, this should work well enough for
1217
+ applications such as visibility testing (see
1218
+ `~psychopy.tools.viewtools.volumeVisible` for more information..
1219
+
1220
+ Parameters
1221
+ ----------
1222
+ points : array_like
1223
+ Nx3 or Nx4 array of points to fit the bounding box to.
1224
+ dtype : dtype or str, optional
1225
+ Data type for computations can either be 'float32' or 'float64'. If
1226
+ `out` is specified, the data type of `out` is used and this argument is
1227
+ ignored. If `out` is not provided, 'float64' is used by default.
1228
+
1229
+ Returns
1230
+ -------
1231
+ ndarray
1232
+ Extents (mins, maxs) as a 2x3 array.
1233
+
1234
+ See Also
1235
+ --------
1236
+ computeBBoxCorners : Convert bounding box extents to corners.
1237
+
1238
+ """
1239
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1240
+
1241
+ points = np.asarray(points, dtype=dtype)
1242
+ extents = np.zeros((2, 3), dtype=dtype)
1243
+
1244
+ extents[0, :] = (np.min(points[:, 0]),
1245
+ np.min(points[:, 1]),
1246
+ np.min(points[:, 2]))
1247
+ extents[1, :] = (np.max(points[:, 0]),
1248
+ np.max(points[:, 1]),
1249
+ np.max(points[:, 2]))
1250
+
1251
+ return extents
1252
+
1253
+
1254
+ def computeBBoxCorners(extents, dtype=None):
1255
+ """Get the corners of an axis-aligned bounding box.
1256
+
1257
+ Parameters
1258
+ ----------
1259
+ extents : array_like
1260
+ 2x3 array indicating the minimum and maximum extents of the bounding
1261
+ box.
1262
+ dtype : dtype or str, optional
1263
+ Data type for computations can either be 'float32' or 'float64'. If
1264
+ `out` is specified, the data type of `out` is used and this argument is
1265
+ ignored. If `out` is not provided, 'float64' is used by default.
1266
+
1267
+ Returns
1268
+ -------
1269
+ ndarray
1270
+ 8x4 array of points defining the corners of the bounding box.
1271
+
1272
+ Examples
1273
+ --------
1274
+ Compute the corner points of a bounding box::
1275
+
1276
+ minExtent = [-1, -1, -1]
1277
+ maxExtent = [1, 1, 1]
1278
+ corners = computeBBoxCorners([minExtent, maxExtent])
1279
+
1280
+ # [[ 1. 1. 1. 1.]
1281
+ # [-1. 1. 1. 1.]
1282
+ # [ 1. -1. 1. 1.]
1283
+ # [-1. -1. 1. 1.]
1284
+ # [ 1. 1. -1. 1.]
1285
+ # [-1. 1. -1. 1.]
1286
+ # [ 1. -1. -1. 1.]
1287
+ # [-1. -1. -1. 1.]]
1288
+
1289
+ """
1290
+ extents = np.asarray(extents, dtype=dtype)
1291
+
1292
+ assert extents.shape == (2, 3,)
1293
+
1294
+ corners = np.zeros((8, 4), dtype=dtype)
1295
+ idx = np.arange(0, 8)
1296
+ corners[:, 0] = np.where(idx[:] & 1, extents[0, 0], extents[1, 0])
1297
+ corners[:, 1] = np.where(idx[:] & 2, extents[0, 1], extents[1, 1])
1298
+ corners[:, 2] = np.where(idx[:] & 4, extents[0, 2], extents[1, 2])
1299
+ corners[:, 3] = 1.0
1300
+
1301
+ return corners
1302
+
1303
+
1304
+ def intersectRayPlane(rayOrig, rayDir, planeOrig, planeNormal, dtype=None):
1305
+ """Get the point which a ray intersects a plane.
1306
+
1307
+ Parameters
1308
+ ----------
1309
+ rayOrig : array_like
1310
+ Origin of the line in space [x, y, z].
1311
+ rayDir : array_like
1312
+ Direction vector of the line [x, y, z].
1313
+ planeOrig : array_like
1314
+ Origin of the plane to test [x, y, z].
1315
+ planeNormal : array_like
1316
+ Normal vector of the plane [x, y, z].
1317
+ dtype : dtype or str, optional
1318
+ Data type for computations can either be 'float32' or 'float64'. If
1319
+ `out` is specified, the data type of `out` is used and this argument is
1320
+ ignored. If `out` is not provided, 'float64' is used by default.
1321
+
1322
+ Returns
1323
+ -------
1324
+ tuple or None
1325
+ Position (`ndarray`) in space which the line intersects the plane and
1326
+ the distance the intersect occurs from the origin (`float`). `None` is
1327
+ returned if the line does not intersect the plane at a single point or
1328
+ at all.
1329
+
1330
+ Examples
1331
+ --------
1332
+ Find the point in the scene a ray intersects the plane::
1333
+
1334
+ # plane information
1335
+ planeOrigin = [0, 0, 0]
1336
+ planeNormal = [0, 0, 1]
1337
+ planeUpAxis = perp([0, 1, 0], planeNormal)
1338
+
1339
+ # ray
1340
+ rayDir = [0, 0, -1]
1341
+ rayOrigin = [0, 0, 5]
1342
+
1343
+ # get the intersect and distance in 3D world space
1344
+ pnt, dist = intersectRayPlane(rayOrigin, rayDir, planeOrigin, planeNormal)
1345
+
1346
+ """
1347
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1348
+
1349
+ # based off the method from GLM
1350
+ rayOrig = np.asarray(rayOrig, dtype=dtype)
1351
+ rayDir = np.asarray(rayDir, dtype=dtype)
1352
+ planeOrig = np.asarray(planeOrig, dtype=dtype)
1353
+ planeNormal = np.asarray(planeNormal, dtype=dtype)
1354
+
1355
+ denom = dot(rayDir, planeNormal, dtype=dtype)
1356
+ if denom == 0.0:
1357
+ return None
1358
+
1359
+ # distance to collision
1360
+ dist = dot((planeOrig - rayOrig), planeNormal, dtype=dtype) / denom
1361
+ intersect = dist * rayDir + rayOrig
1362
+
1363
+ return intersect, dist
1364
+
1365
+
1366
+ def intersectRaySphere(rayOrig, rayDir, sphereOrig=(0., 0., 0.), sphereRadius=1.0,
1367
+ dtype=None):
1368
+ """Calculate the points which a ray/line intersects a sphere (if any).
1369
+
1370
+ Get the 3D coordinate of the point which the ray intersects the sphere and
1371
+ the distance to the point from `orig`. The nearest point is returned if
1372
+ the line intersects the sphere at multiple locations. All coordinates should
1373
+ be in world/scene units.
1374
+
1375
+ Parameters
1376
+ ----------
1377
+ rayOrig : array_like
1378
+ Origin of the ray in space [x, y, z].
1379
+ rayDir : array_like
1380
+ Direction vector of the ray [x, y, z], should be normalized.
1381
+ sphereOrig : array_like
1382
+ Origin of the sphere to test [x, y, z].
1383
+ sphereRadius : float
1384
+ Sphere radius to test in scene units.
1385
+ dtype : dtype or str, optional
1386
+ Data type for computations can either be 'float32' or 'float64'. If
1387
+ `out` is specified, the data type of `out` is used and this argument is
1388
+ ignored. If `out` is not provided, 'float64' is used by default.
1389
+
1390
+ Returns
1391
+ -------
1392
+ tuple
1393
+ Coordinate in world space of the intersection and distance in scene
1394
+ units from `orig`. Returns `None` if there is no intersection.
1395
+
1396
+ """
1397
+ # based off example from https://antongerdelan.net/opengl/raycasting.html
1398
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1399
+
1400
+ rayOrig = np.asarray(rayOrig, dtype=dtype)
1401
+ rayDir = np.asarray(rayDir, dtype=dtype)
1402
+ sphereOrig = np.asarray(sphereOrig, dtype=dtype)
1403
+ sphereRadius = np.asarray(sphereRadius, dtype=dtype)
1404
+
1405
+ d = rayOrig - sphereOrig
1406
+ b = np.dot(rayDir, d)
1407
+ c = np.dot(d, d) - np.square(sphereRadius)
1408
+ b2mc = np.square(b) - c # determinant
1409
+
1410
+ if b2mc < 0.0: # no roots, ray does not intersect sphere
1411
+ return None
1412
+
1413
+ u = np.sqrt(b2mc)
1414
+ nearestDist = np.minimum(-b + u, -b - u)
1415
+ pos = (rayDir * nearestDist) + rayOrig
1416
+
1417
+ return pos, nearestDist
1418
+
1419
+
1420
+ def intersectRayAABB(rayOrig, rayDir, boundsOffset, boundsExtents, dtype=None):
1421
+ """Find the point a ray intersects an axis-aligned bounding box (AABB).
1422
+
1423
+ Parameters
1424
+ ----------
1425
+ rayOrig : array_like
1426
+ Origin of the ray in space [x, y, z].
1427
+ rayDir : array_like
1428
+ Direction vector of the ray [x, y, z], should be normalized.
1429
+ boundsOffset : array_like
1430
+ Offset of the bounding box in the scene [x, y, z].
1431
+ boundsExtents : array_like
1432
+ Minimum and maximum extents of the bounding box.
1433
+ dtype : dtype or str, optional
1434
+ Data type for computations can either be 'float32' or 'float64'. If
1435
+ `out` is specified, the data type of `out` is used and this argument is
1436
+ ignored. If `out` is not provided, 'float64' is used by default.
1437
+
1438
+ Returns
1439
+ -------
1440
+ tuple
1441
+ Coordinate in world space of the intersection and distance in scene
1442
+ units from `rayOrig`. Returns `None` if there is no intersection.
1443
+
1444
+ Examples
1445
+ --------
1446
+ Get the point on an axis-aligned bounding box that the cursor is over and
1447
+ place a 3D stimulus there. The eye location is defined by `RigidBodyPose`
1448
+ object `camera`::
1449
+
1450
+ # get the mouse position on-screen
1451
+ mx, my = mouse.getPos()
1452
+
1453
+ # find the point which the ray intersects on the box
1454
+ result = intersectRayAABB(
1455
+ camera.pos,
1456
+ camera.transformNormal(win.coordToRay((mx, my))),
1457
+ myStim.pos,
1458
+ myStim.thePose.bounds.extents)
1459
+
1460
+ # if the ray intersects, set the position of the cursor object to it
1461
+ if result is not None:
1462
+ cursorModel.thePose.pos = result[0]
1463
+ cursorModel.draw() # don't draw anything if there is no intersect
1464
+
1465
+ Note that if the model is rotated, the bounding box may not be aligned
1466
+ anymore with the axes. Use `intersectRayOBB` if your model rotates.
1467
+
1468
+ """
1469
+ # based of the example provided here:
1470
+ # https://www.scratchapixel.com/lessons/3d-basic-rendering/
1471
+ # minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
1472
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1473
+
1474
+ rayOrig = np.asarray(rayOrig, dtype=dtype)
1475
+ rayDir = np.asarray(rayDir, dtype=dtype)
1476
+ boundsOffset = np.asarray(boundsOffset, dtype=dtype)
1477
+ extents = np.asarray(boundsExtents, dtype=dtype) + boundsOffset
1478
+
1479
+ invDir = 1.0 / rayDir
1480
+ sign = np.zeros((3,), dtype=int)
1481
+ sign[invDir < 0.0] = 1
1482
+
1483
+ tmin = (extents[sign[0], 0] - rayOrig[0]) * invDir[0]
1484
+ tmax = (extents[1 - sign[0], 0] - rayOrig[0]) * invDir[0]
1485
+ tymin = (extents[sign[1], 1] - rayOrig[1]) * invDir[1]
1486
+ tymax = (extents[1 - sign[1], 1] - rayOrig[1]) * invDir[1]
1487
+
1488
+ if tmin > tymax or tymin > tmax:
1489
+ return None
1490
+
1491
+ if tymin > tmin:
1492
+ tmin = tymin
1493
+
1494
+ if tymax < tmax:
1495
+ tmax = tymax
1496
+
1497
+ tzmin = (extents[sign[2], 2] - rayOrig[2]) * invDir[2]
1498
+ tzmax = (extents[1 - sign[2], 2] - rayOrig[2]) * invDir[2]
1499
+
1500
+ if tmin > tzmax or tzmin > tmax:
1501
+ return None
1502
+
1503
+ if tzmin > tmin:
1504
+ tmin = tzmin
1505
+
1506
+ if tzmax < tmax:
1507
+ tmax = tzmax
1508
+
1509
+ if tmin < 0:
1510
+ if tmax < 0:
1511
+ return None
1512
+
1513
+ return (rayDir * tmin) + rayOrig, tmin
1514
+
1515
+
1516
+ def intersectRayOBB(rayOrig, rayDir, modelMatrix, boundsExtents, dtype=None):
1517
+ """Find the point a ray intersects an oriented bounding box (OBB).
1518
+
1519
+ Parameters
1520
+ ----------
1521
+ rayOrig : array_like
1522
+ Origin of the ray in space [x, y, z].
1523
+ rayDir : array_like
1524
+ Direction vector of the ray [x, y, z], should be normalized.
1525
+ modelMatrix : array_like
1526
+ 4x4 model matrix of the object and bounding box.
1527
+ boundsExtents : array_like
1528
+ Minimum and maximum extents of the bounding box.
1529
+ dtype : dtype or str, optional
1530
+ Data type for computations can either be 'float32' or 'float64'. If
1531
+ `out` is specified, the data type of `out` is used and this argument is
1532
+ ignored. If `out` is not provided, 'float64' is used by default.
1533
+
1534
+ Returns
1535
+ -------
1536
+ tuple
1537
+ Coordinate in world space of the intersection and distance in scene
1538
+ units from `rayOrig`. Returns `None` if there is no intersection.
1539
+
1540
+ Examples
1541
+ --------
1542
+ Get the point on an oriented bounding box that the cursor is over and place
1543
+ a 3D stimulus there. The eye location is defined by `RigidBodyPose` object
1544
+ `camera`::
1545
+
1546
+ # get the mouse position on-screen
1547
+ mx, my = mouse.getPos()
1548
+
1549
+ # find the point which the ray intersects on the box
1550
+ result = intersectRayOBB(
1551
+ camera.pos,
1552
+ camera.transformNormal(win.coordToRay((mx, my))),
1553
+ myStim.thePose.getModelMatrix(),
1554
+ myStim.thePose.bounds.extents)
1555
+
1556
+ # if the ray intersects, set the position of the cursor object to it
1557
+ if result is not None:
1558
+ cursorModel.thePose.pos = result[0]
1559
+ cursorModel.draw() # don't draw anything if there is no intersect
1560
+
1561
+ """
1562
+ # based off algorithm:
1563
+ # https://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/
1564
+ # picking-with-custom-ray-obb-function/
1565
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1566
+
1567
+ rayOrig = np.asarray(rayOrig, dtype=dtype)
1568
+ rayDir = np.asarray(rayDir, dtype=dtype)
1569
+ modelMatrix = np.asarray(modelMatrix, dtype=dtype)
1570
+ boundsOffset = np.asarray(modelMatrix[:3, 3], dtype=dtype)
1571
+ extents = np.asarray(boundsExtents, dtype=dtype)
1572
+
1573
+ tmin = 0.0
1574
+ tmax = np.finfo(dtype).max
1575
+ d = boundsOffset - rayOrig
1576
+
1577
+ # solve intersects for each pair of planes along each axis
1578
+ for i in range(3):
1579
+ axis = modelMatrix[:3, i]
1580
+ e = np.dot(axis, d)
1581
+ f = np.dot(rayDir, axis)
1582
+
1583
+ if np.fabs(f) > 1e-5:
1584
+ t1 = (e + extents[0, i]) / f
1585
+ t2 = (e + extents[1, i]) / f
1586
+
1587
+ if t1 > t2:
1588
+ temp = t1
1589
+ t1 = t2
1590
+ t2 = temp
1591
+
1592
+ if t2 < tmax:
1593
+ tmax = t2
1594
+
1595
+ if t1 > tmin:
1596
+ tmin = t1
1597
+
1598
+ if tmin > tmax:
1599
+ return None
1600
+
1601
+ else:
1602
+ # very close to parallel with the face
1603
+ if -e + extents[0, i] > 0.0 or -e + extents[1, i] < 0.0:
1604
+ return None
1605
+
1606
+ return (rayDir * tmin) + rayOrig, tmin
1607
+
1608
+
1609
+ def intersectRayTriangle(rayOrig, rayDir, tri, dtype=None):
1610
+ """Get the intersection of a ray and triangle(s).
1611
+
1612
+ This function can be used to achieve 'pixel-perfect' ray picking/casting on
1613
+ meshes defined with triangles. However, high-poly meshes may lead to
1614
+ performance issues.
1615
+
1616
+ Parameters
1617
+ ----------
1618
+ rayOrig : array_like
1619
+ Origin of the ray in space [x, y, z].
1620
+ rayDir : array_like
1621
+ Direction vector of the ray [x, y, z], should be normalized.
1622
+ tri : array_like
1623
+ Triangle vertices as 2D (3x3) array [p0, p1, p2] where each vertex is a
1624
+ length 3 array [vx, xy, vz]. The input array can be 3D (Nx3x3) to
1625
+ specify multiple triangles.
1626
+ dtype : dtype or str, optional
1627
+ Data type for computations can either be 'float32' or 'float64'. If
1628
+ `out` is specified, the data type of `out` is used and this argument is
1629
+ ignored. If `out` is not provided, 'float64' is used by default.
1630
+
1631
+ Returns
1632
+ -------
1633
+ tuple
1634
+ Coordinate in world space of the intersection, distance in scene
1635
+ units from `rayOrig`, and the barycentric coordinates on the triangle
1636
+ [x, y]. Returns `None` if there is no intersection.
1637
+
1638
+ """
1639
+ # based off `intersectRayTriangle` from GLM (https://glm.g-truc.net)
1640
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1641
+
1642
+ rayOrig = np.asarray(rayOrig, dtype=dtype)
1643
+ rayDir = np.asarray(rayDir, dtype=dtype)
1644
+ triVerts = np.asarray(tri, dtype=dtype)
1645
+
1646
+ edge1 = triVerts[1, :] - triVerts[0, :]
1647
+ edge2 = triVerts[2, :] - triVerts[0, :]
1648
+
1649
+ baryPos = np.zeros((2,), dtype=dtype)
1650
+
1651
+ p = np.cross(rayDir, edge2)
1652
+ det = np.dot(edge1, p)
1653
+
1654
+ if det > np.finfo(dtype).eps:
1655
+ dist = rayOrig - triVerts[0, :]
1656
+
1657
+ baryPos[0] = np.dot(dist, p)
1658
+ if baryPos[0] < 0.0 or baryPos[0] > det:
1659
+ return None
1660
+
1661
+ ortho = np.cross(dist, edge1)
1662
+
1663
+ baryPos[1] = np.dot(rayDir, ortho)
1664
+ if baryPos[1] < 0.0 or baryPos[0] + baryPos[1] > det:
1665
+ return None
1666
+
1667
+ elif det < -np.finfo(dtype).eps:
1668
+ dist = rayOrig - triVerts[0, :]
1669
+
1670
+ baryPos[0] = np.dot(dist, p)
1671
+ if baryPos[0] > 0.0 or baryPos[0] < det:
1672
+ return None
1673
+
1674
+ ortho = np.cross(dist, edge1)
1675
+
1676
+ baryPos[1] = np.dot(rayDir, ortho)
1677
+ if baryPos[1] > 0.0 or baryPos[0] + baryPos[1] < det:
1678
+ return None
1679
+ else:
1680
+ return None
1681
+
1682
+ invDet = 1.0 / det
1683
+ dist = np.dot(edge2, ortho) * invDet
1684
+ baryPos *= invDet
1685
+
1686
+ return (rayDir * dist) + rayOrig, dist, baryPos
1687
+
1688
+
1689
+ def ortho3Dto2D(p, orig, normal, up, right=None, dtype=None):
1690
+ """Get the planar coordinates of an orthogonal projection of a 3D point onto
1691
+ a 2D plane.
1692
+
1693
+ This function gets the nearest point on the plane which a 3D point falls on
1694
+ the plane.
1695
+
1696
+ Parameters
1697
+ ----------
1698
+ p : array_like
1699
+ Point to be projected on the plane.
1700
+ orig : array_like
1701
+ Origin of the plane to test [x, y, z].
1702
+ normal : array_like
1703
+ Normal vector of the plane [x, y, z], must be normalized.
1704
+ up : array_like
1705
+ Normalized up (+Y) direction of the plane's coordinate system. Must be
1706
+ perpendicular to `normal`.
1707
+ right : array_like, optional
1708
+ Perpendicular right (+X) axis. If not provided, the axis will be
1709
+ computed via the cross product between `normal` and `up`.
1710
+ dtype : dtype or str, optional
1711
+ Data type for computations can either be 'float32' or 'float64'. If
1712
+ `out` is specified, the data type of `out` is used and this argument is
1713
+ ignored. If `out` is not provided, 'float64' is used by default.
1714
+
1715
+ Returns
1716
+ -------
1717
+ ndarray
1718
+ Coordinates on the plane [X, Y] where the 3D point projects towards
1719
+ perpendicularly.
1720
+
1721
+ Examples
1722
+ --------
1723
+ This function can be used with :func:`intersectRayPlane` to find the
1724
+ location on the plane the ray intersects::
1725
+
1726
+ # plane information
1727
+ planeOrigin = [0, 0, 0]
1728
+ planeNormal = [0, 0, 1] # must be normalized
1729
+ planeUpAxis = perp([0, 1, 0], planeNormal) # must also be normalized
1730
+
1731
+ # ray
1732
+ rayDir = [0, 0, -1]
1733
+ rayOrigin = [0, 0, 5]
1734
+
1735
+ # get the intersect in 3D world space
1736
+ pnt = intersectRayPlane(rayOrigin, rayDir, planeOrigin, planeNormal)
1737
+
1738
+ # get the 2D coordinates on the plane the intersect occurred
1739
+ planeX, planeY = ortho3Dto2D(pnt, planeOrigin, planeNormal, planeUpAxis)
1740
+
1741
+ """
1742
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1743
+
1744
+ p = np.asarray(p, dtype=dtype)
1745
+ orig = np.asarray(orig, dtype=dtype)
1746
+ normal = np.asarray(normal, dtype=dtype)
1747
+ up = np.asarray(up, dtype=dtype)
1748
+
1749
+ toReturn = np.zeros((2,))
1750
+
1751
+ offset = p - orig
1752
+ if right is None:
1753
+ # derive X axis with cross product
1754
+ toReturn[0] = dot(offset, cross(normal, up, dtype=dtype), dtype=dtype)
1755
+ else:
1756
+ toReturn[0] = dot(offset, np.asarray(right, dtype=dtype), dtype=dtype)
1757
+
1758
+ toReturn[1] = dot(offset, up)
1759
+
1760
+ return toReturn
1761
+
1762
+
1763
+ def articulate(boneVecs, boneOris, dtype=None):
1764
+ """Articulate an armature.
1765
+
1766
+ This function is used for forward kinematics and posing by specifying a list
1767
+ of 'bones'. A bone has a length and orientation, where sequential bones are
1768
+ linked end-to-end. Returns the transformed origins of the bones in scene
1769
+ coordinates and their orientations.
1770
+
1771
+ There are many applications for forward kinematics such as posing armatures
1772
+ and stimuli for display (eg. mocap data). Another application is for getting
1773
+ the location of the end effector of coordinate measuring hardware, where
1774
+ encoders measure the joint angles and the length of linking members are
1775
+ known. This can be used for computing pose from "Sword of Damocles"[1]_ like
1776
+ hardware or some other haptic input devices which the participant wears (eg.
1777
+ a glove that measures joint angles in the hand). The computed pose of the
1778
+ joints can be used to interact with virtual stimuli.
1779
+
1780
+ Parameters
1781
+ ----------
1782
+ boneVecs : array_like
1783
+ Bone lengths [x, y, z] as an Nx3 array.
1784
+ boneOris : array_like
1785
+ Orientation of the bones as quaternions in form [x, y, z, w], relative
1786
+ to the previous bone.
1787
+ dtype : dtype or str, optional
1788
+ Data type for computations can either be 'float32' or 'float64'. If
1789
+ `out` is specified, the data type of `out` is used and this argument is
1790
+ ignored. If `out` is not provided, 'float64' is used by default.
1791
+
1792
+ Returns
1793
+ -------
1794
+ tuple
1795
+ Array of bone origins and orientations. The first origin is root
1796
+ position which is always at [0, 0, 0]. Use :func:`transform` to
1797
+ reposition the armature, or create a transformation matrix and use
1798
+ `applyMatrix` to translate and rotate the whole armature into position.
1799
+
1800
+ References
1801
+ ----------
1802
+ .. [1] Sutherland, I. E. (1968). "A head-mounted three dimensional display".
1803
+ Proceedings of AFIPS 68, pp. 757-764
1804
+
1805
+ Examples
1806
+ --------
1807
+ Compute the orientations and origins of segments of an arm::
1808
+
1809
+ # bone lengths
1810
+ boneLengths = [[0., 1., 0.], [0., 1., 0.], [0., 1., 0.]]
1811
+
1812
+ # create quaternions for joints
1813
+ shoulder = mt.quatFromAxisAngle('-y', 45.0)
1814
+ elbow = mt.quatFromAxisAngle('+z', 45.0)
1815
+ wrist = mt.quatFromAxisAngle('+z', 45.0)
1816
+
1817
+ # articulate the parts of the arm
1818
+ boxPos, boxOri = mt.articulate(pos, [shoulder, elbow, wrist])
1819
+
1820
+ # assign positions and orientations to 3D objects
1821
+ shoulderModel.thePose.posOri = (boxPos[0, :], boxOri[0, :])
1822
+ elbowModel.thePose.posOri = (boxPos[1, :], boxOri[1, :])
1823
+ wristModel.thePose.posOri = (boxPos[2, :], boxOri[2, :])
1824
+
1825
+ """
1826
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1827
+
1828
+ boneVecs = np.asarray(boneVecs, dtype=dtype)
1829
+ boneOris = np.asarray(boneOris, dtype=dtype)
1830
+
1831
+ jointOri = accumQuat(boneOris, dtype=dtype) # get joint orientations
1832
+ bonesRotated = applyQuat(jointOri, boneVecs, dtype=dtype) # rotate bones
1833
+
1834
+ # accumulate
1835
+ bonesTranslated = np.asarray(
1836
+ tuple(itertools.accumulate(bonesRotated[:], lambda a, b: a + b)),
1837
+ dtype=dtype)
1838
+ bonesTranslated -= bonesTranslated[0, :] # offset root length
1839
+
1840
+ return bonesTranslated, jointOri
1841
+
1842
+
1843
+ # ------------------------------------------------------------------------------
1844
+ # Quaternion Operations
1845
+ #
1846
+
1847
+ def slerp(q0, q1, t, shortest=True, out=None, dtype=None):
1848
+ """Spherical linear interpolation (SLERP) between two quaternions.
1849
+
1850
+ The behaviour of this function depends on the types of arguments:
1851
+
1852
+ * If `q0` and `q1` are both 1-D and `t` is scalar, the interpolation at `t`
1853
+ is returned.
1854
+ * If `q0` and `q1` are both 2-D Nx4 arrays and `t` is scalar, an Nx4 array
1855
+ is returned with each row containing the interpolation at `t` for each
1856
+ quaternion pair at matching row indices in `q0` and `q1`.
1857
+
1858
+ Parameters
1859
+ ----------
1860
+ q0 : array_like
1861
+ Initial quaternion in form [x, y, z, w] where w is real and x, y, z
1862
+ are imaginary components.
1863
+ q1 : array_like
1864
+ Final quaternion in form [x, y, z, w] where w is real and x, y, z
1865
+ are imaginary components.
1866
+ t : float
1867
+ Interpolation weight factor within interval 0.0 and 1.0.
1868
+ shortest : bool, optional
1869
+ Ensure interpolation occurs along the shortest arc along the 4-D
1870
+ hypersphere (default is `True`).
1871
+ out : ndarray, optional
1872
+ Optional output array. Must be same `shape` and `dtype` as the expected
1873
+ output if `out` was not specified.
1874
+ dtype : dtype or str, optional
1875
+ Data type for computations can either be 'float32' or 'float64'. If
1876
+ `out` is specified, the data type of `out` is used and this argument is
1877
+ ignored. If `out` is not provided, 'float64' is used by default.
1878
+
1879
+ Returns
1880
+ -------
1881
+ ndarray
1882
+ Quaternion [x, y, z, w] at `t`.
1883
+
1884
+ Examples
1885
+ --------
1886
+ Interpolate between two orientations::
1887
+
1888
+ q0 = quatFromAxisAngle(90.0, degrees=True)
1889
+ q1 = quatFromAxisAngle(-90.0, degrees=True)
1890
+ # halfway between 90 and -90 is 0.0 or quaternion [0. 0. 0. 1.]
1891
+ qr = slerp(q0, q1, 0.5)
1892
+
1893
+ Example of smooth rotation of an object with fixed angular velocity::
1894
+
1895
+ degPerSec = 10.0 # rotate a stimulus at 10 degrees per second
1896
+
1897
+ # initial orientation, axis rotates in the Z direction
1898
+ qr = quatFromAxisAngle([0., 0., -1.], 0.0, degrees=True)
1899
+ # amount to rotate every second
1900
+ qv = quatFromAxisAngle([0., 0., -1.], degPerSec, degrees=True)
1901
+
1902
+ # ---- within main experiment loop ----
1903
+ # `frameTime` is the time elapsed in seconds from last `slerp`.
1904
+ qr = multQuat(qr, slerp((0., 0., 0., 1.), qv, degPerSec * frameTime))
1905
+ _, angle = quatToAxisAngle(qr) # discard axis, only need angle
1906
+
1907
+ # myStim is a GratingStim or anything with an 'ori' argument which
1908
+ # accepts angle in degrees
1909
+ myStim.ori = angle
1910
+ myStim.draw()
1911
+
1912
+ """
1913
+ # Implementation based on code found here:
1914
+ # https://en.wikipedia.org/wiki/Slerp
1915
+ #
1916
+ if out is None:
1917
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1918
+ else:
1919
+ dtype = np.dtype(out.dtype).type
1920
+
1921
+ q0 = normalize(q0, dtype=dtype)
1922
+ q1 = normalize(q1, dtype=dtype)
1923
+ assert q0.shape == q1.shape
1924
+
1925
+ toReturn = np.zeros(q0.shape, dtype=dtype) if out is None else out
1926
+ toReturn.fill(0.0)
1927
+ t = dtype(t)
1928
+ q0, q1, qr = np.atleast_2d(q0, q1, toReturn)
1929
+
1930
+ d = np.clip(np.sum(q0 * q1, axis=1), -1.0, 1.0)
1931
+ if shortest:
1932
+ d[d < 0.0] *= -1.0
1933
+ q1[d < 0.0] *= -1.0
1934
+
1935
+ theta0 = np.arccos(d)
1936
+ theta = theta0 * t
1937
+ sinTheta = np.sin(theta)
1938
+ s1 = sinTheta / np.sin(theta0)
1939
+ s0 = np.cos(theta[:, np.newaxis]) - d[:, np.newaxis] * s1[:, np.newaxis]
1940
+ qr[:, :] = q0 * s0
1941
+ qr[:, :] += q1 * s1[:, np.newaxis]
1942
+ qr[:, :] += 0.0
1943
+
1944
+ return toReturn
1945
+
1946
+
1947
+ def quatToAxisAngle(q, degrees=True, dtype=None):
1948
+ """Convert a quaternion to `axis` and `angle` representation.
1949
+
1950
+ This allows you to use quaternions to set the orientation of stimuli that
1951
+ have an `ori` property.
1952
+
1953
+ Parameters
1954
+ ----------
1955
+ q : tuple, list or ndarray of float
1956
+ Quaternion in form [x, y, z, w] where w is real and x, y, z
1957
+ are imaginary components.
1958
+ degrees : bool, optional
1959
+ Indicate `angle` is to be returned in degrees, otherwise `angle` will be
1960
+ returned in radians.
1961
+ dtype : dtype or str, optional
1962
+ Data type for computations can either be 'float32' or 'float64'. If
1963
+ `out` is specified, the data type of `out` is used and this argument is
1964
+ ignored. If `out` is not provided, 'float64' is used by default.
1965
+
1966
+ Returns
1967
+ -------
1968
+ tuple
1969
+ Axis and angle of quaternion in form ([ax, ay, az], angle). If `degrees`
1970
+ is `True`, the angle returned is in degrees, radians if `False`.
1971
+
1972
+ Examples
1973
+ --------
1974
+ Using a quaternion to rotate a stimulus a fixed angle each frame::
1975
+
1976
+ # initial orientation, axis rotates in the Z direction
1977
+ qr = quatFromAxisAngle([0., 0., -1.], 0.0, degrees=True)
1978
+ # rotation per-frame, here it's 0.1 degrees per frame
1979
+ qf = quatFromAxisAngle([0., 0., -1.], 0.1, degrees=True)
1980
+
1981
+ # ---- within main experiment loop ----
1982
+ # myStim is a GratingStim or anything with an 'ori' argument which
1983
+ # accepts angle in degrees
1984
+ qr = multQuat(qr, qf) # cumulative rotation
1985
+ _, angle = quatToAxisAngle(qr) # discard axis, only need angle
1986
+ myStim.ori = angle
1987
+ myStim.draw()
1988
+
1989
+ """
1990
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
1991
+ q = normalize(q, dtype=dtype) # returns ndarray
1992
+ v = np.sqrt(np.sum(np.square(q[:3])))
1993
+
1994
+ if np.count_nonzero(q[:3]):
1995
+ axis = q[:3] / v
1996
+ angle = dtype(2.0) * np.arctan2(v, q[3])
1997
+ else:
1998
+ axis = np.zeros((3,), dtype=dtype)
1999
+ axis[0] = 1.
2000
+ angle = 0.0
2001
+
2002
+ axis += 0.0
2003
+
2004
+ return axis, np.degrees(angle) if degrees else angle
2005
+
2006
+
2007
+ def quatFromAxisAngle(axis, angle, degrees=True, dtype=None):
2008
+ """Create a quaternion to represent a rotation about `axis` vector by
2009
+ `angle`.
2010
+
2011
+ Parameters
2012
+ ----------
2013
+ axis : tuple, list, ndarray or str
2014
+ Axis vector components or axis name. If a vector, input must be length
2015
+ 3 [x, y, z]. A string can be specified for rotations about world axes
2016
+ (eg. `'+x'`, `'-z'`, `'+y'`, etc.)
2017
+ angle : float
2018
+ Rotation angle in radians (or degrees if `degrees` is `True`. Rotations
2019
+ are right-handed about the specified `axis`.
2020
+ degrees : bool, optional
2021
+ Indicate `angle` is in degrees, otherwise `angle` will be treated as
2022
+ radians.
2023
+ dtype : dtype or str, optional
2024
+ Data type for computations can either be 'float32' or 'float64'. If
2025
+ `out` is specified, the data type of `out` is used and this argument is
2026
+ ignored. If `out` is not provided, 'float64' is used by default.
2027
+
2028
+ Returns
2029
+ -------
2030
+ ndarray
2031
+ Quaternion [x, y, z, w].
2032
+
2033
+ Examples
2034
+ --------
2035
+ Create a quaternion from specified `axis` and `angle`::
2036
+
2037
+ axis = [0., 0., -1.] # rotate about -Z axis
2038
+ angle = 90.0 # angle in degrees
2039
+ ori = quatFromAxisAngle(axis, angle, degrees=True) # using degrees!
2040
+
2041
+ """
2042
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2043
+ toReturn = np.zeros((4,), dtype=dtype)
2044
+
2045
+ if degrees:
2046
+ halfRad = np.radians(angle, dtype=dtype) / dtype(2.0)
2047
+ else:
2048
+ halfRad = np.dtype(dtype).type(angle) / dtype(2.0)
2049
+
2050
+ try:
2051
+ axis = VEC_AXES[axis] if isinstance(axis, str) else axis
2052
+ except KeyError:
2053
+ raise ValueError(
2054
+ "Value of `axis` must be either '+X', '-X', '+Y', '-Y', '+Z' or "
2055
+ "'-Z' or length 3 vector.")
2056
+
2057
+ axis = normalize(axis, dtype=dtype)
2058
+ if np.count_nonzero(axis) == 0:
2059
+ raise ValueError("Value for `axis` is zero-length.")
2060
+
2061
+ np.multiply(axis, np.sin(halfRad), out=toReturn[:3])
2062
+ toReturn[3] = np.cos(halfRad)
2063
+ toReturn += 0.0 # remove negative zeros
2064
+
2065
+ return toReturn
2066
+
2067
+
2068
+ def quatYawPitchRoll(q, degrees=True, out=None, dtype=None):
2069
+ """Get the yaw, pitch, and roll of a quaternion's orientation relative to
2070
+ the world -Z axis.
2071
+
2072
+ You can multiply the quaternion by the inverse of some other one to make the
2073
+ returned values referenced to a local coordinate system.
2074
+
2075
+ Parameters
2076
+ ----------
2077
+ q : tuple, list or ndarray of float
2078
+ Quaternion in form [x, y, z, w] where w is real and x, y, z
2079
+ are imaginary components.
2080
+ degrees : bool, optional
2081
+ Indicate angles are to be returned in degrees, otherwise they will be
2082
+ returned in radians.
2083
+ out : ndarray
2084
+ Optional output array. Must have same `shape` and `dtype` as what is
2085
+ expected to be returned by this function of `out` was not specified.
2086
+ dtype : dtype or str, optional
2087
+ Data type for computations can either be 'float32' or 'float64'. If
2088
+ `out` is specified, the data type of `out` is used and this argument is
2089
+ ignored. If `out` is not provided, 'float64' is used by default.
2090
+
2091
+ Returns
2092
+ -------
2093
+ ndarray
2094
+ Yaw, pitch and roll [yaw, pitch, roll] of quaternion `q`.
2095
+
2096
+ """
2097
+ # based off code found here:
2098
+ # https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
2099
+ # Yields the same results as PsychXR's LibOVRPose.getYawPitchRoll method.
2100
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2101
+ q = np.asarray(q, dtype=dtype)
2102
+
2103
+ toReturn = np.zeros((3,), dtype=dtype) if out is None else out
2104
+
2105
+ sinRcosP = 2.0 * (q[3] * q[0] + q[1] * q[2])
2106
+ cosRcosP = 1.0 - 2.0 * (q[0] * q[0] + q[1] * q[1])
2107
+
2108
+ toReturn[0] = np.arctan2(sinRcosP, cosRcosP)
2109
+
2110
+ sinp = 2.0 * (q[3] * q[1] - q[2] * q[0])
2111
+
2112
+ if np.fabs(sinp) >= 1.:
2113
+ toReturn[1] = np.copysign(np.pi / 2., sinp)
2114
+ else:
2115
+ toReturn[1] = np.arcsin(sinp)
2116
+
2117
+ sinYcosP = 2.0 * (q[3] * q[2] + q[0] * q[1])
2118
+ cosYcosP = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2])
2119
+
2120
+ toReturn[2] = np.arctan2(sinYcosP, cosYcosP)
2121
+
2122
+ if degrees:
2123
+ toReturn[:] = np.degrees(toReturn[:])
2124
+
2125
+ return toReturn
2126
+
2127
+
2128
+ def quatMagnitude(q, squared=False, out=None, dtype=None):
2129
+ """Get the magnitude of a quaternion.
2130
+
2131
+ A quaternion is normalized if its magnitude is 1.
2132
+
2133
+ Parameters
2134
+ ----------
2135
+ q : array_like
2136
+ Quaternion(s) in form [x, y, z, w] where w is real and x, y, z are
2137
+ imaginary components.
2138
+ squared : bool, optional
2139
+ If ``True`` return the squared magnitude. If you are just checking if a
2140
+ quaternion is normalized, the squared magnitude will suffice to avoid
2141
+ the square root operation.
2142
+ out : ndarray, optional
2143
+ Optional output array. Must be same `shape` and `dtype` as the expected
2144
+ output if `out` was not specified.
2145
+ dtype : dtype or str, optional
2146
+ Data type for computations can either be 'float32' or 'float64'. If
2147
+ `out` is specified, the data type of `out` is used and this argument is
2148
+ ignored. If `out` is not provided, 'float64' is used by default.
2149
+
2150
+ Returns
2151
+ -------
2152
+ float or ndarray
2153
+ Magnitude of quaternion `q`.
2154
+
2155
+ """
2156
+ if out is None:
2157
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2158
+ else:
2159
+ dtype = np.dtype(out.dtype).type
2160
+
2161
+ q = np.asarray(q, dtype=dtype)
2162
+ if q.ndim == 1:
2163
+ assert q.shape[0] == 4
2164
+ if squared:
2165
+ toReturn = np.sum(np.square(q))
2166
+ else:
2167
+ toReturn = np.sqrt(np.sum(np.square(q)))
2168
+ elif q.ndim == 2:
2169
+ assert q.shape[1] == 4
2170
+ toReturn = np.zeros((q.shape[0],), dtype=dtype) if out is None else out
2171
+ if squared:
2172
+ toReturn[:] = np.sum(np.square(q), axis=1)
2173
+ else:
2174
+ toReturn[:] = np.sqrt(np.sum(np.square(q), axis=1))
2175
+ else:
2176
+ raise ValueError("Input argument 'q' has incorrect dimensions.")
2177
+
2178
+ return toReturn
2179
+
2180
+
2181
+ def multQuat(q0, q1, out=None, dtype=None):
2182
+ """Multiply quaternion `q0` and `q1`.
2183
+
2184
+ The orientation of the returned quaternion is the combination of the input
2185
+ quaternions.
2186
+
2187
+ Parameters
2188
+ ----------
2189
+ q0, q1 : array_like
2190
+ Quaternions to multiply in form [x, y, z, w] where w is real and x, y, z
2191
+ are imaginary components. If 2D (Nx4) arrays are specified, quaternions
2192
+ are multiplied row-wise between each array.
2193
+ out : ndarray, optional
2194
+ Optional output array. Must be same `shape` and `dtype` as the expected
2195
+ output if `out` was not specified.
2196
+ dtype : dtype or str, optional
2197
+ Data type for computations can either be 'float32' or 'float64'. If
2198
+ `out` is specified, the data type of `out` is used and this argument is
2199
+ ignored. If `out` is not provided, 'float64' is used by default.
2200
+
2201
+ Returns
2202
+ -------
2203
+ ndarray
2204
+ Combined orientations of `q0` amd `q1`.
2205
+
2206
+ Notes
2207
+ -----
2208
+ * Quaternions are normalized prior to multiplication.
2209
+
2210
+ Examples
2211
+ --------
2212
+ Combine the orientations of two quaternions::
2213
+
2214
+ a = quatFromAxisAngle([0, 0, -1], 45.0, degrees=True)
2215
+ b = quatFromAxisAngle([0, 0, -1], 90.0, degrees=True)
2216
+ c = multQuat(a, b) # rotates 135 degrees about -Z axis
2217
+
2218
+ """
2219
+ if out is None:
2220
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2221
+ else:
2222
+ dtype = np.dtype(out.dtype).type
2223
+
2224
+ q0 = normalize(q0, dtype=dtype)
2225
+ q1 = normalize(q1, dtype=dtype)
2226
+ assert q0.shape == q1.shape
2227
+ toReturn = np.zeros(q0.shape, dtype=dtype) if out is None else out
2228
+ toReturn.fill(0.0) # clear array
2229
+ q0, q1, qr = np.atleast_2d(q0, q1, toReturn)
2230
+
2231
+ # multiply quaternions for each row of the operand arrays
2232
+ qr[:, :3] = np.cross(q0[:, :3], q1[:, :3], axis=1)
2233
+ qr[:, :3] += q0[:, :3] * np.expand_dims(q1[:, 3], axis=1)
2234
+ qr[:, :3] += q1[:, :3] * np.expand_dims(q0[:, 3], axis=1)
2235
+ qr[:, 3] = q0[:, 3]
2236
+ qr[:, 3] *= q1[:, 3]
2237
+ qr[:, 3] -= np.sum(np.multiply(q0[:, :3], q1[:, :3]), axis=1) # dot product
2238
+ qr += 0.0
2239
+
2240
+ return toReturn
2241
+
2242
+
2243
+ def invertQuat(q, out=None, dtype=None):
2244
+ """Get the multiplicative inverse of a quaternion.
2245
+
2246
+ This gives a quaternion which rotates in the opposite direction with equal
2247
+ magnitude. Multiplying a quaternion by its inverse returns an identity
2248
+ quaternion as both orientations cancel out.
2249
+
2250
+ Parameters
2251
+ ----------
2252
+ q : ndarray, list, or tuple of float
2253
+ Quaternion to invert in form [x, y, z, w] where w is real and x, y, z
2254
+ are imaginary components. If `q` is 2D (Nx4), each row is treated as a
2255
+ separate quaternion and inverted.
2256
+ out : ndarray, optional
2257
+ Optional output array. Must be same `shape` and `dtype` as the expected
2258
+ output if `out` was not specified.
2259
+ dtype : dtype or str, optional
2260
+ Data type for computations can either be 'float32' or 'float64'. If
2261
+ `out` is specified, the data type of `out` is used and this argument is
2262
+ ignored. If `out` is not provided, 'float64' is used by default.
2263
+
2264
+ Returns
2265
+ -------
2266
+ ndarray
2267
+ Inverse of quaternion `q`.
2268
+
2269
+ Examples
2270
+ --------
2271
+ Show that multiplying a quaternion by its inverse returns an identity
2272
+ quaternion where [x=0, y=0, z=0, w=1]::
2273
+
2274
+ angle = 90.0
2275
+ axis = [0., 0., -1.]
2276
+ q = quatFromAxisAngle(axis, angle, degrees=True)
2277
+ qinv = invertQuat(q)
2278
+ qr = multQuat(q, qinv)
2279
+ qi = np.array([0., 0., 0., 1.]) # identity quaternion
2280
+ print(np.allclose(qi, qr)) # True
2281
+
2282
+ Notes
2283
+ -----
2284
+ * Quaternions are normalized prior to inverting.
2285
+
2286
+ """
2287
+ if out is None:
2288
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2289
+ else:
2290
+ dtype = np.dtype(out.dtype).type
2291
+
2292
+ q = normalize(q, dtype=dtype)
2293
+ toReturn = np.zeros(q.shape, dtype=dtype) if out is None else out
2294
+ qn, qinv = np.atleast_2d(q, toReturn) # 2d views
2295
+
2296
+ # conjugate the quaternion
2297
+ qinv[:, :3] = -qn[:, :3]
2298
+ qinv[:, 3] = qn[:, 3]
2299
+ qinv /= np.sum(np.square(qn), axis=1)[:, np.newaxis]
2300
+ qinv += 0.0 # remove negative zeros
2301
+
2302
+ return toReturn
2303
+
2304
+
2305
+ def applyQuat(q, points, out=None, dtype=None):
2306
+ """Rotate points/coordinates using a quaternion.
2307
+
2308
+ This is similar to using `applyMatrix` with a rotation matrix. However, it
2309
+ is computationally less intensive to use `applyQuat` if one only wishes to
2310
+ rotate points.
2311
+
2312
+ Parameters
2313
+ ----------
2314
+ q : array_like
2315
+ Quaternion to invert in form [x, y, z, w] where w is real and x, y, z
2316
+ are imaginary components.
2317
+ points : array_like
2318
+ 2D array of vectors or points to transform, where each row is a single
2319
+ point. Only the x, y, and z components (the first three columns) are
2320
+ rotated. Additional columns are copied.
2321
+ out : ndarray, optional
2322
+ Optional output array. Must be same `shape` and `dtype` as the expected
2323
+ output if `out` was not specified.
2324
+ dtype : dtype or str, optional
2325
+ Data type for computations can either be 'float32' or 'float64'. If
2326
+ `out` is specified, the data type of `out` is used and this argument is
2327
+ ignored. If `out` is not provided, 'float64' is used by default.
2328
+
2329
+ Returns
2330
+ -------
2331
+ ndarray
2332
+ Transformed points.
2333
+
2334
+ Examples
2335
+ --------
2336
+ Rotate points using a quaternion::
2337
+
2338
+ points = [[1., 0., 0.], [0., -1., 0.]]
2339
+ quat = quatFromAxisAngle(-90.0, [0., 0., -1.], degrees=True)
2340
+ pointsRotated = applyQuat(quat, points)
2341
+ # [[0. 1. 0.]
2342
+ # [1. 0. 0.]]
2343
+
2344
+ Show that you get the same result as a rotation matrix::
2345
+
2346
+ axis = [0., 0., -1.]
2347
+ angle = -90.0
2348
+ rotMat = rotationMatrix(axis, angle)[:3, :3] # rotation sub-matrix only
2349
+ rotQuat = quatFromAxisAngle(angle, axis, degrees=True)
2350
+ points = [[1., 0., 0.], [0., -1., 0.]]
2351
+ isClose = np.allclose(applyMatrix(rotMat, points), # True
2352
+ applyQuat(rotQuat, points))
2353
+
2354
+ Specifying an array to `q` where each row is a quaternion transforms points
2355
+ in corresponding rows of `points`::
2356
+
2357
+ points = [[1., 0., 0.], [0., -1., 0.]]
2358
+ quats = [quatFromAxisAngle(-90.0, [0., 0., -1.], degrees=True),
2359
+ quatFromAxisAngle(45.0, [0., 0., -1.], degrees=True)]
2360
+ applyQuat(quats, points)
2361
+
2362
+ """
2363
+ # based on 'quat_mul_vec3' implementation from linmath.h
2364
+ if out is None:
2365
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2366
+ else:
2367
+ dtype = np.dtype(out.dtype).type
2368
+
2369
+ qin = np.asarray(q, dtype=dtype)
2370
+ points = np.asarray(points, dtype=dtype)
2371
+
2372
+ if out is not None:
2373
+ assert points.shape == out.shape
2374
+
2375
+ toReturn = np.zeros(points.shape, dtype=dtype) if out is None else out
2376
+ pin, pout = np.atleast_2d(points, toReturn)
2377
+ pout[:, :] = pin[:, :] # copy values into output array
2378
+
2379
+ if qin.ndim == 1:
2380
+ assert qin.shape[0] == 4
2381
+ t = cross(qin[:3], pin[:, :3]) * dtype(2.0)
2382
+ u = cross(qin[:3], t)
2383
+ t *= qin[3]
2384
+ pout[:, :3] += t
2385
+ pout[:, :3] += u
2386
+ elif qin.ndim == 2:
2387
+ assert qin.shape[1] == 4 and qin.shape[0] == pin.shape[0]
2388
+ t = cross(qin[:, :3], pin[:, :3])
2389
+ t *= dtype(2.0)
2390
+ u = cross(qin[:, :3], t)
2391
+ t *= np.expand_dims(qin[:, 3], axis=1)
2392
+ pout[:, :3] += t
2393
+ pout[:, :3] += u
2394
+ else:
2395
+ raise ValueError("Input arguments have invalid dimensions.")
2396
+
2397
+ return toReturn
2398
+
2399
+
2400
+ def accumQuat(qlist, out=None, dtype=None):
2401
+ """Accumulate quaternion rotations.
2402
+
2403
+ Chain multiplies an Nx4 array of quaternions, accumulating their rotations.
2404
+ This function can be used for computing the orientation of joints in an
2405
+ armature for forward kinematics. The first quaternion is treated as the
2406
+ 'root' and the last is the orientation of the end effector.
2407
+
2408
+ Parameters
2409
+ ----------
2410
+ q : array_like
2411
+ Nx4 array of quaternions to accumulate, where each row is a quaternion.
2412
+ out : ndarray, optional
2413
+ Optional output array. Must be same `shape` and `dtype` as the expected
2414
+ output if `out` was not specified. In this case, the same shape as
2415
+ `qlist`.
2416
+ dtype : dtype or str, optional
2417
+ Data type for computations can either be 'float32' or 'float64'. If
2418
+ `out` is specified, the data type of `out` is used and this argument is
2419
+ ignored. If `out` is not provided, 'float64' is used by default.
2420
+
2421
+ Returns
2422
+ -------
2423
+ ndarray
2424
+ Nx4 array of quaternions.
2425
+
2426
+ Examples
2427
+ --------
2428
+ Get the orientation of joints in an armature if we know their relative
2429
+ angles::
2430
+
2431
+ shoulder = quatFromAxisAngle('-x', 45.0) # rotate shoulder down 45 deg
2432
+ elbow = quatFromAxisAngle('+x', 45.0) # rotate elbow up 45 deg
2433
+ wrist = quatFromAxisAngle('-x', 45.0) # rotate wrist down 45 deg
2434
+ finger = quatFromAxisAngle('+x', 0.0) # keep finger in-line with wrist
2435
+
2436
+ armRotations = accumQuat([shoulder, elbow, wrist, finger])
2437
+
2438
+ """
2439
+ if out is None:
2440
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2441
+ else:
2442
+ dtype = np.dtype(out.dtype).type
2443
+
2444
+ qlist = np.asarray(qlist, dtype=dtype)
2445
+ qlist = np.atleast_2d(qlist)
2446
+
2447
+ qr = np.zeros_like(qlist, dtype=dtype) if out is None else out
2448
+ qr[:, :] = tuple(itertools.accumulate(
2449
+ qlist[:], lambda a, b: multQuat(a, b, dtype=dtype)))
2450
+
2451
+ return qr
2452
+
2453
+
2454
+ def alignTo(v, t, out=None, dtype=None):
2455
+ """Compute a quaternion which rotates one vector to align with another.
2456
+
2457
+ Parameters
2458
+ ----------
2459
+ v : array_like
2460
+ Vector [x, y, z] to rotate. Can be Nx3, but must have the same shape as
2461
+ `t`.
2462
+ t : array_like
2463
+ Target [x, y, z] vector to align to. Can be Nx3, but must have the same
2464
+ shape as `v`.
2465
+ out : ndarray, optional
2466
+ Optional output array. Must be same `shape` and `dtype` as the expected
2467
+ output if `out` was not specified.
2468
+ dtype : dtype or str, optional
2469
+ Data type for computations can either be 'float32' or 'float64'. If
2470
+ `out` is specified, the data type of `out` is used and this argument is
2471
+ ignored. If `out` is not provided, 'float64' is used by default.
2472
+
2473
+ Returns
2474
+ -------
2475
+ ndarray
2476
+ Quaternion which rotates `v` to `t`.
2477
+
2478
+ Examples
2479
+ --------
2480
+ Rotate some vectors to align with other vectors, inputs should be
2481
+ normalized::
2482
+
2483
+ vec = [[1, 0, 0], [0, 1, 0], [1, 0, 0]]
2484
+ targets = [[0, 1, 0], [0, -1, 0], [-1, 0, 0]]
2485
+
2486
+ qr = alignTo(vec, targets)
2487
+ vecRotated = applyQuat(qr, vec)
2488
+
2489
+ numpy.allclose(vecRotated, targets) # True
2490
+
2491
+ Get matrix which orients vertices towards a point::
2492
+
2493
+ point = [5, 6, 7]
2494
+ vec = [0, 0, -1] # initial facing is -Z (forward in GL)
2495
+
2496
+ targetVec = normalize(point - vec)
2497
+ qr = alignTo(vec, targetVec) # get rotation to align
2498
+
2499
+ M = quatToMatrix(qr) # 4x4 transformation matrix
2500
+
2501
+ """
2502
+ # based off Quaternion::align from Quaternion.hpp from OpenMP
2503
+ if out is None:
2504
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2505
+ else:
2506
+ dtype = np.dtype(out.dtype).type
2507
+
2508
+ v = normalize(v, dtype=dtype)
2509
+ t = normalize(t, dtype=dtype)
2510
+
2511
+ if out is None:
2512
+ if v.ndim == 1:
2513
+ toReturn = np.zeros((4,), dtype=dtype)
2514
+ else:
2515
+ toReturn = np.zeros((v.shape[0], 4), dtype=dtype)
2516
+ else:
2517
+ toReturn = out
2518
+
2519
+ qr, v2d, t2d = np.atleast_2d(toReturn, v, t)
2520
+
2521
+ b = bisector(v2d, t2d, norm=True, dtype=dtype)
2522
+ cosHalfAngle = dot(v2d, b, dtype=dtype)
2523
+
2524
+ nonparallel = cosHalfAngle > 0.0 # rotation is not 180 degrees
2525
+ qr[nonparallel, :3] = cross(v2d[nonparallel], b[nonparallel], dtype=dtype)
2526
+ qr[nonparallel, 3] = cosHalfAngle[nonparallel]
2527
+
2528
+ if np.all(nonparallel): # don't bother handling special cases
2529
+ return toReturn + 0.0
2530
+
2531
+ # deal with cases where the vectors are facing exact opposite directions
2532
+ ry = np.logical_and(np.abs(v2d[:, 0]) >= np.abs(v2d[:, 1]), ~nonparallel)
2533
+ rx = np.logical_and(~ry, ~nonparallel)
2534
+
2535
+ getLength = lambda x, y: np.sqrt(x * x + y * y)
2536
+ if not np.all(rx):
2537
+ invLength = getLength(v2d[ry, 0], v2d[ry, 2])
2538
+ invLength = np.where(invLength > 0.0, 1.0 / invLength, invLength) # avoid x / 0
2539
+ qr[ry, 0] = -v2d[ry, 2] * invLength
2540
+ qr[ry, 2] = v2d[ry, 0] * invLength
2541
+
2542
+ if not np.all(ry): # skip if all the same edge case
2543
+ invLength = getLength(v2d[rx, 1], v2d[rx, 2])
2544
+ invLength = np.where(invLength > 0.0, 1.0 / invLength, invLength)
2545
+ qr[rx, 1] = v2d[rx, 2] * invLength
2546
+ qr[rx, 2] = -v2d[rx, 1] * invLength
2547
+
2548
+ return toReturn + 0.0
2549
+
2550
+
2551
+ def matrixToQuat(m, out=None, dtype=None):
2552
+ """Convert a rotation matrix to a quaternion.
2553
+
2554
+ Parameters
2555
+ ----------
2556
+ m : array_like
2557
+ 3x3 rotation matrix (row-major). A 4x4 affine transformation matrix may
2558
+ be provided, assuming the top-left 3x3 sub-matrix is orthonormal and
2559
+ is a rotation group.
2560
+ out : ndarray, optional
2561
+ Optional output array. Must be same `shape` and `dtype` as the expected
2562
+ output if `out` was not specified.
2563
+ dtype : dtype or str, optional
2564
+ Data type for computations can either be 'float32' or 'float64'. If
2565
+ `out` is specified, the data type of `out` is used and this argument is
2566
+ ignored. If `out` is not provided, 'float64' is used by default.
2567
+
2568
+ Returns
2569
+ -------
2570
+ ndarray
2571
+ Rotation quaternion.
2572
+
2573
+ Notes
2574
+ -----
2575
+ * Depending on the input, returned quaternions may not be exactly the same
2576
+ as the one used to construct the rotation matrix (i.e. by calling
2577
+ `quatToMatrix`), typically when a large rotation angle is used. However,
2578
+ the returned quaternion should result in the same rotation when applied to
2579
+ points.
2580
+
2581
+ Examples
2582
+ --------
2583
+ Converting a rotation matrix from the OpenGL matrix stack to a quaternion::
2584
+
2585
+ glRotatef(45., -1, 0, 0)
2586
+
2587
+ m = np.zeros((4, 4), dtype='float32') # store the matrix
2588
+ GL.glGetFloatv(
2589
+ GL.GL_MODELVIEW_MATRIX,
2590
+ m.ctypes.data_as(ctypes.POINTER(ctypes.c_float)))
2591
+
2592
+ qr = matrixToQuat(m.T) # must be transposed
2593
+
2594
+ Interpolation between two 4x4 transformation matrices::
2595
+
2596
+ interpWeight = 0.5
2597
+
2598
+ posStart = mStart[:3, 3]
2599
+ oriStart = matrixToQuat(mStart)
2600
+
2601
+ posEnd = mEnd[:3, 3]
2602
+ oriEnd = matrixToQuat(mEnd)
2603
+
2604
+ oriInterp = slerp(qStart, qEnd, interpWeight)
2605
+ posInterp = lerp(posStart, posEnd, interpWeight)
2606
+
2607
+ mInterp = posOriToMatrix(posInterp, oriInterp)
2608
+
2609
+ """
2610
+ # based off example `Maths - Conversion Matrix to Quaternion` from
2611
+ # https://www.euclideanspace.com/
2612
+ if out is None:
2613
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2614
+ else:
2615
+ dtype = np.dtype(out.dtype).type
2616
+
2617
+ m = np.asarray(m, dtype=dtype)
2618
+
2619
+ if m.shape == (4, 4,) or m.shape == (3, 4,):
2620
+ m = m[:3, :3] # keep only rotation group sub-matrix
2621
+ elif m.shape == (3, 3,):
2622
+ pass # fine, nop
2623
+ else:
2624
+ raise ValueError("Input matrix `m` must be 3x3 or 4x4.")
2625
+
2626
+ toReturn = np.zeros((4,), dtype=dtype) if out is None else out
2627
+
2628
+ tr = m[0, 0] + m[1, 1] + m[2, 2]
2629
+ if tr > 0.0:
2630
+ s = np.sqrt(tr + 1.0) * 2.0
2631
+ toReturn[3] = dtype(0.25) * s
2632
+ toReturn[0] = (m[2, 1] - m[1, 2]) / s
2633
+ toReturn[1] = (m[0, 2] - m[2, 0]) / s
2634
+ toReturn[2] = (m[1, 0] - m[0, 1]) / s
2635
+ elif m[0, 0] > m[1, 1] and m[0, 0] > m[2, 2]:
2636
+ s = np.sqrt(dtype(1.0) + m[0, 0] - m[1, 1] - m[2, 2]) * dtype(2.0)
2637
+ toReturn[3] = (m[2, 1] - m[1, 2]) / s
2638
+ toReturn[0] = dtype(0.25) * s
2639
+ toReturn[1] = (m[0, 1] + m[1, 0]) / s
2640
+ toReturn[2] = (m[0, 2] + m[2, 0]) / s
2641
+ elif m[1, 1] > m[2, 2]:
2642
+ s = np.sqrt(dtype(1.0) + m[1, 1] - m[0, 0] - m[2, 2]) * dtype(2.0)
2643
+ toReturn[3] = (m[0, 2] - m[2, 0]) / s
2644
+ toReturn[0] = (m[0, 1] + m[1, 0]) / s
2645
+ toReturn[1] = dtype(0.25) * s
2646
+ toReturn[2] = (m[1, 2] + m[2, 1]) / s
2647
+ else:
2648
+ s = np.sqrt(dtype(1.0) + m[2, 2] - m[0, 0] - m[1, 1]) * dtype(2.0)
2649
+ toReturn[3] = (m[1, 0] - m[0, 1]) / s
2650
+ toReturn[0] = (m[0, 2] + m[2, 0]) / s
2651
+ toReturn[1] = (m[1, 2] + m[2, 1]) / s
2652
+ toReturn[2] = dtype(0.25) * s
2653
+
2654
+ return toReturn
2655
+
2656
+
2657
+ # ------------------------------------------------------------------------------
2658
+ # Matrix Operations
2659
+ #
2660
+
2661
+ def quatToMatrix(q, out=None, dtype=None):
2662
+ """Create a 4x4 rotation matrix from a quaternion.
2663
+
2664
+ Parameters
2665
+ ----------
2666
+ q : tuple, list or ndarray of float
2667
+ Quaternion to convert in form [x, y, z, w] where w is real and x, y, z
2668
+ are imaginary components.
2669
+ out : ndarray or None
2670
+ Optional output array. Must be same `shape` and `dtype` as the expected
2671
+ output if `out` was not specified.
2672
+ dtype : dtype or str, optional
2673
+ Data type for computations can either be 'float32' or 'float64'. If
2674
+ `out` is specified, the data type of `out` is used and this argument is
2675
+ ignored. If `out` is not provided, 'float64' is used by default.
2676
+
2677
+ Returns
2678
+ -------
2679
+ ndarray or None
2680
+ 4x4 rotation matrix in row-major order.
2681
+
2682
+ Examples
2683
+ --------
2684
+ Convert a quaternion to a rotation matrix::
2685
+
2686
+ point = [0., 1., 0., 1.] # 4-vector form [x, y, z, 1.0]
2687
+ ori = [0., 0., 0., 1.]
2688
+ rotMat = quatToMatrix(ori)
2689
+ # rotate 'point' using matrix multiplication
2690
+ newPoint = np.matmul(rotMat.T, point) # returns [-1., 0., 0., 1.]
2691
+
2692
+ Rotate all points in an array (each row is a coordinate)::
2693
+
2694
+ points = np.asarray([[0., 0., 0., 1.],
2695
+ [0., 1., 0., 1.],
2696
+ [1., 1., 0., 1.]])
2697
+ newPoints = points.dot(rotMat)
2698
+
2699
+ Notes
2700
+ -----
2701
+ * Quaternions are normalized prior to conversion.
2702
+
2703
+ """
2704
+ # based off implementations from
2705
+ # https://github.com/glfw/glfw/blob/master/deps/linmath.h
2706
+ if out is None:
2707
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2708
+ R = np.zeros((4, 4,), dtype=dtype)
2709
+ else:
2710
+ dtype = np.dtype(out.dtype).type
2711
+ R = out
2712
+ R.fill(0.0)
2713
+
2714
+ q = normalize(q, dtype=dtype)
2715
+ b, c, d, a = q[:]
2716
+ vsqr = np.square(q)
2717
+
2718
+ u = dtype(2.0)
2719
+ R[0, 0] = vsqr[3] + vsqr[0] - vsqr[1] - vsqr[2]
2720
+ R[1, 0] = u * (b * c + a * d)
2721
+ R[2, 0] = u * (b * d - a * c)
2722
+
2723
+ R[0, 1] = u * (b * c - a * d)
2724
+ R[1, 1] = vsqr[3] - vsqr[0] + vsqr[1] - vsqr[2]
2725
+ R[2, 1] = u * (c * d + a * b)
2726
+
2727
+ R[0, 2] = u * (b * d + a * c)
2728
+ R[1, 2] = u * (c * d - a * b)
2729
+ R[2, 2] = vsqr[3] - vsqr[0] - vsqr[1] + vsqr[2]
2730
+
2731
+ R[3, 3] = dtype(1.0)
2732
+ R[:, :] += 0.0 # remove negative zeros
2733
+
2734
+ return R
2735
+
2736
+
2737
+ def scaleMatrix(s, out=None, dtype=None):
2738
+ """Create a scaling matrix.
2739
+
2740
+ The resulting matrix is the same as a generated by a `glScale` call.
2741
+
2742
+ Parameters
2743
+ ----------
2744
+ s : array_like, float or int
2745
+ Scaling factor(s). If `s` is scalar (float), scaling will be uniform.
2746
+ Providing a vector of scaling values [sx, sy, sz] will result in an
2747
+ anisotropic scaling matrix if any of the values differ.
2748
+ out : ndarray, optional
2749
+ Optional output array. Must be same `shape` and `dtype` as the expected
2750
+ output if `out` was not specified.
2751
+ dtype : dtype or str, optional
2752
+ Data type for computations can either be 'float32' or 'float64'. If
2753
+ `out` is specified, the data type of `out` is used and this argument is
2754
+ ignored. If `out` is not provided, 'float64' is used by default.
2755
+
2756
+ Returns
2757
+ -------
2758
+ ndarray
2759
+ 4x4 scaling matrix in row-major order.
2760
+
2761
+ """
2762
+ # from glScale
2763
+ if out is None:
2764
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2765
+ S = np.zeros((4, 4,), dtype=dtype)
2766
+ else:
2767
+ dtype = np.dtype(out.dtype).type
2768
+ S = out
2769
+ S.fill(0.0)
2770
+
2771
+ if isinstance(s, (float, int,)):
2772
+ S[0, 0] = S[1, 1] = S[2, 2] = dtype(s)
2773
+ else:
2774
+ S[0, 0] = dtype(s[0])
2775
+ S[1, 1] = dtype(s[1])
2776
+ S[2, 2] = dtype(s[2])
2777
+
2778
+ S[3, 3] = 1.0
2779
+
2780
+ return S
2781
+
2782
+
2783
+ def rotationMatrix(angle, axis=(0., 0., -1.), out=None, dtype=None):
2784
+ """Create a rotation matrix.
2785
+
2786
+ The resulting matrix will rotate points about `axis` by `angle`. The
2787
+ resulting matrix is similar to that produced by a `glRotate` call.
2788
+
2789
+ Parameters
2790
+ ----------
2791
+ angle : float
2792
+ Rotation angle in degrees.
2793
+ axis : array_like or str
2794
+ Axis vector components or axis name. If a vector, input must be length
2795
+ 3. A string can be specified for rotations about world axes (eg. `'+x'`,
2796
+ `'-z'`, `'+y'`, etc.)
2797
+ out : ndarray, optional
2798
+ Optional output array. Must be same `shape` and `dtype` as the expected
2799
+ output if `out` was not specified.
2800
+ dtype : dtype or str, optional
2801
+ Data type for computations can either be 'float32' or 'float64'. If
2802
+ `out` is specified, the data type of `out` is used and this argument is
2803
+ ignored. If `out` is not provided, 'float64' is used by default.
2804
+
2805
+ Returns
2806
+ -------
2807
+ ndarray
2808
+ 4x4 scaling matrix in row-major order. Will be the same array as `out`
2809
+ if specified, if not, a new array will be allocated.
2810
+
2811
+ Notes
2812
+ -----
2813
+ * Vector `axis` is normalized before creating the matrix.
2814
+
2815
+ """
2816
+ if out is None:
2817
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2818
+ R = np.zeros((4, 4,), dtype=dtype)
2819
+ else:
2820
+ dtype = np.dtype(out.dtype).type
2821
+ R = out
2822
+ R.fill(0.0)
2823
+
2824
+ try:
2825
+ axis = VEC_AXES[axis] if isinstance(axis, str) else axis
2826
+ except KeyError:
2827
+ raise ValueError(
2828
+ "Value of `axis` must be either '+x', '-x', '+y', '-x', '+z' or "
2829
+ "'-z' or length 3 vector.")
2830
+
2831
+ axis = normalize(axis, dtype=dtype)
2832
+ if np.count_nonzero(axis) == 0:
2833
+ raise ValueError("Value for `axis` is zero-length.")
2834
+
2835
+ angle = np.radians(angle, dtype=dtype)
2836
+ c = np.cos(angle, dtype=dtype)
2837
+ s = np.sin(angle, dtype=dtype)
2838
+
2839
+ xs, ys, zs = axis * s
2840
+ x2, y2, z2 = np.square(axis) # type inferred by input
2841
+ x, y, z = axis
2842
+ cd = dtype(1.0) - c
2843
+
2844
+ R[0, 0] = x2 * cd + c
2845
+ R[0, 1] = x * y * cd - zs
2846
+ R[0, 2] = x * z * cd + ys
2847
+
2848
+ R[1, 0] = y * x * cd + zs
2849
+ R[1, 1] = y2 * cd + c
2850
+ R[1, 2] = y * z * cd - xs
2851
+
2852
+ R[2, 0] = x * z * cd - ys
2853
+ R[2, 1] = y * z * cd + xs
2854
+ R[2, 2] = z2 * cd + c
2855
+
2856
+ R[3, 3] = dtype(1.0)
2857
+ R[:, :] += 0.0 # remove negative zeros
2858
+
2859
+ return R
2860
+
2861
+
2862
+ def translationMatrix(t, out=None, dtype=None):
2863
+ """Create a translation matrix.
2864
+
2865
+ The resulting matrix is the same as generated by a `glTranslate` call.
2866
+
2867
+ Parameters
2868
+ ----------
2869
+ t : ndarray, tuple, or list of float
2870
+ Translation vector [tx, ty, tz].
2871
+ out : ndarray, optional
2872
+ Optional output array. Must be same `shape` and `dtype` as the expected
2873
+ output if `out` was not specified.
2874
+ dtype : dtype or str, optional
2875
+ Data type for computations can either be 'float32' or 'float64'. If
2876
+ `out` is specified, the data type of `out` is used and this argument is
2877
+ ignored. If `out` is not provided, 'float64' is used by default.
2878
+
2879
+ Returns
2880
+ -------
2881
+ ndarray
2882
+ 4x4 translation matrix in row-major order. Will be the same array as
2883
+ `out` if specified, if not, a new array will be allocated.
2884
+
2885
+ """
2886
+ if out is None:
2887
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2888
+ T = np.identity(4, dtype=dtype)
2889
+ else:
2890
+ dtype = np.dtype(out.dtype).type
2891
+ T = out
2892
+ T.fill(0.0)
2893
+ np.fill_diagonal(T, 1.0)
2894
+
2895
+ T[:3, 3] = np.asarray(t, dtype=dtype)
2896
+
2897
+ return T
2898
+
2899
+
2900
+ def invertMatrix(m, out=None, dtype=None):
2901
+ """Invert a square matrix.
2902
+
2903
+ Parameters
2904
+ ----------
2905
+ m : array_like
2906
+ Square matrix to invert. Inputs can be 4x4, 3x3 or 2x2.
2907
+ out : ndarray, optional
2908
+ Optional output array. Must be same `shape` and `dtype` as the expected
2909
+ output if `out` was not specified.
2910
+ dtype : dtype or str, optional
2911
+ Data type for computations can either be 'float32' or 'float64'. If
2912
+ `out` is specified, the data type of `out` is used and this argument is
2913
+ ignored. If `out` is not provided, 'float64' is used by default.
2914
+
2915
+ Returns
2916
+ -------
2917
+ ndarray
2918
+ Matrix which is the inverse of `m`
2919
+
2920
+ """
2921
+ if out is None:
2922
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
2923
+ else:
2924
+ dtype = out.dtype
2925
+
2926
+ m = np.asarray(m, dtype=dtype) # input as array
2927
+ toReturn = np.empty_like(m, dtype=dtype) if out is None else out
2928
+ toReturn.fill(0.0)
2929
+
2930
+ if m.shape == (4, 4,):
2931
+ # Special handling of 4x4 matrices, if affine and orthogonal
2932
+ # (homogeneous), simply transpose the matrix rather than doing a full
2933
+ # invert.
2934
+ if isOrthogonal(m[:3, :3]) and isAffine(m):
2935
+ rg = m[:3, :3]
2936
+ toReturn[:3, :3] = rg.T
2937
+ toReturn[:3, 3] = -m[:3, 3].dot(rg)
2938
+ #toReturn[0, 3] = \
2939
+ # -(m[0, 0] * m[0, 3] + m[1, 0] * m[1, 3] + m[2, 0] * m[2, 3])
2940
+ #toReturn[1, 3] = \
2941
+ # -(m[0, 1] * m[0, 3] + m[1, 1] * m[1, 3] + m[2, 1] * m[2, 3])
2942
+ #toReturn[2, 3] = \
2943
+ # -(m[0, 2] * m[0, 3] + m[1, 2] * m[1, 3] + m[2, 2] * m[2, 3])
2944
+ toReturn[3, 3] = 1.0
2945
+ else:
2946
+ toReturn[:, :] = np.linalg.inv(m)
2947
+ elif m.shape[0] == m.shape[1]: # square, other than 4x4
2948
+ toReturn[:, :] = np.linalg.inv(m) if not isOrthogonal(m) else m.T
2949
+ else:
2950
+ toReturn[:, :] = np.linalg.inv(m)
2951
+
2952
+ return toReturn
2953
+
2954
+
2955
+ def multMatrix(matrices, reverse=False, out=None, dtype=None):
2956
+ """Chain multiplication of two or more matrices.
2957
+
2958
+ Multiply a sequence of matrices together, reducing to a single product
2959
+ matrix. For instance, specifying `matrices` the sequence of matrices (A, B,
2960
+ C, D) will return the product (((AB)C)D). If `reverse=True`, the product
2961
+ will be (A(B(CD))).
2962
+
2963
+ Alternatively, a 3D array can be specified to `matrices` as a stack, where
2964
+ an index along axis 0 references a 2D slice storing matrix values. The
2965
+ product of the matrices along the axis will be returned. This is a bit more
2966
+ efficient than specifying separate matrices in a sequence, but the
2967
+ difference is negligible when only a few matrices are being multiplied.
2968
+
2969
+ Parameters
2970
+ ----------
2971
+ matrices : list, tuple or ndarray
2972
+ Sequence or stack of matrices to multiply. All matrices must have the
2973
+ same dimensions.
2974
+ reverse : bool, optional
2975
+ Multiply matrices right-to-left. This is useful when dealing with
2976
+ transformation matrices, where the order of operations for transforms
2977
+ will appear the same as the order the matrices are specified. Default is
2978
+ 'False'. When `True`, this function behaves similarly to
2979
+ :func:`concatenate`.
2980
+ out : ndarray, optional
2981
+ Optional output array. Must be same `shape` and `dtype` as the expected
2982
+ output if `out` was not specified.
2983
+ dtype : dtype or str, optional
2984
+ Data type for computations can either be 'float32' or 'float64'. If
2985
+ `out` is specified, the data type of `out` is used and this argument is
2986
+ ignored. If `out` is not provided, 'float64' is used by default.
2987
+
2988
+ Returns
2989
+ -------
2990
+ ndarray
2991
+ Matrix product.
2992
+
2993
+ Notes
2994
+ -----
2995
+ * You may use `numpy.matmul` when dealing with only two matrices instead of
2996
+ `multMatrix`.
2997
+ * If a single matrix is specified, the returned product will have the same
2998
+ values.
2999
+
3000
+ Examples
3001
+ --------
3002
+ Chain multiplication of SRT matrices::
3003
+
3004
+ translate = translationMatrix((0.035, 0, -0.5))
3005
+ rotate = rotationMatrix(90.0, (0, 1, 0))
3006
+ scale = scaleMatrix(2.0)
3007
+
3008
+ SRT = multMatrix((translate, rotate, scale))
3009
+
3010
+ Same as above, but matrices are in a 3x4x4 array::
3011
+
3012
+ matStack = np.array((translate, rotate, scale))
3013
+
3014
+ # or ...
3015
+ # matStack = np.zeros((3, 4, 4))
3016
+ # matStack[0, :, :] = translate
3017
+ # matStack[1, :, :] = rotate
3018
+ # matStack[2, :, :] = scale
3019
+
3020
+ SRT = multMatrix(matStack)
3021
+
3022
+ Using `reverse=True` allows you to specify transformation matrices in the
3023
+ order which they will be applied::
3024
+
3025
+ SRT = multMatrix(np.array((scale, rotate, translate)), reverse=True)
3026
+
3027
+ """
3028
+ # convert matrix types
3029
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3030
+ matrices = np.asarray(matrices, dtype=dtype) # convert to array
3031
+
3032
+ matrices = np.atleast_3d(matrices)
3033
+ prod = functools.reduce(
3034
+ np.matmul, matrices[:] if not reverse else matrices[::-1])
3035
+
3036
+ if out is not None:
3037
+ toReturn = out
3038
+ toReturn[:, :] = prod
3039
+ else:
3040
+ toReturn = prod
3041
+
3042
+ return toReturn
3043
+
3044
+
3045
+ def concatenate(matrices, out=None, dtype=None):
3046
+ """Concatenate matrix transformations.
3047
+
3048
+ Chain multiply matrices describing transform operations into a single matrix
3049
+ product, that when applied, transforms points and vectors with each
3050
+ operation in the order they're specified.
3051
+
3052
+ Parameters
3053
+ ----------
3054
+ matrices : list or tuple
3055
+ List of matrices to concatenate. All matrices must all have the same
3056
+ size, usually 4x4 or 3x3.
3057
+ out : ndarray, optional
3058
+ Optional output array. Must be same `shape` and `dtype` as the expected
3059
+ output if `out` was not specified.
3060
+ dtype : dtype or str, optional
3061
+ Data type for computations can either be 'float32' or 'float64'. If
3062
+ `out` is specified, the data type of `out` is used and this argument is
3063
+ ignored. If `out` is not provided, 'float64' is used by default.
3064
+
3065
+ Returns
3066
+ -------
3067
+ ndarray
3068
+ Matrix product.
3069
+
3070
+ See Also
3071
+ --------
3072
+ * multMatrix : Chain multiplication of matrices.
3073
+
3074
+ Notes
3075
+ -----
3076
+ * This function should only be used for combining transformation matrices.
3077
+ Use `multMatrix` for general matrix chain multiplication.
3078
+
3079
+ Examples
3080
+ --------
3081
+ Create an SRT (scale, rotate, and translate) matrix to convert model-space
3082
+ coordinates to world-space::
3083
+
3084
+ S = scaleMatrix([2.0, 2.0, 2.0]) # scale model 2x
3085
+ R = rotationMatrix(-90., [0., 0., -1]) # rotate -90 about -Z axis
3086
+ T = translationMatrix([0., 0., -5.]) # translate point 5 units away
3087
+
3088
+ # product matrix when applied to points will scale, rotate and transform
3089
+ # in that order.
3090
+ SRT = concatenate([S, R, T])
3091
+
3092
+ # transform a point in model-space coordinates to world-space
3093
+ pointModel = np.array([0., 1., 0., 1.])
3094
+ pointWorld = np.matmul(SRT, pointModel.T) # point in WCS
3095
+ # ... or ...
3096
+ pointWorld = matrixApply(SRT, pointModel)
3097
+
3098
+ Create a model-view matrix from a world-space pose represented by an
3099
+ orientation (quaternion) and position (vector). The resulting matrix will
3100
+ transform model-space coordinates to eye-space::
3101
+
3102
+ # eye pose as quaternion and vector
3103
+ stimOri = quatFromAxisAngle([0., 0., -1.], -45.0)
3104
+ stimPos = [0., 1.5, -5.]
3105
+
3106
+ # create model matrix
3107
+ R = quatToMatrix(stimOri)
3108
+ T = translationMatrix(stimPos)
3109
+ M = concatenate(R, T) # model matrix
3110
+
3111
+ # create a view matrix, can also be represented as 'pos' and 'ori'
3112
+ eyePos = [0., 1.5, 0.]
3113
+ eyeFwd = [0., 0., -1.]
3114
+ eyeUp = [0., 1., 0.]
3115
+ V = lookAt(eyePos, eyeFwd, eyeUp) # from viewtools
3116
+
3117
+ # modelview matrix
3118
+ MV = concatenate([M, V])
3119
+
3120
+ You can put the created matrix in the OpenGL matrix stack as shown below.
3121
+ Note that the matrix must have a 32-bit floating-point data type and needs
3122
+ to be loaded transposed since OpenGL takes matrices in column-major order::
3123
+
3124
+ GL.glMatrixMode(GL.GL_MODELVIEW)
3125
+
3126
+ # pyglet
3127
+ MV = np.asarray(MV, dtype='float32') # must be 32-bit float!
3128
+ ptrMV = MV.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
3129
+ GL.glLoadTransposeMatrixf(ptrMV)
3130
+
3131
+ # PyOpenGL
3132
+ MV = np.asarray(MV, dtype='float32')
3133
+ GL.glLoadTransposeMatrixf(MV)
3134
+
3135
+ Furthermore, you can convert a point from model-space to homogeneous
3136
+ clip-space by concatenating the projection, view, and model matrices::
3137
+
3138
+ # compute projection matrix, functions here are from 'viewtools'
3139
+ screenWidth = 0.52
3140
+ screenAspect = w / h
3141
+ scrDistance = 0.55
3142
+ frustum = computeFrustum(screenWidth, screenAspect, scrDistance)
3143
+ P = perspectiveProjectionMatrix(*frustum)
3144
+
3145
+ # multiply model-space points by MVP to convert them to clip-space
3146
+ MVP = concatenate([M, V, P])
3147
+ pointModel = np.array([0., 1., 0., 1.])
3148
+ pointClipSpace = np.matmul(MVP, pointModel.T)
3149
+
3150
+ """
3151
+ return multMatrix(matrices, reverse=True, out=out, dtype=dtype)
3152
+
3153
+
3154
+ def matrixFromEulerAngles(rx, ry, rz, degrees=True, out=None, dtype=None):
3155
+ """Construct a 4x4 rotation matrix from Euler angles.
3156
+
3157
+ Rotations are combined by first rotating about the X axis, then Y, and
3158
+ finally Z.
3159
+
3160
+ Parameters
3161
+ ----------
3162
+ rx, ry, rz : float
3163
+ Rotation angles (pitch, yaw, and roll).
3164
+ degrees : bool, optional
3165
+ Rotation angles are specified in degrees. If `False`, they will be
3166
+ assumed as radians. Default is `True`.
3167
+ out : ndarray, optional
3168
+ Optional output array. Must be same `shape` and `dtype` as the expected
3169
+ output if `out` was not specified.
3170
+ dtype : dtype or str, optional
3171
+ Data type for computations can either be 'float32' or 'float64'. If
3172
+ `out` is specified, the data type of `out` is used and this argument is
3173
+ ignored. If `out` is not provided, 'float64' is used by default.
3174
+
3175
+ Returns
3176
+ -------
3177
+ ndarray
3178
+ 4x4 rotation matrix.
3179
+
3180
+ Examples
3181
+ --------
3182
+ Demonstration of how a combination of axis-angle rotations is equivalent
3183
+ to a single call of `matrixFromEulerAngles`::
3184
+
3185
+ m1 = matrixFromEulerAngles(90., 45., 135.))
3186
+
3187
+ # construct rotation matrix from 3 orthogonal rotations
3188
+ rx = rotationMatrix(90., (1, 0, 0)) # x-axis
3189
+ ry = rotationMatrix(45., (0, 1, 0)) # y-axis
3190
+ rz = rotationMatrix(135., (0, 0, 1)) # z-axis
3191
+ m2 = concatenate([rz, ry, rx]) # note the order
3192
+
3193
+ print(numpy.allclose(m1, m2)) # True
3194
+
3195
+ Not only does `matrixFromEulerAngles` require less code, it also is
3196
+ considerably more efficient than constructing and multiplying multiple
3197
+ matrices.
3198
+
3199
+ """
3200
+ # from https://www.j3d.org/matrix_faq/matrfaq_latest.html
3201
+ if out is None:
3202
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3203
+ toReturn = np.zeros((4, 4,), dtype=dtype)
3204
+ else:
3205
+ dtype = np.dtype(dtype).type
3206
+ toReturn = out
3207
+ toReturn.fill(0.0)
3208
+
3209
+ angles = np.asarray([rx, ry, rz], dtype=dtype)
3210
+ if degrees:
3211
+ angles = np.radians(angles)
3212
+
3213
+ a, c, e = np.cos(angles)
3214
+ b, d, f = np.sin(angles)
3215
+ ad = a * d
3216
+ bd = b * d
3217
+
3218
+ toReturn[0, 0] = c * e
3219
+ toReturn[0, 1] = -c * f
3220
+ toReturn[0, 2] = d
3221
+ toReturn[1, 0] = bd * e + a * f
3222
+ toReturn[1, 1] = -bd * f + a * e
3223
+ toReturn[1, 2] = -b * c
3224
+ toReturn[2, 0] = -ad * e + b * f
3225
+ toReturn[2, 1] = ad * f + b * e
3226
+ toReturn[2, 2] = a * c
3227
+ toReturn[3, 3] = 1.0
3228
+
3229
+ return toReturn
3230
+
3231
+
3232
+ def isOrthogonal(m):
3233
+ """Check if a square matrix is orthogonal.
3234
+
3235
+ If a matrix is orthogonal, its columns form an orthonormal basis and is
3236
+ non-singular. An orthogonal matrix is invertible by simply taking the
3237
+ transpose of the matrix.
3238
+
3239
+ Parameters
3240
+ ----------
3241
+ m : array_like
3242
+ Square matrix, either 2x2, 3x3 or 4x4.
3243
+
3244
+ Returns
3245
+ -------
3246
+ bool
3247
+ `True` if the matrix is orthogonal.
3248
+
3249
+ """
3250
+ if not isinstance(m, (np.ndarray,)):
3251
+ m = np.asarray(m)
3252
+
3253
+ assert 2 <= m.shape[0] <= 4 # 2x2 to 4x4
3254
+ assert m.shape[0] == m.shape[1] # must be square
3255
+
3256
+ dtype = np.dtype(m.dtype).type
3257
+ return np.allclose(np.matmul(m.T, m, dtype=dtype),
3258
+ np.identity(m.shape[0], dtype))
3259
+
3260
+
3261
+ def isAffine(m):
3262
+ """Check if a 4x4 square matrix describes an affine transformation.
3263
+
3264
+ Parameters
3265
+ ----------
3266
+ m : array_like
3267
+ 4x4 transformation matrix.
3268
+
3269
+ Returns
3270
+ -------
3271
+ bool
3272
+ `True` if the matrix is affine.
3273
+
3274
+ """
3275
+ assert m.shape[0] == m.shape[1] == 4
3276
+
3277
+ if not isinstance(m, (np.ndarray,)):
3278
+ m = np.asarray(m)
3279
+
3280
+ dtype = np.dtype(m.dtype).type
3281
+ eps = np.finfo(dtype).eps
3282
+
3283
+ return np.all(m[3, :3] < eps) and (dtype(1.0) - m[3, 3]) < eps
3284
+
3285
+
3286
+ def applyMatrix(m, points, out=None, dtype=None):
3287
+ """Apply a matrix over a 2D array of points.
3288
+
3289
+ This function behaves similarly to the following `Numpy` statement::
3290
+
3291
+ points[:, :] = points.dot(m.T)
3292
+
3293
+ Transformation matrices specified to `m` must have dimensions 4x4, 3x4, 3x3
3294
+ or 2x2. With the exception of 4x4 matrices, input `points` must have the
3295
+ same number of columns as the matrix has rows. 4x4 matrices can be used to
3296
+ transform both Nx4 and Nx3 arrays.
3297
+
3298
+ Parameters
3299
+ ----------
3300
+ m : array_like
3301
+ Matrix with dimensions 2x2, 3x3, 3x4 or 4x4.
3302
+ points : array_like
3303
+ 2D array of points/coordinates to transform. Each row should have length
3304
+ appropriate for the matrix being used.
3305
+ out : ndarray, optional
3306
+ Optional output array. Must be same `shape` and `dtype` as the expected
3307
+ output if `out` was not specified.
3308
+ dtype : dtype or str, optional
3309
+ Data type for computations can either be 'float32' or 'float64'. If
3310
+ `out` is specified, the data type of `out` is used and this argument is
3311
+ ignored. If `out` is not provided, 'float64' is used by default.
3312
+
3313
+ Returns
3314
+ -------
3315
+ ndarray
3316
+ Transformed coordinates.
3317
+
3318
+ Notes
3319
+ -----
3320
+ * Input (`points`) and output (`out`) arrays cannot be the same instance for
3321
+ this function.
3322
+ * In the case of 4x4 input matrices, this function performs optimizations
3323
+ based on whether the input matrix is affine, greatly improving performance
3324
+ when working with Nx3 arrays.
3325
+
3326
+ Examples
3327
+ --------
3328
+ Construct a matrix and transform a point::
3329
+
3330
+ # identity 3x3 matrix for this example
3331
+ M = [[1.0, 0.0, 0.0],
3332
+ [0.0, 1.0, 0.0],
3333
+ [0.0, 0.0, 1.0]]
3334
+
3335
+ pnt = [1.0, 0.0, 0.0]
3336
+
3337
+ pntNew = applyMatrix(M, pnt)
3338
+
3339
+ Construct an SRT matrix (scale, rotate, transform) and transform an array of
3340
+ points::
3341
+
3342
+ S = scaleMatrix([5.0, 5.0, 5.0]) # scale 5x
3343
+ R = rotationMatrix(180., [0., 0., -1]) # rotate 180 degrees
3344
+ T = translationMatrix([0., 1.5, -3.]) # translate point up and away
3345
+ M = concatenate([S, R, T]) # create transform matrix
3346
+
3347
+ # points to transform
3348
+ points = np.array([[0., 1., 0., 1.], [-1., 0., 0., 1.]]) # [x, y, z, w]
3349
+ newPoints = applyMatrix(M, points) # apply the transformation
3350
+
3351
+ Convert CIE-XYZ colors to sRGB::
3352
+
3353
+ sRGBMatrix = [[3.2404542, -1.5371385, -0.4985314],
3354
+ [-0.969266, 1.8760108, 0.041556 ],
3355
+ [0.0556434, -0.2040259, 1.0572252]]
3356
+
3357
+ colorsRGB = applyMatrix(sRGBMatrix, colorsXYZ)
3358
+
3359
+ """
3360
+ if out is None:
3361
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3362
+ else:
3363
+ dtype = np.dtype(out.dtype).type
3364
+
3365
+ m = np.asarray(m, dtype=dtype)
3366
+ points = np.asarray(points, dtype=dtype)
3367
+
3368
+ if out is None:
3369
+ toReturn = np.zeros_like(points, dtype=dtype)
3370
+ else:
3371
+ if id(out) == id(points):
3372
+ raise ValueError('Output array cannot be same as input.')
3373
+ toReturn = out
3374
+
3375
+ pout, p = np.atleast_2d(toReturn, points)
3376
+
3377
+ if m.shape[0] == m.shape[1] == 4: # 4x4 matrix
3378
+ if pout.shape[1] == 3: # Nx3
3379
+ pout[:, :] = p.dot(m[:3, :3].T)
3380
+ pout += m[:3, 3]
3381
+ # find `rcpW` as suggested in OpenXR's xr_linear.h header
3382
+ # reciprocal of `w` if the matrix is not orthonormal
3383
+ if not isAffine(m):
3384
+ rcpW = 1.0 / (m[3, 0] * p[:, 0] +
3385
+ m[3, 1] * p[:, 1] +
3386
+ m[3, 2] * p[:, 2] +
3387
+ m[3, 3])
3388
+ pout *= rcpW[:, np.newaxis]
3389
+ elif pout.shape[1] == 4: # Nx4
3390
+ pout[:, :] = p.dot(m.T)
3391
+ else:
3392
+ raise ValueError(
3393
+ 'Input array dimensions invalid. Should be Nx3 or Nx4 when '
3394
+ 'input matrix is 4x4.')
3395
+ elif m.shape[0] == 3 and m.shape[1] == 4: # 3x4 matrix
3396
+ if pout.shape[1] == 3: # Nx3
3397
+ pout[:, :] = p.dot(m[:3, :3].T)
3398
+ pout += m[:3, 3]
3399
+ else:
3400
+ raise ValueError(
3401
+ 'Input array dimensions invalid. Should be Nx3 when input '
3402
+ 'matrix is 3x4.')
3403
+ elif m.shape[0] == m.shape[1] == 3: # 3x3 matrix, e.g colors
3404
+ if pout.shape[1] == 3: # Nx3
3405
+ pout[:, :] = p.dot(m.T)
3406
+ else:
3407
+ raise ValueError(
3408
+ 'Input array dimensions invalid. Should be Nx3 when '
3409
+ 'input matrix is 3x3.')
3410
+ elif m.shape[0] == m.shape[1] == pout.shape[1] == 2: # 2x2 matrix
3411
+ if pout.shape[1] == 2: # Nx2
3412
+ pout[:, :] = p.dot(m.T)
3413
+ else:
3414
+ raise ValueError(
3415
+ 'Input array dimensions invalid. Should be Nx2 when '
3416
+ 'input matrix is 2x2.')
3417
+ else:
3418
+ raise ValueError(
3419
+ 'Only a square matrix with dimensions 2, 3 or 4 can be used.')
3420
+
3421
+ return toReturn
3422
+
3423
+
3424
+ def posOriToMatrix(pos, ori, out=None, dtype=None):
3425
+ """Convert a rigid body pose to a 4x4 transformation matrix.
3426
+
3427
+ A pose is represented by a position coordinate `pos` and orientation
3428
+ quaternion `ori`.
3429
+
3430
+ Parameters
3431
+ ----------
3432
+ pos : ndarray, tuple, or list of float
3433
+ Position vector [x, y, z].
3434
+ ori : tuple, list or ndarray of float
3435
+ Orientation quaternion in form [x, y, z, w] where w is real and x, y, z
3436
+ are imaginary components.
3437
+ out : ndarray, optional
3438
+ Optional output array. Must be same `shape` and `dtype` as the expected
3439
+ output if `out` was not specified.
3440
+ dtype : dtype or str, optional
3441
+ Data type for computations can either be 'float32' or 'float64'. If
3442
+ `out` is specified, the data type of `out` is used and this argument is
3443
+ ignored. If `out` is not provided, 'float64' is used by default.
3444
+
3445
+ Returns
3446
+ -------
3447
+ ndarray
3448
+ 4x4 transformation matrix.
3449
+
3450
+ """
3451
+ if out is None:
3452
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3453
+ toReturn = np.zeros((4, 4,), dtype=dtype)
3454
+ else:
3455
+ dtype = np.dtype(dtype).type
3456
+ toReturn = out
3457
+
3458
+ transMat = translationMatrix(pos, dtype=dtype)
3459
+ rotMat = quatToMatrix(ori, dtype=dtype)
3460
+
3461
+ return np.matmul(transMat, rotMat, out=toReturn)
3462
+
3463
+
3464
+ def transform(pos, ori, points, out=None, dtype=None):
3465
+ """Transform points using a position and orientation. Points are rotated
3466
+ then translated.
3467
+
3468
+ Parameters
3469
+ ----------
3470
+ pos : array_like
3471
+ Position vector in form [x, y, z] or [x, y, z, 1].
3472
+ ori : array_like
3473
+ Orientation quaternion in form [x, y, z, w] where w is real and x, y, z
3474
+ are imaginary components.
3475
+ points : array_like
3476
+ Point(s) [x, y, z] to transform.
3477
+ out : ndarray, optional
3478
+ Optional output array. Must be same `shape` and `dtype` as the expected
3479
+ output if `out` was not specified.
3480
+ dtype : dtype or str, optional
3481
+ Data type for computations can either be 'float32' or 'float64'. If
3482
+ `out` is specified, the data type of `out` is used and this argument is
3483
+ ignored. If `out` is not provided, 'float64' is used by default.
3484
+
3485
+ Returns
3486
+ -------
3487
+ ndarray
3488
+ Transformed points.
3489
+
3490
+ Examples
3491
+ --------
3492
+ Transform points by a position coordinate and orientation quaternion::
3493
+
3494
+ # rigid body pose
3495
+ ori = quatFromAxisAngle([0., 0., -1.], 90.0, degrees=True)
3496
+ pos = [0., 1.5, -3.]
3497
+ # points to transform
3498
+ points = np.array([[0., 1., 0., 1.], [-1., 0., 0., 1.]]) # [x, y, z, 1]
3499
+ outPoints = np.zeros_like(points) # output array
3500
+ transform(pos, ori, points, out=outPoints) # do the transformation
3501
+
3502
+ You can get the same results as the previous example using a matrix by doing
3503
+ the following::
3504
+
3505
+ R = rotationMatrix(90., [0., 0., -1])
3506
+ T = translationMatrix([0., 1.5, -3.])
3507
+ M = concatenate([R, T])
3508
+ applyMatrix(M, points, out=outPoints)
3509
+
3510
+ If you are defining transformations with quaternions and coordinates, you
3511
+ can skip the costly matrix creation process by using `transform`.
3512
+
3513
+ Notes
3514
+ -----
3515
+ * In performance tests, `applyMatrix` is noticeably faster than `transform`
3516
+ for very large arrays, however this is only true if you are applying the
3517
+ same transformation to all points.
3518
+ * If the input arrays for `points` or `pos` is Nx4, the last column is
3519
+ ignored.
3520
+
3521
+ """
3522
+ if out is None:
3523
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3524
+ else:
3525
+ dtype = np.dtype(dtype).type
3526
+
3527
+ pos = np.asarray(pos, dtype=dtype)
3528
+ ori = np.asarray(ori, dtype=dtype)
3529
+ points = np.asarray(points, dtype=dtype)
3530
+
3531
+ if out is None:
3532
+ toReturn = np.zeros_like(points, dtype=dtype)
3533
+ else:
3534
+ if out.shape != points.shape:
3535
+ raise ValueError(
3536
+ "Array 'out' and 'points' do not have matching shapes.")
3537
+
3538
+ toReturn = out
3539
+
3540
+ pout, points, pos2d = np.atleast_2d(toReturn, points, pos) # create 2d views
3541
+
3542
+ # apply rotation
3543
+ applyQuat(ori, points, out=pout)
3544
+
3545
+ # apply translation
3546
+ pout[:, 0] += pos2d[:, 0]
3547
+ pout[:, 1] += pos2d[:, 1]
3548
+ pout[:, 2] += pos2d[:, 2]
3549
+
3550
+ return toReturn
3551
+
3552
+
3553
+ def scale(sf, points, out=None, dtype=None):
3554
+ """Scale points by a factor.
3555
+
3556
+ This is useful for converting points between units, and to stretch or
3557
+ compress points along a given axis. Scaling can be uniform which the same
3558
+ factor is applied along all axes, or anisotropic along specific axes.
3559
+
3560
+ Parameters
3561
+ ----------
3562
+ sf : array_like or float
3563
+ Scaling factor. If scalar, all points will be scaled uniformly by that
3564
+ factor. If a vector, scaling will be anisotropic along an axis.
3565
+ points : array_like
3566
+ Point(s) [x, y, z] to scale.
3567
+ out : ndarray, optional
3568
+ Optional output array. Must be same `shape` and `dtype` as the expected
3569
+ output if `out` was not specified.
3570
+ dtype : dtype or str, optional
3571
+ Data type for computations can either be 'float32' or 'float64'. If
3572
+ `out` is specified, the data type of `out` is used and this argument is
3573
+ ignored. If `out` is not provided, 'float64' is used by default.
3574
+
3575
+ Returns
3576
+ -------
3577
+ ndarray
3578
+ Scaled points.
3579
+
3580
+ Examples
3581
+ --------
3582
+ Apply uniform scaling to points, here we scale to convert points in
3583
+ centimeters to meters::
3584
+
3585
+ CM_TO_METERS = 1.0 / 100.0
3586
+ pointsCM = [[1, 2, 3], [4, 5, 6], [-1, 1, 0]]
3587
+ pointsM = scale(CM_TO_METERS, pointsCM)
3588
+
3589
+ Anisotropic scaling along the X and Y axis::
3590
+
3591
+ pointsM = scale((SCALE_FACTOR_X, SCALE_FACTOR_Y), pointsCM)
3592
+
3593
+ Scale only on the X axis::
3594
+
3595
+ pointsM = scale((SCALE_FACTOR_X,), pointsCM)
3596
+
3597
+ Apply scaling on the Z axis only::
3598
+
3599
+ pointsM = scale((1.0, 1.0, SCALE_FACTOR_Z), pointsCM)
3600
+
3601
+ """
3602
+ if out is None:
3603
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3604
+ else:
3605
+ dtype = np.dtype(dtype).type
3606
+
3607
+ points = np.asarray(points, dtype=dtype)
3608
+ toReturn = np.zeros_like(points, dtype=dtype) if out is None else out
3609
+ toReturn, points = np.atleast_2d(toReturn, points) # create 2d views
3610
+
3611
+ # uniform scaling
3612
+ if isinstance(sf, (float, int)):
3613
+ toReturn[:, :] = points * sf
3614
+ elif isinstance(sf, (list, tuple, np.ndarray)): # anisotropic
3615
+ sf = np.asarray(sf, dtype=dtype)
3616
+ sfLen = len(sf)
3617
+ if sfLen <= 3:
3618
+ toReturn[:, :] = points
3619
+ toReturn[:, :len(sf)] *= sf
3620
+ else:
3621
+ raise ValueError("Scale factor array must have length <= 3.")
3622
+
3623
+ return toReturn
3624
+
3625
+
3626
+ def normalMatrix(modelMatrix, out=None, dtype=None):
3627
+ """Get the normal matrix from a model matrix.
3628
+
3629
+ Parameters
3630
+ ----------
3631
+ modelMatrix : array_like
3632
+ 4x4 homogeneous model matrix.
3633
+ out : ndarray, optional
3634
+ Optional output array. Must be same `shape` and `dtype` as the expected
3635
+ output if `out` was not specified.
3636
+ dtype : dtype or str, optional
3637
+ Data type for computations can either be 'float32' or 'float64'. If
3638
+ `out` is specified, the data type of `out` is used and this argument is
3639
+ ignored. If `out` is not provided, 'float64' is used by default.
3640
+
3641
+ Returns
3642
+ -------
3643
+ ndarray
3644
+ Normal matrix.
3645
+
3646
+ """
3647
+ if out is None:
3648
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3649
+ else:
3650
+ dtype = np.dtype(dtype).type
3651
+
3652
+ modelMatrix = np.asarray(modelMatrix, dtype=dtype)
3653
+
3654
+ toReturn = np.zeros((4, 4), dtype=dtype) if out is None else out
3655
+ toReturn[:, :] = np.linalg.inv(modelMatrix).T
3656
+
3657
+ return toReturn
3658
+
3659
+
3660
+ def forwardProject(objPos, modelView, proj, viewport=None, out=None, dtype=None):
3661
+ """Project a point in a scene to a window coordinate.
3662
+
3663
+ This function is similar to `gluProject` and can be used to find the window
3664
+ coordinate which a point projects to.
3665
+
3666
+ Parameters
3667
+ ----------
3668
+ objPos : array_like
3669
+ Object coordinates (x, y, z). If an Nx3 array of coordinates is
3670
+ specified, where each row contains a window coordinate this function
3671
+ will return an array of projected coordinates with the same size.
3672
+ modelView : array_like
3673
+ 4x4 combined model and view matrix for returned value to be object
3674
+ coordinates. Specify only the view matrix for a coordinate in the scene.
3675
+ proj : array_like
3676
+ 4x4 projection matrix used for rendering.
3677
+ viewport : array_like
3678
+ Viewport rectangle for the window [x, y, w, h]. If not specified, the
3679
+ returned values will be in normalized device coordinates.
3680
+ out : ndarray, optional
3681
+ Optional output array. Must be same `shape` and `dtype` as the expected
3682
+ output if `out` was not specified.
3683
+ dtype : dtype or str, optional
3684
+ Data type for computations can either be 'float32' or 'float64'. If
3685
+ `out` is specified, the data type of `out` is used and this argument is
3686
+ ignored. If `out` is not provided, 'float64' is used by default.
3687
+
3688
+ Returns
3689
+ -------
3690
+ ndarray
3691
+ Normalized device or viewport coordinates [x, y, z] of the point. The
3692
+ `z` component is similar to the depth buffer value for the object point.
3693
+
3694
+ """
3695
+ if out is None:
3696
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3697
+ else:
3698
+ dtype = np.dtype(dtype).type
3699
+
3700
+ toReturn = np.zeros_like(objPos, dtype=dtype) if out is None else out
3701
+ winCoord, objPos = np.atleast_2d(toReturn, objPos)
3702
+
3703
+ # transformation matrix
3704
+ mvp = np.matmul(proj, modelView)
3705
+
3706
+ # must have `w` for this one
3707
+ if objPos.shape[1] == 3:
3708
+ temp = np.zeros((objPos.shape[1], 4), dtype=dtype)
3709
+ temp[:, :3] = objPos
3710
+ objPos = temp
3711
+
3712
+ # transform the points
3713
+ objNorm = applyMatrix(mvp, objPos, dtype=dtype)
3714
+
3715
+ if viewport is not None:
3716
+ # if we have a viewport, transform it
3717
+ objNorm[:, :] += 1.0
3718
+ winCoord[:, 0] = viewport[0] + viewport[2] * objNorm[:, 0]
3719
+ winCoord[:, 1] = viewport[1] + viewport[3] * objNorm[:, 1]
3720
+ winCoord[:, 2] = objNorm[:, 2]
3721
+ winCoord[:, :] /= 2.0
3722
+ else:
3723
+ # already in NDC
3724
+ winCoord[:, :] = objNorm
3725
+
3726
+ return toReturn # ref to winCoord
3727
+
3728
+
3729
+ def reverseProject(winPos, modelView, proj, viewport=None, out=None, dtype=None):
3730
+ """Unproject window coordinates into object or scene coordinates.
3731
+
3732
+ This function works like `gluUnProject` and can be used to find to an object
3733
+ or scene coordinate at the point on-screen (mouse coordinate or pixel). The
3734
+ coordinate can then be used to create a direction vector from the viewer's
3735
+ eye location. Another use of this function is to convert depth buffer
3736
+ samples to object or scene coordinates. This is the inverse operation of
3737
+ :func:`forwardProject`.
3738
+
3739
+ Parameters
3740
+ ----------
3741
+ winPos : array_like
3742
+ Window coordinates (x, y, z). If `viewport` is not specified, these
3743
+ should be normalized device coordinates. If an Nx3 array of coordinates
3744
+ is specified, where each row contains a window coordinate this function
3745
+ will return an array of unprojected coordinates with the same size.
3746
+ Usually, you only need to specify the `x` and `y` coordinate, leaving
3747
+ `z` as zero. However, you can specify `z` if sampling from a depth map
3748
+ or buffer to convert a depth sample to an actual location.
3749
+ modelView : array_like
3750
+ 4x4 combined model and view matrix for returned value to be object
3751
+ coordinates. Specify only the view matrix for a coordinate in the scene.
3752
+ proj : array_like
3753
+ 4x4 projection matrix used for rendering.
3754
+ viewport : array_like
3755
+ Viewport rectangle for the window [x, y, w, h]. Do not specify one if
3756
+ `winPos` is in already in normalized device coordinates.
3757
+ out : ndarray, optional
3758
+ Optional output array. Must be same `shape` and `dtype` as the expected
3759
+ output if `out` was not specified.
3760
+ dtype : dtype or str, optional
3761
+ Data type for computations can either be 'float32' or 'float64'. If
3762
+ `out` is specified, the data type of `out` is used and this argument is
3763
+ ignored. If `out` is not provided, 'float64' is used by default.
3764
+
3765
+ Returns
3766
+ -------
3767
+ ndarray
3768
+ Object or scene coordinates.
3769
+
3770
+ """
3771
+ if out is None:
3772
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3773
+ else:
3774
+ dtype = np.dtype(dtype).type
3775
+
3776
+ toReturn = np.zeros_like(winPos, dtype=dtype) if out is None else out
3777
+ objCoord, winPos = np.atleast_2d(toReturn, winPos)
3778
+
3779
+ # get inverse of model and projection matrix
3780
+ invMVP = np.linalg.inv(np.matmul(proj, modelView))
3781
+
3782
+ if viewport is not None:
3783
+ # if we have a viewport, we need to transform to NDC first
3784
+ objCoord[:, 0] = ((2 * winPos[:, 0] - viewport[0]) / viewport[2])
3785
+ objCoord[:, 1] = ((2 * winPos[:, 1] - viewport[1]) / viewport[3])
3786
+ objCoord[:, 2] = 2 * winPos[:, 2]
3787
+ objCoord -= 1
3788
+ objCoord[:, :] = applyMatrix(invMVP, objCoord, dtype=dtype)
3789
+ else:
3790
+ # already in NDC, just apply
3791
+ objCoord[:, :] = applyMatrix(invMVP, winPos, dtype=dtype)
3792
+
3793
+ return toReturn # ref to objCoord
3794
+
3795
+
3796
+ # ------------------------------------------------------------------------------
3797
+ # Misc. Math Functions
3798
+ #
3799
+
3800
+ def zeroFix(a, inplace=False, threshold=None):
3801
+ """Fix zeros in an array.
3802
+
3803
+ This function truncates very small numbers in an array to zero and removes
3804
+ any negative zeros.
3805
+
3806
+ Parameters
3807
+ ----------
3808
+ a : ndarray
3809
+ Input array, must be a Numpy array.
3810
+ inplace : bool
3811
+ Fix an array inplace. If `True`, the input array will be modified,
3812
+ otherwise a new array will be returned with same `dtype` and shape with
3813
+ the fixed values.
3814
+ threshold : float or None
3815
+ Threshold for truncation. If `None`, the machine epsilon value for the
3816
+ input array `dtype` will be used. You can specify a custom threshold as
3817
+ a float.
3818
+
3819
+ Returns
3820
+ -------
3821
+ ndarray
3822
+ Output array with zeros fixed.
3823
+
3824
+ """
3825
+ toReturn = np.copy(a) if not inplace else a
3826
+ toReturn += 0.0 # remove negative zeros
3827
+ threshold = np.finfo(a.dtype).eps if threshold is None else float(threshold)
3828
+ toReturn[np.abs(toReturn) < threshold] = 0.0 # make zero
3829
+
3830
+ return toReturn
3831
+
3832
+
3833
+ def lensCorrection(xys, coefK=(1.0,), distCenter=(0., 0.), out=None,
3834
+ dtype=None):
3835
+ """Lens correction (or distortion) using the division model with even
3836
+ polynomial terms.
3837
+
3838
+ Calculate new vertex positions or texture coordinates to apply radial
3839
+ warping, such as 'pincushion' and 'barrel' distortion. This is to compensate
3840
+ for optical distortion introduced by lenses placed in the optical path of
3841
+ the viewer and the display (such as in an HMD).
3842
+
3843
+ See references[1]_ for implementation details.
3844
+
3845
+ Parameters
3846
+ ----------
3847
+ xys : array_like
3848
+ Nx2 list of vertex positions or texture coordinates to distort. Works
3849
+ correctly only if input values range between -1.0 and 1.0.
3850
+ coefK : array_like or float
3851
+ Distortion coefficients K_n. Specifying multiple values will add more
3852
+ polynomial terms to the distortion formula. Positive values will produce
3853
+ 'barrel' distortion, whereas negative will produce 'pincushion'
3854
+ distortion. In most cases, two or three coefficients are adequate,
3855
+ depending on the degree of distortion.
3856
+ distCenter : array_like, optional
3857
+ X and Y coordinate of the distortion center (eg. (0.2, -0.4)).
3858
+ out : ndarray, optional
3859
+ Optional output array. Must be same `shape` and `dtype` as the expected
3860
+ output if `out` was not specified.
3861
+ dtype : dtype or str, optional
3862
+ Data type for computations can either be 'float32' or 'float64'. If
3863
+ `out` is specified, the data type of `out` is used and this argument is
3864
+ ignored. If `out` is not provided, 'float64' is used by default.
3865
+
3866
+ Returns
3867
+ -------
3868
+ ndarray
3869
+ Array of distorted vertices.
3870
+
3871
+ Notes
3872
+ -----
3873
+ * At this time tangential distortion (i.e. due to a slant in the display)
3874
+ cannot be corrected for.
3875
+
3876
+ References
3877
+ ----------
3878
+ .. [1] Fitzgibbon, W. (2001). Simultaneous linear estimation of multiple
3879
+ view geometry and lens distortion. Proceedings of the 2001 IEEE Computer
3880
+ Society Conference on Computer Vision and Pattern Recognition (CVPR).
3881
+ IEEE.
3882
+
3883
+ Examples
3884
+ --------
3885
+ Creating a lens correction mesh with barrel distortion (eg. for HMDs)::
3886
+
3887
+ vertices, textureCoords, normals, faces = gltools.createMeshGrid(
3888
+ subdiv=11, tessMode='center')
3889
+
3890
+ # recompute vertex positions
3891
+ vertices[:, :2] = mt.lensCorrection(vertices[:, :2], coefK=(5., 5.))
3892
+
3893
+ """
3894
+ if out is None:
3895
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3896
+ else:
3897
+ dtype = np.dtype(dtype).type
3898
+
3899
+ if isinstance(coefK, (float, int,)):
3900
+ coefK = (coefK,)
3901
+
3902
+ xys = np.asarray(xys, dtype=dtype)
3903
+ coefK = np.asarray(coefK, dtype=dtype)
3904
+
3905
+ d_minus_c = xys - np.asarray(distCenter, dtype=dtype)
3906
+ r = np.power(length(d_minus_c, dtype=dtype)[:, np.newaxis],
3907
+ np.arange(len(coefK), dtype=dtype) * 2. + 2.)
3908
+
3909
+ toReturn = np.zeros_like(xys, dtype=dtype) if out is None else out
3910
+
3911
+ denom = dtype(1.0) + dot(coefK, r, dtype=dtype)
3912
+ toReturn[:, :] = xys + (d_minus_c / denom[:, np.newaxis])
3913
+
3914
+ return toReturn
3915
+
3916
+
3917
+ def lensCorrectionSpherical(xys, coefK=1.0, aspect=1.0, out=None, dtype=None):
3918
+ """Simple lens correction.
3919
+
3920
+ Lens correction for a spherical lenses with distortion centered at the
3921
+ middle of the display. See references[1]_ for implementation details.
3922
+
3923
+ Parameters
3924
+ ----------
3925
+ xys : array_like
3926
+ Nx2 list of vertex positions or texture coordinates to distort. Assumes
3927
+ the output will be rendered to normalized device coordinates where
3928
+ points range from -1.0 to 1.0.
3929
+ coefK : float
3930
+ Distortion coefficient. Use positive numbers for pincushion distortion
3931
+ and negative for barrel distortion.
3932
+ aspect : float
3933
+ Aspect ratio of the target window or buffer (width / height).
3934
+ out : ndarray, optional
3935
+ Optional output array. Must be same `shape` and `dtype` as the expected
3936
+ output if `out` was not specified.
3937
+ dtype : dtype or str, optional
3938
+ Data type for computations can either be 'float32' or 'float64'. If
3939
+ `out` is specified, the data type of `out` is used and this argument is
3940
+ ignored. If `out` is not provided, 'float64' is used by default.
3941
+
3942
+ Returns
3943
+ -------
3944
+ ndarray
3945
+ Array of distorted vertices.
3946
+
3947
+ References
3948
+ ----------
3949
+ .. [1] Lens Distortion White Paper, Andersson Technologies LLC,
3950
+ www.ssontech.com/content/lensalg.html (obtained 07/28/2020)
3951
+
3952
+ Examples
3953
+ --------
3954
+ Creating a lens correction mesh with barrel distortion (eg. for HMDs)::
3955
+
3956
+ vertices, textureCoords, normals, faces = gltools.createMeshGrid(
3957
+ subdiv=11, tessMode='center')
3958
+
3959
+ # recompute vertex positions
3960
+ vertices[:, :2] = mt.lensCorrection2(vertices[:, :2], coefK=2.0)
3961
+
3962
+ """
3963
+ if out is None:
3964
+ dtype = np.float64 if dtype is None else np.dtype(dtype).type
3965
+ else:
3966
+ dtype = np.dtype(dtype).type
3967
+
3968
+ toReturn = np.empty_like(xys, dtype=dtype) if out is None else out
3969
+
3970
+ xys = np.asarray(xys, dtype=dtype)
3971
+ toReturn[:, 0] = u = xys[:, 0]
3972
+ toReturn[:, 1] = v = xys[:, 1]
3973
+ coefKCubed = np.power(coefK, 3, dtype=dtype)
3974
+
3975
+ r2 = aspect * aspect * u * u + v * v
3976
+ r2sqr = np.sqrt(r2, dtype=dtype)
3977
+ f = 1. + r2 * (coefK + coefKCubed * r2sqr)
3978
+
3979
+ toReturn[:, 0] *= f
3980
+ toReturn[:, 1] *= f
3981
+
3982
+ return toReturn
3983
+
3984
+
3985
+ class infrange():
3986
+ """
3987
+ Similar to base Python `range`, but allowing the step to be a float or even
3988
+ 0, useful for specifying ranges for logical comparisons.
3989
+ """
3990
+ def __init__(self, min, max, step=0):
3991
+ self.min = min
3992
+ self.max = max
3993
+ self.step = step
3994
+
3995
+ @property
3996
+ def range(self):
3997
+ return abs(self.max-self.min)
3998
+
3999
+ def __lt__(self, other):
4000
+ return other > self.max
4001
+
4002
+ def __le__(self, other):
4003
+ return other > self.min
4004
+
4005
+ def __gt__(self, other):
4006
+ return self.min > other
4007
+
4008
+ def __ge__(self, other):
4009
+ return self.max > other
4010
+
4011
+ def __contains__(self, item):
4012
+ if self.step == 0:
4013
+ return self.min < item < self.max
4014
+ else:
4015
+ return item in np.linspace(self.min, self.max, int(self.range/self.step)+1)
4016
+
4017
+ def __eq__(self, item):
4018
+ if isinstance(item, self.__class__):
4019
+ return all((
4020
+ self.min == item.min,
4021
+ self.max == item.max,
4022
+ self.step == item.step
4023
+ ))
4024
+ return item in self
4025
+
4026
+ def __add__(self, other):
4027
+ return self.__class__(self.min+other, self.max+other, self.step)
4028
+
4029
+ def __sub__(self, other):
4030
+ return self.__class__(self.min - other, self.max - other, self.step)
4031
+
4032
+ def __mul__(self, other):
4033
+ return self.__class__(self.min * other, self.max * other, self.step * other)
4034
+
4035
+ def __truedic__(self, other):
4036
+ return self.__class__(self.min / other, self.max / other, self.step / other)
4037
+
4038
+
4039
+ if __name__ == "__main__":
4040
+ pass