source: trunk/MagicSoft/Mars/mbase/MGMap.cc@ 9314

Last change on this file since 9314 was 9195, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 16.4 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 Long_t key, val;
161 TExMapIter map(this);
162 while (map.Next(key, val))
163 {
164 delete (TObject*)(key);
165 if (val)
166 delete (TString*)(val);
167 /*
168 Long_t key2, val2;
169 TExMapIter map2(&fMapG);
170 while (map2.Next(key2, val2))
171 if (val==val2)
172 {
173 delete (TObject*)key;
174 fMapG.Remove(key);
175 }
176 */
177 }
178 TExMap::Delete();
179}
180
181// --------------------------------------------------------------------------
182//
183// Paint all TObjects (which are supported) to a drawable with Id id.
184// Scale is the distance of the center of your drawable to one edge in
185// user coordinates.
186//
187// FIXME: Currently the width and height is hardcoded to 768x576 -
188// find a way to get it from the drawable.
189//
190/*
191void MGMap::Paint(Drawable_t id, Float_t scale)
192{
193 if (id==0 && gPad)
194 id = gVirtualX->GetWindowID(gPad->GetPixmapID());
195
196 const Int_t w = 768;
197 const Int_t h = 576;
198
199 scale /= TMath::Hypot((float)w, (float)h)/2;
200
201 Long_t key, val;
202 TExMapIter map(this);
203 while (map.Next(key, val))
204 {
205 TObject *o = (TObject*)key;
206 ((MGX11*)gVirtualX)->DrawLine(id, o, w/2, h/2, scale);
207 ((MGX11*)gVirtualX)->DrawMarker(id, o, w/2, h/2, scale);
208 }
209}
210*/
211
212// --------------------------------------------------------------------------
213//
214// Convert root colors to arbitrary bitmap coordinates
215//
216UChar_t MGMap::Color(int col)
217{
218 switch (col)
219 {
220 case kBlack: return 0;
221 case kWhite: return 0xff;
222 case kYellow: return 0x0f;
223 case kRed: return 2;
224 case kGreen: return 2<<2;
225 case kBlue: return 2<<4;
226 default:
227 return 0;
228 }
229}
230
231// --------------------------------------------------------------------------
232//
233// Draw a line into the buffer (size w*h) from (x1, y1) to (x2, y2) with
234// the color col and the line style style (default: solid)
235//
236void 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)
237{
238 const Int_t step = style==kSolid?1:3;
239 const Double_t len = TMath::Hypot(x2-x1, y2-y1);
240 const Double_t dx = (x2-x1)/len*step;
241 const Double_t dy = (y2-y1)/len*step;
242
243 Double_t x = x1;
244 Double_t y = y1;
245
246 for (int i=0; i<len; i+=step)
247 {
248 x+= dx;
249 y+= dy;
250
251 const Int_t iy = TMath::Nint(y);
252 if (iy<0 || iy>=h)
253 continue;
254
255 const Int_t ix = TMath::Nint(x);
256 if (ix<0 || ix>=w)
257 continue;
258
259 buf[ix+iy*w] = col;
260 }
261}
262
263// --------------------------------------------------------------------------
264//
265// Draw a box into the buffer (size w*h) from (x1, y1) to (x2, y2) with
266// the color col and the line style style (default: solid)
267//
268void 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)
269{
270 DrawLine(buf, w, h, x1, y1, x2, y1, col, style);
271 DrawLine(buf, w, h, x1, y2, x2, y1, col, style);
272 DrawLine(buf, w, h, x1, y1, x1, y2, col, style);
273 DrawLine(buf, w, h, x2, y1, x2, y2, col, style);
274}
275
276// --------------------------------------------------------------------------
277//
278// Draw a hexagon into the buffer (size w*h) around (x, y) with radius r and
279// the color col.
280//
281void MGMap::DrawHexagon(UChar_t *buf, int w, int h, Float_t px, Float_t py, Float_t d, UChar_t col, Int_t style)
282{
283 const Int_t np = 6;
284
285 const Double_t dy[np+1] = { .5 , 0. , -.5 , -.5 , 0. , .5 , .5 };
286 const Double_t dx[np+1] = { .2886, .5772, .2886, -.2886, -.5772, -.2886, .2886 };
287
288 //
289 // calculate the positions of the pixel corners
290 //
291 Double_t x[np+1], y[np+1];
292 for (Int_t i=0; i<np+1; i++)
293 {
294 x[i] = px + dx[i]*d;
295 y[i] = py + dy[i]*d;
296 }
297
298 for (int i=0; i<6; i++)
299 DrawLine(buf, w, h, x[i], y[i], x[i+1], y[i+1], col, style);
300}
301
302// --------------------------------------------------------------------------
303//
304// Draw a circle into the buffer (size w*h) around (x, y) with radius r and
305// the color col.
306//
307void MGMap::DrawCircle(UChar_t *buf, int w, int h, Float_t x, Float_t y, Float_t r, UChar_t col)
308{
309 const Int_t n = TMath::Nint(sqrt(2.)*r*TMath::Pi()/2);
310 for (int i=0; i<n-1; i++)
311 {
312 const Double_t angle = TMath::TwoPi()*i/n;
313
314 const Double_t dx = r*cos(angle);
315 const Double_t dy = r*sin(angle);
316
317 const Int_t x1 = TMath::Nint(x+dx);
318 const Int_t x2 = TMath::Nint(x-dx);
319
320 const Int_t y1 = TMath::Nint(y+dy);
321 if (y1>=0 && y1<h)
322 {
323 if (x1>=0 && x1<w)
324 buf[x1+y1*w] = col;
325
326 if (x2>=0 && x2<w)
327 buf[x2+y1*w] = col;
328 }
329
330 const Int_t y2 = TMath::Nint(y-dy);
331 if (y2>=0 && y2<h)
332 {
333 if (x1>=0 && x1<w)
334 buf[x1+y2*w] = col;
335
336 if (x2>=0 && x2<w)
337 buf[x2+y2*w] = col;
338 }
339 }
340}
341
342// --------------------------------------------------------------------------
343//
344// Draw a dot into the buffer (size w*h) at (x, y) with color col.
345//
346void MGMap::DrawDot(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, UChar_t col)
347{
348 const Int_t x1 = TMath::Nint(cx);
349 const Int_t y1 = TMath::Nint(cy);
350
351 if (x1>=0 && y1>=0 && x1<w && y1<h)
352 buf[x1+y1*w] = col;
353}
354
355// --------------------------------------------------------------------------
356//
357// Draw a line into the buffer. The TObject must be a TLine.
358// Currently only solid and non sloid line are supported.
359//
360void MGMap::DrawLine(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
361{
362 TLine *l = dynamic_cast<TLine*>(o);
363 if (!l)
364 return;
365
366 const Double_t x1 = 0.5*w-(l->GetX1()/scale);
367 const Double_t x2 = 0.5*w-(l->GetX2()/scale);
368 const Double_t y1 = 0.5*h-(l->GetY1()/scale);
369 const Double_t y2 = 0.5*h-(l->GetY2()/scale);
370
371 const Int_t col = Color(l->GetLineColor());
372 DrawLine(buf, w, h, x1, y1, x2, y2, col, l->GetLineStyle());
373}
374
375void MGMap::DrawMultiply(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
376{
377 DrawLine(buf, w, h, cx-size, cy-size, cx+size, cy+size, col);
378 DrawLine(buf, w, h, cx+size, cy-size, cx-size, cy+size, col);
379}
380
381void MGMap::DrawCross(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
382{
383 DrawLine(buf, w, h, cx-size, cy, cx+size, cy, col);
384 DrawLine(buf, w, h, cx, cy-size, cx, cy+size, col);
385}
386
387// --------------------------------------------------------------------------
388//
389// Draw marker into the buffer. The TObject must be a TMarker.
390// Currently kCircle, kMultiply and KDot are supported.
391//
392void MGMap::DrawMarker(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
393{
394 TMarker *m = dynamic_cast<TMarker*>(o);
395 if (!m)
396 return;
397
398 Double_t x = 0.5*w-(m->GetX()/scale);
399 Double_t y = 0.5*h-(m->GetY()/scale);
400
401 Int_t col = Color(m->GetMarkerColor());
402
403 switch (m->GetMarkerStyle())
404 {
405 case kCircle:
406 DrawCircle(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
407 break;
408 case kDot:
409 DrawDot(buf, w, h, x, y, col);
410 break;
411 case kMultiply:
412 DrawMultiply(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
413 break;
414 case kCross:
415 DrawCross(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
416 break;
417 }
418}
419
420// --------------------------------------------------------------------------
421//
422// Paint all elements to the pad by calling their Paint() function
423//
424void MGMap::Paint(Option_t *)
425{
426 Long_t key, val;
427 TExMapIter map(this);
428 while (map.Next(key, val))
429 ((TObject*)key)->Paint();
430}
431
432// --------------------------------------------------------------------------
433//
434// Paint all objects into a buffer of w*h UChar_ts. The scale
435// gives you the conversio factor to convert pad coordinates into
436// buffer pixels - it is the distance from the center of the buffer
437// to one of its edges.
438//
439void MGMap::Paint(UChar_t *buf, int w, int h, Float_t scale)
440{
441 scale /= TMath::Hypot((float)w, (float)h)/2;
442
443 Long_t key, val;
444 TExMapIter map(this);
445 while (map.Next(key, val))
446 {
447 TObject *o = (TObject*)key;
448 DrawLine(o, buf, w, h, scale);
449 DrawMarker(o, buf, w, h, scale);
450 }
451}
452
453// --------------------------------------------------------------------------
454//
455// Search for an object at px, py. Return the pointer to it
456// if found. Set str accordingly if a corresponding TString is found.
457//
458TObject *MGMap::PickObject(Int_t px, Int_t py, TString &str) const
459{
460 Long_t key, val;
461 TExMapIter map(this);
462 while (map.Next(key, val))
463 {
464 if (!val)
465 continue;
466
467 TObject *o=(TObject*)key;
468 if (o->DistancetoPrimitive(px, py)>TPad::GetMaxPickDistance())
469 continue;
470
471 str = *(TString*)val;
472 return o;
473 }
474 return NULL;
475}
476
477// ------------------------------------------------------------------------
478//
479// Returns string containing info about the object at position (px,py).
480// Returned string will be re-used (lock in MT environment).
481// The text will be truncated to 128 charcters
482//
483char *MGMap::GetObjectInfo(Int_t px, Int_t py) const
484{
485 TString str;
486 PickObject(px, py, str);
487
488 static char txt[129];
489 txt[128]=0;
490
491 return strncpy(txt, str.Data(), 128);
492}
493
494// --------------------------------------------------------------------------
495//
496// Calculate distance to primitive by checking all gui elements
497//
498Int_t MGMap::DistancetoPrimitive(Int_t px, Int_t py)
499{
500 Int_t min = INT_MAX;
501
502 Long_t key, val;
503 TExMapIter map(this);
504 while (map.Next(key, val))
505 {
506 TObject *o=(TObject*)key;
507
508 const Int_t d = o->DistancetoPrimitive(px, py);
509
510 if (d<TPad::GetMaxPickDistance())
511 return 0;
512
513 if (d<min)
514 min=d;
515 }
516
517 return min;
518}
519
520// --------------------------------------------------------------------------
521//
522// Displays a tooltip
523//
524/*
525void MGMap::ShowToolTip(Int_t px, Int_t py, const char *txt)
526{
527 if (TestBit(kNoToolTips))
528 return;
529
530 Int_t x=0;
531 Int_t y=0;
532
533 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
534 const Window_t id2 = fToolTip->GetParent()->GetId();
535
536 Window_t id3;
537 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
538
539 // Show tool tip
540 fToolTip->SetText(txt);
541 fToolTip->Show(x+4, y+4);
542}
543*/
544
545// --------------------------------------------------------------------------
546//
547// This function was connected to all created canvases. It is used
548// to redirect GetObjectInfo into our own status bar.
549//
550// The 'connection' is done in Draw. It seems that 'connected'
551// functions must be public.
552//
553/*
554void MGMap::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
555{
556 TVirtualPad *c = (TVirtualPad*)gTQSender; // gTQSender==TCanvas
557
558 gPad = c ? c->GetSelectedPad() : NULL;
559 if (!gPad)
560 return;
561
562 // Try to find a corresponding object with kCannotPick set and
563 // an available TString (for a tool tip)
564 TString str;
565 if (!selected || selected==this)
566 selected = PickObject(px, py, str);
567
568 if (!selected)
569 return;
570
571 // Handle some gui events
572 switch (event)
573 {
574 case kMouseMotion:
575 if (!fToolTip->IsMapped() && !str.IsNull())
576 ShowToolTip(px, py, str);
577 break;
578
579 case kMouseLeave:
580 if (fToolTip->IsMapped())
581 fToolTip->Hide();
582 break;
583
584 default:
585 ExecuteEvent(event, px, py);
586 break;
587 }
588}
589*/
590
591/*
592void MAstroCatalog::RecursiveRemove(TObject *obj)
593{
594 ULong_t hash;
595 Long_t key, val;
596
597 TExMapIter map(&fMapG);
598 while (map.Next(hash, key, val))
599 {
600 if (key != (Long_t)obj)
601 continue;
602
603 fMapG.Remove(hash, key);
604 delete (TObject*)(key);
605 if (val)
606 delete (TString*)(val);
607 break;
608 }
609}
610*/
Note: See TracBrowser for help on using the repository browser.