MeteorShower.cpp   MeteorShower.cpp 
/* /*
* Stellarium: Meteor Showers Plug-in * Stellarium: Meteor Showers Plug-in
* Copyright (C) 2013 Marcos Cardinot * Copyright (C) 2013-2015 Marcos Cardinot
* Copyright (C) 2011 Alexander Wolf
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* 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 <QtMath>
#include "LandscapeMgr.hpp"
#include "MeteorShower.hpp" #include "MeteorShower.hpp"
#include "MeteorShowers.hpp" #include "MeteorShowers.hpp"
#include "SporadicMeteorMgr.hpp"
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelCore.hpp" #include "StelCore.hpp"
#include "StelModuleMgr.hpp" #include "StelModuleMgr.hpp"
#include "StelObjectMgr.hpp"
#include "StelTexture.hpp" #include "StelTexture.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
StelTextureSP MeteorShower::radiantTexture; MeteorShower::MeteorShower(MeteorShowersMgr* mgr, const QVariantMap& map)
bool MeteorShower::showLabels = true; : m_mgr(mgr)
bool MeteorShower::radiantMarkerEnabled = true; , m_status(INVALID)
bool MeteorShower::showActiveRadiantsOnly = true; , m_speed(0)
, m_rAlphaPeak(0)
MeteorShower::MeteorShower(const QVariantMap& map) , m_rDeltaPeak(0)
: initialized(false) , m_driftAlpha(0)
, active(false) , m_driftDelta(0)
, speed(0) , m_pidx(0)
, rAlphaPeak(0) , m_radiantAlpha(0)
, rDeltaPeak(0) , m_radiantDelta(0)
, driftAlpha(0)
, driftDelta(0)
, pidx(0)
, radiantAlpha(0)
, radiantDelta(0)
, zhr(0)
, status(0)
{ {
// return initialized if the mandatory fields are not present // return initialized if the mandatory fields are not present
if(!map.contains("showerID")) if(!map.contains("showerID") || !map.contains("activity")
|| !map.contains("radiantAlpha") || !map.contains("radiantDe
lta"))
{
qWarning() << "MeteorShower: INVALID meteor shower!" << map.
value("showerID").toString();
qWarning() << "MeteorShower: Please, check your 'showers.jso
n' catalog!";
return; return;
}
m_showerID = map.value("showerID").toString();
m_designation = map.value("designation").toString();
m_speed = map.value("speed").toInt();
m_radiantAlpha = StelUtils::getDecAngle(map.value("radiantAlpha").to
String());
m_radiantDelta = StelUtils::getDecAngle(map.value("radiantDelta").to
String());
m_parentObj = map.value("parentObj").toString();
m_pidx = map.value("pidx").toFloat();
// the catalog (IMO) will give us the drift for a five-day interval
from peak
m_driftAlpha = StelUtils::getDecAngle(map.value("driftAlpha").toStri
ng()) / 5.f;
m_driftDelta = StelUtils::getDecAngle(map.value("driftDelta").toStri
ng()) / 5.f;
m_rAlphaPeak = m_radiantAlpha;
m_rDeltaPeak = m_radiantDelta;
const int genericYear = 1000;
// build the activity list
QList<QVariant> activities = map.value("activity").toList();
foreach(const QVariant &ms, activities)
{
QVariantMap activityMap = ms.toMap();
Activity d;
d.zhr = activityMap.value("zhr").toInt();
//
// 'variable'field
//
QStringList variable = activityMap.value("variable").toStrin
g().split("-");
if (d.zhr == -1) // is variable
{
bool ok = variable.size() == 2;
for (int i=0; i < 2 && ok; i++)
{
d.variable.append(variable.at(i).toInt(&ok))
;
}
showerID = map.value("showerID").toString(); if (!ok)
designation = map.value("designation").toString(); {
speed = map.value("speed").toInt(); qWarning() << "MeteorShower: INVALID data fo
rAlphaPeak = radiantAlpha = StelUtils::getDecAngle(map.value("radian r " << m_showerID;
tAlpha").toString()); qWarning() << "MeteorShower: Please, check y
rDeltaPeak = radiantDelta = StelUtils::getDecAngle(map.value("radian our 'showers.json' catalog!";
tDelta").toString()); return;
driftAlpha = StelUtils::getDecAngle(map.value("driftAlpha").toString }
());
driftDelta = StelUtils::getDecAngle(map.value("driftDelta").toString
());
parentObj = map.value("parentObj").toString();
pidx = map.value("pidx").toFloat();
if(map.contains("activity"))
{
foreach(const QVariant &ms, map.value("activity").toList())
{
QVariantMap activityMap = ms.toMap();
activityData d;
d.year = activityMap.value("year").toString();
d.zhr = activityMap.value("zhr").toInt();
d.variable = activityMap.value("variable").toString(
);
d.peak = activityMap.value("peak").toString();
d.start = activityMap.value("start").toString();
d.finish = activityMap.value("finish").toString();
activity.append(d);
} }
//
// 'start', 'finish' and 'peak' fields
//
d.year = activityMap.value("year").toInt();
QString year = QString::number(d.year == 0 ? genericYear : d
.year);
QString start = activityMap.value("start").toString();
start = start.isEmpty() ? "" : start + " " + year;
d.start = QDate::fromString(start, "MM.dd yyyy");
QString finish = activityMap.value("finish").toString();
finish = finish.isEmpty() ? "" : finish + " " + year;
d.finish = QDate::fromString(finish, "MM.dd yyyy");
QString peak = activityMap.value("peak").toString();
peak = peak.isEmpty() ? "" : peak + " " + year;
d.peak = QDate::fromString(peak, "MM.dd yyyy");
m_activities.append(d);
}
// filling null values of the activity list with generic data
// and fixing the edge cases (showers between december and january)
const Activity& g = m_activities.at(0);
const int activitiesSize = m_activities.size();
for (int i = 0; i < activitiesSize; ++i)
{
Activity a = m_activities.at(i);
if (i != 0)
{
if (a.zhr == 0)
{
a.zhr = g.zhr;
a.variable = g.variable;
}
int aux = a.year - genericYear;
a.start = a.start.isValid() ? a.start : g.start.addY
ears(aux);
a.finish = a.finish.isValid() ? a.finish : g.finish.
addYears(aux);
a.peak = a.peak.isValid() ? a.peak : g.peak.addYears
(aux);
}
if (a.start.isValid() && a.finish.isValid() && a.peak.isVali
d())
{
// Fix the 'finish' year! Handling cases when the sh
ower starts on
// the current year and ends on the next year!
if(a.start.operator >(a.finish))
{
a.finish = a.finish.addYears(1);
}
// Fix the 'peak' year
if(a.start.operator >(a.peak))
{
a.peak = a.peak.addYears(1);
}
}
else
{
qWarning() << "MeteorShower: INVALID data for "
<< m_showerID << "Unable to read some dat
es!";
qWarning() << "MeteorShower: Please, check your 'sho
wers.json' catalog!";
return;
}
m_activities.replace(i, a);
} }
if(map.contains("colors")) if(map.contains("colors"))
{ {
int totalIntensity = 0;
foreach(const QVariant &ms, map.value("colors").toList()) foreach(const QVariant &ms, map.value("colors").toList())
{ {
QVariantMap colorMap = ms.toMap(); QVariantMap colorMap = ms.toMap();
QString color = colorMap.value("color").toString(); QString color = colorMap.value("color").toString();
int intensity = colorMap.value("intensity").toInt(); int intensity = colorMap.value("intensity").toInt();
colors.append(colorPair(color, intensity)); m_colors.append(Meteor::ColorPair(color, intensity))
;
totalIntensity += intensity;
}
// the total intensity must be 100
if (totalIntensity != 100) {
qWarning() << "MeteorShower: INVALID data for "
<< m_showerID << "The total intensity mus
t be equal to 100";
qWarning() << "MeteorShower: Please, check your 'sho
wers.json' catalog!";
m_colors.clear();
} }
} }
updateCurrentData(getSkyQDateTime()); if (m_colors.isEmpty()) {
// ensures that all objects will be drawn once m_colors.push_back(Meteor::ColorPair("white", 100));
// that's to avoid crashes by trying select a nonexistent object }
StelPainter painter(StelApp::getInstance().getCore()->getProjection(
StelCore::FrameJ2000));
draw(painter);
qsrand(QDateTime::currentMSecsSinceEpoch()); m_status = UNDEFINED;
initialized = true; qsrand(QDateTime::currentMSecsSinceEpoch());
} }
MeteorShower::~MeteorShower() MeteorShower::~MeteorShower()
{ {
// qDeleteAll(m_activeMeteors);
m_activeMeteors.clear();
} }
QVariantMap MeteorShower::getMap(void) bool MeteorShower::enabled() const
{ {
QVariantMap map; if (m_status == INVALID)
map["showerID"] = showerID; {
map["designation"] = designation; return false;
map["speed"] = speed; }
map["radiantAlpha"] = rAlphaPeak; else if (m_status == UNDEFINED)
map["radiantDelta"] = rDeltaPeak; {
map["driftAlpha"] = driftAlpha; return true;
map["driftDelta"] = driftDelta; }
map["parentObj"] = parentObj; else if (m_mgr->getActiveRadiantOnly())
map["pidx"] = pidx; {
return m_status == ACTIVE_GENERIC || m_status == ACTIVE_CONF
IRMED;
}
else
{
return true;
}
}
QVariantList activityList; void MeteorShower::update(StelCore* core, double deltaTime)
foreach(const activityData &p, activity) {
if (m_status == INVALID)
{ {
QVariantMap activityMap; return;
activityMap["year"] = p.year;
activityMap["zhr"] = p.zhr;
activityMap["variable"] = p.variable;
activityMap["start"] = p.start;
activityMap["finish"] = p.finish;
activityMap["peak"] = p.peak;
activityList << activityMap;
} }
map["activity"] = activityList;
QVariantList colorList; // gets the current UTC date
foreach(const colorPair &c, colors) double currentJD = core->getJD();
QDate currentDate = QDate::fromJulianDay(currentJD);
// updating status and activity
bool found = false;
m_status = INACTIVE;
m_activity = hasConfirmedShower(currentDate, found);
if (found)
{
m_status = ACTIVE_CONFIRMED;
}
else
{ {
QVariantMap colorMap; m_activity = hasGenericShower(currentDate, found);
colorMap["color"] = c.first; if (found)
colorMap["intensity"] = c.second; {
colorList << colorMap; m_status = ACTIVE_GENERIC;
}
} }
map["colors"] = colorList;
return map; // will be displayed?
} if (!enabled())
{
return;
}
float MeteorShower::getSelectPriority(const StelCore*) const // fix the radiant position (considering drift)
{ m_radiantAlpha = m_rAlphaPeak;
return -4.0; m_radiantDelta = m_rDeltaPeak;
} if (m_status != INACTIVE)
{
double daysToPeak = currentJD - m_activity.peak.toJulianDay(
);
m_radiantAlpha += m_driftAlpha * daysToPeak;
m_radiantDelta += m_driftDelta * daysToPeak;
}
QString MeteorShower::getDesignation() const // step through and update all active meteors
{ foreach (MeteorObj* m, m_activeMeteors)
if (showerID.toInt()) // if showerID is a number
{ {
return ""; if (!m->update(deltaTime))
{
m_activeMeteors.removeOne(m);
}
} }
return showerID;
}
QString MeteorShower::getDateFromJSON(QString jsondate) const // going forward or backward ?
{ // don't create new meteors
QStringList parsedDate = jsondate.split("."); if(!core->getRealTimeSpeed())
{
return;
}
return QString("%1 %2").arg(parsedDate.at(1).toInt()).arg(getMonthNa // calculates a ZHR for the current date
me(parsedDate.at(0).toInt())); int currentZHR = calculateZHR(currentJD);
} if (currentZHR < 1)
{
return;
}
QString MeteorShower::getDayFromJSON(QString jsondate) const // average meteors per frame
{ float mpf = currentZHR * deltaTime / 3600.f;
QStringList parsedDate = jsondate.split(".");
return QString("%1").arg(parsedDate.at(1).toInt()); // maximum amount of meteors for the current frame
int maxMpf = qRound(mpf);
maxMpf = maxMpf < 1 ? 1 : maxMpf;
float rate = mpf / (float) maxMpf;
for (int i = 0; i < maxMpf; ++i)
{
float prob = (float) qrand() / (float) RAND_MAX;
if (prob < rate)
{
MeteorObj *m = new MeteorObj(core, m_speed, m_radian
tAlpha, m_radiantDelta,
m_pidx, m_colors, m_mgr
->getBolideTexture());
if (m->isAlive())
{
m_activeMeteors.append(m);
}
}
}
} }
int MeteorShower::getMonthFromJSON(QString jsondate) const void MeteorShower::draw(StelCore* core)
{ {
QStringList parsedDate = jsondate.split("."); if (!enabled())
{
return parsedDate.at(0).toInt(); return;
}
drawRadiant(core);
drawMeteors(core);
} }
QString MeteorShower::getMonthNameFromJSON(QString jsondate) const void MeteorShower::drawRadiant(StelCore *core)
{ {
QStringList parsedDate = jsondate.split("."); StelPainter painter(core->getProjection(StelCore::FrameJ2000));
return QString("%1").arg(getMonthName(parsedDate.at(0).toInt())); Vec3d XY;
} StelUtils::spheToRect(m_radiantAlpha, m_radiantDelta, m_position);
painter.getProjector()->project(m_position, XY);
QString MeteorShower::getMonthName(int number) const glEnable(GL_TEXTURE_2D);
{ glEnable(GL_BLEND);
QStringList monthList; glBlendFunc(GL_SRC_ALPHA, GL_ONE);
monthList.append(N_("January"));
monthList.append(N_("February"));
monthList.append(N_("March"));
monthList.append(N_("April"));
monthList.append(N_("May"));
monthList.append(N_("June"));
monthList.append(N_("July"));
monthList.append(N_("August"));
monthList.append(N_("September"));
monthList.append(N_("October"));
monthList.append(N_("November"));
monthList.append(N_("December"));
return q_(monthList.at(number-1)); Vec3f rgb;
} float alpha = 0.85f + ((float) qrand() / (float) RAND_MAX) / 10.f;
switch(m_status)
{
case ACTIVE_CONFIRMED: //Active, confirmed data
rgb = m_mgr->getColorARC();
break;
case ACTIVE_GENERIC: //Active, generic data
rgb = m_mgr->getColorARG();
break;
default: //Inactive
rgb = m_mgr->getColorIR();
}
rgb /= 255.f;
painter.setColor(rgb[0], rgb[1], rgb[2], alpha);
QDateTime MeteorShower::getSkyQDateTime() const Vec3d win;
{ if (m_mgr->getEnableMarker() && painter.getProjector()->projectCheck
StelCore* core = StelApp::getInstance().getCore(); (m_position, win))
//get the current sky date {
double JD = core->getJDay(); m_mgr->getRadiantTexture()->bind();
return StelUtils::jdToQDateTime(JD+StelUtils::getGMTShiftFromQT(JD)/ painter.drawSprite2dMode(XY[0], XY[1], 45);
24-core->getDeltaT(JD)/86400);
if (m_mgr->getEnableLabels())
{
painter.setFont(m_mgr->getFont());
float size = getAngularSize(NULL)*M_PI/180.*painter.
getProjector()->getPixelPerRadAtCenter();
float shift = 8.f + size/1.8f;
painter.drawText(XY[0]+shift, XY[1]+shift, getNameI1
8n(), 0, 0, 0, false);
}
}
} }
void MeteorShower::updateCurrentData(QDateTime skyDate) void MeteorShower::drawMeteors(StelCore *core)
{ {
//Check if we have real data for the current sky year if (!core->getSkyDrawer()->getFlagHasAtmosphere())
int index = searchRealData(skyDate.toString("yyyy")); {
return;
}
/************************** LandscapeMgr* landmgr = GETSTELMODULE(LandscapeMgr);
*ZHR info if (landmgr->getFlagAtmosphere() && landmgr->getLuminance() > 5.f)
**************************/ {
zhr = activity[index].zhr == 0 ? activity[0].zhr : activity[index].z return;
hr; }
if (zhr == -1) // step through and draw all active meteors
variable = activity[index].variable.isEmpty() ? activity[0]. StelPainter painter(core->getProjection(StelCore::FrameAltAz));
variable : activity[index].variable; foreach (MeteorObj* m, m_activeMeteors)
else {
variable = ""; m->draw(core, painter);
}
}
/*************************** MeteorShower::Activity MeteorShower::hasGenericShower(QDate date, bool &fou
*Dates - start/finish/peak nd) const
***************************/ {
QString dateStart = activity[index].start.isEmpty() ? activity[0].st int year = date.year();
art : activity[index].start; Activity g = m_activities.at(0);
QString dateFinish = activity[index].finish.isEmpty() ? activity[0]. bool peakOnStart = g.peak.year() == g.start.year(); // 'peak' and 's
finish : activity[index].finish; tart' on the same year ?
QString datePeak = activity[index].peak.isEmpty() ? activity[0].peak
: activity[index].peak;
QString yearBase = activity[index].year == "generic" ? skyDate.toStr
ing("yyyy") : activity[index].year;
QString yearS, yearF;
int monthStart = getMonthFromJSON(dateStart);
int monthFinish = getMonthFromJSON(dateFinish);
if(monthStart > monthFinish) //Fix the 'generic years'!
// Handling cases when the shower starts on the current year and
// ends on the next year; or when it started on the last year...
if (g.start.year() != g.finish.year()) // edge case?
{ {
if(monthStart == skyDate.toString("MM").toInt()) // trying the current year with the next year
{ g.start.setDate(year, g.start.month(), g.start.day());
yearS = yearBase; g.finish.setDate(year + 1, g.finish.month(), g.finish.day())
yearF = QString("%1").arg(yearBase.toInt() + 1); ;
} found = date.operator >=(g.start) && date.operator <=(g.fini
else sh);
if (!found)
{ {
yearS = QString("%1").arg(yearBase.toInt() - 1); // trying the last year with the current year
yearF = yearBase; g.start.setDate(year - 1, g.start.month(), g.start.d
ay());
g.finish.setDate(year, g.finish.month(), g.finish.da
y());
found = date.operator >=(g.start) && date.operator <
=(g.finish);
} }
} }
else else
{ {
yearS = yearF = yearBase; g.start.setDate(year, g.start.month(), g.start.day());
g.finish.setDate(year, g.finish.month(), g.finish.day());
found = date.operator >=(g.start) && date.operator <=(g.fini
sh);
} }
start = QDateTime::fromString(dateStart + " " + yearS, "MM.dd yyyy") if (found)
;
finish = QDateTime::fromString(dateFinish + " " + yearF, "MM.dd yyyy
");
peak = QDateTime::fromString(datePeak + " " + yearS, "MM.dd yyyy");
if (peak.operator <(start) || peak.operator >(finish))
peak = QDateTime::fromString(datePeak + " " + yearF, "MM.dd
yyyy");
/***************************
*Activity - is active?
***************************/
if(skyDate.operator >=(start) && skyDate.operator <=(finish))
{ {
if(index) g.year = g.start.year();
status = ACTIVE_REAL; // real data g.peak.setDate(peakOnStart ? g.start.year() : g.finish.year(
else ),
status = ACTIVE_GENERIC; // generic data g.peak.month(),
g.peak.day());
return g;
} }
else
{
status = INACTIVE; // isn't active
}
active = (status != INACTIVE) || !showActiveRadiantsOnly;
/************************** return Activity();
*Radiant drift }
*************************/
radiantAlpha = rAlphaPeak;
radiantDelta = rDeltaPeak;
if (status != INACTIVE) MeteorShower::Activity MeteorShower::hasConfirmedShower(QDate date, bool& f
ound) const
{
const int activitiesSize = m_activities.size();
for (int i = 1; i < activitiesSize; ++i)
{ {
double time = (StelUtils::qDateTimeToJd(skyDate) - StelUtils const Activity& a = m_activities.at(i);
::qDateTimeToJd(peak))*24; if (date.operator >=(a.start) && date.operator <=(a.finish))
radiantAlpha += (driftAlpha/120)*time; {
radiantDelta += (driftDelta/120)*time; found = true;
return a;
}
} }
return Activity();
} }
int MeteorShower::searchRealData(QString yyyy) const int MeteorShower::calculateZHR(const double& currentJD)
{ {
int index = -1; double startJD = m_activity.start.toJulianDay();
foreach(const activityData &p, activity) double finishJD = m_activity.finish.toJulianDay();
double peakJD = m_activity.peak.toJulianDay();
float sd; //standard deviation
if (currentJD >= startJD && currentJD < peakJD) //left side of gauss
ian
{
sd = (peakJD - startJD) / 2.f;
}
else
{ {
index++; sd = (finishJD - peakJD) / 2.f;
if(p.year == yyyy)
return index;
} }
return 0; float maxZHR = m_activity.zhr == -1 ? m_activity.variable.at(1) : m_
activity.zhr;
float minZHR = m_activity.zhr == -1 ? m_activity.variable.at(0) : 0;
float gaussian = maxZHR * qExp( - qPow(currentJD - peakJD, 2) / (2 *
sd * sd) ) + minZHR;
return qRound(gaussian);
} }
float MeteorShower::getSolarLongitude(QDateTime QDT) const QString MeteorShower::getSolarLongitude(QDate date) const
{ {
//The number of days (positive or negative) since Greenwich noon, //The number of days (positive or negative) since Greenwich noon,
//Terrestrial Time, on 1 January 2000 (J2000.0) //Terrestrial Time, on 1 January 2000 (J2000.0)
double n = StelUtils::qDateTimeToJd(QDT) - 2451545.0; double n = date.toJulianDay() - 2451545.0;
//The mean longitude of the Sun, corrected for the aberration of lig ht //The mean longitude of the Sun, corrected for the aberration of lig ht
float slong = (280.460 + 0.9856474*n) / 360; float l = 280.460 + 0.9856474 * n;
slong = (slong - (int) slong) * 360 - 1;
// put it in the range 0 to 360 degrees
l /= 360.f;
l = (l - (int) l) * 360.f - 1.f;
return slong; return QString::number(l, 'f', 2);
}
QString MeteorShower::getDesignation() const
{
if (m_showerID.toInt()) // if showerID is a number
{
return "";
}
return m_showerID;
}
Vec3f MeteorShower::getInfoColor(void) const
{
return StelApp::getInstance().getVisionModeNight() ? Vec3f(0.6, 0.0,
0.0) : Vec3f(1.0, 1.0, 1.0);
} }
QString MeteorShower::getInfoString(const StelCore* core, const InfoStringG roup& flags) const QString MeteorShower::getInfoString(const StelCore* core, const InfoStringG roup& flags) const
{ {
if (!enabled())
{
GETSTELMODULE(StelObjectMgr)->unSelect();
return "";
}
QString str; QString str;
QTextStream oss(&str); QTextStream oss(&str);
QString mstdata = q_("generic data"); QString mstdata;
if(status == ACTIVE_REAL) if (m_status == ACTIVE_GENERIC)
mstdata = q_("real data"); {
mstdata = q_("generic data");
}
else if (m_status == ACTIVE_CONFIRMED)
{
mstdata = q_("confirmed data");
}
else if (m_status == INACTIVE)
{
mstdata = q_("inactive");
}
if(flags&Name) if(flags&Name)
{ {
oss << "<h2>" << getNameI18n(); oss << "<h2>" << getNameI18n();
if (!showerID.toInt()) if (!m_showerID.toInt())
{ {
oss << " (" << showerID <<")</h2>"; oss << " (" << m_showerID <<")</h2>";
} }
else else
{ {
oss << "</h2>"; oss << "</h2>";
} }
} }
if(flags&Extra) if(flags&Extra)
{ {
oss << q_("Type: <b>%1</b> (%2)").arg(q_("meteor shower"), m stdata) << "<br />"; oss << q_("Type: <b>%1</b> (%2)").arg(q_("meteor shower"), m stdata) << "<br />";
} }
// Ra/Dec etc. // Ra/Dec etc.
oss << getPositionInfoString(core, flags); oss << getPositionInfoString(core, flags);
if(flags&Extra) if(flags&Extra)
{ {
oss << QString("%1: %2/%3") oss << QString("%1: %2/%3")
.arg(q_("Radiant drift (per day)")) .arg(q_("Radiant drift (per day)"))
.arg(StelUtils::radToHmsStr(driftAlpha/5)) .arg(StelUtils::radToHmsStr(m_driftAlpha))
.arg(StelUtils::radToDmsStr(driftDelta/5)); .arg(StelUtils::radToDmsStr(m_driftDelta));
oss << "<br />"; oss << "<br />";
if (speed>0) if (m_speed > 0)
{ {
oss << q_("Geocentric meteoric velocity: %1 km/s").a rg(speed) << "<br />"; oss << q_("Geocentric meteoric velocity: %1 km/s").a rg(m_speed) << "<br />";
} }
if(pidx>0) if(m_pidx > 0)
{ {
oss << q_("The population index: %1").arg(pidx) << " <br />"; oss << q_("The population index: %1").arg(m_pidx) << "<br />";
} }
if(!parentObj.isEmpty()) if(!m_parentObj.isEmpty())
{ {
oss << q_("Parent body: %1").arg(q_(parentObj)) << " <br />"; oss << q_("Parent body: %1").arg(q_(m_parentObj)) << "<br />";
} }
if(start.toString("M") == finish.toString("M")) // activity info
{ if (m_status != INACTIVE)
oss << QString("%1: %2 - %3 %4")
.arg(q_("Active"))
.arg(start.toString("d"))
.arg(finish.toString("d"))
.arg(start.toString("MMMM"));
}
else
{ {
oss << QString("%1: %2 - %3") if(m_activity.start.month() == m_activity.finish.mon
.arg(q_("Activity")) th())
.arg(start.toString("d MMMM")) {
.arg(finish.toString("d MMMM")); oss << QString("%1: %2 - %3 %4")
} .arg(q_("Active"))
oss << "<br />"; .arg(m_activity.start.day())
oss << q_("Maximum: %1").arg(peak.toString("d MMMM")); .arg(m_activity.finish.day())
.arg(m_activity.start.toString("MMMM"
));
}
else
{
oss << QString("%1: %2 - %3")
.arg(q_("Activity"))
.arg(m_activity.start.toString("d MMM
M"))
.arg(m_activity.finish.toString("d MM
MM"));
}
oss << "<br />";
oss << q_("Maximum: %1").arg(m_activity.peak.toStrin
g("d MMMM"));
QString slong = QString::number( MeteorShower::getSolarLongi oss << QString(" (%1 %2&deg;)").arg(q_("Solar longit
tude(peak), 'f', 2 ); ude"))
oss << QString(" (%1 %2&deg;)").arg(q_("Solar longitude is") .arg(getSolarLongitude(m_activity.peak));
).arg(slong); oss << "<br />";
oss << "<br />";
if(zhr>0) if(m_activity.zhr > 0)
{
oss << QString("ZHR<sub>max</sub>: %1").arg(zhr) <<
"<br />";
}
else
{
oss << QString("ZHR<sub>max</sub>: %1").arg(q_("vari
able"));
if(!variable.isEmpty())
{ {
oss << "; " << variable; oss << QString("ZHR<sub>max</sub>: %1").arg(
m_activity.zhr) << "<br />";
}
else
{
oss << QString("ZHR<sub>max</sub>: %1").arg(
q_("variable"));
if(m_activity.variable.size() == 2)
{
oss << QString("; %1-%2").arg(m_acti
vity.variable.at(0))
.arg(m_activity.variable.at(1
));
}
oss << "<br />";
} }
oss << "<br />";
} }
} }
postProcessInfoString(str, flags); postProcessInfoString(str, flags);
return str; return str;
} }
Vec3f MeteorShower::getInfoColor(void) const
{
return StelApp::getInstance().getVisionModeNight() ? Vec3f(0.6, 0.0,
0.0) : Vec3f(1.0, 1.0, 1.0);
}
double MeteorShower::getAngularSize(const StelCore*) const
{
return 0.001;
}
void MeteorShower::update(double deltaTime)
{
labelsFader.update((int)(deltaTime*1000));
updateCurrentData(getSkyQDateTime());
}
void MeteorShower::draw(StelPainter &painter)
{
StelUtils::spheToRect(radiantAlpha, radiantDelta, XYZ);
painter.getProjector()->project(XYZ, XY);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
qreal r, g, b;
float alpha = 0.85f + ((double) qrand() / (RAND_MAX))/10;
switch(status)
{
case ACTIVE_REAL: //Active, real data
GETSTELMODULE(MeteorShowers)->getColorARR().getRgbF(
&r,&g,&b);
break;
case ACTIVE_GENERIC: //Active, generic data
GETSTELMODULE(MeteorShowers)->getColorARG().getRgbF(
&r,&g,&b);
break;
default: //Inactive
GETSTELMODULE(MeteorShowers)->getColorIR().getRgbF(&
r,&g,&b);
}
painter.setColor(r, g, b, alpha);
Vec3d win;
if (MeteorShower::radiantMarkerEnabled && painter.getProjector()->pr
ojectCheck(XYZ, win))
{
MeteorShower::radiantTexture->bind();
painter.drawSprite2dMode(XY[0], XY[1], 45);
if (MeteorShower::showLabels)
{
float size = getAngularSize(NULL)*M_PI/180.*painter.
getProjector()->getPixelPerRadAtCenter();
float shift = 8.f + size/1.8f;
painter.drawText(XY[0]+shift, XY[1]+shift, getNameI1
8n(), 0, 0, 0, false);
}
}
}
 End of changes. 82 change blocks. 
271 lines changed or deleted 501 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/