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

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