2 * psychlops_exp_psychophysics.cpp
\r
3 * Psychlops Standard Library (Universal)
\r
5 * Last Modified 2009/07/ by Kenchi HOSOKAWA
\r
6 * (C) 2005 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
\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
15 #include <algorithm>
\r
23 namespace Psychlops {
\r
25 namespace ExperimentalMethods {
\r
28 SliderInterface::SliderInterface()
\r
32 void SliderInterface::set(Variable* target)
\r
35 Widgets::Slider *s = new Widgets::Slider();
\r
39 //set(target->label.length()*Font::default_font.size, Font::default_font.size+4);
\r
41 SliderInterface::~SliderInterface()
\r
44 Widgets::Slider *s = (Widgets::Slider *)body;
\r
48 SliderInterface& SliderInterface::set(double wid, double hei)
\r
50 if(body==0) return *this;
\r
51 Widgets::Slider *s = (Widgets::Slider *)body;
\r
52 s->setSize(wid, hei);
\r
55 SliderInterface& SliderInterface::set(std::string s, double hei)
\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
63 SliderInterface& SliderInterface::set(std::wstring ws, double hei)
\r
65 if(body==0) return *this;
\r
66 Widgets::Slider *s = (Widgets::Slider *)body;
\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
76 if(body==0) return *this;
\r
77 Widgets::Slider *s = (Widgets::Slider *)body;
\r
81 SliderInterface& SliderInterface::shift(const double x, const double y, const double z)
\r
83 if(body==0) return *this;
\r
84 Widgets::Slider *s = (Widgets::Slider *)body;
\r
88 SliderInterface& SliderInterface::setLabel(std::wstring ws)
\r
90 if(body==0) return *this;
\r
91 Widgets::Slider *s = (Widgets::Slider *)body;
\r
95 SliderInterface& SliderInterface::draw(Drawable &target)
\r
97 if(body==0) return *this;
\r
98 Widgets::Slider *s = (Widgets::Slider *)body;
\r
103 bool SliderInterface::changed()
\r
105 if(body==0) return false;
\r
106 Widgets::Slider *s = (Widgets::Slider *)body;
\r
107 return s->changed();
\r
109 SliderInterface::operator double()
\r
111 if(body==0) return 0;
\r
112 Widgets::Slider *s = (Widgets::Slider *)body;
\r
115 void SliderInterface::appendTo(Group &target)
\r
117 if(body==0) return;
\r
119 Widgets::Slider *s = (Widgets::Slider *)body;
\r
126 typedef std::deque<Variable *>::iterator VariableList;
\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
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
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
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
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
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
161 //////// ExperimentalVariables ////////
\r
163 Variables::Variables()
\r
166 slider_switch_ = false;
\r
168 Variables::~Variables() {
\r
169 if(!variables.empty()) {
\r
170 for(VariableList i = variables.begin(); i!=variables.end(); i++) {
\r
175 Variable& Variables::operator [](const size_t index) {
\r
176 return *(variables.at(index));
\r
178 Variable& Variables::operator [](const std::string &index) {
\r
179 return operator [](index.c_str());
\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
185 std::string err("No variable named as ");
\r
187 err.append(" was found.");
\r
188 throw new Exception(err);
\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
194 throw new Exception("No variable which has designated address was found.");
\r
196 bool Variables::changed() {
\r
198 for(size_t i=0; i<variables.size(); i++) flag |= variables.at(i)->changed();
\r
201 void Variables::console(bool on_off)
\r
205 Procedure * p = (Procedure *)proc___;
\r
206 p->console(on_off);
\r
209 void Variables::slider(bool on_off)
\r
211 if(slider_switch_==false)
\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
219 if(Drawable::prime==Drawable::dummy) {
\r
220 Drawable::billboard.append(sliders_);
\r
222 dynamic_cast<Canvas*>(Drawable::prime)->billboard.push_back(&sliders_);
\r
225 slider_switch_ = true;
\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
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
245 if(o.variables.empty()) {
\r
246 // throw new Exception("VariableConsole: No Variable is determined.");
\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
258 active_bar = (int)floor((mouse.y-y)/20);
\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
269 Display::msg(buf, content_right, current_y, fgcolor[active_==i?0:1]);
\r
278 //////// ExperimentalMethod ////////
\r
279 ExperimentalMethod::ExperimentalMethod() : result_file_location("%EXPNAME__%TIME_.dat"), ITERATION(1) {
\r
281 ExperimentalMethod::~ExperimentalMethod() {
\r
283 void ExperimentalMethod::run() {
\r
285 initialize_default();
\r
287 terminate_default();
\r
289 void ExperimentalMethod::terminate() {
\r
291 void ExperimentalMethod::initialize_wait() {
\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
299 bool ExperimentalMethod::isDemo() {
\r
305 //////// ExperimentalMethods::Demo ////////
\r
306 Demo::Demo() : ExperimentalMethod(), console(Independent) {
\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
316 void Demo::initialize_default() {
\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
323 if((**i).getNumberOfLevels()==1) (**i).setByLevel(0);
\r
327 if(Drawable::prime_is_a_canvas()) {
\r
328 dynamic_cast<Canvas *>(Drawable::prime)->billboard.push_back(&console);
\r
331 bool Demo::nextCondition() {
\r
334 void Demo::trial_default() {
\r
337 void Demo::terminate_default() {
\r
341 void Demo::terminate() {
\r
343 void Demo::saveResults() {
\r
345 bool Demo::isDemo() {
\r
351 //////// ExperimentalMethods::Constant ////////
\r
352 Constant::Constant() {
\r
354 Constant::~Constant() {
\r
356 void Constant::initialize_default() {
\r
359 int num_trials = ITERATION;
\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
371 num_trials *= (**i).getNumberOfLevels();
\r
373 for(VariableList i=Independent.variables.begin(); i!=Independent.variables.end(); i++) {
\r
374 (**i).setColumn(num_trials);
\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
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
391 void Constant::initialize_wait() {
\r
393 Display::msg("Push space bar to start.", Display::getCenter().x/2-30, Display::getCenter().y/2-3,Color::white);
\r
395 while(!Input::get(Keyboard::spc)) ;
\r
399 void Constant::trial_default() {
\r
400 int product_of_devided_conditions, index_of_this_condition;
\r
401 NUM_TRIALS = conditions_.size();
\r
403 // loop for each conditions
\r
404 for(size_t i=0; i<conditions_.size(); i++) {
\r
405 CURRENT_TRIAL = i+1;
\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
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
425 bool Constant::nextCondition() {
\r
428 void Constant::terminate_default() {
\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
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
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
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
458 for(VariableList ind=Dependent.variables.begin(); ind!=Dependent.variables.end(); ind++) {
\r
459 (**ind).to_str_ColumnCell_at(i, f);
\r
468 int Constant::set(int vnum, int arraynum, double *array)
\r
470 Independent.append().setLevels(array, arraynum);
\r
472 void Constant::randomize(char* dataname=NULL)
\r
474 initialize_default();
\r
476 double Constant::get(int vnum, int trial_now);
\r
483 ExperimentalMethods::Variables Independent;
\r
485 Procedure::Procedure() : console_(Independent) {
\r
486 Independent.proc___ = this;
\r
488 void Procedure::setDesign(DESIGN d) {
\r
491 void Procedure::setProcedure(void (*func)()) {
\r
493 func_with_canvas_ = 1;
\r
495 void Procedure::setProcedure(void (*func)(Canvas &)) {
\r
496 func_canvas_ = func;
\r
497 func_with_canvas_ = 2;
\r
499 void Procedure::run() {
\r
500 if(func_with_canvas_==1) {
\r
501 if(design_==DEMO) {
\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
516 void Procedure::console(bool on_off) {
\r
517 if(Drawable::prime==Drawable::dummy) {
\r
518 Drawable::billboard.append(console_);
\r
520 dynamic_cast<Canvas*>(Drawable::prime)->billboard.push_back(&console_);
\r
526 } /* <- namespace Psycholops */
\r