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.
319 lines
8.4 KiB
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 <tdeglobal.h>
|
|
#include <tdelocale.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( TDEGlobal::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;
|