/*************************************************************************** * GSkyRegions.cpp - Sky region container class * * ----------------------------------------------------------------------- * * copyright (C) 2013-2016 by Pierrick Martin * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ /** * @file GSkyRegions.cpp * @brief Sky regions container class definition * @author Pierrick Martin */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #include #endif #include "GBase.hpp" #include "GTools.hpp" #include "GSkyDir.hpp" #include "GSkyRegion.hpp" #include "GSkyRegionCircle.hpp" #include "GSkyRegions.hpp" /* __ Method name definitions ____________________________________________ */ #define G_ACCESS "GSkyRegions::operator[](std::string&)" #define G_AT "GSkyRegions::at(int&)" #define G_SET1 "GSkyRegions::set(int&, GSkyRegion&)" #define G_SET2 "GSkyRegions::set(std::string&, GSkyRegion&)" #define G_APPEND "GSkyRegions::append(GSkyRegion&)" #define G_INSERT1 "GSkyRegions::insert(int&, GSkyRegion&)" #define G_INSERT2 "GSkyRegions::insert(std::string&, GSkyRegion&)" #define G_REMOVE1 "GSkyRegions::remove(int&)" #define G_REMOVE2 "GSkyRegions::remove(std::string&)" #define G_EXTEND "GSkyRegions::extend(GSkyRegions&)" #define G_LOAD "GSkyRegions::load(GFilename&)" #define G_SAVE "GSkyRegions::save(GFilename&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ GSkyRegions::GSkyRegions(void) { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] regions region container. ***************************************************************************/ GSkyRegions::GSkyRegions(const GSkyRegions& regions) { // Initialise members init_members(); // Copy members copy_members(regions); // Return return; } /***********************************************************************//** * @brief Load constructor * * @param[in] filename DS9 region file. * * Constructs region container from a DS9 region file. ***************************************************************************/ GSkyRegions::GSkyRegions(const GFilename& filename) { // Initialise members init_members(); // Load XML file load(filename); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ GSkyRegions::~GSkyRegions(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] regions region container. * @return region container. ***************************************************************************/ GSkyRegions& GSkyRegions::operator=(const GSkyRegions& regions) { // Execute only if object is not identical if (this != ®ions) { // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(regions); } // endif: object was not identical // Return return *this; } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Clear object * * Removes all regions from the container. ***************************************************************************/ void GSkyRegions::clear(void) { // Free class members free_members(); // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Clone instance * * @return Pointer to deep copy of region container * * Makes a deep copy of the region container instance. ***************************************************************************/ GSkyRegions* GSkyRegions::clone(void) const { return new GSkyRegions(*this); } /***********************************************************************//** * @brief Return pointer to region * * @param[in] index region index [0,...,size()-1]. * * @exception GException::out_of_range * region index is out of range. * * Returns a pointer to the region with the specified @p index. ***************************************************************************/ GSkyRegion* GSkyRegions::at(const int& index) { // Raise exception if index is out of range if (index < 0 || index >= size()) { throw GException::out_of_range(G_AT, index, 0, size()-1); } // Return pointer return m_regions[index]; } /***********************************************************************//** * @brief Return pointer to region (const version) * * @param[in] index region index [0,...,size()-1]. * * @exception GException::out_of_range * region index is out of range. * * Returns a const pointer to the region with the specified @p index. ***************************************************************************/ const GSkyRegion* GSkyRegions::at(const int& index) const { // Raise exception if index is out of range if (index < 0 || index >= size()) { throw GException::out_of_range(G_AT, index, 0, size()-1); } // Return pointer return m_regions[index]; } /***********************************************************************//** * @brief Set region in container * * @param[in] index sky region index [0,...,size()-1]. * @param[in] region sky region. * @return Pointer to deep copy of sky region. * * @exception GException::out_of_range * region index is out of range. * @exception GException::invalid_value * Name of region exists already in container. * * Set sky region in the container. A deep copy of the region will be made. ***************************************************************************/ GSkyRegion* GSkyRegions::set(const int& index, const GSkyRegion& region) { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (index < 0 || index >= size()) { throw GException::out_of_range(G_SET1, index, 0, size()-1); } #endif // Delete any existing region if (m_regions[index] != NULL) delete m_regions[index]; // Assign new region by cloning m_regions[index] = region.clone(); // Return pointer to region return m_regions[index]; } /***********************************************************************//** * @brief Append region to container * * @param[in] region region. * @return Pointer to deep copy of region. * * @exception GException::invalid_value * Name of region exists already in container. * * Appends region to the container by making a deep copy of the region and * storing its pointer. ***************************************************************************/ GSkyRegion* GSkyRegions::append(const GSkyRegion& region) { // Create deep copy of region GSkyRegion* ptr = region.clone(); // Append deep copy of region m_regions.push_back(ptr); // Return pointer to region return ptr; } /***********************************************************************//** * @brief Insert region into container * * @param[in] index region index [0,...,size()-1]. * @param[in] region region. * @return Pointer to deep copy of region. * * @exception GException::out_of_range * region index is out of range. * @exception GException::invalid_value * Name of region exists already in container. * * Inserts a @p region into the container before the region with the specified * @p index. ***************************************************************************/ GSkyRegion* GSkyRegions::insert(const int& index, const GSkyRegion& region) { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (is_empty()) { if (index > 0) { throw GException::out_of_range(G_INSERT1, index, 0, size()-1); } } else { if (index < 0 || index >= size()) { throw GException::out_of_range(G_INSERT1, index, 0, size()-1); } } #endif // Create deep copy of region GSkyRegion* ptr = region.clone(); // Inserts deep copy of region m_regions.insert(m_regions.begin()+index, ptr); // Return pointer to region return ptr; } /***********************************************************************//** * @brief Remove region from container * * @param[in] index region index [0,...,size()-1]. * * @exception GException::out_of_range * region index is out of range. * * Remove region of specified @p index from container. ***************************************************************************/ void GSkyRegions::remove(const int& index) { // Compile option: raise exception if index is out of range #if defined(G_RANGE_CHECK) if (index < 0 || index >= size()) { throw GException::out_of_range(G_REMOVE1, index, 0, size()-1); } #endif // Delete region delete m_regions[index]; // Erase region component from container m_regions.erase(m_regions.begin() + index); // Return return; } /***********************************************************************//** * @brief Append region container * * @param[in] regions region container. * * Append region container to the container. ***************************************************************************/ void GSkyRegions::extend(const GSkyRegions& regions) { // Do nothing if region container is empty if (!regions.is_empty()) { // Get size. Note that we extract the size first to avoid an // endless loop that arises when a container is appended to // itself. int num = regions.size(); // Reserve enough space reserve(size() + num); // Loop over all region components and append pointers to deep copies for (int i = 0; i < num; ++i) { // Append region to container m_regions.push_back(regions[i]->clone()); } // endfor: looped over all regions } // endif: region container was not empty // Return return; } /***********************************************************************//** * @brief Load regions from DS9 region file * * @param[in] filename DS9 region filename. * * @exception GException::file_open_error * File could not be opened. * * Loads all regions from a DS9 region file. ***************************************************************************/ void GSkyRegions::load(const GFilename& filename) { // Clear any existing regions clear(); // Open file. Throw an exception if opening failed. std::ifstream ds9file; ds9file.open(filename.url().c_str()); if (ds9file.is_open()) { // Loop over file lines std::string fileline = ""; std::string coordsys = "galactic"; while (ds9file.good()) { // Read one line getline(ds9file,fileline); // If line is a comment then continue if (fileline[0] == '#') { continue; } // Check for global definition of coordinate system if (std::string::npos != fileline.find("fk5")) { coordsys = "fk5"; } else if (std::string::npos != fileline.find("icrs")) { coordsys = "icrs"; } // If region is a circle if (std::string::npos != fileline.find("circle")) { // Create instance of GSkyRegion object GSkyRegionCircle region; // If coordinate system and region defined on the same line if ((std::string::npos != fileline.find("fk5")) || (std::string::npos != fileline.find("icrs")) || (std::string::npos != fileline.find("galactic"))) { region.read(fileline); append(region); } // else, prepend the coordinate system else { std::string newfileline = coordsys; newfileline.append("; "); newfileline.append(fileline); region.read(newfileline); append(region); } } } // Close file ds9file.close(); // Store filename m_filename = filename; } // File could not be opened else { throw GException::file_open_error(G_LOAD, filename.url()); } // Return return; } /***********************************************************************//** * @brief Save regions into DS9 region file * * @param[in] filename DS9 region filename. * * @exception GException::file_open_error * File could not be opened. * * Saves all regions in the container into a DS9 region file. ***************************************************************************/ void GSkyRegions::save(const GFilename& filename) const { // Open file std::ofstream ds9file; ds9file.open(filename.url().c_str()); // If file opened correctly, then save regions if (ds9file.is_open()) { // Write global definition std::string fileline; fileline.append("# Region file format: DS9 version 4.1\n"); fileline.append("global color=green dashlist=8 3 width=1"); // fileline.append("font=\"helvetica 10 normal\" select=1"); // "highlite=1 dash=0 fixed=0 edit=1 move=1"+ // "delete=1 include=1 source=1"; ds9file << fileline << "\n"; // Loop over regions in container for (int i = 0; i < size(); ++i) { ds9file << m_regions[i]->write() << "\n"; } // Close file ds9file.close(); // Store filename m_filename = filename; } // ... otherwise, if file could not be opened then throw an exception else { throw GException::file_open_error(G_SAVE, filename.url()); } // Return return; } /***********************************************************************//** * @brief Print regions * * @param[in] chatter Chattiness * @return String containing region container information. * * Prints all regions into a string. ***************************************************************************/ std::string GSkyRegions::print(const GChatter& chatter) const { // Initialise result string std::string result; // Continue only if chatter is not silent if (chatter != SILENT) { // Append header result.append("=== GSkyRegions ==="); // Append information result.append("\n"+gammalib::parformat("Number of regions")); result.append(gammalib::str(size())); // Append regions for (int i = 0; i < size(); ++i) { result.append("\n"+m_regions[i]->print(chatter)); } } // endif: chatter was not silent // Return result return result; } /***********************************************************************//** * @brief Tells if direction is contained in one of the regions * * @param[in] dir A sky direction * @return True or False * * Tells if direction is contained in one of the regions ***************************************************************************/ bool GSkyRegions::contains(const GSkyDir& dir) const { // Initialise return value bool dir_is_in = false; // Loop over regions for (int i = 0; i < size(); ++i) { dir_is_in=m_regions[i]->contains(dir); if (dir_is_in) break; } // Return result return dir_is_in; } /***********************************************************************//** * @brief Tells if region overlaps one of the regions * * @param[in] reg A sky region * @return True or False * * Tells if region overlaps one of the regions ***************************************************************************/ bool GSkyRegions::overlaps(const GSkyRegion& reg) const { // Initialise return value bool reg_is_in = false; // Loop over regions for (int i = 0; i < size(); ++i) { reg_is_in=m_regions[i]->overlaps(reg); if (reg_is_in) break; } // Return result return reg_is_in; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GSkyRegions::init_members(void) { // Initialise members m_filename.clear(); m_regions.clear(); // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] regions region container. * * Makes a copy of all class members. All regions are deep copied, and the * linear pointer array for parameter access through the GOptimizerPars * base class is set. ***************************************************************************/ void GSkyRegions::copy_members(const GSkyRegions& regions) { // Copy members m_filename = regions.m_filename; // Copy regions m_regions.clear(); for (int i = 0; i < regions.m_regions.size(); ++i) { m_regions.push_back((regions.m_regions[i]->clone())); } // Return return; } /***********************************************************************//** * @brief Delete class members * * Deallocates all regions. The method loops over the region container and * deallocates the memory that has been allocated before. ***************************************************************************/ void GSkyRegions::free_members(void) { // Free regions for (int i = 0; i < m_regions.size(); ++i) { delete m_regions[i]; m_regions[i] = NULL; } // Return return; }