You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kstars/kstars/dms.cpp

319 lines
8.4 KiB

/***************************************************************************
dms.cpp - Trinity Desktop Planetarium
-------------------
begin : Sun Feb 11 2001
copyright : (C) 2001 by Jason Harris
email : jharris@30doradus.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdlib.h>
#include "dms.h"
#include <kglobal.h>
#include <klocale.h>
#include <tqregexp.h>
void dms::setD( const double &x ) {
D = x;
scDirty = true;
rDirty = true;
}
void dms::setD(const int &d, const int &m, const int &s, const int &ms) {
D = (double)abs(d) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.;
if (d<0) {D = -1.0*D;}
scDirty = true;
rDirty = true;
}
void dms::setH( const double &x ) {
setD( x*15.0 );
}
void dms::setH(const int &h, const int &m, const int &s, const int &ms) {
D = 15.0*((double)abs(h) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.);
if (h<0) {D = -1.0*D;}
scDirty = true;
rDirty = true;
}
void dms::setRadians( const double &Rad ) {
setD( Rad/DegToRad );
Radians = Rad;
}
bool dms::setFromString( const TQString &str, bool isDeg ) {
int d(0), m(0);
double s(0.0);
bool checkValue( false ), badEntry( false ), negative( false );
TQString entry = str.stripWhiteSpace();
//remove any instances of unit characters.
//h, d, m, s, ', ", or the degree symbol (ASCII 176)
entry.replace( TQRegExp("h"), "" );
entry.replace( TQRegExp("d"), "" );
entry.replace( TQRegExp("m"), "" );
entry.replace( TQRegExp("s"), "" );
TQString sdeg;
sdeg.sprintf("%c", 176);
entry.replace( TQRegExp(sdeg), "" );
entry.replace( TQRegExp("\'"), "" );
entry.replace( TQRegExp("\""), "" );
//Account for localized decimal-point settings
//TQString::toDouble() requires that the decimal symbol is "."
entry.replace( KGlobal::locale()->decimalSymbol(), "." );
//empty entry returns false
if ( entry.isEmpty() ) {
setD( 0.0 );
return false;
}
//try parsing a simple integer
d = entry.toInt( &checkValue );
if ( checkValue ) {
if (isDeg) setD( d, 0, 0 );
else setH( d, 0, 0 );
return true;
}
//try parsing a simple double
double x = entry.toDouble( &checkValue );
if ( checkValue ) {
if ( isDeg ) setD( x );
else setH( x );
return true;
}
//try parsing multiple fields.
TQStringList fields;
//check for colon-delimiters or space-delimiters
if ( entry.contains(':') )
fields = TQStringList::split( ':', entry );
else fields = TQStringList::split( " ", entry );
//anything with one field is invalid!
if ( fields.count() == 1 ) {
setD(0.0);
return false;
}
//If two fields we will add a third one, and then parse with
//the 3-field code block. If field[1] is an int, add a third field equal to "0".
//If field[1] is a double, convert it to integer arcmin, and convert
//the remainder to integer arcsec
//If field[1] is neither int nor double, return false.
if ( fields.count() == 2 ) {
m = fields[1].toInt( &checkValue );
if ( checkValue ) fields.append( TQString( "0" ) );
else {
double mx = fields[1].toDouble( &checkValue );
if ( checkValue ) {
fields[1] = TQString("%1").arg( int(mx) );
fields.append( TQString("%1").arg( int( 60.0*(mx - int(mx)) ) ) );
} else {
setD( 0.0 );
return false;
}
}
}
//Now have (at least) three fields ( h/d m s );
//we can ignore anything after 3rd field
if ( fields.count() >= 3 ) {
//See if first two fields parse as integers, and third field as a double
d = fields[0].toInt( &checkValue );
if ( !checkValue ) badEntry = true;
m = fields[1].toInt( &checkValue );
if ( !checkValue ) badEntry = true;
s = fields[2].toDouble( &checkValue );
if ( !checkValue ) badEntry = true;
//Special case: If first field is "-0", store the negative sign.
//(otherwise it gets dropped)
if ( fields[0].at(0) == '-' && d == 0 ) negative = true;
}
if ( !badEntry ) {
double D = (double)abs(d) + (double)abs(m)/60.
+ (double)fabs(s)/3600.;
if ( negative || d<0 || m < 0 || s<0 ) { D = -1.0*D;}
if (isDeg) {
setD( D );
} else {
setH( D );
}
} else {
setD( 0.0 );
return false;
}
return true;
}
const int dms::arcmin( void ) const {
int am = int( float( 60.0*( fabs(D) - abs( degree() ) ) ) );
if ( D<0.0 && D>-1.0 ) { //angle less than zero, but greater than -1.0
am = -1*am; //make minute negative
}
return am;
}
const int dms::arcsec( void ) const {
int as = int( float( 60.0*( 60.0*( fabs(D) - abs( degree() ) ) - abs( arcmin() ) ) ) );
//If the angle is slightly less than 0.0, give ArcSec a neg. sgn.
if ( degree()==0 && arcmin()==0 && D<0.0 ) {
as = -1*as;
}
return as;
}
const int dms::marcsec( void ) const {
int as = int( float( 1000.0*(60.0*( 60.0*( fabs(D) - abs( degree() ) ) - abs( arcmin() ) ) - abs( arcsec() ) ) ) );
//If the angle is slightly less than 0.0, give ArcSec a neg. sgn.
if ( degree()==0 && arcmin()==0 && arcsec()== 0 && D<0.0 ) {
as = -1*as;
}
return as;
}
const int dms::minute( void ) const {
int hm = int( float( 60.0*( fabs( Hours() ) - abs( hour() ) ) ) );
if ( Hours()<0.0 && Hours()>-1.0 ) { //angle less than zero, but greater than -1.0
hm = -1*hm; //make minute negative
}
return hm;
}
const int dms::second( void ) const {
int hs = int( float( 60.0*( 60.0*( fabs( Hours() ) - abs( hour() ) ) - abs( minute() ) ) ) );
if ( hour()==0 && minute()==0 && Hours()<0.0 ) {
hs = -1*hs;
}
return hs;
}
const int dms::msecond( void ) const {
int hs = int( float( 1000.0*(60.0*( 60.0*( fabs( Hours() ) - abs( hour() ) ) - abs( minute() ) ) - abs( second() ) ) ) );
if ( hour()==0 && minute()==0 && second()==0 && Hours()<0.0 ) {
hs = -1*hs;
}
return hs;
}
const double& dms::sin( void ) const {
if ( scDirty ) {
double s,c;
SinCos( s, c );
}
return Sin;
}
const double& dms::cos( void ) const {
if ( scDirty ) {
double s,c;
SinCos( s, c );
}
return Cos;
}
void dms::SinCos( double &sina, double &cosa ) const {
/**We have two versions of this function. One is ANSI standard, but
*slower. The other is faster, but is GNU only.
*Using the __GLIBC_ and __GLIBC_MINOR_ constants to determine if the
* GNU extension sincos() is defined.
*/
if ( scDirty ) {
#ifdef __GLIBC__
#if ( __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 && !defined(__UCLIBC__))
//GNU version
sincos( radians(), &Sin, &Cos );
#else
//For older GLIBC versions
Sin = ::sin( radians() );
Cos = ::cos( radians() );
#endif
#else
//ANSI-compliant version
Sin = ::sin( radians() );
Cos = ::cos( radians() );
#endif
scDirty = false;
}
sina = Sin;
cosa = Cos;
}
const double& dms::radians( void ) const {
if ( rDirty ) {
Radians = D*DegToRad;
rDirty = false;
}
return Radians;
}
const dms dms::reduce( void ) const {
double a = D;
while (a<0.0) {a += 360.0;}
while (a>=360.0) {a -= 360.0;}
return dms( a );
}
const TQString dms::toDMSString(bool forceSign) const {
TQString dummy;
char pm(' ');
int dd = abs(degree());
int dm = abs(arcmin());
int ds = abs(arcsec());
if ( Degrees() < 0.0 ) pm = '-';
else if (forceSign && Degrees() > 0.0 ) pm = '+';
TQString format( "%c%3d%c %02d\' %02d\"" );
if ( dd < 100 ) format = "%c%2d%c %02d\' %02d\"";
if ( dd < 10 ) format = "%c%1d%c %02d\' %02d\"";
return dummy.sprintf(format.local8Bit(), pm, dd, 176, dm, ds);
}
const TQString dms::toHMSString() const {
TQString dummy;
return dummy.sprintf("%02dh %02dm %02ds", hour(), minute(), second());
}
dms dms::fromString(TQString & st, bool deg) {
dms result;
bool ok( false );
ok = result.setFromString( st, deg );
// if ( ok )
return result;
// else {
// kdDebug() << i18n( "Could Not Set Angle from string: " ) << st << endl;
// return result;
// }
}
// M_PI is defined in math.h
const double dms::PI = M_PI;
const double dms::DegToRad = PI/180.0;