source: trunk/MagicSoft/Mars/mtools/MagicDomino.cc@ 9366

Last change on this file since 9366 was 8910, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 16.6 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MagicDomino
28// -----------
29//
30// Magic Camera games.
31//
32// Start the show by:
33// MagicDomino show;
34//
35// Use the following keys:
36// -----------------------
37//
38// * Cursor up/down, left/right:
39// Move tile
40//
41// * Space:
42// Rotate tile
43//
44// * Enter:
45// Set tile
46//
47// * Esc:
48// Skip tile
49//
50// Rules:
51// ------
52//
53// Each hexagon in the tile must at least have one neighbor
54// which has the same color. It is not allowed to put a tile onto
55// another one. The game is over if you have skipped three tiles
56// in a row.
57//
58////////////////////////////////////////////////////////////////////////////
59#include "MagicDomino.h"
60
61#include <iostream>
62
63#include <KeySymbols.h>
64
65#include <TMath.h>
66#include <TCanvas.h>
67#include <TRandom.h>
68#include <TInterpreter.h>
69
70#include "MHexagon.h"
71
72#include "MGeomPix.h"
73#include "MGeomCamCT1.h"
74#include "MGeomCamMagic.h"
75
76ClassImp(MagicDomino);
77
78using namespace std;
79
80// ------------------------------------------------------------------------
81//
82// Free all onbects connected to a special camera geometry
83//
84void MagicDomino::Free()
85{
86 if (!fGeomCam)
87 return;
88
89 fPixels->Delete();
90
91 delete fPixels;
92
93 delete fGeomCam;
94}
95
96// ------------------------------------------------------------------------
97//
98// Draw all pixels of the camera
99// (means apend all pixelobjects to the current pad)
100//
101void MagicDomino::DrawHexagons()
102{
103 for (UInt_t i=0; i<fNumPixels; i++)
104 (*this)[i].Draw();
105}
106
107// ------------------------------------------------------------------------
108//
109// Change camera from Magic to CT1 and back
110//
111void MagicDomino::ChangeCamera()
112{
113 static Bool_t ct1=kFALSE;
114
115 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
116
117 if (ct1)
118 SetNewCamera(new MGeomCamMagic);
119 else
120 SetNewCamera(new MGeomCamCT1);
121
122 ct1 = !ct1;
123
124 Reset();
125 DrawHexagons();
126}
127
128// ------------------------------------------------------------------------
129//
130// Reset/set all veriables needed for a new camera geometry
131//
132void MagicDomino::SetNewCamera(MGeomCam *geom)
133{
134 Free();
135
136 //
137 // Reset the display geometry
138 //
139 fW=0;
140 fH=0;
141
142 //
143 // Set new camera
144 //
145 fGeomCam = geom;
146
147 //
148 // create the hexagons of the display
149 //
150 fNumPixels = fGeomCam->GetNumPixels();
151 fRange = fGeomCam->GetMaxRadius();
152
153 //
154 // Construct all hexagons. Use new-operator with placement
155 //
156 fPixels = new TClonesArray("MHexagon", fNumPixels);
157
158 for (UInt_t i=0; i<fNumPixels; i++)
159 {
160 MHexagon &h = *new ((*fPixels)[i]) MHexagon((*fGeomCam)[i]);
161#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
162 h.SetBit(kNoContextMenu|kCannotPick);
163#endif
164 }
165}
166
167// ------------------------------------------------------------------------
168//
169// remove the pixel numbers in the tile from the pad
170//
171void MagicDomino::RemoveNumbers()
172{
173 for (int i=0; i<6; i++)
174 if (fText[i])
175 {
176 delete fText[i];
177 fText[i] = NULL;
178 }
179}
180
181// ------------------------------------------------------------------------
182//
183// Reset/restart the game
184//
185void MagicDomino::Reset()
186{
187 for (UInt_t i=0; i<fNumPixels; i++)
188 {
189 MHexagon &h = (*this)[i];
190 h.SetFillColor(kBackground);
191 h.ResetBit(kUserBits);
192 }
193
194
195#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
196 fDrawingPad->SetBit(kNoContextMenu);
197 SetBit(kNoContextMenu);
198#endif
199
200 if (fDone)
201 {
202 delete fDone;
203 fDone = NULL;
204 }
205
206
207 fDrawingPad->SetFillColor(22);
208
209 fNumPixel = -1;
210 fNumTile = 0;
211 fPoints = 0;
212
213 NewTile();
214}
215
216// ------------------------------------------------------------------------
217//
218void MagicDomino::Init()
219{
220 memset(fText, 0, sizeof(fText));
221
222 //
223 // Make sure, that the object is destroyed when the canvas/pad is
224 // destroyed. Make also sure, that the interpreter doesn't try to
225 // delete it a second time.
226 //
227 SetBit(kCanDelete);
228 gInterpreter->DeleteGlobal(this);
229
230 Draw();
231}
232
233// ------------------------------------------------------------------------
234//
235// default constructor
236//
237MagicDomino::MagicDomino()
238 : fGeomCam(NULL), fDir(kBottom), fDone(NULL)
239{
240 SetNewCamera(new MGeomCamMagic);
241 Init();
242}
243// ------------------------------------------------------------------------
244//
245//
246MagicDomino::MagicDomino(const MGeomCam &geom)
247 : fGeomCam(NULL), fDir(kBottom), fDone(NULL)
248{
249 SetNewCamera(static_cast<MGeomCam*>(geom.Clone()));
250 Init();
251}
252
253// ------------------------------------------------------------------------
254//
255// Destructor. Deletes TClonesArrays for hexagons and legend elements.
256//
257MagicDomino::~MagicDomino()
258{
259 Free();
260
261 RemoveNumbers();
262
263 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
264 {
265 fDrawingPad->RecursiveRemove(this);
266 delete fDrawingPad;
267 }
268
269}
270
271// ------------------------------------------------------------------------
272//
273// This is called at any time the canvas should get repainted.
274// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
275// that the camera image doesn't get distorted by resizing the canvas.
276//
277void MagicDomino::Paint(Option_t *opt)
278{
279 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
280 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
281
282 //
283 // Check for a change in width or height, and make sure, that the
284 // first call also sets the range
285 //
286 if (w*fH == h*fW && fW && fH)
287 return;
288
289 //
290 // Calculate aspect ratio (5/4=1.25 recommended)
291 //
292 const Double_t ratio = (Double_t)w/h;
293
294 Float_t x;
295 Float_t y;
296
297 if (ratio>1.0)
298 {
299 x = fRange*(ratio*2-1);
300 y = fRange;
301 }
302 else
303 {
304 x = fRange;
305 y = fRange/ratio;
306 }
307
308 fH = h;
309 fW = w;
310
311 //
312 // Set new range
313 //
314 fDrawingPad->Range(-fRange, -y, x, y);
315}
316
317// ------------------------------------------------------------------------
318//
319// Call this function to draw the camera layout into your canvas.
320// Setup a drawing canvas. Add this object and all child objects
321// (hexagons, etc) to the current pad. If no pad exists a new one is
322// created.
323//
324void MagicDomino::Draw(Option_t *option)
325{
326 //
327 // if no canvas is yet existing to draw into, create a new one
328 //
329 /*TCanvas *c =*/ new TCanvas("MagicDomino", "Magic Domino Next Neighbours", 0, 0, 800, 800);
330 //c->ToggleEventStatus();
331
332 fDrawingPad = gPad;
333 fDrawingPad->SetBorderMode(0);
334
335 //
336 // Append this object, so that the aspect ratio is maintained
337 // (Paint-function is called)
338 //
339 AppendPad(option);
340
341 //
342 // Reset the game pad
343 //
344 Reset();
345 DrawHexagons();
346
347 /*
348 TPave *p = new TPave(-0.66*fRange, 0.895*fRange, 0.66*fRange, 0.995*fRange, 4, "br");
349 p->ConvertNDCtoPad();
350 p->SetFillColor(12);
351 p->SetBit(kCanDelete);
352 p->Draw();
353 */
354
355 fDomino.SetTextAlign(23); // centered/bottom
356#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
357 fDomino.SetBit(kNoContextMenu|kCannotPick);
358#endif
359 fDomino.Draw();
360}
361
362void MagicDomino::Update()
363{
364 TString txt = "Points: ";
365 txt += fPoints;
366 txt += " Tile: ";
367 txt += fNumTile;
368
369 switch (fSkipped)
370 {
371 case 0:
372 fDomino.SetTextColor(8/*kGreen*/);
373 break;
374 case 1:
375 fDomino.SetTextColor(kYellow);
376 break;
377 case 2:
378 fDomino.SetTextColor(kRed);
379 break;
380 default:
381 fDomino.SetTextColor(kWhite);
382 break;
383 }
384 fDomino.SetText(0, fRange, txt);
385}
386
387// ------------------------------------------------------------------------
388//
389// Choose new colors for the tile
390//
391void MagicDomino::NewColors()
392{
393 TRandom rnd(0);
394 for (int i=0; i<3; i++)
395 {
396 Int_t color = (Int_t)rnd.Uniform(5)+2;
397 fNewColors[i*2] = color;
398 fNewColors[i*2+1] = color;
399 }
400}
401
402// ------------------------------------------------------------------------
403//
404// Create a new tile
405//
406void MagicDomino::NewTile()
407{
408 if (fNumPixel>=0)
409 {
410 const MGeomPix &pix=(*fGeomCam)[fNumPixel];
411 (*this)[fNumPixel].ResetBit(kIsTile);
412 for (int i=0; i<pix.GetNumNeighbors(); i++)
413 (*this)[pix.GetNeighbor(i)].ResetBit(kIsTile);
414
415 fPoints += pix.GetNumNeighbors();
416 }
417
418 RemoveNumbers();
419
420 fNumPixel = -1;
421 fSkipped = 0;
422 fNumTile++;
423
424 NewColors();
425 Update();
426
427 fDrawingPad->Update();
428}
429
430// ------------------------------------------------------------------------
431//
432// Check for at least one correct color for each pixel in tile.
433// Ignore the tile itself and all background pixels. Check whether
434// background of tile is empty.
435//
436Bool_t MagicDomino::CheckTile()
437{
438 if (fNumPixel<0)
439 return kFALSE;
440
441 for (int i=0; i<7; i++)
442 if (fOldColors[i]!=kBackground)
443 return kFALSE;
444
445 Int_t cnt=0;
446 const MGeomPix &pix1=(*fGeomCam)[fNumPixel];
447 for (int i=0; i<pix1.GetNumNeighbors(); i++)
448 {
449 const Int_t idx1 = pix1.GetNeighbor(i);
450 const MGeomPix &pix2 = (*fGeomCam)[idx1];
451
452 Byte_t ignored = 0;
453 Byte_t found = 0;
454 for (int j=0; j<pix2.GetNumNeighbors(); j++)
455 {
456 const Int_t idx2 = pix2.GetNeighbor(j);
457 const MHexagon &hex = (*this)[idx2];
458
459 if (hex.TestBit(kIsTile) || hex.GetFillColor()==kBackground)
460 {
461 ignored++;
462 continue;
463 }
464
465 if (hex.GetFillColor()==(*this)[idx1].GetFillColor())
466 found++;
467 }
468 if (ignored==pix2.GetNumNeighbors() || found>0)
469 cnt++;
470 }
471
472 return cnt==pix1.GetNumNeighbors();
473}
474
475// ------------------------------------------------------------------------
476//
477// Game over!
478//
479void MagicDomino::Done()
480{
481 fDone = new TText(0, 0, "Game Over!");
482 fDone->SetTextColor(kWhite); // white
483 fDone->SetTextAlign(22); // centered/centered
484 fDone->SetTextSize(0.05); // white
485 fDone->Draw();
486
487 fDomino.SetTextColor(kBlue);
488
489 fDrawingPad->SetFillColor(kRed);
490#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
491 fDone->SetBit(kNoContextMenu|kCannotPick);
492 fDrawingPad->ResetBit(kNoContextMenu);
493 ResetBit(kNoContextMenu);
494#endif
495
496 fDrawingPad->Modified();
497 fDrawingPad->Update();
498}
499
500// ------------------------------------------------------------------------
501//
502// Execute a mouse event on the camera
503//
504void MagicDomino::ExecuteEvent(Int_t event, Int_t keycode, Int_t keysym)
505{
506 if (event!=kKeyPress || fDone)
507 return;
508
509 switch (keysym)
510 {
511 case kKey_Escape:
512 fPoints -= 6;
513 fSkipped++;
514 if (fSkipped==3)
515 {
516 Done();
517 return;
518 }
519 NewColors();
520 RotateTile(0);
521 return;
522
523 case kKey_Space:
524 RotateTile(-1);
525 return;
526
527 case kKey_Return:
528 if (CheckTile())
529 NewTile();
530 return;
531
532 case kKey_Right:
533 fDir = kRight;
534 Step(kRight);
535 return;
536
537 case kKey_Left:
538 fDir = kLeft;
539 Step(kLeft);
540 return;
541
542 case kKey_Up:
543 Step(kTop|fDir);
544 return;
545
546 case kKey_Down:
547 Step(kBottom|fDir);
548 return;
549
550 case kKey_Plus:
551 RotateTile(+1);
552 return;
553
554 case kKey_Minus:
555 RotateTile(-1);
556 return;
557 }
558}
559
560// ------------------------------------------------------------------------
561//
562// Rotate the colors in the tile
563//
564void MagicDomino::RotateTile(Int_t add)
565{
566 fPosition += add+6; // Make result positive
567 fPosition %= 6; // Align result between 0 and 5
568
569 HideTile();
570 ShowTile();
571
572 Update();
573
574 fDrawingPad->Modified();
575 fDrawingPad->Update();
576}
577
578// ------------------------------------------------------------------------
579//
580// Hide the tile from the pad
581//
582void MagicDomino::HideTile()
583{
584 if (fNumPixel<0)
585 return;
586
587 MagicDomino &This = *this;
588
589 RemoveNumbers();
590
591 const MGeomPix &pix1=(*fGeomCam)[fNumPixel];
592 This[fNumPixel].SetFillColor(fOldColors[6]);
593 This[fNumPixel].ResetBit(kIsTile);
594 for (int i=0; i<pix1.GetNumNeighbors(); i++)
595 {
596 Int_t idx = pix1.GetNeighbor(i);
597
598 This[idx].SetFillColor(fOldColors[i]);
599 This[idx].ResetBit(kIsTile);
600 }
601}
602
603// ------------------------------------------------------------------------
604//
605// Show the tile on the pad
606//
607void MagicDomino::ShowTile()
608{
609 if (fNumPixel<0)
610 return;
611
612 MagicDomino &This = *this;
613
614 Int_t indices[6];
615 GetSortedNeighbors(indices);
616
617 RemoveNumbers();
618
619 const MGeomPix &pix2=(*fGeomCam)[fNumPixel];
620 fOldColors[6] = This[fNumPixel].GetFillColor();
621 This[fNumPixel].SetFillColor(kBlack);
622 This[fNumPixel].SetBit(kIsTile);
623 for (int i=0; i<pix2.GetNumNeighbors(); i++)
624 {
625 Int_t idx = pix2.GetNeighbor(i);
626
627 fOldColors[i] = This[idx].GetFillColor();
628
629 int j=0;
630 while (indices[j]!=i)
631 j++;
632
633 This[idx].SetFillColor(fNewColors[(j+fPosition)%6]);
634 This[idx].SetBit(kIsTile);
635
636 TString num;
637 num += idx;
638
639 fText[i] = new TText(This[idx].GetX(), This[idx].GetY(), num);
640 fText[i]->SetTextSize(0.3*This[idx].GetD()/fGeomCam->GetMaxRadius());
641 fText[i]->SetTextFont(122);
642 fText[i]->SetTextAlign(22); // centered/centered
643 fText[i]->Draw();
644 }
645}
646
647// ------------------------------------------------------------------------
648//
649// Hide the tile, change its position, show it again, update status text
650//
651void MagicDomino::ChangePixel(Int_t add)
652{
653 HideTile();
654
655 fNumPixel = add;
656
657 ShowTile();
658
659 Update();
660
661 fDrawingPad->Update();
662}
663
664// ------------------------------------------------------------------------
665//
666// Analyse the directions of the next neighbors
667//
668Short_t MagicDomino::AnalysePixel(Int_t dir)
669{
670 const MGeomPix &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel];
671
672 Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 };
673
674 for (int i=0; i<pix.GetNumNeighbors(); i++)
675 {
676 MGeomPix &next = (*fGeomCam)[pix.GetNeighbor(i)];
677 fAngle[i] = atan2(next.GetY()-pix.GetY(), next.GetX()-pix.GetX());
678 }
679
680 Int_t indices[6];
681 TMath::Sort(6, fAngle, indices); // left, top, right, bottom
682
683 for (int i=0; i<pix.GetNumNeighbors(); i++)
684 {
685 const Int_t idx = pix.GetNeighbor(indices[i]);
686 const Double_t angle = fAngle[indices[i]]*180/TMath::Pi();
687
688 if (angle<-149 && dir==kLeft)
689 return idx;
690 if (angle>-149 && angle<-90 && dir==kBottomLeft)
691 return idx;
692 //if (angle==-90 && dir==kBottom)
693 // return idx;
694 if (angle>-90 && angle<-31 && dir==kBottomRight)
695 return idx;
696 if (angle>-31 && angle<31 && dir==kRight)
697 return idx;
698 if (angle>31 && angle<90 && dir==kTopRight)
699 return idx;
700 //if (angle==90 && dir==kTop)
701 // return idx;
702 if (angle>90 && angle<149 && dir==kTopLeft)
703 return idx;
704 if (angle>149 && dir==kLeft)
705 return idx;
706 }
707 return -1;
708}
709
710// ------------------------------------------------------------------------
711//
712// Sort the next neighbort from the left, top, right, bottom
713//
714void MagicDomino::GetSortedNeighbors(Int_t indices[6])
715{
716 const MGeomPix &pix=(*fGeomCam)[fNumPixel<0?0:fNumPixel];
717
718 Double_t fAngle[6] = { -10, -10, -10, -10, -10, -10 };
719
720 for (int i=0; i<pix.GetNumNeighbors(); i++)
721 {
722 MGeomPix &next = (*fGeomCam)[pix.GetNeighbor(i)];
723 fAngle[i] = atan2(next.GetY()-pix.GetY(), next.GetX()-pix.GetX());
724 }
725
726 TMath::Sort(6, fAngle, indices); // left, top, right, bottom
727}
728
729// ------------------------------------------------------------------------
730//
731// Move tile one step in the given direction
732//
733void MagicDomino::Step(Int_t dir)
734{
735 Short_t newidx = AnalysePixel(dir);
736 if (newidx<0)
737 return;
738 ChangePixel(newidx);
739}
740
Note: See TracBrowser for help on using the repository browser.