LCOV - code coverage report
Current view: top level - imageanalysis/Annotations - AnnEllipse.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 42 100 42.0 %
Date: 2024-12-11 20:54:31 Functions: 3 10 30.0 %

          Line data    Source code
       1             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       2             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
       3             : //# License for more details.
       4             : //#
       5             : //# You should have received a copy of the GNU Library General Public License
       6             : //# along with this library; if not, write to the Free Software Foundation,
       7             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
       8             : //#
       9             : //# Correspondence concerning AIPS++ should be addressed as follows:
      10             : //#        Internet email: casa-feedback@nrao.edu.
      11             : //#        Postal address: AIPS++ Project Office
      12             : //#                        National Radio Astronomy Observatory
      13             : //#                        520 Edgemont Road
      14             : //#                        Charlottesville, VA 22903-2475 USA
      15             : //#
      16             : 
      17             : #include <imageanalysis/Annotations/AnnEllipse.h>
      18             : 
      19             : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
      20             : #include <casacore/casa/Quanta/QLogical.h>
      21             : #include <casacore/images/Regions/WCEllipsoid.h>
      22             : 
      23             : using namespace casacore;
      24             : namespace casa {
      25             : 
      26          90 : AnnEllipse::AnnEllipse(
      27             :         const Quantity& xcenter, const Quantity& ycenter,
      28             :         const Quantity& semiMajorAxis,
      29             :         const Quantity& semiMinorAxis, const Quantity& positionAngle,
      30             :         const String& dirRefFrameString,
      31             :         const CoordinateSystem& csys,
      32             :         const IPosition& imShape,
      33             :         const Quantity& beginFreq,
      34             :         const Quantity& endFreq,
      35             :         const String& freqRefFrameString,
      36             :         const String& dopplerString,
      37             :         const Quantity& restfreq,
      38             :         const Vector<Stokes::StokesTypes> stokes,
      39             :         const Bool annotationOnly,
      40             :         const Bool requireImageRegion
      41          90 : ) : AnnRegion(
      42             :                 ELLIPSE, dirRefFrameString, csys, imShape, beginFreq,
      43             :                 endFreq, freqRefFrameString, dopplerString,
      44             :                 restfreq, stokes, annotationOnly, requireImageRegion
      45          90 : ), _inputCenter(AnnotationBase::Direction(1)), _inputSemiMajorAxis(semiMajorAxis),
      46          90 :         _inputSemiMinorAxis(semiMinorAxis),
      47         180 :         _inputPositionAngle(positionAngle) {
      48          90 :         _init(xcenter, ycenter);
      49          90 : }
      50             : 
      51         393 : AnnEllipse::AnnEllipse(
      52             :         const Quantity& xcenter, const Quantity& ycenter,
      53             :         const Quantity& semiMajorAxis,
      54             :         const Quantity& semiMinorAxis, const Quantity& positionAngle,
      55             :         const CoordinateSystem& csys,
      56             :         const IPosition& imShape,
      57             :         const Vector<Stokes::StokesTypes>& stokes,
      58             :         const Bool requireImageRegion
      59         393 : ) : AnnRegion(ELLIPSE, csys, imShape, stokes, requireImageRegion),
      60         393 :         _inputCenter(AnnotationBase::Direction(1)), _inputSemiMajorAxis(semiMajorAxis),
      61         393 :         _inputSemiMinorAxis(semiMinorAxis),
      62         786 :         _inputPositionAngle(positionAngle) {
      63         393 :         _init(xcenter, ycenter);
      64         393 : }
      65             : 
      66           0 : AnnEllipse& AnnEllipse::operator= (
      67             :         const AnnEllipse& other
      68             : ) {
      69           0 :         if (this == &other) {
      70           0 :                 return *this;
      71             :         }
      72           0 :         AnnRegion::operator=(other);
      73           0 :         _inputCenter.resize(other._inputCenter.nelements());
      74           0 :         _inputCenter = other._inputCenter;
      75           0 :         _inputSemiMajorAxis = other._inputSemiMajorAxis;
      76           0 :         _inputSemiMinorAxis = other._inputSemiMinorAxis;
      77           0 :         _inputPositionAngle = other._inputPositionAngle;
      78           0 :         _convertedSemiMajorAxis = other._convertedSemiMajorAxis;
      79           0 :         _convertedSemiMinorAxis = other._convertedSemiMinorAxis;
      80           0 :         _convertedPositionAngle = other._convertedPositionAngle;
      81           0 :         return *this;
      82             : }
      83             : 
      84           0 : Bool AnnEllipse::operator== (
      85             :         const AnnEllipse& other
      86             : )const {
      87           0 :         if (this == &other) {
      88           0 :                 return true;
      89             :         }
      90           0 :         return AnnRegion::operator==(other)
      91           0 :                 && allTrue(_inputCenter == other._inputCenter)
      92           0 :                 && _inputSemiMajorAxis == other._inputSemiMajorAxis
      93           0 :                 && _inputSemiMinorAxis == other._inputSemiMinorAxis
      94           0 :                 && _inputPositionAngle == other._inputPositionAngle
      95           0 :                 && _convertedSemiMajorAxis == other._convertedSemiMajorAxis
      96           0 :                 && _convertedSemiMinorAxis == other._convertedSemiMinorAxis
      97           0 :                 && _convertedPositionAngle == other._convertedPositionAngle;
      98             : }
      99             : 
     100           0 : MDirection AnnEllipse::getCenter() const {
     101           0 :         return getConvertedDirections()[0];
     102             : }
     103             : 
     104           0 : Quantity AnnEllipse::getSemiMajorAxis() const {
     105           0 :         return _convertedSemiMajorAxis;
     106             : }
     107             : 
     108           0 : Quantity AnnEllipse::getSemiMinorAxis() const {
     109           0 :         return _convertedSemiMinorAxis;
     110             : }
     111             : 
     112           0 : Quantity AnnEllipse::getPositionAngle() const {
     113           0 :         return _convertedPositionAngle;
     114             : }
     115             : 
     116           0 : ostream& AnnEllipse::print(ostream &os) const {
     117           0 :         _printPrefix(os);
     118           0 :         os << "ellipse [["
     119           0 :                 << _printDirection(_inputCenter[0].first, _inputCenter[0].second)
     120           0 :                 << "], [" << _toArcsec(_inputSemiMajorAxis)
     121           0 :                 << ", " << _toArcsec(_inputSemiMinorAxis) << "], "
     122           0 :                 << _toDeg(_inputPositionAngle) << "]";
     123           0 :         _printPairs(os);
     124           0 :         return os;
     125             : }
     126             : 
     127         483 : void AnnEllipse::_init(
     128             :         const Quantity& xcenter, const Quantity& ycenter
     129             : ) {
     130         483 :         ThrowIf(
     131             :                 ! _inputPositionAngle.isConform("rad"),
     132             :                 "Position angle must have angular units"
     133             :         );
     134         483 :         ThrowIf(
     135             :                 _inputSemiMajorAxis.getUnit() == "pix"
     136             :                 && ! getCsys().directionCoordinate().hasSquarePixels()
     137             :                 && (
     138             :                         ! casacore::near(fmod(_inputPositionAngle.getValue("rad"), C::pi), 0.0)
     139             :                         && ! casacore::near(fmod(fabs(_inputPositionAngle.getValue("rad")), C::pi), C::pi_2)
     140             :                 ),
     141             :                 "When pixels are not square and units are expressed in "
     142             :                 "pixels, position angle must be zero"
     143             :         );
     144         483 :         const CoordinateSystem csys = getCsys();
     145         483 :         uInt x = csys.isDirectionAbscissaLongitude() ? 0 : 1;
     146         483 :         uInt y = x == 0 ? 1 : 0;
     147         483 :         _convertedSemiMajorAxis = _lengthToAngle(_inputSemiMajorAxis, _getDirectionAxes()[y]);
     148         483 :         _convertedSemiMinorAxis = _lengthToAngle(_inputSemiMinorAxis, _getDirectionAxes()[x]);
     149         483 :         _convertedPositionAngle = _inputPositionAngle;
     150         483 :         if (
     151         483 :                 csys.directionCoordinate().directionType() != _getDirectionRefFrame()
     152             :         ) {
     153           0 :                 Quantity angle;
     154           0 :                 csys.directionCoordinate().convert(angle, _getDirectionRefFrame());
     155             :                 // add the clockwise angle rather than subtract because the pixel
     156             :                 // axes are aligned with the "from" (current) world coordinate system rather
     157             :                 // than the "to" world coordinate system
     158           0 :                 _convertedPositionAngle += angle;
     159           0 :         }
     160         483 :         if (_convertedSemiMajorAxis < _convertedSemiMinorAxis) {
     161           0 :                 std::swap(_convertedSemiMajorAxis, _convertedSemiMinorAxis);
     162           0 :                 _convertedPositionAngle = Quantity(
     163           0 :                         std::fmod(
     164           0 :                                 (_inputPositionAngle + Quantity(C::pi_2, "rad")).getValue("rad"),
     165             :                                 C::pi),
     166             :                         "rad"
     167           0 :                 );
     168           0 :                 _convertedPositionAngle.convert(_inputPositionAngle);
     169             :         }
     170         483 :         _inputCenter[0].first = xcenter;
     171         483 :         _inputCenter[0].second = ycenter;
     172             : 
     173         483 :         _checkAndConvertDirections(String(__func__), _inputCenter);
     174             : 
     175         966 :         Vector<Double> coords = getConvertedDirections()[0].getAngle("rad").getValue();
     176             : 
     177         483 :         Vector<Quantity> qCenter(2);
     178         483 :         qCenter[0] = Quantity(coords[0], "rad");
     179         483 :         qCenter[1] = Quantity(coords[1], "rad");
     180             : 
     181             :         // WCEllipsoid expects the angle to the major axis to be relative to the positive x
     182             :         // axis. Astronomers however measure the position angle relative to north (positive y axis usually).
     183         966 :         Quantity relToXAxis = _convertedPositionAngle + Quantity(90, "deg");
     184             : 
     185             :         try {
     186             :                 WCEllipsoid ellipse(
     187         483 :                         qCenter[0], qCenter[1],
     188         483 :                         _convertedSemiMajorAxis, _convertedSemiMinorAxis, relToXAxis,
     189         966 :                         _getDirectionAxes()[0], _getDirectionAxes()[1], getCsys()
     190        1932 :                 );
     191         483 :                 _setDirectionRegion(ellipse);
     192         483 :                 _extend();
     193         483 :         } catch (const ToLCRegionConversionError& err) {
     194           0 :                 if (_requireImageRegion) {
     195           0 :                         throw(err);
     196             :                 } else {
     197           0 :                         ImageRegion defaultRegion;
     198           0 :                         _setDirectionRegion(defaultRegion);
     199           0 :                         _imageRegion = _directionRegion;
     200           0 :                 }
     201           0 :         }
     202         483 : }
     203             : 
     204             : }

Generated by: LCOV version 1.16