LCOV - code coverage report
Current view: top level - imageanalysis/Annotations - AnnotationBase.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 355 687 51.7 %
Date: 2023-11-06 10:06:49 Functions: 42 74 56.8 %

          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         139 : 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         139 : )
      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         139 :   _printGlobals(false), _labelOff(DEFAULT_LABELOFF) {
     103         139 :         ThrowIf(
     104             :                 ! csys.hasDirectionCoordinate(),
     105             :                 "Coordinate system has no direction coordinate"
     106             :         );
     107             :         const uInt *oname;
     108             :         Int nall, nex;
     109         139 :         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         139 :         ThrowIf(
     113             :                 find( tname, tname+nall, dirRefFrameString) == tname+nall,
     114             :                 "Unknown direction reference frame '" + dirRefFrameString + "'"
     115             :         );
     116         139 :         ThrowIf (
     117             :                 ! MDirection::getType(_directionRefFrame, dirRefFrameString),
     118             :                 "Unknown direction reference frame " + dirRefFrameString
     119             :         );
     120         139 :         setFrequencyLimits(
     121             :                 beginFreq, endFreq, freqRefFrame,
     122             :                 dopplerString, restfreq
     123             :         );
     124         139 :         _init();
     125         139 : }
     126             : 
     127         427 : AnnotationBase::AnnotationBase(
     128             :         const Type type, const CoordinateSystem& csys,
     129             :         const Vector<Stokes::StokesTypes>& stokes
     130         427 : )
     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         427 :   _printGlobals(false), _labelOff(DEFAULT_LABELOFF)
     142             :  {
     143         854 :         String preamble = String(__FUNCTION__) + ": ";
     144         427 :         if (!csys.hasDirectionCoordinate()) {
     145             :                 throw AipsError(
     146           0 :                         preamble + "Coordinate system has no direction coordinate"
     147           0 :                 );
     148             :         }
     149         427 :         _directionRefFrame = _csys.directionCoordinate().directionType();
     150         427 :         _init();
     151         427 : }
     152             : 
     153         566 : 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         566 : void AnnotationBase::_init() {
     191        1698 :         String preamble = _class + ": " + String(__FUNCTION__) + ": ";
     192         566 :         _initColors();
     193         566 :         if (
     194         566 :                 _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         566 :                 && _directionRefFrame != MDirection::ICRS
     204             :         ) {
     205             :                 throw AipsError(preamble
     206           0 :                         + "Unsupported coordinate frame for regions "
     207           0 :                         + MDirection::showType(_directionRefFrame)
     208           0 :                 );
     209             :         }
     210         566 :         _params[COORD] = MDirection::showType(_directionRefFrame);
     211         566 :         _directionAxes = IPosition(_csys.directionAxesNumbers());
     212             : 
     213         566 :         uInt nStokes = _stokes.size();
     214         566 :         if (nStokes > 0) {
     215           3 :                 ostringstream os;
     216           3 :                 os << "[";
     217           7 :                 for (uInt i=0; i< nStokes; i++) {
     218           4 :                         os << Stokes::name(_stokes[i]);
     219           4 :                         if (i != _stokes.size() - 1) {
     220           1 :                                 os << ", ";
     221             :                         }
     222             :                 }
     223           3 :                 os << "]";
     224           3 :                 _params[CORR] = os.str();
     225             :         }
     226       11886 :         for(uInt i=0; i<N_KEYS; i++) {
     227       11320 :                 _globals[(Keyword)i] = false;
     228             :         }
     229         566 :         _initParams();
     230         566 : }
     231             : 
     232         566 : void AnnotationBase::_initParams() {
     233         566 :         _params[LINEWIDTH] = String::toString(_linewidth);
     234         566 :         _params[LINESTYLE] = lineStyleToString(_linestyle);
     235         566 :         _params[SYMSIZE] = String::toString(_symbolsize);
     236         566 :         _params[SYMTHICK] = String::toString(_symbolthickness);
     237         566 :         _params[COLOR] = getColorString();
     238         566 :         _params[FONT] = _font;
     239         566 :         _params[FONTSIZE] = String::toString(_fontsize);
     240         566 :         _params[FONTSTYLE] = fontStyleToString(_fontstyle);
     241         566 :         _params[USETEX] = _usetex ? "true" : "false";
     242         566 :         if (! _label.empty()) {
     243           0 :                 _params[LABEL] = _label;
     244             :         }
     245         566 : }
     246             : 
     247          68 : void AnnotationBase::unitInit() {
     248          68 :         if (! _doneUnitInit) {
     249           1 :                 UnitMap::putUser("pix",UnitVal(1.0), "pixel units");
     250           1 :                 UnitMap::putUser("channel",UnitVal(1.0), "channel number");
     251           1 :         UnitMap::putUser("chan",UnitVal(1.0), "channel number");
     252           1 :                 _doneUnitInit = true;
     253             :         }
     254          68 : }
     255             : 
     256             : 
     257         139 : 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         417 :         String preamble(_class + ": " + String(__FUNCTION__) + ": ");
     265         139 :     if (beginFreq.getValue() == 0 && endFreq.getValue() == 0) {
     266         128 :         return false;
     267             :     }
     268          11 :         if (! getCsys().hasSpectralAxis()) {
     269           0 :                 return false;
     270             :         }
     271          11 :     if ( beginFreq.getUnit().empty() && endFreq.getUnit().empty()) {
     272             :         throw AipsError(
     273           0 :             preamble + "Neither frequency specified has units. Both must"
     274           0 :         );
     275             :     }
     276          11 :         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          11 :         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          11 :         if (! beginFreq.getUnit().empty()) {
     289          11 :                 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          11 :                 if (
     298          11 :                         ! beginFreq.isConform("Hz")
     299          13 :                         && ! beginFreq.isConform("m/s")
     300          13 :                         && ! beginFreq.isConform("pix")
     301             :                 ) {
     302             :                         throw AipsError(
     303             :                                 preamble
     304           0 :                                 + "Invalid frequency unit " + beginFreq.getUnit()
     305           0 :                         );
     306             :                 }
     307          11 :                 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          11 :                 if (freqRefFrame.empty()) {
     314          11 :                         _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          11 :                 if (dopplerString.empty()) {
     327          11 :                         _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          11 :                 _beginFreq = beginFreq;
     338          11 :                 _endFreq = endFreq;
     339          11 :                 _restFreq = restfreq;
     340          11 :                 _setParam(AnnotationBase::RANGE, _printFreqRange());
     341          11 :                 _setParam(AnnotationBase::RESTFREQ, _printFreq(_restFreq));
     342             : 
     343          11 :                 _checkAndConvertFrequencies();
     344          11 :                 return true;
     345             :         }
     346           0 :         return false;
     347             : }
     348             : 
     349             : 
     350         566 : Vector<MFrequency> AnnotationBase::getFrequencyLimits() const {
     351         566 :         return _convertedFreqLimits;
     352             : }
     353             : 
     354         566 : Vector<Stokes::StokesTypes> AnnotationBase::getStokes() const {
     355         566 :         return _stokes;
     356             : }
     357             : 
     358          11 : void AnnotationBase::_checkAndConvertFrequencies() {
     359          11 :         const CoordinateSystem& csys = getCsys();
     360          22 :         const SpectralCoordinate spcoord = csys.spectralCoordinate();
     361          11 :     MFrequency::Types cFrameType = spcoord.frequencySystem(false);
     362          11 :         MDoppler::Types cDopplerType = spcoord.velocityDoppler();
     363          11 :         _convertedFreqLimits.resize(2);
     364          33 :     for (Int i=0; i<2; i++) {
     365          44 :                 Quantity qFreq = i == 0 ? _beginFreq : _endFreq;
     366          44 :                 String unit = qFreq.getUnit();
     367          22 :                 if (qFreq.isConform("pix")) {
     368           4 :                         Int spectralAxisNumber = csys.spectralAxisNumber(true);
     369           4 :                         String unit = csys.worldAxisUnits()[spectralAxisNumber];
     370             :                         Double world;
     371           4 :                         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           4 :                         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           4 :                         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           4 :                         _freqRefFrame = cFrameType;
     398           4 :                         _dopplerType = cDopplerType;
     399           8 :                         _convertedFreqLimits[i] = MFrequency(
     400           8 :                                 Quantity(world, unit),
     401             :                                 _freqRefFrame
     402           4 :                         );
     403             :                 }
     404          18 :                 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          18 :                 else if ( qFreq.isConform("Hz")) {
     422          18 :                         _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          22 :                 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          11 : }
     445             : 
     446             : 
     447          11 : String AnnotationBase::_printFreqRange() const {
     448          11 :         ostringstream os;
     449          11 :         os << "["
     450          11 :                 << _printFreq(_beginFreq) << ", "
     451          11 :                 << _printFreq(_endFreq) << "]";
     452          22 :         return os.str();
     453             : }
     454             : 
     455          33 : String AnnotationBase::_printFreq(const Quantity& freq) {
     456          33 :         if (freq.isConform("pix")) {
     457           4 :                 return _printPixel(freq.getValue());
     458             :         }
     459          29 :         ostringstream os;
     460          29 :         os << std::fixed;
     461          29 :         if (freq.isConform("km/s")) {
     462           0 :                 os << std::setprecision(4) << freq.getValue("km/s") << "km/s";
     463             :         }
     464             :         else {
     465          29 :                 os << std::setprecision(3) << freq.getValue("MHz") << "MHz";
     466             :         }
     467          29 :         return os.str();
     468             : }
     469             : 
     470           0 : AnnotationBase::Type AnnotationBase::getType() const {
     471           0 :         return _type;
     472             : }
     473             : 
     474           1 : void AnnotationBase::_initTypeMap() {
     475           1 :         _typeMap["line"] = LINE;
     476           1 :         _typeMap["vector"] = VECTOR;
     477           1 :         _typeMap["text"] = TEXT;
     478           1 :         _typeMap["symbol"] = SYMBOL;
     479           1 :         _typeMap["box"] = RECT_BOX;
     480           1 :         _typeMap["rectangularbox"] = RECT_BOX;
     481           1 :         _typeMap["centerbox"] = CENTER_BOX;
     482           1 :         _typeMap["rotatedbox"] = ROTATED_BOX;
     483           1 :         _typeMap["rotbox"] = ROTATED_BOX;
     484           1 :         _typeMap["poly"] = POLYGON;
     485           1 :         _typeMap["polygon"] = POLYGON;
     486           1 :         _typeMap["circle"] = CIRCLE;
     487           1 :         _typeMap["annulus"] = ANNULUS;
     488           1 :         _typeMap["ellipse"] = ELLIPSE;
     489           1 : }
     490             : 
     491         139 : AnnotationBase::Type AnnotationBase::typeFromString(
     492             :         const String& type
     493             : ) {
     494         139 :         if (_typeMap.size() == 0) {
     495           1 :                 _initTypeMap();
     496             :         }
     497         139 :         String cType = type;
     498         139 :         cType.downcase();
     499         139 :         cType.trim();
     500         139 :         if (_typeMap.find(cType) == _typeMap.end()) {
     501           0 :                 throw AipsError(type + " is not a supported annotation type");
     502             :         }
     503         278 :         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         141 : AnnotationBase::LineStyle AnnotationBase::lineStyleFromString(const String& ls) {
     527         141 :         if (_lineStyleMap.size() == 0) {
     528           1 :                 _lineStyleMap["-"] = SOLID;
     529           1 :                 _lineStyleMap["--"] = DASHED;
     530           1 :                 _lineStyleMap["-."] = DOT_DASHED;
     531           1 :                 _lineStyleMap[":"] = DOTTED;
     532             :         }
     533         282 :         String cls = ls;
     534         141 :         cls.trim();
     535         141 :         if (cls.empty()) {
     536         137 :                 return DEFAULT_LINESTYLE;
     537             :         }
     538           4 :         if (_lineStyleMap.find(cls) == _lineStyleMap.end()) {
     539             :                 throw AipsError(
     540           0 :                         ls + " is not a supported line style"
     541           0 :                 );
     542             :         }
     543           4 :         return _lineStyleMap.at(cls);
     544             : }
     545             : 
     546             : AnnotationBase::FontStyle
     547         141 : AnnotationBase::fontStyleFromString(const String& fs) {
     548         282 :         String cfs = fs;
     549         141 :         cfs.downcase();
     550         141 :         cfs.trim();
     551             :         // FIXME when nothing to do and feeling anal, turn this into
     552             :         // a static map
     553         141 :         if (cfs.empty()) {
     554         137 :                 return DEFAULT_FONTSTYLE;
     555             :         }
     556           4 :         else if (cfs == "normal") {
     557           4 :                 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         705 : String AnnotationBase::fontStyleToString(
     576             :         const AnnotationBase::FontStyle fs
     577             : ) {
     578         705 :         switch (fs) {
     579           2 :         case NORMAL: return "normal";
     580         703 :         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           2 : void AnnotationBase::setLabel(const String& s) {
     592           2 :         _label = s;
     593           2 :         if (_label.empty()) {
     594           0 :                 if (_params.find(LABEL) != _params.end()) {
     595           0 :                         _params.erase(LABEL);
     596             :                 }
     597             :         }
     598             :         else {
     599           2 :                 _params[LABEL] = _label;
     600             :         }
     601           2 : }
     602             : 
     603           0 : String AnnotationBase::getLabel() const {
     604           0 :         return _label;
     605             : }
     606             : 
     607         853 : Bool AnnotationBase::_isRGB(const AnnotationBase::RGB& rgb) {
     608         853 :         if (rgb.size() != 3) {
     609           0 :                 return false;
     610             :         }
     611        3412 :         for (RGB::const_iterator iter=rgb.begin(); iter!=rgb.end(); iter++) {
     612        2559 :                 if (*iter < 0 || *iter > 255) {
     613           0 :                         return false;
     614             :                 }
     615             :         }
     616         853 :         return true;
     617             : }
     618             : 
     619         143 : AnnotationBase::RGB AnnotationBase::_colorStringToRGB(const String& s) {
     620         286 :     String c = s;
     621         143 :     c.trim();
     622         143 :     c.downcase();
     623         143 :     if (_colors.find(c) != _colors.end()) {
     624         142 :         return _colors.find(c)->second;
     625             :     }
     626           1 :     else if (c.find(rgbHexRegex) != String::npos) {
     627           2 :         RGB rgb(3);
     628           4 :         for (uInt i=0; i<3; i++) {
     629           3 :                 String comp = s.substr(2*i, 2);
     630             :                 int hexInt;
     631           3 :                 sscanf(comp.c_str(), "%x", &hexInt );
     632           3 :                 rgb[i] = hexInt;
     633             :         }
     634           1 :         return rgb;
     635             :     }
     636             :     else {
     637           0 :         throw AipsError("Unrecognized color specification " + s);
     638             :     }
     639             : }
     640             : 
     641         139 : void AnnotationBase::setColor(const String& s) {
     642         139 :         _color = _colorStringToRGB(s);
     643         139 :         _params[COLOR] = colorToString(_color);
     644         139 : }
     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         566 : String AnnotationBase::getColorString() const {
     662         566 :         return colorToString(_color);
     663             : }
     664             : 
     665         853 : String AnnotationBase::colorToString(const AnnotationBase::RGB& color) {
     666         853 :         if (! _isRGB(color)) {
     667             :                 throw AipsError(
     668           0 :                         _class + "::" + __FUNCTION__
     669           0 :                                 + ": input vector is not a valid RGB representation"
     670           0 :                 );
     671             :         }
     672         853 :         if (_rgbNameMap.find(color) != _rgbNameMap.end()) {
     673         851 :                 return _rgbNameMap.find(color)->second;
     674             :         }
     675             :         else {
     676           4 :                 ostringstream oss;
     677           2 :                 oss << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[0] + 0.5)
     678           2 :                         << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[1] + 0.5)
     679           2 :                         << hex << std::setw(2) << std::setfill('0') << (Int)floor(color[2] + 0.5);
     680           4 :                 String rgbString = oss.str();
     681           2 :                 rgbString.downcase();
     682           2 :                 return rgbString;
     683             :         }
     684             : }
     685             : 
     686           4 : void AnnotationBase::setLabelColor(const String& color) {
     687           4 :         _labelColor = _colorStringToRGB(color);
     688           4 :         _params[LABELCOLOR] = color;
     689           4 : }
     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         139 : void AnnotationBase::setLineStyle(const LineStyle s) {
     711         139 :         _linestyle = s;
     712         139 :         _params[LINESTYLE] = lineStyleToString(_linestyle);
     713         139 : }
     714             : 
     715           0 : AnnotationBase::LineStyle AnnotationBase::getLineStyle() const {
     716           0 :         return _linestyle;
     717             : }
     718             : 
     719         139 : void AnnotationBase::setLineWidth(const uInt s) {
     720         139 :         _linewidth = s;
     721         139 :         _params[LINEWIDTH] = String::toString(_linewidth);
     722         139 : }
     723             : 
     724           0 : uInt AnnotationBase::getLineWidth() const {
     725           0 :         return _linewidth;
     726             : }
     727             : 
     728         139 : void AnnotationBase::setSymbolSize(const uInt s) {
     729         139 :         _symbolsize = s;
     730         139 :         _params[SYMSIZE] = String::toString(_symbolsize);
     731         139 : }
     732             : 
     733           0 : uInt AnnotationBase::getSymbolSize() const {
     734           0 :         return _symbolsize;
     735             : }
     736             : 
     737         139 : void AnnotationBase::setSymbolThickness(const uInt s) {
     738         139 :         _symbolthickness = s;
     739         139 :         _params[SYMTHICK] = String::toString(_symbolthickness);
     740         139 : }
     741             : 
     742           0 : uInt AnnotationBase::getSymbolThickness() const {
     743           0 :         return _symbolthickness;
     744             : }
     745             : 
     746         139 : void AnnotationBase::setFont(const String& s) {
     747         139 :         _font = s;
     748         139 :         _params[FONT] = _font;
     749         139 : }
     750             : 
     751           0 : String AnnotationBase::getFont() const {
     752           0 :         return _font;
     753             : }
     754             : 
     755         139 : void AnnotationBase::setFontSize(const uInt s) {
     756         139 :         _fontsize = s;
     757         139 :         _params[FONTSIZE] = String::toString(_fontsize);
     758         139 : }
     759             : 
     760           0 : uInt AnnotationBase::getFontSize() const {
     761           0 :         return _fontsize;
     762             : }
     763             : 
     764         139 : void AnnotationBase::setFontStyle(const AnnotationBase::FontStyle& fs) {
     765         139 :         _fontstyle = fs;
     766         139 :         _params[FONTSTYLE] = fontStyleToString(_fontstyle);
     767         139 : }
     768             : 
     769           0 : AnnotationBase::FontStyle AnnotationBase::getFontStyle() const {
     770           0 :         return _fontstyle;
     771             : }
     772             : 
     773         139 : void AnnotationBase::setUseTex(const Bool s) {
     774         139 :         _usetex = s;
     775         139 :         _params[USETEX] = _usetex ? "true" : "false";
     776         139 : }
     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           2 : void AnnotationBase::setLabelPosition(const String& position) {
     787           2 :         String c = position;
     788           2 :         c.trim();
     789           2 :         c.downcase();
     790           2 :         if (
     791           2 :                 c != "top" && c != "bottom"
     792           2 :                 && c != "left" && c != "right"
     793             :         ) {
     794             :                 throw AipsError(
     795           0 :                         _class + "::" + __FUNCTION__
     796           0 :                                 + ": Unknown label position " + position
     797           0 :                 );
     798             :         }
     799           2 :         _labelPos = c;
     800           2 :         _params[LABELPOS] = _labelPos;
     801           2 : }
     802             : 
     803           2 : void AnnotationBase::setLabelOffset(const vector<Int>& offset) {
     804           2 :         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           2 :         _labelOff = offset;
     812           2 :         _params[LABELOFF] = "[" + String::toString(offset[0]) + ", " + String::toString(offset[1]) + "]";
     813           2 : }
     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         139 : void AnnotationBase::setGlobals(
     824             :         const Vector<Keyword>& globalKeys
     825             : ) {
     826        2380 :         for (
     827         278 :                 Vector<Keyword>::const_iterator iter=globalKeys.begin();
     828        2519 :                 iter != globalKeys.end(); iter++) {
     829        2380 :                         _globals[*iter] = true;
     830             :         }
     831         139 : }
     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         705 : String AnnotationBase::lineStyleToString(
     867             :         const LineStyle style
     868             : ) {
     869         705 :         switch(style) {
     870         705 :         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         566 : void AnnotationBase::_checkMixed(
     961             :         const String& origin, const AnnotationBase::Direction& quantities
     962             : ) {
     963         566 :         Bool isWorld = false;
     964         566 :         Bool isPixel = false;
     965        1132 :         Quantity qArg;
     966         743 :         for (
     967        1132 :                 Direction::const_iterator iter = quantities.begin();
     968        1309 :                 iter != quantities.end(); iter++
     969             :         ) {
     970        2229 :                 for (uInt i=0; i<2; i++) {
     971        2972 :                         Quantity tQ = i == 0 ? iter->first : iter->second;
     972        1486 :                         Bool pix = tQ.getUnit() == "pix";
     973        1486 :                         Bool world = ! pix;
     974        1486 :                         isWorld = isWorld || world;
     975        1486 :                         isPixel = isPixel || pix;
     976        1486 :                         if (isPixel && isWorld) {
     977             :                                 throw AipsError(
     978             :                                         origin
     979           0 :                                         + ": Mixed world and pixel coordinates not supported"
     980           0 :                                 );
     981             :                         }
     982             :                 }
     983             :         }
     984         566 : }
     985             : 
     986         777 : MDirection AnnotationBase::_directionFromQuantities(
     987             :         const Quantity& q0, const Quantity& q1
     988             : ) {
     989        1554 :         ostringstream oss;
     990         777 :         oss << q0 << ", " << q1;
     991        1554 :         Quantity d0 = q0;
     992        1554 :         Quantity d1 = q1;
     993             : 
     994        1554 :         String value = oss.str();
     995         777 :         if (q0.getUnit() == "pix") {
     996             :                 // both quantities are in pix, this check should
     997             :                 // have been done prior to calling this method
     998         278 :                 Vector<Double> pixel(_csys.nPixelAxes(), 0);
     999         139 :                 pixel[_directionAxes[0]] = q0.getValue();
    1000         139 :                 pixel[_directionAxes[1]] = q1.getValue();
    1001         278 :                 Vector<Double> world;
    1002         139 :                 _csys.toWorld(world, pixel);
    1003         139 :                 Vector<String> axesUnits = _csys.worldAxisUnits();
    1004         139 :                 d0 = Quantity(world[_directionAxes[0]], axesUnits[_directionAxes[0]]);
    1005         139 :                 d1 = Quantity(world[_directionAxes[1]], axesUnits[_directionAxes[1]]);
    1006         139 :                 MDirection::Types csysDirectionType = _csys.directionCoordinate().directionType(false);
    1007         139 :                 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         139 :                 _directionRefFrame = csysDirectionType;
    1018             :         }
    1019             :         try {
    1020        1554 :                 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         566 : void AnnotationBase::_checkAndConvertDirections(
    1031             :         const String& origin, const AnnotationBase::Direction& quantities
    1032             : ) {
    1033         566 :         _checkMixed(origin, quantities);
    1034         566 :         MDirection::Types csysDirectionRefFrame = _csys.directionCoordinate().directionType(false);
    1035         566 :         Bool needsConverting = _directionRefFrame != csysDirectionRefFrame;
    1036         566 :         _convertedDirections.resize(quantities.size());
    1037        1309 :         for (uInt i=0; i<quantities.size(); i++) {
    1038         743 :                 _convertedDirections[i] = _directionFromQuantities(quantities(i).first, quantities(i).second);
    1039         743 :                 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         566 :         _testConvertToPixel();
    1046         566 : }
    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         566 : void AnnotationBase::_initColors() {
    1062         566 :         if (_doneColorInit) {
    1063         565 :                 return;
    1064             :         }
    1065           1 :         _colors.insert(make_pair("black", BLACK));
    1066           1 :         _colors.insert(make_pair("blue", BLUE));
    1067           1 :         _colors.insert(make_pair("cyan", CYAN));
    1068           1 :         _colors.insert(make_pair("gray", GRAY));
    1069           1 :         _colors.insert(make_pair("green", GREEN));
    1070           1 :         _colors.insert(make_pair("magenta", MAGENTA));
    1071           1 :         _colors.insert(make_pair("orange", ORANGE));
    1072           1 :         _colors.insert(make_pair("red", RED));
    1073           1 :         _colors.insert(make_pair("white", WHITE));
    1074           1 :         _colors.insert(make_pair("yellow", YELLOW));
    1075             : 
    1076          10 :         for (
    1077           1 :                 map<string, RGB>::const_iterator iter=_colors.begin();
    1078          21 :                         iter != _colors.end(); iter++
    1079             :                 ) {
    1080          10 :                 _rgbNameMap[iter->second] = iter->first;
    1081          10 :                 _colorNames.push_back(iter->first);
    1082             :         }
    1083           1 :     _doneColorInit = true;
    1084             : }
    1085             : 
    1086           0 : std::list<std::string> AnnotationBase::colorChoices() {
    1087           0 :         _initColors();
    1088           0 :         return _colorNames;
    1089             : }
    1090             : 
    1091         566 : void AnnotationBase::_testConvertToPixel() const {
    1092        1132 :         Vector<Double> pixel(2);
    1093        1132 :         Vector<Double> world(2);
    1094        1132 :         const auto units = _csys.worldAxisUnits();
    1095        1132 :         const auto end = _convertedDirections.end();
    1096        1309 :         for (auto iter = _convertedDirections.begin(); iter != end; ++iter) {
    1097         743 :                 world[0] = iter->getAngle().getValue(units[0])[0];
    1098         743 :                 world[1] = iter->getAngle().getValue(units[1])[1];
    1099         743 :                 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         566 : }
    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           4 : String AnnotationBase::_printPixel(const Double& d) {
    1164           4 :         ostringstream os;
    1165           4 :         os << std::fixed << std::setprecision(1)
    1166           4 :                 << d << "pix";
    1167           8 :         return os.str();
    1168             : }
    1169             : 
    1170             : 
    1171             : }
    1172             : 
    1173             : 
    1174             : 

Generated by: LCOV version 1.16