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

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