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

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