00001 /** @file Psycho/ArrayCreator.C jittered array of search elements */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: David J. Berg <dberg@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Psycho/ArrayCreator.C $ 00035 00036 #ifndef PSYCHO_ARRAYCREATOR_C_DEFINED 00037 #define PSYCHO_ARRAYCREATOR_C_DEFINED 00038 00039 #include "Psycho/ArrayCreator.H" 00040 00041 #include "Component/ModelOptionDef.H" 00042 #include "Util/StringConversions.H" 00043 #include "Util/StringUtil.H" 00044 #include "Image/DrawOps.H" 00045 00046 #include <iostream> 00047 #include <fstream> 00048 00049 const ModelOptionCateg MOC_PSYCHOARRAYCREATOR = { 00050 MOC_SORTPRI_2, "ArrayCreator realted options" }; 00051 00052 // Used by: ArrayCreator 00053 const ModelOptionDef OPT_ACFileName = 00054 { MODOPT_ARG_STRING, "ACFileName", &MOC_PSYCHOARRAYCREATOR, OPTEXP_CORE, 00055 "File name of configuration file for ArrayCreator", 00056 "ac-filename", '\0', "<filename>", "array_config.conf" }; 00057 00058 // Used by: ArrayCreator 00059 const ModelOptionDef OPT_ACItemRadius = 00060 { MODOPT_ARG(uint), "ACItemRadius", &MOC_PSYCHOARRAYCREATOR, 00061 OPTEXP_CORE, 00062 "default radius to use for array items, in degrees of visual angle", 00063 "ac-itemradius", '\0', "<uint>", "2" }; 00064 00065 // Used by: ArrayCreator 00066 const ModelOptionDef OPT_ACJitterLevel = 00067 { MODOPT_ARG(float), "ACJitterLevel", &MOC_PSYCHOARRAYCREATOR, 00068 OPTEXP_CORE, "The default off-grid jitter of the items, " 00069 "in degrees of visual angle", "ac-jitter", '\0', "<float>", "1" }; 00070 00071 // Used by: ArrayCreator 00072 const ModelOptionDef OPT_ACBackgroundColor = 00073 { MODOPT_ARG(PixRGB<byte>), "ACBackgroundColor", &MOC_PSYCHOARRAYCREATOR, 00074 OPTEXP_CORE, "value of the default background pixel, in RGB", 00075 "ac-bgcolor", '\0', "<byte,byte,byte>", "128,128,128" }; 00076 00077 // Used by: ArrayCreator 00078 const ModelOptionDef OPT_ACPpdX = 00079 { MODOPT_ARG(float), "ACPpdX", &MOC_PSYCHOARRAYCREATOR, 00080 OPTEXP_CORE, "pixels per degree for x direction", 00081 "ac-ppdx", '\0', "<float>", "10.0" }; 00082 00083 // Used by: ArrayCreator 00084 const ModelOptionDef OPT_ACPpdY = 00085 { MODOPT_ARG(float), "ACPpdY", &MOC_PSYCHOARRAYCREATOR, 00086 OPTEXP_CORE, "pixels per degree for y direction", 00087 "ac-ppdy", '\0', "<float>", "10.0" }; 00088 00089 // Used by: ArrayCreator 00090 const ModelOptionDef OPT_ACPermuteTargs = 00091 { MODOPT_FLAG, "ACPermuteTargs", &MOC_PSYCHOARRAYCREATOR, 00092 OPTEXP_CORE, "Display more than one target at a time?", 00093 "ac-perm-targs", '\0', "<bool>", "true" }; 00094 00095 00096 // ###################################################################### 00097 // implementation of for ItemType and ColorSpace 00098 // ###################################################################### 00099 std::string convertToString(const ItemType& item) 00100 { 00101 switch (item) 00102 { 00103 case BARH: 00104 return std::string("BARH"); 00105 case BARV: 00106 return std::string("BARV"); 00107 case CIRCLE: 00108 return std::string("CIRCLE"); 00109 case SQUARE: 00110 return std::string("SQUARE"); 00111 case BLOB: 00112 return std::string("BLOB"); 00113 default: 00114 { 00115 LFATAL("No such item type"); 00116 return std::string(); 00117 } 00118 } 00119 } 00120 00121 // ###################################################################### 00122 void convertFromString(const std::string& str, ItemType& itemtype) 00123 { 00124 if (str.compare("SQUARE") == 0) 00125 itemtype = SQUARE; 00126 else if (str.compare("BLOB") == 0) 00127 itemtype = BLOB; 00128 else if (str.compare("CIRCLE") == 0) 00129 itemtype = CIRCLE; 00130 else if (str.compare("BARH") == 0) 00131 itemtype = BARH; 00132 else if (str.compare("BARV") == 0) 00133 itemtype = BARV; 00134 else 00135 LFATAL("No such search array item option."); 00136 } 00137 00138 // ###################################################################### 00139 std::string convertToString(const ColorSpace& colorspace) 00140 { 00141 switch (colorspace) 00142 { 00143 case RGB: 00144 return std::string("RGB"); 00145 case HSV: 00146 return std::string("HSV"); 00147 case DKL: 00148 return std::string("DKL"); 00149 default: 00150 { 00151 LFATAL("No ColorSpace set"); 00152 return std::string(); 00153 } 00154 } 00155 } 00156 00157 // ###################################################################### 00158 void convertFromString(const std::string& str, ColorSpace& itemtype) 00159 { 00160 if (str.compare("HSV") == 0) 00161 itemtype = HSV; 00162 else if (str.compare("RGB") == 0) 00163 itemtype = RGB; 00164 else if (str.compare("DKL") == 0) 00165 itemtype = DKL; 00166 else 00167 LFATAL("No such color space option."); 00168 } 00169 00170 // ###################################################################### 00171 // Implementation of ArrayItem and derivitives 00172 // ###################################################################### 00173 template <typename PIXEL_TYPE> 00174 ArrayItem::ArrayItem(const uint xpos, const uint ypos, const uint radius, 00175 const PIXEL_TYPE& color, const float& orientation) : 00176 itsPos(xpos,ypos), itsRad(radius), itsCol(color), itsOrient(orientation) 00177 { 00178 } 00179 00180 // ###################################################################### 00181 ArrayItem::~ArrayItem() 00182 { 00183 } 00184 00185 // ###################################################################### 00186 std::string ArrayItem::toString() const 00187 { 00188 std::string str = toStr<uint>(itsPos.x()) + ":" + toStr<uint>(itsPos.y()) + 00189 ":" + toStr<int>(itsRad) + ":" + toStr<PixRGB<byte> >(itsCol) + ":" + 00190 toStr<float>(itsOrient) + ":" + getShapeName(); 00191 return str; 00192 } 00193 00194 // ###################################################################### 00195 template <class PIXEL_TYPE> 00196 BarItem::BarItem(const uint xpos, const uint ypos, const uint radius, 00197 const PIXEL_TYPE& color, const float& orientation) : 00198 ArrayItem(xpos,ypos,radius,color,orientation) 00199 { 00200 } 00201 00202 // ###################################################################### 00203 BarItem::~BarItem() 00204 { 00205 } 00206 00207 // ###################################################################### 00208 std::string BarItem::getShapeName() const 00209 { 00210 return "BAR"; 00211 } 00212 00213 // ###################################################################### 00214 void BarItem::drawItem(Image<PixRGB<byte> >& dst) const 00215 { 00216 int tt = (int)(getPos().y() - getRad()); 00217 int bb = (int)(getPos().y() + getRad()); 00218 int ll = (int)((float)getPos().x() - getRad()/3.0f); 00219 int rr = (int)((float)getPos().x() + getRad()/3.0f); 00220 while ( ((bb - tt) > 0) && ((rr - ll) > 0) ) 00221 { 00222 tt++; bb--; ll++; rr--; 00223 Rectangle r = Rectangle::tlbrO(tt, ll, bb, rr); 00224 drawRectOR(dst, r, getCol(), 1, getOrient()); 00225 } 00226 } 00227 00228 // ###################################################################### 00229 template <class PIXEL_TYPE> 00230 CircleItem::CircleItem(const uint xpos, const uint ypos, const uint radius, 00231 const PIXEL_TYPE& color, const float& orientation) : 00232 ArrayItem(xpos,ypos,radius,color,orientation) 00233 { 00234 } 00235 00236 // ###################################################################### 00237 CircleItem::~CircleItem() 00238 { 00239 } 00240 00241 // ###################################################################### 00242 std::string CircleItem::getShapeName() const 00243 { 00244 return "CIRCLE"; 00245 } 00246 00247 // ###################################################################### 00248 void CircleItem::drawItem(Image<PixRGB<byte> >& dst) const 00249 { 00250 drawDisk(dst, Point2D<int>((int)getPos().x(),(int)getPos().y()), 00251 getRad(), getCol()); 00252 } 00253 00254 // ###################################################################### 00255 template <class PIXEL_TYPE> 00256 SquareItem::SquareItem(const uint xpos, const uint ypos, const uint radius, 00257 const PIXEL_TYPE& color, const float& orientation) : 00258 ArrayItem(xpos,ypos,radius,color,orientation) 00259 { 00260 } 00261 00262 // ###################################################################### 00263 SquareItem::~SquareItem() 00264 { 00265 } 00266 00267 // ###################################################################### 00268 std::string SquareItem::getShapeName() const 00269 { 00270 return "SQUARE"; 00271 } 00272 00273 // ###################################################################### 00274 void SquareItem::drawItem(Image<PixRGB<byte> >& dst) const 00275 { 00276 drawPatch(dst, Point2D<int>((int)getPos().x(),(int)getPos().y()), 00277 getRad(), getCol()); 00278 } 00279 00280 // ###################################################################### 00281 template <class PIXEL_TYPE> 00282 BlobItem::BlobItem(const uint xpos, const uint ypos, const uint radius, 00283 const PIXEL_TYPE& color, const float& orientation) : 00284 ArrayItem(xpos,ypos,radius,color,orientation) 00285 { 00286 } 00287 00288 // ###################################################################### 00289 BlobItem::~BlobItem() 00290 { 00291 } 00292 00293 // ###################################################################### 00294 std::string BlobItem::getShapeName() const 00295 { 00296 return "BLOB"; 00297 } 00298 00299 // ###################################################################### 00300 void BlobItem::drawItem(Image<PixRGB<byte> >& dst) const 00301 { 00302 float stddev = (float)getRad()/2; 00303 int psize = stddev*2; 00304 00305 int ux = int(getPos().x()) - psize; 00306 int step = dst.getWidth() - 2 * psize-1; 00307 00308 Image<PixRGB<byte> >::iterator dptr = dst.beginw() + 00309 int(getPos().y() - psize) * dst.getWidth() + ux; 00310 00311 for (int y = -1*psize; y <= psize; y++) 00312 { 00313 float resultX,resultY; 00314 resultY = exp(-(float(y*y)/(stddev*stddev))); 00315 for (int x = -1*psize; x <= psize; x++) 00316 { 00317 resultX = exp(-((x*x)/(stddev*stddev))); 00318 float g = resultX*resultY; 00319 00320 //the current pixel will be g*col + (1-g)*oldcol 00321 PixRGB<byte> col = getCol(); 00322 col *= g; 00323 *dptr *= (1-g); 00324 (*dptr++) += col; 00325 } 00326 dptr += step; 00327 } 00328 } 00329 00330 // ###################################################################### 00331 // Implementation of ArrayCreator 00332 // ###################################################################### 00333 ArrayCreator::ArrayCreator(const std::string& filename, const float& radius, 00334 const float& noise, const Dims& dims, 00335 const float& ppdx, const float& ppdy, 00336 const PixRGB<byte>& background, 00337 const float& fix_size, const bool permTargs) : 00338 itsRF(), itsColT(), itsColD(), itsDist(), itsShape(), 00339 itsStims(), itsDescr(), itsDims(dims), itsRad(radius), itsNoise(noise), 00340 itsPpdx(ppdx), itsPpdy(ppdy), itsPpd(sqrt(ppdx*ppdx + ppdy*ppdy)), 00341 itsBackgroundColor(background), itsFixSize(fix_size), rnum((int)time(NULL)), 00342 itsPermTargs(permTargs) 00343 { 00344 parseFile(filename);//read the config file 00345 computeSequence(); //compute the stim permutations, item positions, 00346 //and descriptive string. 00347 } 00348 00349 // ###################################################################### 00350 ArrayCreator::~ArrayCreator() 00351 { 00352 for (size_t ii = 0; ii < itsStims.size(); ++ii) 00353 for (size_t jj = 0; jj < itsStims.size(); ++jj) 00354 delete itsStims[ii][jj]; 00355 } 00356 00357 // ###################################################################### 00358 uint ArrayCreator::size() const 00359 { 00360 return (uint)itsStims.size(); 00361 } 00362 00363 // ###################################################################### 00364 Image<PixRGB<byte> > ArrayCreator::draw(const uint permnum) const 00365 { 00366 Image<PixRGB<byte> > img(itsDims, ZEROS); 00367 img += itsBackgroundColor; 00368 draw(img, permnum); 00369 return img; 00370 } 00371 00372 // ###################################################################### 00373 void ArrayCreator::draw(Image<PixRGB<byte> >& dst, const uint permnum) const 00374 { 00375 if (dst.getDims() != itsDims) 00376 LFATAL("Image dimensions must be the same as those specified at " 00377 "this objects creation. "); 00378 00379 std::vector<ArrayItem*> temp = itsStims[permnum]; 00380 std::vector<ArrayItem*>::iterator iter = temp.begin(); 00381 while (iter != temp.end()) 00382 (*iter++)->drawItem(dst); 00383 00384 if (itsFixSize > 0) 00385 { 00386 int size = int(itsFixSize * itsPpd); 00387 if ((size % 2) == 0) 00388 size = size / 2; 00389 else 00390 size = (size - 1) / 2; 00391 const int i = itsDims.w()/2-1,j = itsDims.h()/2-1; 00392 Rectangle frect = Rectangle::tlbrI(j-size+1, i-size+1, 00393 j + size, i + size); 00394 drawFilledRect(dst, frect, PixRGB<byte>(255,255,255)); 00395 } 00396 } 00397 00398 // ###################################################################### 00399 std::string ArrayCreator::toString(const uint permnum) const 00400 { 00401 return itsDescr[permnum]; 00402 } 00403 00404 // ###################################################################### 00405 void ArrayCreator::parseFile(const std::string& file) 00406 { 00407 //open file 00408 std::ifstream f(file.c_str()); 00409 if (!f.is_open()) 00410 LFATAL("Couldn't open '%s' for reading.",file.c_str()); 00411 LINFO("%s opened for reading",file.c_str()); 00412 00413 //read in RF and other targt locations 00414 std::string line = readLine(f); 00415 while (line.find(':') == std::string::npos) 00416 { 00417 std::vector<std::string> tok;//tokenizer 00418 split(line, ",", std::back_inserter(tok)); 00419 int xpix = int((float)fromStr<int>(tok[0]) * itsPpdx + itsDims.w()/2); 00420 int ypix = int((float)fromStr<int>(tok[1]) * itsPpdy + itsDims.h()/2); 00421 if (((int)xpix < itsDims.w()) && ((int)ypix < itsDims.h()) && 00422 (xpix >=0) && (ypix >=0)) 00423 { 00424 float size = fromStr<float>(tok[2]) * itsPpd; 00425 RF r = {geom::vec2<uint>((uint)xpix,(uint)ypix), size}; 00426 itsRF.push_back(r); 00427 } 00428 line = readLine(f); 00429 } 00430 LINFO("%d RF's and other target locations",(int)itsRF.size()); 00431 00432 //parse the color list 00433 std::vector<std::string> tok;//tokenizer 00434 split(line, " ", std::back_inserter(tok)); 00435 for (size_t ii = 0; ii < tok.size(); ++ii) 00436 { 00437 std::vector<std::string> tok1;//tokenizer 00438 split(tok[ii], ":", std::back_inserter(tok1)); 00439 std::string type = tok1[0]; 00440 ColorSpace cs = RGB; 00441 convertFromString(tok1[1], cs); 00442 switch (cs) 00443 { 00444 case RGB: 00445 { 00446 (type.compare("T") == 0)? 00447 itsColT.push_back(fromStr<PixRGB<byte> >(tok1[2])): 00448 itsColD.push_back(fromStr<PixRGB<byte> >(tok1[2])); 00449 break; 00450 } 00451 case HSV: 00452 { 00453 PixHSV<byte> thsv(fromStr<PixHSV<byte> >(tok1[2])); 00454 PixRGB<byte> tmp(thsv); 00455 (type.compare("T") == 0)? 00456 itsColT.push_back(tmp): 00457 itsColD.push_back(tmp); 00458 break; 00459 } 00460 case DKL: 00461 { 00462 LFATAL("DKL Colorspace options are currently unfunctional, " 00463 "please use HSV, or RGB"); 00464 //PixDKL<byte> tdkl(fromStr<PixDKL<byte> >(tok1[2])); 00465 //PixRGB<byte> tmp(tdkl); //DKL->RGB not supported 00466 break; 00467 } 00468 default: 00469 { 00470 LFATAL("No ColorSpace set"); 00471 break; 00472 } 00473 } 00474 } 00475 00476 LINFO("%d targets and %d distractors color conditions", 00477 (int)itsColT.size(), (int)itsColD.size()); 00478 00479 //get distractor density list 00480 line = readLine(f); 00481 tok.clear(); 00482 split(line, " ", std::back_inserter(tok)); 00483 for (size_t ii = 0; ii < tok.size(); ++ii) 00484 itsDist.push_back(fromStr<uint>(tok[ii])); 00485 LINFO("%d distractor set sizes",(int)itsDist.size()); 00486 00487 //get the shape list 00488 line = readLine(f); 00489 tok.clear(); 00490 split(line, " ", std::back_inserter(tok)); 00491 for (size_t ii = 0; ii < tok.size(); ++ii) 00492 { 00493 std::vector<std::string> ttok;//tokenizer 00494 split(tok[ii], "-", std::back_inserter(ttok)); 00495 if (ttok.size() > 2) 00496 LFATAL("Cannot have more than two paired shapes"); 00497 00498 std::vector<ItemType> tempv; 00499 for (size_t jj = 0; jj < ttok.size(); ++jj) 00500 { 00501 ItemType it = SQUARE; 00502 convertFromString(ttok[jj], it); 00503 tempv.push_back(it); 00504 } 00505 itsShape.push_back(tempv); 00506 } 00507 LINFO("%d shape conditions", (int)itsShape.size()); 00508 f.close(); 00509 } 00510 00511 // ###################################################################### 00512 std::string ArrayCreator::readLine(std::ifstream& fs) 00513 { 00514 using namespace std; 00515 string line = "#"; 00516 00517 if (fs.eof()) 00518 return line; 00519 00520 while (line[0] == '#') 00521 getline(fs, line); 00522 00523 return line; 00524 } 00525 00526 // ###################################################################### 00527 void ArrayCreator::computeSequence() 00528 { 00529 //Basically, here we are going to compute itsRF.size() choose ii 00530 //permutations (without repeats, ie 1-2 is the same subset as 00531 //2-1). We are going to select all the combinations of ii members of 00532 //the set with size itsRF.size(), and store them in one large 00533 //vector. This will give us all possible combintations of RF on/off 00534 //for all # of targets 00535 std::vector<std::vector<int> > idx; //index of on targets for each 00536 //condition. 00537 00538 if (itsPermTargs) 00539 { 00540 std::vector<int> t; 00541 t.push_back(0); 00542 idx.push_back(t); 00543 subset(idx, (int)itsRF.size()); 00544 t.resize(0); 00545 t.push_back(-1); 00546 idx.push_back(t); 00547 } 00548 else 00549 for (uint ii = 0; ii < itsRF.size(); ++ii) 00550 { 00551 std::vector<int> t; 00552 t.push_back(ii); 00553 idx.push_back(t); 00554 } 00555 00556 //Now loop through all the conditions and compute target and 00557 //distractors for different color, shape and positions, 00558 //counterbalanced. See ArrayCreator.H for more info on the design. 00559 00560 if (itsColT.size() > 2) 00561 LFATAL("currently only two target types are supported"); 00562 00563 //loop through all the distractor colors. 00564 for (uint ccd = 0; ccd < itsColD.size(); ++ccd)//colors distractor 00565 for (uint cct1 = 0; cct1 < itsColT.size(); ++cct1)//colors target 00566 for (uint cct2 = cct1; cct2 < itsColT.size(); ++cct2)//colors target1 00567 for (uint dd = 0; dd < itsDist.size(); ++dd)//distractor sets 00568 for (uint ss = 0; ss < itsShape.size(); ++ss)//shapes 00569 for (uint sst = 0; sst < itsShape[ss].size(); ++sst)//paired Targs 00570 for (uint ssd = 0; ssd < itsShape[ss].size(); ++ssd)//distractor 00571 if ((sst != ssd) || (itsShape[ss].size() == 1)) 00572 for (uint id = 0; id < idx.size(); ++id)//target on/of subset 00573 for (uint tp = 0; tp < idx[id].size(); ++tp)//col targ pos 00574 { 00575 //continue if we are on a zero destractor set, 00576 //and we are on the present nothing in RF - 00577 //as nothing on the screen is not 00578 //very interesting. 00579 if ((itsDist[dd] == 0) && (idx[id][0] == -1)) 00580 continue; 00581 00582 //if we only have one thing on the screen, there 00583 //is no reason to conterbalance colors, othewise 00584 //we get repeats. 00585 if ((idx[id].size() == 1) && (cct1 != cct2)) 00586 continue; 00587 00588 //if target and other targets are the same color 00589 //there is no need have different target 00590 //positions as it gives us repeats 00591 if ((cct1 == cct2) && (tp > 0)) 00592 continue; 00593 00594 //get possible distractor locations, excluding 00595 //ones near our on RF's for this trial. 00596 std::vector<geom::vec2<uint> > grid = getGrid(idx[id]); 00597 00598 //choose a distractor set size of these points to be on 00599 //by shuffle and resizing to the set size. 00600 std::random_shuffle(grid.begin(), grid.end()); 00601 if (itsDist[dd] < grid.size()) 00602 grid.resize(itsDist[dd]); 00603 00604 std::vector<ArrayItem*> array; 00605 std::string arraydescr, conddescr; 00606 00607 //distractor positions 00608 for (uint ii = 0; ii < grid.size(); ++ii) 00609 { 00610 ArrayItem* ai = createItem(itsShape[ss][ssd], 00611 grid[ii], 00612 itsColD[ccd]); 00613 array.push_back(ai); 00614 arraydescr += "::D:" + ai->toString(); 00615 } 00616 00617 00618 //Target positions 00619 std::vector<int>::iterator iter = idx[id].begin(); 00620 uint otc(0), rfc(0); 00621 while (iter != idx[id].end()) 00622 { 00623 if (*iter == -1) 00624 { 00625 ++iter; 00626 continue; 00627 } 00628 00629 ArrayItem* ai = NULL; 00630 if (*iter == idx[id][tp]) 00631 ai = createItem(itsShape[ss][sst], 00632 itsRF[*iter].pos, 00633 itsColT[cct1]); 00634 else 00635 ai = createItem(itsShape[ss][sst], 00636 itsRF[*iter].pos, 00637 itsColT[cct2]); 00638 00639 array.push_back(ai); 00640 if (itsRF[*iter].size == 0) 00641 { 00642 arraydescr += "::OT:" + ai->toString(); 00643 ++otc; 00644 } 00645 else 00646 { 00647 arraydescr += "::RF:" + ai->toString(); 00648 ++rfc; 00649 } 00650 ++iter; 00651 } 00652 00653 //ok lets add some description of the condition 00654 //target count 00655 conddescr += toStr<uint>(rfc) + ":"; 00656 //other target cound 00657 conddescr += toStr<uint>(otc) + ":"; 00658 //target color 00659 conddescr += toStr<PixRGB<byte> >(itsColT[cct1]) + ":"; 00660 //other target color 00661 conddescr += toStr<PixRGB<byte> >(itsColT[cct2]) + ":"; 00662 //distractor color 00663 conddescr += toStr<PixRGB<byte> >(itsColD[ccd]) + ":"; 00664 //setsize 00665 conddescr += toStr<uint>(itsDist[dd]) + ":"; 00666 //target shape 00667 conddescr += toStr<ItemType>(itsShape[ss][sst]) + ":"; 00668 //distractor shape 00669 conddescr += toStr<ItemType>(itsShape[ss][ssd]); 00670 00671 //store array and description 00672 itsDescr.push_back(conddescr + arraydescr); 00673 itsStims.push_back(array); 00674 00675 } 00676 } 00677 00678 // ###################################################################### 00679 void ArrayCreator::subset(std::vector<std::vector<int> >& sub, const uint N) 00680 { 00681 uint tu = sub.back().back()+1; 00682 if (tu < N) 00683 { 00684 std::vector<int> tv = sub.back(); 00685 tv.push_back(tu); 00686 sub.push_back(tv); 00687 this->subset(sub, N); 00688 } 00689 else 00690 { 00691 std::vector<int> tv = sub.back(); 00692 if (tv.size() > 1) 00693 { 00694 tv.pop_back(); 00695 tv.back()+=1; 00696 sub.push_back(tv); 00697 this->subset(sub, N); 00698 } 00699 } 00700 } 00701 00702 // ###################################################################### 00703 std::vector<geom::vec2<uint> > 00704 ArrayCreator::getGrid(const std::vector<int>& onpos) 00705 { 00706 std::vector<int> pos; 00707 if (onpos[0] == -1) 00708 for (size_t ii = 0; ii < itsRF.size(); ++ii) 00709 pos.push_back((int)ii); 00710 else 00711 pos = onpos; 00712 00713 //create a grid 00714 const int rad = int(itsRad * itsPpd + 0.5f);//conver to pixels 00715 const int noise = int(itsNoise * itsPpd + 0.5f); 00716 const int fxsize = int(itsFixSize * itsPpd + 0.5f); 00717 const int sz = rad*2 + noise; 00718 const int sz2 = rad*2 + 2*noise; 00719 00720 Dims gsize(itsDims.w() - sz, itsDims.h() - sz); 00721 Dims nums(int((float)gsize.w() / (float)(sz2)), 00722 int((float)gsize.h() / (float)(sz2))); 00723 00724 int tx = nums.w() * sz2; 00725 int ty = nums.h() * sz2; 00726 00727 int lx = int(float(itsDims.w() - tx)/2.0f); 00728 int ly = int(float(itsDims.h() - ty)/2.0f); 00729 00730 geom::vec2<int> c(itsDims.w()/2 - 1, itsDims.h()/2 - 1); 00731 std::vector<geom::vec2<uint> > grid; 00732 for (int xx = lx; xx <= itsDims.w() - lx; xx += sz2) 00733 for (int yy = ly; yy <= itsDims.h() - ly; yy += sz2) 00734 { 00735 geom::vec2<float> polar; 00736 polar.set_polar_rad(rnum.fdraw_range(0, noise), 00737 rnum.fdraw_range(0,2*M_PI)); 00738 geom::vec2<int> tv(xx + polar.x(), yy + polar.y()); 00739 00740 bool use = true; 00741 std::vector<int>::const_iterator op = pos.begin(); 00742 while (op != pos.end()) 00743 { 00744 geom::vec2<int> rf((int)itsRF[*op].pos.x(), 00745 (int)itsRF[*op].pos.y()); 00746 float d = tv.distance_to(rf); 00747 if (d <= rad*2) 00748 use = false; 00749 ++op; 00750 } 00751 00752 float dc = 10000; 00753 if (fxsize > 0) 00754 dc = tv.distance_to(c); 00755 00756 if (use && (dc > (rad + fxsize/2 + noise))) 00757 grid.push_back(geom::vec2<uint>((uint)tv.x(), (uint)tv.y())); 00758 } 00759 return grid; 00760 } 00761 00762 // ###################################################################### 00763 ArrayItem* ArrayCreator::createItem(const ItemType item, 00764 const geom::vec2<uint>& pos, 00765 const PixRGB<byte>& color) 00766 { 00767 const uint rad = uint(itsRad * itsPpd + 0.5f); 00768 switch (item) 00769 { 00770 case BARH: 00771 return new BarItem(pos.x(), pos.y(), rad, color, float(M_PI/2.0)); 00772 case BARV: 00773 return new BarItem(pos.x(), pos.y(), rad, color, 0); 00774 case CIRCLE: 00775 return new CircleItem(pos.x(), pos.y(), rad, color, 0); 00776 case SQUARE: 00777 return new SquareItem(pos.x(), pos.y(), rad, color, 0); 00778 case BLOB: 00779 return new BlobItem(pos.x(), pos.y(), rad, color, 0); 00780 default: 00781 { 00782 LFATAL("No such item type"); 00783 return NULL; 00784 } 00785 } 00786 } 00787 00788 // ###################################################################### 00789 /* So things look consistent in everyone's emacs... */ 00790 /* Local Variables: */ 00791 /* mode: c++ */ 00792 /* indent-tabs-mode: nil */ 00793 /* End: */ 00794 00795 #endif // PSYCHO_ARRAYCREATOR_C_DEFINED