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

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