StelUtils.cpp   StelUtils.cpp 
skipping to change at line 20 skipping to change at line 20
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/ */
#include <cmath> // std::fmod
#ifdef CYGWIN #ifdef CYGWIN
#include <malloc.h> #include <malloc.h>
#endif #endif
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "VecMath.hpp" #include "VecMath.hpp"
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTextStream> #include <QTextStream>
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
#include <QLocale> #include <QLocale>
#include <QRegExp> #include <QRegExp>
#include <QtGlobal> #include <QProcess>
#include <QSysInfo>
#include <cmath> // std::fmod
#include <zlib.h>
namespace StelUtils namespace StelUtils
{ {
//! Return the full name of stellarium, i.e. "stellarium 0.9.0" //! Return the full name of stellarium, i.e. "stellarium 0.9.0"
QString getApplicationName() QString getApplicationName()
{ {
return QString("Stellarium")+" "+StelUtils::getApplicationVersion(); return QString("Stellarium")+" "+StelUtils::getApplicationVersion();
} }
//! Return the version of stellarium, i.e. "0.9.0" //! Return the version of stellarium, i.e. "0.9.0"
skipping to change at line 57 skipping to change at line 58
{ {
#ifdef BZR_REVISION #ifdef BZR_REVISION
return QString(PACKAGE_VERSION)+" (BZR r"+BZR_REVISION+")"; return QString(PACKAGE_VERSION)+" (BZR r"+BZR_REVISION+")";
#elif SVN_REVISION #elif SVN_REVISION
return QString(PACKAGE_VERSION)+" (SVN r"+SVN_REVISION+")"; return QString(PACKAGE_VERSION)+" (SVN r"+SVN_REVISION+")";
#else #else
return QString(PACKAGE_VERSION); return QString(PACKAGE_VERSION);
#endif #endif
} }
QString getOperatingSystemInfo()
{
QString OS = "Unknown operating system";
#ifdef Q_OS_WIN
switch(QSysInfo::WindowsVersion)
{
case QSysInfo::WV_95:
OS = "Windows 95";
break;
case QSysInfo::WV_98:
OS = "Windows 98";
break;
case QSysInfo::WV_Me:
OS = "Windows Me";
break;
case QSysInfo::WV_NT:
OS = "Windows NT";
break;
case QSysInfo::WV_2000:
OS = "Windows 2000";
break;
case QSysInfo::WV_XP:
OS = "Windows XP";
break;
case QSysInfo::WV_2003:
OS = "Windows Server 2003";
break;
case QSysInfo::WV_VISTA:
OS = "Windows Vista";
break;
case QSysInfo::WV_WINDOWS7:
OS = "Windows 7";
break;
#ifdef WV_WINDOWS8
case QSysInfo::WV_WINDOWS8:
OS = "Windows 8";
break;
#endif
#ifdef WV_WINDOWS8_1
case QSysInfo::WV_WINDOWS8_1
OS = "Windows 8.1";
break;
#endif
default:
OS = "Unsupported Windows version";
break;
}
// somebody writing something useful for Macs would be great here
#elif defined Q_OS_MAC
switch(QSysInfo::MacintoshVersion)
{
case QSysInfo::MV_PANTHER:
OS = "Mac OS X 10.3 series";
break;
case QSysInfo::MV_TIGER:
OS = "Mac OS X 10.4 series";
break;
case QSysInfo::MV_LEOPARD:
OS = "Mac OS X 10.5 series";
break;
case QSysInfo::MV_SNOWLEOPARD:
OS = "Mac OS X 10.6 series";
break;
case QSysInfo::MV_LION:
OS = "Mac OS X 10.7 series";
break;
case QSysInfo::MV_MOUNTAINLION:
OS = "Mac OS X 10.8 series";
break;
case QSysInfo::MV_MAVERICKS:
OS = "Mac OS X 10.9 series";
break;
#ifdef MV_YOSEMITE
case QSysInfo::MV_YOSEMITE
OS = "Mac OS X 10.10 series";
break;
#endif
default:
OS = "Unsupported Mac version";
break;
}
#elif defined Q_OS_LINUX
QFile procVersion("/proc/version");
if(!procVersion.open(QIODevice::ReadOnly | QIODevice::Text))
OS = "Unknown Linux version";
else
{
QString version = procVersion.readAll();
if(version.right(1) == "\n")
version.chop(1);
OS = version;
procVersion.close();
}
#elif defined Q_OS_BSD4
// Check FreeBSD, NetBSD, OpenBSD and DragonFly BSD
QProcess uname;
uname.start("/usr/bin/uname -srm");
uname.waitForStarted();
uname.waitForFinished();
const QString BSDsystem = uname.readAllStandardOutput();
OS = BSDsystem.trimmed();
#endif
return OS;
}
double hmsToRad(const unsigned int h, const unsigned int m, const double s ) double hmsToRad(const unsigned int h, const unsigned int m, const double s )
{ {
//return (double)M_PI/24.*h*2.+(double)M_PI/12.*m/60.+s*M_PI/43200.; // Wrong formula! --AW //return (double)M_PI/24.*h*2.+(double)M_PI/12.*m/60.+s*M_PI/43200.; // Wrong formula! --AW
return (double)h*M_PI/12.+(double)m*M_PI/10800.+(double)s*M_PI/64800 0.; return (double)h*M_PI/12.+(double)m*M_PI/10800.+(double)s*M_PI/64800 0.;
} }
double dmsToRad(const int d, const unsigned int m, const double s) double dmsToRad(const int d, const unsigned int m, const double s)
{ {
if (d>=0) if (d>=0)
return (double)M_PI/180.*d+(double)M_PI/10800.*m+s*M_PI/6480 00.; return (double)M_PI/180.*d+(double)M_PI/10800.*m+s*M_PI/6480 00.;
skipping to change at line 106 skipping to change at line 216
} }
angle *= 180./M_PI; angle *= 180./M_PI;
d = (unsigned int)angle; d = (unsigned int)angle;
m = (unsigned int)((angle - d)*60); m = (unsigned int)((angle - d)*60);
s = (angle-d)*3600-60*m; s = (angle-d)*3600-60*m;
// workaround for rounding numbers // workaround for rounding numbers
if (s>59.9) if (s>59.9)
{ {
s = 0.; s = 0.;
if (sign) m += 1;
m += 1;
else
m -= 1;
} }
if (m==60) if (m==60)
{ {
m = 0.; m = 0.;
if (sign) d += 1;
d += 1;
else
d -= 1;
} }
} }
/************************************************************************* /*************************************************************************
Convert an angle in radian to a hms formatted string Convert an angle in radian to a hms formatted string
If the minute and second part are null are too small, don't print them If the minute and second part are null are too small, don't print them
*************************************************************************/ *************************************************************************/
QString radToHmsStrAdapt(const double angle) QString radToHmsStrAdapt(const double angle)
{ {
unsigned int h,m; unsigned int h,m;
skipping to change at line 420 skipping to change at line 524
qDebug() << "getDecAngle failed to parse angle string:" << str; qDebug() << "getDecAngle failed to parse angle string:" << str;
return -0.0; return -0.0;
} }
// Check if a number is a power of 2 // Check if a number is a power of 2
bool isPowerOfTwo(const int value) bool isPowerOfTwo(const int value)
{ {
return (value & -value) == value; return (value & -value) == value;
} }
// Return the first power of two greater or equal to the given value // Return the first power of two bigger than the given value
int smallestPowerOfTwoGreaterOrEqualTo(const int value) int getBiggerPowerOfTwo(int value)
{
#ifndef NDEBUG
const int twoTo30 = 1073741824;
Q_ASSERT_X(value <= twoTo30, Q_FUNC_INFO,
"Value too large - smallest greater/equal power-of-2 is o
ut of range");
#endif
if(value == 0){return 0;}
int pot=1;
while (pot<value){pot<<=1;}
return pot;
}
QSize smallestPowerOfTwoSizeGreaterOrEqualTo(const QSize base)
{ {
return QSize(smallestPowerOfTwoGreaterOrEqualTo(base.width()), int p=1;
smallestPowerOfTwoGreaterOrEqualTo(base.height())); while (p<value)
p<<=1;
return p;
} }
// Return the inverse sinus hyperbolic of z // Return the inverse sinus hyperbolic of z
double asinh(const double z) double asinh(const double z)
{ {
return std::log(z+std::sqrt(z*z+1)); double returned;
if(z>0)
returned = std::log(z + std::sqrt(z*z+1));
else
returned = -std::log(-z + std::sqrt(z*z+1));
return returned;
} }
/************************************************************************* /*************************************************************************
Convert a QT QDateTime class to julian day Convert a QT QDateTime class to julian day
*************************************************************************/ *************************************************************************/
double qDateTimeToJd(const QDateTime& dateTime) double qDateTimeToJd(const QDateTime& dateTime)
{ {
return (double)(dateTime.date().toJulianDay())+(double)1./(24*60*60* 1000)*QTime().msecsTo(dateTime.time())-0.5; return (double)(dateTime.date().toJulianDay())+(double)1./(24*60*60* 1000)*QTime(0, 0, 0, 0).msecsTo(dateTime.time())-0.5;
} }
QDateTime jdToQDateTime(const double& jd) QDateTime jdToQDateTime(const double& jd)
{ {
int year, month, day; int year, month, day;
getDateFromJulianDay(jd, &year, &month, &day); getDateFromJulianDay(jd, &year, &month, &day);
QDateTime result = QDateTime::fromString(QString("%1.%2.%3").arg(yea r, 4, 10, QLatin1Char('0')).arg(month).arg(day), "yyyy.M.d"); QDateTime result = QDateTime::fromString(QString("%1.%2.%3").arg(yea r, 4, 10, QLatin1Char('0')).arg(month).arg(day), "yyyy.M.d");
result.setTime(jdFractionToQTime(jd)); result.setTime(jdFractionToQTime(jd));
return result; return result;
} }
skipping to change at line 702 skipping to change at line 799
//! use QDateTime to get a Julian Date from the system's current time. //! use QDateTime to get a Julian Date from the system's current time.
//! this is an acceptable use of QDateTime because the system's current //! this is an acceptable use of QDateTime because the system's current
//! time is more than likely always going to be expressible by QDateTime. //! time is more than likely always going to be expressible by QDateTime.
double getJDFromSystem() double getJDFromSystem()
{ {
return qDateTimeToJd(QDateTime::currentDateTime().toUTC()); return qDateTimeToJd(QDateTime::currentDateTime().toUTC());
} }
double qTimeToJDFraction(const QTime& time) double qTimeToJDFraction(const QTime& time)
{ {
return (double)1./(24*60*60*1000)*QTime().msecsTo(time)-0.5; return (double)1./(24*60*60*1000)*QTime(0, 0, 0, 0).msecsTo(time)-0. 5;
} }
QTime jdFractionToQTime(const double jd) QTime jdFractionToQTime(const double jd)
{ {
double decHours = std::fmod(jd+0.5, 1.0); double decHours = std::fmod(jd+0.5, 1.0);
int hours = (int)(decHours/0.041666666666666666666); int hours = (int)(decHours/0.041666666666666666666);
int mins = (int)((decHours-(hours*0.041666666666666666666))/0.000694 44444444444444444); int mins = (int)((decHours-(hours*0.041666666666666666666))/0.000694 44444444444444444);
return QTime::fromString(QString("%1.%2").arg(hours).arg(mins), "h.m "); return QTime::fromString(QString("%1.%2").arg(hours).arg(mins), "h.m ");
} }
skipping to change at line 749 skipping to change at line 846
return shiftInHours; return shiftInHours;
} }
// UTC ! // UTC !
bool getJDFromDate(double* newjd, const int y, const int m, const int d, co nst int h, const int min, const int s) bool getJDFromDate(double* newjd, const int y, const int m, const int d, co nst int h, const int min, const int s)
{ {
static const long IGREG2 = 15+31L*(10+12L*1582); static const long IGREG2 = 15+31L*(10+12L*1582);
double deltaTime = (h / 24.0) + (min / (24.0*60.0)) + (s / (24.0 * 6 0.0 * 60.0)) - 0.5; double deltaTime = (h / 24.0) + (min / (24.0*60.0)) + (s / (24.0 * 6 0.0 * 60.0)) - 0.5;
QDate test((y <= 0 ? y-1 : y), m, d); QDate test((y <= 0 ? y-1 : y), m, d);
// if QDate will oblige, do so. // if QDate will oblige, do so.
if ( test.isValid() ) // added hook for Julian calendar, because he has been removed from
Qt5 --AW
if ( test.isValid() && y>1582)
{ {
double qdjd = (double)test.toJulianDay(); double qdjd = (double)test.toJulianDay();
qdjd += deltaTime; qdjd += deltaTime;
*newjd = qdjd; *newjd = qdjd;
return true; return true;
} }
else else
{ {
/* /*
* Algorithm taken from "Numerical Recipes in c, 2nd Ed." (1 992), pp. 11-12 * Algorithm taken from "Numerical Recipes in c, 2nd Ed." (1 992), pp. 11-12
skipping to change at line 1063 skipping to change at line 1161
double a = AU*1000*SemiMajorAxis; double a = AU*1000*SemiMajorAxis;
// Calculate orbital period in seconds // Calculate orbital period in seconds
// Here 1.32712440018e20 is heliocentric gravitational constant // Here 1.32712440018e20 is heliocentric gravitational constant
double period = 2*M_PI*std::sqrt(a*a*a/1.32712440018e20); double period = 2*M_PI*std::sqrt(a*a*a/1.32712440018e20);
return period/86400; // return period in days return period/86400; // return period in days
} }
QString hoursToHmsStr(const double hours) QString hoursToHmsStr(const double hours)
{ {
int h = (int)hours; int h = (int)hours;
int m = (int)((std::abs(hours)-std::abs(h))*60); int m = (int)((std::abs(hours)-std::abs(double(h)))*60);
float s = (((std::abs(hours)-std::abs(h))*60)-m)*60; float s = (((std::abs(hours)-std::abs(double(h)))*60)-m)*60;
return QString("%1h%2m%3s").arg(h).arg(m).arg(QString::number(s, 'f' , 1)); return QString("%1h%2m%3s").arg(h).arg(m).arg(QString::number(s, 'f' , 1));
} }
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
#include <sys/time.h>
#else
#include <time.h>
#endif
//! Get current time in seconds (relative to some arbitrary beginning in th
e past)
//!
//! Currently we only have a high-precision implementation for Mac, Linux a
nd
//! FreeBSD. A Windows implementation would be good as well (clock_t,
//! which we use right now, might be faster/slower than wall clock time
//! and usually supports milliseconds at best).
static long double getTime()
{
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
struct timeval timeVal;
if(gettimeofday(&timeVal, NULL) != 0)
{
Q_ASSERT_X(false, Q_FUNC_INFO, "Failed to get time");
}
return static_cast<long double>(timeVal.tv_sec) + 0.000001L * timeVa
l.tv_usec;
#else
clock_t cpuTime = clock();
return static_cast<long double>(cpuTime) / CLOCKS_PER_SEC;
#endif
}
//! Time when the program execution started.
long double startTime = getTime();
long double secondsSinceStart()
{
return getTime() - startTime;
}
/* /////////////////// DELTA T VARIANTS /* /////////////////// DELTA T VARIANTS
// For the standard epochs for many formulae, we use // For the standard epochs for many formulae, we use
// J2000.0=2000-jan-1.5=2451545.0, // J2000.0=2000-jan-1.5=2451545.0,
// 1900.0=1900-jan-0.5=2415020.0 // 1900.0=1900-jan-0.5=2415020.0
// 1820.0=1820-jan-0.5=2385800.0 // 1820.0=1820-jan-0.5=2385800.0
// 1810.0=1810-jan-0.5=2382148.0 // 1810.0=1810-jan-0.5=2382148.0
// 1800.0=1800-jan-0.5=2378496.0 // 1800.0=1800-jan-0.5=2378496.0
// 1735.0=1735-jan-0.5=2354755.0 // 1735.0=1735-jan-0.5=2354755.0
// 1625.0=1625-jan-0.5=2314579.0 // 1625.0=1625-jan-0.5=2314579.0
*/ */
skipping to change at line 1726 skipping to change at line 1789
if (-1000 <= year && year <= 1600) if (-1000 <= year && year <= 1600)
{ {
double cDiff1820= (jDay-2385800.0)/36525.0; // 1820.0=182 0-jan-0.5=2385800.0 double cDiff1820= (jDay-2385800.0)/36525.0; // 1820.0=182 0-jan-0.5=2385800.0
// sigma = std::pow((yeardec-1820.0)/100,2); // sigma(DeltaT ) = 0.8*u^2 // sigma = std::pow((yeardec-1820.0)/100,2); // sigma(DeltaT ) = 0.8*u^2
sigma = 0.8 * cDiff1820 * cDiff1820; sigma = 0.8 * cDiff1820 * cDiff1820;
} }
return sigma; return sigma;
} }
// Arrays to keep cos/sin of angles and multiples of angles. rho and theta
are delta angles, and these arrays
#define MAX_STACKS 4096
static float cos_sin_rho[2*(MAX_STACKS+1)];
#define MAX_SLICES 4096
static float cos_sin_theta[2*(MAX_SLICES+1)];
//! Compute cosines and sines around a circle which is split in "segments"
parts.
//! Values are stored in the global static array cos_sin_theta.
//! Used for the sin/cos values along a latitude circle, equator, etc. for
a spherical mesh.
//! @param slices number of partitions (elsewhere called "segments") for th
e circle
float* ComputeCosSinTheta(const int slices)
{
Q_ASSERT(slices<=MAX_SLICES);
// Difference angle between the stops. Always use 2*M_PI/slices!
const float dTheta = 2.f * M_PI / slices;
float *cos_sin = cos_sin_theta;
float *cos_sin_rev = cos_sin + 2*(slices+1);
const float c = std::cos(dTheta);
const float s = std::sin(dTheta);
*cos_sin++ = 1.f;
*cos_sin++ = 0.f;
*--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2];
*cos_sin++ = c;
*cos_sin++ = s;
*--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2];
while (cos_sin < cos_sin_rev) // compares array address indices on
ly!
{
// avoid expensive trig functions by use of the addition the
orem.
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
cos_sin += 2;
*--cos_sin_rev = -cos_sin[-1];
*--cos_sin_rev = cos_sin[-2];
}
return cos_sin_theta;
}
//! Compute cosines and sines around a half-circle which is split in "segme
nts" parts.
//! Values are stored in the global static array cos_sin_rho.
//! Used for the sin/cos values along a meridian for a spherical mesh.
//! @param segments number of partitions (elsewhere called "stacks") for th
e half-circle
float* ComputeCosSinRho(const int segments)
{
Q_ASSERT(segments<=MAX_STACKS);
// Difference angle between the stops. Always use M_PI/segments!
const float dRho = M_PI / segments;
float *cos_sin = cos_sin_rho;
float *cos_sin_rev = cos_sin + 2*(segments+1);
const float c = std::cos(dRho);
const float s = std::sin(dRho);
*cos_sin++ = 1.f;
*cos_sin++ = 0.f;
*--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2];
*cos_sin++ = c;
*cos_sin++ = s;
*--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2];
while (cos_sin < cos_sin_rev) // compares array address indices o
nly!
{
// avoid expensive trig functions by use of the addition the
orem.
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
cos_sin += 2;
*--cos_sin_rev = cos_sin[-1];
*--cos_sin_rev = -cos_sin[-2];
}
return cos_sin_rho;
}
//! Compute cosines and sines around part of a circle (from top to bottom)
which is split in "segments" parts.
//! Values are stored in the global static array cos_sin_rho.
//! Used for the sin/cos values along a meridian.
//! GZ: allow leaving away pole caps. The array now contains values for the
region minAngle+segments*phi
//! @param dRho a difference angle between the stops
//! @param segments number of segments
//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+s
egments*phi
float *ComputeCosSinRhoZone(const float dRho, const int segments, const flo
at minAngle)
{
float *cos_sin = cos_sin_rho;
const float c = cos(dRho);
const float s = sin(dRho);
*cos_sin++ = cos(minAngle);
*cos_sin++ = sin(minAngle);
for (int i=0; i<segments; ++i) // we cannot mirror this, it may be u
nequal.
{ // efficient computation, avoid expensive trig functions by use
of the addition theorem.
cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
cos_sin += 2;
}
return cos_sin_rho;
}
//! Uncompress gzip or zlib compressed data.
QByteArray uncompress(const QByteArray& data)
{
if (data.size() <= 4)
return QByteArray();
static const int CHUNK = 1024;
QByteArray buffer(CHUNK, 0);
QByteArray out;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = data.size();
strm.next_in = (Bytef*)(data.data());
// 15 + 32 for gzip automatic header detection.
int ret = inflateInit2(&strm, 15 + 32);
if (ret != Z_OK) return QByteArray();
do
{
strm.avail_out = CHUNK;
strm.next_out = (Bytef*)(buffer.data());
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR);
if (ret < 0)
{
out.clear();
break;
}
out.append(buffer.data(), CHUNK - strm.avail_out);
}
while (strm.avail_out == 0);
inflateEnd(&strm);
return out;
}
} // end of the StelUtils namespace } // end of the StelUtils namespace
 End of changes. 14 change blocks. 
75 lines changed or deleted 287 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/