source: trunk/Mars/mastro/MAstroCatalog.cc

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