00001 //# MVAngle.h: Class to handle angle type conversions and I/O 00002 //# Copyright (C) 1996,1997,1998,1999,2000,2001 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id$ 00027 00028 #ifndef CASA_MVANGLE_H 00029 #define CASA_MVANGLE_H 00030 00031 00032 //# Includes 00033 #include <casacore/casa/aips.h> 00034 #include <casacore/casa/Quanta/Quantum.h> 00035 #include <casacore/casa/iosfwd.h> 00036 00037 namespace casacore { //# NAMESPACE CASACORE - BEGIN 00038 00039 //# Forward Declarations 00040 class String; 00041 class MUString; 00042 00043 //# Constants (SUN compiler does not accept non-simple default arguments) 00044 00045 // <summary> 00046 // Class to handle angle type conversions and I/O 00047 // </summary> 00048 00049 // <use visibility=export> 00050 00051 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="tMeasure" demos=""> 00052 // </reviewed> 00053 00054 // <prerequisite> 00055 // <li> <linkto class=Quantum>Quantum</linkto> 00056 // </prerequisite> 00057 // 00058 // <etymology> 00059 // From Measure, Value and Angle 00060 // </etymology> 00061 // 00062 // <synopsis> 00063 // An MVAngle is a simple Double, to be used for angle conversions and I/O. 00064 // It can be constructed from a Double (in which case radians are assumed), 00065 // or from a Quantity (<src>Quantum<Double></src>). Quantities must be in 00066 // either angle or time units.<br> 00067 // It has an automatic conversion to Double, so all standard mathematical 00068 // operations can operate on it.<br> 00069 // The class has a number of special member operations: 00070 // <ul> 00071 // <li> <src>MVAngle operator()</src> will normalise the angle between 00072 // -180 and +180(inclusive) degrees and return the value 00073 // <li> <src>MVAngle operator(Double)</src> will normalise the angle 00074 // using the value specified (and return the value) 00075 // in fractions of a circle (this was chosen rather than radians to make 00076 // for easier and more precise programming) as a lower bound. I.e. 00077 // (-0.5) will normalise between -180 and +180 degrees, (0.) between 00078 // 0 and 360 degrees, (-0.25) between -90 and +270 degrees, 00079 // (5.) between 1800 and 2160 dgrees. 00080 // <li> <src>MVAngle operator(MVAngle)</src> will normalise (and 00081 // return the normalised value) to within 180 degrees of the 00082 // argument value. This is useful for making a range of angles 00083 // contiguous. 00084 // <li> <src>MVAngle binorm(Double)</src> will normalise the angle in 00085 // steps of 180 degrees. 00086 // using the value specified (and return the value) 00087 // in fractions of 180 degrees (this was chosen rather than radians to make 00088 // for easier and more precise programming) as a lower bound. I.e. 00089 // (-0.5) will normalise between -90 and +90 degrees, (0.) between 00090 // 0 and 180 degrees, (10.) between 1800 and 1980 dgrees. 00091 // <li> <src>Double radian()</src> will return value in radians 00092 // <li> <src>Double degree()</src> will return value in degrees 00093 // <li> <src>Double circle()</src> will return value in fraction of circles 00094 // <li> <src>MVAngle coAngle()</src> will return 90-angle (or rather 00095 // pi/2 - angle), with (0) normalisation. 00096 // <li> <src>Quantity get()</src> will return radians 00097 // <li> <src>Quantity get(Unit)</src> will return in specified units 00098 // (angle or time) 00099 // </ul> 00100 // Output formatting is done with the <src><<</src> statement, with the 00101 // following rules: 00102 // <ul> 00103 // <li> standard output is done in the following format: 00104 // <src>+ddd.mm.ss.tt</src> with a floating sign. The number of 00105 // digits presented will be based on the precision attached to the 00106 // current stream 00107 // <li> output can be formatted by using either the <src>setFormat()</src> 00108 // method for global angle format setting, or the output of 00109 // <src>MVAngle::Format()</src> data for a once off change (see later). 00110 // Formats have a first argument which 00111 // determines the type (default, if not given, MVAngle::ANGLE, other 00112 // possibility MVAngle::TIME (as hh:mm:ss.tt..), 00113 // the second the number of digits wanted (default stream precision), 00114 // with a value: 00115 // <ul> 00116 // <li> <3 : ddd.. only 00117 // <li> <5 : ddd.mm. 00118 // <li> <7 : ddd.mm.ss 00119 // <li> >6 : with precision-6 t's added 00120 // </ul> 00121 // comparable for time. <note role=tip> The added periods are to enable input 00122 // checking of the format. Look at the 'clean' types to bypass them. 00123 // </note> 00124 // The output format can be modified with modifiers (specify as 00125 // MVAngle::ANGLE | MVAngle::MOD (or + MVAngle::MOD)). 00126 // <note role=caution> 00127 // For overloading/casting problems with some compilers, the 00128 // use of modifiers necessitates either the presence of a precision 00129 // (i.e. <src>(A|B, prec)</src>), or an explicit cast: 00130 // <src>((MVAngle::formatTypes)(A|B))</src>, or make use of 00131 // the provided <src>ANGLE[_CLEAN][_NO_D[M]]</src> and 00132 // <src>TIME[_CLEAN][_NO_H[M]].</src> 00133 // </note> 00134 // 00135 // The modifiers can be: 00136 // <ul> 00137 // <li> <src>MVAngle::CLEAN</src> to suppress leading or trailing 00138 // periods (or colons for TIME), + and leading zeroes in degree 00139 // field for angle representation will be replaced with a space. 00140 // Note that the result can not be read automatically. 00141 // <li> <src>MVAngle::NO_D</src> (or <src>NO_H</src>) to suppress 00142 // the output of degrees (or hours): useful for offsets 00143 // <li> <src>MVAngle::NO_DM</src> (or <src>NO_HM</src>), to 00144 // suppress the degrees and minutes. 00145 // <li> <src>MVAngle::DIG2</src> to allow only 2 digits for degrees, 00146 // or -12 - +12 range for hours 00147 // <li> <src>MVAngle::LOCAL</src> to indicate local time to FITS 00148 // formatting only 00149 // <li> <src>MVAngle::FITS</src> to produce, if 00150 // LOCAL set, the time zone (note that if local set 00151 // here, as opposed to in MVTime) the angle is supposed 00152 // to be in local time already). 00153 // <li> <src>MVAngle::ALPHA</src> to use d (or h) and m instead of 00154 // periods or colons. 00155 // </ul> 00156 // Output in formats like <src>20'</src> can be done via the standard 00157 // Quantum output (e.g. <src> stream << angle.get("'") </src>). 00158 // <li> Available formats: 00159 // <ul> 00160 // <li> MVAngle::ANGLE in +ddd.mm.ss.ttt format 00161 // <li> MVAngle::TIME in hh:mm:ss.ttt format 00162 // <li> MVAngle::[ANGLE|TIME]_CLEAN format without superfluous periods 00163 // <li> MVAngle::[ANGLE|TIME][_CLEAN]_NO_[D|H][M] in format with 00164 // leading zero fields left empty. 00165 // <li> MVAngle::CLEAN modifier for suppressing superfluous periods 00166 // <li> MVAngle::NO_[D|H][M] modifier to suppress first field(s) 00167 // <li> MVAngle::DIG2 modifier to output in +dd.mm.ss.ttt format or 00168 // in time format in range -12 to +12h 00169 // </ul> 00170 // </ul> 00171 // The default formatting can be overwritten by a 00172 // <src> MVAngle::setFormat(); </src> statement; which returns an 00173 // MVAngle::Format 00174 // structure, that can be used in a subsequent one to reset to previous. 00175 // The format set holds for all MVAngle output on all streams.<br> 00176 // Temporary formats (i.e. for one MVAngle output only), can be set by 00177 // outputting a format (i.e. <src> stream << MVAngle::Format() << ... </src>). 00178 // <note role=caution> A setFormat() will also reset any lingering temporary format. 00179 // A setFormat(getFormat()) will reset without changing. Problems could 00180 // arise in parallel processors. </note> 00181 // Input can be read if the values are in any of the above (non-clean) output 00182 // formats. <br> 00183 // For other formatting practice, the output can be written to a String with 00184 // the string() member function.<br> 00185 // Note that using a temporary format is inherently thread-unsafe because 00186 // the format is kept in a static variable. Another thread may overwrite 00187 // the format just set. The only thread-safe way to format an MVTime is using 00188 // a <src>print</src> or <src>string</src> that accepts a Format object. 00189 // 00190 // Strings and input can be converted to an MVAngle (or Quantity) by 00191 // <src>Bool read(Quantity &out, const String &in)</src> and 00192 // <src> istream >> MVAngle &</src>. In the latter case the actual 00193 // reading is done by the String read, which reads between white-spaces.<br> 00194 // The following input formats (note no blanks allowed) are supported 00195 // (+stands for an optional + or -; v for an unsigned integer; dv for a 00196 // floating number. [] indicate optional values. Separating codes are 00197 // case insensitive): 00198 // <ul> 00199 // <li> +[v].[v].[dv] -- value in deg, arcmin, arcsec 00200 // <li> +[v]D[v[M[dv]]] -- value in deg, arcmin, arcsec 00201 // <li> +[v]:[v[:[dv]]] -- value in h, min, s 00202 // <li> +[v]H[v[M[dv]]] -- value in h, min, s 00203 // <li> +[v]{D|H|:}[dv] -- value in deg (or h), arcmin (or min) 00204 // <li> +dv[unit string] -- value in time or angle units. rad default 00205 // </ul> 00206 // Examples of valid strings: 00207 // <srcblock> 00208 // 5::2.59 5h + 0min + 2.59 s 00209 // 5..2.59 5deg + 0arcmin + 2.59arcsec 00210 // 5.259 5.259 rad 00211 // 5..259 5deg + 259arcsec 00212 // 5.259a 5.259 * pi * 2 *365.25 rad (normalised) 00213 // </srcblock> 00214 // <note role=caution> In general the input will be read as a Quantity. 00215 // Reading of Quantities will always try to read special formats (like 00216 // MVAngle, MVTime) first. In 00217 // that case problems could arise converting strings like 5d, 5::, 5hm, 5dm. 00218 // In 'angle' mode they could have meant to be 00219 // 5d0m, 5:0:, 5h0m, 5d0m, but they could have 00220 // meant: days, min, hectometre, decimetre. In the same vain 5d2 could have 00221 // meant 5d2m or 5 d<sup>2</sup>. 00222 // To try to guess the general use, the following interpretation is made: 00223 // <ul> 00224 // <li> 5d, 5:: == 5deg, 5h0m; make float (like 5.d) to make it days/min 00225 // <li> 5dm, 5hm == decimetre, hectometre; use 5d0m 5h0m for 00226 // angle 00227 // <li> 5d2, 5h2, 5:2 == 5d2m, 5h2m, 5:2:; use float 5 or explicit () for 00228 // other interpretation 00229 // </ul> 00230 // </note> 00231 // </synopsis> 00232 // 00233 // <example> 00234 // See synopsis 00235 // </example> 00236 // 00237 // <motivation> 00238 // To be able to format angle-like values in user-required ways. 00239 // </motivation> 00240 // 00241 // <todo asof="1997/09/16"> 00242 // <li> Use AipsrcData once moved to aips from trial 00243 // </todo> 00244 00245 class MVAngle { 00246 00247 public: 00248 00249 //# Enumerations (should mimic those in MVTime) 00250 // Format types 00251 enum formatTypes { 00252 ANGLE, 00253 TIME, 00254 CLEAN = 4, 00255 NO_D = 8, 00256 NO_DM = NO_D+16, 00257 DIG2 = 1024, 00258 FITS = TIME+2048, 00259 LOCAL = 4096, 00260 USE_SPACE = 8192, //# Only for MVTIme compatibility 00261 ALPHA = 16384, 00262 NO_H = NO_D, 00263 NO_HM = NO_DM, 00264 ANGLE_CLEAN = ANGLE + CLEAN, 00265 ANGLE_NO_D = ANGLE + NO_D, 00266 ANGLE_NO_DM = ANGLE + NO_DM, 00267 ANGLE_CLEAN_NO_D = ANGLE + CLEAN + NO_D, 00268 ANGLE_CLEAN_NO_DM = ANGLE + CLEAN + NO_DM, 00269 TIME_CLEAN = TIME + CLEAN, 00270 TIME_NO_H = TIME + NO_H, 00271 TIME_NO_HM = TIME + NO_HM, 00272 TIME_CLEAN_NO_H = TIME + CLEAN + NO_H, 00273 TIME_CLEAN_NO_HM = TIME + CLEAN + NO_HM , 00274 MOD_MASK = CLEAN + NO_DM + DIG2 + LOCAL + USE_SPACE + ALPHA}; 00275 00276 //# Local structure 00277 // Format structure 00278 class Format { 00279 public: 00280 friend class MVAngle; 00281 Format(MVAngle::formatTypes intyp = MVAngle::ANGLE, 00282 uInt inprec = 0) : 00283 typ(intyp), prec(inprec) {;}; 00284 Format(uInt inprec) : 00285 typ(MVAngle::ANGLE), prec(inprec) {;}; 00286 // Construct from type and precision (present due to overlaoding problems) 00287 Format(uInt intyp, uInt inprec) : 00288 typ((MVAngle::formatTypes) intyp), prec(inprec) {;}; 00289 Format(const Format &other) : 00290 typ(other.typ), prec(other.prec) {;}; 00291 private: 00292 MVAngle::formatTypes typ; 00293 uInt prec; 00294 }; 00295 00296 //# Friends 00297 // Output an angle 00298 friend ostream &operator<<(ostream &os, const MVAngle &meas); 00299 // Input an angle 00300 friend istream &operator>>(istream &is, MVAngle &meas); 00301 // Set a temporary format 00302 friend ostream &operator<<(ostream &os, const MVAngle::Format &form); 00303 00304 //# Constructors 00305 // Default constructor: generate a zero value 00306 MVAngle(); 00307 // Copy constructor 00308 MVAngle(const MVAngle &other); 00309 // Copy assignment 00310 MVAngle &operator=(const MVAngle &other); 00311 // Constructor from Double 00312 MVAngle(Double d); 00313 // Constructor from Quantum : value can be an angle or time 00314 // <thrown> 00315 // <li> AipsError if not a time or angle 00316 // </thrown> 00317 MVAngle(const Quantity &other); 00318 00319 // Destructor 00320 ~MVAngle(); 00321 00322 //# Operators 00323 // Conversion operator 00324 operator Double() const; 00325 // Normalisation between -180 and +180 degrees (-pi and +pi) 00326 const MVAngle &operator()(); 00327 // Normalisation between 2pi*norm and 2pi*norm + 2pi 00328 const MVAngle &operator()(Double norm); 00329 // Normalisation between norm-pi and norm+pi 00330 const MVAngle &operator()(const MVAngle &norm); 00331 00332 //# General member functions 00333 // Normalisation between pi*norm and pi*norm + pi 00334 const MVAngle &binorm(Double norm); 00335 // Check if String unit 00336 static Bool unitString(UnitVal &uv, String &us, MUString &in); 00337 // Make res angle Quantity from string in angle/time-like format. In the 00338 // case of String input, also quantities are recognised. chk checks eos 00339 // <group> 00340 static Bool read(Quantity &res, const String &in, Bool chk=True); 00341 static Bool read(Quantity &res, MUString &in, Bool chk=True); 00342 // </group> 00343 // Make co-angle (e.g. zenith distance from elevation) 00344 MVAngle coAngle() const; 00345 // Get value in given unit 00346 // <group> 00347 Double radian() const; 00348 Double degree() const; 00349 Double circle() const; 00350 Quantity get() const; 00351 Quantity get(const Unit &inunit) const; 00352 // </group> 00353 // Output data 00354 // <note role=warning> 00355 // The first function below is thread-unsafe because it uses the result of 00356 // the setFormat function which changes a static class member. 00357 // The other functions are thread-safe because the format is directly given. 00358 // </note> 00359 // <group> 00360 String string() const; 00361 String string(MVAngle::formatTypes intyp, uInt inprec = 0) const; 00362 String string(uInt intyp, uInt inprec) const; 00363 String string(uInt inprec) const; 00364 String string(const MVAngle::Format &form) const; 00365 void print(ostream &oss, const MVAngle::Format &form) const; 00366 void print(ostream &oss, const MVAngle::Format &form, Bool loc) const; 00367 // </group> 00368 // Set default format 00369 // <note role=warning> 00370 // It is thread-unsafe to print using the setFormat functions because they 00371 // change a static class member. The only thred-safe way to print a time is 00372 // to use the print function above. 00373 // </note> 00374 // <group> 00375 static Format setFormat(MVAngle::formatTypes intyp, 00376 uInt inprec = 0); 00377 static Format setFormat(uInt intyp, uInt inprec); 00378 static Format setFormat(uInt inprec = 0); 00379 static Format setFormat(const Format &form); 00380 // </group> 00381 // Get default format 00382 static Format getFormat(); 00383 // Get code belonging to string. 0 if not known 00384 static MVAngle::formatTypes giveMe(const String &in); 00385 // Get time zone offset (in days) 00386 static Double timeZone(); 00387 00388 private: 00389 //# Data 00390 // Value 00391 Double val; 00392 // Default format 00393 static MVAngle::Format defaultFormat; 00394 // Temporary format 00395 // <group> 00396 static MVAngle::Format interimFormat; 00397 static Bool interimSet; 00398 // </group> 00399 00400 //# Member functions 00401 }; 00402 00403 // Global functions 00404 // <summary> Global output/input functions </summary> 00405 // Output/Input 00406 // <group name=output> 00407 ostream &operator<<(ostream &os, const MVAngle &meas); 00408 istream &operator>>(istream &is, MVAngle &meas); 00409 // Set a temporary format (thread-unsafe). 00410 ostream &operator<<(ostream &os, const MVAngle::Format &form); 00411 // </group> 00412 00413 00414 } //# NAMESPACE CASACORE - END 00415 00416 #endif