Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/celastro/astro.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ struct KeplerElements
double argPericenter{ 0.0 };
double meanAnomaly{ 0.0 };
double period{ 0.0 };
double nodalPeriod{ 0.0 };
double apsidalPeriod{ 0.0 };
};


Expand Down
36 changes: 32 additions & 4 deletions src/celengine/parseobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,9 @@ GetDefaultUnits(bool usePlanetUnits, double& distanceScale)
* SemiMajorAxis <number>
* PericenterDistance <number>
*
* # Required
* # One of the following is required:
* Period <number>
* AnomalisticPeriod <number>
*
* Eccentricity <number> (default: 0.0)
* Inclination <degrees> (default: 0.0)
Expand All @@ -133,14 +134,20 @@ GetDefaultUnits(bool usePlanetUnits, double& distanceScale)
* # One or none of the following:
* MeanAnomaly <degrees> (default: 0.0)
* MeanLongitude <degrees> (default: 0.0)
*
* # One or both of the following for a precessing orbit:
* # Default values result in no precession
* NodalPrecessionPeriod <number> (default: 0.0)
* ApsidalPrecessionPeriod <number> (default: 0.0)
* } \endcode
*
* If usePlanetUnits is true:
* Period is in Julian years
* Period or AnomalisticPeriod is in Julian years
* SemiMajorAxis or PericenterDistance is in AU
* Otherwise:
* Period is in Julian days
* Period or AnomalisticPeriod is in Julian days
* SemiMajorAxis or PericenterDistance is in kilometers.
* The default unit for precession periods is Julian years.
*/
std::shared_ptr<const ephem::Orbit>
CreateKeplerianOrbit(const AssociativeArray* orbitData,
Expand Down Expand Up @@ -183,6 +190,9 @@ CreateKeplerianOrbit(const AssociativeArray* orbitData,
return nullptr;
}

elements.nodalPeriod = orbitData->getTime<double>("NodalPrecessionPeriod", 1.0, astro::DAYS_PER_YEAR).value_or(0.0);
elements.apsidalPeriod = orbitData->getTime<double>("ApsidalPrecessionPeriod", 1.0, astro::DAYS_PER_YEAR).value_or(0.0);

if (auto periodValue = orbitData->getTime<double>("Period", 1.0, timeScale); periodValue.has_value())
{
elements.period = *periodValue;
Expand All @@ -192,6 +202,21 @@ CreateKeplerianOrbit(const AssociativeArray* orbitData,
return nullptr;
}
}
else if (auto anomPeriodValue = orbitData->getTime<double>("AnomalisticPeriod", 1.0, timeScale); anomPeriodValue.has_value())
{
double periodCorrection = 0.0;
if (elements.nodalPeriod != 0.0)
periodCorrection -= 1.0 / elements.nodalPeriod;
if (elements.apsidalPeriod != 0.0)
periodCorrection += 1.0 / elements.apsidalPeriod;

elements.period = 1.0 / (1.0 / *anomPeriodValue + periodCorrection);
if (elements.period == 0.0)
{
GetLogger()->error("AnomalisticPeriod cannot be zero.\n");
return nullptr;
}
}
else
{
GetLogger()->error("Period must be specified in EllipticalOrbit.\n");
Expand Down Expand Up @@ -228,7 +253,10 @@ CreateKeplerianOrbit(const AssociativeArray* orbitData,

if (elements.eccentricity < 1.0)
{
return std::make_shared<ephem::EllipticalOrbit>(elements, epoch);
if (elements.nodalPeriod == 0.0 && elements.apsidalPeriod == 0.0)
return std::make_shared<ephem::EllipticalOrbit>(elements, epoch);

return std::make_shared<ephem::PrecessingOrbit>(elements, epoch);
}

return std::make_shared<ephem::HyperbolicOrbit>(elements, epoch);
Expand Down
7 changes: 5 additions & 2 deletions src/celengine/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@

for (unsigned int mipLevel = 0; mipLevel <= log2size; mipLevel++)
{
/*
// Optional gaussian glare

Check warning on line 368 in src/celengine/render.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the misleading "//" characters.

See more on https://sonarcloud.io/project/issues?id=CelestiaProject_Celestia&issues=AZ2e3abzuhKPs5YIS6jx&open=AZ2e3abzuhKPs5YIS6jx&pullRequest=2364
float fwhm = (float) pow(2.0f, (float) (log2size - mipLevel)) * 0.15f;
float power = (float) pow(2.0f, (float) (log2size - mipLevel)) * 0.15f;
BuildGaussianDiscMipLevel(img->getMipLevel(mipLevel),
Expand All @@ -375,13 +375,13 @@
*/

Check warning on line 375 in src/celengine/render.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the commented out code.

See more on https://sonarcloud.io/project/issues?id=CelestiaProject_Celestia&issues=AZ2e3abzuhKPs5YIS6jz&open=AZ2e3abzuhKPs5YIS6jz&pullRequest=2364
BuildGlareMipLevel(img->getMipLevel(mipLevel),
log2size - mipLevel,
25.0f / (float) pow(2.0f, (float) (log2size - mipLevel)),

Check warning on line 378 in src/celengine/render.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this redundant cast.

See more on https://sonarcloud.io/project/issues?id=CelestiaProject_Celestia&issues=AZ2e3abzuhKPs5YIS6jy&open=AZ2e3abzuhKPs5YIS6jy&pullRequest=2364
0.66f);
/*
BuildGlareMipLevel2(img->getMipLevel(mipLevel),
log2size - mipLevel,
1.0f / (float) pow(2.0f, (float) (log2size - mipLevel)));
*/

Check warning on line 384 in src/celengine/render.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the commented out code.

See more on https://sonarcloud.io/project/issues?id=CelestiaProject_Celestia&issues=AZ2e3abzuhKPs5YIS6j0&open=AZ2e3abzuhKPs5YIS6j0&pullRequest=2364
}

return std::make_unique<ImageTexture>(*img,
Expand Down Expand Up @@ -1002,8 +1002,11 @@
const Body* body = orbitPath.body;
double nearZ = -nearDist; // negate, becase z is into the screen in camera space
double farZ = -farDist;
bool isFadingEnabled = util::is_set(renderFlags, RenderFlags::ShowFadingOrbits);

const auto* orbit = body != nullptr ? body->getOrbit(t) : orbitPath.star->getOrbit();
const auto* orbit = body != nullptr ?
body->getOrbit(t)->getOrbitForSampling(t, isFadingEnabled) :
orbitPath.star->getOrbit()->getOrbitForSampling(t, isFadingEnabled);

CurvePlot* cachedOrbit = nullptr;
if (auto cached = orbitCache.lower_bound(orbit);
Expand Down Expand Up @@ -1174,7 +1177,7 @@
double windowStart = windowEnd - period * OrbitPeriodsShown;
double windowDuration = windowEnd - windowStart;

if (LinearFadeFraction == 0.0f || !util::is_set(renderFlags, RenderFlags::ShowFadingOrbits))
if (LinearFadeFraction == 0.0f || !isFadingEnabled)
{
cachedOrbit->render(modelview,
nearZ, farZ, viewFrustumPlaneNormals,
Expand Down
165 changes: 153 additions & 12 deletions src/celephem/orbit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@
CreateKeplerOrbit(const astro::KeplerElements& elements, double epoch)
{
if (elements.eccentricity < 1.0)
return std::make_unique<EllipticalOrbit>(elements, epoch);
{
if (elements.nodalPeriod == 0.0 && elements.apsidalPeriod == 0.0)
return std::make_unique<EllipticalOrbit>(elements, epoch);

return std::make_unique<PrecessingOrbit>(elements, epoch);
}

return std::make_unique<HyperbolicOrbit>(elements, epoch);
}
Expand Down Expand Up @@ -269,15 +274,18 @@
}


EllipticalOrbit::EllipticalOrbit(const astro::KeplerElements& _elements, double _epoch) :
const Orbit* Orbit::getOrbitForSampling(double /*t*/, bool /*isFadingEnabled*/) const
{
return this;
}


EllipticalOrbitBase::EllipticalOrbitBase(const astro::KeplerElements& _elements, double _epoch) :
semiMajorAxis(_elements.semimajorAxis),
eccentricity(_elements.eccentricity),
meanAnomalyAtEpoch(_elements.meanAnomaly),
period(_elements.period),
epoch(_epoch),
orbitPlaneRotation((math::ZRotation(_elements.longAscendingNode) *
math::XRotation(_elements.inclination) *
math::ZRotation(_elements.argPericenter)).toRotationMatrix())
epoch(_epoch)
{
assert(eccentricity >= 0.0 && eccentricity < 1.0);
assert(semiMajorAxis >= 0.0);
Expand All @@ -286,7 +294,7 @@
}


double EllipticalOrbit::eccentricAnomaly(double M) const
double EllipticalOrbitBase::eccentricAnomaly(double M) const
{
if (eccentricity == 0.0)
{
Expand All @@ -313,6 +321,26 @@
}


double EllipticalOrbitBase::getPeriod() const
{
return period;
}


double EllipticalOrbitBase::getBoundingRadius() const
{
// TODO: watch out for unbounded parabolic and hyperbolic orbits
return semiMajorAxis * (1.0 + eccentricity);
}


EllipticalOrbit::EllipticalOrbit(const astro::KeplerElements& _elements, double _epoch) :
EllipticalOrbitBase(_elements, _epoch),
orbitPlaneRotation((math::ZRotation(_elements.longAscendingNode) *
math::XRotation(_elements.inclination) *
math::ZRotation(_elements.argPericenter)).toRotationMatrix()) {}


// Compute the position at the specified eccentric
// anomaly E.
Eigen::Vector3d EllipticalOrbit::positionAtE(double E) const
Expand Down Expand Up @@ -370,16 +398,129 @@
}


double EllipticalOrbit::getPeriod() const
void EllipticalOrbit::setOrientation(const Eigen::Matrix3d& _orbitPlaneRotation)
{
return period;
orbitPlaneRotation = _orbitPlaneRotation;
}


double EllipticalOrbit::getBoundingRadius() const
PrecessingOrbit::PrecessingOrbit(const astro::KeplerElements& _elements, double _epoch) :
EllipticalOrbitBase(_elements, _epoch),
longAscendingNodeAtEpoch(_elements.longAscendingNode),
argPericenterAtEpoch(_elements.argPericenter),
nodalPeriod(_elements.nodalPeriod),
apsidalPeriod(_elements.apsidalPeriod),
inclinationRotation(math::XRotation(_elements.inclination)) {}


// Compute the position at the specified eccentric
// anomaly E.
Eigen::Vector3d PrecessingOrbit::positionAtE(double E, double longAscendingNode, double argPericenter) const
{
// TODO: watch out for unbounded parabolic and hyperbolic orbits
return semiMajorAxis * (1.0 + eccentricity);
double x = semiMajorAxis * (std::cos(E) - eccentricity);
double y = semiMinorAxis * std::sin(E);

Eigen::Matrix3d orbitPlaneRotation = (math::ZRotation(longAscendingNode) *
inclinationRotation *
math::ZRotation(argPericenter)).toRotationMatrix();
Eigen::Vector3d p = orbitPlaneRotation * Eigen::Vector3d(x, y, 0);

// Convert to Celestia's internal coordinate system
return Eigen::Vector3d(p.x(), p.z(), -p.y());
}


// Compute the velocity at the specified eccentric
// anomaly E.
Eigen::Vector3d PrecessingOrbit::velocityAtE(double E, double longAscendingNode, double argPericenter, double meanMotion) const
{
double sinE;
double cosE;
math::sincos(E, sinE, cosE);

double edot = meanMotion / (1.0 - eccentricity * cosE);

double x = -semiMajorAxis * sinE * edot;
double y = semiMinorAxis * cosE * edot;

Eigen::Matrix3d orbitPlaneRotation = (math::ZRotation(longAscendingNode) *
inclinationRotation *
math::ZRotation(argPericenter)).toRotationMatrix();
Eigen::Vector3d v = orbitPlaneRotation* Eigen::Vector3d(x, y, 0);

// Convert to Celestia's coordinate system
return Eigen::Vector3d(v.x(), v.z(), -v.y());
}


// Return the offset from the center
Eigen::Vector3d PrecessingOrbit::positionAtTime(double t) const
{
t = t - epoch;

// Period is assumed to be sidereal
double meanMotion = 2.0 * celestia::numbers::pi / period;
double nodalPrecessionRate = nodalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / -nodalPeriod : 0.0;
double apsidalPrecessionRate = apsidalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / apsidalPeriod : 0.0;

double longAscendingNode = longAscendingNodeAtEpoch + t * nodalPrecessionRate;
double argPericenter = argPericenterAtEpoch + t * apsidalPrecessionRate;
double meanAnomaly = meanAnomalyAtEpoch + t * (meanMotion - apsidalPrecessionRate - nodalPrecessionRate);
double E = eccentricAnomaly(meanAnomaly);

return positionAtE(E, longAscendingNode, argPericenter);
}


Eigen::Vector3d PrecessingOrbit::velocityAtTime(double t) const
{
t = t - epoch;

// Period is assumed to be sidereal
double meanMotion = 2.0 * celestia::numbers::pi / period;
double nodalPrecessionRate = nodalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / -nodalPeriod : 0.0;
double apsidalPrecessionRate = apsidalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / apsidalPeriod : 0.0;

double longAscendingNode = longAscendingNodeAtEpoch + t * nodalPrecessionRate;
double argPericenter = argPericenterAtEpoch + t * apsidalPrecessionRate;
double meanAnomaly = meanAnomalyAtEpoch + t * (meanMotion - apsidalPrecessionRate - nodalPrecessionRate);
double E = eccentricAnomaly(meanAnomaly);

return velocityAtE(E, longAscendingNode, argPericenter, meanMotion);
}


// For precessing orbits, get the osculating orbit when fading is disabled
const Orbit* PrecessingOrbit::getOrbitForSampling(double t, bool isFadingEnabled) const
{
if (!isFadingEnabled)
{
t = t - epoch;
double meanMotion = 2.0 * celestia::numbers::pi / period;
double nodalPrecessionRate = nodalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / -nodalPeriod : 0.0;
double apsidalPrecessionRate = apsidalPeriod != 0.0 ? 2.0 * celestia::numbers::pi / apsidalPeriod : 0.0;

double longAscendingNode = longAscendingNodeAtEpoch + t * nodalPrecessionRate;
double argPericenter = argPericenterAtEpoch + t * apsidalPrecessionRate;
double meanAnomaly = meanAnomalyAtEpoch + t * (meanMotion - apsidalPrecessionRate - nodalPrecessionRate);

astro::KeplerElements elements;
elements.semimajorAxis = semiMajorAxis;
elements.eccentricity = eccentricity;
elements.meanAnomaly = meanAnomaly;
elements.period = period;

Eigen::Matrix3d orbitPlaneRotation = (math::ZRotation(longAscendingNode) *
inclinationRotation *
math::ZRotation(argPericenter)).toRotationMatrix();

auto* orbit = new EllipticalOrbit(elements, t);

Check failure on line 517 in src/celephem/orbit.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the use of "new" with an operation that automatically manages the memory.

See more on https://sonarcloud.io/project/issues?id=CelestiaProject_Celestia&issues=AZ2e3afOuhKPs5YIS6j1&open=AZ2e3afOuhKPs5YIS6j1&pullRequest=2364
orbit->setOrientation(orbitPlaneRotation);

return orbit;
}

return this;
}


Expand Down
Loading
Loading