LCOV - code coverage report
Current view: top level - imageanalysis/Annotations - AnnotationBase.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 0 687 0.0 %
Date: 2023-11-02 14:27:30 Functions: 0 74 0.0 %

          Line data    Source code
       1             : //# GaussianShape.cc:
       2             : //# Copyright (C) 1998,1999,2000
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: aips2-request@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : 
      27             : #include <imageanalysis/Annotations/AnnotationBase.h>
      28             : 
      29             : #include <casacore/casa/Exceptions/Error.h>
      30             : #include <casacore/casa/Quanta/MVAngle.h>
      31             : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
      32             : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
      33             : #include <casacore/measures/Measures/MCDirection.h>
      34             : #include <casacore/measures/Measures/VelocityMachine.h>
      35             : #include <casacore/casa/Quanta/UnitMap.h>
      36             : 
      37             : #include <iomanip>
      38             : 
      39             : using namespace std;
      40             : 
      41             : using namespace casacore;
      42             : namespace casa {
      43             : 
      44             : const AnnotationBase::RGB AnnotationBase::BLACK(3, 0.0);
      45             : const AnnotationBase::RGB AnnotationBase::BLUE{0.0,0.0,255.0};
      46             : const AnnotationBase::RGB AnnotationBase::CYAN{255.0,255.0,0.0};
      47             : const AnnotationBase::RGB AnnotationBase::GRAY{190.0,190.0,190.0};
      48             : const AnnotationBase::RGB AnnotationBase::GREEN{0.0,255.0,0.0};
      49             : const AnnotationBase::RGB AnnotationBase::MAGENTA{255.0,0.0,255.0};
      50             : const AnnotationBase::RGB AnnotationBase::ORANGE{255.0,165.0,0.0};
      51             : const AnnotationBase::RGB AnnotationBase::RED{255.0,0.0,0.0};
      52             : const AnnotationBase::RGB AnnotationBase::WHITE(3, 255.0);
      53             : const AnnotationBase::RGB AnnotationBase::YELLOW{255.0,255.0,0.0};
      54             : 
      55             : const String AnnotationBase::DEFAULT_LABEL = "";
      56             : const AnnotationBase::RGB AnnotationBase::DEFAULT_COLOR = AnnotationBase::GREEN;
      57             : const AnnotationBase::LineStyle AnnotationBase::DEFAULT_LINESTYLE = AnnotationBase::SOLID;
      58             : const uInt AnnotationBase::DEFAULT_LINEWIDTH = 1;
      59             : const uInt AnnotationBase::DEFAULT_SYMBOLSIZE = 1;
      60             : const uInt AnnotationBase::DEFAULT_SYMBOLTHICKNESS = 1;
      61             : const String AnnotationBase::DEFAULT_FONT = "Helvetica";
      62             : const uInt AnnotationBase::DEFAULT_FONTSIZE = 10;
      63             : const AnnotationBase::FontStyle AnnotationBase::DEFAULT_FONTSTYLE = AnnotationBase::BOLD;
      64             : const Bool AnnotationBase::DEFAULT_USETEX = false;
      65             : const AnnotationBase::RGB AnnotationBase::DEFAULT_LABELCOLOR = AnnotationBase::GREEN;
      66             : const String AnnotationBase::DEFAULT_LABELPOS = "top";
      67             : const vector<Int> AnnotationBase::DEFAULT_LABELOFF = vector<Int>(2, 0);
      68             : 
      69             : const String AnnotationBase::_class = "AnnotationBase";
      70             : 
      71             : std::list<string> AnnotationBase::_colorNames;
      72             : 
      73             : Bool AnnotationBase::_doneUnitInit = false;
      74             : Bool AnnotationBase::_doneColorInit = false;
      75             : 
      76             : map<String, AnnotationBase::Type> AnnotationBase::_typeMap;
      77             : map<String, AnnotationBase::LineStyle> AnnotationBase::_lineStyleMap;
      78             : 
      79             : map<string, AnnotationBase::RGB> AnnotationBase::_colors;
      80             : map<AnnotationBase::RGB, string> AnnotationBase::_rgbNameMap;
      81             : 
      82             : const Regex AnnotationBase::rgbHexRegex("([0-9]|[a-f]){6}");
      83             : 
      84             : 
      85           0 : AnnotationBase::AnnotationBase(
      86             :         const Type type, const String& dirRefFrameString,
      87             :         const CoordinateSystem& csys, const Quantity& beginFreq,
      88             :         const Quantity& endFreq,
      89             :         const String& freqRefFrame,
      90             :         const String& dopplerString,
      91             :         const Quantity& restfreq,
      92             :         const Vector<Stokes::StokesTypes>& stokes
      93           0 : )
      94             : : _type(type), _csys(csys), _label(DEFAULT_LABEL),_font(DEFAULT_FONT),
      95             :   _labelPos(DEFAULT_LABELPOS), _color(DEFAULT_COLOR), _labelColor(DEFAULT_LABELCOLOR),
      96             :   _fontstyle(DEFAULT_FONTSTYLE), _linestyle(DEFAULT_LINESTYLE), _fontsize(DEFAULT_FONTSIZE),
      97             :   _linewidth(DEFAULT_LINEWIDTH), _symbolsize(DEFAULT_SYMBOLSIZE),
      98             :   _symbolthickness(DEFAULT_SYMBOLTHICKNESS), _usetex(DEFAULT_USETEX),
      99             : 
     100             :   _convertedFreqLimits(0), _stokes(stokes),
     101             :   _globals(map<Keyword, Bool>()), _params(map<Keyword, String>()),
     102           0 :   _printGlobals(false), _labelOff(DEFAULT_LABELOFF) {
     103           0 :         ThrowIf(
     104             :                 ! csys.hasDirectionCoordinate(),
     105             :                 "Coordinate system has no direction coordinate"
     106             :         );
     107             :         const uInt *oname;
     108             :         Int nall, nex;
     109           0 :         const auto *tname = MDirection::allMyTypes(nall, nex, oname);
     110             :         // Because MDirection::getType() only does minimal match, bogus strings
     111             :         // can tacitly be let through, so we do a more rigorous check here.
     112           0 :         ThrowIf(
     113             :                 find( tname, tname+nall, dirRefFrameString) == tname+nall,
     114             :                 "Unknown direction reference frame '" + dirRefFrameString + "'"
     115             :         );
     116           0 :         ThrowIf (
     117             :                 ! MDirection::getType(_directionRefFrame, dirRefFrameString),
     118             :                 "Unknown direction reference frame " + dirRefFrameString
     119             :         );
     120           0 :         setFrequencyLimits(
     121             :                 beginFreq, endFreq, freqRefFrame,
     122             :                 dopplerString, restfreq
     123             :         );
     124           0 :         _init();
     125           0 : }
     126             : 
     127           0 : AnnotationBase::AnnotationBase(
     128             :         const Type type, const CoordinateSystem& csys,
     129             :         const Vector<Stokes::StokesTypes>& stokes
     130           0 : )
     131             : : _type(type), _csys(csys), _label(DEFAULT_LABEL),
     132             :   _font(DEFAULT_FONT), _labelPos(DEFAULT_LABELPOS),
     133             :   _color(DEFAULT_COLOR), _labelColor(DEFAULT_LABELCOLOR),
     134             :   _fontstyle(DEFAULT_FONTSTYLE), _linestyle(DEFAULT_LINESTYLE),
     135             :   _fontsize(DEFAULT_FONTSIZE),
     136             :   _linewidth(DEFAULT_LINEWIDTH), _symbolsize(DEFAULT_SYMBOLSIZE),
     137             :   _symbolthickness(DEFAULT_SYMBOLTHICKNESS), _usetex(DEFAULT_USETEX),
     138             :   _convertedFreqLimits(0), _beginFreq(Quantity(0, "Hz")), _endFreq(Quantity(0, "Hz")),
     139             :         _restFreq(Quantity(0, "Hz")), _stokes(stokes),
     140             :   _globals(map<Keyword, Bool>()), _params(map<Keyword, String>()),
     141           0 :   _printGlobals(false), _labelOff(DEFAULT_LABELOFF)
     142             :  {
     143           0 :         String preamble = String(__FUNCTION__) + ": ";
     144           0 :         if (!csys.hasDirectionCoordinate()) {
     145             :                 throw AipsError(
     146           0 :                         preamble + "Coordinate system has no direction coordinate"
     147           0 :                 );
     148             :         }
     149           0 :         _directionRefFrame = _csys.directionCoordinate().directionType();
     150           0 :         _init();
     151           0 : }
     152             : 
     153           0 : AnnotationBase::~AnnotationBase() {}
     154             : 
     155           0 : AnnotationBase& AnnotationBase::operator= (
     156             :         const AnnotationBase& other
     157             : ) {
     158           0 :     if (this == &other) {
     159           0 :         return *this;
     160             :     }
     161           0 :     _type = other._type;
     162           0 :     _directionRefFrame = other._directionRefFrame;
     163           0 :     _csys = other._csys;
     164           0 :     _directionAxes.resize(other._directionAxes.nelements());
     165           0 :     _directionAxes = other._directionAxes;
     166           0 :     _convertedFreqLimits.assign(other._convertedFreqLimits);
     167           0 :     _beginFreq = other._beginFreq;
     168           0 :     _endFreq = other._endFreq;
     169           0 :     _restFreq = other._restFreq;
     170           0 :     _stokes.assign(other._stokes);
     171           0 :     _freqRefFrame = other._freqRefFrame;
     172           0 :     _dopplerType = other._dopplerType;
     173           0 :     _label = other._label;
     174           0 :     _color = other._color;
     175           0 :     _font = other._font;
     176           0 :     _fontsize = other._fontsize;
     177           0 :     _fontstyle = other._fontstyle;
     178           0 :     _linestyle = other._linestyle;
     179           0 :     _linewidth = other._linewidth;
     180           0 :     _symbolsize = other._symbolsize;
     181           0 :     _symbolthickness = other._symbolthickness;
     182           0 :     _usetex = other._usetex;
     183           0 :     _convertedDirections.assign(other._convertedDirections);
     184           0 :     _globals = other._globals;
     185           0 :     _params = other._params;
     186           0 :     _printGlobals = other._printGlobals;
     187           0 :     return *this;
     188             : }
     189             : 
     190           0 : void AnnotationBase::_init() {
     191           0 :         String preamble = _class + ": " + String(__FUNCTION__) + ": ";
     192           0 :         _initColors();
     193           0 :         if (
     194           0 :                 _directionRefFrame != _csys.directionCoordinate().directionType(false)
     195           0 :                 && _directionRefFrame != MDirection::B1950
     196           0 :                 && _directionRefFrame != MDirection::B1950_VLA
     197           0 :                 && _directionRefFrame != MDirection::BMEAN
     198           0 :                 && _directionRefFrame != MDirection::DEFAULT
     199           0 :                 && _directionRefFrame != MDirection::ECLIPTIC
     200           0 :                 && _directionRefFrame != MDirection::GALACTIC
     201           0 :                 && _directionRefFrame != MDirection::J2000
     202           0 :                 && _directionRefFrame != MDirection::SUPERGAL
     203           0 :                 && _directionRefFrame != MDirection::ICRS
     204             :         ) {
     205             :                 throw AipsError(preamble
     206           0 :                         + "Unsupported coordinate frame for regions "
     207           0 :                         + MDirection::showType(_directionRefFrame)
     208           0 :                 );
     209             :         }
     210           0 :         _params[COORD] = MDirection::showType(_directionRefFrame);
     211           0 :         _directionAxes = IPosition(_csys.directionAxesNumbers());
     212             : 
     213           0 :         uInt nStokes = _stokes.size();
     214           0 :         if (nStokes > 0) {
     215           0 :                 ostringstream os;
     216           0 :                 os << "[";
     217           0 :                 for (uInt i=0; i< nStokes; i++) {
     218           0 :                         os << Stokes::name(_stokes[i]);
     219           0 :                         if (i != _stokes.size() - 1) {
     220           0 :                                 os << ", ";
     221             :                         }
     222             :                 }
     223           0 :                 os << "]";
     224           0 :                 _params[CORR] = os.str();
     225             :         }
     226           0 :         for(uInt i=0; i<N_KEYS; i++) {
     227           0 :                 _globals[(Keyword)i] = false;
     228             :         }
     229           0 :         _initParams();
     230           0 : }
     231             : 
     232           0 : void AnnotationBase::_initParams() {
     233           0 :         _params[LINEWIDTH] = String::toString(_linewidth);
     234           0 :         _params[LINESTYLE] = lineStyleToString(_linestyle);
     235           0 :         _params[SYMSIZE] = String::toString(_symbolsize);
     236           0 :         _params[SYMTHICK] = String::toString(_symbolthickness);
     237           0 :         _params[COLOR] = getColorString();
     238           0 :         _params[FONT] = _font;
     239           0 :         _params[FONTSIZE] = String::toString(_fontsize);
     240           0 :         _params[FONTSTYLE] = fontStyleToString(_fontstyle);
     241           0 :         _params[USETEX] = _usetex ? "true" : "false";
     242           0 :         if (! _label.empty()) {
     243           0 :                 _params[LABEL] = _label;
     244             :         }
     245           0 : }
     246             : 
     247           0 : void AnnotationBase::unitInit() {
     248           0 :         if (! _doneUnitInit) {
     249           0 :                 UnitMap::putUser("pix",UnitVal(1.0), "pixel units");
     250           0 :                 UnitMap::putUser("channel",UnitVal(1.0), "channel number");
     251           0 :         UnitMap::putUser("chan",UnitVal(1.0), "channel number");
     252           0 :                 _doneUnitInit = true;
     253             :         }
     254           0 : }
     255             : 
     256             : 
     257           0 : Bool AnnotationBase::setFrequencyLimits(
     258             :         const Quantity& beginFreq,
     259             :         const Quantity& endFreq,
     260             :         const String& freqRefFrame,
     261             :         const String& dopplerString,
     262             :         const Quantity& restfreq
     263             : ) {
     264           0 :         String preamble(_class + ": " + String(__FUNCTION__) + ": ");
     265           0 :     if (beginFreq.getValue() == 0 && endFreq.getValue() == 0) {
     266           0 :         return false;
     267             :     }
     268           0 :         if (! getCsys().hasSpectralAxis()) {
     269           0 :                 return false;
     270             :         }
     271           0 :     if ( beginFreq.getUnit().empty() && endFreq.getUnit().empty()) {
     272             :         throw AipsError(
     273           0 :             preamble + "Neither frequency specified has units. Both must"
     274           0 :         );
     275             :     }
     276           0 :         if (! beginFreq.getUnit().empty() && endFreq.getUnit().empty()) {
     277             :                 throw AipsError(
     278           0 :                         preamble + "beginning frequency specified but ending frequency not. "
     279           0 :                         + "Both must specified or both must be unspecified."
     280           0 :                 );
     281             :         }
     282           0 :         if (beginFreq.getUnit().empty() && ! endFreq.getUnit().empty()) {
     283             :                 throw AipsError(
     284           0 :                         preamble + "ending frequency specified but beginning frequency not. "
     285           0 :                         + "Both must specified or both must be unspecified."
     286           0 :                 );
     287             :         }
     288           0 :         if (! beginFreq.getUnit().empty()) {
     289           0 :                 if (! beginFreq.isConform(endFreq)) {
     290             :                         throw AipsError(
     291           0 :                                 preamble + "Beginning freq units (" + beginFreq.getUnit()
     292           0 :                                 + ") do not conform to ending freq units (" + endFreq.getUnit()
     293           0 :                                 + ") but they must."
     294           0 :                         );
     295             :                 }
     296             : 
     297           0 :                 if (
     298           0 :                         ! beginFreq.isConform("Hz")
     299           0 :                         && ! beginFreq.isConform("m/s")
     300           0 :                         && ! beginFreq.isConform("pix")
     301             :                 ) {
     302             :                         throw AipsError(
     303             :                                 preamble
     304           0 :                                 + "Invalid frequency unit " + beginFreq.getUnit()
     305           0 :                         );
     306             :                 }
     307           0 :                 if (beginFreq.isConform("m/s") && restfreq.getValue() <= 0) {
     308             :                         throw AipsError(
     309             :                                 preamble
     310           0 :                                 + "Beginning and ending velocities supplied but no restfreq specified"
     311           0 :                         );
     312             :                 }
     313           0 :                 if (freqRefFrame.empty()) {
     314           0 :                         _freqRefFrame = getCsys().spectralCoordinate().frequencySystem();
     315             :                 }
     316           0 :                 else if (! MFrequency::getType(_freqRefFrame, freqRefFrame)) {
     317             :                         throw AipsError(
     318             :                                 preamble
     319           0 :                                 + "Unknown frequency frame code "
     320           0 :                                 + freqRefFrame
     321           0 :                         );
     322             :                 }
     323             :                 else {
     324           0 :                         _setParam(AnnotationBase::FRAME, freqRefFrame);
     325             :                 }
     326           0 :                 if (dopplerString.empty()) {
     327           0 :                         _dopplerType = getCsys().spectralCoordinate().velocityDoppler();
     328             :                 }
     329           0 :                 else if (! MDoppler::getType(_dopplerType, dopplerString)) {
     330             :                         throw AipsError(
     331           0 :                                 preamble + "Unknown doppler code " + dopplerString
     332           0 :                         );
     333             :                 }
     334             :                 else {
     335           0 :                         _setParam(AnnotationBase::VELTYPE, dopplerString);
     336             :                 }
     337           0 :                 _beginFreq = beginFreq;
     338           0 :                 _endFreq = endFreq;
     339           0 :                 _restFreq = restfreq;
     340           0 :                 _setParam(AnnotationBase::RANGE, _printFreqRange());
     341           0 :                 _setParam(AnnotationBase::RESTFREQ, _printFreq(_restFreq));
     342             : 
     343           0 :                 _checkAndConvertFrequencies();
     344           0 :                 return true;
     345             :         }
     346           0 :         return false;
     347             : }
     348             : 
     349             : 
     350           0 : Vector<MFrequency> AnnotationBase::getFrequencyLimits() const {
     351           0 :         return _convertedFreqLimits;
     352             : }
     353             : 
     354           0 : Vector<Stokes::StokesTypes> AnnotationBase::getStokes() const {
     355           0 :         return _stokes;
     356             : }
     357             : 
     358           0 : void AnnotationBase::_checkAndConvertFrequencies() {
     359           0 :         const CoordinateSystem& csys = getCsys();
     360           0 :         const SpectralCoordinate spcoord = csys.spectralCoordinate();
     361           0 :     MFrequency::Types cFrameType = spcoord.frequencySystem(false);
     362           0 :         MDoppler::Types cDopplerType = spcoord.velocityDoppler();
     363           0 :         _convertedFreqLimits.resize(2);
     364           0 :     for (Int i=0; i<2; i++) {
     365           0 :                 Quantity qFreq = i == 0 ? _beginFreq : _endFreq;
     366           0 :                 String unit = qFreq.getUnit();
     367           0 :                 if (qFreq.isConform("pix")) {
     368           0 :                         Int spectralAxisNumber = csys.spectralAxisNumber(true);
     369           0 :                         String unit = csys.worldAxisUnits()[spectralAxisNumber];
     370             :                         Double world;
     371           0 :                         if (! spcoord.toWorld(world, qFreq.getValue())) {
     372           0 :                                 ostringstream os;
     373           0 :                                 os << String(__FUNCTION__) << ": Unable to convert pixel to world value "
     374           0 :                                         << "for spectral coordinate";
     375           0 :                                 throw AipsError(os.str());
     376             :                         }
     377           0 :                         if (_freqRefFrame != cFrameType) {
     378           0 :                                 LogIO log;
     379           0 :                                 log << LogOrigin(String(__FUNCTION__)) << LogIO::WARN
     380             :                                         << ": Frequency range given in pixels but supplied frequency ref frame ("
     381             :                                         << MFrequency::showType(_freqRefFrame) << ") differs from that of "
     382             :                                         << "the provided coordinate system (" << MFrequency::showType(cFrameType)
     383             :                                         << "). The provided frequency range will therefore be assumed to already "
     384             :                                         << "be in the coordinate system frequency reference frame and no conversion "
     385           0 :                                         << "will be done" << LogIO::POST;
     386             :                         }
     387           0 :                         if (_dopplerType != cDopplerType) {
     388           0 :                                 LogIO log;
     389           0 :                                 log << LogOrigin(String(__FUNCTION__)) << LogIO::WARN
     390             :                                         << ": Frequency range given in pixels but supplied doppler type ("
     391             :                                         << MDoppler::showType(_dopplerType) << ") differs from that of "
     392             :                                         << "the provided coordinate system (" << MDoppler::showType(cDopplerType)
     393             :                                         << "). The provided frequency range will therefore be assumed to already "
     394             :                                         << "be in the coordinate system doppler and no conversion "
     395           0 :                                         << "will be done" << LogIO::POST;
     396             :                         }
     397           0 :                         _freqRefFrame = cFrameType;
     398           0 :                         _dopplerType = cDopplerType;
     399           0 :                         _convertedFreqLimits[i] = MFrequency(
     400           0 :                                 Quantity(world, unit),
     401             :                                 _freqRefFrame
     402           0 :                         );
     403             :                 }
     404           0 :                 else if (qFreq.isConform("m/s")) {
     405           0 :                         MFrequency::Ref freqRef(_freqRefFrame);
     406           0 :                         MDoppler::Ref velRef(_dopplerType);
     407           0 :                         VelocityMachine vm(freqRef, Unit("GHz"),
     408           0 :                                 MVFrequency(_restFreq),
     409             :                                 velRef, unit
     410           0 :                         );
     411           0 :                         qFreq = vm(qFreq);
     412           0 :                         _convertedFreqLimits[i] = MFrequency(qFreq, _freqRefFrame);
     413           0 :                         if (_dopplerType != cDopplerType) {
     414           0 :                                 MDoppler dopplerConversion = MDoppler::Convert(_dopplerType, cDopplerType)();
     415           0 :                                 _convertedFreqLimits[i] = MFrequency::fromDoppler(
     416             :                                         dopplerConversion,
     417           0 :                                         _convertedFreqLimits[i].get("Hz"), cFrameType
     418           0 :                                 );
     419             :                         }
     420             :                 }
     421           0 :                 else if ( qFreq.isConform("Hz")) {
     422           0 :                         _convertedFreqLimits[i] = MFrequency(qFreq, _freqRefFrame);
     423             :                 }
     424             :                 else {
     425             :                         throw AipsError("Logic error. Bad spectral unit "
     426           0 :                                 + unit
     427           0 :                                 + " somehow made it to a place where it shouldn't have"
     428           0 :                         );
     429             :                 }
     430           0 :                 if (_freqRefFrame != cFrameType) {
     431           0 :                         Vector<Double> refDirection = csys.directionCoordinate().referenceValue();
     432           0 :                         Vector<String> directionUnits = csys.directionCoordinate().worldAxisUnits();
     433             :                         MDirection refDir(
     434           0 :                                 Quantity(refDirection[0], directionUnits[0]),
     435           0 :                                 Quantity(refDirection[1], directionUnits[1]),
     436           0 :                                 getCsys().directionCoordinate().directionType()
     437           0 :                         );
     438           0 :                         MFrequency::Ref inFrame(_freqRefFrame, MeasFrame(refDir));
     439           0 :                         MFrequency::Ref outFrame(cFrameType, MeasFrame(refDir));
     440           0 :                         MFrequency::Convert converter(inFrame, outFrame);
     441           0 :                         _convertedFreqLimits[i] = converter(_convertedFreqLimits[i]);
     442             :                 }
     443             :         }
     444           0 : }
     445             : 
     446             : 
     447           0 : String AnnotationBase::_printFreqRange() const {
     448           0 :         ostringstream os;
     449           0 :         os << "["
     450           0 :                 << _printFreq(_beginFreq) << ", "
     451           0 :                 << _printFreq(_endFreq) << "]";
     452           0 :         return os.str();
     453             : }
     454             : 
     455           0 : String AnnotationBase::_printFreq(const Quantity& freq) {
     456           0 :         if (freq.isConform("pix")) {
     457           0 :                 return _printPixel(freq.getValue());
     458             :         }
     459           0 :         ostringstream os;
     460           0 :         os << std::fixed;
     461           0 :         if (freq.isConform("km/s")) {
     462           0 :                 os << std::setprecision(4) << freq.getValue("km/s") << "km/s";
     463             :         }
     464             :         else {
     465           0 :                 os << std::setprecision(3) << freq.getValue("MHz") << "MHz";
     466             :         }
     467           0 :         return os.str();
     468             : }
     469             : 
     470           0 : AnnotationBase::Type AnnotationBase::getType() const {
     471           0 :         return _type;
     472             : }
     473             : 
     474           0 : void AnnotationBase::_initTypeMap() {
     475           0 :         _typeMap["line"] = LINE;
     476           0 :         _typeMap["vector"] = VECTOR;
     477           0 :         _typeMap["text"] = TEXT;
     478           0 :         _typeMap["symbol"] = SYMBOL;
     479           0 :         _typeMap["box"] = RECT_BOX;
     480           0 :         _typeMap["rectangularbox"] = RECT_BOX;
     481           0 :         _typeMap["centerbox"] = CENTER_BOX;
     482           0 :         _typeMap["rotatedbox"] = ROTATED_BOX;
     483           0 :         _typeMap["rotbox"] = ROTATED_BOX;
     484           0 :         _typeMap["poly"] = POLYGON;
     485           0 :         _typeMap["polygon"] = POLYGON;
     486           0 :         _typeMap["circle"] = CIRCLE;
     487           0 :         _typeMap["annulus"] = ANNULUS;
     488           0 :         _typeMap["ellipse"] = ELLIPSE;
     489           0 : }
     490             : 
     491           0 : AnnotationBase::Type AnnotationBase::typeFromString(
     492             :         const String& type
     493             : ) {
     494           0 :         if (_typeMap.size() == 0) {
     495           0 :                 _initTypeMap();
     496             :         }
     497           0 :         String cType = type;
     498           0 :         cType.downcase();
     499           0 :         cType.trim();
     500           0 :         if (_typeMap.find(cType) == _typeMap.end()) {
     501           0 :                 throw AipsError(type + " is not a supported annotation type");
     502             :         }
     503           0 :         return _typeMap.at(cType);
     504             : }
     505             : 
     506           0 : String AnnotationBase::typeToString(const AnnotationBase::Type type) {
     507           0 :         if (_typeMap.size() == 0) {
     508           0 :                 _initTypeMap();
     509             :         }
     510           0 :         for (
     511           0 :                 map<String, Type>::const_iterator iter = _typeMap.begin();
     512           0 :                 iter != _typeMap.end(); iter++
     513             :         ) {
     514           0 :                 if (iter->second == type) {
     515           0 :                         return iter->first;
     516             :                 }
     517             : 
     518             :         }
     519             :         throw AipsError(
     520           0 :                 _class + "::" + __FUNCTION__ + ": Logic error. Type "
     521           0 :                 + String::toString(type) + " not handled"
     522           0 :         );
     523             : }
     524             : 
     525             : 
     526           0 : AnnotationBase::LineStyle AnnotationBase::lineStyleFromString(const String& ls) {
     527           0 :         if (_lineStyleMap.size() == 0) {
     528           0 :                 _lineStyleMap["-"] = SOLID;
     529           0 :                 _lineStyleMap["--"] = DASHED;
     530           0 :                 _lineStyleMap["-."] = DOT_DASHED;
     531           0 :                 _lineStyleMap[":"] = DOTTED;
     532             :         }
     533           0 :         String cls = ls;
     534           0 :         cls.trim();
     535           0 :         if (cls.empty()) {
     536           0 :                 return DEFAULT_LINESTYLE;
     537             :         }
     538           0 :         if (_lineStyleMap.find(cls) == _lineStyleMap.end()) {
     539             :                 throw AipsError(
     540           0 :                         ls + " is not a supported line style"
     541           0 :                 );
     542             :         }
     543           0 :         return _lineStyleMap.at(cls);
     544             : }
     545             : 
     546             : AnnotationBase::FontStyle
     547           0 : AnnotationBase::fontStyleFromString(const String& fs) {
     548           0 :         String cfs = fs;
     549           0 :         cfs.downcase();
     550           0 :         cfs.trim();
     551             :         // FIXME when nothing to do and feeling anal, turn this into
     552             :         // a static map
     553           0 :         if (cfs.empty()) {
     554           0 :                 return DEFAULT_FONTSTYLE;
     555             :         }
     556           0 :         else if (cfs == "normal") {
     557           0 :                 return NORMAL;
     558             :         }
     559           0 :         else if (cfs == "bold") {
     560           0 :                 return BOLD;
     561             :         }
     562           0 :         else if (cfs == "italic") {
     563           0 :                 return ITALIC;
     564             :         }
     565           0 :         else if (cfs == "bold-italic") {
     566           0 :                 return ITALIC_BOLD;
     567             :         }
     568             :         else {
     569             :                 throw AipsError(
     570           0 :                         fs + " is not a supported font style"
     571           0 :                 );
     572             :         }
     573             : }
     574             : 
     575           0 : String AnnotationBase::fontStyleToString(
     576             :         const AnnotationBase::FontStyle fs
     577             : ) {
     578           0 :         switch (fs) {
     579           0 :         case NORMAL: return "normal";
     580           0 :         case BOLD: return "bold";
     581           0 :         case ITALIC: return "italic";
     582           0 :         case ITALIC_BOLD: return "itatlic_bold";
     583           0 :         default:
     584             :                 throw AipsError(
     585           0 :                         _class + ": " + String(__FUNCTION__) + ": "
     586           0 :                         + ": Logic error, should never have gotten here"
     587           0 :                 );
     588             :         }
     589             : }
     590             : 
     591           0 : void AnnotationBase::setLabel(const String& s) {
     592           0 :         _label = s;
     593           0 :         if (_label.empty()) {
     594           0 :                 if (_params.find(LABEL) != _params.end()) {
     595           0 :                         _params.erase(LABEL);
     596             :                 }
     597             :         }
     598             :         else {
     599           0 :                 _params[LABEL] = _label;
     600             :         }
     601           0 : }
     602             : 
     603           0 : String AnnotationBase::getLabel() const {
     604           0 :         return _label;
     605             : }
     606             : 
     607           0 : Bool AnnotationBase::_isRGB(const AnnotationBase::RGB& rgb) {
     608           0 :         if (rgb.size() != 3) {
     609           0 :                 return false;
     610             :         }
     611           0 :         for (RGB::const_iterator iter=rgb.begin(); iter!=rgb.end(); iter++) {
     612           0 :                 if (*iter < 0 || *iter > 255) {
     613           0 :                         return false;
     614             :                 }
     615             :         }
     616           0 :         return true;
     617             : }
     618             : 
     619           0 : AnnotationBase::RGB AnnotationBase::_colorStringToRGB(const String& s) {
     620           0 :     String c = s;
     621           0 :     c.trim();
     622           0 :     c.downcase();
     623           0 :     if (_colors.find(c) != _colors.end()) {
     624           0 :         return _colors.find(c)->second;
     625             :     }
     626           0 :     else if (c.find(rgbHexRegex) != String::npos) {
     627           0 :         RGB rgb(3);
     628           0 :         for (uInt i=0; i<3; i++) {
     629           0 :                 String comp = s.substr(2*i, 2);
     630             :                 int hexInt;
     631           0 :                 sscanf(comp.c_str(), "%x", &hexInt );
     632           0 :                 rgb[i] = hexInt;
     633             :         }
     634           0 :         return rgb;
     635             :     }
     636             :     else {
     637           0 :         throw AipsError("Unrecognized color specification " + s);
     638             :     }
     639             : }
     640             : 
     641           0 : void AnnotationBase::setColor(const String& s) {
     642           0 :         _color = _colorStringToRGB(s);
     643           0 :         _params[COLOR] = colorToString(_color);
     644           0 : }
     645             : 
     646           0 : void AnnotationBase::setColor(const RGB& rgb) {
     647           0 :         if (! _isRGB(rgb)) {
     648             :                 throw AipsError(
     649           0 :                         _class + "::" + __FUNCTION__
     650           0 :                                 + ": input vector is not a valid RGB representation"
     651           0 :                 );
     652             :         }
     653           0 :         _color = rgb;
     654           0 :         _params[COLOR] = colorToString(_color);
     655           0 : }
     656             : 
     657           0 : AnnotationBase::RGB AnnotationBase::getColor() const {
     658           0 :         return _color;
     659             : }
     660             : 
     661           0 : String AnnotationBase::getColorString() const {
     662           0 :         return colorToString(_color);
     663             : }
     664             : 
     665           0 : String AnnotationBase::colorToString(const AnnotationBase::RGB& color) {
     666           0 :         if (! _isRGB(color)) {
     667             :                 throw AipsError(
     668           0 :                         _class + "::" + __FUNCTION__
     669           0 :                                 + ": input vector is not a valid RGB representation"
     670           0 :                 );
     671             :         }
     672           0 :         if (_rgbNameMap.find(color) != _rgbNameMap.end()) {
     673           0 :                 return _rgbNameMap.find(color)->second;
     674             :         }
     675             :         else {
     676           0 :                 ostringstream oss;
     677           0 :                 oss << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[0] + 0.5)
     678           0 :                         << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[1] + 0.5)
     679           0 :                         << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[2] + 0.5);
     680           0 :                 String rgbString = oss.str();
     681           0 :                 rgbString.downcase();
     682           0 :                 return rgbString;
     683             :         }
     684             : }
     685             : 
     686           0 : void AnnotationBase::setLabelColor(const String& color) {
     687           0 :         _labelColor = _colorStringToRGB(color);
     688           0 :         _params[LABELCOLOR] = color;
     689           0 : }
     690             : 
     691           0 : void AnnotationBase::setLabelColor(const RGB& color) {
     692           0 :         if (! _isRGB(color)) {
     693             :                 throw AipsError(
     694           0 :                         _class + "::" + __FUNCTION__
     695           0 :                                 + ": input vector is not a valid RGB representation"
     696           0 :                 );
     697             :         }
     698           0 :         _labelColor = color;
     699           0 :         _params[LABELCOLOR] = colorToString(_labelColor);
     700           0 : }
     701             : 
     702           0 : String AnnotationBase::getLabelColorString() const {
     703           0 :         return colorToString(_labelColor);
     704             : }
     705             : 
     706           0 : AnnotationBase::RGB AnnotationBase::getLabelColor() const {
     707           0 :         return _labelColor;
     708             : }
     709             : 
     710           0 : void AnnotationBase::setLineStyle(const LineStyle s) {
     711           0 :         _linestyle = s;
     712           0 :         _params[LINESTYLE] = lineStyleToString(_linestyle);
     713           0 : }
     714             : 
     715           0 : AnnotationBase::LineStyle AnnotationBase::getLineStyle() const {
     716           0 :         return _linestyle;
     717             : }
     718             : 
     719           0 : void AnnotationBase::setLineWidth(const uInt s) {
     720           0 :         _linewidth = s;
     721           0 :         _params[LINEWIDTH] = String::toString(_linewidth);
     722           0 : }
     723             : 
     724           0 : uInt AnnotationBase::getLineWidth() const {
     725           0 :         return _linewidth;
     726             : }
     727             : 
     728           0 : void AnnotationBase::setSymbolSize(const uInt s) {
     729           0 :         _symbolsize = s;
     730           0 :         _params[SYMSIZE] = String::toString(_symbolsize);
     731           0 : }
     732             : 
     733           0 : uInt AnnotationBase::getSymbolSize() const {
     734           0 :         return _symbolsize;
     735             : }
     736             : 
     737           0 : void AnnotationBase::setSymbolThickness(const uInt s) {
     738           0 :         _symbolthickness = s;
     739           0 :         _params[SYMTHICK] = String::toString(_symbolthickness);
     740           0 : }
     741             : 
     742           0 : uInt AnnotationBase::getSymbolThickness() const {
     743           0 :         return _symbolthickness;
     744             : }
     745             : 
     746           0 : void AnnotationBase::setFont(const String& s) {
     747           0 :         _font = s;
     748           0 :         _params[FONT] = _font;
     749           0 : }
     750             : 
     751           0 : String AnnotationBase::getFont() const {
     752           0 :         return _font;
     753             : }
     754             : 
     755           0 : void AnnotationBase::setFontSize(const uInt s) {
     756           0 :         _fontsize = s;
     757           0 :         _params[FONTSIZE] = String::toString(_fontsize);
     758           0 : }
     759             : 
     760           0 : uInt AnnotationBase::getFontSize() const {
     761           0 :         return _fontsize;
     762             : }
     763             : 
     764           0 : void AnnotationBase::setFontStyle(const AnnotationBase::FontStyle& fs) {
     765           0 :         _fontstyle = fs;
     766           0 :         _params[FONTSTYLE] = fontStyleToString(_fontstyle);
     767           0 : }
     768             : 
     769           0 : AnnotationBase::FontStyle AnnotationBase::getFontStyle() const {
     770           0 :         return _fontstyle;
     771             : }
     772             : 
     773           0 : void AnnotationBase::setUseTex(const Bool s) {
     774           0 :         _usetex = s;
     775           0 :         _params[USETEX] = _usetex ? "true" : "false";
     776           0 : }
     777             : 
     778           0 : Bool AnnotationBase::isUseTex() const {
     779           0 :         return _usetex;
     780             : }
     781             : 
     782           0 : String AnnotationBase::getLabelPosition() const {
     783           0 :         return _labelPos;
     784             : }
     785             : 
     786           0 : void AnnotationBase::setLabelPosition(const String& position) {
     787           0 :         String c = position;
     788           0 :         c.trim();
     789           0 :         c.downcase();
     790           0 :         if (
     791           0 :                 c != "top" && c != "bottom"
     792           0 :                 && c != "left" && c != "right"
     793             :         ) {
     794             :                 throw AipsError(
     795           0 :                         _class + "::" + __FUNCTION__
     796           0 :                                 + ": Unknown label position " + position
     797           0 :                 );
     798             :         }
     799           0 :         _labelPos = c;
     800           0 :         _params[LABELPOS] = _labelPos;
     801           0 : }
     802             : 
     803           0 : void AnnotationBase::setLabelOffset(const vector<Int>& offset) {
     804           0 :         if (offset.size() != 2) {
     805             :                 throw AipsError(
     806           0 :                         _class + "::" + __FUNCTION__
     807           0 :                                 + ": Number of elements in label offset must be exactly 2, not "
     808           0 :                                 + String(offset.size())
     809           0 :                 );
     810             :         }
     811           0 :         _labelOff = offset;
     812           0 :         _params[LABELOFF] = "[" + String::toString(offset[0]) + ", " + String::toString(offset[1]) + "]";
     813           0 : }
     814             : 
     815           0 : vector<Int> AnnotationBase::getLabelOffset() const {
     816           0 :         return _labelOff;
     817             : }
     818             : 
     819           0 : Bool AnnotationBase::isRegion() const {
     820           0 :         return false;
     821             : }
     822             : 
     823           0 : void AnnotationBase::setGlobals(
     824             :         const Vector<Keyword>& globalKeys
     825             : ) {
     826           0 :         for (
     827           0 :                 Vector<Keyword>::const_iterator iter=globalKeys.begin();
     828           0 :                 iter != globalKeys.end(); iter++) {
     829           0 :                         _globals[*iter] = true;
     830             :         }
     831           0 : }
     832             : 
     833           0 : String AnnotationBase::keywordToString(
     834             :         const Keyword key
     835             : ) {
     836           0 :         switch(key) {
     837           0 :         case COORD: return "coord";
     838           0 :         case RANGE: return "range";
     839           0 :         case FRAME: return "frame";
     840           0 :         case CORR: return "corr";
     841           0 :         case VELTYPE: return "veltype";
     842           0 :         case RESTFREQ: return "restfreq";
     843           0 :         case LINEWIDTH: return "linewidth";
     844           0 :         case LINESTYLE: return "linestyle";
     845           0 :         case SYMSIZE: return "symsize";
     846           0 :         case SYMTHICK: return "symthick";
     847           0 :         case COLOR: return "color";
     848           0 :         case FONT: return "font";
     849           0 :         case FONTSIZE: return "fontsize";
     850           0 :         case FONTSTYLE: return "fontstyle";
     851           0 :         case USETEX: return "usetex";
     852           0 :         case LABEL: return "label";
     853           0 :         case LABELCOLOR: return "labelcolor";
     854           0 :         case LABELPOS: return "labelpos";
     855           0 :         case LABELOFF: return "labeloff";
     856           0 :         case UNKNOWN_KEYWORD:
     857             :         case N_KEYS:
     858             :         default:
     859             :                 throw AipsError(
     860           0 :                         _class + "::" + __FUNCTION__
     861           0 :                         + ": Logic error: No string representation for Keyword " + String(key)
     862           0 :                 );
     863             :         }
     864             : }
     865             : 
     866           0 : String AnnotationBase::lineStyleToString(
     867             :         const LineStyle style
     868             : ) {
     869           0 :         switch(style) {
     870           0 :         case SOLID: return "-";
     871           0 :         case DASHED: return "--";
     872           0 :         case DOT_DASHED: return "-.";
     873           0 :         case DOTTED: return ":";
     874           0 :         default:
     875           0 :                 ThrowCc(
     876             :                         "Logic error: No string representation for LineStyle "
     877             :                         + String::toString(style)
     878             :                 );
     879             :         }
     880             : }
     881             : 
     882           0 : ostream& AnnotationBase::print(
     883             :         ostream& os, const LineStyle ls
     884             : ) {
     885           0 :         os << lineStyleToString(ls);
     886           0 :         return os;
     887             : }
     888             : 
     889           0 : ostream& AnnotationBase::print(
     890             :         ostream& os, const FontStyle fs
     891             : ) {
     892           0 :         os << fontStyleToString(fs);
     893           0 :         return os;
     894             : }
     895             : 
     896           0 : ostream& AnnotationBase::print(
     897             :         ostream& os, const map<Keyword, String>& params
     898             : ) {
     899           0 :         if (params.size() == 0) {
     900           0 :                 return os;
     901             :         }
     902           0 :         Bool hasLabel = params.find(LABEL) != params.end();
     903           0 :         for (
     904           0 :                 map<Keyword, String>::const_iterator iter=params.begin();
     905           0 :                 iter!=params.end(); iter++
     906             :         ) {
     907           0 :                 Keyword key = iter->first;
     908           0 :                 if (! iter->second.empty()) {
     909           0 :                         if (
     910           0 :                                 ! hasLabel && (
     911           0 :                                         key == LABELCOLOR || key == LABELPOS
     912           0 :                                         || key == LABELOFF
     913             :                                 )
     914             :                         ) {
     915           0 :                                 continue;
     916             :                         }
     917           0 :                         if (iter != params.begin()) {
     918           0 :                                 os << ", ";
     919             :                         }
     920             :                         String quote = key == LABEL
     921           0 :                                 || (
     922           0 :                                         iter->second.contains(' ')
     923           0 :                                         && (key != RANGE && key != CORR && key != LABELOFF)
     924             :                                 )
     925           0 :                                 ? "\"" : "";
     926           0 :                         os << keywordToString((Keyword)iter->first)
     927           0 :                                 << "=" << quote << iter->second << quote;
     928             :                 }
     929             :         }
     930           0 :         return os;
     931             : }
     932             : 
     933           0 : ostream& AnnotationBase::print(
     934             :         ostream& os, const Direction d
     935             : ) {
     936           0 :         for (uInt i=0; i<d.size(); i++) {
     937           0 :                 os << i << ": " << d[i].first << ", " << d[i].second << endl;
     938             :         }
     939           0 :         return os;
     940             : }
     941             : 
     942           0 : void AnnotationBase::_printPairs(ostream &os) const {
     943           0 :         map<Keyword, String> x = _params;
     944           0 :         if (! _printGlobals) {
     945           0 :                 for (
     946           0 :                         map<Keyword, String>::const_iterator iter = _params.begin();
     947           0 :                         iter != _params.end(); iter++
     948             :                 ) {
     949           0 :                         Keyword k = iter->first;
     950           0 :                         if (_globals.find(k) != _globals.end() && _globals.at(k)) {
     951           0 :                                 x.erase(k);
     952             :                         }
     953             :                 }
     954             :         }
     955           0 :         if (x.size() > 0) {
     956           0 :                 os << " " << x;
     957             :         }
     958           0 : }
     959             : 
     960           0 : void AnnotationBase::_checkMixed(
     961             :         const String& origin, const AnnotationBase::Direction& quantities
     962             : ) {
     963           0 :         Bool isWorld = false;
     964           0 :         Bool isPixel = false;
     965           0 :         Quantity qArg;
     966           0 :         for (
     967           0 :                 Direction::const_iterator iter = quantities.begin();
     968           0 :                 iter != quantities.end(); iter++
     969             :         ) {
     970           0 :                 for (uInt i=0; i<2; i++) {
     971           0 :                         Quantity tQ = i == 0 ? iter->first : iter->second;
     972           0 :                         Bool pix = tQ.getUnit() == "pix";
     973           0 :                         Bool world = ! pix;
     974           0 :                         isWorld = isWorld || world;
     975           0 :                         isPixel = isPixel || pix;
     976           0 :                         if (isPixel && isWorld) {
     977             :                                 throw AipsError(
     978             :                                         origin
     979           0 :                                         + ": Mixed world and pixel coordinates not supported"
     980           0 :                                 );
     981             :                         }
     982             :                 }
     983             :         }
     984           0 : }
     985             : 
     986           0 : MDirection AnnotationBase::_directionFromQuantities(
     987             :         const Quantity& q0, const Quantity& q1
     988             : ) {
     989           0 :         ostringstream oss;
     990           0 :         oss << q0 << ", " << q1;
     991           0 :         Quantity d0 = q0;
     992           0 :         Quantity d1 = q1;
     993             : 
     994           0 :         String value = oss.str();
     995           0 :         if (q0.getUnit() == "pix") {
     996             :                 // both quantities are in pix, this check should
     997             :                 // have been done prior to calling this method
     998           0 :                 Vector<Double> pixel(_csys.nPixelAxes(), 0);
     999           0 :                 pixel[_directionAxes[0]] = q0.getValue();
    1000           0 :                 pixel[_directionAxes[1]] = q1.getValue();
    1001           0 :                 Vector<Double> world;
    1002           0 :                 _csys.toWorld(world, pixel);
    1003           0 :                 Vector<String> axesUnits = _csys.worldAxisUnits();
    1004           0 :                 d0 = Quantity(world[_directionAxes[0]], axesUnits[_directionAxes[0]]);
    1005           0 :                 d1 = Quantity(world[_directionAxes[1]], axesUnits[_directionAxes[1]]);
    1006           0 :                 MDirection::Types csysDirectionType = _csys.directionCoordinate().directionType(false);
    1007           0 :                 if (_directionRefFrame != csysDirectionType) {
    1008           0 :                         LogIO log;
    1009           0 :                         log << LogOrigin(String(__FUNCTION__)) << LogIO::WARN
    1010             :                                 << ": Direction quantities specified in pixels but specified direction reference "
    1011             :                                 << "frame (" << MDirection::showType(_directionRefFrame) << ") is different from "
    1012             :                                 << "the reference frame (" << MDirection::showType(csysDirectionType)
    1013             :                                 << ") of the coordinate system. The reference frame of the coordinate system "
    1014             :                                 << "will be used and the direction coordinates will not be transformed"
    1015           0 :                                 << LogIO::POST;
    1016             :                 }
    1017           0 :                 _directionRefFrame = csysDirectionType;
    1018             :         }
    1019             :         try {
    1020           0 :                 return MDirection(d0, d1, _directionRefFrame);
    1021             :         }
    1022           0 :         catch (const AipsError& x) {
    1023             :                 throw AipsError(
    1024           0 :                         _class + "::" + String(__FUNCTION__) + ": Error converting direction ("
    1025           0 :                         + value + ") to MDirection: " + x.getMesg()
    1026           0 :                 );
    1027             :         }
    1028             : }
    1029             : 
    1030           0 : void AnnotationBase::_checkAndConvertDirections(
    1031             :         const String& origin, const AnnotationBase::Direction& quantities
    1032             : ) {
    1033           0 :         _checkMixed(origin, quantities);
    1034           0 :         MDirection::Types csysDirectionRefFrame = _csys.directionCoordinate().directionType(false);
    1035           0 :         Bool needsConverting = _directionRefFrame != csysDirectionRefFrame;
    1036           0 :         _convertedDirections.resize(quantities.size());
    1037           0 :         for (uInt i=0; i<quantities.size(); i++) {
    1038           0 :                 _convertedDirections[i] = _directionFromQuantities(quantities(i).first, quantities(i).second);
    1039           0 :                 if (needsConverting) {
    1040           0 :                         _convertedDirections[i] = MDirection::Convert(_convertedDirections[i], csysDirectionRefFrame)();
    1041             :                 }
    1042             :         }
    1043             :         // check this now because if converting from world to pixel fails when
    1044             :         // regions are being formed, it will wreak havoc
    1045           0 :         _testConvertToPixel();
    1046           0 : }
    1047             : 
    1048           0 : AnnotationBase::Direction AnnotationBase::getDirections() const {
    1049           0 :         Direction res(_convertedDirections.size());
    1050           0 :         for (uInt i=0; i<res.size(); i++) {
    1051           0 :                 Quantum<Vector<Double> > angles = _convertedDirections[i].getAngle();
    1052           0 :                 String unit = angles.getUnit();
    1053           0 :                 Vector<Double> vals = angles.getValue();
    1054           0 :                 res[i].first = Quantity(vals[0], unit);
    1055           0 :                 res[i].second = Quantity(vals[1], unit);
    1056             : 
    1057             :         }
    1058           0 :         return res;
    1059             : }
    1060             : 
    1061           0 : void AnnotationBase::_initColors() {
    1062           0 :         if (_doneColorInit) {
    1063           0 :                 return;
    1064             :         }
    1065           0 :         _colors.insert(make_pair("black", BLACK));
    1066           0 :         _colors.insert(make_pair("blue", BLUE));
    1067           0 :         _colors.insert(make_pair("cyan", CYAN));
    1068           0 :         _colors.insert(make_pair("gray", GRAY));
    1069           0 :         _colors.insert(make_pair("green", GREEN));
    1070           0 :         _colors.insert(make_pair("magenta", MAGENTA));
    1071           0 :         _colors.insert(make_pair("orange", ORANGE));
    1072           0 :         _colors.insert(make_pair("red", RED));
    1073           0 :         _colors.insert(make_pair("white", WHITE));
    1074           0 :         _colors.insert(make_pair("yellow", YELLOW));
    1075             : 
    1076           0 :         for (
    1077           0 :                 map<string, RGB>::const_iterator iter=_colors.begin();
    1078           0 :                         iter != _colors.end(); iter++
    1079             :                 ) {
    1080           0 :                 _rgbNameMap[iter->second] = iter->first;
    1081           0 :                 _colorNames.push_back(iter->first);
    1082             :         }
    1083           0 :     _doneColorInit = true;
    1084             : }
    1085             : 
    1086           0 : std::list<std::string> AnnotationBase::colorChoices() {
    1087           0 :         _initColors();
    1088           0 :         return _colorNames;
    1089             : }
    1090             : 
    1091           0 : void AnnotationBase::_testConvertToPixel() const {
    1092           0 :         Vector<Double> pixel(2);
    1093           0 :         Vector<Double> world(2);
    1094           0 :         const auto units = _csys.worldAxisUnits();
    1095           0 :         const auto end = _convertedDirections.end();
    1096           0 :         for (auto iter = _convertedDirections.begin(); iter != end; ++iter) {
    1097           0 :                 world[0] = iter->getAngle().getValue(units[0])[0];
    1098           0 :                 world[1] = iter->getAngle().getValue(units[1])[1];
    1099           0 :                 if (! _csys.directionCoordinate().toPixel(pixel, world)) {
    1100           0 :                         ostringstream oss;
    1101           0 :                         oss << "Could not convert world coordinate " << world << "to pixel";
    1102           0 :                         throw (WorldToPixelConversionError(oss.str()));
    1103             :                 }
    1104             :         }
    1105           0 : }
    1106             : 
    1107           0 : String AnnotationBase::_printDirection(
    1108             :         const Quantity& longitude, const Quantity& latitude
    1109             : ) const {
    1110           0 :         if (longitude.getUnit() == "pix") {
    1111           0 :                 ostringstream os;
    1112           0 :                 os << _printPixel(longitude.getValue())
    1113           0 :                         << ", "
    1114           0 :                         << _printPixel(latitude.getValue());
    1115           0 :                 return os.str();
    1116             :         }
    1117             :         MDirection::Types frame;
    1118           0 :         MDirection::getType(frame, _params.find(COORD)->second);
    1119           0 :         if (
    1120           0 :                 frame == MDirection::J2000
    1121           0 :                 || frame == MDirection::B1950
    1122           0 :                 || frame == MDirection::JMEAN
    1123           0 :                 || frame == MDirection::JTRUE
    1124           0 :                 || frame == MDirection::B1950_VLA
    1125           0 :                 || frame == MDirection::BMEAN
    1126           0 :                 || frame == MDirection::BTRUE
    1127             :         ) {
    1128             :                 // equatorial coordinates in sexigesimal
    1129           0 :                 MVAngle x(longitude);
    1130           0 :                 MVAngle y(latitude);
    1131           0 :                 return x.string(MVAngle::TIME_CLEAN, 11) + ", " + y.string(MVAngle::ANGLE, 10);
    1132             :         }
    1133             :         else {
    1134             :                 // non-equatorial coordinates in degrees
    1135           0 :                 return _toDeg(longitude) + ", " + _toDeg(latitude);
    1136             :         }
    1137             : }
    1138             : 
    1139           0 : String AnnotationBase::_toArcsec(const Quantity& angle) {
    1140           0 :         ostringstream os;
    1141           0 :         if (angle.getUnit() == "pix") {
    1142           0 :                 os << _printPixel(angle.getValue());
    1143             :         }
    1144             :         else {
    1145           0 :                 os << std::fixed << std::setprecision(4)
    1146           0 :                         << angle.getValue("arcsec") << "arcsec";
    1147             :         }
    1148           0 :         return os.str();
    1149             : }
    1150             : 
    1151           0 : String AnnotationBase::_toDeg(const Quantity& angle) {
    1152           0 :         ostringstream os;
    1153           0 :         if (angle.getUnit() == "pix") {
    1154           0 :                 os << _printPixel(angle.getValue());
    1155             :         }
    1156             :         else {
    1157           0 :                 os << std::fixed << std::setprecision(8)
    1158           0 :                         << angle.getValue("deg") << "deg";
    1159             :         }
    1160           0 :         return os.str();
    1161             : }
    1162             : 
    1163           0 : String AnnotationBase::_printPixel(const Double& d) {
    1164           0 :         ostringstream os;
    1165           0 :         os << std::fixed << std::setprecision(1)
    1166           0 :                 << d << "pix";
    1167           0 :         return os.str();
    1168             : }
    1169             : 
    1170             : 
    1171             : }
    1172             : 
    1173             : 
    1174             : 

Generated by: LCOV version 1.16