GammaLib 2.0.0
Loading...
Searching...
No Matches
GSkyRegionCircle.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSkyRegionCircle.cpp - Circular sky region class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2013-2020 by Michael Mayer *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GSkyRegionCircle.hpp
23 * @brief Circular sky region implementation
24 * @author Michael Mayer
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GTools.hpp"
32#include "GSkyRegionCircle.hpp"
34#include "GSkyRegionMap.hpp"
35
36/* __ Method name definitions ____________________________________________ */
37#define G_RADIUS "GSkyRegionCircle::radius(double&)"
38#define G_READ "GSkyRegionCircle::read(std::string&)"
39#define G_CONTAINS "GSkyRegionCircle::contains(GSkyRegion&)"
40#define G_OVERLAPS "GSkyRegionCircle::overlaps(GSkyRegion&)"
41
42/* __ Macros _____________________________________________________________ */
43
44/* __ Coding definitions _________________________________________________ */
45
46/* __ Debug definitions __________________________________________________ */
47
48/* __ Prototype __________________________________________________________ */
49
50
51/*==========================================================================
52 = =
53 = Constructors/destructors =
54 = =
55 ==========================================================================*/
56
57/***********************************************************************//**
58 * @brief Void constructor
59 ***************************************************************************/
61{
62 // Initialise members
64
65 // Return
66 return;
67}
68
69
70/***********************************************************************//**
71 * @brief Direction constructor
72 *
73 * @param[in] centre Centre sky direction.
74 * @param[in] radius Region radius (degrees).
75 ***************************************************************************/
77 const double& radius) : GSkyRegion()
78{
79 // Initialise members
81
82 // Set members
83 this->centre(centre);
84 this->radius(radius);
85
86 // Compute solid angle
88
89 // Return
90 return;
91}
92
93
94/***********************************************************************//**
95 * @brief Direction constructor
96 *
97 * @param[in] ra Right Ascension of region centre (degrees).
98 * @param[in] dec Declination of region centre (degrees).
99 * @param[in] radius Region radius (degrees).
100 ***************************************************************************/
102 const double& dec,
103 const double& radius) : GSkyRegion()
104{
105 // Initialise members
106 init_members();
107
108 // Set members
109 this->centre(ra, dec);
110 this->radius(radius);
111
112 // Compute solid angle
114
115 // Return
116 return;
117}
118
119
120/***********************************************************************//**
121 * @brief String constructor
122 *
123 * @param[in] line DS9 region file line.
124 *
125 * Constructs region from a DS9 region file line.
126 ***************************************************************************/
128{
129 // Initialise members
130 init_members();
131
132 // Read information from DS9 region file line
133 read(line);
134
135 // Return
136 return;
137
138}
139
140
141/***********************************************************************//**
142 * @brief Copy constructor
143 *
144 * @param[in] region Circular sky region.
145 ***************************************************************************/
147 GSkyRegion(region)
148{
149 // Initialise members
150 init_members();
151
152 // Copy members
153 copy_members(region);
154
155 // Return
156 return;
157}
158
159
160/***********************************************************************//**
161 * @brief Destructor
162 ***************************************************************************/
164{
165 // Free members
166 free_members();
167
168 // Return
169 return;
170}
171
172
173/*==========================================================================
174 = =
175 = Operators =
176 = =
177 ==========================================================================*/
178
179/***********************************************************************//**
180 * @brief Assignment operator
181 *
182 * @param[in] region Circular sky region.
183 * @return Circular sky region.
184 ***************************************************************************/
186{
187 // Execute only if object is not identical
188 if (this != &region) {
189
190 // Copy base class members
191 this->GSkyRegion::operator=(region);
192
193 // Free members
194 free_members();
195
196 // Initialise private members for clean destruction
197 init_members();
198
199 // Copy members
200 copy_members(region);
201
202 } // endif: object was not identical
203
204 // Return this object
205 return *this;
206}
207
208
209/*==========================================================================
210 = =
211 = Public methods =
212 = =
213 ==========================================================================*/
214
215/***********************************************************************//**
216 * @brief Clear instance
217 ***************************************************************************/
219{
220 // Free members
221 free_members();
223
224 // Initialise private members
226 init_members();
227
228 // Return
229 return;
230}
231
232
233/***********************************************************************//**
234 * @brief Clone circular sky region
235 *
236 * @return Deep copy to circular sky region.
237 ***************************************************************************/
239{
240 // Clone circular sky region
241 return new GSkyRegionCircle(*this);
242}
243
244
245/***********************************************************************//**
246 * @brief Set radius of circular region
247 *
248 * @param[in] radius Radius (degrees).
249 *
250 * @exception GException::invalid_argument
251 * Radius value is less than 0.
252 *
253 * Sets the radius of the circular sky region. Only non-negative radii are
254 * allowed.
255 ***************************************************************************/
256void GSkyRegionCircle::radius(const double& radius)
257{
258 // Check if radius is valid
259 if (radius < 0.0) {
260 std::string msg =
261 "A negative radius of "+gammalib::str(radius)+" degrees has been "
262 "specified for a circular sky region. Please specify a "
263 "non-negative radius.";
265 }
266
267 // Set radius value
269
270 // Compute the solid angle
272
273 // Return
274 return;
275}
276
277
278/***********************************************************************//**
279 * @brief Read region from DS9 string
280 *
281 * @param[in] line String in DS9 format.
282 *
283 * @exception GException::invalid_value
284 * Invalid value found in DS9 format string.
285 ***************************************************************************/
286void GSkyRegionCircle::read(const std::string& line)
287{
288 // Clear the current instance
289 clear();
290
291 // Split the string into 2 parts seperated by #
292 std::vector<std::string> substrings = gammalib::split(line,"#");
293 std::string region_def = (!substrings.empty()) ? substrings[0] : "";
294 std::string comment = (substrings.size() > 1) ? substrings[1] : "";
295
296 // Finding the circle
297 if (region_def.find("circle") == std::string::npos) {
298 std::string msg =
299 "Unable to find the key word \"circle\" in provided string"
300 " \""+line+"\". The \"circle\" key word is mandatory.";
302 }
303
304 // Get the the coordinate system of the values
305 std::string system = gammalib::split(region_def, ";")[0];
306
307 // Get the substring of the important values
308 size_t pos = region_def.find("circle(");
309 size_t end = region_def.find(")");
310 std::string circlestring = region_def.substr(pos+7, end);
311 circlestring.erase(circlestring.find(")"), 1);
312
313 // Get the values of the region x,y,and radius
314 std::vector<std::string> values = gammalib::split(circlestring,",");
315 if (values.size() != 3) {
316 std::string msg =
317 "Invalid number of "+gammalib::str(values.size())+" arguments "
318 "after the \"circle\" key word in provided string \""+line+"\". "
319 "Exactly 3 arguments are expected.";
321 }
322 double x = gammalib::todouble(values[0]);
323 double y = gammalib::todouble(values[1]);
324 double radius = gammalib::todouble(values[2]);
325
326 // Get radius units
327 if (gammalib::contains(values[2], "'")) {
328 radius /= 60.0;
329 }
330 else if (gammalib::contains(values[2], "\"")) {
331 radius /= 3600.0;
332 }
333
334 // Initialise centre direction
336
337 // Set the values in the correct system
338 if (system == "fk5" || system == "icrs") {
339 centre.radec_deg(x,y);
340 }
341 else if (system == "galactic") {
342 centre.lb_deg(x,y);
343 }
344 else {
345 std::string msg =
346 "Unsupported coordinate system \""+system+"\" in provided string "
347 "\""+line+"\". Only the following coordinate systems are "
348 "supported: \"fk5\", \"icrs\" and \"galactic\".";
350 }
351
352 // Set members
353 this->centre(centre);
354 this->radius(radius);
355
356 // Compute solid angle
358
359 // Check if there is a given name for the region and set it. Strings may
360 // be quoted with " or ' or {}
361 pos = comment.find("text");
362 if (pos != std::string::npos) {
363 pos = comment.find("=", pos+4);
364 if (pos != std::string::npos) {
365
366 // Set possible quotes
367 const std::string quotes_open = "{'\"";
368 const std::string quotes_close = "}'\"";
369
370 // Set quotes found flag
371 bool found = false;
372
373 // Search for possible quotes and extract name
374 for (int i = 0; i < quotes_open.size(); ++i) {
375 std::string quote_open = quotes_open.substr(i,1);
376 std::string quote_close = quotes_close.substr(i,1);
377 pos = comment.find(quote_open, pos+1);
378 if (pos != std::string::npos) {
379 end = comment.find(quote_close, pos+1);
380 if (end != std::string::npos) {
381 int length = end-pos-1;
382 if (length > 0) {
383 m_name = comment.substr(pos+1, length);
384 }
385 else {
386 m_name = "";
387 }
388 found = true;
389 }
390 else {
391 std::string msg = "Missing "+quote_open+" following "+
392 quote_close+" encountered after "
393 "text attribute. Please add closing "
394 "quotes to text="+quote_open+"Name"+
395 quote_close+" attribute.";
397 }
398 }
399 } // endfor: looped over possible quotes
400
401 // Throw an exception if no quotes were found
402 if (!found) {
403 std::string msg = "Missing quotes \" or ' or {} following "
404 "text attribute. Please specify quotes "
405 "around the names of the text, for example "
406 "text={Name}.";
408 }
409
410 } // endif: = character found
411
412 // Signal that no = character was found after text
413 else {
414 std::string msg = "Missing = following text attribute. Please "
415 "specify the value for a text attribute, "
416 "for example text={Name}.";
418 }
419
420 } // endif: text attribute found
421
422 // Return
423 return;
424}
425
426
427/***********************************************************************//**
428 * @brief Write region into a string
429 *
430 * @return String to be written in a DS9 region file
431 *
432 * Writes a DS9 region into a string. The region name is only written if it
433 * is defined.
434 ***************************************************************************/
435std::string GSkyRegionCircle::write(void) const
436{
437 // Allocate string
438 std::string result;
439
440 // Set string
441 result.append("fk5;circle(");
442 result.append(gammalib::str(m_centre.ra_deg()));
443 result.append(",");
444 result.append(gammalib::str(m_centre.dec_deg()));
445 result.append(",");
446 result.append(gammalib::str(m_radius));
447 result.append(")");
448
449 // Optionally add region name
450 if (m_name.length() > 0) {
451 result.append(" # text=");
452 result.append("{");
453 result.append(m_name);
454 result.append("}");
455 }
456
457 // Return string
458 return result;
459}
460
461
462/***********************************************************************//**
463 * @brief Print circular region
464 *
465 * @param[in] chatter Chattiness
466 * @return String containing region information.
467 ***************************************************************************/
468std::string GSkyRegionCircle::print(const GChatter& chatter) const
469{
470 // Initialise result string
471 std::string result;;
472
473 // Continue only if chatter is not silent
474 if (chatter != SILENT) {
475
476 // Append header
477 result.append("=== GSkyRegionCircle ===");
478
479 // Append sky circle information
480 result.append("\n"+gammalib::parformat("Right Ascension of centre"));
481 result.append(gammalib::str(ra())+" deg");
482 result.append("\n"+gammalib::parformat("Declination of centre"));
483 result.append(gammalib::str(dec())+" deg");
484 result.append("\n"+gammalib::parformat("Radius"));
485 result.append(gammalib::str(radius())+" deg");
486
487 } // endif: chatter was not silent
488
489 // Return result
490 return result;
491}
492
493/***********************************************************************//**
494 * @brief Checks if sky direction lies within region
495 *
496 * @param[in] dir Sky direction.
497 * @return True if sky direction is contained in region.
498 *
499 * A sky direction lies within a region when its distance to the region
500 * centre is not larger than the region radius.
501 ***************************************************************************/
503{
504 // Initialise containment flag
505 bool contains = false;
506
507 // calculate distance from dir to centre
508 double distance = dir.dist_deg(m_centre);
509
510 // Check if distance < radius
511 if (distance <= radius()) {
512 contains = true;
513 }
514
515 // Return containment flag
516 return contains;
517}
518
519/***********************************************************************//**
520 * @brief Checks if region is fully contained within this region
521 *
522 * @param[in] reg Sky region.
523 * @return True if region is contained in region.
524 *
525 * @exception GException::feature_not_implemented
526 * Regions differ in type.
527 ***************************************************************************/
529{
530 // Initialise return value
531 bool contains = false;
532
533 // If the other region is a circle then check whether it is fully
534 // container in the circle
535 if (reg.type() == "Circle") {
536
537 // Create circular region from reg
538 const GSkyRegionCircle* circle =
539 static_cast<const GSkyRegionCircle*>(&reg);
540
541 // Calculate angular distance between the centres
542 double ang_dist = m_centre.dist_deg(circle->centre());
543
544 // Check if the region is contained in this
545 if ((ang_dist + circle->radius()) <= m_radius) {
546 contains = true;
547 }
548
549 } // endif: other region was of type "Circle"
550
551 // ... otherwise, if the other region is a rectangle then check whether
552 // all four corners are contained within the circle
553 else if (reg.type() == "Rectangle") {
554
555 // Create rectangular region from reg
556 const GSkyRegionRectangle* rect =
557 static_cast<const GSkyRegionRectangle*>(&reg);
558
559 // Check containment of all corners
560 contains = this->contains(rect->corner(0)) &&
561 this->contains(rect->corner(1)) &&
562 this->contains(rect->corner(2)) &&
563 this->contains(rect->corner(3));
564
565 }
566
567 // ... otherwise, if the other region is a map then check whether it
568 // is contained within the rectangle
569 else if (reg.type() == "Map") {
570
571 // Create map from reg
572 const GSkyRegionMap* map = static_cast<const GSkyRegionMap*>(&reg);
573
574 // Get non-zero indices
575 const std::vector<int>& indices = map->nonzero_indices();
576
577 // Initialise containment flag to true
578 contains = true;
579
580 // Loop over all indices
581 for (int i = 0; i < indices.size(); ++i) {
582
583 // Get sky direction of map pixel
584 GSkyDir dir = map->map().inx2dir(indices[i]);
585
586 // If pixel is not contained then set containment flag to false
587 // and break
588 if (!this->contains(dir)) {
589 contains = false;
590 break;
591 }
592
593 } // endfor: looped over non-zero map indices
594
595 } // endif: other region was of type "Map"
596
597 // ... otherwise throw an exception
598 else {
600 "Cannot compare to region type \""+reg.type()+"\" yet.");
601 }
602
603 // Return containment flag
604 return contains;
605}
606
607
608/***********************************************************************//**
609 * @brief Checks if region is overlapping with this region
610 *
611 * @param[in] reg Sky region.
612 * @return True if region overlaps with region.
613 *
614 * @exception GException::feature_not_implemented
615 * Regions differ in type.
616 ***************************************************************************/
618{
619 // Initialise return value
620 bool overlap = false;
621
622 // If region is circle then check overlap by comparing the centre
623 // distances
624 if (reg.type() == "Circle") {
625
626 // Create circular region from reg
627 const GSkyRegionCircle* circle =
628 static_cast<const GSkyRegionCircle*>(&reg);
629
630 // Calculate angular distance between the centres
631 double ang_dist = m_centre.dist_deg(circle->centre());
632
633 // Check if the distance is smaller than the sum of both radii
634 if (ang_dist <= (m_radius + circle->radius())) {
635 overlap = true;
636 }
637
638 } // endif: region was circle
639
640 // ... otherwise if region is rectangle then check overlap
641 else if (reg.type() == "Rectangle") {
642
643 // Create rectangular region from reg
644 const GSkyRegionRectangle* rect =
645 static_cast<const GSkyRegionRectangle*>(&reg);
646
647 // Check overlap with circle
648 overlap = rect->overlaps(*this);
649
650 } // endif: region was rectangle
651
652 // ... otherwise if region is map then check overlap with map
653 else if (reg.type() == "Map") {
654
655 // Create map from reg
656 const GSkyRegionMap* map = static_cast<const GSkyRegionMap*>(&reg);
657
658 // Check overlap with circle
659 overlap = map->overlaps(*this);
660
661 } // endif: region was map
662
663 // ... otherwise throw an exception
664 else {
666 "Cannot compare to region type \""+reg.type()+"\" yet.");
667 }
668
669 // Return value
670 return overlap;
671}
672
673
674/*==========================================================================
675 = =
676 = Private methods =
677 = =
678 ==========================================================================*/
679
680/***********************************************************************//**
681 * @brief Initialise class members
682 ***************************************************************************/
684{
685 // Initialise members
686 m_centre = GSkyDir();
687 m_radius = 0.0;
688 m_type = "Circle";
689
690 //Return
691 return;
692}
693
694
695/***********************************************************************//**
696 * @brief Copy class members
697 *
698 * @param[in] region Circular sky region.
699 ***************************************************************************/
701{
702 // Copy attributes
703 m_centre = region.m_centre;
704 m_radius = region.m_radius;
705
706 // Return
707 return;
708}
709
710
711/***********************************************************************//**
712 * @brief Delete class members
713 ***************************************************************************/
715{
716 // Return
717 return;
718}
719
720
721/***********************************************************************//**
722 * @brief Compute solid angle
723 ***************************************************************************/
725{
726 // Convert radius from degrees to radians
727 double radius_rad = m_radius * gammalib::deg2rad;
728
729 // Compute solid angle
730 m_solid = gammalib::twopi * (1.0 - std::cos(radius_rad));
731
732 // Return
733 return;
734}
735
736
737/***********************************************************************//**
738 * @brief Equality operator
739 *
740 * @param[in] a First sky region circle.
741 * @param[in] b Second sky region circle.
742 * @return True if both sky region circles are identical.
743 *
744 * Returns true if two sky region circles and identical.
745 ***************************************************************************/
747{
748 // Return equality
749 return ((a.m_centre == b.m_centre) && (a.m_radius == b.m_radius));
750}
751
752
753/***********************************************************************//**
754 * @brief Non equality operator
755 *
756 * @param[in] a First sky region circle.
757 * @param[in] b Second sky region circle.
758 * @return True if both sky region circles are different.
759 ***************************************************************************/
761{
762 // Return non equality
763 return ((a.m_centre != b.m_centre) || (a.m_radius != b.m_radius));
764}
#define G_READ
bool operator==(const GSkyRegionCircle &a, const GSkyRegionCircle &b)
Equality operator.
bool operator!=(const GSkyRegionCircle &a, const GSkyRegionCircle &b)
Non equality operator.
#define G_CONTAINS
#define G_RADIUS
Circular sky region class interface definition.
Sky region map class interface definition.
Rectangular sky region class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Sky direction class.
Definition GSkyDir.hpp:62
void lb_deg(const double &l, const double &b)
Set galactic sky direction (degrees)
Definition GSkyDir.cpp:278
double dec_deg(void) const
Returns Declination in degrees.
Definition GSkyDir.hpp:256
double ra_deg(void) const
Returns Right Ascension in degrees.
Definition GSkyDir.hpp:229
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition GSkyDir.cpp:224
double dist_deg(const GSkyDir &dir) const
Compute angular distance between sky directions in degrees.
Definition GSkyDir.hpp:286
Interface for the circular sky region class.
double dec(void) const
Return circular region centre Declination.
std::string print(const GChatter &chatter=NORMAL) const
Print circular region.
virtual ~GSkyRegionCircle(void)
Destructor.
GSkyRegionCircle * clone(void) const
Clone circular sky region.
void compute_solid_angle(void)
Compute solid angle.
GSkyDir m_centre
Centre or reference point of the region.
GSkyRegionCircle & operator=(const GSkyRegionCircle &region)
Assignment operator.
double m_radius
Radius of circular the region (degrees)
void read(const std::string &line)
Read region from DS9 string.
bool contains(const GSkyDir &dir) const
Checks if sky direction lies within region.
GSkyRegionCircle(void)
Void constructor.
bool overlaps(const GSkyRegion &reg) const
Checks if region is overlapping with this region.
double ra(void) const
Return circular region centre Right Ascension.
void copy_members(const GSkyRegionCircle &region)
Copy class members.
void clear(void)
Clear instance.
const double & radius(void) const
Return circular region radius (in degrees)
const GSkyDir & centre(void) const
Return circular region centre.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
std::string write(void) const
Write region into a string.
Interface for a sky region map.
void map(const GSkyMap &map)
Set sky map.
bool overlaps(const GSkyRegion &reg) const
Checks if a given region is overlapping with this region.
const std::vector< int > & nonzero_indices(void) const
Get non-zero index vector.
Interface for the rectangular sky region class.
bool overlaps(const GSkyRegion &reg) const
Checks if region is overlapping with this region.
GSkyDir corner(const int &index) const
Return sky direction of one corner of the rectangle.
Abstract interface for the sky region class.
const std::string & type(void) const
Return region type.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
std::string m_name
Name of the region.
std::string m_type
Type of the region (circle, rectangle,...)
double m_solid
Solid angle subtended by the region (sr)
virtual GSkyRegion & operator=(const GSkyRegion &region)
Assignment operator.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:926
const double deg2rad
Definition GMath.hpp:43
bool contains(const std::string &str, const std::string &substring)
Checks if a substring is in a string.
Definition GTools.cpp:1342
const double twopi
Definition GMath.hpp:36
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition GTools.cpp:983