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

Last change on this file since 8785 was 8725, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 42.3 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MAstroCatalog.cc,v 1.29 2007-09-02 13:53:55 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 if (!fRaDec.IsValid())
721 return;
722
723 SetRangePad(o);
724
725 // In the case MAstroCatalog has been loaded from a file
726 // kHasChanged is not set, but fMapG.GetSize() is ==0
727 if (TestBit(kHasChanged) || fMapG.GetSize()==0)
728 DrawPrimitives(o);
729
730 fMapG.Paint();
731}
732
733// --------------------------------------------------------------------------
734//
735// Set Range of pad if pad available. If something has changed create
736// and draw new primitives. Paint all gui primitives to the Drawable with
737// Id id. This can be used to be able to
738//
739/*
740void MAstroCatalog::PaintImg(Int_t id, Option_t *o)
741{
742 if (gPad)
743 SetRangePad(o);
744
745 if (TestBit(kHasChanged))
746 {
747 if (id>0)
748 gPad=0;
749 DrawPrimitives(o);
750 }
751
752 fMapG.Paint(id, fRadiusFOV);
753}
754*/
755
756// --------------------------------------------------------------------------
757//
758// Set Range of pad. If something has changed create and draw new primitives.
759// Paint all gui primitives.
760//
761// Because in some kind of multi-threaded environments gPad doesn't stay
762// the same in a single thread (because it might be changed in the same
763// thread inside a gui updating timer for example) we have to secure the
764// usage of gPad with a bit. This is also not multi-thread safe against
765// calling this function, but the function should work well in multi-
766// threaded environments. Never call this function from different threads
767// simultaneously.
768//
769void MAstroCatalog::PaintImg(unsigned char *buf, int w, int h, Option_t *o)
770{
771 if (!o)
772 o = "local mirrorx yellow * =";
773
774 if (TestBit(kHasChanged))
775 {
776 SetBit(kDrawingImage);
777 DrawPrimitives(o);
778 ResetBit(kDrawingImage);
779 }
780
781 fMapG.Paint(buf, w, h, fRadiusFOV);
782}
783
784// --------------------------------------------------------------------------
785//
786// Draw a black marker at the position of the star. Create a corresponding
787// tooltip with the coordinates.
788// x, y: Pad Coordinates to draw star
789// v: Sky position (Ra/Dec) of the star
790// col: Color of marker (<0 mean transparent)
791// txt: additional tooltip text
792// resize: means resize the marker according to the magnitude
793//
794void MAstroCatalog::DrawStar(Double_t x, Double_t y, const TVector3 &v, Int_t col, const char *txt, Bool_t resize)
795{
796 const Double_t ra = v.Phi()*TMath::RadToDeg()/15;
797 const Double_t dec = (TMath::Pi()/2-v.Theta())*TMath::RadToDeg();
798
799 const Double_t mag = -2.5*log10(v.Mag());
800
801 TString str(v.GetName());
802 if (!str.IsNull())
803 str += ": ";
804 str += MString::Format("Ra=%.2fh Dec=%.1fd Mag=%.1f", ra, dec, mag);
805 if (txt)
806 {
807 str += " (";
808 str += txt;
809 str += ")";
810 }
811
812 // draw star on the camera display
813 TMarker *tip=new TMarker(x, y, kDot);
814 TAttMarker::Copy(*tip);
815
816 fMapG.Add(tip, new TString(str));
817
818 if (resize)
819 tip->SetMarkerSize((10 - (mag>1 ? mag : 1))/15);
820}
821
822// --------------------------------------------------------------------------
823//
824// Set pad as modified.
825//
826void MAstroCatalog::Update(Bool_t upd)
827{
828 SetBit(kHasChanged);
829 if (gPad && TestBit(kMustCleanup))
830 {
831 gPad->Modified();
832 if (upd)
833 gPad->Update();
834 }
835}
836
837// --------------------------------------------------------------------------
838//
839// Set the observation time. Necessary to use local coordinate
840// system. The MTime object is cloned.
841//
842void MAstroCatalog::SetTime(const MTime &time)
843{
844 if (fTime)
845 delete fTime;
846 fTime=(MTime*)time.Clone();
847}
848
849// --------------------------------------------------------------------------
850//
851// Set the observatory location. Necessary to use local coordinate
852// system. The MObservatory object is cloned.
853//
854void MAstroCatalog::SetObservatory(const MObservatory &obs)
855{
856 if (fObservatory)
857 delete fObservatory;
858 fObservatory=new MObservatory;
859 obs.Copy(*fObservatory);
860}
861
862// --------------------------------------------------------------------------
863//
864// Convert the vector to pad coordinates. After conversion
865// the x- coordinate of the vector must be the x coordinate
866// of the pad - the same for y. If the coordinate is inside
867// the current draw area return kTRUE, otherwise kFALSE.
868// If it is an invalid coordinate return kERROR
869//
870Int_t MAstroCatalog::ConvertToPad(const TVector3 &w0, TVector2 &v) const
871{
872 TVector3 w(w0);
873
874 // Stretch such, that the Z-component is alwas the same. Now
875 // X and Y contains the intersection point between the star-light
876 // and the plain of a virtual plain screen (ccd...)
877 if (TestBit(kPlainScreen))
878 w *= 1./w(2);
879
880 w *= TMath::RadToDeg(); // FIXME: *conversion factor?
881 v.Set(TestBit(kMirrorX) ? -w(0) : w(0),
882 TestBit(kMirrorY) ? -w(1) : w(1));
883
884 v=v.Rotate(fAngle*TMath::DegToRad());
885
886 if (w(2)<0)
887 return kERROR;
888
889 if (TestBit(kDrawingImage) || !gPad)
890 return v.Mod2()<fRadiusFOV*fRadiusFOV;
891
892 return v.X()>gPad->GetX1() && v.Y()>gPad->GetY1() &&
893 v.X()<gPad->GetX2() && v.Y()<gPad->GetY2();
894}
895
896// --------------------------------------------------------------------------
897//
898// Convert theta/phi coordinates of v by TRotation into new coordinate
899// system and convert the coordinated to pad by ConvertToPad.
900// The result is retunred in v.
901//
902Int_t MAstroCatalog::Convert(const TRotation &rot, TVector2 &v) const
903{
904 MVector3 w;
905 w.SetMagThetaPhi(1, v.Y(), v.X());
906 w *= rot;
907
908 return ConvertToPad(w, v);
909}
910
911// --------------------------------------------------------------------------
912//
913// Draw a line from v to v+(dx,dy) using Convert/ConvertToPad to get the
914// corresponding pad coordinates.
915//
916Bool_t MAstroCatalog::DrawLine(const TVector2 &v, Int_t dx, Int_t dy, const TRotation &rot, Int_t type)
917{
918 const TVector2 add(dx*TMath::DegToRad(), dy*TMath::DegToRad());
919
920 // Define all lines in the same direction
921 const TVector2 va(dy==1?v:v+add);
922 const TVector2 vb(dy==1?v+add:v);
923
924 TVector2 v0(va);
925 TVector2 v1(vb);
926
927 const Int_t rc0 = Convert(rot, v0);
928 const Int_t rc1 = Convert(rot, v1);
929
930 // Both are kFALSE or both are kERROR
931 if ((rc0|rc1)==kFALSE || (rc0&rc1)==kERROR)
932 return kFALSE;
933
934 TLine *line = new TLine(v0.X(), v0.Y(), v1.X(), v1.Y());
935 if (type==1)
936 dynamic_cast<TAttLine&>(fAttLineSky).Copy(dynamic_cast<TAttLine&>(*line));
937 else
938 dynamic_cast<TAttLine&>(fAttLineLocal).Copy(dynamic_cast<TAttLine&>(*line));
939 fMapG.Add(line);
940
941 if (dx!=0)
942 return kTRUE;
943
944 const TVector2 deg = va*TMath::RadToDeg();
945
946 MString txt;
947 if (type==1)
948 txt.Print("Ra=%.2fh Dec=%.1fd", fmod(deg.X()/15+48, 24), fmod(90-deg.Y()+270,180)-90);
949 else
950 txt.Print("Zd=%.1fd Az=%.1fd", fmod(deg.Y()+270,180)-90, fmod(deg.X()+720, 360));
951
952 TMarker *tip=new TMarker(v0.X(), v0.Y(), kDot);
953 tip->SetMarkerColor(kWhite+type*2);
954 fMapG.Add(tip, new TString(txt));
955
956 return kTRUE;
957}
958
959// --------------------------------------------------------------------------
960//
961// Use "local" draw option to align the display to the local
962// coordinate system instead of the sky coordinate system.
963// dx, dy are arrays storing recuresively all touched points
964// stepx, stepy are the step-size of the current grid.
965//
966void MAstroCatalog::Draw(const TVector2 &v0, const TRotation &rot, TArrayI &dx, TArrayI &dy, Int_t stepx, Int_t stepy, Int_t type)
967{
968 // Calculate the end point
969 const TVector2 v1 = v0 + TVector2(dx[0]*TMath::DegToRad(), dy[0]*TMath::DegToRad());
970
971 // Check whether the point has already been touched.
972 Int_t idx[] = {1, 1, 1, 1};
973
974 Int_t dirs[4][2] = { {0, stepy}, {stepx, 0}, {0, -stepy}, {-stepx, 0} };
975
976 // Check for ambiguities.
977 for (int i=0; i<dx.GetSize(); i++)
978 {
979 for (int j=0; j<4; j++)
980 {
981 const Bool_t rcx0 = (dx[i]+720)%360==(dx[0]+dirs[j][0]+720)%360;
982 const Bool_t rcy0 = (dy[i]+360)%180==(dy[0]+dirs[j][1]+360)%180;
983 if (rcx0&&rcy0)
984 idx[j] = 0;
985 }
986 }
987
988 // Enhance size of array by 1, copy current
989 // position as last entry
990 dx.Set(dx.GetSize()+1);
991 dy.Set(dy.GetSize()+1);
992
993 dx[dx.GetSize()-1] = dx[0];
994 dy[dy.GetSize()-1] = dy[0];
995
996 // Store current positon
997 const Int_t d[2] = { dx[0], dy[0] };
998
999 for (int i=0; i<4; i++)
1000 if (idx[i])
1001 {
1002 // Calculate new position
1003 dx[0] = d[0]+dirs[i][0];
1004 dy[0] = d[1]+dirs[i][1];
1005
1006 // Draw corresponding line and iterate through grid
1007 if (DrawLine(v1, dirs[i][0], dirs[i][1], rot, type))
1008 Draw(v0, rot, dx, dy, stepx, stepy, type);
1009
1010 dx[0]=d[0];
1011 dy[0]=d[1];
1012 }
1013}
1014
1015// --------------------------------------------------------------------------
1016//
1017// Draw a grid recursively around the point v0 (either Ra/Dec or Zd/Az)
1018// The points in the grid are converted by a TRotation and CovertToPad
1019// to pad coordinates. The type arguemnts is neccessary to create the
1020// correct tooltip (Ra/Dec, Zd/Az) at the grid-points.
1021// From the pointing position the step-size of teh gris is caluclated.
1022//
1023void MAstroCatalog::DrawGrid(const TVector3 &v0, const TRotation &rot, Int_t type)
1024{
1025 TArrayI dx(1);
1026 TArrayI dy(1);
1027
1028 // align to 1deg boundary
1029 TVector2 v(v0.Phi()*TMath::RadToDeg(), v0.Theta()*TMath::RadToDeg());
1030 v.Set((Float_t)TMath::Nint(v.X()), (Float_t)TMath::Nint(v.Y()));
1031
1032 // calculate stepsizes based on visible FOV
1033 Int_t stepx = 1;
1034
1035 if (v.Y()<fRadiusFOV || v.Y()>180-fRadiusFOV)
1036 stepx=36;
1037 else
1038 {
1039 // This is a rough estimate how many degrees are visible
1040 const Float_t m = log(fRadiusFOV/180.)/log(90./(fRadiusFOV+1)+1);
1041 const Float_t t = log(180.)-m*log(fRadiusFOV);
1042 const Float_t f = m*log(90-fabs(90-v.Y()))+t;
1043 const Int_t nx = (Int_t)(exp(f)+0.5);
1044 stepx = nx<4 ? 1 : nx/4;
1045 if (stepx>36)
1046 stepx=36;
1047 }
1048
1049 const Int_t ny = (Int_t)(fRadiusFOV+1);
1050 Int_t stepy = ny<4 ? 1 : ny/4;
1051
1052 // align stepsizes to be devisor or 180 and 90
1053 while (180%stepx)
1054 stepx++;
1055 while (90%stepy)
1056 stepy++;
1057
1058 // align to step-size boundary (search for the nearest one)
1059 Int_t dv = 1;
1060 while ((int)(v.X())%stepx)
1061 {
1062 v.Set(v.X()+dv, v.Y());
1063 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
1064 }
1065
1066 dv = 1;
1067 while ((int)(v.Y())%stepy)
1068 {
1069 v.Set(v.X(), v.Y()+dv);
1070 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
1071 }
1072
1073 // draw...
1074 v *= TMath::DegToRad();
1075
1076 Draw(v, rot, dx, dy, stepx, stepy, type);
1077}
1078
1079// --------------------------------------------------------------------------
1080//
1081// Get a rotation matrix which aligns the pointing position
1082// to the center of the x,y plain
1083//
1084TRotation MAstroCatalog::AlignCoordinates(const TVector3 &v) const
1085{
1086 TRotation trans;
1087 trans.RotateZ(-v.Phi());
1088 trans.RotateY(-v.Theta());
1089 trans.RotateZ(-TMath::Pi()/2);
1090 return trans;
1091}
1092
1093// --------------------------------------------------------------------------
1094//
1095// Return the rotation matrix which converts either sky or
1096// local coordinates to coordinates which pole is the current
1097// pointing direction.
1098//
1099TRotation MAstroCatalog::GetGrid(Bool_t local)
1100{
1101 const Bool_t enable = fTime && fObservatory;
1102
1103 // If sky coordinate view is requested get rotation matrix and
1104 // draw corresponding sky-grid and if possible local grid
1105 if (!local)
1106 {
1107 const TRotation trans(AlignCoordinates(fRaDec));
1108
1109 DrawGrid(fRaDec, trans, 1);
1110
1111 if (enable)
1112 {
1113 const MAstroSky2Local rot(*fTime, *fObservatory);
1114 DrawGrid(rot*fRaDec, trans*rot.Inverse(), 2);
1115 }
1116
1117 // Return the correct rotation matrix
1118 return trans;
1119 }
1120
1121 // If local coordinate view is requested get rotation matrix and
1122 // draw corresponding sky-grid and if possible local grid
1123 if (local && enable)
1124 {
1125 const MAstroSky2Local rot(*fTime, *fObservatory);
1126
1127 const TRotation trans(AlignCoordinates(rot*fRaDec));
1128
1129 DrawGrid(fRaDec, trans*rot, 1);
1130 DrawGrid(rot*fRaDec, trans, 2);
1131
1132 // Return the correct rotation matrix
1133 return trans*rot;
1134 }
1135
1136 return TRotation();
1137}
1138
1139// --------------------------------------------------------------------------
1140//
1141// Create the title for the pad.
1142//
1143TString MAstroCatalog::GetPadTitle() const
1144{
1145 const Double_t ra = fRaDec.Phi()*TMath::RadToDeg();
1146 const Double_t dec = (TMath::Pi()/2-fRaDec.Theta())*TMath::RadToDeg();
1147
1148 TString txt;
1149 txt += Form("\\alpha=%.2fh ", fmod(ra/15+48, 24));
1150 txt += Form("\\delta=%.1f\\circ ", fmod(dec+270,180)-90);
1151 txt += Form("/ FOV=%.1f\\circ", fRadiusFOV);
1152
1153 if (!fTime || !fObservatory)
1154 return txt;
1155
1156 const MAstroSky2Local rot(*fTime, *fObservatory);
1157 const TVector3 loc = rot*fRaDec;
1158
1159 const Double_t rho = rot.RotationAngle(fRaDec.Phi(), TMath::Pi()/2-fRaDec.Theta());
1160
1161 const Double_t zd = TMath::RadToDeg()*loc.Theta();
1162 const Double_t az = TMath::RadToDeg()*loc.Phi();
1163
1164 txt.Prepend("#splitline{");
1165 txt += Form(" \\theta=%.1f\\circ ", fmod(zd+270,180)-90);
1166 txt += Form("\\phi=%.1f\\circ ", fmod(az+720, 360));
1167 txt += Form(" / \\rho=%.1f\\circ", rho*TMath::RadToDeg());
1168 txt += "}{<";
1169 txt += fTime->GetSqlDateTime();
1170 txt += ">}";
1171 return txt;
1172}
1173
1174// --------------------------------------------------------------------------
1175//
1176// To overlay the catalog make sure, that in any case you are using
1177// the 'same' option.
1178//
1179// If you want to overlay this on top of any picture which is created
1180// by derotation of the camera plain you have to use the 'mirror' option
1181// the compensate the mirroring of the image in the camera plain.
1182//
1183// If you have already compensated this by x=-x and y=-y when creating
1184// the histogram you can simply overlay the catalog.
1185//
1186// To overlay the catalog on a 2D histogram the histogram must have
1187// units of degrees (which are plain, like you directly convert the
1188// camera units by multiplication to degrees)
1189//
1190// To be 100% exact you must use the option 'plain' which assumes a plain
1191// screen. This is not necessary for the MAGIC-camera because the
1192// difference between both is less than 1e-3.
1193//
1194// You should always be aware of the fact, that the shown stars and the
1195// displayed grid is the ideal case, like a reflection on a virtual
1196// perfectly aligned central mirror. In reality the star-positions are
1197// smeared to the edge of the camera the more the distance to the center
1198// is, such that the center of gravity of the light distribution might
1199// be more far away from the center than the display shows.
1200//
1201// If you want the stars to be displayed as circles with a size
1202// showing their magnitude use "*" as an option.
1203//
1204// Use 'white' to display white instead of black stars
1205// Use 'yellow' to display white instead of black stars
1206//
1207//
1208void MAstroCatalog::AddPrimitives(TString o)
1209{
1210 const Bool_t same = o.Contains("same", TString::kIgnoreCase);
1211 const Bool_t local = o.Contains("local", TString::kIgnoreCase);
1212 const Bool_t mirx = o.Contains("mirrorx", TString::kIgnoreCase);
1213 const Bool_t miry = o.Contains("mirrory", TString::kIgnoreCase);
1214 const Bool_t mirror = o.Contains("mirror", TString::kIgnoreCase) && !mirx && !miry;
1215 const Bool_t size = o.Contains("*", TString::kIgnoreCase);
1216 const Bool_t white = o.Contains("white", TString::kIgnoreCase);
1217 const Bool_t yellow = o.Contains("yellow", TString::kIgnoreCase) && !white;
1218 const Bool_t rot180 = o.Contains("180", TString::kIgnoreCase);
1219 const Bool_t rot270 = o.Contains("270", TString::kIgnoreCase);
1220 const Bool_t rot90 = o.Contains("90", TString::kIgnoreCase);
1221
1222 if (white)
1223 SetMarkerColor(kWhite);
1224
1225 fAngle = 0;
1226 if (rot90)
1227 fAngle=90;
1228 if (rot180)
1229 fAngle=180;
1230 if (rot270)
1231 fAngle=270;
1232
1233 // X is vice versa, because ra is defined anti-clockwise
1234 mirx || mirror ? ResetBit(kMirrorX) : SetBit(kMirrorX);
1235 miry || mirror ? SetBit(kMirrorY) : ResetBit(kMirrorY);
1236
1237 const TRotation rot(GetGrid(local));
1238
1239 TIter Next(&fList);
1240 MVector3 *v=0;
1241 while ((v=(MVector3*)Next()))
1242 {
1243 if (v->Magnitude()>fLimMag)
1244 continue;
1245
1246 TVector2 s(v->Phi(), v->Theta());
1247 if (Convert(rot, s)==kTRUE)
1248 DrawStar(s.X(), s.Y(), *v, yellow?kYellow:(white?kWhite:kBlack), 0, size);
1249 }
1250
1251 if (!same && !TestBit(kDrawingImage) && gPad)
1252 {
1253 TPaveText *pv = new TPaveText(0.01, 0.90, 0.63, 0.99, "brNDC");
1254 pv->AddText(GetPadTitle());
1255 fMapG.Add(pv);
1256 }
1257
1258 TMarker *mk=new TMarker(0, 0, kMultiply);
1259 mk->SetMarkerColor(white||yellow?kWhite:kBlack);
1260 mk->SetMarkerSize(1.5);
1261 fMapG.Add(mk);
1262}
1263
1264// --------------------------------------------------------------------------
1265//
1266// Do nothing if 'same' option given.
1267// Otherwise set pad-range such that x- and y- coordinates have the same
1268// step-size
1269//
1270void MAstroCatalog::SetRangePad(Option_t *o)
1271{
1272 if (TString(o).Contains("same", TString::kIgnoreCase))
1273 return;
1274
1275 const Double_t edge = fRadiusFOV/TMath::Sqrt(2.);
1276 //gPad->Range(-edge, -edge, edge, edge);
1277
1278 const Float_t w = gPad->GetWw();
1279 const Float_t h = gPad->GetWh();
1280
1281 if (w<h)
1282 gPad->Range(-edge, -edge*h/w, edge, edge*h/w);
1283 else
1284 gPad->Range(-edge*w/h, -edge, edge*w/h, edge);
1285}
1286
1287// --------------------------------------------------------------------------
1288//
1289// Bends some pointers into the right direction...
1290// Calls TAttLine::SetLineAttributes and connects some signals
1291// to the gui to recreate the gui elements if something has changed.
1292//
1293void MAstroCatalog::SetLineAttributes(MAttLine &att)
1294{
1295 if (!gPad)
1296 return;
1297
1298 gPad->SetSelected(&att);
1299 gROOT->SetSelectedPrimitive(&att);
1300
1301 att.SetLineAttributes();
1302
1303 TQObject::Connect("TGColorSelect", "ColorSelected(Pixel_t)", "MAstroCatalog", this, "ForceUpdate()");
1304 TQObject::Connect("TGListBox", "Selected(Int_t)", "MAstroCatalog", this, "ForceUpdate()");
1305}
1306
1307// --------------------------------------------------------------------------
1308//
1309// Calls TAttMarker::SetMarkerAttributes and connects some signals
1310// to the gui to recreate the gui elements if something has changed.
1311//
1312void MAstroCatalog::SetMarkerAttributes()
1313{
1314 if (!gPad)
1315 return;
1316
1317 TAttMarker::SetMarkerAttributes();
1318
1319 // Make sure that if something is changed the gui elements
1320 // are recreated
1321 TQObject::Connect("TGedMarkerSelect", "MarkerSelected(Style_t)", "MAstroCatalog", this, "ForceUpdate()");
1322 TQObject::Connect("TGColorSelect", "ColorSelected(Pixel_t)", "MAstroCatalog", this, "ForceUpdate()");
1323 TQObject::Connect("TGListBox", "Selected(Int_t)", "MAstroCatalog", this, "ForceUpdate()");
1324}
1325
1326void MAstroCatalog::DrawPrimitives(Option_t *o)
1327{
1328 fMapG.Delete();
1329
1330 if (!TestBit(kDrawingImage) && gPad)
1331 SetRangePad(o);
1332
1333#ifdef DEBUG
1334 TStopwatch clk;
1335 clk.Start();
1336#endif
1337 AddPrimitives(o);
1338#ifdef DEBUG
1339 clk.Stop();
1340 clk.Print();
1341#endif
1342
1343 // Append to a possible second pad
1344 if (!TestBit(kDrawingImage) && gPad && !gPad->GetListOfPrimitives()->FindObject(this))
1345 AppendPad(o);
1346
1347 ResetBit(kHasChanged);
1348}
1349
1350// --------------------------------------------------------------------------
1351//
1352// Append "this" to current pad
1353// set bit kHasChanged to recreate all gui elements
1354// Connect signal
1355//
1356void MAstroCatalog::Draw(Option_t *o)
1357{
1358 // Append to first pad
1359 AppendPad(o);
1360
1361 // If contents have not previously changed make sure that
1362 // all primitives are recreated.
1363 SetBit(kHasChanged);
1364
1365 // Connect all TCanvas::ProcessedEvent to this->EventInfo
1366 // This means, that after TCanvas has processed an event
1367 // EventInfo of this class is called, see TCanvas::HandleInput
1368 gPad->GetCanvas()->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
1369 "MAstroCatalog", this,
1370 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
1371}
1372
1373// --------------------------------------------------------------------------
1374//
1375// This function was connected to all created canvases. It is used
1376// to redirect GetObjectInfo into our own status bar.
1377//
1378// The 'connection' is done in Draw. It seems that 'connected'
1379// functions must be public.
1380//
1381void MAstroCatalog::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
1382{
1383 TCanvas *c = (TCanvas*)gTQSender;
1384
1385 gPad = c ? c->GetSelectedPad() : NULL;
1386 if (!gPad)
1387 return;
1388
1389
1390 // Try to find a corresponding object with kCannotPick set and
1391 // an available TString (for a tool tip)
1392 TString str;
1393 if (!selected || selected==this)
1394 selected = fMapG.PickObject(px, py, str);
1395
1396 if (!selected)
1397 return;
1398
1399 // Handle some gui events
1400 switch (event)
1401 {
1402 case kMouseMotion:
1403 if (fToolTip && !fToolTip->IsMapped() && !str.IsNull())
1404 ShowToolTip(px, py, str);
1405 break;
1406
1407 case kMouseLeave:
1408 if (fToolTip && fToolTip->IsMapped())
1409 fToolTip->Hide();
1410 break;
1411
1412 case kKeyPress:
1413 ExecuteEvent(kKeyPress, px, py);
1414 break;
1415 }
1416}
1417
1418// --------------------------------------------------------------------------
1419//
1420// Handle keyboard events.
1421//
1422void MAstroCatalog::ExecuteEventKbd(Int_t keycode, Int_t keysym)
1423{
1424 Double_t dra =0;
1425 Double_t ddec=0;
1426
1427 switch (keysym)
1428 {
1429 case kKey_Left:
1430 dra = -TMath::DegToRad();
1431 break;
1432 case kKey_Right:
1433 dra = +TMath::DegToRad();
1434 break;
1435 case kKey_Up:
1436 ddec = +TMath::DegToRad();
1437 break;
1438 case kKey_Down:
1439 ddec = -TMath::DegToRad();
1440 break;
1441 case kKey_Plus:
1442 SetRadiusFOV(fRadiusFOV+1);
1443 break;
1444 case kKey_Minus:
1445 SetRadiusFOV(fRadiusFOV-1);
1446 break;
1447
1448 default:
1449 return;
1450 }
1451
1452 const Double_t r = fRaDec.Phi();
1453 const Double_t d = TMath::Pi()/2-fRaDec.Theta();
1454
1455 SetRaDec(r+dra, d+ddec);
1456
1457 gPad->Update();
1458}
1459
1460// ------------------------------------------------------------------------
1461//
1462// Execute a gui event on the camera
1463//
1464void MAstroCatalog::ExecuteEvent(Int_t event, Int_t mp1, Int_t mp2)
1465{
1466 if (!TestBit(kGuiActive))
1467 return;
1468
1469 if (event==kKeyPress)
1470 ExecuteEventKbd(mp1, mp2);
1471}
1472
1473// --------------------------------------------------------------------------
1474//
1475// Displays a tooltip
1476//
1477void MAstroCatalog::ShowToolTip(Int_t px, Int_t py, const char *txt)
1478{
1479 if (TestBit(kNoToolTips))
1480 return;
1481
1482 Int_t x=0;
1483 Int_t y=0;
1484
1485 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
1486 const Window_t id2 = fToolTip->GetParent()->GetId();
1487
1488 Window_t id3;
1489 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
1490
1491 // Show tool tip
1492 fToolTip->SetText(txt);
1493 fToolTip->Show(x+4, y+4);
1494}
1495
1496// --------------------------------------------------------------------------
1497//
1498// Calculate distance to primitive by checking all gui elements
1499//
1500Int_t MAstroCatalog::DistancetoPrimitive(Int_t px, Int_t py)
1501{
1502 return fMapG.DistancetoPrimitive(px, py);
1503}
1504
1505// ------------------------------------------------------------------------
1506//
1507// Returns string containing info about the object at position (px,py).
1508// Returned string will be re-used (lock in MT environment).
1509//
1510char *MAstroCatalog::GetObjectInfo(Int_t px, Int_t py) const
1511{
1512 return fMapG.GetObjectInfo(px, py);
1513}
Note: See TracBrowser for help on using the repository browser.