source: trunk/Mars/mbase/MGMap.cc@ 9969

Last change on this file since 9969 was 9552, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 16.9 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, 05/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2002-2008
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MGMap
28// =====
29//
30// This Map of TObjects connects TObjects with a TString. It can be used
31// to create maps which displays tooltips it the mouse is above the objects.
32//
33// It is also a tool to convert TObjects which are drawn into
34// a bitmap or to draw them into a TGFrame. Because in both cases the
35// support for drawing such object must be programmed explicitly only
36// simple objects (TLine, TMarker, etc) are supported.
37//
38//////////////////////////////////////////////////////////////////////////////
39#include "MGMap.h"
40
41#include <climits> // INT_MAX (Ubuntu 8.10)
42
43#include <TMath.h>
44
45#include <TPad.h> // gPad, TPad::GetMaxDistance()
46
47#include <TLine.h>
48#include <TMarker.h>
49
50#include <TGToolTip.h>
51
52ClassImp(MGMap);
53
54using namespace std;
55
56//
57// THIS IS A WORKAROUND TO GET A MORE DIRECT ACCESS TO TGX11
58//
59/*
60#include <TGX11.h>
61class MGX11 : public TGX11
62{
63public:
64 ULong_t GetGc(Int_t which) const
65 {
66 return (ULong_t)*TGX11::GetGC(which);
67 }
68 void DrawLine(Drawable_t id, TObject *o, Int_t dx, Int_t dy, Float_t r)
69 {
70 TLine *l = dynamic_cast<TLine*>(o);
71 if (!l)
72 return;
73
74 SetLineColor(l->GetLineColor());
75 SetLineWidth(l->GetLineWidth());
76 SetLineStyle(l->GetLineStyle());
77
78 if (l->GetLineColor()==kRed)
79 SetLineColor(50);
80 if (l->GetLineColor()==kBlue)
81 SetLineColor(9);
82
83 gVirtualX->DrawLine(id, GetGc(0),
84 dx+(l->GetX1()/r), dy-(l->GetY1()/r),
85 dx+(l->GetX2()/r), dy-(l->GetY2()/r));
86 }
87 void DrawMarker(Drawable_t id, TObject *o, Int_t dx, Int_t dy, Float_t r)
88 {
89 TMarker *m = dynamic_cast<TMarker*>(o);
90 if (!m)
91 return;
92
93 SetLineColor(m->GetMarkerColor());
94 SetLineStyle(kSolid);
95 SetLineWidth(1);
96
97 const Double_t x = dx+(m->GetX()/r);
98 const Double_t y = dy-(m->GetY()/r);
99 const Int_t l = (Int_t)(m->GetMarkerSize()*5)+1;
100
101 switch (m->GetMarkerStyle())
102 {
103 case kPlus:
104 gVirtualX->DrawLine(id, GetGc(0), x-l, y, x+l, y);
105 gVirtualX->DrawLine(id, GetGc(0), x, y-l, x, y+l);
106 break;
107 case kCircle:
108 for (int i=0; i<8; i++)
109 gVirtualX->DrawLine(id, GetGc(0),
110 x+l*cos(i*TMath::TwoPi()/8),
111 y+l*sin(i*TMath::TwoPi()/8),
112 x+l*cos(((i+1)%8)*TMath::TwoPi()/8),
113 y+l*sin(((i+1)%8)*TMath::TwoPi()/8));
114 break;
115 case kCross:
116 gVirtualX->DrawLine(id, GetGc(0), x-l, y-l, x+l, y+l);
117 gVirtualX->DrawLine(id, GetGc(0), x-l, y+l, x+l, y-l);
118 break;
119 }
120 }
121};
122*/
123// --------------------------------------------------------------------------
124//
125// Constructor. For more details see TExMap
126//
127MGMap::MGMap(Int_t mapSize) : TExMap(mapSize)//, fToolTip(0)
128{
129// fToolTip = new TGToolTip(0, "", 0);
130}
131
132// --------------------------------------------------------------------------
133//
134// Destructor. Deletes all objects of the map if kIsOwner is set via
135// SetOwner.
136//
137MGMap::~MGMap()
138{
139 if (TestBit(kIsOwner))
140 Delete();
141}
142
143// --------------------------------------------------------------------------
144//
145// Add an TObject to be drawn and if necessary a corresponding TString
146// to the Map. You must take care of deleting both objects if SetOwner()
147// was not called. Otherwise MGMap takes the ownership of the objects.
148//
149void MGMap::Add(TObject *k, TString *v)
150{
151 TExMap::Add((ULong_t)GetSize(), (Long_t)k, (Long_t)v);
152}
153
154// --------------------------------------------------------------------------
155//
156// Delete all objects stored in the TExMap
157//
158void MGMap::Delete(Option_t *)
159{
160#if ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)
161 Long_t key, val;
162#else
163 Long64_t key, val;
164#endif
165
166 TExMapIter map(this);
167 while (map.Next(key, val))
168 {
169 delete (TObject*)(key);
170 if (val)
171 delete (TString*)(val);
172 /*
173 Long_t key2, val2;
174 TExMapIter map2(&fMapG);
175 while (map2.Next(key2, val2))
176 if (val==val2)
177 {
178 delete (TObject*)key;
179 fMapG.Remove(key);
180 }
181 */
182 }
183 TExMap::Delete();
184}
185
186// --------------------------------------------------------------------------
187//
188// Paint all TObjects (which are supported) to a drawable with Id id.
189// Scale is the distance of the center of your drawable to one edge in
190// user coordinates.
191//
192// FIXME: Currently the width and height is hardcoded to 768x576 -
193// find a way to get it from the drawable.
194//
195/*
196void MGMap::Paint(Drawable_t id, Float_t scale)
197{
198 if (id==0 && gPad)
199 id = gVirtualX->GetWindowID(gPad->GetPixmapID());
200
201 const Int_t w = 768;
202 const Int_t h = 576;
203
204 scale /= TMath::Hypot((float)w, (float)h)/2;
205
206 Long_t key, val;
207 TExMapIter map(this);
208 while (map.Next(key, val))
209 {
210 TObject *o = (TObject*)key;
211 ((MGX11*)gVirtualX)->DrawLine(id, o, w/2, h/2, scale);
212 ((MGX11*)gVirtualX)->DrawMarker(id, o, w/2, h/2, scale);
213 }
214}
215*/
216
217// --------------------------------------------------------------------------
218//
219// Convert root colors to arbitrary bitmap coordinates
220//
221UChar_t MGMap::Color(int col)
222{
223 switch (col)
224 {
225 case kBlack: return 0;
226 case kWhite: return 0xff;
227 case kYellow: return 0x0f;
228 case kRed: return 2;
229 case kGreen: return 2<<2;
230 case kBlue: return 2<<4;
231 default:
232 return 0;
233 }
234}
235
236// --------------------------------------------------------------------------
237//
238// Draw a line into the buffer (size w*h) from (x1, y1) to (x2, y2) with
239// the color col and the line style style (default: solid)
240//
241void MGMap::DrawLine(UChar_t *buf, int w, int h, Float_t x1, Float_t y1, Float_t x2, Float_t y2, UChar_t col, Int_t style)
242{
243 const Int_t step = style==kSolid?1:3;
244 const Double_t len = TMath::Hypot(x2-x1, y2-y1);
245 const Double_t dx = (x2-x1)/len*step;
246 const Double_t dy = (y2-y1)/len*step;
247
248 Double_t x = x1;
249 Double_t y = y1;
250
251 for (int i=0; i<len; i+=step)
252 {
253 x+= dx;
254 y+= dy;
255
256 const Int_t iy = TMath::Nint(y);
257 if (iy<0 || iy>=h)
258 continue;
259
260 const Int_t ix = TMath::Nint(x);
261 if (ix<0 || ix>=w)
262 continue;
263
264 buf[ix+iy*w] = col;
265 }
266}
267
268// --------------------------------------------------------------------------
269//
270// Draw a box into the buffer (size w*h) from (x1, y1) to (x2, y2) with
271// the color col and the line style style (default: solid)
272//
273void MGMap::DrawBox(UChar_t *buf, int w, int h, Float_t x1, Float_t y1, Float_t x2, Float_t y2, UChar_t col, Int_t style)
274{
275 DrawLine(buf, w, h, x1, y1, x2, y1, col, style);
276 DrawLine(buf, w, h, x1, y2, x2, y1, col, style);
277 DrawLine(buf, w, h, x1, y1, x1, y2, col, style);
278 DrawLine(buf, w, h, x2, y1, x2, y2, col, style);
279}
280
281// --------------------------------------------------------------------------
282//
283// Draw a hexagon into the buffer (size w*h) around (x, y) with radius r and
284// the color col.
285//
286void MGMap::DrawHexagon(UChar_t *buf, int w, int h, Float_t px, Float_t py, Float_t d, UChar_t col, Int_t style)
287{
288 const Int_t np = 6;
289
290 const Double_t dy[np+1] = { .5 , 0. , -.5 , -.5 , 0. , .5 , .5 };
291 const Double_t dx[np+1] = { .2886, .5772, .2886, -.2886, -.5772, -.2886, .2886 };
292
293 //
294 // calculate the positions of the pixel corners
295 //
296 Double_t x[np+1], y[np+1];
297 for (Int_t i=0; i<np+1; i++)
298 {
299 x[i] = px + dx[i]*d;
300 y[i] = py + dy[i]*d;
301 }
302
303 for (int i=0; i<6; i++)
304 DrawLine(buf, w, h, x[i], y[i], x[i+1], y[i+1], col, style);
305}
306
307// --------------------------------------------------------------------------
308//
309// Draw a circle into the buffer (size w*h) around (x, y) with radius r and
310// the color col.
311//
312void MGMap::DrawCircle(UChar_t *buf, int w, int h, Float_t x, Float_t y, Float_t r, UChar_t col)
313{
314 const Int_t n = TMath::Nint(sqrt(2.)*r*TMath::Pi()/2);
315 for (int i=0; i<n-1; i++)
316 {
317 const Double_t angle = TMath::TwoPi()*i/n;
318
319 const Double_t dx = r*cos(angle);
320 const Double_t dy = r*sin(angle);
321
322 const Int_t x1 = TMath::Nint(x+dx);
323 const Int_t x2 = TMath::Nint(x-dx);
324
325 const Int_t y1 = TMath::Nint(y+dy);
326 if (y1>=0 && y1<h)
327 {
328 if (x1>=0 && x1<w)
329 buf[x1+y1*w] = col;
330
331 if (x2>=0 && x2<w)
332 buf[x2+y1*w] = col;
333 }
334
335 const Int_t y2 = TMath::Nint(y-dy);
336 if (y2>=0 && y2<h)
337 {
338 if (x1>=0 && x1<w)
339 buf[x1+y2*w] = col;
340
341 if (x2>=0 && x2<w)
342 buf[x2+y2*w] = col;
343 }
344 }
345}
346
347// --------------------------------------------------------------------------
348//
349// Draw a dot into the buffer (size w*h) at (x, y) with color col.
350//
351void MGMap::DrawDot(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, UChar_t col)
352{
353 const Int_t x1 = TMath::Nint(cx);
354 const Int_t y1 = TMath::Nint(cy);
355
356 if (x1>=0 && y1>=0 && x1<w && y1<h)
357 buf[x1+y1*w] = col;
358}
359
360// --------------------------------------------------------------------------
361//
362// Draw a line into the buffer. The TObject must be a TLine.
363// Currently only solid and non sloid line are supported.
364//
365void MGMap::DrawLine(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
366{
367 TLine *l = dynamic_cast<TLine*>(o);
368 if (!l)
369 return;
370
371 const Double_t x1 = 0.5*w-(l->GetX1()/scale);
372 const Double_t x2 = 0.5*w-(l->GetX2()/scale);
373 const Double_t y1 = 0.5*h-(l->GetY1()/scale);
374 const Double_t y2 = 0.5*h-(l->GetY2()/scale);
375
376 const Int_t col = Color(l->GetLineColor());
377 DrawLine(buf, w, h, x1, y1, x2, y2, col, l->GetLineStyle());
378}
379
380void MGMap::DrawMultiply(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
381{
382 DrawLine(buf, w, h, cx-size, cy-size, cx+size, cy+size, col);
383 DrawLine(buf, w, h, cx+size, cy-size, cx-size, cy+size, col);
384}
385
386void MGMap::DrawCross(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
387{
388 DrawLine(buf, w, h, cx-size, cy, cx+size, cy, col);
389 DrawLine(buf, w, h, cx, cy-size, cx, cy+size, col);
390}
391
392// --------------------------------------------------------------------------
393//
394// Draw marker into the buffer. The TObject must be a TMarker.
395// Currently kCircle, kMultiply and KDot are supported.
396//
397void MGMap::DrawMarker(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
398{
399 TMarker *m = dynamic_cast<TMarker*>(o);
400 if (!m)
401 return;
402
403 Double_t x = 0.5*w-(m->GetX()/scale);
404 Double_t y = 0.5*h-(m->GetY()/scale);
405
406 Int_t col = Color(m->GetMarkerColor());
407
408 switch (m->GetMarkerStyle())
409 {
410 case kCircle:
411 DrawCircle(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
412 break;
413 case kDot:
414 DrawDot(buf, w, h, x, y, col);
415 break;
416 case kMultiply:
417 DrawMultiply(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
418 break;
419 case kCross:
420 DrawCross(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
421 break;
422 }
423}
424
425// --------------------------------------------------------------------------
426//
427// Paint all elements to the pad by calling their Paint() function
428//
429void MGMap::Paint(Option_t *)
430{
431#if ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)
432 Long_t key, val;
433#else
434 Long64_t key, val;
435#endif
436
437 TExMapIter map(this);
438 while (map.Next(key, val))
439 ((TObject*)key)->Paint();
440}
441
442// --------------------------------------------------------------------------
443//
444// Paint all objects into a buffer of w*h UChar_ts. The scale
445// gives you the conversio factor to convert pad coordinates into
446// buffer pixels - it is the distance from the center of the buffer
447// to one of its edges.
448//
449void MGMap::Paint(UChar_t *buf, int w, int h, Float_t scale)
450{
451 scale /= TMath::Hypot((float)w, (float)h)/2;
452
453#if ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)
454 Long_t key, val;
455#else
456 Long64_t key, val;
457#endif
458
459 TExMapIter map(this);
460 while (map.Next(key, val))
461 {
462 TObject *o = (TObject*)key;
463 DrawLine(o, buf, w, h, scale);
464 DrawMarker(o, buf, w, h, scale);
465 }
466}
467
468// --------------------------------------------------------------------------
469//
470// Search for an object at px, py. Return the pointer to it
471// if found. Set str accordingly if a corresponding TString is found.
472//
473TObject *MGMap::PickObject(Int_t px, Int_t py, TString &str) const
474{
475#if ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)
476 Long_t key, val;
477#else
478 Long64_t key, val;
479#endif
480
481 TExMapIter map(this);
482 while (map.Next(key, val))
483 {
484 if (!val)
485 continue;
486
487 TObject *o=(TObject*)key;
488 if (o->DistancetoPrimitive(px, py)>TPad::GetMaxPickDistance())
489 continue;
490
491 str = *(TString*)val;
492 return o;
493 }
494 return NULL;
495}
496
497// ------------------------------------------------------------------------
498//
499// Returns string containing info about the object at position (px,py).
500// Returned string will be re-used (lock in MT environment).
501// The text will be truncated to 128 charcters
502//
503char *MGMap::GetObjectInfo(Int_t px, Int_t py) const
504{
505 TString str;
506 PickObject(px, py, str);
507
508 static char txt[129];
509 txt[128]=0;
510
511 return strncpy(txt, str.Data(), 128);
512}
513
514// --------------------------------------------------------------------------
515//
516// Calculate distance to primitive by checking all gui elements
517//
518Int_t MGMap::DistancetoPrimitive(Int_t px, Int_t py)
519{
520 Int_t min = INT_MAX;
521
522#if ROOT_VERSION_CODE < ROOT_VERSION(5,26,00)
523 Long_t key, val;
524#else
525 Long64_t key, val;
526#endif
527
528 TExMapIter map(this);
529 while (map.Next(key, val))
530 {
531 TObject *o=(TObject*)key;
532
533 const Int_t d = o->DistancetoPrimitive(px, py);
534
535 if (d<TPad::GetMaxPickDistance())
536 return 0;
537
538 if (d<min)
539 min=d;
540 }
541
542 return min;
543}
544
545// --------------------------------------------------------------------------
546//
547// Displays a tooltip
548//
549/*
550void MGMap::ShowToolTip(Int_t px, Int_t py, const char *txt)
551{
552 if (TestBit(kNoToolTips))
553 return;
554
555 Int_t x=0;
556 Int_t y=0;
557
558 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
559 const Window_t id2 = fToolTip->GetParent()->GetId();
560
561 Window_t id3;
562 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
563
564 // Show tool tip
565 fToolTip->SetText(txt);
566 fToolTip->Show(x+4, y+4);
567}
568*/
569
570// --------------------------------------------------------------------------
571//
572// This function was connected to all created canvases. It is used
573// to redirect GetObjectInfo into our own status bar.
574//
575// The 'connection' is done in Draw. It seems that 'connected'
576// functions must be public.
577//
578/*
579void MGMap::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
580{
581 TVirtualPad *c = (TVirtualPad*)gTQSender; // gTQSender==TCanvas
582
583 gPad = c ? c->GetSelectedPad() : NULL;
584 if (!gPad)
585 return;
586
587 // Try to find a corresponding object with kCannotPick set and
588 // an available TString (for a tool tip)
589 TString str;
590 if (!selected || selected==this)
591 selected = PickObject(px, py, str);
592
593 if (!selected)
594 return;
595
596 // Handle some gui events
597 switch (event)
598 {
599 case kMouseMotion:
600 if (!fToolTip->IsMapped() && !str.IsNull())
601 ShowToolTip(px, py, str);
602 break;
603
604 case kMouseLeave:
605 if (fToolTip->IsMapped())
606 fToolTip->Hide();
607 break;
608
609 default:
610 ExecuteEvent(event, px, py);
611 break;
612 }
613}
614*/
615
616/*
617void MAstroCatalog::RecursiveRemove(TObject *obj)
618{
619 ULong_t hash;
620 Long_t key, val;
621
622 TExMapIter map(&fMapG);
623 while (map.Next(hash, key, val))
624 {
625 if (key != (Long_t)obj)
626 continue;
627
628 fMapG.Remove(hash, key);
629 delete (TObject*)(key);
630 if (val)
631 delete (TString*)(val);
632 break;
633 }
634}
635*/
Note: See TracBrowser for help on using the repository browser.