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

Last change on this file since 7184 was 4748, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 15.6 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 *opt)
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 circle into the buffer (size w*h) around (x, y) with radius r and
277// the color col.
278//
279void MGMap::DrawCircle(UChar_t *buf, int w, int h, Float_t x, Float_t y, Float_t r, UChar_t col)
280{
281 const Int_t n = TMath::Nint(sqrt(2.)*r*TMath::Pi()/2);
282 for (int i=0; i<n-1; i++)
283 {
284 const Double_t angle = TMath::TwoPi()*i/n;
285
286 const Double_t dx = r*cos(angle);
287 const Double_t dy = r*sin(angle);
288
289 const Int_t x1 = TMath::Nint(x+dx);
290 const Int_t x2 = TMath::Nint(x-dx);
291
292 const Int_t y1 = TMath::Nint(y+dy);
293 if (y1>=0 && y1<h)
294 {
295 if (x1>=0 && x1<w)
296 buf[x1+y1*w] = col;
297
298 if (x2>=0 && x2<w)
299 buf[x2+y1*w] = col;
300 }
301
302 const Int_t y2 = TMath::Nint(y-dy);
303 if (y2>=0 && y2<h)
304 {
305 if (x1>=0 && x1<w)
306 buf[x1+y2*w] = col;
307
308 if (x2>=0 && x2<w)
309 buf[x2+y2*w] = col;
310 }
311 }
312}
313
314// --------------------------------------------------------------------------
315//
316// Draw a dot into the buffer (size w*h) at (x, y) with color col.
317//
318void MGMap::DrawDot(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, UChar_t col)
319{
320 const Int_t x1 = TMath::Nint(cx);
321 const Int_t y1 = TMath::Nint(cy);
322
323 if (x1>=0 && y1>=0 && x1<w && y1<h)
324 buf[x1+y1*w] = col;
325}
326
327// --------------------------------------------------------------------------
328//
329// Draw a line into the buffer. The TObject must be a TLine.
330// Currently only solid and non sloid line are supported.
331//
332void MGMap::DrawLine(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
333{
334 TLine *l = dynamic_cast<TLine*>(o);
335 if (!l)
336 return;
337
338 const Double_t x1 = 0.5*w-(l->GetX1()/scale);
339 const Double_t x2 = 0.5*w-(l->GetX2()/scale);
340 const Double_t y1 = 0.5*h-(l->GetY1()/scale);
341 const Double_t y2 = 0.5*h-(l->GetY2()/scale);
342
343 const Int_t col = Color(l->GetLineColor());
344 DrawLine(buf, w, h, x1, y1, x2, y2, col, l->GetLineStyle());
345}
346
347void MGMap::DrawMultiply(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
348{
349 DrawLine(buf, w, h, cx-size, cy-size, cx+size, cy+size, col);
350 DrawLine(buf, w, h, cx+size, cy-size, cx-size, cy+size, col);
351}
352
353void MGMap::DrawCross(UChar_t *buf, int w, int h, Float_t cx, Float_t cy, Float_t size, UChar_t col)
354{
355 DrawLine(buf, w, h, cx-size, cy, cx+size, cy, col);
356 DrawLine(buf, w, h, cx, cy-size, cx, cy+size, col);
357}
358
359// --------------------------------------------------------------------------
360//
361// Draw marker into the buffer. The TObject must be a TMarker.
362// Currently kCircle, kMultiply and KDot are supported.
363//
364void MGMap::DrawMarker(TObject *o, UChar_t *buf, int w, int h, Double_t scale)
365{
366 TMarker *m = dynamic_cast<TMarker*>(o);
367 if (!m)
368 return;
369
370 Double_t x = 0.5*w-(m->GetX()/scale);
371 Double_t y = 0.5*h-(m->GetY()/scale);
372
373 Int_t col = Color(m->GetMarkerColor());
374
375 switch (m->GetMarkerStyle())
376 {
377 case kCircle:
378 DrawCircle(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
379 break;
380 case kDot:
381 DrawDot(buf, w, h, x, y, col);
382 break;
383 case kMultiply:
384 DrawMultiply(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
385 break;
386 case kCross:
387 DrawCross(buf, w, h, x, y, m->GetMarkerSize()*2+1, col);
388 break;
389 }
390}
391
392// --------------------------------------------------------------------------
393//
394// Paint all elements to the pad by calling their Paint() function
395//
396void MGMap::Paint(Option_t *o)
397{
398 Long_t key, val;
399 TExMapIter map(this);
400 while (map.Next(key, val))
401 ((TObject*)key)->Paint();
402}
403
404// --------------------------------------------------------------------------
405//
406// Paint all objects into a buffer of w*h UChar_ts. The scale
407// gives you the conversio factor to convert pad coordinates into
408// buffer pixels - it is the distance from the center of the buffer
409// to one of its edges.
410//
411void MGMap::Paint(UChar_t *buf, int w, int h, Float_t scale)
412{
413 scale /= TMath::Hypot((float)w, (float)h)/2;
414
415 Long_t key, val;
416 TExMapIter map(this);
417 while (map.Next(key, val))
418 {
419 TObject *o = (TObject*)key;
420 DrawLine(o, buf, w, h, scale);
421 DrawMarker(o, buf, w, h, scale);
422 }
423}
424
425// --------------------------------------------------------------------------
426//
427// Search for an object at px, py. Return the pointer to it
428// if found. Set str accordingly if a corresponding TString is found.
429//
430TObject *MGMap::PickObject(Int_t px, Int_t py, TString &str) const
431{
432 Long_t key, val;
433 TExMapIter map(this);
434 while (map.Next(key, val))
435 {
436 if (!val)
437 continue;
438
439 TObject *o=(TObject*)key;
440 if (o->DistancetoPrimitive(px, py)>TPad::GetMaxPickDistance())
441 continue;
442
443 str = *(TString*)val;
444 return o;
445 }
446 return NULL;
447}
448
449// ------------------------------------------------------------------------
450//
451// Returns string containing info about the object at position (px,py).
452// Returned string will be re-used (lock in MT environment).
453// The text will be truncated to 128 charcters
454//
455char *MGMap::GetObjectInfo(Int_t px, Int_t py) const
456{
457 TString str;
458 PickObject(px, py, str);
459
460 static char txt[129];
461 txt[128]=0;
462
463 return strncpy(txt, str.Data(), 128);
464}
465
466// --------------------------------------------------------------------------
467//
468// Calculate distance to primitive by checking all gui elements
469//
470Int_t MGMap::DistancetoPrimitive(Int_t px, Int_t py)
471{
472 Int_t min = INT_MAX;
473
474 Long_t key, val;
475 TExMapIter map(this);
476 while (map.Next(key, val))
477 {
478 TObject *o=(TObject*)key;
479
480 const Int_t d = o->DistancetoPrimitive(px, py);
481
482 if (d<TPad::GetMaxPickDistance())
483 return 0;
484
485 if (d<min)
486 min=d;
487 }
488
489 return min;
490}
491
492// --------------------------------------------------------------------------
493//
494// Displays a tooltip
495//
496/*
497void MGMap::ShowToolTip(Int_t px, Int_t py, const char *txt)
498{
499 if (TestBit(kNoToolTips))
500 return;
501
502 Int_t x=0;
503 Int_t y=0;
504
505 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
506 const Window_t id2 = fToolTip->GetParent()->GetId();
507
508 Window_t id3;
509 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
510
511 // Show tool tip
512 fToolTip->SetText(txt);
513 fToolTip->Show(x+4, y+4);
514}
515*/
516
517// --------------------------------------------------------------------------
518//
519// This function was connected to all created canvases. It is used
520// to redirect GetObjectInfo into our own status bar.
521//
522// The 'connection' is done in Draw. It seems that 'connected'
523// functions must be public.
524//
525/*
526void MGMap::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
527{
528 TVirtualPad *c = (TVirtualPad*)gTQSender; // gTQSender==TCanvas
529
530 gPad = c ? c->GetSelectedPad() : NULL;
531 if (!gPad)
532 return;
533
534 // Try to find a corresponding object with kCannotPick set and
535 // an available TString (for a tool tip)
536 TString str;
537 if (!selected || selected==this)
538 selected = PickObject(px, py, str);
539
540 if (!selected)
541 return;
542
543 // Handle some gui events
544 switch (event)
545 {
546 case kMouseMotion:
547 if (!fToolTip->IsMapped() && !str.IsNull())
548 ShowToolTip(px, py, str);
549 break;
550
551 case kMouseLeave:
552 if (fToolTip->IsMapped())
553 fToolTip->Hide();
554 break;
555
556 default:
557 ExecuteEvent(event, px, py);
558 break;
559 }
560}
561*/
562
563/*
564void MAstroCatalog::RecursiveRemove(TObject *obj)
565{
566 ULong_t hash;
567 Long_t key, val;
568
569 TExMapIter map(&fMapG);
570 while (map.Next(hash, key, val))
571 {
572 if (key != (Long_t)obj)
573 continue;
574
575 fMapG.Remove(hash, key);
576 delete (TObject*)(key);
577 if (val)
578 delete (TString*)(val);
579 break;
580 }
581}
582*/
Note: See TracBrowser for help on using the repository browser.