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

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