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

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