OSDN Git Service

first
[psychlops/cpp.git] / psychlops / extension / standard / psychophysics / psychlops_exp_psychophysics.cpp
1 /*\r
2  *  psychlops_exp_psychophysics.cpp\r
3  *  Psychlops Standard Library (Universal)\r
4  *\r
5  *  Last Modified 2009/07/ by Kenchi HOSOKAWA\r
6  *  (C) 2005 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO\r
7  */\r
8 \r
9 \r
10 #include "../../../psychlops_core.h"\r
11 #include "../widgets/psychlops_widget.h"\r
12 #include "../widgets/psychlops_widgets.h"\r
13 #include "psychlops_exp_psychophysics.h"\r
14 \r
15 #include <algorithm>\r
16 #include <deque>\r
17 #include <fstream>\r
18 #include <typeinfo>\r
19 #include <stdio.h>\r
20 #include <string.h>\r
21 \r
22 \r
23 namespace Psychlops {\r
24 \r
25 namespace ExperimentalMethods {\r
26 \r
27 \r
28         SliderInterface::SliderInterface()\r
29         {\r
30                 body = 0;\r
31         }\r
32         void SliderInterface::set(Variable* target)\r
33         {\r
34                 if(body!=0) return;\r
35                 Widgets::Slider *s = new Widgets::Slider();\r
36                 s->linkTo(target);\r
37                 body = s;\r
38                 set(target->label);\r
39                 //set(target->label.length()*Font::default_font.size, Font::default_font.size+4);\r
40         }\r
41         SliderInterface::~SliderInterface()\r
42         {\r
43                 if(body==0) return;\r
44                 Widgets::Slider *s = (Widgets::Slider *)body;\r
45                 delete s;\r
46                 body = 0;\r
47         }\r
48         SliderInterface& SliderInterface::set(double wid, double hei)\r
49         {\r
50                 if(body==0) return *this;\r
51                 Widgets::Slider *s = (Widgets::Slider *)body;\r
52                 s->setSize(wid, hei);\r
53                 return *this;\r
54         }\r
55         SliderInterface& SliderInterface::set(std::string s, double hei)\r
56         {\r
57                 if(body==0) return *this;\r
58                 std::wstring temp(s.length(),L' ');\r
59                 std::copy(s.begin(), s.end(), temp.begin());\r
60                 return set(temp, hei);\r
61                 return *this;\r
62         }\r
63         SliderInterface& SliderInterface::set(std::wstring ws, double hei)\r
64         {\r
65                 if(body==0) return *this;\r
66                 Widgets::Slider *s = (Widgets::Slider *)body;\r
67                 s->setLabel(ws);\r
68                 //s->set(ws, hei);\r
69                 return *this;\r
70         }\r
71         SliderInterface& SliderInterface::centering(Drawable &target) { return centering(target.getCenter()); }\r
72         SliderInterface& SliderInterface::centering(const Figure &target) { return centering(target.getDatum()); }\r
73         SliderInterface& SliderInterface::centering(const Point &p) { return centering(p.x, p.y, p.z); }\r
74         SliderInterface& SliderInterface::centering(const double x, const double y, const double z)\r
75         {\r
76                 if(body==0) return *this;\r
77                 Widgets::Slider *s = (Widgets::Slider *)body;\r
78                 s->shift(x,y,z);\r
79                 return *this;\r
80         }\r
81         SliderInterface& SliderInterface::shift(const double x, const double y, const double z)\r
82         {\r
83                 if(body==0) return *this;\r
84                 Widgets::Slider *s = (Widgets::Slider *)body;\r
85                 s->shift(x,y,z);\r
86                 return *this;\r
87         }\r
88         SliderInterface& SliderInterface::setLabel(std::wstring ws)\r
89         {\r
90                 if(body==0) return *this;\r
91                 Widgets::Slider *s = (Widgets::Slider *)body;\r
92                 s->setLabel(ws);\r
93                 return *this;\r
94         }\r
95         SliderInterface& SliderInterface::draw(Drawable &target)\r
96         {\r
97                 if(body==0) return *this;\r
98                 Widgets::Slider *s = (Widgets::Slider *)body;\r
99                 s->draw(target);\r
100                 return *this;\r
101         }\r
102 \r
103         bool SliderInterface::changed()\r
104         {\r
105                 if(body==0) return false;\r
106                 Widgets::Slider *s = (Widgets::Slider *)body;\r
107                 return s->changed();\r
108         }\r
109         SliderInterface::operator double()\r
110         {\r
111                 if(body==0) return 0;\r
112                 Widgets::Slider *s = (Widgets::Slider *)body;\r
113                 return (*s);\r
114         }\r
115         void SliderInterface::appendTo(Group &target)\r
116         {\r
117                 if(body==0) return;\r
118                 //std::cout << 0;\r
119                 Widgets::Slider *s = (Widgets::Slider *)body;\r
120                 target.append(s);\r
121         }\r
122 \r
123 \r
124 \r
125 \r
126         typedef std::deque<Variable *>::iterator VariableList;\r
127 \r
128         Variable::~Variable() {}\r
129         namespace VariableInstanceImpl {\r
130                 template<> void initialize<bool>(Interval *i, std::vector<bool> *step_) { Interval intvl; 0<intvl<=1; *i=intvl; step_->push_back(true); }\r
131                 template<> void increment<bool>(bool* const link_, bool delta, Interval intvl) { *link_ = !(*link_); }\r
132                 template<> void decrement<bool>(bool* const link_, bool delta, Interval intvl) { *link_ = !(*link_); }\r
133                 template<> double getRatio<bool>(bool* const link_, Interval intvl) { return *link_ ? 1 : 0; }\r
134                 template<> void setByRatio<bool>(bool* const link_, double ratio, Interval intvl) { *link_ = ratio<0.5 ? false : true; }\r
135 \r
136                 template<> double getRatio<float>(float* const link_, Interval intvl) { return ( intvl.bounded() ? ((*link_-intvl.begin.value) / (intvl.end.value-intvl.begin.value)) : 0); }\r
137                 template<> void setByRatio<float>(float* const link_, double ratio, Interval intvl) { *link_ = (float)(ratio*(intvl.end.value-intvl.begin.value)+intvl.begin.value); }\r
138                 template<> double getRatio<double>(double* const link_, Interval intvl) { return ( intvl.bounded() ? ((*link_-intvl.begin.value) / (intvl.end.value-intvl.begin.value)) : 0); }\r
139                 template<> void setByRatio<double>(double* const link_, double ratio, Interval intvl) { *link_ = (double)(ratio*(intvl.end.value-intvl.begin.value)+intvl.begin.value); }\r
140 /*\r
141                 template<> double getRatio<float>(float* const link_, Interval intvl) {\r
142                         if(levels_.size()<2) { return ( intvl.bounded() ? ((*link_-intvl.begin.value) / (intvl.end.value-intvl.begin.value)) : 0); }\r
143                         else { return (double)current_level_ / levels_.size(); }\r
144                 }\r
145                 template<> void setByRatio<float>(float* const link_, double ratio, Interval intvl) {\r
146                         if(levels_.size()<2) { *link_ = (float)(ratio*(intvl.end.value-intvl.begin.value)+intvl.begin.value); }\r
147                         else { current_level_ = (int)Math::round(ratio*levels_.size()); setByLevel(current_level_); }\r
148                 }\r
149                 template<> double getRatio<double>(double* const link_, Interval intvl) {\r
150                         if(levels_.size()<2) { return ( intvl.bounded() ? ((*link_-intvl.begin.value) / (intvl.end.value-intvl.begin.value)) : 0); }\r
151                         else { return (double)current_level_ / levels_.size(); }\r
152                 }\r
153                 template<> void setByRatio<double>(double* const link_, double ratio, Interval intvl) {\r
154                         if(levels_.size()<2) { *link_ = (double)(ratio*(intvl.end.value-intvl.begin.value)+intvl.begin.value); }\r
155                         else { current_level_ = (int)Math::round(ratio*levels_.size()); setByLevel(current_level_); }\r
156                 }\r
157 */\r
158         }\r
159 \r
160 \r
161         ////////        ExperimentalVariables   ////////\r
162 \r
163         Variables::Variables()\r
164         {\r
165                 proc___ = 0;\r
166                 slider_switch_ = false;\r
167         }\r
168         Variables::~Variables() {\r
169                 if(!variables.empty()) {\r
170                         for(VariableList i = variables.begin(); i!=variables.end(); i++) {\r
171                                 delete *i;\r
172                         }\r
173                 }\r
174         }\r
175         Variable& Variables::operator [](const size_t index) {\r
176                 return *(variables.at(index));\r
177         }\r
178         Variable& Variables::operator [](const std::string &index) {\r
179                 return operator [](index.c_str());\r
180         }\r
181         Variable& Variables::operator [](const char* index) {\r
182                 for(size_t i=0; i<variables.size(); i++) {\r
183                         if(0==strcmp(variables.at(i)->label.c_str(), index)) return *(variables.at(i));\r
184                 }\r
185                 std::string err("No variable named as ");\r
186                 err.append(index);\r
187                 err.append(" was found.");\r
188                 throw new Exception(err);\r
189         }\r
190         Variable& Variables::operator [](const void* index) {\r
191                 for(size_t i=0; i<variables.size(); i++) {\r
192                         if(variables.at(i)->addr()==index) return *(variables.at(i));\r
193                 }\r
194                 throw new Exception("No variable which has designated address was found.");\r
195         }\r
196         bool Variables::changed() {\r
197                 bool flag = false;\r
198                 for(size_t i=0; i<variables.size(); i++) flag |= variables.at(i)->changed();\r
199                 return flag;\r
200         }\r
201         void Variables::console(bool on_off)\r
202         {\r
203                 if(proc___!=0)\r
204                 {\r
205                         Procedure * p = (Procedure *)proc___;\r
206                         p->console(on_off);\r
207                 }\r
208         }\r
209         void Variables::slider(bool on_off)\r
210         {\r
211                 if(slider_switch_==false)\r
212                 {\r
213                         if(!variables.empty()) {\r
214                                 for(VariableList i = variables.begin(); i!=variables.end(); i++) {\r
215                                         (**i).slider.set(*i);\r
216                                         sliders_.append((**i).slider);\r
217                                 }\r
218                         }\r
219                         if(Drawable::prime==Drawable::dummy) {\r
220                                 Drawable::billboard.append(sliders_);\r
221                         } else {\r
222                                 dynamic_cast<Canvas*>(Drawable::prime)->billboard.push_back(&sliders_);\r
223                         }\r
224                         Mouse::show();\r
225                         slider_switch_ = true;\r
226                 }\r
227         }\r
228 \r
229 \r
230         ////////        VariableConsole ////////\r
231         VariableConsole::VariableConsole(const Variables& v)\r
232          : active_(0), active_bar(0), o(v), bgcolor(Color(0.5,0.5,0.5,0.5)), barcolor(Color(0.2,0.2,8.0,0.4)), active_barcolor(Color(0.0,0.0,1.0,0.6)) {\r
233                 fgcolor[0] = Color::white;\r
234                 fgcolor[1] = Color(0.7);\r
235         }\r
236         VariableConsole::~VariableConsole() {}\r
237         VariableConsole& VariableConsole::draw(Drawable &target) {\r
238                 const double x=datum.x, y=datum.y, z=datum.z;\r
239                 const int MAX_LETTERS=62;\r
240                 char buf[MAX_LETTERS];\r
241                 double content_left=x+10, content_right=x, current_y=y+15;\r
242                 Psychlops::Rectangle bgrect_, barrect;\r
243                 Point mouse = Widgets::drawableMouse(target);\r
244 \r
245                 if(o.variables.empty()) {\r
246 //                      throw new Exception("VariableConsole: No Variable is determined.");\r
247                         return *this;\r
248                 } else {\r
249                         if(Keyboard::right.pushed()) o.variables.at(active_)->increment(Input::get(Keyboard::shift, Keyboard::pressed));\r
250                         if(Keyboard::left.pushed())  o.variables.at(active_)->decrement(Input::get(Keyboard::shift, Keyboard::pressed));\r
251                         if(Keyboard::up.pushed())   if(--active_<0) active_ = o.variables.size()-1;\r
252                         if(Keyboard::down.pushed()) if(++active_>=o.variables.size()) active_ = 0;\r
253                         if(Mouse::left.pressed()) {\r
254                                 size_t c = active_bar;\r
255                                 double cratio = (mouse.x-content_left)/200.0;\r
256                                 if(c<o.variables.size() && c>=0 && cratio>=0 && cratio<=1) { o.variables.at(c)->setByRatio(cratio); }\r
257                         } else {\r
258                                 active_bar = (int)floor((mouse.y-y)/20);\r
259                         }\r
260 \r
261                         bgrect_.set(220, 20*o.variables.size()).shift(x,y).draw(bgcolor, target);\r
262                         for(size_t i=0; i<o.variables.size(); i++ ) {\r
263                                 barrect.set(content_left, current_y, content_left+(200*o.variables.at(i)->getRatio()), current_y-12);\r
264                                 if(i==active_bar) barrect.draw(active_barcolor); else barrect.draw(barcolor);\r
265                                 Display::msg(o.variables.at(i)->label   , content_left,  current_y, fgcolor[active_==i?0:1]);\r
266                                 if(o.variables.at(i)->to_str().size()<MAX_LETTERS-2) {\r
267                     sprintf(buf, "%30s", o.variables.at(i)->to_str().c_str());\r
268                 }\r
269                                 Display::msg(buf, content_right, current_y, fgcolor[active_==i?0:1]);\r
270                                 current_y+=20;\r
271                         }\r
272                         return *this;\r
273                 }\r
274         }\r
275 \r
276 \r
277 \r
278         ////////        ExperimentalMethod      ////////\r
279         ExperimentalMethod::ExperimentalMethod() : result_file_location("%EXPNAME__%TIME_.dat"), ITERATION(1) {\r
280         }\r
281         ExperimentalMethod::~ExperimentalMethod() {\r
282         }\r
283         void ExperimentalMethod::run() {\r
284                 setExpname();\r
285                 initialize_default();\r
286                 trial_default();\r
287                 terminate_default();\r
288         }\r
289         void ExperimentalMethod::terminate() {\r
290         }\r
291         void ExperimentalMethod::initialize_wait() {\r
292         }\r
293         void ExperimentalMethod::setExpname() {\r
294                 experiment_name = typeid(*this).name();\r
295                 char first = experiment_name[0];\r
296                 if(!( (0x40<first && first<0x5B) || (0x60<first && first<0x7B) )) experiment_name.erase(0,2);\r
297                 AppInfo::expname = experiment_name;\r
298         }\r
299         bool ExperimentalMethod::isDemo() {\r
300                 return false;\r
301         }\r
302 \r
303 \r
304 \r
305         ////////        ExperimentalMethods::Demo       ////////\r
306         Demo::Demo() : ExperimentalMethod(), console(Independent) {\r
307         }\r
308         Demo::~Demo() {\r
309                 if(Drawable::prime_is_a_canvas()) {\r
310                         std::vector<Figure*> &b = dynamic_cast<Canvas *>(Drawable::prime)->billboard;\r
311                         for(std::vector<Figure*>::iterator i = b.begin(); i!=b.end(); i++) {\r
312                                 if(*i==&console) b.erase(i);\r
313                         }\r
314                 }\r
315         }\r
316         void Demo::initialize_default() {\r
317                 initialize();\r
318                 if(!Independent.variables.empty()) {\r
319                         for(VariableList i=Independent.variables.begin(); i!=Independent.variables.end(); i++) {\r
320                                 if((**i).getNumberOfLevels()>1) {\r
321                                         (**i).setByLevel((**i).getNumberOfLevels()/2);\r
322                                 } else {\r
323                                         if((**i).getNumberOfLevels()==1) (**i).setByLevel(0);\r
324                                 }\r
325                         }\r
326                 }\r
327                 if(Drawable::prime_is_a_canvas()) {\r
328                         dynamic_cast<Canvas *>(Drawable::prime)->billboard.push_back(&console);\r
329                 }\r
330         }\r
331         bool Demo::nextCondition() {\r
332                 return true;\r
333         }\r
334         void Demo::trial_default() {\r
335                 trial();\r
336         }\r
337         void Demo::terminate_default() {\r
338                 saveResults();\r
339                 terminate();\r
340         }\r
341         void Demo::terminate() {\r
342         }\r
343         void Demo::saveResults() {\r
344         }\r
345         bool Demo::isDemo() {\r
346                 return true;\r
347         }\r
348 \r
349 \r
350 \r
351         ////////        ExperimentalMethods::Constant   ////////\r
352         Constant::Constant() {\r
353         }\r
354         Constant::~Constant() {\r
355         }\r
356         void Constant::initialize_default() {\r
357                 initialize();\r
358 \r
359                 int num_trials = ITERATION;\r
360 \r
361                 // loop for devide independent variables and invariants\r
362                 if(Independent.variables.empty()) throw Exception(typeid(*this), "VARIABLE REQUIRED", "No independent variable was set.");\r
363                 for(VariableList i=Independent.variables.begin(); i!=Independent.variables.end(); i++) {\r
364                         if((**i).getNumberOfLevels() <= 1) {\r
365                                 if((**i).getNumberOfLevels() == 1) (**i).setByLevel(0);\r
366                                 invariant_.insert( std::map<std::string, Variable *>::value_type((**i).label, *i) );\r
367                                 Independent.variables.erase(i);\r
368                                 i--;\r
369                                 continue;\r
370                         }\r
371                         num_trials *= (**i).getNumberOfLevels();\r
372                 }\r
373                 for(VariableList i=Independent.variables.begin(); i!=Independent.variables.end(); i++) {\r
374                         (**i).setColumn(num_trials);\r
375                 }\r
376 \r
377                 // loop for check dependent variables\r
378                 if(Dependent.variables.empty()) throw Exception(typeid(*this), "VARIABLE REQUIRED", "No dependent variable was set.");\r
379                 for(VariableList i=Dependent.variables.begin(); i!=Dependent.variables.end(); i++) {\r
380                         (**i).setColumn(num_trials);\r
381                 }\r
382 \r
383                 // assign conditions for each trial\r
384                 conditions_.assign(num_trials, 0);\r
385                 for(size_t i=0; i<conditions_.size(); i++) conditions_.at(i) = i;\r
386                 int (*random_func)(int) = Psychlops::random;\r
387                 std::random_shuffle(conditions_.begin(), conditions_.end(), random_func);\r
388 \r
389                 initialize_wait();\r
390         }\r
391         void Constant::initialize_wait() {\r
392                 Display::clear();\r
393                 Display::msg("Push space bar to start.", Display::getCenter().x/2-30, Display::getCenter().y/2-3,Color::white);\r
394                 Display::flip();\r
395                 while(!Input::get(Keyboard::spc)) ;\r
396                 Display::clear();\r
397                 Display::flip();\r
398         }\r
399         void Constant::trial_default() {\r
400                 int product_of_devided_conditions, index_of_this_condition;\r
401                 NUM_TRIALS = conditions_.size();\r
402 \r
403                 // loop for each conditions\r
404                 for(size_t i=0; i<conditions_.size(); i++) {\r
405                         CURRENT_TRIAL = i+1;\r
406 \r
407                         // Set independent variables for this trial\r
408                         product_of_devided_conditions = 1;\r
409                         for(VariableList ind=Independent.variables.begin(); ind!=Independent.variables.end(); ind++) {\r
410                                 index_of_this_condition = conditions_.at(i) / product_of_devided_conditions % (**ind).getNumberOfLevels();\r
411                                 product_of_devided_conditions *= (**ind).getNumberOfLevels();\r
412                                 (**ind).setByLevel( index_of_this_condition );\r
413                                 (**ind).setColumnCellByLevel( i, index_of_this_condition );\r
414                         }\r
415 \r
416                         // trial\r
417                         trial();\r
418 \r
419                         // Save result-of-this-trial into data column\r
420                         for(VariableList ind=Dependent.variables.begin(); ind!=Dependent.variables.end(); ind++) {\r
421                                 (**ind).setColumnCellByCurrentValue(i);\r
422                         }\r
423                 }\r
424         }\r
425         bool Constant::nextCondition() {\r
426                 return false;\r
427         }\r
428         void Constant::terminate_default() {\r
429                 saveResults();\r
430                 terminate();\r
431         }\r
432         void Constant::saveResults() {\r
433                 std::string file_url = File::decodePath(result_file_location);\r
434                 std::ofstream f(file_url.c_str());\r
435                 char delimiter = '\t';\r
436                 f << experiment_name << std::endl;\r
437                 f << result_file_header << std::endl;\r
438 \r
439                 //      put invariants\r
440                 if(invariant_.size()>0)\r
441                         for(std::map<std::string, Variable *>::iterator ind=invariant_.begin(); ind!=invariant_.end(); ind++)\r
442                                 f << ind->second->label << delimiter << ind->second->to_str() << ";" << delimiter;\r
443                 f << std::endl;\r
444 \r
445                 //      put column title\r
446                 f << "TRIAL#" << delimiter;\r
447                 if(!Independent.variables.empty()) for(VariableList ind=Independent.variables.begin(); ind!=Independent.variables.end(); ind++) f << (**ind).label << delimiter;\r
448                 if(!Dependent.variables.empty()) for(VariableList ind=Dependent.variables.begin(); ind!=Dependent.variables.end(); ind++) f << (**ind).label << delimiter;\r
449                 f << std::endl;\r
450 \r
451                 //      put column cells\r
452                 for(size_t i=0; i<conditions_.size(); i++) {\r
453                         f << i+1 << delimiter;\r
454                         for(VariableList ind=Independent.variables.begin(); ind!=Independent.variables.end(); ind++) {\r
455                                 (**ind).to_str_ColumnCell_at(i, f);\r
456                                 f << delimiter;\r
457                         }\r
458                         for(VariableList ind=Dependent.variables.begin(); ind!=Dependent.variables.end(); ind++) {\r
459                                 (**ind).to_str_ColumnCell_at(i, f);\r
460                                 f << delimiter;\r
461                         }\r
462                         f << std::endl;\r
463                 }\r
464                 f.close();\r
465         }\r
466 \r
467 /*\r
468         int Constant::set(int vnum, int arraynum, double *array)\r
469         {\r
470                 Independent.append().setLevels(array, arraynum);\r
471         }\r
472         void Constant::randomize(char* dataname=NULL)\r
473         {\r
474                 initialize_default();\r
475         }\r
476         double Constant::get(int vnum, int trial_now);\r
477 */\r
478 \r
479 }\r
480 \r
481 \r
482 \r
483         ExperimentalMethods::Variables Independent;\r
484 \r
485         Procedure::Procedure() : console_(Independent) {\r
486                 Independent.proc___ = this;\r
487         }\r
488         void Procedure::setDesign(DESIGN d) {\r
489                 design_ = d;\r
490         }\r
491         void Procedure::setProcedure(void (*func)()) {\r
492                 func_ = func;\r
493                 func_with_canvas_ = 1;\r
494         }\r
495         void Procedure::setProcedure(void (*func)(Canvas &)) {\r
496                 func_canvas_ = func;\r
497                 func_with_canvas_ = 2;\r
498         }\r
499         void Procedure::run() {\r
500                 if(func_with_canvas_==1) {\r
501                         if(design_==DEMO) {\r
502                                 console(true);\r
503                         }\r
504                         func_();\r
505                 }\r
506         }\r
507         void Procedure::run(Canvas &cnv) {\r
508                 if(func_with_canvas_==2) {\r
509                         if(design_==DEMO) {\r
510                                 cnv.billboard.push_back(&console_);\r
511                         }\r
512                         Mouse::show();\r
513                         func_canvas_(cnv);\r
514                 }\r
515         }\r
516         void Procedure::console(bool on_off) {\r
517                 if(Drawable::prime==Drawable::dummy) {\r
518                         Drawable::billboard.append(console_);\r
519                 } else {\r
520                         dynamic_cast<Canvas*>(Drawable::prime)->billboard.push_back(&console_);\r
521                 }\r
522                 Mouse::show();\r
523         }\r
524 \r
525 \r
526 }       /*      <- namespace Psycholops         */\r
527 \r
528 \r
529 \r