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