GammaLib 2.0.0
Loading...
Searching...
No Matches
GSkyRegions.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSkyRegions.cpp - Sky region container class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2013-2021 by Pierrick Martin *
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 GSkyRegions.cpp
23* @brief Sky regions container class definition
24* @author Pierrick Martin
25*/
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#include <fstream>
31#endif
32#include "GBase.hpp"
33#include "GTools.hpp"
34#include "GSkyDir.hpp"
35#include "GSkyRegion.hpp"
36#include "GSkyRegionCircle.hpp"
38#include "GSkyRegions.hpp"
39
40/* __ Method name definitions ____________________________________________ */
41#define G_ACCESS "GSkyRegions::operator[](std::string&)"
42#define G_AT "GSkyRegions::at(int&)"
43#define G_SET1 "GSkyRegions::set(int&, GSkyRegion&)"
44#define G_SET2 "GSkyRegions::set(std::string&, GSkyRegion&)"
45#define G_APPEND "GSkyRegions::append(GSkyRegion&)"
46#define G_INSERT1 "GSkyRegions::insert(int&, GSkyRegion&)"
47#define G_INSERT2 "GSkyRegions::insert(std::string&, GSkyRegion&)"
48#define G_REMOVE1 "GSkyRegions::remove(int&)"
49#define G_REMOVE2 "GSkyRegions::remove(std::string&)"
50#define G_EXTEND "GSkyRegions::extend(GSkyRegions&)"
51#define G_LOAD "GSkyRegions::load(GFilename&)"
52#define G_SAVE "GSkyRegions::save(GFilename&)"
53
54/* __ Macros _____________________________________________________________ */
55
56/* __ Coding definitions _________________________________________________ */
57
58/* __ Debug definitions __________________________________________________ */
59
60
61/*==========================================================================
62 = =
63 = Constructors/destructors =
64 = =
65 ==========================================================================*/
66
67/***********************************************************************//**
68 * @brief Void constructor
69 ***************************************************************************/
71{
72 // Initialise members
74
75 // Return
76 return;
77}
78
79
80/***********************************************************************//**
81 * @brief Copy constructor
82 *
83 * @param[in] regions region container.
84 ***************************************************************************/
86{
87 // Initialise members
89
90 // Copy members
91 copy_members(regions);
92
93 // Return
94 return;
95}
96
97
98/***********************************************************************//**
99 * @brief Load constructor
100 *
101 * @param[in] filename DS9 region file.
102 *
103 * Constructs region container from a DS9 region file.
104 ***************************************************************************/
106{
107 // Initialise members
108 init_members();
109
110 // Load XML file
111 load(filename);
112
113 // Return
114 return;
115}
116
117
118/***********************************************************************//**
119 * @brief Destructor
120 ***************************************************************************/
122{
123 // Free members
124 free_members();
125
126 // Return
127 return;
128}
129
130
131/*==========================================================================
132 = =
133 = Operators =
134 = =
135 ==========================================================================*/
136
137/***********************************************************************//**
138 * @brief Assignment operator
139 *
140 * @param[in] regions region container.
141 * @return region container.
142 ***************************************************************************/
144{
145 // Execute only if object is not identical
146 if (this != &regions) {
147
148 // Free members
149 free_members();
150
151 // Initialise members
152 init_members();
153
154 // Copy members
155 copy_members(regions);
156
157 } // endif: object was not identical
158
159 // Return
160 return *this;
161}
162
163
164/*==========================================================================
165 = =
166 = Public methods =
167 = =
168 ==========================================================================*/
169
170/***********************************************************************//**
171 * @brief Clear object
172 *
173 * Removes all regions from the container.
174 ***************************************************************************/
176{
177 // Free class members
178 free_members();
179
180 // Initialise members
181 init_members();
182
183 // Return
184 return;
185}
186
187
188/***********************************************************************//**
189 * @brief Clone instance
190 *
191 * @return Pointer to deep copy of region container
192 *
193 * Makes a deep copy of the region container instance.
194 ***************************************************************************/
196{
197 return new GSkyRegions(*this);
198}
199
200
201/***********************************************************************//**
202 * @brief Return pointer to region
203 *
204 * @param[in] index Sky region index [0,...,size()[.
205 *
206 * @exception GException::out_of_range
207 * Sky region index is out of range.
208 *
209 * Returns a pointer to the region with the specified @p index.
210 ***************************************************************************/
211GSkyRegion* GSkyRegions::at(const int& index)
212{
213 // Throw exception if index is out of range
214 if (index < 0 || index >= size()) {
215 throw GException::out_of_range(G_AT, "Sky region index",
216 index, size());
217 }
218
219 // Return pointer
220 return m_regions[index];
221}
222
223
224/***********************************************************************//**
225 * @brief Return pointer to region (const version)
226 *
227 * @param[in] index Sky region index [0,...,size()[.
228 *
229 * @exception GException::out_of_range
230 * Sky region index is out of range.
231 *
232 * Returns a const pointer to the region with the specified @p index.
233 ***************************************************************************/
234const GSkyRegion* GSkyRegions::at(const int& index) const
235{
236 // Raise exception if index is out of range
237 if (index < 0 || index >= size()) {
238 throw GException::out_of_range(G_AT, "Sky Region index",
239 index, size());
240 }
241
242 // Return pointer
243 return m_regions[index];
244}
245
246
247/***********************************************************************//**
248 * @brief Set region in container
249 *
250 * @param[in] index Sky region index [0,...,size()[.
251 * @param[in] region Sky region.
252 * @return Pointer to deep copy of sky region.
253 *
254 * @exception GException::out_of_range
255 * Sky region index is out of range.
256 * @exception GException::invalid_value
257 * Name of region exists already in container.
258 *
259 * Set sky region in the container. A deep copy of the region will be made.
260 ***************************************************************************/
261GSkyRegion* GSkyRegions::set(const int& index, const GSkyRegion& region)
262{
263 // Compile option: raise exception if index is out of range
264 #if defined(G_RANGE_CHECK)
265 if (index < 0 || index >= size()) {
266 throw GException::out_of_range(G_SET1, "Sky Region index",
267 index, size());
268 }
269 #endif
270
271 // Free existing region only if it differs from current region. This
272 // prevents unintential deallocation of the argument
273 if ((m_regions[index] != NULL) && (m_regions[index] != &region)) {
274 delete m_regions[index];
275 }
276
277 // Assign new region by cloning
278 m_regions[index] = region.clone();
279
280 // Return pointer to region
281 return m_regions[index];
282}
283
284
285/***********************************************************************//**
286 * @brief Append region to container
287 *
288 * @param[in] region region.
289 * @return Pointer to deep copy of region.
290 *
291 * @exception GException::invalid_value
292 * Name of region exists already in container.
293 *
294 * Appends region to the container by making a deep copy of the region and
295 * storing its pointer.
296 ***************************************************************************/
298{
299 // Create deep copy of region
300 GSkyRegion* ptr = region.clone();
301
302 // Append deep copy of region
303 m_regions.push_back(ptr);
304
305 // Return pointer to region
306 return ptr;
307}
308
309
310/***********************************************************************//**
311 * @brief Insert region into container
312 *
313 * @param[in] index Sky region index [0,...,size()[.
314 * @param[in] region Sky region.
315 * @return Pointer to deep copy of sky region.
316 *
317 * @exception GException::out_of_range
318 * Sky region index is out of range.
319 * @exception GException::invalid_value
320 * Name of region exists already in container.
321 *
322 * Inserts a @p region into the container before the region with the specified
323 * @p index.
324 ***************************************************************************/
325GSkyRegion* GSkyRegions::insert(const int& index, const GSkyRegion& region)
326{
327 // Compile option: raise exception if index is out of range
328 #if defined(G_RANGE_CHECK)
329 if (is_empty()) {
330 if (index > 0) {
331 throw GException::out_of_range(G_INSERT1, "Sky Region index",
332 index, size());
333 }
334 }
335 else {
336 if (index < 0 || index >= size()) {
337 throw GException::out_of_range(G_INSERT1, "Sky Region index",
338 index, size());
339 }
340 }
341 #endif
342
343 // Create deep copy of region
344 GSkyRegion* ptr = region.clone();
345
346 // Inserts deep copy of region
347 m_regions.insert(m_regions.begin()+index, ptr);
348
349 // Return pointer to region
350 return ptr;
351}
352
353
354/***********************************************************************//**
355 * @brief Remove region from container
356 *
357 * @param[in] index Sky region index [0,...,size()[.
358 *
359 * @exception GException::out_of_range
360 * Sky region index is out of range.
361 *
362 * Remove sky region of specified @p index from container.
363 ***************************************************************************/
364void GSkyRegions::remove(const int& index)
365{
366 // Compile option: raise exception if index is out of range
367 #if defined(G_RANGE_CHECK)
368 if (index < 0 || index >= size()) {
369 throw GException::out_of_range(G_REMOVE1, "Sky Region index",
370 index, size());
371 }
372 #endif
373
374 // Delete region
375 delete m_regions[index];
376
377 // Erase region component from container
378 m_regions.erase(m_regions.begin() + index);
379
380 // Return
381 return;
382}
383
384
385/***********************************************************************//**
386 * @brief Append region container
387 *
388 * @param[in] regions region container.
389 *
390 * Append region container to the container.
391 ***************************************************************************/
393{
394 // Do nothing if region container is empty
395 if (!regions.is_empty()) {
396
397 // Get size. Note that we extract the size first to avoid an
398 // endless loop that arises when a container is appended to
399 // itself.
400 int num = regions.size();
401
402 // Reserve enough space
403 reserve(size() + num);
404
405 // Loop over all region components and append pointers to deep copies
406 for (int i = 0; i < num; ++i) {
407
408 // Append region to container
409 m_regions.push_back(regions[i]->clone());
410
411 } // endfor: looped over all regions
412
413 } // endif: region container was not empty
414
415 // Return
416 return;
417}
418
419
420/***********************************************************************//**
421 * @brief Check if direction is contained in one of the regions
422 *
423 * @param[in] dir Sky direction.
424 * @return True if the sky direction is container in one of the regions,
425 * falls otherwise.
426 *
427 * Checks if a sky direction is contained in one of the regions of the
428 * container.
429 ***************************************************************************/
430bool GSkyRegions::contains(const GSkyDir& dir) const
431{
432 // Initialise return value
433 bool overlap = false;
434
435 // Loop over regions
436 for (int i = 0; i < size(); ++i) {
437 overlap = m_regions[i]->contains(dir);
438 if (overlap) {
439 break;
440 }
441 }
442
443 // Return result
444 return overlap;
445}
446
447
448/***********************************************************************//**
449 * @brief Check if region overlaps one of the regions
450 *
451 * @param[in] region Sky region.
452 * @return True if @p region overlaps with one of the regions in the region
453 * container, false otherwise
454 *
455 * Tells if region overlaps one of the regions
456 ***************************************************************************/
457bool GSkyRegions::overlaps(const GSkyRegion& region) const
458{
459 // Initialise return value
460 bool overlap = false;
461
462 // Loop over regions
463 for (int i = 0; i < size(); ++i) {
464 overlap = m_regions[i]->overlaps(region);
465 if (overlap) {
466 break;
467 }
468 }
469
470 // Return result
471 return overlap;
472}
473
474
475/***********************************************************************//**
476 * @brief Check if any of the regions in two containers overlap
477 *
478 * @param[in] regions Sky region container.
479 * @return True if one of the regions in the @p regions container overlaps
480 * with one of the regions in the container, false otherwise
481 *
482 * Tells if all regions in overlaps one of the regions. Note, this method
483 * returns true if ANY of the regions in the two containers overlap with
484 * each other
485 ***************************************************************************/
486bool GSkyRegions::overlaps(const GSkyRegions& regions) const
487{
488 // Initialize return value
489 bool overlap = false;
490
491 // Loop over each region in the container
492 for (int i = 0; i < size(); ++i) {
493 overlap = regions.overlaps(*m_regions[i]);
494 if (overlap) {
495 break;
496 }
497 }
498
499 // Return result
500 return overlap;
501}
502
503
504/***********************************************************************//**
505 * @brief Load regions from DS9 region file
506 *
507 * @param[in] filename DS9 region filename.
508 *
509 * @exception GException::file_error
510 * Unable to open file.
511 *
512 * Loads all regions from a DS9 region file.
513 ***************************************************************************/
514void GSkyRegions::load(const GFilename& filename)
515{
516 // Clear any existing regions
517 clear();
518
519 // Open file. Throw an exception if opening failed.
520 std::ifstream ds9file;
521 ds9file.open(filename.url().c_str());
522 if (ds9file.is_open()) {
523
524 // Loop over file lines
525 std::string fileline = "";
526 std::string coordsys = "galactic";
527 while (ds9file.good()) {
528
529 // Read one line
530 getline(ds9file,fileline);
531
532 // If line is a comment then continue
533 if (fileline[0] == '#') {
534 continue;
535 }
536
537 // Check for global definition of coordinate system
538 if (std::string::npos != fileline.find("fk5")) {
539 coordsys = "fk5";
540 }
541 else if (std::string::npos != fileline.find("icrs")) {
542 coordsys = "icrs";
543 }
544
545 // If region is a circle then read circle
546 if (std::string::npos != fileline.find("circle")) {
547
548 // Create instance of GSkyRegionCircle object
549 GSkyRegionCircle region;
550
551 // If coordinate system and region defined on the same line
552 if ((std::string::npos != fileline.find("fk5")) ||
553 (std::string::npos != fileline.find("icrs")) ||
554 (std::string::npos != fileline.find("galactic"))) {
555 region.read(fileline);
556 append(region);
557 }
558
559 // else, prepend the coordinate system
560 else {
561 std::string newfileline = coordsys;
562 newfileline.append("; ");
563 newfileline.append(fileline);
564 region.read(newfileline);
565 append(region);
566 }
567
568 } // endif: region was circle
569
570 // ... otherwise if region is a box then read rectangle
571 else if (std::string::npos != fileline.find("box")) {
572
573 // Create instance of GSkyRegionRectangle object
574 GSkyRegionRectangle region;
575
576 // If coordinate system and region defined on the same line
577 if ((std::string::npos != fileline.find("fk5")) ||
578 (std::string::npos != fileline.find("icrs")) ||
579 (std::string::npos != fileline.find("galactic"))) {
580 region.read(fileline);
581 append(region);
582 }
583
584 // else, prepend the coordinate system
585 else {
586 std::string newfileline = coordsys;
587 newfileline.append("; ");
588 newfileline.append(fileline);
589 region.read(newfileline);
590 append(region);
591 }
592
593 } // endif: region was box
594
595 } // endwhile: looped over file
596
597 // Close file
598 ds9file.close();
599
600 // Store filename
602
603 }
604
605 // File could not be opened
606 else {
607 std::string msg = "Unable to open file \""+filename.url()+"\". Please "
608 "specify a valid file name.";
609 throw GException::file_error(G_LOAD, msg);
610 }
611
612 // Return
613 return;
614}
615
616
617/***********************************************************************//**
618 * @brief Save regions into DS9 region file
619 *
620 * @param[in] filename DS9 region filename.
621 *
622 * @exception GException::file_error
623 * Unable to open file.
624 *
625 * Saves all regions in the container into a DS9 region file.
626 ***************************************************************************/
627void GSkyRegions::save(const GFilename& filename) const
628{
629 // Open file
630 std::ofstream ds9file;
631 ds9file.open(filename.url().c_str());
632
633 // If file opened correctly, then save regions
634 if (ds9file.is_open()) {
635
636 // Write global definition
637 std::string fileline;
638 fileline.append("# Region file format: DS9 version 4.1\n");
639 fileline.append("global color=green dashlist=8 3 width=1");
640 ds9file << fileline << "\n";
641
642 // Loop over regions in container
643 for (int i = 0; i < size(); ++i) {
644 ds9file << m_regions[i]->write() << "\n";
645 }
646
647 // Close file
648 ds9file.close();
649
650 // Store filename
652
653 }
654
655 // ... otherwise, if file could not be opened then throw an exception
656 else {
657 std::string msg = "Unable to open file \""+filename.url()+"\". Please "
658 "specify a valid file name.";
659 throw GException::file_error(G_SAVE, msg);
660 }
661
662 // Return
663 return;
664}
665
666
667/***********************************************************************//**
668 * @brief Print regions
669 *
670 * @param[in] chatter Chattiness.
671 * @return String containing region container information.
672 *
673 * Prints all regions into a string.
674 ***************************************************************************/
675std::string GSkyRegions::print(const GChatter& chatter) const
676{
677 // Initialise result string
678 std::string result;
679
680 // Continue only if chatter is not silent
681 if (chatter != SILENT) {
682
683 // Append header
684 result.append("=== GSkyRegions ===");
685
686 // Append information
687 result.append("\n"+gammalib::parformat("Number of regions"));
688 result.append(gammalib::str(size()));
689
690 // Append regions
691 for (int i = 0; i < size(); ++i) {
692 result.append("\n"+m_regions[i]->print(chatter));
693 }
694
695 } // endif: chatter was not silent
696
697 // Return result
698 return result;
699}
700
701
702/*==========================================================================
703 = =
704 = Private methods =
705 = =
706 ==========================================================================*/
707
708/***********************************************************************//**
709 * @brief Initialise class members
710 ***************************************************************************/
712{
713 // Initialise members
715 m_regions.clear();
716
717 // Return
718 return;
719}
720
721
722/***********************************************************************//**
723 * @brief Copy class members
724 *
725 * @param[in] regions region container.
726 *
727 * Makes a copy of all class members. All regions are deep copied.
728 ***************************************************************************/
730{
731 // Copy members
732 m_filename = regions.m_filename;
733
734 // Copy regions
735 for (int i = 0; i < regions.m_regions.size(); ++i) {
736 m_regions.push_back((regions.m_regions[i]->clone()));
737 }
738
739 // Return
740 return;
741}
742
743
744/***********************************************************************//**
745 * @brief Delete class members
746 *
747 * Deallocates all regions. The method loops over the region container and
748 * deallocates the memory that has been allocated before.
749 ***************************************************************************/
751{
752 // Free regions
753 for (int i = 0; i < m_regions.size(); ++i) {
754 if (m_regions[i] != NULL) {
755 delete m_regions[i];
756 }
757 m_regions[i] = NULL;
758 }
759
760 // Return
761 return;
762}
#define G_AT
#define G_REMOVE1
#define G_SAVE
#define G_INSERT1
Definition of interface for all GammaLib classes.
#define G_SET1
Definition GFits.cpp:57
#define G_LOAD
Sky direction class interface definition.
Circular sky region class interface definition.
Rectangular sky region class interface definition.
Abstract sky region base class interface definition.
Sky regions container class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
Sky direction class.
Definition GSkyDir.hpp:62
Interface for the circular sky region class.
void read(const std::string &line)
Read region from DS9 string.
Interface for the rectangular sky region class.
void read(const std::string &line)
Read region from DS9 string.
Abstract interface for the sky region class.
virtual GSkyRegion * clone(void) const =0
Clones object.
Sky region container class.
GSkyRegions * clone(void) const
Clone instance.
std::string print(const GChatter &chatter=NORMAL) const
Print regions.
void remove(const int &index)
Remove region from container.
void init_members(void)
Initialise class members.
const GFilename & filename(void) const
Return regions file name.
GSkyRegion * at(const int &index)
Return pointer to region.
virtual ~GSkyRegions(void)
Destructor.
GSkyRegions & operator=(const GSkyRegions &regions)
Assignment operator.
bool contains(const GSkyDir &dir) const
Check if direction is contained in one of the regions.
void load(const GFilename &filename)
Load regions from DS9 region file.
void clear(void)
Clear object.
GSkyRegion * append(const GSkyRegion &region)
Append region to container.
void free_members(void)
Delete class members.
GSkyRegion * insert(const int &index, const GSkyRegion &region)
Insert region into container.
void extend(const GSkyRegions &regions)
Append region container.
GSkyRegion * set(const int &index, const GSkyRegion &region)
Set region in container.
bool is_empty(void) const
Signals if there are no regions in container.
bool overlaps(const GSkyRegion &region) const
Check if region overlaps one of the regions.
void save(const GFilename &filename) const
Save regions into DS9 region file.
void reserve(const int &num)
Reserves space for regions in container.
void copy_members(const GSkyRegions &regions)
Copy class members.
std::vector< GSkyRegion * > m_regions
List of regions.
GSkyRegions(void)
Void constructor.
GFilename m_filename
Filename of origin.
int size(void) const
Return number of regions in container.
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