PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Rex/labTools/task_utilities.c

http://dotsx.googlecode.com/
C | 556 lines | 265 code | 95 blank | 196 comment | 84 complexity | e24e87179a2e7c49281abdfa3f708516 MD5 | raw file
Possible License(s): LGPL-2.0
  1. /*
  2. ** TASK_UTILITIES.C
  3. **
  4. ** Utility functions to use with pRec/pTask
  5. ** structures & routines
  6. */
  7. #include <stddef.h>
  8. #include "toys.h"
  9. #include "task_utilities.h"
  10. #include "property_list.h"
  11. /* PUBLIC ROUTINES */
  12. /* make trials */
  13. /* PUBLIC ROUTINE: tu_make_trials1D
  14. **
  15. */
  16. void tu_make_trials1D(_PRtask task,
  17. char *name, int num, int *values, float multiplier)
  18. {
  19. register int i;
  20. /* check args ... be sure to free trials
  21. ** if none given
  22. */
  23. if(num <= 0) {
  24. pr_task_clear(task);
  25. return;
  26. }
  27. /* add the array of (empty) trials */
  28. pr_task_add_trials1D(task, num);
  29. /* For each, add a list with the value
  30. ** of the given property.
  31. */
  32. for(i=0;i<num;i++) {
  33. task->trials[i]->id = task->id*100+i;
  34. task->trials[i]->list =
  35. pl_list_initV("1dtc", 0, 1,
  36. name, values[i], multiplier,
  37. NULL);
  38. }
  39. }
  40. /* PUBLIC ROUTINE: tu_make_trials2D
  41. **
  42. ** Utility to make a 2D trial set.
  43. ** Parameter #1 is rows
  44. ** Parameter #2 is columns
  45. **
  46. ** Remember that, as per C conventions, matrix
  47. ** is stored row by row.
  48. **
  49. ** Arguments:
  50. ** _PRtask ... the task to update
  51. ** name1 ... string name of paramter #1
  52. ** n1 ... number of values in paramter #1 array (rows)
  53. ** v1 ... array of values for paramter #1
  54. ** m1 ... multiplier for paramter #1
  55. ** name2 ... string name of paramter #2
  56. ** n2 ... number of values in paramter #2 array (cols)
  57. ** v2 ... array of values for paramter #2
  58. ** m2 ... multiplier for paramter #2
  59. */
  60. void tu_make_trials2D(_PRtask task,
  61. char *name1, int n1, int *v1, float m1,
  62. char *name2, int n2, int *v2, float m2)
  63. {
  64. long dummy = 0;
  65. register int i, j, k;
  66. /* check args ... be sure to free trials
  67. ** if none given
  68. */
  69. if(n1 <= 0 && n2 <= 0) {
  70. pr_task_clear(task);
  71. return;
  72. }
  73. if(n1 <= 0) {
  74. n1 = 1;
  75. v1 = &dummy;
  76. m1 = 1.0;
  77. }
  78. if(n2 <= 0) {
  79. n2 = 1;
  80. v2 = &dummy;
  81. m2 = 1.0;
  82. }
  83. /* add the array of (empty) trials */
  84. pr_task_add_trials2D(task, n1, n2);
  85. /* For each, add a list of 2 properties,
  86. ** corresponding to the values of the two
  87. ** variables.
  88. */
  89. for(k=0,i=0;i<n1;i++) {
  90. for(j=0;j<n2;j++,k++) {
  91. task->trials[k]->id = task->id*100+k;
  92. task->trials[k]->list =
  93. pl_list_initV("2dtc", 0, 1,
  94. name1, v1[i], m1,
  95. name2, v2[j], m2,
  96. NULL);
  97. }
  98. }
  99. }
  100. /* get trials */
  101. /* PUBLIC ROUTINE: tu_get_block
  102. **
  103. ** Gets the next trial from a standard (not randomized) block,
  104. ** making the block if necessary
  105. **
  106. ** Arguments:
  107. ** task ... See paradgim_rec for details.
  108. ** num_blocks ... Number of blocks (reps) of the set of trials
  109. ** that should be used when creating the
  110. ** pointer array.
  111. ** reset_flag ... If true, set the pointer back to the beginning
  112. ** after reaching the end of the array.
  113. **
  114. */
  115. _PRtrial tu_get_block(_PRtask task, int num_blocks, int reset_flag)
  116. {
  117. int last_score = task->pmf ? task->pmf->last_score : 0;
  118. /* Conditionally make a single block...
  119. ** This will also reset the index to 0
  120. */
  121. if(task->trialPs == NULL) {
  122. pr_task_make_trialP_all(task, num_blocks);
  123. /* check that it worked */
  124. if(task->trialPs == NULL)
  125. return(NULL);
  126. /* Otherwise increment the pointer and check for
  127. ** end of the array
  128. */
  129. } else if(last_score >= 0 &&
  130. ++(task->trialPs_index) >= task->trialPs_length) {
  131. /* end of the line ... check for reset */
  132. if(reset_flag > 0)
  133. /* reset pointer back to the beginning of the array */
  134. task->trialPs_index = 0;
  135. else
  136. /* no reset, end of the line */
  137. return(NULL);
  138. }
  139. /* return the current trial */
  140. return(task->trialPs[task->trialPs_index]);
  141. }
  142. /* PUBLIC ROUTINE: tu_get_random
  143. **
  144. ** Gets the next trial in a randomized block,
  145. ** making the block if necessary.
  146. **
  147. ** Arguments:
  148. ** task ... See paradgim_rec for details.
  149. ** num_blocks ... Number of blocks (reps) of the set of trials
  150. ** that should be used when creating the
  151. ** pointer array.
  152. ** reset_flag ... If true, set the pointer back to the beginning
  153. ** after reaching the end of the array.
  154. */
  155. _PRtrial tu_get_random(_PRtask task, int num_blocks, int reset_flag)
  156. {
  157. int last_score = task->pmf ? task->pmf->last_score : 0;
  158. if(task->trialPs) {
  159. /* check previous score ... */
  160. if(last_score < 0) {
  161. /* swap trial with later trial */
  162. pr_task_swap_trialP(task);
  163. /* try to increment the pointer */
  164. } else if((++(task->trialPs_index)) == task->trialPs_length) {
  165. /* reached the end, clear pointer array
  166. ** so next time through it gets re-randomized
  167. */
  168. SAFE_FREE(task->trialPs);
  169. task->trialPs_length = 0;
  170. }
  171. } else {
  172. /* force 'reset' first time through */
  173. reset_flag = 1;
  174. }
  175. /* check to make block */
  176. if(reset_flag && !task->trialPs) {
  177. /* make the randomized set... the second argument
  178. ** determines the minimum number of trial
  179. ** blocks to include in the array -- this
  180. ** is to make sure that redoing trials
  181. ** after an nc/brfix doesn't cause
  182. ** a predictable pattern to accumulate
  183. ** at the end of the list
  184. */
  185. pr_task_make_trialP_allR(task, num_blocks);
  186. }
  187. /* check if there is a list of pointers */
  188. if(!task->trialPs)
  189. return(NULL);
  190. /* return pointer to the current trial */
  191. return(task->trialPs[task->trialPs_index]);
  192. }
  193. /* PUBLIC ROUTINE: tu_get_random_altRows
  194. **
  195. ** Modified by Long from tu_get_random()
  196. ** make a superblock by combining randomized blocks by rows.
  197. ** Gets the next trial in a randomized block,
  198. ** making the block if necessary.
  199. **
  200. ** Arguments:
  201. ** task ... See paradgim_rec for details.
  202. ** num_blocks ... Number of blocks (reps) of the set of trials
  203. ** that should be used when creating the
  204. ** pointer array.
  205. ** reset_flag ... If true, set the pointer back to the beginning
  206. ** after reaching the end of the array.
  207. */
  208. _PRtrial tu_get_random_altRows(_PRtask task, int num_blocks, int reset_flag)
  209. {
  210. int last_score = task->pmf ? task->pmf->last_score : 0;
  211. int flagRepeat = pl_list_get_v(task->task_menus->lists[1], "flagRepeat") ;
  212. if(task->trialPs) {
  213. /* check previous score ... */
  214. if ( (last_score <= -1) || ( (last_score==0) && flagRepeat ) ) {
  215. /* always repeat fixbreak or no-choice trials , or error-trial with flagRepeat on */
  216. printf (" repeat trial \n");
  217. return(task->trialPs[task->trialPs_index]);
  218. }
  219. if ( (last_score<0) && !flagRepeat ) {
  220. /* swap trial with later trial */
  221. printf (" swap trial \n");
  222. pr_task_swap_trialP(task);
  223. /* try to increment the pointer */
  224. } else if((++(task->trialPs_index)) == task->trialPs_length) {
  225. /* reached the end, clear pointer array
  226. ** so next time through it gets re-randomized
  227. */
  228. SAFE_FREE(task->trialPs);
  229. task->trialPs_length = 0;
  230. }
  231. } else {
  232. /* force 'reset' first time through */
  233. reset_flag = 1;
  234. }
  235. /* check to make block */
  236. if(reset_flag && !task->trialPs) {
  237. int num_sets = task->trials_rows;
  238. int num_cols = task->trials_columns;
  239. int count_per_row = num_cols * num_blocks;
  240. _PRtrial *finaltrialPs = SAFE_ZALLOC(_PRtrial, num_sets*count_per_row);
  241. int i, j, k, m, n;
  242. /*
  243. ** Long: create a super block with blocks of randomized sets.
  244. ** Each block contains num_blocks randomized trials.
  245. */
  246. SAFE_FREE(task->trialPs);
  247. task->trialPs = SAFE_ZALLOC(_PRtrial, count_per_row);
  248. task->trialPs_length = count_per_row;
  249. task->trialPs_index = 0;
  250. n = 0;
  251. for(m=0; m<num_sets; m++) {
  252. /* fill the array with repeated blocks of pointers
  253. ** to trials, in order
  254. */
  255. k = 0;
  256. for(i=0;i<num_blocks;i++)
  257. for(j=0;j<num_cols;j++) {
  258. task->trialPs[k] = task->trials[j + m*num_cols];
  259. k++;
  260. }
  261. pr_task_randomize_trialP(task);
  262. for (i=0; i<k; i++) {
  263. finaltrialPs[n] = task->trialPs[i];
  264. n++;
  265. }
  266. }
  267. SAFE_FREE(task->trialPs);
  268. task->trialPs = finaltrialPs;
  269. task->trialPs_length = n;
  270. task->trialPs_index = 0;
  271. }
  272. /* check if there is a list of pointers */
  273. if(!task->trialPs)
  274. return(NULL);
  275. /* return pointer to the current trial */
  276. return(task->trialPs[task->trialPs_index]);
  277. }
  278. /* PUBLIC ROUTINE: tu_compute_xyrt
  279. **
  280. ** Computes x,y positions of a set of
  281. ** graphics objects with properties
  282. ** defined as "TU_XYRT_LIST"
  283. ** (see task_utilities.h)
  284. **
  285. */
  286. void tu_compute_xyrt(_PLlist list)
  287. {
  288. int pi=0;
  289. register int i=0;
  290. if(!list || !list->properties_length ||
  291. !list->values_length)
  292. return;
  293. /* find index of property DX_X */
  294. while(pi<list->properties_length &&
  295. strcmp(list->properties[pi]->name, DX_X)) pi++;
  296. if(pi == list->properties_length)
  297. return;
  298. /* set each rt */
  299. for(i=0;i<list->values_length;i++) {
  300. tu_compute_rtR(list->properties, pi, i);
  301. /*
  302. ** printf("obj %d, r = %d, t = %d\n", i,
  303. ** list->properties[pi+kR]->values_wc[i],
  304. ** list->properties[pi+kT]->values_wc[i]);
  305. */
  306. }
  307. /* set each xy */
  308. for(i=0;i<list->values_length;i++) {
  309. tu_compute_xyR(list->properties, pi, i);
  310. /*
  311. ** printf("obj %d, x = %d, y = %d\n", i,
  312. ** list->properties[pi]->values_wc[i],
  313. ** list->properties[pi+1]->values_wc[i]);
  314. */
  315. }
  316. }
  317. #define WVI(ki_,vi_) ps[pi+(ki_)]->values_wc[(vi_)]
  318. #define WV(ki_) WVI(ki_, vi)
  319. #define WC_VDV(v_,dv_) WC_V(v_, dv_); WC_DV(v_,dv_)
  320. #define WC_V(v_,dv_) if(WV(v_) == NULLI) { WV(v_) = 0; }
  321. #define WC_DV(v_,dv_) if(WV(dv_)>0) { \
  322. WV(v_) += (TOY_RAND(2*WV(dv_)+1) - WV(dv_)); \
  323. WV(dv_) = NULLI; }
  324. void tu_compute_rtR(_PLproperty *ps, int pi, int vi)
  325. {
  326. int wrti;
  327. /*
  328. ** Check r,t
  329. */
  330. WC_VDV(kR, kDR);
  331. WC_VDV(kT, kDT);
  332. /*
  333. ** Get WRT angle ... first get index of wrt object,
  334. ** then marks as NULLI to avoid inf recurs.
  335. */
  336. wrti = WV(kWRT);
  337. WV(kWRT) = NULLI;
  338. /* check for no wrt */
  339. if(wrti == NULLI || wrti == vi || wrti < 0 ||
  340. wrti >= (*ps)->values_length)
  341. return;
  342. /* recursively compute the angle ! */
  343. tu_compute_rtR(ps, pi, wrti);
  344. /* add the angle */
  345. WV(kR) += WVI(kR, wrti);
  346. }
  347. void tu_compute_xyR(_PLproperty *ps, int pi, int vi)
  348. {
  349. int vertexi, vx, vy;
  350. /*
  351. ** Check if x, y are set ...
  352. */
  353. if(WV(kX) != NULLI && WV(kY) != NULLI) {
  354. /* check for dx, dy */
  355. WC_DV(kX, kDX);
  356. WC_DV(kY, kDY);
  357. /* outta */
  358. return;
  359. }
  360. /* r, t should already be set */
  361. vertexi = WV(kVERTEX);
  362. WV(kVERTEX) = NULLI;
  363. /* check for no vertex */
  364. if(vertexi == NULLI || vertexi == vi || vertexi < 0 ||
  365. vertexi >= (*ps)->values_length) {
  366. vx = 0;
  367. vy = 0;
  368. } else {
  369. tu_compute_xyR(ps, pi, vertexi);
  370. vx = WVI(kX, vertexi);
  371. vy = WVI(kY, vertexi);
  372. }
  373. /* compute x, y from r, t, and
  374. ** add dx,dy if neccesary.
  375. */
  376. WV(kX) = TOY_RT_TO_X(vx, WV(kR), WV(kT));
  377. WC_DV(kX, kDX);
  378. WV(kY) = TOY_RT_TO_Y(vy, WV(kR), WV(kT));
  379. WC_DV(kY, kDY);
  380. /*
  381. ** printf("vt=%d,vx=%d,vy=%d,kr=%d,kt=%d,kdx=%d,kdy=%d,kx=%d,ky=%d\n",
  382. ** vertexi,vx,vy,WV(kR),WV(kT),WV(kDX),WV(kDY),WV(kX),WV(kY));
  383. */
  384. }
  385. /* PUBLIC ROUTINE: tu_compute_dangle
  386. ** Returns an array containing target angles +/- RAND(dangle)
  387. ** Added by bss on 04/26/2007
  388. */
  389. int *tu_compute_dangle(int angle, int toff, int dangle, int radius, int dangle_limit)
  390. {
  391. int *dangled[3];
  392. int t1, t2;
  393. int ang_betw_t;
  394. double d_betw_t;
  395. /* Choose a position for T1 everything else is relative to this */
  396. if(TOY_RAND(100)<=49) {
  397. angle+=toff;
  398. }
  399. else {
  400. angle+=(toff+180);
  401. }
  402. /* Choose if you are adding or subtracting dangle */
  403. if(dangle>1) {
  404. if(TOY_RAND(100)<=49) {
  405. t1=angle-TOY_RAND(dangle);
  406. }
  407. else {
  408. t1=angle+TOY_RAND(dangle);
  409. }
  410. if(TOY_RAND(100)<=49) {
  411. t2=angle+180-TOY_RAND(dangle);
  412. }
  413. else {
  414. t2=angle+180+TOY_RAND(dangle);
  415. }
  416. }
  417. else {
  418. t1=angle;
  419. t2=angle+180;
  420. }
  421. /* Check final angles to make sure that they are not too close */
  422. ang_betw_t=abs(t2-t1);
  423. if(ang_betw_t>180) {
  424. ang_betw_t=360-ang_betw_t; /* Normalize */
  425. }
  426. d_betw_t=2*(sin(DEG2RAD*((double)ang_betw_t/2)))*((double)radius/10);
  427. if(d_betw_t>dangle_limit) {
  428. dangled[2]=1;
  429. }
  430. else {
  431. dangled[2]=0;
  432. }
  433. dangled[0]=t1;
  434. dangled[1]=t2;
  435. return(dangled);
  436. }
  437. /* PUBLIC ROUTINE: tu_get_seed
  438. **
  439. ** Generate seed for random number generator.
  440. ** Behavior depends on seed_base:
  441. ** <0 ... generate random seed
  442. ** =0 ... use zero as seed
  443. ** >0 ... generate seed from base, coherence, angle
  444. */
  445. int tu_get_seed(int seed_base, int coherence, int angle)
  446. {
  447. struct timespec now;
  448. int seed;
  449. if (seed_base < 0) {
  450. clock_gettime(CLOCK_REALTIME, &now);
  451. seed = now.tv_sec%1000;
  452. }
  453. else if (seed_base == 0) {
  454. seed = 0;
  455. }
  456. else {
  457. seed = seed_base + coherence + angle;
  458. }
  459. printf("dot seed = %d\n", seed);
  460. return (seed);
  461. }