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

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