moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / dms.cpp
blob0cc280c39551dc5d7d3cb9cd42f15ad8c755f98d
1 /***************************************************************************
2 dms.cpp - K Desktop Planetarium
3 -------------------
4 begin : Sun Feb 11 2001
5 copyright : (C) 2001 by Jason Harris
6 email : jharris@30doradus.org
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include <stdlib.h>
20 #include "dms.h"
21 #include <kglobal.h>
22 #include <klocale.h>
23 #include <qregexp.h>
25 void dms::setD( const double &x ) {
26 D = x;
27 scDirty = true;
28 rDirty = true;
31 void dms::setD(const int &d, const int &m, const int &s, const int &ms) {
32 D = (double)abs(d) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.;
33 if (d<0) {D = -1.0*D;}
34 scDirty = true;
35 rDirty = true;
38 void dms::setH( const double &x ) {
39 setD( x*15.0 );
42 void dms::setH(const int &h, const int &m, const int &s, const int &ms) {
43 D = 15.0*((double)abs(h) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.);
44 if (h<0) {D = -1.0*D;}
45 scDirty = true;
46 rDirty = true;
49 void dms::setRadians( const double &Rad ) {
50 setD( Rad/DegToRad );
51 Radians = Rad;
54 bool dms::setFromString( const QString &str, bool isDeg ) {
55 int d(0), m(0);
56 double s(0.0);
57 bool checkValue( false ), badEntry( false ), negative( false );
58 QString entry = str.stripWhiteSpace();
60 //remove any instances of unit characters.
61 //h, d, m, s, ', ", or the degree symbol (ASCII 176)
62 entry.replace( QRegExp("h"), "" );
63 entry.replace( QRegExp("d"), "" );
64 entry.replace( QRegExp("m"), "" );
65 entry.replace( QRegExp("s"), "" );
66 QString sdeg;
67 sdeg.sprintf("%c", 176);
68 entry.replace( QRegExp(sdeg), "" );
69 entry.replace( QRegExp("\'"), "" );
70 entry.replace( QRegExp("\""), "" );
72 //Account for localized decimal-point settings
73 //QString::toDouble() requires that the decimal symbol is "."
74 entry.replace( KGlobal::locale()->decimalSymbol(), "." );
76 //empty entry returns false
77 if ( entry.isEmpty() ) {
78 setD( 0.0 );
79 return false;
82 //try parsing a simple integer
83 d = entry.toInt( &checkValue );
84 if ( checkValue ) {
85 if (isDeg) setD( d, 0, 0 );
86 else setH( d, 0, 0 );
87 return true;
90 //try parsing a simple double
91 double x = entry.toDouble( &checkValue );
92 if ( checkValue ) {
93 if ( isDeg ) setD( x );
94 else setH( x );
95 return true;
98 //try parsing multiple fields.
99 QStringList fields;
101 //check for colon-delimiters or space-delimiters
102 if ( entry.contains(':') )
103 fields = QStringList::split( ':', entry );
104 else fields = QStringList::split( " ", entry );
106 //anything with one field is invalid!
107 if ( fields.count() == 1 ) {
108 setD(0.0);
109 return false;
112 //If two fields we will add a third one, and then parse with
113 //the 3-field code block. If field[1] is an int, add a third field equal to "0".
114 //If field[1] is a double, convert it to integer arcmin, and convert
115 //the remainder to integer arcsec
116 //If field[1] is neither int nor double, return false.
117 if ( fields.count() == 2 ) {
118 m = fields[1].toInt( &checkValue );
119 if ( checkValue ) fields.append( QString( "0" ) );
120 else {
121 double mx = fields[1].toDouble( &checkValue );
122 if ( checkValue ) {
123 fields[1] = QString("%1").arg( int(mx) );
124 fields.append( QString("%1").arg( int( 60.0*(mx - int(mx)) ) ) );
125 } else {
126 setD( 0.0 );
127 return false;
132 //Now have (at least) three fields ( h/d m s );
133 //we can ignore anything after 3rd field
134 if ( fields.count() >= 3 ) {
135 //See if first two fields parse as integers, and third field as a double
137 d = fields[0].toInt( &checkValue );
138 if ( !checkValue ) badEntry = true;
139 m = fields[1].toInt( &checkValue );
140 if ( !checkValue ) badEntry = true;
141 s = fields[2].toDouble( &checkValue );
142 if ( !checkValue ) badEntry = true;
144 //Special case: If first field is "-0", store the negative sign.
145 //(otherwise it gets dropped)
146 if ( fields[0].at(0) == '-' && d == 0 ) negative = true;
149 if ( !badEntry ) {
150 double D = (double)abs(d) + (double)abs(m)/60.
151 + (double)fabs(s)/3600.;
153 if ( negative || d<0 || m < 0 || s<0 ) { D = -1.0*D;}
155 if (isDeg) {
156 setD( D );
157 } else {
158 setH( D );
160 } else {
161 setD( 0.0 );
162 return false;
165 return true;
168 const int dms::arcmin( void ) const {
169 int am = int( 60.0*( fabs(D) - abs( degree() ) ) );
170 if ( D<0.0 && D>-1.0 ) { //angle less than zero, but greater than -1.0
171 am = -1*am; //make minute negative
173 return am;
176 const int dms::arcsec( void ) const {
177 int as = int( 60.0*( 60.0*( fabs(D) - abs( degree() ) ) - abs( arcmin() ) ) );
178 //If the angle is slightly less than 0.0, give ArcSec a neg. sgn.
179 if ( degree()==0 && arcmin()==0 && D<0.0 ) {
180 as = -1*as;
182 return as;
185 const int dms::marcsec( void ) const {
186 int as = int( 1000.0*(60.0*( 60.0*( fabs(D) - abs( degree() ) ) - abs( arcmin() ) ) - abs( arcsec() ) ) );
187 //If the angle is slightly less than 0.0, give ArcSec a neg. sgn.
188 if ( degree()==0 && arcmin()==0 && arcsec()== 0 && D<0.0 ) {
189 as = -1*as;
191 return as;
194 const int dms::minute( void ) const {
195 int hm = int( 60.0*( fabs( Hours() ) - abs( hour() ) ) );
196 if ( Hours()<0.0 && Hours()>-1.0 ) { //angle less than zero, but greater than -1.0
197 hm = -1*hm; //make minute negative
199 return hm;
202 const int dms::second( void ) const {
203 int hs = int( 60.0*( 60.0*( fabs( Hours() ) - abs( hour() ) ) - abs( minute() ) ) );
204 if ( hour()==0 && minute()==0 && Hours()<0.0 ) {
205 hs = -1*hs;
207 return hs;
210 const int dms::msecond( void ) const {
211 int hs = int( 1000.0*(60.0*( 60.0*( fabs( Hours() ) - abs( hour() ) ) - abs( minute() ) ) - abs( second() ) ) );
212 if ( hour()==0 && minute()==0 && second()==0 && Hours()<0.0 ) {
213 hs = -1*hs;
215 return hs;
218 const double& dms::sin( void ) const {
219 if ( scDirty ) {
220 double s,c;
221 SinCos( s, c );
224 return Sin;
227 const double& dms::cos( void ) const {
228 if ( scDirty ) {
229 double s,c;
230 SinCos( s, c );
233 return Cos;
236 void dms::SinCos( double &sina, double &cosa ) const {
237 /**We have two versions of this function. One is ANSI standard, but
238 *slower. The other is faster, but is GNU only.
239 *Using the __GLIBC_ and __GLIBC_MINOR_ constants to determine if the
240 * GNU extension sincos() is defined.
243 if ( scDirty ) {
244 #ifdef __GLIBC__
245 #if ( __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 )
246 //GNU version
247 sincos( radians(), &Sin, &Cos );
248 #else
249 //For older GLIBC versions
250 Sin = ::sin( radians() );
251 Cos = ::cos( radians() );
252 #endif
253 #else
254 //ANSI-compliant version
255 Sin = ::sin( radians() );
256 Cos = ::cos( radians() );
257 #endif
258 scDirty = false;
260 sina = Sin;
261 cosa = Cos;
264 const double& dms::radians( void ) const {
265 if ( rDirty ) {
266 Radians = D*DegToRad;
267 rDirty = false;
270 return Radians;
273 const dms dms::reduce( void ) const {
274 double a = D;
275 while (a<0.0) {a += 360.0;}
276 while (a>=360.0) {a -= 360.0;}
277 return dms( a );
280 const QString dms::toDMSString(bool forceSign) const {
281 QString dummy;
282 char pm(' ');
283 int dd = abs(degree());
284 int dm = abs(arcmin());
285 int ds = abs(arcsec());
287 if ( Degrees() < 0.0 ) pm = '-';
288 else if (forceSign && Degrees() > 0.0 ) pm = '+';
290 QString format( "%c%3d%c %02d\' %02d\"" );
291 if ( dd < 100 ) format = "%c%2d%c %02d\' %02d\"";
292 if ( dd < 10 ) format = "%c%1d%c %02d\' %02d\"";
294 return dummy.sprintf(format.local8Bit(), pm, dd, 176, dm, ds);
297 const QString dms::toHMSString() const {
298 QString dummy;
299 return dummy.sprintf("%02dh %02dm %02ds", hour(), minute(), second());
302 dms dms::fromString(QString & st, bool deg) {
303 dms result;
304 bool ok( false );
306 ok = result.setFromString( st, deg );
308 // if ( ok )
309 return result;
310 // else {
311 // kdDebug() << i18n( "Could Not Set Angle from string: " ) << st << endl;
312 // return result;
313 // }
316 // M_PI is defined in math.h
317 const double dms::PI = M_PI;
318 const double dms::DegToRad = PI/180.0;