/* * Stellarium * Copyright (C) 2002 Fabien Chereau * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "SolarSystem.hpp" #include "StelTexture.hpp" #include "stellplanet.h" #include "Orbit.hpp" #include "StelNavigator.hpp" #include "StelProjector.hpp" #include "StelApp.hpp" #include "StelCore.hpp" #include "StelTextureMgr.hpp" #include "StelObjectMgr.hpp" #include "StelLocaleMgr.hpp" #include "StelSkyCultureMgr.hpp" #include "StelFileMgr.hpp" #include "StelModuleMgr.hpp" #include "StelIniParser.hpp" #include "Planet.hpp" #include "StelNavigator.hpp" #include "StelSkyDrawer.hpp" #include "StelUtils.hpp" #include "StelPainter.hpp" #include "TrailGroup.hpp" #include #include #include #include #include #include #include #include #include #include #include SolarSystem::SolarSystem() : moonScale(1.), flagOrbits(false), flagLightTravelTime(false), allTrails(NULL) { planetNameFont.setPixelSize(13); setObjectName("SolarSystem"); } void SolarSystem::setFontSize(float newFontSize) { planetNameFont.setPixelSize(newFontSize); } SolarSystem::~SolarSystem() { // release selected: selected.clear(); foreach (Orbit* orb, orbits) { delete orb; orb = NULL; } sun.clear(); moon.clear(); earth.clear(); Planet::hintCircleTex.clear(); Planet::texEarthShadow.clear(); delete allTrails; allTrails = NULL; // Get rid of circular reference between the shared pointers which prevent proper destruction of the Planet objects. foreach (PlanetP p, systemPlanets) { p->satellites.clear(); } } /************************************************************************* Reimplementation of the getCallOrder method *************************************************************************/ double SolarSystem::getCallOrder(StelModuleActionName actionName) const { if (actionName==StelModule::ActionDraw) return StelApp::getInstance().getModuleMgr().getModule("StarMgr")->getCallOrder(actionName)+10; return 0; } // Init and load the solar system data void SolarSystem::init() { QSettings* conf = StelApp::getInstance().getSettings(); Q_ASSERT(conf); loadPlanets(); // Load planets data // Compute position and matrix of sun and all the satellites (ie planets) // for the first initialization Q_ASSERT that center is sun center (only impacts on light speed correction) computePositions(StelUtils::getJDFromSystem()); setSelected(""); // Fix a bug on macosX! Thanks Fumio! setFlagMoonScale(conf->value("viewing/flag_moon_scaled", conf->value("viewing/flag_init_moon_scaled", "false").toBool()).toBool()); // name change setMoonScale(conf->value("viewing/moon_scale", 5.0).toFloat()); setFlagPlanets(conf->value("astro/flag_planets").toBool()); setFlagHints(conf->value("astro/flag_planets_hints").toBool()); setFlagLabels(conf->value("astro/flag_planets_labels", true).toBool()); setLabelsAmount(conf->value("astro/labels_amount", 3.).toFloat()); setFlagOrbits(conf->value("astro/flag_planets_orbits").toBool()); setFlagLightTravelTime(conf->value("astro/flag_light_travel_time", false).toBool()); recreateTrails(); setFlagTrails(conf->value("astro/flag_object_trails", false).toBool()); GETSTELMODULE(StelObjectMgr)->registerStelObjectMgr(this); texPointer = StelApp::getInstance().getTextureManager().createTexture("textures/pointeur4.png"); Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture("textures/planet-indicator.png"); } void SolarSystem::recreateTrails() { // Create a trail group containing all the planets orbiting the sun (not including satellites) if (allTrails!=NULL) delete allTrails; allTrails = new TrailGroup(365.f); foreach (const PlanetP& p, getSun()->satellites) { allTrails->addObject((QSharedPointer)p, &trailColor); } } void SolarSystem::drawPointer(const StelCore* core) { const StelNavigator* nav = core->getNavigator(); const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000); const QList newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet"); if (!newSelected.empty()) { const StelObjectP obj = newSelected[0]; Vec3d pos=obj->getJ2000EquatorialPos(nav); Vec3d screenpos; // Compute 2D pos and return if outside screen if (!prj->project(pos, screenpos)) return; StelPainter sPainter(prj); sPainter.setColor(1.0f,0.3f,0.3f); float size = obj->getAngularSize(core)*M_PI/180.*prj->getPixelPerRadAtCenter()*2.; size+=40.f + 10.f*std::sin(2.f * StelApp::getInstance().getTotalRunTime()); texPointer->bind(); sPainter.enableTexture2d(true); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Normal transparency mode size*=0.5; const float angleBase = StelApp::getInstance().getTotalRunTime() * 10; // We draw 4 instances of the sprite at the corners of the pointer for (int i = 0; i < 4; ++i) { const float angle = angleBase + i * 90; const double x = screenpos[0] + size * cos(angle / 180 * M_PI); const double y = screenpos[1] + size * sin(angle / 180 * M_PI); sPainter.drawSprite2dMode(x, y, 10, angle); } } } void ellipticalOrbitPosFunc(double jd,double xyz[3], void* userDataPtr) { static_cast(userDataPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz); } void cometOrbitPosFunc(double jd,double xyz[3], void* userDataPtr) { static_cast(userDataPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz); } // Init and load the solar system data void SolarSystem::loadPlanets() { qDebug() << "Loading Solar System data ..."; QString iniFile; try { iniFile = StelFileMgr::findFile("data/ssystem.ini"); } catch(std::runtime_error& e) { qWarning() << "ERROR while loading ssysyem.ini (unable to find data/ssystem.ini): " << e.what() << endl; return; } QSettings pd(iniFile, StelIniFormat); if (pd.status() != QSettings::NoError) { qWarning() << "ERROR while parsing ssysyem.ini file"; return; } // QSettings does not allow us to say that the sections of the file // will be listed in the same order as in the file like the old // InitParser used to so we can no longer assume that. // // This means we must first decide what order to read the sections // of the file in (each section contains one planet) to avoid setting // the parent Planet* to one which has not yet been created. // // Stage 1: Make a map of body names back to the section names // which they come from. Also make a map of body name to parent body // name. These two maps can be made in a single pass through the // sections of the file. // // Stage 2: Make an ordered list of section names such that each // item is only ever dependent on items which appear earlier in the // list. // 2a: Make a QMultiMap relating the number of levels of dependency // to the body name, i.e. // 0 -> Sun // 1 -> Mercury // 1 -> Venus // 1 -> Earth // 2 -> Moon // etc. // 2b: Populate an ordered list of section names by iterating over // the QMultiMap. This type of contains is always sorted on the // key, so it's easy. // i.e. [sol, earth, moon] is fine, but not [sol, moon, earth] // // Stage 3: iterate over the ordered sections decided in stage 2, // creating the planet objects from the QSettings data. // Stage 1 (as described above). QMap secNameMap; QMap parentMap; QStringList sections = pd.childGroups(); for (int i=0; i depLevelMap; for (int i=0; i levelMapIt(depLevelMap); while(levelMapIt.hasNext()) { levelMapIt.next(); orderedSections << levelMapIt.value(); } // Stage 3 (as described above). int readOk=0; int totalPlanets=0; for (int i = 0;igetEnglishName()==strParent) { parent = p; break; } } if (parent.isNull()) { qWarning() << "ERROR : can't find parent solar system body for " << englishName; abort(); continue; } } const QString funcName = pd.value(secname+"/coord_func").toString(); posFuncType posfunc=NULL; void* userDataPtr=NULL; OsulatingFunctType *osculatingFunc = 0; bool closeOrbit = pd.value(secname+"/closeOrbit", true).toBool(); if (funcName=="ell_orbit") { // Read the orbital elements const double epoch = pd.value(secname+"/orbit_Epoch",J2000).toDouble(); const double eccentricity = pd.value(secname+"/orbit_Eccentricity").toDouble(); if (eccentricity >= 1.0) closeOrbit = false; double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); double semi_major_axis; if (pericenterDistance <= 0.0) { semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble(); if (semi_major_axis <= -1e100) { qDebug() << "ERROR: " << englishName << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis"; abort(); } else { semi_major_axis /= AU; Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis pericenterDistance = semi_major_axis * (1.0-eccentricity); } } else { pericenterDistance /= AU; semi_major_axis = (eccentricity == 1.0) ? 0.0 // parabolic orbits have no semi_major_axis : pericenterDistance / (1.0-eccentricity); } double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); double period; if (meanMotion <= -1e100) { period = pd.value(secname+"/orbit_Period",-1e100).toDouble(); if (period <= -1e100) { meanMotion = (eccentricity == 1.0) ? 0.01720209895 * (1.5/pericenterDistance) * sqrt(0.5/pericenterDistance) : (semi_major_axis > 0.0) ? 0.01720209895 / (semi_major_axis*sqrt(semi_major_axis)) : 0.01720209895 / (-semi_major_axis*sqrt(-semi_major_axis)); period = 2.0*M_PI/meanMotion; } else { meanMotion = 2.0*M_PI/period; } } else { period = 2.0*M_PI/meanMotion; } const double inclination = pd.value(secname+"/orbit_Inclination").toDouble()*(M_PI/180.0); const double ascending_node = pd.value(secname+"/orbit_AscendingNode").toDouble()*(M_PI/180.0); double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter",-1e100).toDouble(); double long_of_pericenter; if (arg_of_pericenter <= -1e100) { long_of_pericenter = pd.value(secname+"/orbit_LongOfPericenter").toDouble()*(M_PI/180.0); arg_of_pericenter = long_of_pericenter - ascending_node; } else { arg_of_pericenter *= (M_PI/180.0); long_of_pericenter = arg_of_pericenter + ascending_node; } double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble(); double mean_longitude; if (mean_anomaly <= -1e100) { mean_longitude = pd.value(secname+"/orbit_MeanLongitude").toDouble()*(M_PI/180.0); mean_anomaly = mean_longitude - long_of_pericenter; } else { mean_anomaly *= (M_PI/180.0); mean_longitude = mean_anomaly + long_of_pericenter; } // when the parent is the sun use ecliptic rathe than sun equator: const double parentRotObliquity = parent->getParent() ? parent->getRotObliquity() : 0.0; const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingnode() : 0.0; double parent_rot_j2000_longitude = 0.0; if (parent->getParent()) { const double c_obl = cos(parentRotObliquity); const double s_obl = sin(parentRotObliquity); const double c_nod = cos(parent_rot_asc_node); const double s_nod = sin(parent_rot_asc_node); const Vec3d OrbitAxis0( c_nod, s_nod, 0.0); const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl); const Vec3d OrbitPole( s_nod*s_obl,-c_nod*s_obl,c_obl); const Vec3d J2000Pole(StelNavigator::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1))); Vec3d J2000NodeOrigin(J2000Pole^OrbitPole); J2000NodeOrigin.normalize(); parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0); } // Create an elliptical orbit EllipticalOrbit *orb = new EllipticalOrbit(pericenterDistance, eccentricity, inclination, ascending_node, arg_of_pericenter, mean_anomaly, period, epoch, parentRotObliquity, parent_rot_asc_node, parent_rot_j2000_longitude); orbits.push_back(orb); userDataPtr = orb; posfunc = &ellipticalOrbitPosFunc; } else if (funcName=="comet_orbit") { // Read the orbital elements // orbit_PericenterDistance,orbit_SemiMajorAxis: given in AU // orbit_MeanMotion: given in degrees/day // orbit_Period: given in days // orbit_TimeAtPericenter,orbit_Epoch: JD // orbit_MeanAnomaly,orbit_Inclination,orbit_ArgOfPericenter,orbit_AscendingNode: given in degrees const double eccentricity = pd.value(secname+"/orbit_Eccentricity",0.0).toDouble(); if (eccentricity >= 1.0) closeOrbit = false; double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); double semi_major_axis; if (pericenterDistance <= 0.0) { semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble(); if (semi_major_axis <= -1e100) { qWarning() << "ERROR: " << englishName << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis"; abort(); } else { Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis pericenterDistance = semi_major_axis * (1.0-eccentricity); } } else { semi_major_axis = (eccentricity == 1.0) ? 0.0 // parabolic orbits have no semi_major_axis : pericenterDistance / (1.0-eccentricity); } double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); if (meanMotion <= -1e100) { const double period = pd.value(secname+"/orbit_Period",-1e100).toDouble(); if (period <= -1e100) { if (parent->getParent()) { qWarning() << "ERROR: " << englishName << ": when the parent body is not the sun, you must provide " << "either orbit_MeanMotion or orbit_Period"; } else { // in case of parent=sun: use Gaussian gravitational constant // for calculating meanMotion: meanMotion = (eccentricity == 1.0) ? 0.01720209895 * (1.5/pericenterDistance) * sqrt(0.5/pericenterDistance) : (semi_major_axis > 0.0) ? 0.01720209895 / (semi_major_axis*sqrt(semi_major_axis)) : 0.01720209895 / (-semi_major_axis*sqrt(-semi_major_axis)); } } else { meanMotion = 2.0*M_PI/period; } } else { meanMotion *= (M_PI/180.0); } double time_at_pericenter = pd.value(secname+"/orbit_TimeAtPericenter",-1e100).toDouble(); if (time_at_pericenter <= -1e100) { const double epoch = pd.value(secname+"/orbit_Epoch",-1e100).toDouble(); double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble(); if (epoch <= -1e100 || mean_anomaly <= -1e100) { qWarning() << "ERROR: " << englishName << ": when you do not provide orbit_TimeAtPericenter, you must provide both " << "orbit_Epoch and orbit_MeanAnomaly"; abort(); } else { mean_anomaly *= (M_PI/180.0); time_at_pericenter = epoch - mean_anomaly / meanMotion; } } const double inclination = pd.value(secname+"/orbit_Inclination").toDouble()*(M_PI/180.0); const double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter").toDouble()*(M_PI/180.0); const double ascending_node = pd.value(secname+"/orbit_AscendingNode").toDouble()*(M_PI/180.0); const double parentRotObliquity = parent->getParent() ? parent->getRotObliquity() : 0.0; const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingnode() : 0.0; double parent_rot_j2000_longitude = 0.0; if (parent->getParent()) { const double c_obl = cos(parentRotObliquity); const double s_obl = sin(parentRotObliquity); const double c_nod = cos(parent_rot_asc_node); const double s_nod = sin(parent_rot_asc_node); const Vec3d OrbitAxis0( c_nod, s_nod, 0.0); const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl); const Vec3d OrbitPole( s_nod*s_obl,-c_nod*s_obl,c_obl); const Vec3d J2000Pole(StelNavigator::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1))); Vec3d J2000NodeOrigin(J2000Pole^OrbitPole); J2000NodeOrigin.normalize(); parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0); } CometOrbit *orb = new CometOrbit(pericenterDistance, eccentricity, inclination, ascending_node, arg_of_pericenter, time_at_pericenter, meanMotion, parentRotObliquity, parent_rot_asc_node, parent_rot_j2000_longitude); orbits.push_back(orb); userDataPtr = orb; posfunc = &cometOrbitPosFunc; } if (funcName=="sun_special") posfunc = &get_sun_helio_coordsv; if (funcName=="mercury_special") { posfunc = &get_mercury_helio_coordsv; osculatingFunc = &get_mercury_helio_osculating_coords; } if (funcName=="venus_special") { posfunc = &get_venus_helio_coordsv; osculatingFunc = &get_venus_helio_osculating_coords; } if (funcName=="earth_special") { posfunc = &get_earth_helio_coordsv; osculatingFunc = &get_earth_helio_osculating_coords; } if (funcName=="lunar_special") posfunc = &get_lunar_parent_coordsv; if (funcName=="mars_special") { posfunc = &get_mars_helio_coordsv; osculatingFunc = &get_mars_helio_osculating_coords; } if (funcName=="phobos_special") posfunc = posFuncType(get_phobos_parent_coordsv); if (funcName=="deimos_special") posfunc = &get_deimos_parent_coordsv; if (funcName=="jupiter_special") { posfunc = &get_jupiter_helio_coordsv; osculatingFunc = &get_jupiter_helio_osculating_coords; } if (funcName=="europa_special") posfunc = &get_europa_parent_coordsv; if (funcName=="calisto_special") posfunc = &get_callisto_parent_coordsv; if (funcName=="io_special") posfunc = &get_io_parent_coordsv; if (funcName=="ganymede_special") posfunc = &get_ganymede_parent_coordsv; if (funcName=="saturn_special") { posfunc = &get_saturn_helio_coordsv; osculatingFunc = &get_saturn_helio_osculating_coords; } if (funcName=="mimas_special") posfunc = &get_mimas_parent_coordsv; if (funcName=="enceladus_special") posfunc = &get_enceladus_parent_coordsv; if (funcName=="tethys_special") posfunc = &get_tethys_parent_coordsv; if (funcName=="dione_special") posfunc = &get_dione_parent_coordsv; if (funcName=="rhea_special") posfunc = &get_rhea_parent_coordsv; if (funcName=="titan_special") posfunc = &get_titan_parent_coordsv; if (funcName=="iapetus_special") posfunc = &get_iapetus_parent_coordsv; if (funcName=="hyperion_special") posfunc = &get_hyperion_parent_coordsv; if (funcName=="uranus_special") { posfunc = &get_uranus_helio_coordsv; osculatingFunc = &get_uranus_helio_osculating_coords; } if (funcName=="miranda_special") posfunc = &get_miranda_parent_coordsv; if (funcName=="ariel_special") posfunc = &get_ariel_parent_coordsv; if (funcName=="umbriel_special") posfunc = &get_umbriel_parent_coordsv; if (funcName=="titania_special") posfunc = &get_titania_parent_coordsv; if (funcName=="oberon_special") posfunc = &get_oberon_parent_coordsv; if (funcName=="neptune_special") { posfunc = posFuncType(get_neptune_helio_coordsv); osculatingFunc = &get_neptune_helio_osculating_coords; } if (funcName=="pluto_special") posfunc = &get_pluto_helio_coordsv; if (posfunc==NULL) { qWarning() << "ERROR : can't find posfunc " << funcName << " for " << englishName; exit(-1); } // Create the Planet and add it to the list PlanetP p(new Planet(englishName, pd.value(secname+"/lighting").toBool(), pd.value(secname+"/radius").toDouble()/AU, pd.value(secname+"/oblateness", 0.0).toDouble(), StelUtils::strToVec3f(pd.value(secname+"/color").toString()), pd.value(secname+"/albedo").toFloat(), pd.value(secname+"/tex_map").toString(), posfunc, userDataPtr, osculatingFunc, closeOrbit, pd.value(secname+"/hidden", 0).toBool(), pd.value(secname+"/atmosphere", false).toBool())); if (!parent.isNull()) { parent->satellites.append(p); p->parent = parent; } if (secname=="earth") earth = p; if (secname=="sun") sun = p; if (secname=="moon") moon = p; double rotObliquity = pd.value(secname+"/rot_obliquity",0.).toDouble()*(M_PI/180.0); double rotAscNode = pd.value(secname+"/rot_equator_ascending_node",0.).toDouble()*(M_PI/180.0); // Use more common planet North pole data if available // NB: N pole as defined by IAU (NOT right hand rotation rule) // NB: J2000 epoch double J2000NPoleRA = pd.value(secname+"/rot_pole_ra", 0.).toDouble()*M_PI/180.; double J2000NPoleDE = pd.value(secname+"/rot_pole_de", 0.).toDouble()*M_PI/180.; if(J2000NPoleRA || J2000NPoleDE) { Vec3d J2000NPole; StelUtils::spheToRect(J2000NPoleRA,J2000NPoleDE,J2000NPole); Vec3d vsop87Pole(StelNavigator::matJ2000ToVsop87.multiplyWithoutTranslation(J2000NPole)); double ra, de; StelUtils::rectToSphe(&ra, &de, vsop87Pole); rotObliquity = (M_PI_2 - de); rotAscNode = (ra + M_PI_2); // qDebug() << "\tCalculated rotational obliquity: " << rotObliquity*180./M_PI << endl; // qDebug() << "\tCalculated rotational ascending node: " << rotAscNode*180./M_PI << endl; } p->setRotationElements( pd.value(secname+"/rot_periode", pd.value(secname+"/orbit_Period", 24.).toDouble()).toDouble()/24., pd.value(secname+"/rot_rotation_offset",0.).toDouble(), pd.value(secname+"/rot_epoch", J2000).toDouble(), rotObliquity, rotAscNode, pd.value(secname+"/rot_precession_rate",0.).toDouble()*M_PI/(180*36525), pd.value(secname+"/orbit_visualization_period",0.).toDouble()); if (pd.value(secname+"/rings", 0).toBool()) { const double rMin = pd.value(secname+"/ring_inner_size").toDouble()/AU; const double rMax = pd.value(secname+"/ring_outer_size").toDouble()/AU; Ring *r = new Ring(rMin,rMax,pd.value(secname+"/tex_ring").toString()); p->setRings(r); } systemPlanets.push_back(p); readOk++; } // special case: load earth shadow texture Planet::texEarthShadow = StelApp::getInstance().getTextureManager().createTexture("textures/earth-shadow.png"); qDebug() << "Loaded" << readOk << "/" << totalPlanets << "planet orbits"; } // Compute the position for every elements of the solar system. // The order is not important since the position is computed relatively to the mother body void SolarSystem::computePositions(double date, const Vec3d& observerPos) { if (flagLightTravelTime) { foreach (PlanetP p, systemPlanets) { p->computePositionWithoutOrbits(date); } foreach (PlanetP p, systemPlanets) { const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).length() * (AU / (SPEED_OF_LIGHT * 86400)); p->computePosition(date-light_speed_correction); } } else { foreach (PlanetP p, systemPlanets) { p->computePosition(date); } } computeTransMatrices(date, observerPos); } // Compute the transformation matrix for every elements of the solar system. // The elements have to be ordered hierarchically, eg. it's important to compute earth before moon. void SolarSystem::computeTransMatrices(double date, const Vec3d& observerPos) { if (flagLightTravelTime) { foreach (PlanetP p, systemPlanets) { const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).length() * (AU / (SPEED_OF_LIGHT * 86400)); p->computeTransMatrix(date-light_speed_correction); } } else { foreach (PlanetP p, systemPlanets) { p->computeTransMatrix(date); } } } // And sort them from the furthest to the closest to the observer struct biggerDistance : public std::binary_function { bool operator()(PlanetP p1, PlanetP p2) { return p1->getDistance() > p2->getDistance(); } }; // Draw all the elements of the solar system // We are supposed to be in heliocentric coordinate void SolarSystem::draw(StelCore* core) { if (!flagShow) return; StelNavigator* nav = core->getNavigator(); // Compute each Planet distance to the observer Vec3d obsHelioPos = nav->getObserverHeliocentricEclipticPos(); foreach (PlanetP p, systemPlanets) { p->computeDistance(obsHelioPos); } // And sort them from the furthest to the closest sort(systemPlanets.begin(),systemPlanets.end(),biggerDistance()); if (trailFader.getInterstate()>0.0000001f) { StelPainter* sPainter = new StelPainter(core->getProjection2d()); allTrails->setOpacity(trailFader.getInterstate()); allTrails->draw(core, sPainter); delete sPainter; } // Draw the elements float maxMagLabel=core->getSkyDrawer()->getLimitMagnitude()*0.80f+(labelsAmount*1.2f)-2.f; foreach (const PlanetP& p, systemPlanets) { p->draw(core, maxMagLabel, planetNameFont); } if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer()) drawPointer(core); } void SolarSystem::setStelStyle(const QString& section) { // Load colors from config file QSettings* conf = StelApp::getInstance().getSettings(); QString defaultColor = conf->value(section+"/default_color").toString(); setLabelsColor(StelUtils::strToVec3f(conf->value(section+"/planet_names_color", defaultColor).toString())); setOrbitsColor(StelUtils::strToVec3f(conf->value(section+"/planet_orbits_color", defaultColor).toString())); setTrailsColor(StelUtils::strToVec3f(conf->value(section+"/object_trails_color", defaultColor).toString())); // Recreate the trails to apply new colors recreateTrails(); } PlanetP SolarSystem::searchByEnglishName(QString planetEnglishName) const { foreach (const PlanetP& p, systemPlanets) { if (p->getEnglishName() == planetEnglishName) return p; } return PlanetP(); } StelObjectP SolarSystem::searchByNameI18n(const QString& planetNameI18) const { foreach (const PlanetP& p, systemPlanets) { if (p->getNameI18n() == planetNameI18) return qSharedPointerCast(p); } return StelObjectP(); } StelObjectP SolarSystem::searchByName(const QString& name) const { foreach (const PlanetP& p, systemPlanets) { if (p->getEnglishName() == name) return qSharedPointerCast(p); } return StelObjectP(); } // Search if any Planet is close to position given in earth equatorial position and return the distance StelObjectP SolarSystem::search(Vec3d pos, const StelCore* core) const { pos.normalize(); PlanetP closest; double cos_angle_closest = 0.; Vec3d equPos; foreach (const PlanetP& p, systemPlanets) { equPos = p->getEquinoxEquatorialPos(core->getNavigator()); equPos.normalize(); double cos_ang_dist = equPos*pos; if (cos_ang_dist>cos_angle_closest) { closest = p; cos_angle_closest = cos_ang_dist; } } if (cos_angle_closest>0.999) { return qSharedPointerCast(closest); } else return StelObjectP(); } // Return a stl vector containing the planets located inside the limFov circle around position v QList SolarSystem::searchAround(const Vec3d& vv, double limitFov, const StelCore* core) const { QList result; if (!getFlagPlanets()) return result; Vec3d v = core->getNavigator()->j2000ToEquinoxEqu(vv); v.normalize(); double cosLimFov = std::cos(limitFov * M_PI/180.); Vec3d equPos; foreach (const PlanetP& p, systemPlanets) { equPos = p->getEquinoxEquatorialPos(core->getNavigator()); equPos.normalize(); if (equPos*v>=cosLimFov) { result.append(qSharedPointerCast(p)); } } return result; } // Update i18 names from english names according to passed translator void SolarSystem::updateI18n() { StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator(); foreach (PlanetP p, systemPlanets) p->translateName(trans); } QString SolarSystem::getPlanetHashString(void) { QString str; QTextStream oss(&str); foreach (const PlanetP& p, systemPlanets) { if (!p->getParent().isNull() && p->getParent()->getEnglishName() != "Sun") { oss << p->getParent()->getEnglishName() << " : "; } oss << p->getEnglishName() << endl; oss << p->getEnglishName() << endl; } return str; } void SolarSystem::setFlagTrails(bool b) { trailFader = b; if (b) allTrails->reset(); } bool SolarSystem::getFlagTrails() const { return (bool)trailFader; } void SolarSystem::setFlagHints(bool b) { foreach (PlanetP p, systemPlanets) p->setFlagHints(b); } bool SolarSystem::getFlagHints(void) const { foreach (const PlanetP& p, systemPlanets) { if (p->getFlagHints()) return true; } return false; } void SolarSystem::setFlagLabels(bool b) { foreach (PlanetP p, systemPlanets) p->setFlagLabels(b); } bool SolarSystem::getFlagLabels() const { foreach (const PlanetP& p, systemPlanets) { if (p->getFlagLabels()) return true; } return false; } void SolarSystem::setFlagOrbits(bool b) { flagOrbits = b; if (!b || !selected || selected==sun) { foreach (PlanetP p, systemPlanets) p->setFlagOrbits(b); } else { // If a Planet is selected and orbits are on, fade out non-selected ones foreach (PlanetP p, systemPlanets) { if (selected == p) p->setFlagOrbits(b); else p->setFlagOrbits(false); } } } void SolarSystem::setFlagLightTravelTime(bool b) { flagLightTravelTime = b; } void SolarSystem::setSelected(PlanetP obj) { if (obj && obj->getType() == "Planet") selected = obj; else selected.clear();; // Undraw other objects hints, orbit, trails etc.. setFlagHints(getFlagHints()); setFlagOrbits(getFlagOrbits()); } void SolarSystem::update(double deltaTime) { trailFader.update(deltaTime*1000); if (trailFader.getInterstate()>0.f) { allTrails->update(); } foreach (PlanetP p, systemPlanets) { p->update((int)(deltaTime*1000)); } } // is a lunar eclipse close at hand? bool SolarSystem::nearLunarEclipse() { // TODO: could replace with simpler test Vec3d e = getEarth()->getEclipticPos(); Vec3d m = getMoon()->getEclipticPos(); // relative to earth Vec3d mh = getMoon()->getHeliocentricEclipticPos(); // relative to sun // shadow location at earth + moon distance along earth vector from sun Vec3d en = e; en.normalize(); Vec3d shadow = en * (e.length() + m.length()); // find shadow radii in AU double r_penumbra = shadow.length()*702378.1/AU/e.length() - 696000/AU; // modify shadow location for scaled moon Vec3d mdist = shadow - mh; if(mdist.length() > r_penumbra + 2000/AU) return 0; // not visible so don't bother drawing return 1; } //! Find and return the list of at most maxNbItem objects auto-completing the passed object I18n name QStringList SolarSystem::listMatchingObjectsI18n(const QString& objPrefix, int maxNbItem) const { QStringList result; if (maxNbItem==0) return result; QString objw = objPrefix.toUpper(); foreach (const PlanetP& p, systemPlanets) { QString constw = p->getNameI18n().mid(0, objw.size()).toUpper(); if (constw==objw) { result << p->getNameI18n(); if (result.size()==maxNbItem) return result; } } return result; } void SolarSystem::selectedObjectChangeCallBack(StelModuleSelectAction) { const QList newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet"); if (!newSelected.empty()) setSelected(qSharedPointerCast(newSelected[0])); } // Activate/Deactivate planets display void SolarSystem::setFlagPlanets(bool b) { flagShow=b; } bool SolarSystem::getFlagPlanets(void) const {return flagShow;} // Set/Get planets names color void SolarSystem::setLabelsColor(const Vec3f& c) {Planet::setLabelColor(c);} const Vec3f& SolarSystem::getLabelsColor(void) const {return Planet::getLabelColor();} // Set/Get orbits lines color void SolarSystem::setOrbitsColor(const Vec3f& c) {Planet::setOrbitColor(c);} Vec3f SolarSystem::getOrbitsColor(void) const {return Planet::getOrbitColor();} // Set/Get if Moon display is scaled void SolarSystem::setFlagMoonScale(bool b) { if (!b) getMoon()->setSphereScale(1); else getMoon()->setSphereScale(moonScale); flagMoonScale = b; } // Set/Get Moon display scaling factor void SolarSystem::setMoonScale(float f) { moonScale = f; if (flagMoonScale) getMoon()->setSphereScale(moonScale); } // Set selected planets by englishName void SolarSystem::setSelected(const QString& englishName) { setSelected(searchByEnglishName(englishName)); } // Get the list of all the planet english names QStringList SolarSystem::getAllPlanetEnglishNames() const { QStringList res; foreach (const PlanetP& p, systemPlanets) res.append(p->englishName); return res; }