Commit ca6d6d37239a755eb77055fd1ba8cd78173555d3
1 parent
1c7cb600
Adjust sky region classes (#3248)
Renamed the GSkyRegionRect::get_corner() method to GSkyRegionRect::corner() and make local coordinate methods provide. Use GSkyPixel to carry local coordinates in units of radians. Extent the GSkyRegionRect::contains() and GSkyRegionRect::overlaps() method to cover all other possible sky region types. Adjust GSkyRegionCircle and GSkyRegionMap to the new interface and make sure that their contains() and overlaps() method deal with all other regions. Adjust the GSkyRegionRect unit test accordingly.
Showing
6 changed files
with
318 additions
and
229 deletions
include/GSkyRegionRect.hpp
| ... | ... | @@ -34,6 +34,7 @@ |
| 34 | 34 | #include "GSkyRegion.hpp" |
| 35 | 35 | |
| 36 | 36 | /* __ Forward declarations _______________________________________________ */ |
| 37 | +class GSkyPixel; | |
| 37 | 38 | |
| 38 | 39 | |
| 39 | 40 | /***********************************************************************//** |
| ... | ... | @@ -97,26 +98,26 @@ public: |
| 97 | 98 | void read(const std::string& line); |
| 98 | 99 | std::string write(void) const; |
| 99 | 100 | bool contains(const GSkyDir& dir) const; |
| 100 | - bool contains_local(const GSkyDir& locdir) const; | |
| 101 | 101 | bool contains(const GSkyRegion& reg) const; |
| 102 | 102 | bool overlaps(const GSkyRegion& reg) const; |
| 103 | - GSkyDir transform_to_local(const GSkyDir& skydir) const; | |
| 104 | - GSkyDir transform_to_global(const GSkyDir& locdir) const; | |
| 105 | - GSkyDir get_corner(const int& index) const; | |
| 103 | + GSkyDir corner(const int& index) const; | |
| 106 | 104 | std::string print(const GChatter& chatter = NORMAL) const; |
| 107 | 105 | |
| 108 | 106 | protected: |
| 109 | 107 | // Protected methods |
| 110 | - void init_members(void); | |
| 111 | - void copy_members(const GSkyRegionRect& region); | |
| 112 | - void free_members(void); | |
| 113 | - void compute_solid_angle(void); | |
| 108 | + void init_members(void); | |
| 109 | + void copy_members(const GSkyRegionRect& region); | |
| 110 | + void free_members(void); | |
| 111 | + void compute_solid_angle(void); | |
| 112 | + bool contains(const GSkyPixel& local) const; | |
| 113 | + GSkyPixel dir_to_local(const GSkyDir& dir) const; | |
| 114 | + GSkyDir local_to_dir(const GSkyPixel& local) const; | |
| 114 | 115 | |
| 115 | 116 | // Protected members |
| 116 | - GSkyDir m_centre; //!< Centre or reference point of the region | |
| 117 | - double m_width; //!< Width of the region (degrees) | |
| 118 | - double m_height; //!< Height of the region (degrees) | |
| 119 | - double m_posang; //!< Position angle, counterclockwise from North (degrees) | |
| 117 | + GSkyDir m_centre; //!< Centre or reference point of the region | |
| 118 | + double m_width; //!< Width of the region (degrees) | |
| 119 | + double m_height; //!< Height of the region (degrees) | |
| 120 | + double m_posang; //!< Position angle, counterclockwise from North (degrees) | |
| 120 | 121 | }; |
| 121 | 122 | |
| 122 | 123 | ... | ... |
pyext/GSkyRegionRect.i
| ... | ... | @@ -70,12 +70,9 @@ public: |
| 70 | 70 | void read(const std::string& line); |
| 71 | 71 | std::string write(void) const; |
| 72 | 72 | bool contains(const GSkyDir& dir) const; |
| 73 | - bool contains_local(const GSkyDir& locdir) const; | |
| 74 | 73 | bool contains(const GSkyRegion& reg) const; |
| 75 | 74 | bool overlaps(const GSkyRegion& reg) const; |
| 76 | - GSkyDir transform_to_local(const GSkyDir& skydir) const; | |
| 77 | - GSkyDir transform_to_global(const GSkyDir& locdir) const; | |
| 78 | - GSkyDir get_corner(const int& index) const; | |
| 75 | + GSkyDir corner(const int& index) const; | |
| 79 | 76 | }; |
| 80 | 77 | |
| 81 | 78 | ... | ... |
src/sky/GSkyRegionCircle.cpp
| ... | ... | @@ -526,47 +526,78 @@ bool GSkyRegionCircle::contains(const GSkyDir& dir) const |
| 526 | 526 | bool GSkyRegionCircle::contains(const GSkyRegion& reg) const |
| 527 | 527 | { |
| 528 | 528 | // Initialise return value |
| 529 | - bool fully_inside = false; | |
| 529 | + bool contains = false; | |
| 530 | 530 | |
| 531 | - // If other region is circle use a simple way to calculate | |
| 531 | + // If the other region is a circle then check whether it is fully | |
| 532 | + // container in the circle | |
| 532 | 533 | if (reg.type() == "Circle") { |
| 533 | 534 | |
| 534 | 535 | // Create circular region from reg |
| 535 | - const GSkyRegionCircle* regcirc = | |
| 536 | - dynamic_cast<const GSkyRegionCircle*>(®); | |
| 536 | + const GSkyRegionCircle* circle = dynamic_cast<const GSkyRegionCircle*>(®); | |
| 537 | 537 | |
| 538 | 538 | // Calculate angular distance between the centres |
| 539 | - double ang_dist = m_centre.dist_deg(regcirc->centre()); | |
| 539 | + double ang_dist = m_centre.dist_deg(circle->centre()); | |
| 540 | 540 | |
| 541 | 541 | // Check if the region is contained in this |
| 542 | - if ((ang_dist + regcirc->radius()) <= m_radius) { | |
| 543 | - fully_inside = true; | |
| 542 | + if ((ang_dist + circle->radius()) <= m_radius) { | |
| 543 | + contains = true; | |
| 544 | 544 | } |
| 545 | 545 | |
| 546 | - } | |
| 546 | + } // endif: other region was of type "Circle" | |
| 547 | 547 | |
| 548 | - // If other region is rectangle check corners | |
| 548 | + // ... otherwise, if the other region is a rectangle then check whether | |
| 549 | + // all four corners are contained within the circle | |
| 549 | 550 | else if (reg.type() == "Rect") { |
| 550 | 551 | |
| 551 | 552 | // Create rectangular region from reg |
| 552 | - const GSkyRegionRect* regrect = | |
| 553 | - dynamic_cast<const GSkyRegionRect*>(®); | |
| 554 | - | |
| 555 | - // Check containment of all edges | |
| 556 | - fully_inside = contains(regrect->get_corner(0)) && | |
| 557 | - contains(regrect->get_corner(1)) && | |
| 558 | - contains(regrect->get_corner(2)) && | |
| 559 | - contains(regrect->get_corner(3)); | |
| 553 | + const GSkyRegionRect* rect = dynamic_cast<const GSkyRegionRect*>(®); | |
| 554 | + | |
| 555 | + // Check containment of all corners | |
| 556 | + contains = this->contains(rect->corner(0)) && | |
| 557 | + this->contains(rect->corner(1)) && | |
| 558 | + this->contains(rect->corner(2)) && | |
| 559 | + this->contains(rect->corner(3)); | |
| 560 | + | |
| 560 | 561 | } |
| 561 | 562 | |
| 563 | + // ... otherwise, if the other region is a map then check whether it | |
| 564 | + // is contained within the rectangle | |
| 565 | + else if (reg.type() == "Map") { | |
| 566 | + | |
| 567 | + // Create map from reg | |
| 568 | + const GSkyRegionMap* map = dynamic_cast<const GSkyRegionMap*>(®); | |
| 569 | + | |
| 570 | + // Get non-zero indices | |
| 571 | + std::vector<int> indices = map->nonzero_indices(); | |
| 572 | + | |
| 573 | + // Initialise containment flag to true | |
| 574 | + contains = true; | |
| 575 | + | |
| 576 | + // Loop over all indices | |
| 577 | + for (int i = 0; i < indices.size(); ++i) { | |
| 578 | + | |
| 579 | + // Get sky direction of map pixel | |
| 580 | + GSkyDir dir = map->map().inx2dir(i); | |
| 581 | + | |
| 582 | + // If pixel is not contained then set containment flag to false | |
| 583 | + // and break | |
| 584 | + if (!this->contains(dir)) { | |
| 585 | + contains = false; | |
| 586 | + break; | |
| 587 | + } | |
| 588 | + | |
| 589 | + } // endfor: looped over non-zero map indices | |
| 590 | + | |
| 591 | + } // endif: other region was of type "Map" | |
| 592 | + | |
| 562 | 593 | // ... otherwise throw an exception |
| 563 | 594 | else { |
| 564 | 595 | throw GException::feature_not_implemented(G_CONTAINS, |
| 565 | 596 | "Cannot compare to region type \""+reg.type()+"\" yet."); |
| 566 | 597 | } |
| 567 | 598 | |
| 568 | - // Return value | |
| 569 | - return fully_inside; | |
| 599 | + // Return containment flag | |
| 600 | + return contains; | |
| 570 | 601 | } |
| 571 | 602 | |
| 572 | 603 | |
| ... | ... | @@ -590,14 +621,13 @@ bool GSkyRegionCircle::overlaps(const GSkyRegion& reg) const |
| 590 | 621 | if (reg.type() == "Circle") { |
| 591 | 622 | |
| 592 | 623 | // Create circular region from reg |
| 593 | - const GSkyRegionCircle* regcirc = | |
| 594 | - dynamic_cast<const GSkyRegionCircle*>(®); | |
| 624 | + const GSkyRegionCircle* circle = dynamic_cast<const GSkyRegionCircle*>(®); | |
| 595 | 625 | |
| 596 | 626 | // Calculate angular distance between the centres |
| 597 | - double ang_dist = m_centre.dist_deg(regcirc->centre()); | |
| 627 | + double ang_dist = m_centre.dist_deg(circle->centre()); | |
| 598 | 628 | |
| 599 | 629 | // Check if the distance is smaller than the sum of both radii |
| 600 | - if (ang_dist <= (m_radius + regcirc->radius())) { | |
| 630 | + if (ang_dist <= (m_radius + circle->radius())) { | |
| 601 | 631 | overlap = true; |
| 602 | 632 | } |
| 603 | 633 | |
| ... | ... | @@ -607,11 +637,10 @@ bool GSkyRegionCircle::overlaps(const GSkyRegion& reg) const |
| 607 | 637 | else if (reg.type() == "Rect") { |
| 608 | 638 | |
| 609 | 639 | // Create rectangular region from reg |
| 610 | - const GSkyRegionRect* regrect = | |
| 611 | - dynamic_cast<const GSkyRegionRect*>(®); | |
| 640 | + const GSkyRegionRect* rect = dynamic_cast<const GSkyRegionRect*>(®); | |
| 612 | 641 | |
| 613 | 642 | // Check overlap with circle |
| 614 | - overlap = regrect->overlaps(*this); | |
| 643 | + overlap = rect->overlaps(*this); | |
| 615 | 644 | |
| 616 | 645 | } // endif: region was rectangle |
| 617 | 646 | |
| ... | ... | @@ -619,11 +648,10 @@ bool GSkyRegionCircle::overlaps(const GSkyRegion& reg) const |
| 619 | 648 | else if (reg.type() == "Map") { |
| 620 | 649 | |
| 621 | 650 | // Create map from reg |
| 622 | - const GSkyRegionMap* regmap = | |
| 623 | - dynamic_cast<const GSkyRegionMap*>(®); | |
| 651 | + const GSkyRegionMap* map = dynamic_cast<const GSkyRegionMap*>(®); | |
| 624 | 652 | |
| 625 | 653 | // Check overlap with circle |
| 626 | - overlap = regmap->overlaps(*this); | |
| 654 | + overlap = map->overlaps(*this); | |
| 627 | 655 | |
| 628 | 656 | } // endif: region was map |
| 629 | 657 | |
| ... | ... | @@ -638,7 +666,6 @@ bool GSkyRegionCircle::overlaps(const GSkyRegion& reg) const |
| 638 | 666 | } |
| 639 | 667 | |
| 640 | 668 | |
| 641 | - | |
| 642 | 669 | /*========================================================================== |
| 643 | 670 | = = |
| 644 | 671 | = Private methods = | ... | ... |
src/sky/GSkyRegionMap.cpp
| ... | ... | @@ -677,7 +677,7 @@ void GSkyRegionMap::set_region_rect(const GSkyRegionRect* rect) |
| 677 | 677 | for (int icorner = 0; icorner < 4; ++icorner) { |
| 678 | 678 | |
| 679 | 679 | // Get skydir of current corner |
| 680 | - GSkyDir corner = rect->get_corner(icorner); | |
| 680 | + GSkyDir corner = rect->corner(icorner); | |
| 681 | 681 | |
| 682 | 682 | // Compute polar props in global coords relative to rectangle centre |
| 683 | 683 | double dist = rect->centre().dist(corner); | ... | ... |
src/sky/GSkyRegionRect.cpp
| ... | ... | @@ -39,7 +39,7 @@ |
| 39 | 39 | #define G_READ "GSkyRegionRect::read(std::string&)" |
| 40 | 40 | #define G_CONTAINS "GSkyRegionRect::contains(GSkyRegion&)" |
| 41 | 41 | #define G_OVERLAPS "GSkyRegionRect::overlaps(GSkyRegion&)" |
| 42 | -#define G_GET_CORNER "GSkyRegionRect::get_corner(int&)" | |
| 42 | +#define G_CORNER "GSkyRegionRect::corner(int&)" | |
| 43 | 43 | |
| 44 | 44 | /* __ Macros _____________________________________________________________ */ |
| 45 | 45 | |
| ... | ... | @@ -102,8 +102,8 @@ GSkyRegionRect::GSkyRegionRect(const GSkyDir& centre, |
| 102 | 102 | /***********************************************************************//** |
| 103 | 103 | * @brief Right Ascension and Declination constructor |
| 104 | 104 | * |
| 105 | - * @param[in] ra Right Ascension of region centre [deg]. | |
| 106 | - * @param[in] dec Declination of region centre [deg]. | |
| 105 | + * @param[in] ra Right Ascension of region centre (degrees). | |
| 106 | + * @param[in] dec Declination of region centre (degrees). | |
| 107 | 107 | * @param[in] width Region width (degrees). |
| 108 | 108 | * @param[in] height Region height (degrees). |
| 109 | 109 | * @param[in] posang Position angle (degrees). |
| ... | ... | @@ -258,7 +258,7 @@ GSkyRegionRect* GSkyRegionRect::clone(void) const |
| 258 | 258 | /***********************************************************************//** |
| 259 | 259 | * @brief Set width of rectangular region |
| 260 | 260 | * |
| 261 | - * @param[in] width Width (degrees). | |
| 261 | + * @param[in] width Rectangle width (degrees). | |
| 262 | 262 | * |
| 263 | 263 | * @exception GException::invalid_argument |
| 264 | 264 | * Width value is less than 0. |
| ... | ... | @@ -291,7 +291,7 @@ void GSkyRegionRect::width(const double& width) |
| 291 | 291 | /***********************************************************************//** |
| 292 | 292 | * @brief Set height of rectangular region |
| 293 | 293 | * |
| 294 | - * @param[in] height Height (degrees). | |
| 294 | + * @param[in] height Rectangle height (degrees). | |
| 295 | 295 | * |
| 296 | 296 | * @exception GException::invalid_argument |
| 297 | 297 | * Height value is less than 0. |
| ... | ... | @@ -488,43 +488,14 @@ std::string GSkyRegionRect::write(void) const |
| 488 | 488 | ***************************************************************************/ |
| 489 | 489 | bool GSkyRegionRect::contains(const GSkyDir& dir) const |
| 490 | 490 | { |
| 491 | - // Compute sky direction in local coordinate system | |
| 492 | - GSkyDir locdir = transform_to_local(dir); | |
| 491 | + // Transform sky direction to local coordinate system | |
| 492 | + GSkyPixel local = dir_to_local(dir); | |
| 493 | 493 | |
| 494 | 494 | // Check containment using local coordinate system |
| 495 | - bool dir_is_in = contains_local(locdir); | |
| 495 | + bool contains = this->contains(local); | |
| 496 | 496 | |
| 497 | - // Return bool | |
| 498 | - return dir_is_in; | |
| 499 | -} | |
| 500 | - | |
| 501 | - | |
| 502 | -/***********************************************************************//** | |
| 503 | - * @brief Checks if local direction lies within region | |
| 504 | - * | |
| 505 | - * @param[in] locdir Sky direction in local coordinate system. | |
| 506 | - * | |
| 507 | - * A local direction lies within a region when its distance to the region | |
| 508 | - * centre is not larger than the region extension in both axes directions. | |
| 509 | - ***************************************************************************/ | |
| 510 | -bool GSkyRegionRect::contains_local(const GSkyDir& locdir) const | |
| 511 | -{ | |
| 512 | - // Initialise return value | |
| 513 | - bool dir_is_in = false; | |
| 514 | - | |
| 515 | - // Check containment: declination axis | |
| 516 | - if ((std::abs(locdir.dec_deg()) - 1.0e-10) <= 0.5 * m_height) { | |
| 517 | - | |
| 518 | - // Check containment: right ascension axis | |
| 519 | - if ((std::abs(locdir.ra_deg()) - 1.0e-10) <= 0.5 * m_width) { | |
| 520 | - | |
| 521 | - // Sky direction is inside the rectangle | |
| 522 | - dir_is_in = true; | |
| 523 | - } | |
| 524 | - } | |
| 525 | - | |
| 526 | - // Return bool | |
| 527 | - return dir_is_in; | |
| 497 | + // Return containment flag | |
| 498 | + return contains; | |
| 528 | 499 | } |
| 529 | 500 | |
| 530 | 501 | |
| ... | ... | @@ -539,60 +510,88 @@ bool GSkyRegionRect::contains_local(const GSkyDir& locdir) const |
| 539 | 510 | bool GSkyRegionRect::contains(const GSkyRegion& reg) const |
| 540 | 511 | { |
| 541 | 512 | // Initialise return value |
| 542 | - bool is_fully_inside = false; | |
| 513 | + bool contains = false; | |
| 543 | 514 | |
| 544 | - // If other region is circle use a simple way to calculate | |
| 515 | + // If the other region is a circle then check whether it is fully | |
| 516 | + // contained within the rectangle | |
| 545 | 517 | if (reg.type() == "Circle") { |
| 546 | 518 | |
| 547 | 519 | // Create circular region from reg |
| 548 | - const GSkyRegionCircle* regcirc = | |
| 549 | - dynamic_cast<const GSkyRegionCircle*>(®); | |
| 520 | + const GSkyRegionCircle* circle = dynamic_cast<const GSkyRegionCircle*>(®); | |
| 550 | 521 | |
| 551 | 522 | // Transform circle center to local coordinate system |
| 552 | - GSkyDir local_centre = transform_to_local(regcirc->centre()); | |
| 553 | - | |
| 554 | - // Get circle radius | |
| 555 | - const double circ_rad = regcirc->radius(); | |
| 556 | - | |
| 557 | - // Check extension of circle along declination axis | |
| 558 | - if ((std::abs(local_centre.dec_deg()) + circ_rad) <= 0.5 * m_height) { | |
| 523 | + GSkyPixel local = dir_to_local(circle->centre()); | |
| 524 | + double x_deg = local.x() * gammalib::rad2deg; | |
| 525 | + double y_deg = local.y() * gammalib::rad2deg; | |
| 559 | 526 | |
| 560 | - // Check extension of circle along right ascension axis | |
| 561 | - if ((std::abs(local_centre.ra_deg()) + circ_rad) <= 0.5 * m_width) { | |
| 527 | + // Get circle radius in degrees | |
| 528 | + double radius = circle->radius(); | |
| 562 | 529 | |
| 563 | - // Circle is fully contained in this rectangle | |
| 564 | - is_fully_inside = true; | |
| 530 | + // Check whether circle is contained within rectangle | |
| 531 | + if ((std::abs(y_deg) + radius) <= 0.5 * m_height) { | |
| 532 | + if ((std::abs(x_deg) + radius) <= 0.5 * m_width) { | |
| 533 | + contains = true; | |
| 565 | 534 | } |
| 566 | 535 | } |
| 567 | - } // Region was of type "Circle" | |
| 568 | 536 | |
| 569 | - // If other region is rectangle use a simple way to calculate | |
| 537 | + } // endif: other region was of type "Circle" | |
| 538 | + | |
| 539 | + // ... otherwise, if the other region is a rectangle then check whether | |
| 540 | + // all corners fall within the rectangle | |
| 570 | 541 | else if (reg.type() == "Rect") { |
| 571 | 542 | |
| 572 | 543 | // Create rectangular region from reg |
| 573 | - const GSkyRegionRect* regrect = | |
| 574 | - dynamic_cast<const GSkyRegionRect*>(®); | |
| 544 | + const GSkyRegionRect* rect = dynamic_cast<const GSkyRegionRect*>(®); | |
| 545 | + | |
| 546 | + // Initialise containment flag to true | |
| 547 | + contains = true; | |
| 575 | 548 | |
| 576 | 549 | // Loop over the four corners of the rectangle :regrect: |
| 577 | - for (int icorner = 0; icorner < 4; ++icorner) { | |
| 550 | + for (int i = 0; i < 4; ++i) { | |
| 578 | 551 | |
| 579 | - // Get skydir of current corner | |
| 580 | - GSkyDir corner = regrect->get_corner(icorner); | |
| 552 | + // Get sky direction of current corner | |
| 553 | + GSkyDir corner = rect->corner(i); | |
| 581 | 554 | |
| 582 | - // Check corner containment | |
| 583 | - if (!contains(corner)) { | |
| 555 | + // If corner is not contained then set containment flag to false | |
| 556 | + // and break | |
| 557 | + if (!this->contains(corner)) { | |
| 558 | + contains = false; | |
| 584 | 559 | break; |
| 585 | 560 | } |
| 586 | - // Did we arrive at the last corner? | |
| 587 | - else if (icorner == 3) { | |
| 588 | 561 | |
| 589 | - // As we reached this point, the three prior corners were inside | |
| 590 | - // and the last corner now is also inside: | |
| 591 | - // Rectangle is fully inside | |
| 592 | - is_fully_inside = true; | |
| 562 | + } // endfor: looped over the four corners | |
| 563 | + | |
| 564 | + } // endif: other region was of type "Rect" | |
| 565 | + | |
| 566 | + // ... otherwise, if the other region is a map then check whether it | |
| 567 | + // is contained within the rectangle | |
| 568 | + else if (reg.type() == "Map") { | |
| 569 | + | |
| 570 | + // Create map from reg | |
| 571 | + const GSkyRegionMap* map = dynamic_cast<const GSkyRegionMap*>(®); | |
| 572 | + | |
| 573 | + // Get non-zero indices | |
| 574 | + std::vector<int> indices = map->nonzero_indices(); | |
| 575 | + | |
| 576 | + // Initialise containment flag to true | |
| 577 | + contains = true; | |
| 578 | + | |
| 579 | + // Loop over all indices | |
| 580 | + for (int i = 0; i < indices.size(); ++i) { | |
| 581 | + | |
| 582 | + // Get sky direction of map pixel | |
| 583 | + GSkyDir dir = map->map().inx2dir(i); | |
| 584 | + | |
| 585 | + // If pixel is not contained then set containment flag to false | |
| 586 | + // and break | |
| 587 | + if (!this->contains(dir)) { | |
| 588 | + contains = false; | |
| 589 | + break; | |
| 593 | 590 | } |
| 594 | - } // Looped over the four corners | |
| 595 | - } // Region was of type "Rect" | |
| 591 | + | |
| 592 | + } // endfor: looped over non-zero map indices | |
| 593 | + | |
| 594 | + } // endif: other region was of type "Map" | |
| 596 | 595 | |
| 597 | 596 | // ... otherwise throw an exception |
| 598 | 597 | else { |
| ... | ... | @@ -600,8 +599,8 @@ bool GSkyRegionRect::contains(const GSkyRegion& reg) const |
| 600 | 599 | "Cannot compare to region type \""+reg.type()+"\" yet."); |
| 601 | 600 | } |
| 602 | 601 | |
| 603 | - // Return value | |
| 604 | - return is_fully_inside; | |
| 602 | + // Return containment flag | |
| 603 | + return contains; | |
| 605 | 604 | } |
| 606 | 605 | |
| 607 | 606 | |
| ... | ... | @@ -614,36 +613,34 @@ bool GSkyRegionRect::contains(const GSkyRegion& reg) const |
| 614 | 613 | * Regions differ in type. |
| 615 | 614 | * |
| 616 | 615 | * @todo Improve implementation for rectangle-rectangle |
| 617 | - * @todo Implement check for map | |
| 618 | 616 | ***************************************************************************/ |
| 619 | 617 | bool GSkyRegionRect::overlaps(const GSkyRegion& reg) const |
| 620 | 618 | { |
| 621 | 619 | // Initialise return value |
| 622 | 620 | bool overlap = false; |
| 623 | 621 | |
| 624 | - // If region is circle then check overlap between circle and rectangle | |
| 622 | + // If the region is a circle then check overlap between circle and | |
| 623 | + // rectangle | |
| 625 | 624 | if (reg.type() == "Circle") { |
| 626 | 625 | |
| 627 | 626 | // Create circular region from reg |
| 628 | - const GSkyRegionCircle* regcirc = | |
| 629 | - dynamic_cast<const GSkyRegionCircle*>(®); | |
| 627 | + const GSkyRegionCircle* circle = dynamic_cast<const GSkyRegionCircle*>(®); | |
| 630 | 628 | |
| 631 | 629 | // Transform circle center to local coordinate system |
| 632 | - GSkyDir local_centre = transform_to_local(regcirc->centre()); | |
| 633 | - | |
| 634 | - // Get circle radius | |
| 635 | - const double circ_rad = regcirc->radius(); | |
| 630 | + GSkyPixel local = dir_to_local(circle->centre()); | |
| 631 | + double x_deg = local.x() * gammalib::rad2deg; | |
| 632 | + double y_deg = local.y() * gammalib::rad2deg; | |
| 636 | 633 | |
| 637 | - // Check extension of circle along declination axis | |
| 638 | - if (std::abs(local_centre.dec_deg()) <= (0.5 * m_height + circ_rad)) { | |
| 634 | + // Get circle radius in degrees | |
| 635 | + double radius = circle->radius(); | |
| 639 | 636 | |
| 640 | - // Check extension of circle along right ascension axis | |
| 641 | - if (std::abs(local_centre.ra_deg()) <= (0.5 * m_width + circ_rad)) { | |
| 642 | - | |
| 643 | - // Circle is overlapping with rectangle | |
| 637 | + // Check whether circle overlaps within rectangle | |
| 638 | + if (std::abs(y_deg) <= (0.5 * m_height + radius)) { | |
| 639 | + if (std::abs(x_deg) <= (0.5 * m_width + radius)) { | |
| 644 | 640 | overlap = true; |
| 645 | 641 | } |
| 646 | 642 | } |
| 643 | + | |
| 647 | 644 | } // endif: region was of type "Circle" |
| 648 | 645 | |
| 649 | 646 | // ... otherwise if region is a rectangle then check overlap between |
| ... | ... | @@ -651,12 +648,11 @@ bool GSkyRegionRect::overlaps(const GSkyRegion& reg) const |
| 651 | 648 | else if (reg.type() == "Rect") { |
| 652 | 649 | |
| 653 | 650 | // Create rectangular region from reg |
| 654 | - const GSkyRegionRect* regrect = | |
| 655 | - dynamic_cast<const GSkyRegionRect*>(®); | |
| 651 | + const GSkyRegionRect* rect = dynamic_cast<const GSkyRegionRect*>(®); | |
| 656 | 652 | |
| 657 | 653 | // Dirty kludge: compare with map |
| 658 | - GSkyRegionMap regmap = GSkyRegionMap(regrect); | |
| 659 | - overlap = regmap.overlaps(*this); | |
| 654 | + GSkyRegionMap map = GSkyRegionMap(rect); | |
| 655 | + overlap = map.overlaps(*this); | |
| 660 | 656 | |
| 661 | 657 | } // endif: region was of type "Rect" |
| 662 | 658 | |
| ... | ... | @@ -664,11 +660,10 @@ bool GSkyRegionRect::overlaps(const GSkyRegion& reg) const |
| 664 | 660 | else if (reg.type() == "Map") { |
| 665 | 661 | |
| 666 | 662 | // Create map from reg |
| 667 | - const GSkyRegionMap* regmap = | |
| 668 | - dynamic_cast<const GSkyRegionMap*>(®); | |
| 663 | + const GSkyRegionMap* map = dynamic_cast<const GSkyRegionMap*>(®); | |
| 669 | 664 | |
| 670 | 665 | // Check overlap with circle |
| 671 | - overlap = regmap->overlaps(*this); | |
| 666 | + overlap = map->overlaps(*this); | |
| 672 | 667 | |
| 673 | 668 | } // endif: region was map |
| 674 | 669 | |
| ... | ... | @@ -684,99 +679,47 @@ bool GSkyRegionRect::overlaps(const GSkyRegion& reg) const |
| 684 | 679 | |
| 685 | 680 | |
| 686 | 681 | /***********************************************************************//** |
| 687 | - * @brief Transform a sky direction to the local cartesian coordinate system. | |
| 688 | - * | |
| 689 | - * @param[in] skydir Sky direction in global coordinate system. | |
| 690 | - * @return Sky direction in local cartesian region object coordinates. | |
| 691 | - * | |
| 692 | - * Transform the sky direction @p skydir to the local cartesian coordinate | |
| 693 | - * system. The origin of the local coordinate system is fixed to the center | |
| 694 | - * of the rectangle and aligned in +ra (width) and +dec (height). Please | |
| 695 | - * note, that a GSkyDir object is returned, even if the local coordsys is | |
| 696 | - * is cartesian. | |
| 697 | - ***************************************************************************/ | |
| 698 | -GSkyDir GSkyRegionRect::transform_to_local(const GSkyDir& skydir) const | |
| 699 | -{ | |
| 700 | - // Get distance and polar angle relative to rectangle centre | |
| 701 | - double dist = m_centre.dist(skydir); | |
| 702 | - double pa = m_centre.posang(skydir) - m_posang * gammalib::deg2rad; | |
| 703 | - | |
| 704 | - // Compute corresponding x and y coordinate from polar coords | |
| 705 | - double x = dist * std::sin(pa); | |
| 706 | - double y = dist * std::cos(pa); | |
| 707 | - | |
| 708 | - // Create output sky direction | |
| 709 | - GSkyDir transformed; | |
| 710 | - transformed.radec(x, y); | |
| 711 | - | |
| 712 | - // Return | |
| 713 | - return transformed; | |
| 714 | -} | |
| 715 | - | |
| 716 | - | |
| 717 | -/***********************************************************************//** | |
| 718 | - * @brief Transform a local coordinate to the global coordinate system. | |
| 719 | - * | |
| 720 | - * @param[in] locdir Direction in local coordinate system. | |
| 721 | - * @return Sky direction in global coordinate system. | |
| 722 | - * | |
| 723 | - * Transform the local direction @p locdir to the global coordinate system. | |
| 724 | - * The origin of the local coordinate system is fixed to the center of the | |
| 725 | - * rectangle and aligned in +ra (width) and +dec (height). | |
| 726 | - ***************************************************************************/ | |
| 727 | -GSkyDir GSkyRegionRect::transform_to_global(const GSkyDir& locdir) const | |
| 728 | -{ | |
| 729 | - // // Initialise centre in local coordinates (maybe make class member?) | |
| 730 | - GSkyDir centre_local; | |
| 731 | - centre_local.radec(0,0); | |
| 732 | - | |
| 733 | - // Access x and y in local coordsys | |
| 734 | - double x = locdir.ra(); | |
| 735 | - double y = locdir.dec(); | |
| 736 | - | |
| 737 | - // Compute dist and position angle in polar coords | |
| 738 | - double dist = std::sqrt(x*x + y*y); | |
| 739 | - double pa = gammalib::pihalf - std::atan2(y, x) + | |
| 740 | - m_posang * gammalib::deg2rad; | |
| 741 | - | |
| 742 | - // Create output global sky direction | |
| 743 | - GSkyDir transformed(m_centre); | |
| 744 | - transformed.rotate(pa, dist); | |
| 745 | - | |
| 746 | - // Return | |
| 747 | - return transformed; | |
| 748 | -} | |
| 749 | - | |
| 750 | - | |
| 751 | -/***********************************************************************//** | |
| 752 | - * @brief Get the sky direction of a corner of the rectangle, there are four. | |
| 682 | + * @brief Return sky direction of one corner of the rectangle | |
| 753 | 683 | * |
| 754 | 684 | * @param[in] index Corner index [0,3] |
| 755 | - * @return Sky direction of corner in global coordinate system. | |
| 685 | + * @return Sky direction of corner. | |
| 756 | 686 | * |
| 757 | 687 | * @exception GException::out_of_range |
| 758 | 688 | * Corner index is not in [0,3]. |
| 759 | 689 | * |
| 760 | - * The index counts CCW starting from +RA,+DEC: +R+D, +R-D, -R-D, -R+D. | |
| 690 | + * Returns the sky direction of one corner of the rectangle. The corner | |
| 691 | + * @p index is counted counterclockwise from the positive Right Ascension | |
| 692 | + * and Declination directions: | |
| 693 | + * | |
| 694 | + * * `index = 0` : \f$(\alpha + \frac{\rm width}{2}, \delta + \frac{\rm height}{2})\f$ | |
| 695 | + * * `index = 1` : \f$(\alpha + \frac{\rm width}{2}, \delta - \frac{\rm height}{2})\f$ | |
| 696 | + * * `index = 2` : \f$(\alpha - \frac{\rm width}{2}, \delta + \frac{\rm height}{2})\f$ | |
| 697 | + * * `index = 3` : \f$(\alpha - \frac{\rm width}{2}, \delta - \frac{\rm height}{2})\f$ | |
| 698 | + * | |
| 699 | + * where \f$\alpha\f$ and \f$\delta\f$ are the Right Ascension and | |
| 700 | + * Declination of the rectangle centre, and \f${\rm width}\f$ and | |
| 701 | + * \f${\rm height}\f$ are the width and height of the rectangle. | |
| 761 | 702 | ***************************************************************************/ |
| 762 | -GSkyDir GSkyRegionRect::get_corner(const int& index) const | |
| 703 | +GSkyDir GSkyRegionRect::corner(const int& index) const | |
| 763 | 704 | { |
| 764 | 705 | // Assert index is in [0,3] |
| 765 | 706 | if ((index < 0) || (index > 3)) { |
| 766 | - throw GException::out_of_range(G_GET_CORNER, "Corner index", index, 3); | |
| 707 | + throw GException::out_of_range(G_CORNER, "Corner index", index, 3); | |
| 767 | 708 | } |
| 768 | 709 | |
| 769 | - // Compute the offset to the corners | |
| 770 | - // Index counts CCW starting from +RA,+DEC: +R+D, +R-D, -R-D, -R+D | |
| 710 | + // Compute the offset to the corners in degrees | |
| 771 | 711 | double dx = 0.5 * m_width * (1 - 2*int(index >= 2)); |
| 772 | 712 | double dy = 0.5 * m_height * (1 - 2*int((index==1) || (index==2))); |
| 773 | 713 | |
| 774 | - // Define local corner sky direction | |
| 775 | - GSkyDir corner; | |
| 776 | - corner.radec_deg(dx,dy); | |
| 714 | + // Convert offset into radians | |
| 715 | + dx *= gammalib::deg2rad; | |
| 716 | + dy *= gammalib::deg2rad; | |
| 717 | + | |
| 718 | + // Define corner in local coordinates | |
| 719 | + GSkyPixel local(dx,dy); | |
| 777 | 720 | |
| 778 | 721 | // Transform to global sky direction |
| 779 | - corner = transform_to_global(corner); | |
| 722 | + GSkyDir corner = local_to_dir(local); | |
| 780 | 723 | |
| 781 | 724 | // Return |
| 782 | 725 | return corner; |
| ... | ... | @@ -871,7 +814,19 @@ void GSkyRegionRect::free_members(void) |
| 871 | 814 | |
| 872 | 815 | |
| 873 | 816 | /***********************************************************************//** |
| 874 | - * @brief Compute solid angle (sr) | |
| 817 | + * @brief Compute solid angle of rectangle | |
| 818 | + * | |
| 819 | + * This method computes the solid angle of the rectangle in steradians and | |
| 820 | + * stores the result in the `m_solid` member. | |
| 821 | + * | |
| 822 | + * The solid angle is computed using | |
| 823 | + * | |
| 824 | + * \f[ | |
| 825 | + * \Omega = {\rm width} \times {\rm height} | |
| 826 | + * \f] | |
| 827 | + * | |
| 828 | + * where \f${\rm width}\f$ and \f${\rm height}\f$ are the width and the | |
| 829 | + * height of the rectangle expressed in radians. | |
| 875 | 830 | ***************************************************************************/ |
| 876 | 831 | void GSkyRegionRect::compute_solid_angle(void) |
| 877 | 832 | { |
| ... | ... | @@ -881,3 +836,110 @@ void GSkyRegionRect::compute_solid_angle(void) |
| 881 | 836 | // Return |
| 882 | 837 | return; |
| 883 | 838 | } |
| 839 | + | |
| 840 | + | |
| 841 | +/***********************************************************************//** | |
| 842 | + * @brief Checks if local direction lies within region | |
| 843 | + * | |
| 844 | + * @param[in] locdir Sky direction in local coordinate system. | |
| 845 | + * | |
| 846 | + * A local direction lies within a region when its distance to the region | |
| 847 | + * centre is not larger than the region extension in both axes directions. | |
| 848 | + ***************************************************************************/ | |
| 849 | +bool GSkyRegionRect::contains(const GSkyPixel& local) const | |
| 850 | +{ | |
| 851 | + // Initialise return value | |
| 852 | + bool contains = false; | |
| 853 | + | |
| 854 | + // Get local y coordinate in degrees | |
| 855 | + double y = local.y() * gammalib::rad2deg; | |
| 856 | + | |
| 857 | + // Continue if the y coordinate is within half of the height | |
| 858 | + if ((std::abs(y) - 1.0e-10) <= 0.5 * m_height) { | |
| 859 | + | |
| 860 | + // Get local x coordinate in degrees | |
| 861 | + double x = local.x() * gammalib::rad2deg; | |
| 862 | + | |
| 863 | + // If the x coordinate is within half of the width the local | |
| 864 | + // coordinate is contained within the rectangle | |
| 865 | + if ((std::abs(x) - 1.0e-10) <= 0.5 * m_width) { | |
| 866 | + contains = true; | |
| 867 | + } | |
| 868 | + | |
| 869 | + } // endif: y coordinate is within half of the height | |
| 870 | + | |
| 871 | + // Return containment | |
| 872 | + return contains; | |
| 873 | +} | |
| 874 | + | |
| 875 | + | |
| 876 | +/***********************************************************************//** | |
| 877 | + * @brief Transform sky direction to local rectangle coordinates | |
| 878 | + * | |
| 879 | + * @param[in] dir Sky direction. | |
| 880 | + * @return Local cartesian region object coordinates. | |
| 881 | + * | |
| 882 | + * Transform the sky direction @p dir to the local cartesian coordinate | |
| 883 | + * system. The local coordinates \f$(x,y)\f$ are defined by | |
| 884 | + * | |
| 885 | + * \f[ | |
| 886 | + * x = d \sin(\phi) | |
| 887 | + * \f] | |
| 888 | + * | |
| 889 | + * and | |
| 890 | + * | |
| 891 | + * \f[ | |
| 892 | + * y = d \cos(\phi) | |
| 893 | + * \f] | |
| 894 | + * | |
| 895 | + * where \f$d\f$ is the angular distance between the sky direction @p dir | |
| 896 | + * and the centre of the rectangle in radians, and \f$\phi\f$ is the | |
| 897 | + * position angle of the sky direction @p dir with respect to the position | |
| 898 | + * angle of the rectangle, computed counter clockwise. | |
| 899 | + ***************************************************************************/ | |
| 900 | +GSkyPixel GSkyRegionRect::dir_to_local(const GSkyDir& dir) const | |
| 901 | +{ | |
| 902 | + // Get distance and polar angle relative to rectangle centre | |
| 903 | + double dist = m_centre.dist(dir); | |
| 904 | + double pa = m_centre.posang(dir) - m_posang * gammalib::deg2rad; | |
| 905 | + | |
| 906 | + // Compute corresponding x and y coordinate from polar coords | |
| 907 | + double x = dist * std::sin(pa); | |
| 908 | + double y = dist * std::cos(pa); | |
| 909 | + | |
| 910 | + // Create local coordinates | |
| 911 | + GSkyPixel local(x,y); | |
| 912 | + | |
| 913 | + // Return local coordinates | |
| 914 | + return local; | |
| 915 | +} | |
| 916 | + | |
| 917 | + | |
| 918 | +/***********************************************************************//** | |
| 919 | + * @brief Transform local rectangle coordinates to sky direction | |
| 920 | + * | |
| 921 | + * @param[in] local Local rectangle coordinates. | |
| 922 | + * @return Sky direction. | |
| 923 | + * | |
| 924 | + * Transform the local coordinates @p local to a sky direction. See | |
| 925 | + * GSkyRegionRect::dir_to_local for the relation between local rectangle | |
| 926 | + * coordinates and the sky direction. | |
| 927 | + ***************************************************************************/ | |
| 928 | +GSkyDir GSkyRegionRect::local_to_dir(const GSkyPixel& local) const | |
| 929 | +{ | |
| 930 | + // Get local coordinates (radians) | |
| 931 | + double x = local.x(); | |
| 932 | + double y = local.y(); | |
| 933 | + | |
| 934 | + // Compute dist and position angle in polar coords | |
| 935 | + double dist = std::sqrt(x*x + y*y); | |
| 936 | + double pa = gammalib::pihalf - std::atan2(y, x) + | |
| 937 | + m_posang * gammalib::deg2rad; | |
| 938 | + | |
| 939 | + // Create output global sky direction | |
| 940 | + GSkyDir dir(m_centre); | |
| 941 | + dir.rotate(pa, dist); | |
| 942 | + | |
| 943 | + // Return sky direction | |
| 944 | + return dir; | |
| 945 | +} | ... | ... |
test/test_GSky.cpp
| ... | ... | @@ -1983,35 +1983,37 @@ void TestGSky::test_GSkyRegionRect(void) |
| 1983 | 1983 | test_assert(!refregion.contains(test_dir_2),"test for containment"); |
| 1984 | 1984 | |
| 1985 | 1985 | // Corners |
| 1986 | - test_assert(refregion.contains(refregion.get_corner(0)),"test for corner containment"); | |
| 1987 | - test_assert(refregion.contains(refregion.get_corner(1)),"test for corner containment"); | |
| 1988 | - test_assert(refregion.contains(refregion.get_corner(2)),"test for corner containment"); | |
| 1989 | - test_assert(refregion.contains(refregion.get_corner(3)),"test for corner containment"); | |
| 1986 | + test_assert(refregion.contains(refregion.corner(0)),"test for corner containment"); | |
| 1987 | + test_assert(refregion.contains(refregion.corner(1)),"test for corner containment"); | |
| 1988 | + test_assert(refregion.contains(refregion.corner(2)),"test for corner containment"); | |
| 1989 | + test_assert(refregion.contains(refregion.corner(3)),"test for corner containment"); | |
| 1990 | 1990 | |
| 1991 | 1991 | |
| 1992 | 1992 | // Check GSkyDir containment for rotated rectangle |
| 1993 | 1993 | GSkyRegionRect refregion_rot(refdir_radeczerozero, 10, 10, 45); |
| 1994 | 1994 | |
| 1995 | 1995 | // Check corner containment |
| 1996 | - test_assert(refregion_rot.contains(refregion_rot.get_corner(0)),"test for corner containment"); | |
| 1997 | - test_assert(refregion_rot.contains(refregion_rot.get_corner(1)),"test for corner containment"); | |
| 1998 | - test_assert(refregion_rot.contains(refregion_rot.get_corner(2)),"test for corner containment"); | |
| 1999 | - test_assert(refregion_rot.contains(refregion_rot.get_corner(3)),"test for corner containment"); | |
| 1996 | + test_assert(refregion_rot.contains(refregion_rot.corner(0)),"test for corner containment"); | |
| 1997 | + test_assert(refregion_rot.contains(refregion_rot.corner(1)),"test for corner containment"); | |
| 1998 | + test_assert(refregion_rot.contains(refregion_rot.corner(2)),"test for corner containment"); | |
| 1999 | + test_assert(refregion_rot.contains(refregion_rot.corner(3)),"test for corner containment"); | |
| 2000 | 2000 | |
| 2001 | 2001 | // Check GSkyDir containment |
| 2002 | - test_dir_0.radec_deg(refregion_rot.get_corner(0).ra_deg()+1, 0); | |
| 2003 | - test_dir_1.radec_deg(refregion_rot.get_corner(0).ra_deg() , 0); | |
| 2004 | - test_dir_2.radec_deg(refregion_rot.get_corner(0).ra_deg()-1, 0); | |
| 2002 | + test_dir_0.radec_deg(refregion_rot.corner(0).ra_deg()+1, 0); | |
| 2003 | + test_dir_1.radec_deg(refregion_rot.corner(0).ra_deg() , 0); | |
| 2004 | + test_dir_2.radec_deg(refregion_rot.corner(0).ra_deg()-1, 0); | |
| 2005 | 2005 | test_assert(!refregion_rot.contains(test_dir_0),"test for containment"); |
| 2006 | 2006 | test_assert(refregion_rot.contains(test_dir_1),"test for containment"); |
| 2007 | 2007 | test_assert(refregion_rot.contains(test_dir_2),"test for containment"); |
| 2008 | 2008 | |
| 2009 | 2009 | // Check local<->global coordinate transformations |
| 2010 | + /* | |
| 2010 | 2011 | test_dir_0.radec_deg(50,50); |
| 2011 | 2012 | test_dir_1 = refregion_rot.transform_to_local(test_dir_0); |
| 2012 | 2013 | test_dir_2 = refregion_rot.transform_to_global(test_dir_1); |
| 2013 | 2014 | test_value(test_dir_0.ra(), test_dir_2.ra(), 1.0e-10, "Test coord trafo"); |
| 2014 | 2015 | test_value(test_dir_0.dec(), test_dir_2.dec(), 1.0e-10, "Test coord trafo"); |
| 2016 | + */ | |
| 2015 | 2017 | |
| 2016 | 2018 | // Check other rects containment |
| 2017 | 2019 | GSkyDir refdir_raoffset = GSkyDir(); | ... | ... |