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

Last change on this file since 3797 was 3710, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 33.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
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-2004
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// Usage:
35// ------
36//
37// To display a starfield you must have a supported catalog, then do:
38//
39// MTime time;
40// // Time for which to get the picture
41// time.Set(2004, 2, 28, 20, 14, 7);
42// // Current observatory
43// MObservatory magic1;
44// // Right Ascension [h] and declination [deg] of source
45// // Currently 'perfect' pointing is assumed
46// const Double_t ra = MAstro::Hms2Rad(5, 34, 31.9);
47// const Double_t dec = MAstro::Dms2Rad(22, 0, 52.0);
48// MAstroCatalog stars;
49// // Magnitude up to which the stars are loaded from the catalog
50// stars.SetLimMag(6);
51// // Radius of FOV around the source position to load the stars
52// stars.SetRadiusFOV(3);
53// // Source position
54// stars.SetRaDec(ra, dec);
55// // Catalog to load (here: Bright Star Catalog V5)
56// stars.ReadBSC("bsc5.dat");
57// // Obersavatory and time to also get local coordinate information
58// stars.SetObservatory(magic1);
59// stars.SetTime(time);
60// // Enable interactive GUI
61// stars.SetGuiActive();
62// //Clone the catalog due to the validity range of the instance
63// TObject *o = stars.Clone();
64// o->SetBit(kCanDelete);
65// o->Draw();
66//
67// If no time and/or Obervatory location is given no local coordinate
68// information is displayed.
69//
70//
71// Coordinate Transformation:
72// -------------------------
73// The conversion from sky coordinates to local coordinates is done using
74// MAstroSky2Local which does a simple rotation of the coordinate system.
75// This is inaccurate in the order of 30arcsec due to ignorance of all
76// astrometrical corrections (nutation, precission, abberation, ...)
77//
78//
79// GUI:
80// ----
81// * If the gui is interactive you can use the cursor keys to change
82// the position you are looking at and with plus/minus you
83// can (un)zoom the FOV (Field Of View)
84// * The displayed values mean the following:
85// + alpha: Right Ascension
86// + delta: Declination
87// + theta: zenith distance / zenith angle
88// + phi: azimuth angle
89// + rho: angle of rotation sky-coordinate system vs local-
90// coordinate system
91// + time of display
92// * Move the mouse on top of the grid points or the stars to get
93// more setailed information.
94// * Enable the event-info in a canvas to see the current
95// ObjectInfo=tooltip-text
96// * call SetNoToolTips to supress the tooltips
97// * the blue lines are the local coordinat system
98// * the red lines are sky coordinate system
99//
100//
101// ToDo:
102// -----
103// - replace MVetcor3 by a more convinient class. Maybe use TExMap, too.
104// - change tooltips to multi-line tools tips as soon as root
105// supports them
106// - a derived class is missing which supports all astrometrical
107// correction (base on slalib and useable in Cosy)
108//
109//////////////////////////////////////////////////////////////////////////////
110#include "MAstroCatalog.h"
111
112#include <errno.h> // strerror
113#include <fstream> // ifstream
114#include <stdlib.h> // ati, atof
115#include <limits.h> // INT_MAX (Suse 7.3/gcc 2.95)
116
117#include <KeySymbols.h> // kKey_*
118
119#include <TLine.h> // TLine
120#include <TMarker.h> // TMarker
121#include <TCanvas.h> // TCanvas
122#include <TArrayI.h> // TArrayI
123#include <TGToolTip.h> // TGToolTip
124#include <TPaveText.h> // TPaveText
125
126#include "MLog.h"
127#include "MLogManip.h"
128
129#include "MTime.h"
130#include "MAstro.h"
131#include "MAstroSky2Local.h"
132#include "MObservatory.h"
133
134#undef DEBUG
135//#define DEBUG
136
137#ifdef DEBUG
138#include <TStopwatch.h>
139#endif
140
141ClassImp(MVector3);
142ClassImp(MAstroCatalog);
143
144using namespace std;
145
146// --------------------------------------------------------------------------
147//
148// Default Constructor. Set Default values:
149// fLimMag = 99
150// fRadiusFOV = 90
151//
152MAstroCatalog::MAstroCatalog() : fLimMag(99), fRadiusFOV(90), fToolTip(0), fObservatory(0), fTime(0)
153{
154 fList.SetOwner();
155 fToolTip = new TGToolTip(0, "", 0);
156}
157
158// --------------------------------------------------------------------------
159//
160// Destructor. Delete fTime, fObservatory. Disconnect signal. delete tooltip.
161// Delete Map with gui primitives
162//
163MAstroCatalog::~MAstroCatalog()
164{
165 // First disconnect the EventInfo...
166 // FIXME: There must be an easier way!
167 TIter Next(gROOT->GetListOfCanvases());
168 TCanvas *c;
169 while ((c=(TCanvas*)Next()))
170 c->Disconnect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", this,
171 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
172
173 // Now delete the data members
174 if (fTime)
175 delete fTime;
176 if (fObservatory)
177 delete fObservatory;
178
179 fToolTip->Hide();
180 delete fToolTip;
181
182 DeleteMap();
183}
184
185// --------------------------------------------------------------------------
186//
187// Snippet to for reading ctalog files.
188//
189TString MAstroCatalog::FindToken(TString &line, Char_t tok)
190{
191 Ssiz_t token = line.First(tok);
192 if (token<0)
193 {
194 const TString copy(line);
195 line = "";
196 return copy;
197 }
198
199 const TString res = line(0, token);
200 line.Remove(0, token+1);
201 return res;
202}
203
204// --------------------------------------------------------------------------
205//
206// return int correspoding to TSubString
207//
208Int_t MAstroCatalog::atoi(const TSubString &sub)
209{
210 return atoi(TString(sub));
211}
212
213// --------------------------------------------------------------------------
214//
215// return float correspoding to TSubString
216//
217Float_t MAstroCatalog::atof(const TSubString &sub)
218{
219 return atof(TString(sub));
220}
221
222// --------------------------------------------------------------------------
223//
224// return int correspoding to TString
225//
226Int_t MAstroCatalog::atoi(const TString &s)
227{
228 return std::atoi(s);
229}
230
231// --------------------------------------------------------------------------
232//
233// return float correspoding to TString
234//
235Float_t MAstroCatalog::atof(const TString &s)
236{
237 return std::atof(s);
238}
239
240// --------------------------------------------------------------------------
241//
242// Read from a xephem catalog, set bit kHasChahanged.
243// Already read data is not deleted. To delete the stored data call
244// Delete().
245//
246Int_t MAstroCatalog::ReadXephem(TString catalog)
247{
248 SetBit(kHasChanged);
249
250 gLog << inf << "Reading Xephem catalog: " << catalog << endl;
251
252 ifstream fin(catalog);
253 if (!fin)
254 {
255 gLog << err << "Cannot open file " << catalog << ": ";
256 gLog << strerror(errno) << endl;
257 return 0;
258 }
259
260 Int_t add =0;
261 Int_t cnt =0;
262 Int_t line=0;
263
264 Double_t maxmag=0;
265
266 while (1)
267 {
268 TString row;
269 row.ReadLine(fin);
270 if (!fin)
271 break;
272
273 line++;
274
275 if (row[0]=='#')
276 continue;
277
278 TString line(row);
279
280 TString name = FindToken(line);
281 TString dummy = FindToken(line);
282 TString r = FindToken(line);
283 TString d = FindToken(line);
284 TString m = FindToken(line);
285 TString epoch = FindToken(line);
286
287 if (name.IsNull() || r.IsNull() || d.IsNull() || m.IsNull() || epoch.IsNull())
288 {
289 gLog << warn << "Invalid Entry Line #" << line << ": " << row << endl;
290 continue;
291 }
292
293 cnt++;
294
295 const Double_t mag = atof(m);
296
297 maxmag = TMath::Max(maxmag, mag);
298
299 if (mag>fLimMag)
300 continue;
301
302 if (epoch!="2000")
303 {
304 gLog << warn << "Epoch != 2000... skipped." << endl;
305 continue;
306 }
307
308 Double_t ra0, dec0;
309 MAstro::Coordinate2Angle(r, ra0);
310 MAstro::Coordinate2Angle(d, dec0);
311
312 ra0 *= TMath::Pi()/12;
313 dec0 *= TMath::Pi()/180;
314
315 MVector3 *star=new MVector3;
316 star->SetRaDec(ra0, dec0, mag);
317 star->SetName(name);
318 if (star->Angle(fRaDec)*TMath::RadToDeg()>fRadiusFOV)
319 {
320 delete star;
321 continue;
322 }
323
324 fList.Add(star);
325 add++;
326 }
327 gLog << inf << "Read " << add << " out of " << cnt << " (Total max mag=" << maxmag << ")" << endl;
328
329 return add;
330}
331
332// --------------------------------------------------------------------------
333//
334// Read from a NGC2000 catalog. set bit kHasChanged
335// Already read data is not deleted. To delete the stored data call
336// Delete().
337//
338Int_t MAstroCatalog::ReadNGC2000(TString catalog)
339{
340 SetBit(kHasChanged);
341
342 gLog << inf << "Reading NGC2000 catalog: " << catalog << endl;
343
344 ifstream fin(catalog);
345 if (!fin)
346 {
347 gLog << err << "Cannot open file " << catalog << ": ";
348 gLog << strerror(errno) << endl;
349 return 0;
350 }
351
352 Int_t add=0;
353 Int_t cnt=0;
354 Int_t n =0;
355
356 Double_t maxmag=0;
357
358 while (1)
359 {
360 TString row;
361 row.ReadLine(fin);
362 if (!fin)
363 break;
364
365 cnt++;
366
367 const Int_t rah = atoi(row(13, 2));
368 const Float_t ram = atof(row(16, 4));
369 const Char_t decs = row(22);
370 const Int_t decd = atoi(row(23, 2));
371 const Int_t decm = atoi(row(26, 2));
372 const TString m = row(43, 4);
373
374 if (m.Strip().IsNull())
375 continue;
376
377 n++;
378
379 const Double_t mag = atof(m);
380
381 maxmag = TMath::Max(maxmag, mag);
382
383 if (mag>fLimMag)
384 continue;
385
386 const Double_t ra = MAstro::Hms2Rad(rah, (int)ram, fmod(ram, 1)*60);
387 const Double_t dec = MAstro::Dms2Rad(decd, decm, 0, decs);
388
389 MVector3 *star=new MVector3;
390 star->SetRaDec(ra, dec, mag);
391 star->SetName(row(0, 8));
392 if (star->Angle(fRaDec)*TMath::RadToDeg()>fRadiusFOV)
393 {
394 delete star;
395 continue;
396 }
397
398 fList.Add(star);
399 add++;
400 }
401
402 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
403
404 return add;
405}
406
407// --------------------------------------------------------------------------
408//
409// Read from a Bright Star Catalog catalog. set bit kHasChanged
410// Already read data is not deleted. To delete the stored data call
411// Delete().
412//
413Int_t MAstroCatalog::ReadBSC(TString catalog)
414{
415 SetBit(kHasChanged);
416
417 gLog << inf << "Reading Bright Star Catalog (BSC5) catalog: " << catalog << endl;
418
419 ifstream fin(catalog);
420 if (!fin)
421 {
422 gLog << err << "Cannot open file " << catalog << ": ";
423 gLog << strerror(errno) << endl;
424 return 0;
425 }
426
427 Int_t add=0;
428 Int_t cnt=0;
429 Int_t n =0;
430
431 Double_t maxmag=0;
432
433 while (1)
434 {
435 TString row;
436 row.ReadLine(fin);
437 if (!fin)
438 break;
439
440 cnt++;
441
442 const Int_t rah = atoi(row(75, 2));
443 const Int_t ram = atoi(row(77, 2));
444 const Float_t ras = atof(row(79, 4));
445 const Char_t decsgn = row(83);
446 const Int_t decd = atoi(row(84, 2));
447 const Int_t decm = atoi(row(86, 2));
448 const Int_t decs = atoi(row(88, 2));
449 const TString m = row(102, 5);
450
451 if (m.Strip().IsNull())
452 continue;
453
454 n++;
455
456 const Double_t mag = atof(m.Data());
457
458 maxmag = TMath::Max(maxmag, mag);
459
460 if (mag>fLimMag)
461 continue;
462
463 const Double_t ra = MAstro::Hms2Rad(rah, ram, ras);
464 const Double_t dec = MAstro::Dms2Rad(decd, decm, decs, decsgn);
465
466 MVector3 *star=new MVector3;
467 star->SetRaDec(ra, dec, mag);
468 star->SetName(row(4,9));
469 if (star->Angle(fRaDec)*TMath::RadToDeg()>fRadiusFOV)
470 {
471 delete star;
472 continue;
473 }
474
475 fList.Add(star);
476 add++;
477 }
478
479 gLog << inf << "Read " << add << " out of " << n << " (Total max mag=" << maxmag << ")" << endl;
480
481 return add;
482}
483
484// --------------------------------------------------------------------------
485//
486// Set Range of pad. If something has changed create and draw new primitives.
487// Paint all gui primitives.
488//
489void MAstroCatalog::Paint(Option_t *o)
490{
491 SetRangePad(o);
492
493 if (TestBit(kHasChanged))
494 DrawPrimitives(o);
495
496 PaintMap();
497}
498
499// --------------------------------------------------------------------------
500//
501// Draw a black marker at the position of the star. Create a corresponding
502// tooltip with the coordinates.
503// x, y: Pad Coordinates to draw star
504// v: Sky position (Ra/Dec) of the star
505// transparent: Draw marker or tooltip only
506// txt: additional tooltip text
507//
508void MAstroCatalog::DrawStar(Double_t x, Double_t y, const TVector3 &v, Bool_t transparent, const char *txt)
509{
510 const Double_t ra = v.Phi()*TMath::RadToDeg()/15;
511 const Double_t dec = (TMath::Pi()/2-v.Theta())*TMath::RadToDeg();
512
513 TString str = v.GetName();
514 str += Form(": Ra=%.2fh", ra);
515 str += Form(" Dec=%.1fd", dec);
516 str += Form(" Mag=%.1f", -2.5*log10(v.Mag()));
517 if (txt)
518 str += Form(" (%s)", txt);
519
520 // draw star on the camera display
521 TMarker *tip=new TMarker(x, y, transparent ? kDot : kFullDotMedium);;
522 tip->SetMarkerColor(kBlack);
523 AddMap(tip, new TString(str));
524}
525
526// --------------------------------------------------------------------------
527//
528// Set pad as modified.
529//
530void MAstroCatalog::Update(Bool_t upd)
531{
532 if (gPad && TestBit(kMustCleanup))
533 {
534 SetBit(kHasChanged);
535 gPad->Modified();
536 if (upd)
537 gPad->Update();
538 }
539}
540
541// --------------------------------------------------------------------------
542//
543// Set the observation time. Necessary to use local coordinate
544// system. The MTime object is cloned.
545//
546void MAstroCatalog::SetTime(const MTime &time)
547{
548 if (fTime)
549 delete fTime;
550 fTime=(MTime*)time.Clone();
551}
552
553// --------------------------------------------------------------------------
554//
555// Set the observatory location. Necessary to use local coordinate
556// system. The MObservatory object is cloned.
557//
558void MAstroCatalog::SetObservatory(const MObservatory &obs)
559{
560 if (fObservatory)
561 delete fObservatory;
562 fObservatory=(MObservatory*)obs.Clone();
563}
564
565// --------------------------------------------------------------------------
566//
567// Convert the vector to pad coordinates. After conversion
568// the x- coordinate of the vector must be the x coordinate
569// of the pad - the same for y. If the coordinate is inside
570// the current draw area return kTRUE, otherwise kFALSE.
571// If it is an invalid coordinate return kERROR
572//
573Int_t MAstroCatalog::ConvertToPad(const TVector3 &w0, TVector2 &v) const
574{
575 TVector3 w(w0);
576
577 // Stretch such, that the Z-component is alwas the same. Now
578 // X and Y contains the intersection point between the star-light
579 // and the plain of a virtual plain screen (ccd...)
580 if (TestBit(kPlainScreen))
581 w *= 1./w(2);
582
583 w *= TMath::RadToDeg(); // FIXME: *conversion factor?
584 v.Set(TestBit(kMirrorX) ? -w(0) : w(0),
585 TestBit(kMirrorY) ? -w(1) : w(1));
586
587 if (w(2)<0)
588 return kERROR;
589
590 return v.X()>gPad->GetX1() && v.Y()>gPad->GetY1() &&
591 v.X()<gPad->GetX2() && v.Y()<gPad->GetY2();
592}
593
594// --------------------------------------------------------------------------
595//
596// Convert theta/phi coordinates of v by TRotation into new coordinate
597// system and convert the coordinated to pad by ConvertToPad.
598// The result is retunred in v.
599//
600Int_t MAstroCatalog::Convert(const TRotation &rot, TVector2 &v) const
601{
602 MVector3 w;
603 w.SetMagThetaPhi(1, v.Y(), v.X());
604 w *= rot;
605
606 return ConvertToPad(w, v);
607}
608
609// --------------------------------------------------------------------------
610//
611// Draw a line from v to v+(dx,dy) using Convert/ConvertToPad to get the
612// corresponding pad coordinates.
613//
614Bool_t MAstroCatalog::DrawLine(const TVector2 &v, Double_t dx, Double_t dy, const TRotation &rot, Int_t type)
615{
616 const TVector2 add(dx*TMath::DegToRad(), dy*TMath::DegToRad());
617
618 TVector2 v0 = v;
619 TVector2 v1 = v+add;
620
621 const Int_t rc0 = Convert(rot, v0);
622 const Int_t rc1 = Convert(rot, v1);
623
624 // Both are kFALSE or both are kERROR
625 if ((rc0|rc1)==kFALSE || (rc0&rc1)==kERROR)
626 return kFALSE;
627
628 TLine *line = new TLine(v0.X(), v0.Y(), v1.X(), v1.Y());
629 line->SetLineStyle(kDashDotted); //kDashed, kDotted, kDashDotted
630 line->SetLineColor(kWhite+type*2);
631 AddMap(line);
632
633 const TVector2 deg = v*TMath::RadToDeg();
634 TString txt = type==1 ?
635 Form("Ra=%.2fh Dec=%.1fd", fmod(deg.X()/15+48, 24), fmod(90-deg.Y()+270,180)-90) :
636 Form("Zd=%.1fd Az=%.1fd", fmod(deg.Y()+270,180)-90, fmod(deg.X()+720, 360));
637
638 TMarker *tip=new TMarker(v0.X(), v0.Y(), kDot);
639 tip->SetMarkerColor(kWhite+type*2);
640 AddMap(tip, new TString(txt));
641
642 return kTRUE;
643}
644
645// --------------------------------------------------------------------------
646//
647// Use "local" draw option to align the display to the local
648// coordinate system instead of the sky coordinate system.
649// dx, dy are arrays storing recuresively all touched points
650// stepx, stepy are the step-size of the current grid.
651//
652void MAstroCatalog::Draw(const TVector2 &v0, const TRotation &rot, TArrayI &dx, TArrayI &dy, Int_t stepx, Int_t stepy, Int_t type)
653{
654 // Calculate the end point
655 const TVector2 v1 = v0 + TVector2(dx[0]*TMath::DegToRad(), dy[0]*TMath::DegToRad());
656
657 // Check whether the point has already been touched.
658 Int_t idx[] = {1, 1, 1, 1};
659
660 Int_t dirs[4][2] = { {0, stepy}, {stepx, 0}, {0, -stepy}, {-stepx, 0} };
661
662 // Check for ambiguities.
663 for (int i=0; i<dx.GetSize(); i++)
664 {
665 for (int j=0; j<4; j++)
666 {
667 const Bool_t rcx0 = (dx[i]+720)%360==(dx[0]+dirs[j][0]+720)%360;
668 const Bool_t rcy0 = (dy[i]+360)%180==(dy[0]+dirs[j][1]+360)%180;
669 if (rcx0&&rcy0)
670 idx[j] = 0;
671 }
672 }
673
674 // Enhance size of array by 1, copy current
675 // position as last entry
676 dx.Set(dx.GetSize()+1);
677 dy.Set(dy.GetSize()+1);
678
679 dx[dx.GetSize()-1] = dx[0];
680 dy[dy.GetSize()-1] = dy[0];
681
682 // Store current positon
683 const Int_t d[2] = { dx[0], dy[0] };
684
685 for (int i=0; i<4; i++)
686 if (idx[i])
687 {
688 // Calculate new position
689 dx[0] = d[0]+dirs[i][0];
690 dy[0] = d[1]+dirs[i][1];
691
692 // Draw corresponding line and iterate through grid
693 if (DrawLine(v1, dirs[i][0], dirs[i][1], rot, type))
694 Draw(v0, rot, dx, dy, stepx, stepy, type);
695
696 dx[0]=d[0];
697 dy[0]=d[1];
698 }
699}
700
701// --------------------------------------------------------------------------
702//
703// Draw a grid recursively around the point v0 (either Ra/Dec or Zd/Az)
704// The points in the grid are converted by a TRotation and CovertToPad
705// to pad coordinates. The type arguemnts is neccessary to create the
706// correct tooltip (Ra/Dec, Zd/Az) at the grid-points.
707// From the pointing position the step-size of teh gris is caluclated.
708//
709void MAstroCatalog::DrawGrid(const TVector3 &v0, const TRotation &rot, Int_t type)
710{
711 TArrayI dx(1);
712 TArrayI dy(1);
713
714 // align to 1deg boundary
715 TVector2 v(v0.Phi()*TMath::RadToDeg(), v0.Theta()*TMath::RadToDeg());
716 v.Set((Float_t)TMath::Nint(v.X()), (Float_t)TMath::Nint(v.Y()));
717
718 // calculate stepsizes based on visible FOV
719 Int_t stepx = 1;
720
721 if (v.Y()<fRadiusFOV || v.Y()>180-fRadiusFOV)
722 stepx=36;
723 else
724 {
725 // This is a rough estimate how many degrees are visible
726 const Float_t m = log(fRadiusFOV/180.)/log(90./(fRadiusFOV+1)+1);
727 const Float_t t = log(180.)-m*log(fRadiusFOV);
728 const Float_t f = m*log(90-fabs(90-v.Y()))+t;
729 const Int_t nx = (Int_t)(exp(f)+0.5);
730 stepx = nx<4 ? 1 : nx/4;
731 if (stepx>36)
732 stepx=36;
733 }
734
735 const Int_t ny = (Int_t)(fRadiusFOV+1);
736 Int_t stepy = ny<4 ? 1 : ny/4;
737
738 // align stepsizes to be devisor or 180 and 90
739 while (180%stepx)
740 stepx++;
741 while (90%stepy)
742 stepy++;
743
744 // align to step-size boundary (search for the nearest one)
745 Int_t dv = 1;
746 while ((int)(v.X())%stepx)
747 {
748 v.Set(v.X()+dv, v.Y());
749 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
750 }
751
752 dv = 1;
753 while ((int)(v.Y())%stepy)
754 {
755 v.Set(v.X(), v.Y()+dv);
756 dv = -TMath::Sign(TMath::Abs(dv)+1, dv);
757 }
758
759 // draw...
760 v *= TMath::DegToRad();
761
762 Draw(v, rot, dx, dy, stepx, stepy, type);
763}
764
765// --------------------------------------------------------------------------
766//
767// Get a rotation matrix which aligns the pointing position
768// to the center of the x,y plain
769//
770TRotation MAstroCatalog::AlignCoordinates(const TVector3 &v) const
771{
772 TRotation trans;
773 trans.RotateZ(-v.Phi());
774 trans.RotateY(-v.Theta());
775 trans.RotateZ(-TMath::Pi()/2);
776 return trans;
777}
778
779// --------------------------------------------------------------------------
780//
781// Return the rotation matrix which converts either sky or
782// local coordinates to coordinates which pole is the current
783// pointing direction.
784//
785TRotation MAstroCatalog::GetGrid(Bool_t local)
786{
787 const Bool_t enable = fTime && fObservatory;
788
789 // If sky coordinate view is requested get rotation matrix and
790 // draw corresponding sky-grid and if possible local grid
791 if (!local)
792 {
793 const TRotation trans(AlignCoordinates(fRaDec));
794
795 DrawGrid(fRaDec, trans, 1);
796
797 if (enable)
798 {
799 const MAstroSky2Local rot(*fTime, *fObservatory);
800 DrawGrid(rot*fRaDec, trans*rot.Inverse(), 2);
801 }
802
803 // Return the correct rotation matrix
804 return trans;
805 }
806
807 // If local coordinate view is requested get rotation matrix and
808 // draw corresponding sky-grid and if possible local grid
809 if (local && enable)
810 {
811 const MAstroSky2Local rot(*fTime, *fObservatory);
812
813 const TRotation trans(AlignCoordinates(rot*fRaDec));
814
815 DrawGrid(fRaDec, trans*rot, 1);
816 DrawGrid(rot*fRaDec, trans, 2);
817
818 // Return the correct rotation matrix
819 return trans*rot;
820 }
821
822 return TRotation();
823}
824
825// --------------------------------------------------------------------------
826//
827// Create the title for the pad.
828//
829TString MAstroCatalog::GetPadTitle() const
830{
831 const Double_t ra = fRaDec.Phi()*TMath::RadToDeg();
832 const Double_t dec = (TMath::Pi()/2-fRaDec.Theta())*TMath::RadToDeg();
833
834 TString txt;
835 txt += Form("\\alpha=%.2fh ", fmod(ra/15+48, 24));
836 txt += Form("\\delta=%.1f\\circ ", fmod(dec+270,180)-90);
837 txt += Form("/ FOV=%.1f\\circ", fRadiusFOV);
838
839 if (!fTime || !fObservatory)
840 return txt;
841
842 const MAstroSky2Local rot(*fTime, *fObservatory);
843 const TVector3 loc = rot*fRaDec;
844
845 const Double_t rho = rot.RotationAngle(fRaDec.Phi(), TMath::Pi()/2-fRaDec.Theta());
846
847 const Double_t zd = TMath::RadToDeg()*loc.Theta();
848 const Double_t az = TMath::RadToDeg()*loc.Phi();
849
850 txt.Prepend("#splitline{");
851 txt += Form(" \\theta=%.1f\\circ ", fmod(zd+270,180)-90);
852 txt += Form("\\phi=%.1f\\circ ", fmod(az+720, 360));
853 txt += Form(" / \\rho=%.1f\\circ", rho*TMath::RadToDeg());
854 txt += "}{<";
855 txt += fTime->GetSqlDateTime();
856 txt += ">}";
857 return txt;
858}
859
860// --------------------------------------------------------------------------
861//
862// To overlay the catalog make sure, that in any case you are using
863// the 'same' option.
864//
865// If you want to overlay this on top of any picture which is created
866// by derotation of the camera plain you have to use the 'mirror' option
867// the compensate the mirroring of the image in the camera plain.
868//
869// If you have already compensated this by x=-x and y=-y when creating
870// the histogram you can simply overlay the catalog.
871//
872// To overlay the catalog on a 2D histogram the histogram must have
873// units of degrees (which are plain, like you directly convert the
874// camera units by multiplication to degrees)
875//
876// To be 100% exact you must use the option 'plain' which assumes a plain
877// screen. This is not necessary for the MAGIC-camera because the
878// difference between both is less than 1e-3.
879//
880// You should always be aware of the fact, that the shown stars and the
881// displayed grid is the ideal case, like a reflection on a virtual
882// perfectly aligned central mirror. In reality the star-positions are
883// smeared to the edge of the camera the more the distance to the center
884// is, such that the center of gravity of the light distribution might
885// be more far away from the center than the display shows.
886//
887//
888void MAstroCatalog::AddPrimitives(TString o)
889{
890 const Bool_t same = o.Contains("same", TString::kIgnoreCase);
891 const Bool_t local = o.Contains("local", TString::kIgnoreCase);
892 const Bool_t mirx = o.Contains("mirrorx", TString::kIgnoreCase);
893 const Bool_t miry = o.Contains("mirrory", TString::kIgnoreCase);
894 const Bool_t mirror = o.Contains("mirror", TString::kIgnoreCase) && !mirx && !miry;
895
896 // X is vice versa, because ra is defined anti-clockwise
897 mirx || mirror ? ResetBit(kMirrorX) : SetBit(kMirrorX);
898 miry || mirror ? SetBit(kMirrorY) : ResetBit(kMirrorY);
899
900 const TRotation rot(GetGrid(local));
901
902 TIter Next(&fList);
903 TVector3 *v=0;
904 while ((v=(TVector3*)Next()))
905 {
906 // FIXME: Check Magnitude!
907 TVector2 s(v->Phi(), v->Theta());
908 if (Convert(rot, s)==kTRUE)
909 DrawStar(s.X(), s.Y(), *v, kFALSE);
910 }
911
912 if (!same)
913 {
914 TPaveText *pv = new TPaveText(0.01, 0.90, 0.63, 0.99, "brNDC");
915 pv->AddText(GetPadTitle());
916 AddMap(pv);
917 }
918
919 TMarker *mk=new TMarker(0, 0, kMultiply);
920 mk->SetMarkerColor(kBlack);
921 mk->SetMarkerSize(1.5);
922 AddMap(mk);
923}
924
925// --------------------------------------------------------------------------
926//
927// Do nothing if 'same' option given.
928// Otherwise set pad-range such that x- and y- coordinates have the same
929// step-size
930//
931void MAstroCatalog::SetRangePad(Option_t *o)
932{
933 if (TString(o).Contains("same", TString::kIgnoreCase))
934 return;
935
936 const Double_t edge = fRadiusFOV/TMath::Sqrt(2.);
937 gPad->Range(-edge, -edge, edge, edge);
938
939 const Float_t w = gPad->GetWw();
940 const Float_t h = gPad->GetWh();
941
942 if (w<h)
943 gPad->Range(-edge, -edge*h/w, edge, edge*h/w);
944 else
945 gPad->Range(-edge*w/h, -edge, edge*w/h, edge);
946}
947
948// --------------------------------------------------------------------------
949//
950// First delete all gui elements.
951// Set the correct range of the pad.
952// Create all gui primitives
953// If "this" is not in the current pad add it to the current pad.
954// Reset vit kHasChanged
955//
956void MAstroCatalog::DrawPrimitives(Option_t *o)
957{
958 DeleteMap();
959
960 SetRangePad(o);
961
962#ifdef DEBUG
963 TStopwatch clk;
964 clk.Start();
965#endif DEBUG
966 AddPrimitives(o);
967#ifdef DEBUG
968 clk.Stop();
969 clk.Print();
970#endif DEBUG
971
972 // Append to a possible second pad
973 if (!gPad->GetListOfPrimitives()->FindObject(this))
974 AppendPad(o);
975
976 ResetBit(kHasChanged);
977}
978
979// --------------------------------------------------------------------------
980//
981// Call Paint() of all gui elements
982//
983void MAstroCatalog::PaintMap()
984{
985 Long_t key, val;
986 TExMapIter map(&fMapG);
987 while (map.Next(key, val))
988 ((TObject*)key)->Paint();
989}
990
991// --------------------------------------------------------------------------
992//
993// Append "this" to current pad
994// set bit kHasChanged to recreate all gui elements
995// Connect signal
996//
997void MAstroCatalog::Draw(Option_t *o)
998{
999 // Append to first pad
1000 AppendPad(o);
1001
1002 // If contents have not previously changed make sure that
1003 // all primitives are recreated.
1004 SetBit(kHasChanged);
1005
1006 // Connect all TCanvas::ProcessedEvent to this->EventInfo
1007 // This means, that after TCanvas has processed an event
1008 // EventInfo of this class is called, see TCanvas::HandleInput
1009 gPad->GetCanvas()->Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
1010 "MAstroCatalog", this,
1011 "EventInfo(Int_t,Int_t,Int_t,TObject*)");
1012}
1013
1014// --------------------------------------------------------------------------
1015//
1016// Search for an object at px, py in fMapG. Return the pointer to it
1017// if found. Set str accordingly if a tooltip string is found.
1018//
1019TObject *MAstroCatalog::PickObject(Int_t px, Int_t py, TString &str) const
1020{
1021 Long_t key, val;
1022 TExMapIter map(&fMapG);
1023 while (map.Next(key, val))
1024 {
1025 if (!val)
1026 continue;
1027
1028 TObject *o=(TObject*)key;
1029 if (o->DistancetoPrimitive(px, py)>TPad::GetMaxPickDistance())
1030 continue;
1031
1032 str = *(TString*)val;
1033 return o;
1034 }
1035 return NULL;
1036}
1037
1038// --------------------------------------------------------------------------
1039//
1040// This function was connected to all created canvases. It is used
1041// to redirect GetObjectInfo into our own status bar.
1042//
1043// The 'connection' is done in Draw. It seems that 'connected'
1044// functions must be public.
1045//
1046void MAstroCatalog::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
1047{
1048 TCanvas *c = (TCanvas*)gTQSender;
1049
1050 gPad = c ? c->GetSelectedPad() : NULL;
1051 if (!gPad)
1052 return;
1053
1054 // Try to find a corresponding object with kCannotPick set and
1055 // an available TString (for a tool tip)
1056 TString str;
1057 if (!selected || selected==this)
1058 selected = PickObject(px, py, str);
1059
1060 if (!selected)
1061 return;
1062
1063 // Handle some gui events
1064 switch (event)
1065 {
1066 case kMouseMotion:
1067 if (!fToolTip->IsMapped() && !str.IsNull())
1068 ShowToolTip(px, py, str);
1069 break;
1070
1071 case kMouseLeave:
1072 if (fToolTip->IsMapped())
1073 fToolTip->Hide();
1074 break;
1075
1076 case kKeyPress:
1077 ExecuteEvent(kKeyPress, px, py);
1078 break;
1079 }
1080}
1081
1082// --------------------------------------------------------------------------
1083//
1084// Handle keyboard events.
1085//
1086void MAstroCatalog::ExecuteEventKbd(Int_t keycode, Int_t keysym)
1087{
1088 Double_t dra =0;
1089 Double_t ddec=0;
1090
1091 switch (keysym)
1092 {
1093 case kKey_Left:
1094 dra = -TMath::DegToRad();
1095 break;
1096 case kKey_Right:
1097 dra = +TMath::DegToRad();
1098 break;
1099 case kKey_Up:
1100 ddec = +TMath::DegToRad();
1101 break;
1102 case kKey_Down:
1103 ddec = -TMath::DegToRad();
1104 break;
1105 case kKey_Plus:
1106 SetRadiusFOV(fRadiusFOV+1);
1107 break;
1108 case kKey_Minus:
1109 SetRadiusFOV(fRadiusFOV-1);
1110 break;
1111
1112 default:
1113 return;
1114 }
1115
1116 const Double_t r = fRaDec.Phi();
1117 const Double_t d = TMath::Pi()/2-fRaDec.Theta();
1118
1119 SetRaDec(r+dra, d+ddec);
1120
1121 gPad->Update();
1122}
1123
1124// ------------------------------------------------------------------------
1125//
1126// Execute a gui event on the camera
1127//
1128void MAstroCatalog::ExecuteEvent(Int_t event, Int_t mp1, Int_t mp2)
1129{
1130 if (!TestBit(kGuiActive))
1131 return;
1132
1133 if (event==kKeyPress)
1134 ExecuteEventKbd(mp1, mp2);
1135}
1136
1137// --------------------------------------------------------------------------
1138//
1139// Calculate distance to primitive by checking all gui elements
1140//
1141Int_t MAstroCatalog::DistancetoPrimitive(Int_t px, Int_t py)
1142{
1143 Int_t min = INT_MAX;
1144
1145 Long_t key, val;
1146 TExMapIter map(&fMapG);
1147 while (map.Next(key, val))
1148 {
1149 TObject *o=(TObject*)key;
1150
1151 const Int_t d = o->DistancetoPrimitive(px, py);
1152
1153 if (d<TPad::GetMaxPickDistance())
1154 return 0;
1155
1156 if (d<min)
1157 min=d;
1158 }
1159
1160 return min;
1161}
1162
1163// --------------------------------------------------------------------------
1164//
1165// Displays a tooltip
1166//
1167void MAstroCatalog::ShowToolTip(Int_t px, Int_t py, const char *txt)
1168{
1169 if (TestBit(kNoToolTips))
1170 return;
1171
1172 Int_t x=0;
1173 Int_t y=0;
1174
1175 const Window_t id1 = gVirtualX->GetWindowID(gPad->GetCanvasID());
1176 const Window_t id2 = fToolTip->GetParent()->GetId();
1177
1178 Window_t id3;
1179 gVirtualX->TranslateCoordinates(id1, id2, px, py, x, y, id3);
1180
1181 // Show tool tip
1182 fToolTip->SetText(txt);
1183 fToolTip->Show(x+4, y+4);
1184}
1185
1186// ------------------------------------------------------------------------
1187//
1188// Returns string containing info about the object at position (px,py).
1189// Returned string will be re-used (lock in MT environment).
1190//
1191char *MAstroCatalog::GetObjectInfo(Int_t px, Int_t py) const
1192{
1193
1194 TString str;
1195 PickObject(px, py, str);
1196
1197 static char txt[129];
1198 txt[128]=0;
1199
1200 return strncpy(txt, str.Data(), 128);
1201}
1202
1203
1204/*
1205void MAstroCatalog::RecursiveRemove(TObject *obj)
1206{
1207 ULong_t hash;
1208 Long_t key, val;
1209
1210 TExMapIter map(&fMapG);
1211 while (map.Next(hash, key, val))
1212 {
1213 if (key != (Long_t)obj)
1214 continue;
1215
1216 fMapG.Remove(hash, key);
1217 delete (TObject*)(key);
1218 if (val)
1219 delete (TString*)(val);
1220 break;
1221 }
1222}
1223*/
Note: See TracBrowser for help on using the repository browser.