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

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