00001 #ifndef Impala_Visualization_RotorBrowser_ThreadClusterSelector_h
00002 #define Impala_Visualization_RotorBrowser_ThreadClusterSelector_h
00003
00004 #include "OglGui/Window.h"
00005 #include "Visualization/KeyBindingsMap.h"
00006 #include "RotorView.h"
00007 #include "RotorViewCache.h"
00008 #include "RotorBrowserContext.h"
00009
00010 #include "Core/Trec/ThreadSet.h"
00011
00012 #include <vector>
00013
00014
00015 namespace Impala {
00016 namespace Visualization {
00017 namespace RotorBrowser {
00018
00019
00020
00021
00022 class ThreadClusterSelector
00023 {
00024 public:
00025 typedef Core::Trec::Thread Thread;
00026 typedef Core::Trec::ThreadShots ThreadShots;
00027 typedef Core::Trec::ThreadRank ThreadRank;
00028 typedef Core::Trec::ThreadVisualSimilarity ThreadVisualSimilarity;
00029
00030 ThreadClusterSelector(RotorViewCache *cache)
00031 {
00032 InitKeyBindings();
00033 mCache = cache;
00034 mShowing = false;
00035 mSelectionSize = 36;
00036 mPaginated = true;
00037
00038 mThresholdDelta = 0.2;
00039 mThresholdDissim = true;
00040 }
00041
00042 bool CheckKBN(String keyStr, int c, int state, int n=6)
00043 {
00044 return CheckKeyBindingExt(mKeyBindings, keyStr, c, state, n);
00045 }
00046
00047 void InitKeyBindings()
00048 {
00049 KeyBindingsMap& kb = mKeyBindings;
00050
00051 InitKeyBinding(kb,"RbCsNextPage", "d", "D");
00052 InitKeyBinding(kb,"RbCsPrevPage", "a", "A");
00053 InitKeyBinding(kb,"RbCsIncrSelectionSize", "w", "W");
00054 InitKeyBinding(kb,"RbCsDecrSelectionSize", "s", "S");
00055 InitKeyBinding(kb,"RbCsBrowseDecrSelectionSize", "a", "A");
00056 InitKeyBinding(kb,"RbCsBrowseIncrSelectionSize", "d", "D");
00057 InitKeyBinding(kb,"RbCsTogglePaginate", "r", "R");
00058 InitKeyBinding(kb,"RbCsClusterBookPositive", "space");
00059 InitKeyBinding(kb,"RbCsClusterBookPositiveForced", "shift-space");
00060 InitKeyBinding(kb,"RbCsClusterBookNegative", "x");
00061 InitKeyBinding(kb,"RbCsClusterBookNegativeForced", "X");
00062 }
00063
00064 void Show(RotorBrowserContext *context)
00065 {
00066 mContext = context;
00067 mShowing = true;
00068 ILOG_DEBUG("Showing thread cluster selector");
00069 mThresholdDelta = GetThresholdForNumber(6);
00070 ShowRelevantSquare();
00071 }
00072
00073 void Hide()
00074 {
00075 mShowing = false;
00076 }
00077
00078 bool IsActive()
00079 {
00080 return mShowing;
00081 }
00082
00083 int GetSelectionSize()
00084 {
00085 if (!mPaginated)
00086 return GetNumberForThreshold();
00087 return mSelectionSize;
00088 }
00089
00090 void SetSelectionSize(int nr)
00091 {
00092 if (!mPaginated)
00093 return;
00094
00095 if (nr < 1)
00096 nr = 1;
00097 if (nr > 96)
00098 nr = 96;
00099 mSelectionSize = nr;
00100 ShowRelevantSquare();
00101 }
00102
00103
00104 int GetPageSize(int n)
00105 {
00106 if (n > 96) return 13;
00107 if (n > 88) return 12;
00108 if (n > 80) return 11;
00109 if (n > 72) return 10;
00110 if (n > 64) return 9;
00111 if (n > 49) return 8;
00112 if (n > 36) return 7;
00113 if (n > 25) return 6;
00114 if (n > 16) return 5;
00115 if (n > 9) return 4;
00116 if (n > 4) return 3;
00117 if (n > 1) return 2;
00118 if (n== 1) return 1;
00119 return 0;
00120 }
00121
00122 int GetNumberOnPage(int n)
00123 {
00124 if (n < 0) n = 0;
00125 if (n > 11) n = 11;
00126 switch (n)
00127 {
00128 case 1: return 1;
00129 case 2: return 4;
00130 case 3: return 9;
00131 case 4: return 16;
00132 case 5: return 25;
00133 case 6: return 36;
00134 case 7: return 49;
00135 case 8: return 64;
00136 case 9: return 72;
00137 case 10: return 80;
00138 case 11: return 88;
00139 case 12: return 96;
00140 }
00141
00142 return n;
00143 }
00144
00145 Real64 GetThresholdForShotId(int shot)
00146 {
00147
00148
00149 Thread *t = mContext->GetThread();
00150 int position = t->GetShotPosition(shot);
00151 if (t >= 0)
00152 {
00153 if (t->GetType() == Thread::SHOTS)
00154 return ((ThreadShots*)t)->GetShotScore(position);
00155 if (t->GetType() == Thread::RANK)
00156 return ((ThreadRank*)t)->GetShotScore(position);
00157 if (t->GetType() == Thread::VISUAL)
00158 return ((ThreadVisualSimilarity*)t)->GetSimilarity(shot);
00159 }
00160 else
00161 {
00162 ILOG_WARN("Could not find position for shot " << shot <<
00163 " in thread " << mContext->GetName());
00164 return 1.0;
00165 }
00166
00167 return 1.0;
00168 }
00169
00170 Real64 GetTDelta(Real64 a, Real64 b)
00171 {
00172 if (b > a)
00173 return b - a;
00174 return a - b;
00175 }
00176
00177 int GetNumberForThreshold()
00178 {
00179 bool goodShot = true;
00180 double thisShotSim = GetThresholdForShotId( GetRelevant(0) );
00181 ILOG_DEBUG("Base thres=" << thisShotSim);
00182 int ctr = 1;
00183 while (true)
00184 {
00185 double nextShotSim = GetThresholdForShotId( GetRelevant(ctr) );
00186
00187 if (GetTDelta(thisShotSim, nextShotSim) > mThresholdDelta)
00188 {
00189 ILOG_DEBUG(" pos " << ctr << " shot " << GetRelevant(ctr) <<
00190 " score " << nextShotSim);
00191 break;
00192 }
00193 if (ctr < 10)
00194 ILOG_DEBUG(" pos " << ctr << " shot " << GetRelevant(ctr) <<
00195 " score " << nextShotSim);
00196 ctr ++;
00197
00198 if (ctr >= 96)
00199 break;
00200 }
00201 ILOG_DEBUG("number of relevant images: " << ctr);
00202 return ctr;
00203 }
00204
00205 Real64 GetThresholdForNumber(int number)
00206 {
00207
00208 Real64 thisShotSim = GetThresholdForShotId( GetRelevant(0) );
00209 ILOG_DEBUG("GetThresholdForNumber start thres=" << thisShotSim);
00210 Real64 thatShotSim = GetThresholdForShotId( GetRelevant(number) );
00211 ILOG_DEBUG("GetThresholdForNumber stop " << number << " thres=" <<
00212 thatShotSim);
00213
00214 Real64 tdelta = GetTDelta(thatShotSim, thisShotSim);
00215
00216 tdelta += 0.05 * tdelta;
00217
00218 ILOG_DEBUG("Threshold for " << number << " images: " << tdelta);
00219 return tdelta;
00220 }
00221
00222
00223
00224
00225
00226 bool CurrentContextHasSimilarities()
00227 {
00228 return mContext && mContext->GetThread() &&
00229 (mContext->GetThread()->GetType() == Thread::RANK ||
00230 mContext->GetThread()->GetType() == Thread::SHOTS ||
00231 mContext->GetThread()->GetType() == Thread::VISUAL);
00232 }
00233
00234 void DecreaseThreshold()
00235 {
00236 int number = GetNumberForThreshold();
00237 number = number / 2;
00238 mThresholdDelta = GetThresholdForNumber(number);
00239
00240 if (mThresholdDelta < 0.001) mThresholdDelta = 0.001;
00241 ILOG_DEBUG("Threshold at " << mThresholdDelta);
00242 }
00243
00244 void IncreaseThreshold()
00245 {
00246 int number = GetNumberForThreshold();
00247 mThresholdDelta = GetThresholdForNumber(number + 1);
00248
00249
00250 ILOG_DEBUG("Threshold at " << mThresholdDelta);
00251 }
00252
00253 void IncreaseSelectionSize()
00254 {
00255 if (mPaginated)
00256 SetSelectionSize(GetNumberOnPage(GetPageSize(mSelectionSize)+1));
00257 else
00258 {
00259 IncreaseThreshold();
00260 SetSelectionSize(GetNumberForThreshold());
00261 }
00262 ShowRelevantSquare();
00263 }
00264
00265 void DecreaseSelectionSize()
00266 {
00267 if (mPaginated)
00268 SetSelectionSize(GetNumberOnPage(GetPageSize(mSelectionSize)-1));
00269 else
00270 {
00271 DecreaseThreshold();
00272 SetSelectionSize(GetNumberForThreshold());
00273 }
00274 ShowRelevantSquare();
00275 }
00276
00277 bool GetPagemode()
00278 {
00279 return mPaginated;
00280 }
00281
00282
00283
00284
00285
00286 void SetPagemode(bool pagemode)
00287 {
00288 if (pagemode == false && !CurrentContextHasSimilarities())
00289 {
00290 ILOG_WARN("Could not switch to threshold mode, " <<
00291 "active thread does not have similarities.");
00292 return;
00293 }
00294 mPaginated = pagemode;
00295 ShowRelevantSquare();
00296 }
00297
00298
00299
00300
00301 int GetSelectedShotsCount()
00302 {
00303 if (!mPaginated)
00304 return GetNumberForThreshold();
00305 return mSelectionSize;
00306 }
00307
00308 std::vector<int> GetSelectedShots()
00309 {
00310 std::vector<int> shots;
00311 for (int i=0; i<GetSelectedShotsCount(); i++)
00312 shots.push_back(GetRelevant(i));
00313
00314 return shots;
00315 }
00316
00317
00318
00319 int GetVisibleShotsCount()
00320 {
00321 if (!mPaginated)
00322 return GetNumberForThreshold();
00323 return mSelectionSize;
00324 }
00325
00326 std::vector<int> GetVisibleShots()
00327 {
00328 std::vector<int> shots;
00329 for (int i=0; i<GetVisibleShotsCount(); i++)
00330 shots.push_back(GetRelevant(i));
00331
00332 return shots;
00333 }
00334
00335 bool ClusterKeyboardFunc(int c, int state)
00336 {
00337 bool keyHandled = true;
00338
00339 if (!GetPagemode())
00340 {
00341
00342
00343
00344
00345 if (CheckKBN("RbCsBrowseDecrSelectionSize", c, state))
00346 c = 's';
00347 if (CheckKBN("RbCsBrowseIncrSelectionSize", c, state))
00348 c = 'w';
00349 }
00350
00351 if (CheckKBN("RbCsDecrSelectionSize", c, state))
00352 c = 's';
00353 else if (CheckKBN("RbCsIncrSelectionSize", c, state))
00354 c = 'w';
00355 else if (CheckKBN("RbCsNextPage", c, state))
00356 c = 'd';
00357 else if (CheckKBN("RbCsPrevPage", c, state))
00358 c = 'a';
00359 else if (CheckKBN("RbCsTogglePaginate", c, state))
00360 c = 'r';
00361
00362 switch (c)
00363 {
00364 case 's':
00365 ILOG_USER("KB: decrease selection size in cluster viewer");
00366 DecreaseSelectionSize();
00367 break;
00368 case 'w':
00369 ILOG_USER("KB: decrease selection size in cluster viewer");
00370 IncreaseSelectionSize();
00371 break;
00372
00373 case 'd':
00374 ILOG_USER("KB: move to next page in cluster viewer");
00375 mContext->MoveRelative(GetSelectionSize());
00376 Show(mContext);
00377 break;
00378
00379 case 'a':
00380 ILOG_USER("KB: move to previous page in cluster viewer");
00381 mContext->MoveRelative(-GetSelectionSize());
00382 Show(mContext);
00383 break;
00384
00385 case 'r':
00386 ILOG_USER("KB: Toggle paginate / threshold mode");
00387 SetPagemode(!GetPagemode());
00388 ILOG_USER("KB: Toggle paginate / threshold mode, now: " <<
00389 GetPagemode());
00390
00391
00392 break;
00393
00394 default:
00395 keyHandled = false;
00396 }
00397 return keyHandled;
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 private:
00455
00456 int GetWidth(int number)
00457 {
00458 int h = GetHeight(number);
00459 return (int)ceil((float)number / (float)h);
00460 }
00461
00462 int GetHeight(int number)
00463 {
00464 int n = (int)ceil(sqrt((float)number));
00465 if (n > 8) n = 8;
00466 return n;
00467 }
00468
00469 void ShowRelevantSquare()
00470 {
00471 int number = mSelectionSize;
00472 if (!mPaginated)
00473 {
00474 if (!CurrentContextHasSimilarities())
00475 {
00476 ILOG_DEBUG("Showing paginated mode, curr thread has no sims.");
00477 }
00478 else
00479 number = GetNumberForThreshold();
00480 }
00481
00482 mCache->DoHide(mCache->GetViews());
00483
00484 float xspacer = 0.65f;
00485 float yspacer = 0.55f;
00486
00487 int ctr = 0;
00488 float bx = -GetWidth(number) * xspacer / 2.0f + 0.5f * xspacer;
00489 float by = -GetHeight(number) * yspacer / 2.0f + 0.5f * yspacer;
00490 ILOG_DEBUG("ShowRelevantSquare(" << number<< "): width=" <<
00491 GetWidth(number) << " height=" << GetHeight(number));
00492 for (int i=0; i < GetHeight(number); i++)
00493 {
00494 for (int j=0; j < GetWidth(number); j++)
00495 {
00496 int item = GetRelevant(ctr);
00497 if (item < 0)
00498 {
00499 ctr = number + 1;
00500 break;
00501 }
00502 RotorView *v =
00503 mCache->GetViewFor(mContext->GetName(), GetRelevant(ctr));
00504 float x = bx + xspacer * j;
00505 float y = -by - yspacer * i;
00506 v->MoveFrom(0.0f, 0.0f, -10.0f, 0.5f, 1.0f);
00507 v->MoveTo(x,y,-2.0f,0.5f,1.0f);
00508
00509 if (++ctr > number)
00510 break;
00511 }
00512 if (ctr > number)
00513 break;
00514 }
00515
00516 mCache->DoCleanup(mCache->GetViews());
00517 }
00518
00519 int GetRelevant(int pos)
00520 {
00521 int item = mContext->GetRelative(pos);
00522 return item;
00523 }
00524
00525 KeyBindingsMap mKeyBindings;
00526 RotorBrowserContext* mContext;
00527 RotorViewCache* mCache;
00528
00529 Real64 mThresholdDelta;
00530
00531 int mSelectionSize;
00532
00533 bool mThresholdDissim;
00534 bool mShowing;
00535 bool mPaginated;
00536
00537 ILOG_VAR_DEC;
00538
00539 };
00540
00541 ILOG_VAR_INIT(ThreadClusterSelector, Visualization.RotorBrowser);
00542
00543 }
00544 }
00545 }
00546 #endif