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

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