source: trunk/MagicSoft/Mars/mastro/MAstroCatalog.cc@ 8073

Last change on this file since 8073 was 8066, checked in by tbretz, 18 years ago
*** empty log message ***
File size: 42.1 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 expressed
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 03/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2002-2005
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MAstroCatalog
28// =============
29//
30// THIS IMPLEMENTATION IS PRELIMINARY AND WILL BE MERGED WITH
31// SOME PARTS OF THE DRIVE SOFTWARE SOON!
32//
33//
34// Catalogs:
35// ---------
36//
37// To be able to use this class you need a catalog file suppored by
38// MAstroCatalog.
39// Catalog files can be found at
40// http://magic.astro.uni-wuerzburg.de/mars/catalogs.html
41// You must copy the file into the directory from which you start your macro
42// or give an abolute path loading the catalog.
43//
44//
45// Usage:
46// ------
47//
48// To display a starfield you must have a supported catalog, then do:
49//
50// MTime time;
51// // Time for which to get the picture
52// time.Set(2004, 2, 28, 20, 14, 7);
53// // Current observatory
54// MObservatory magic1;
55// // Right Ascension [h] and declination [deg] of source
56// // Currently 'perfect' pointing is assumed
57// const Double_t ra = MAstro::Hms2Rad(5, 34, 31.9);
58// const Double_t dec = MAstro::Dms2Rad(22, 0, 52.0);
59// MAstroCatalog stars;
60// // Magnitude up to which the stars are loaded from the catalog
61// stars.SetLimMag(6);
62// // Radius of FOV around the source position to load the stars
63// stars.SetRadiusFOV(3);
64// // Source position
65// stars.SetRaDec(ra, dec);
66// // Catalog to load (here: Bright Star Catalog V5)
67// stars.ReadBSC("bsc5.dat");
68// // Obersavatory and time to also get local coordinate information
69// stars.SetObservatory(magic1);
70// stars.SetTime(time);
71// // Enable interactive GUI
72// stars.SetGuiActive();
73// //Clone the catalog due to the validity range of the instance
74// TObject *o = stars.Clone();
75// o->SetBit(kCanDelete);
76// o->Draw();
77//
78// If no time and/or Obervatory location is given no local coordinate
79// information is displayed.
80//
81//
82// Coordinate Transformation:
83// -------------------------
84// The conversion from sky coordinates to local coordinates is done using
85// MAstroSky2Local which does a simple rotation of the coordinate system.
86// This is inaccurate in the order of 30arcsec due to ignorance of all
87// astrometrical corrections (nutation, precission, abberation, ...)
88//
89//
90// GUI:
91// ----
92// * If the gui is interactive you can use the cursor keys to change
93// the position you are looking at and with plus/minus you
94// can (un)zoom the FOV (Field Of View)
95// * The displayed values mean the following:
96// + alpha: Right Ascension
97// + delta: Declination
98// + theta: zenith distance / zenith angle
99// + phi: azimuth angle
100// + rho: angle of rotation sky-coordinate system vs local-
101// coordinate system
102// + time of display
103// * Move the mouse on top of the grid points or the stars to get
104// more setailed information.
105// * Enable the event-info in a canvas to see the current
106// ObjectInfo=tooltip-text
107// * call SetNoToolTips to supress the tooltips
108// * the blue lines are the local coordinat system
109// * the red lines are sky coordinate system
110//
111//
112// ToDo:
113// -----
114// - replace MVetcor3 by a more convinient class. Maybe use TExMap, too.
115// - change tooltips to multi-line tools tips as soon as root
116// supports them
117// - a derived class is missing which supports all astrometrical
118// correction (base on slalib and useable in Cosy)
119// - Implement a general loader for heasarc catlogs, see
120// http://heasarc.gsfc.nasa.gov/W3Browse/star-catalog/
121//
122// Class Version 2:
123// + MAttLine fAttLineSky; // Line Style and color for sky coordinates
124// + MAttLine fAttLineLocal; // Line Style and color for local coordinates
125// + added new base class TAttMarker
126//
127//////////////////////////////////////////////////////////////////////////////
128#include "MAstroCatalog.h"
129
130#include <errno.h> // strerror
131#include <stdlib.h> // ati, atof
132#include <limits.h> // INT_MAX (Suse 7.3/gcc 2.95)
133
134#include <KeySymbols.h> // kKey_*
135
136#include <TLine.h> // TLine
137#include <TMarker.h> // TMarker
138#include <TCanvas.h> // TCanvas
139#include <TArrayI.h> // TArrayI
140#include <TGToolTip.h> // TGToolTip
141#include <TPaveText.h> // TPaveText
142
143#include <TGraph.h>
144
145#include "MLog.h"
146#include "MLogManip.h"
147
148#include "MZlib.h" // MZlib <ifstream>
149
150#include "MTime.h"
151#include "MString.h"
152#include "MAstro.h"
153#include "MAstroSky2Local.h"
154#include "MObservatory.h"
155
156#undef DEBUG
157//#define DEBUG
158
159#ifdef DEBUG
160#include <TStopwatch.h>
161#endif
162
163ClassImp(MAttLine);
164ClassImp(MAstroCatalog);
165
166using namespace std;
167
168// --------------------------------------------------------------------------
169//
170// Default Constructor. Set Default values:
171// fLimMag = 99
172// fRadiusFOV = 90
173//
174MAstroCatalog::MAstroCatalog() : fLimMag(99), fRadiusFOV(90), fToolTip(0), fObservatory(0), fTime(0)
175{
176 fList.SetOwner();
177 fMapG.SetOwner();
178
179 fToolTip = gROOT->IsBatch() || !gClient ? 0 : new TGToolTip(0, "", 0);
180
181 fAttLineSky.SetLineStyle(kDashDotted);
182 fAttLineLocal.SetLineStyle(kDashDotted);
183
184 fAttLineSky.SetLineColor(kRed);
185 fAttLineLocal.SetLineColor(kBlue);
186
187 SetMarkerColor(kBlack);
188 SetMarkerStyle(kCircle);
189}
190
191// --------------------------------------------------------------------------
192//
193// Destructor. Delete fTime, fObservatory. Disconnect signal. delete tooltip.
194// Delete Map with gui primitives
195//
196MAstroCatalog::~MAstroCatalog()
197{
198 // First disconnect the EventInfo...
199 // FIXME: There must be an easier way!
200 TIter Next(gROOT->GetListOfCanvases());
201 TCanvas *c;
202 while ((c=(TCanvas*)Next()))
203 c->Disconnect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", this,
204 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
205
206 // Now delete the data members
207 if (fTime)
208 delete fTime;
209 if (fObservatory)
210 delete fObservatory;
211
212 if (fToolTip)
213 {
214 fToolTip->Hide();
215 delete fToolTip;
216 }
217}
218
219// --------------------------------------------------------------------------
220//
221// Snippet to for reading catalog files.
222//
223TString MAstroCatalog::FindToken(TString &line, Char_t tok)
224{
225 Ssiz_t token = line.First(tok);
226 if (token<0)
227 {
228 const TString copy(line);
229 line = "";
230 return copy;
231 }
232
233 const TString res = line(0, token);
234 line.Remove(0, token+1);
235 return res;
236}
237
238// --------------------------------------------------------------------------
239//
240// return int correspoding to TString
241//
242Int_t MAstroCatalog::atoi(const TString &s)
243{
244 return const_cast<TString&>(s).Atoi();
245}
246
247// --------------------------------------------------------------------------
248//
249// return float correspoding to TString
250//
251Float_t MAstroCatalog::atof(const TString &s)
252{
253 return const_cast<TString&>(s).Atof();
254}
255
256// --------------------------------------------------------------------------
257//
258// Read from a xephem catalog, set bit kHasChahanged.
259// Already read data is not deleted. To delete the stored data call
260// Delete().
261//
262Int_t MAstroCatalog::ReadXephem(TString catalog)
263{
264 gLog << inf << "Reading Xephem catalog: " << catalog << endl;
265
266 MZlib fin(catalog);
267 if (!fin)
268 {
269 gLog << err << "Cannot open catalog file " << catalog << ": ";
270 gLog << strerror(errno) << endl;
271 return 0;
272 }
273
274 Int_t add =0;
275 Int_t cnt =0;
276 Int_t line=0;
277
278 Double_t maxmag=0;
279
280 while (1)
281 {
282 TString row;
283 row.ReadLine(fin);
284 if (!fin)
285 break;
286
287 line++;
288
289 if (row[0]=='#')
290 continue;
291
292 TString line(row);
293
294 TString name = FindToken(line);
295 TString dummy = FindToken(line);
296 TString r = FindToken(line);
297 TString d = FindToken(line);
298 TString m = FindToken(line);
299 TString epoch = FindToken(line);
300
301 if (name.IsNull() || r.IsNull() || d.IsNull() || m.IsNull() || epoch.IsNull())
302 {
303 gLog << warn << "Invalid Entry Line #" << line << ": " << row << endl;
304 continue;
305 }
306
307 cnt++;
308
309 const Double_t mag = atof(m);
310
311 maxmag = TMath::Max(maxmag, mag);
312
313 if (mag>fLimMag)
314 continue;
315
316 if (epoch.Atoi()!=2000)
317 {
318 gLog << warn << "Epoch != 2000... skipped." << endl;
319 continue;
320 }
321
322 Double_t ra0, dec0;
323 MAstro::Coordinate2Angle(r, ra0);
324 MAstro::Coordinate2Angle(d, dec0);
325
326 ra0 *= TMath::Pi()/12;
327 dec0 *= TMath::Pi()/180;
328
329 if (AddObject(ra0, dec0, mag, name))
330 add++;
331 }
332 gLog << inf << "Read " << add << " out of " << cnt << " (Total max mag=" << maxmag << ")" << endl;
333
334 return add;
335}
336
337// --------------------------------------------------------------------------
338//
339// Read from a NGC2000 catalog. set bit kHasChanged
340// Already read data is not deleted. To delete the stored data call
341// Delete().
342//
343Int_t MAstroCatalog::ReadNGC2000(TString catalog)
344{
345 gLog << inf << "Reading NGC2000 catalog: " << catalog << endl;
346
347 MZlib fin(catalog);
348 if (!fin)
349 {
350 gLog << err << "Cannot open catalog file " << catalog << ": ";
351 gLog << strerror(errno) << endl;
352 return 0;
353 }
354
355 Int_t add=0;
356 Int_t cnt=0;
357 Int_t n =0;
358
359 Double_t maxmag=0;
360
361 while (1)
362 {
363 TString row;
364 row.ReadLine(fin);
365 if (!fin)
366 break;
367
368 cnt++;
369
370 const Int_t rah = atoi(row(13, 2));
371 const Float_t ram = atof(row(16, 4));
372 const Char_t decs = row(22);
373 const Int_t decd = atoi(row(23, 2));
374 const Int_t decm = atoi(row(26, 2));
375 const TString m = row(43, 4);
376
377 if (m.Strip().IsNull())
378 continue;
379
380 n++;
381
382 const Double_t mag = atof(m);
383
384 maxmag = TMath::Max(maxmag, mag);
385
386 if (mag>fLimMag)
387 continue;
388
389 const Double_t ra = MAstro::Hms2Rad(rah, (int)ram, fmod(ram, 1)*60);
390 const Double_t dec = MAstro::Dms2Rad(decd, decm, 0, decs);
391
392 if (AddObject(ra, dec, mag, row(0,8)))
393 add++;
394 }
395
396 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
397
398 return add;
399}
400
401// --------------------------------------------------------------------------
402//
403// Read from a Bright Star Catalog catalog. set bit kHasChanged
404// Already read data is not deleted. To delete the stored data call
405// Delete().
406//
407Int_t MAstroCatalog::ReadBSC(TString catalog)
408{
409 gLog << inf << "Reading Bright Star Catalog (BSC5) catalog: " << catalog << endl;
410
411 MZlib fin(catalog);
412 if (!fin)
413 {
414 gLog << err << "Cannot open catalog file " << catalog << ": ";
415 gLog << strerror(errno) << endl;
416 return 0;
417 }
418
419 Int_t add=0;
420 Int_t cnt=0;
421 Int_t n =0;
422
423 Double_t maxmag=0;
424
425 while (1)
426 {
427 TString row;
428 row.ReadLine(fin);
429 if (!fin)
430 break;
431
432 cnt++;
433
434 const Int_t rah = atoi(row(75, 2));
435 const Int_t ram = atoi(row(77, 2));
436 const Float_t ras = atof(row(79, 4));
437 const Char_t decsgn = row(83);
438 const Int_t decd = atoi(row(84, 2));
439 const Int_t decm = atoi(row(86, 2));
440 const Int_t decs = atoi(row(88, 2));
441 const TString m = row(102, 5);
442
443 if (m.Strip().IsNull())
444 continue;
445
446 n++;
447
448 const Double_t mag = atof(m.Data());
449
450 maxmag = TMath::Max(maxmag, mag);
451
452 if (mag>fLimMag)
453 continue;
454
455 const Double_t ra = MAstro::Hms2Rad(rah, ram, ras);
456 const Double_t dec = MAstro::Dms2Rad(decd, decm, decs, decsgn);
457
458 if (AddObject(ra, dec, mag, row(4,9)))
459 add++;
460 }
461
462 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
463
464 return add;
465}
466
467// --------------------------------------------------------------------------
468//
469// Read from a ascii heasarc ppm catalog. set bit kHasChanged
470// Already read data is not deleted. To delete the stored data call
471// Delete().
472// If the second argument is given all survived stars are written
473// to a file outname. This files will contain an apropriate compressed
474// file format. You can read such files again using ReadCompressed.
475//
476// FIXME: A General loader for heasarc catlogs is missing, see
477// http://heasarc.gsfc.nasa.gov/W3Browse/star-catalog/
478//
479Int_t MAstroCatalog::ReadHeasarcPPM(TString catalog, TString outname)
480{
481 gLog << inf << "Reading Heasarc PPM catalog: " << catalog << endl;
482
483 MZlib fin(catalog);
484 if (!fin)
485 {
486 gLog << err << "Cannot open catalog file " << catalog << ": ";
487 gLog << strerror(errno) << endl;
488 return 0;
489 }
490
491 ofstream *fout = outname.IsNull() ? 0 : new ofstream(outname);
492 if (fout && !*fout)
493 {
494 gLog << warn << "Cannot open output file " << outname << ": ";
495 gLog << strerror(errno) << endl;
496 delete fout;
497 fout = 0;
498 }
499
500 Int_t add=0;
501 Int_t cnt=0;
502 Int_t n =0;
503
504 Double_t maxmag=0;
505
506 while (1)
507 {
508 TString row;
509 row.ReadLine(fin);
510 if (!fin)
511 break;
512
513 cnt++;
514
515 if (!row.BeginsWith("PPM "))
516 continue;
517
518 const TString name = row(0, row.First('|'));
519 row = row(row.First('|')+1, row.Length());
520 row = row(row.First('|')+1, row.Length());
521
522 const TString vmag = row(0, row.First('|'));
523
524 n++;
525 const Double_t mag = atof(vmag.Data());
526 maxmag = TMath::Max(maxmag, mag);
527 if (mag>fLimMag)
528 continue;
529
530 row = row(row.First('|')+1, row.Length());
531 row = row(row.First('|')+1, row.Length());
532
533 row = row(row.First('|')+1, row.Length());
534 row = row(row.First('|')+1, row.Length());
535
536 row = row(row.First('|')+1, row.Length());
537 row = row(row.First('|')+1, row.Length());
538
539 const TString ra = row(0, row.First('|'));
540 row = row(row.First('|')+1, row.Length());
541 const TString de = row(0, row.First('|'));
542 row = row(row.First('|')+1, row.Length());
543
544 Char_t sgn;
545 Int_t d, m;
546 Float_t s;
547 if (sscanf(ra.Data(), "%d %d %f", &d, &m, &s)!=3)
548 {
549 // gLog << "Error loading entry in line " << i << endl;
550 continue;
551 }
552 const Double_t ra0 = MAstro::Hms2Rad(d, m, s);
553
554 if (sscanf(de.Data(), "%c%d %d %f", &sgn, &d, &m, &s)!=4)
555 {
556 // gLog << "Error loading entry in line " << i << endl;
557 continue;
558 }
559 const Double_t de0 = MAstro::Dms2Rad(d, m, s, sgn);
560
561 if (!AddObject(ra0, de0, mag, name))
562 continue;
563
564 add++;
565
566 if (fout)
567 ((MVector3*)fList.Last())->WriteBinary(*fout);
568 }
569
570 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
571
572 return add;
573}
574
575// --------------------------------------------------------------------------
576//
577// Read from a MAstroCatalog compressed catalog. set bit kHasChanged
578// Already read data is not deleted. To delete the stored data call
579// Delete().
580//
581Int_t MAstroCatalog::ReadCompressed(TString catalog)
582{
583 SetBit(kHasChanged);
584
585 gLog << inf << "Reading MAstroCatalog compressed catalog: " << catalog << endl;
586
587 MZlib fin(catalog);
588 if (!fin)
589 {
590 gLog << err << "Cannot open catalog file " << catalog << ": ";
591 gLog << strerror(errno) << endl;
592 return 0;
593 }
594
595 Int_t add=0;
596 Int_t cnt=0;
597 Int_t n =0;
598
599 Double_t maxmag=0;
600
601 MVector3 entry;
602
603 while (1)
604 {
605 cnt++;
606
607 entry.ReadBinary(fin);
608 if (!fin)
609 break;
610
611 n++;
612
613 const Double_t mag = entry.Magnitude();
614 maxmag = TMath::Max(maxmag, mag);
615 if (mag>fLimMag)
616 continue;
617
618 if (entry.Angle(fRaDec)*TMath::RadToDeg()>fRadiusFOV)
619 continue;
620
621 fList.Add(entry.Clone());
622 add++;
623 }
624
625 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
626
627 return add;
628}
629
630// --------------------------------------------------------------------------
631//
632// Add an object to the star catalog manually. Return true if the object
633// was added and false otherwise (criteria is the FOV)
634//
635Bool_t MAstroCatalog::AddObject(Float_t ra, Float_t dec, Float_t mag, TString name)
636{
637 MVector3 *star = new MVector3;
638 star->SetRaDec(ra, dec, mag);
639 star->SetName(name);
640
641 if (star->Angle(fRaDec)*TMath::RadToDeg()>fRadiusFOV)
642 {
643 delete star;
644 return 0;
645 }
646
647 SetBit(kHasChanged);
648 fList.AddLast(star);
649 return 1;
650}
651
652// --------------------------------------------------------------------------
653//
654// Get the visibility curve (altitude vs time) for the current time
655// and observatory for the catalog entry with name name.
656// If name==0 the name of the TGraph is taken instead.
657// The day is divided into as many points as the graph has
658// points. If the graph has no points the default is 96.
659//
660void MAstroCatalog::GetVisibilityCurve(TGraph &g, const char *name) const
661{
662 if (!fTime || !fObservatory)
663 {
664 g.Set(0);
665 return;
666 }
667
668 MVector3 *star = static_cast<MVector3*>(FindObject(name ? name : g.GetName()));
669 if (!star)
670 return;
671
672 const Double_t mjd = TMath::Floor(fTime->GetMjd());
673 const Double_t lng = fObservatory->GetLongitudeDeg()/360;
674
675 if (g.GetN()==0)
676 g.Set(96);
677
678 for (int i=0; i<g.GetN(); i++)
679 {
680 const Double_t offset = (Double_t)i/g.GetN() - 0.5;
681
682 const MTime tm(mjd-lng+offset);
683
684 MVector3 v(*star);
685 v *= MAstroSky2Local(tm.GetGmst(), *fObservatory);
686
687 g.SetPoint(i, tm.GetAxisTime(), 90-v.Theta()*TMath::RadToDeg());
688 }
689
690 TH1 &h = *g.GetHistogram();
691 TAxis &x = *h.GetXaxis();
692 TAxis &y = *h.GetYaxis();
693
694 y.SetTitle("Altitude [\\circ]");
695 y.CenterTitle();
696
697 x.SetTitle("UTC");
698 x.CenterTitle();
699 x.SetTimeFormat("%H:%M %F1995-01-01 00:00:00 GMT");
700 x.SetTimeDisplay(1);
701 x.SetLabelSize(0.033);
702
703 const Double_t atm = MTime(mjd).GetAxisTime();
704
705 x.SetRangeUser(atm-(0.5+lng)*24*60*60+15*60, atm+(0.5-lng)*24*60*60-15*60);
706
707 g.SetMinimum(5);
708 g.SetMaximum(90);
709}
710
711// --------------------------------------------------------------------------
712//
713// Set Range of pad. If something has changed create and draw new primitives.
714// Paint all gui primitives.
715//
716void MAstroCatalog::Paint(Option_t *o)
717{
718 SetRangePad(o);
719
720 // In the case MAstroCatalog has been loaded from a file
721 // kHasChanged is not set, but fMapG.GetSize() is ==0
722 if (TestBit(kHasChanged) || fMapG.GetSize()==0)
723 DrawPrimitives(o);
724
725 fMapG.Paint();
726}
727
728// --------------------------------------------------------------------------
729//
730// Set Range of pad if pad available. If something has changed create
731// and draw new primitives. Paint all gui primitives to the Drawable with
732// Id id. This can be used to be able to
733//
734/*
735void MAstroCatalog::PaintImg(Int_t id, Option_t *o)
736{
737 if (gPad)
738 SetRangePad(o);
739
740 if (TestBit(kHasChanged))
741 {
742 if (id>0)
743 gPad=0;
744 DrawPrimitives(o);
745 }
746
747 fMapG.Paint(id, fRadiusFOV);
748}
749*/
750
751// --------------------------------------------------------------------------
752//
753// Set Range of pad. If something has changed create and draw new primitives.
754// Paint all gui primitives.
755//
756// Because in some kind of multi-threaded environments gPad doesn't stay
757// the same in a single thread (because it might be changed in the same
758// thread inside a gui updating timer for example) we have to secure the
759// usage of gPad with a bit. This is also not multi-thread safe against
760// calling this function, but the function should work well in multi-
761// threaded environments. Never call this function from different threads
762// simultaneously.
763//
764void MAstroCatalog::PaintImg(unsigned char *buf, int w, int h, Option_t *o)
765{
766 if (!o)
767 o = "local mirrorx yellow * =";
768
769 if (TestBit(kHasChanged))
770 {
771 SetBit(kDrawingImage);
772 DrawPrimitives(o);
773 ResetBit(kDrawingImage);
774 }
775
776 fMapG.Paint(buf, w, h, fRadiusFOV);
777}
778
779// --------------------------------------------------------------------------
780//
781// Draw a black marker at the position of the star. Create a corresponding
782// tooltip with the coordinates.
783// x, y: Pad Coordinates to draw star
784// v: Sky position (Ra/Dec) of the star
785// col: Color of marker (<0 mean transparent)
786// txt: additional tooltip text
787// resize: means resize the marker according to the magnitude
788//
789void MAstroCatalog::DrawStar(Double_t x, Double_t y, const TVector3 &v, Int_t col, const char *txt, Bool_t resize)
790{
791 const Double_t ra = v.Phi()*TMath::RadToDeg()/15;
792 const Double_t dec = (TMath::Pi()/2-v.Theta())*TMath::RadToDeg();
793
794 const Double_t mag = -2.5*log10(v.Mag());
795
796 TString str(v.GetName());
797 if (!str.IsNull())
798 str += ": ";
799 str += MString::Format("Ra=%.2fh Dec=%.1fd Mag=%.1f", ra, dec, mag);
800 if (txt)
801 {
802 str += " (";
803 str += txt;
804 str += ")";
805 }
806
807 // draw star on the camera display
808 TMarker *tip=new TMarker(x, y, kDot);
809 TAttMarker::Copy(*tip);
810
811 fMapG.Add(tip, new TString(str));
812
813 if (resize)
814 tip->SetMarkerSize((10 - (mag>1 ? mag : 1))/15);
815}
816
817// --------------------------------------------------------------------------
818//
819// Set pad as modified.
820//
821void MAstroCatalog::Update(Bool_t upd)
822{
823 SetBit(kHasChanged);
824 if (gPad && TestBit(kMustCleanup))
825 {
826 gPad->Modified();
827 if (upd)
828 gPad->Update();
829 }
830}
831
832// --------------------------------------------------------------------------
833//
834// Set the observation time. Necessary to use local coordinate
835// system. The MTime object is cloned.
836//
837void MAstroCatalog::SetTime(const MTime &time)
838{
839 if (fTime)
840 delete fTime;
841 fTime=(MTime*)time.Clone();
842}
843
844// --------------------------------------------------------------------------
845//
846// Set the observatory location. Necessary to use local coordinate
847// system. The MObservatory object is cloned.
848//
849void MAstroCatalog::SetObservatory(const MObservatory &obs)
850{
851 if (fObservatory)
852 delete fObservatory;
853 fObservatory=new MObservatory;
854 obs.Copy(*fObservatory);
855}
856
857// --------------------------------------------------------------------------
858//
859// Convert the vector to pad coordinates. After conversion
860// the x- coordinate of the vector must be the x coordinate
861// of the pad - the same for y. If the coordinate is inside
862// the current draw area return kTRUE, otherwise kFALSE.
863// If it is an invalid coordinate return kERROR
864//
865Int_t MAstroCatalog::ConvertToPad(const TVector3 &w0, TVector2 &v) const
866{
867 TVector3 w(w0);
868
869 // Stretch such, that the Z-component is alwas the same. Now
870 // X and Y contains the intersection point between the star-light
871 // and the plain of a virtual plain screen (ccd...)
872 if (TestBit(kPlainScreen))
873 w *= 1./w(2);
874
875 w *= TMath::RadToDeg(); // FIXME: *conversion factor?
876 v.Set(TestBit(kMirrorX) ? -w(0) : w(0),
877 TestBit(kMirrorY) ? -w(1) : w(1));
878
879 v=v.Rotate(fAngle*TMath::DegToRad());
880
881 if (w(2)<0)
882 return kERROR;
883
884 if (TestBit(kDrawingImage) || !gPad)
885 return v.Mod2()<fRadiusFOV*fRadiusFOV;
886
887 return v.X()>gPad->GetX1() && v.Y()>gPad->GetY1() &&
888 v.X()<gPad->GetX2() && v.Y()<gPad->GetY2();
889}
890
891// --------------------------------------------------------------------------
892//
893// Convert theta/phi coordinates of v by TRotation into new coordinate
894// system and convert the coordinated to pad by ConvertToPad.
895// The result is retunred in v.
896//
897Int_t MAstroCatalog::Convert(const TRotation &rot, TVector2 &v) const
898{
899 MVector3 w;
900 w.SetMagThetaPhi(1, v.Y(), v.X());
901 w *= rot;
902
903 return ConvertToPad(w, v);
904}
905
906// --------------------------------------------------------------------------
907//
908// Draw a line from v to v+(dx,dy) using Convert/ConvertToPad to get the
909// corresponding pad coordinates.
910//
911Bool_t MAstroCatalog::DrawLine(const TVector2 &v, Int_t dx, Int_t dy, const TRotation &rot, Int_t type)
912{
913 const TVector2 add(dx*TMath::DegToRad(), dy*TMath::DegToRad());
914
915 // Define all lines in the same direction
916 const TVector2 va(dy==1?v:v+add);
917 const TVector2 vb(dy==1?v+add:v);
918
919 TVector2 v0(va);
920 TVector2 v1(vb);
921
922 const Int_t rc0 = Convert(rot, v0);
923 const Int_t rc1 = Convert(rot, v1);
924
925 // Both are kFALSE or both are kERROR
926 if ((rc0|rc1)==kFALSE || (rc0&rc1)==kERROR)
927 return kFALSE;
928
929 TLine *line = new TLine(v0.X(), v0.Y(), v1.X(), v1.Y());
930 if (type==1)
931 dynamic_cast<TAttLine&>(fAttLineSky).Copy(dynamic_cast<TAttLine&>(*line));
932 else
933 dynamic_cast<TAttLine&>(fAttLineLocal).Copy(dynamic_cast<TAttLine&>(*line));
934 fMapG.Add(line);
935
936 if (dx!=0)
937 return kTRUE;
938
939 const TVector2 deg = va*TMath::RadToDeg();
940
941 MString txt;
942 if (type==1)
943 txt.Print("Ra=%.2fh Dec=%.1fd", fmod(deg.X()/15+48, 24), fmod(90-deg.Y()+270,180)-90);
944 else
945 txt.Print("Zd=%.1fd Az=%.1fd", fmod(deg.Y()+270,180)-90, fmod(deg.X()+720, 360));
946
947 TMarker *tip=new TMarker(v0.X(), v0.Y(), kDot);
948 tip->SetMarkerColor(kWhite+type*2);
949 fMapG.Add(tip, new TString(txt));
950
951 return kTRUE;
952}
953
954// --------------------------------------------------------------------------
955//
956// Use "local" draw option to align the display to the local
957// coordinate system instead of the sky coordinate system.
958// dx, dy are arrays storing recuresively all touched points
959// stepx, stepy are the step-size of the current grid.
960//
961void MAstroCatalog::Draw(const TVector2 &v0, const TRotation &rot, TArrayI &dx, TArrayI &dy, Int_t stepx, Int_t stepy, Int_t type)
962{
963 // Calculate the end point
964 const TVector2 v1 = v0 + TVector2(dx[0]*TMath::DegToRad(), dy[0]*TMath::DegToRad());
965
966 // Check whether the point has already been touched.
967 Int_t idx[] = {1, 1, 1, 1};
968
969 Int_t dirs[4][2] = { {0, stepy}, {stepx, 0}, {0, -stepy}, {-stepx, 0} };
970
971 // Check for ambiguities.
972 for (int i=0; i<dx.GetSize(); i++)
973 {
974 for (int j=0; j<4; j++)
975 {
976 const Bool_t rcx0 = (dx[i]+720)%360==(dx[0]+dirs[j][0]+720)%360;
977 const Bool_t rcy0 = (dy[i]+360)%180==(dy[0]+dirs[j][1]+360)%180;
978 if (rcx0&&rcy0)
979 idx[j] = 0;
980 }
981 }
982
983 // Enhance size of array by 1, copy current
984 // position as last entry
985 dx.Set(dx.GetSize()+1);
986 dy.Set(dy.GetSize()+1);
987
988 dx[dx.GetSize()-1] = dx[0];
989 dy[dy.GetSize()-1] = dy[0];
990
991 // Store current positon
992 const Int_t d[2] = { dx[0], dy[0] };
993
994 for (int i=0; i<4; i++)
995 if (idx[i])
996 {
997 // Calculate new position
998 dx[0] = d[0]+dirs[i][0];
999 dy[0] = d[1]+dirs[i][1];
1000
1001 // Draw corresponding line and iterate through grid
1002 if (DrawLine(v1, dirs[i][0], dirs[i][1], rot, type))
1003 Draw(v0, rot, dx, dy, stepx, stepy, type);
1004
1005 dx[0]=d[0];
1006 dy[0]=d[1];
1007 }
1008}
1009
1010// --------------------------------------------------------------------------
1011//
1012// Draw a grid recursively around the point v0 (either Ra/Dec or Zd/Az)
1013// The points in the grid are converted by a TRotation and CovertToPad
1014// to pad coordinates. The type arguemnts is neccessary to create the
1015// correct tooltip (Ra/Dec, Zd/Az) at the grid-points.
1016// From the pointing position the step-size of teh gris is caluclated.
1017//
1018void MAstroCatalog::DrawGrid(const TVector3 &v0, const TRotation &rot, Int_t type)
1019{
1020 TArrayI dx(1);
1021 TArrayI dy(1);
1022
1023 // align to 1deg boundary
1024 TVector2 v(v0.Phi()*TMath::RadToDeg(), v0.Theta()*TMath::RadToDeg());
1025 v.Set((Float_t)TMath::Nint(v.X()), (Float_t)TMath::Nint(v.Y()));
1026
1027 // calculate stepsizes based on visible FOV
1028 Int_t stepx = 1;
1029
1030 if (v.Y()<fRadiusFOV || v.Y()>180-fRadiusFOV)
1031 stepx=36;
1032 else
1033 {
1034 // This is a rough estimate how many degrees are visible
1035 const Float_t m = log(fRadiusFOV/180.)/log(90./(fRadiusFOV+1)+1);
1036 const Float_t t = log(180.)-m*log(fRadiusFOV);
1037 const Float_t f = m*log(90-fabs(90-v.Y()))+t;
1038 const Int_t nx = (Int_t)(exp(f)+0.5);
1039 stepx = nx<4 ? 1 : nx/4;
1040 if (stepx>36)
1041 stepx=36;
1042 }
1043
1044 const Int_t ny = (Int_t)(fRadiusFOV+1);
1045 Int_t stepy = ny<4 ? 1 : ny/4;
1046
1047 // align stepsizes to be devisor or 180 and 90
1048 while (180%stepx)
1049 stepx++;
1050 while (90%stepy)
1051 stepy++;
1052
1053 // align to step-size boundary (search for the nearest one)
1054 Int_t dv = 1;
1055 while ((int)(v.X())%stepx)
1056 {
1057 v.Set(v.X()+dv, v.Y());
1058 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
1059 }
1060
1061 dv = 1;
1062 while ((int)(v.Y())%stepy)
1063 {
1064 v.Set(v.X(), v.Y()+dv);
1065 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
1066 }
1067
1068 // draw...
1069 v *= TMath::DegToRad();
1070
1071 Draw(v, rot, dx, dy, stepx, stepy, type);
1072}
1073
1074// --------------------------------------------------------------------------
1075//
1076// Get a rotation matrix which aligns the pointing position
1077// to the center of the x,y plain
1078//
1079TRotation MAstroCatalog::AlignCoordinates(const TVector3 &v) const
1080{
1081 TRotation trans;
1082 trans.RotateZ(-v.Phi());
1083 trans.RotateY(-v.Theta());
1084 trans.RotateZ(-TMath::Pi()/2);
1085 return trans;
1086}
1087
1088// --------------------------------------------------------------------------
1089//
1090// Return the rotation matrix which converts either sky or
1091// local coordinates to coordinates which pole is the current
1092// pointing direction.
1093//
1094TRotation MAstroCatalog::GetGrid(Bool_t local)
1095{
1096 const Bool_t enable = fTime && fObservatory;
1097
1098 // If sky coordinate view is requested get rotation matrix and
1099 // draw corresponding sky-grid and if possible local grid
1100 if (!local)
1101 {
1102 const TRotation trans(AlignCoordinates(fRaDec));
1103
1104 DrawGrid(fRaDec, trans, 1);
1105
1106 if (enable)
1107 {
1108 const MAstroSky2Local rot(*fTime, *fObservatory);
1109 DrawGrid(rot*fRaDec, trans*rot.Inverse(), 2);
1110 }
1111
1112 // Return the correct rotation matrix
1113 return trans;
1114 }
1115
1116 // If local coordinate view is requested get rotation matrix and
1117 // draw corresponding sky-grid and if possible local grid
1118 if (local && enable)
1119 {
1120 const MAstroSky2Local rot(*fTime, *fObservatory);
1121
1122 const TRotation trans(AlignCoordinates(rot*fRaDec));
1123
1124 DrawGrid(fRaDec, trans*rot, 1);
1125 DrawGrid(rot*fRaDec, trans, 2);
1126
1127 // Return the correct rotation matrix
1128 return trans*rot;
1129 }
1130
1131 return TRotation();
1132}
1133
1134// --------------------------------------------------------------------------
1135//
1136// Create the title for the pad.
1137//
1138TString MAstroCatalog::GetPadTitle() const
1139{
1140 const Double_t ra = fRaDec.Phi()*TMath::RadToDeg();
1141 const Double_t dec = (TMath::Pi()/2-fRaDec.Theta())*TMath::RadToDeg();
1142
1143 TString txt;
1144 txt += Form("\\alpha=%.2fh ", fmod(ra/15+48, 24));
1145 txt += Form("\\delta=%.1f\\circ ", fmod(dec+270,180)-90);
1146 txt += Form("/ FOV=%.1f\\circ", fRadiusFOV);
1147
1148 if (!fTime || !fObservatory)
1149 return txt;
1150
1151 const MAstroSky2Local rot(*fTime, *fObservatory);
1152 const TVector3 loc = rot*fRaDec;
1153
1154 const Double_t rho = rot.RotationAngle(fRaDec.Phi(), TMath::Pi()/2-fRaDec.Theta());
1155
1156 const Double_t zd = TMath::RadToDeg()*loc.Theta();
1157 const Double_t az = TMath::RadToDeg()*loc.Phi();
1158
1159 txt.Prepend("#splitline{");
1160 txt += Form(" \\theta=%.1f\\circ ", fmod(zd+270,180)-90);
1161 txt += Form("\\phi=%.1f\\circ ", fmod(az+720, 360));
1162 txt += Form(" / \\rho=%.1f\\circ", rho*TMath::RadToDeg());
1163 txt += "}{<";
1164 txt += fTime->GetSqlDateTime();
1165 txt += ">}";
1166 return txt;
1167}
1168
1169// --------------------------------------------------------------------------
1170//
1171// To overlay the catalog make sure, that in any case you are using
1172// the 'same' option.
1173//
1174// If you want to overlay this on top of any picture which is created
1175// by derotation of the camera plain you have to use the 'mirror' option
1176// the compensate the mirroring of the image in the camera plain.
1177//
1178// If you have already compensated this by x=-x and y=-y when creating
1179// the histogram you can simply overlay the catalog.
1180//
1181// To overlay the catalog on a 2D histogram the histogram must have
1182// units of degrees (which are plain, like you directly convert the
1183// camera units by multiplication to degrees)
1184//
1185// To be 100% exact you must use the option 'plain' which assumes a plain
1186// screen. This is not necessary for the MAGIC-camera because the
1187// difference between both is less than 1e-3.
1188//
1189// You should always be aware of the fact, that the shown stars and the
1190// displayed grid is the ideal case, like a reflection on a virtual
1191// perfectly aligned central mirror. In reality the star-positions are
1192// smeared to the edge of the camera the more the distance to the center
1193// is, such that the center of gravity of the light distribution might
1194// be more far away from the center than the display shows.
1195//
1196// If you want the stars to be displayed as circles with a size
1197// showing their magnitude use "*" as an option.
1198//
1199// Use 'white' to display white instead of black stars
1200// Use 'yellow' to display white instead of black stars
1201//
1202//
1203void MAstroCatalog::AddPrimitives(TString o)
1204{
1205 const Bool_t same = o.Contains("same", TString::kIgnoreCase);
1206 const Bool_t local = o.Contains("local", TString::kIgnoreCase);
1207 const Bool_t mirx = o.Contains("mirrorx", TString::kIgnoreCase);
1208 const Bool_t miry = o.Contains("mirrory", TString::kIgnoreCase);
1209 const Bool_t mirror = o.Contains("mirror", TString::kIgnoreCase) && !mirx && !miry;
1210 const Bool_t size = o.Contains("*", TString::kIgnoreCase);
1211 const Bool_t white = o.Contains("white", TString::kIgnoreCase);
1212 const Bool_t yellow = o.Contains("yellow", TString::kIgnoreCase) && !white;
1213 const Bool_t rot180 = o.Contains("180", TString::kIgnoreCase);
1214 const Bool_t rot270 = o.Contains("270", TString::kIgnoreCase);
1215 const Bool_t rot90 = o.Contains("90", TString::kIgnoreCase);
1216
1217 if (white)
1218 SetMarkerColor(kWhite);
1219
1220 fAngle = 0;
1221 if (rot90)
1222 fAngle=90;
1223 if (rot180)
1224 fAngle=180;
1225 if (rot270)
1226 fAngle=270;
1227
1228 // X is vice versa, because ra is defined anti-clockwise
1229 mirx || mirror ? ResetBit(kMirrorX) : SetBit(kMirrorX);
1230 miry || mirror ? SetBit(kMirrorY) : ResetBit(kMirrorY);
1231
1232 const TRotation rot(GetGrid(local));
1233
1234 TIter Next(&fList);
1235 MVector3 *v=0;
1236 while ((v=(MVector3*)Next()))
1237 {
1238 if (v->Magnitude()>fLimMag)
1239 continue;
1240
1241 TVector2 s(v->Phi(), v->Theta());
1242 if (Convert(rot, s)==kTRUE)
1243 DrawStar(s.X(), s.Y(), *v, yellow?kYellow:(white?kWhite:kBlack), 0, size);
1244 }
1245
1246 if (!same && !TestBit(kDrawingImage) && gPad)
1247 {
1248 TPaveText *pv = new TPaveText(0.01, 0.90, 0.63, 0.99, "brNDC");
1249 pv->AddText(GetPadTitle());
1250 fMapG.Add(pv);
1251 }
1252
1253 TMarker *mk=new TMarker(0, 0, kMultiply);
1254 mk->SetMarkerColor(white||yellow?kWhite:kBlack);
1255 mk->SetMarkerSize(1.5);
1256 fMapG.Add(mk);
1257}
1258
1259// --------------------------------------------------------------------------
1260//
1261// Do nothing if 'same' option given.
1262// Otherwise set pad-range such that x- and y- coordinates have the same
1263// step-size
1264//
1265void MAstroCatalog::SetRangePad(Option_t *o)
1266{
1267 if (TString(o).Contains("same", TString::kIgnoreCase))
1268 return;
1269
1270 const Double_t edge = fRadiusFOV/TMath::Sqrt(2.);
1271 //gPad->Range(-edge, -edge, edge, edge);
1272
1273 const Float_t w = gPad->GetWw();
1274 const Float_t h = gPad->GetWh();
1275
1276 if (w<h)
1277 gPad->Range(-edge, -edge*h/w, edge, edge*h/w);
1278 else
1279 gPad->Range(-edge*w/h, -edge, edge*w/h, edge);
1280}
1281
1282// --------------------------------------------------------------------------
1283//
1284// Bends some pointers into the right direction...
1285// Calls TAttLine::SetLineAttributes and connects some signals
1286// to the gui to recreate the gui elements if something has changed.
1287//
1288void MAstroCatalog::SetLineAttributes(MAttLine &att)
1289{
1290 if (!gPad)
1291 return;
1292
1293 gPad->SetSelected(&att);
1294 gROOT->SetSelectedPrimitive(&att);
1295
1296 att.SetLineAttributes();
1297
1298 TQObject::Connect("TGColorSelect", "ColorSelected(Pixel_t)", "MAstroCatalog", this, "ForceUpdate()");
1299 TQObject::Connect("TGListBox", "Selected(Int_t)", "MAstroCatalog", this, "ForceUpdate()");
1300}
1301
1302// --------------------------------------------------------------------------
1303//
1304// Calls TAttMarker::SetMarkerAttributes and connects some signals
1305// to the gui to recreate the gui elements if something has changed.
1306//
1307void MAstroCatalog::SetMarkerAttributes()
1308{
1309 if (!gPad)
1310 return;
1311
1312 TAttMarker::SetMarkerAttributes();
1313
1314 // Make sure that if something is changed the gui elements
1315 // are recreated
1316 TQObject::Connect("TGedMarkerSelect", "MarkerSelected(Style_t)", "MAstroCatalog", this, "ForceUpdate()");
1317 TQObject::Connect("TGColorSelect", "ColorSelected(Pixel_t)", "MAstroCatalog", this, "ForceUpdate()");
1318 TQObject::Connect("TGListBox", "Selected(Int_t)", "MAstroCatalog", this, "ForceUpdate()");
1319}
1320
1321void MAstroCatalog::DrawPrimitives(Option_t *o)
1322{
1323 fMapG.Delete();
1324
1325 if (!TestBit(kDrawingImage) && gPad)
1326 SetRangePad(o);
1327
1328#ifdef DEBUG
1329 TStopwatch clk;
1330 clk.Start();
1331#endif
1332 AddPrimitives(o);
1333#ifdef DEBUG
1334 clk.Stop();
1335 clk.Print();
1336#endif
1337
1338 // Append to a possible second pad
1339 if (!TestBit(kDrawingImage) && gPad && !gPad->GetListOfPrimitives()->FindObject(this))
1340 AppendPad(o);
1341
1342 ResetBit(kHasChanged);
1343}
1344
1345// --------------------------------------------------------------------------
1346//
1347// Append "this" to current pad
1348// set bit kHasChanged to recreate all gui elements
1349// Connect signal
1350//
1351void MAstroCatalog::Draw(Option_t *o)
1352{
1353 // Append to first pad
1354 AppendPad(o);
1355
1356 // If contents have not previously changed make sure that
1357 // all primitives are recreated.
1358 SetBit(kHasChanged);
1359
1360 // Connect all TCanvas::ProcessedEvent to this->EventInfo
1361 // This means, that after TCanvas has processed an event
1362 // EventInfo of this class is called, see TCanvas::HandleInput
1363 gPad->GetCanvas()->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
1364 "MAstroCatalog", this,
1365 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
1366}
1367
1368// --------------------------------------------------------------------------
1369//
1370// This function was connected to all created canvases. It is used
1371// to redirect GetObjectInfo into our own status bar.
1372//
1373// The 'connection' is done in Draw. It seems that 'connected'
1374// functions must be public.
1375//
1376void MAstroCatalog::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
1377{
1378 TCanvas *c = (TCanvas*)gTQSender;
1379
1380 gPad = c ? c->GetSelectedPad() : NULL;
1381 if (!gPad)
1382 return;
1383
1384
1385 // Try to find a corresponding object with kCannotPick set and
1386 // an available TString (for a tool tip)
1387 TString str;
1388 if (!selected || selected==this)
1389 selected = fMapG.PickObject(px, py, str);
1390
1391 if (!selected)
1392 return;
1393
1394 // Handle some gui events
1395 switch (event)
1396 {
1397 case kMouseMotion:
1398 if (fToolTip && !fToolTip->IsMapped() && !str.IsNull())
1399 ShowToolTip(px, py, str);
1400 break;
1401
1402 case kMouseLeave:
1403 if (fToolTip && fToolTip->IsMapped())
1404 fToolTip->Hide();
1405 break;
1406
1407 case kKeyPress:
1408 ExecuteEvent(kKeyPress, px, py);
1409 break;
1410 }
1411}
1412
1413// --------------------------------------------------------------------------
1414//
1415// Handle keyboard events.
1416//
1417void MAstroCatalog::ExecuteEventKbd(Int_t keycode, Int_t keysym)
1418{
1419 Double_t dra =0;
1420 Double_t ddec=0;
1421
1422 switch (keysym)
1423 {
1424 case kKey_Left:
1425 dra = -TMath::DegToRad();
1426 break;
1427 case kKey_Right:
1428 dra = +TMath::DegToRad();
1429 break;
1430 case kKey_Up:
1431 ddec = +TMath::DegToRad();
1432 break;
1433 case kKey_Down:
1434 ddec = -TMath::DegToRad();
1435 break;
1436 case kKey_Plus:
1437 SetRadiusFOV(fRadiusFOV+1);
1438 break;
1439 case kKey_Minus:
1440 SetRadiusFOV(fRadiusFOV-1);
1441 break;
1442
1443 default:
1444 return;
1445 }
1446
1447 const Double_t r = fRaDec.Phi();
1448 const Double_t d = TMath::Pi()/2-fRaDec.Theta();
1449
1450 SetRaDec(r+dra, d+ddec);
1451
1452 gPad->Update();
1453}
1454
1455// ------------------------------------------------------------------------
1456//
1457// Execute a gui event on the camera
1458//
1459void MAstroCatalog::ExecuteEvent(Int_t event, Int_t mp1, Int_t mp2)
1460{
1461 if (!TestBit(kGuiActive))
1462 return;
1463
1464 if (event==kKeyPress)
1465 ExecuteEventKbd(mp1, mp2);
1466}
1467
1468// --------------------------------------------------------------------------
1469//
1470// Displays a tooltip
1471//
1472void MAstroCatalog::ShowToolTip(Int_t px, Int_t py, const char *txt)
1473{
1474 if (TestBit(kNoToolTips))
1475 return;
1476
1477 Int_t x=0;
1478 Int_t y=0;
1479
1480 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
1481 const Window_t id2 = fToolTip->GetParent()->GetId();
1482
1483 Window_t id3;
1484 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
1485
1486 // Show tool tip
1487 fToolTip->SetText(txt);
1488 fToolTip->Show(x+4, y+4);
1489}
1490
1491// --------------------------------------------------------------------------
1492//
1493// Calculate distance to primitive by checking all gui elements
1494//
1495Int_t MAstroCatalog::DistancetoPrimitive(Int_t px, Int_t py)
1496{
1497 return fMapG.DistancetoPrimitive(px, py);
1498}
1499
1500// ------------------------------------------------------------------------
1501//
1502// Returns string containing info about the object at position (px,py).
1503// Returned string will be re-used (lock in MT environment).
1504//
1505char *MAstroCatalog::GetObjectInfo(Int_t px, Int_t py) const
1506{
1507 return fMapG.GetObjectInfo(px, py);
1508}
Note: See TracBrowser for help on using the repository browser.