diff --git a/src/celengine/body.cpp b/src/celengine/body.cpp index 51192afff9..e5dfec8d36 100644 --- a/src/celengine/body.cpp +++ b/src/celengine/body.cpp @@ -813,7 +813,7 @@ bool Body::extant(double t) const } -void Body::getLifespan(double& begin, double& end) const +void Body::getLifespan(std::optional& begin, std::optional& end) const { begin = timeline->startTime(); end = timeline->endTime(); diff --git a/src/celengine/body.h b/src/celengine/body.h index 27686ff9a5..dd3925ba61 100644 --- a/src/celengine/body.h +++ b/src/celengine/body.h @@ -308,8 +308,7 @@ class Body Eigen::Vector3d eclipticToPlanetocentric(const Eigen::Vector3d& ecl, double tdb) const; bool extant(double) const; - void setLifespan(double, double); - void getLifespan(double&, double&) const; + void getLifespan(std::optional&, std::optional&) const; Surface* getAlternateSurface(const std::string&) const; void addAlternateSurface(const std::string&, Surface*); diff --git a/src/celengine/fisheyeprojectionmode.cpp b/src/celengine/fisheyeprojectionmode.cpp index 782d5e5e72..c9753eb652 100644 --- a/src/celengine/fisheyeprojectionmode.cpp +++ b/src/celengine/fisheyeprojectionmode.cpp @@ -59,7 +59,7 @@ float FisheyeProjectionMode::getFieldCorrection(float /*zoom*/) const } celmath::Frustum -FisheyeProjectionMode::getFrustum(float nearZ, float farZ, float zoom) const +FisheyeProjectionMode::getFrustum(float nearZ, std::optional farZ, float zoom) const { return celmath::Frustum(getFOV(zoom), width / height, nearZ, farZ); } diff --git a/src/celengine/fisheyeprojectionmode.h b/src/celengine/fisheyeprojectionmode.h index cb3453ca6a..505c53ca0e 100644 --- a/src/celengine/fisheyeprojectionmode.h +++ b/src/celengine/fisheyeprojectionmode.h @@ -32,7 +32,7 @@ class FisheyeProjectionMode : public ProjectionMode float getZoom(float fov) const override; float getPixelSize(float zoom) const override; float getFieldCorrection(float zoom) const override; - celmath::Frustum getFrustum(float nearZ, float farZ, float zoom) const override; + celmath::Frustum getFrustum(float nearZ, std::optional farZ, float zoom) const override; double getViewConeAngleMax(float zoom) const override; float getNormalizedDeviceZ(float nearZ, float farZ, float z) const override; diff --git a/src/celengine/parseobject.cpp b/src/celengine/parseobject.cpp index f23f8453f1..ce5f22f4cd 100644 --- a/src/celengine/parseobject.cpp +++ b/src/celengine/parseobject.cpp @@ -87,27 +87,31 @@ GetDefaultUnits(bool usePlanetUnits, double& distanceScale) bool ParseDate(const Hash* hash, const string& name, double& jd) { - // Check first for a number value representing a Julian date - if (auto jdVal = hash->getNumber(name); jdVal.has_value()) + if (auto value = ParseDate(hash, name); value.has_value()) { - jd = *jdVal; + jd = value.value(); return true; } + return false; +} + +std::optional +ParseDate(const Hash* hash, const string& name) +{ + // Check first for a number value representing a Julian date + if (auto jdVal = hash->getNumber(name); jdVal.has_value()) + return *jdVal; if (const std::string* dateString = hash->getString(name); dateString != nullptr) { astro::Date date(1, 1, 1); if (astro::parseDate(*dateString, date)) - { - jd = (double) date; - return true; - } + return static_cast(date); } - return false; + return std::nullopt; } - /*! * Create a new Keplerian orbit from an ssc property table: * diff --git a/src/celengine/parseobject.h b/src/celengine/parseobject.h index 56fa86f263..05bb5ed9ad 100644 --- a/src/celengine/parseobject.h +++ b/src/celengine/parseobject.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,7 @@ enum class DataDisposition bool ParseDate(const Hash* hash, const std::string& name, double& jd); +std::optional ParseDate(const Hash* hash, const std::string& name); celestia::ephem::Orbit* CreateOrbit(const Selection& centralObject, const Hash* planetData, diff --git a/src/celengine/perspectiveprojectionmode.cpp b/src/celengine/perspectiveprojectionmode.cpp index bf344077ad..9534dfba2c 100644 --- a/src/celengine/perspectiveprojectionmode.cpp +++ b/src/celengine/perspectiveprojectionmode.cpp @@ -56,7 +56,7 @@ float PerspectiveProjectionMode::getFieldCorrection(float zoom) const } celmath::Frustum -PerspectiveProjectionMode::getFrustum(float nearZ, float farZ, float zoom) const +PerspectiveProjectionMode::getFrustum(float nearZ, std::optional farZ, float zoom) const { return celmath::Frustum(getFOV(zoom), width / height, nearZ, farZ); } diff --git a/src/celengine/perspectiveprojectionmode.h b/src/celengine/perspectiveprojectionmode.h index 8013d9ab29..3176ae8723 100644 --- a/src/celengine/perspectiveprojectionmode.h +++ b/src/celengine/perspectiveprojectionmode.h @@ -32,7 +32,7 @@ class PerspectiveProjectionMode : public ProjectionMode float getZoom(float fov) const override; float getPixelSize(float zoom) const override; float getFieldCorrection(float zoom) const override; - celmath::Frustum getFrustum(float nearZ, float farZ, float zoom) const override; + celmath::Frustum getFrustum(float nearZ, std::optional farZ, float zoom) const override; double getViewConeAngleMax(float zoom) const override; float getNormalizedDeviceZ(float nearZ, float farZ, float z) const override; diff --git a/src/celengine/projectionmode.h b/src/celengine/projectionmode.h index 950ee6eaac..ac6d4502fa 100644 --- a/src/celengine/projectionmode.h +++ b/src/celengine/projectionmode.h @@ -10,6 +10,7 @@ #pragma once #include +#include class ShaderManager; @@ -36,7 +37,7 @@ class ProjectionMode virtual float getZoom(float fov) const = 0; virtual float getPixelSize(float zoom) const = 0; virtual float getFieldCorrection(float zoom) const = 0; - virtual celmath::Frustum getFrustum(float nearZ, float farZ, float zoom) const = 0; + virtual celmath::Frustum getFrustum(float nearZ, std::optional farZ, float zoom) const = 0; // Calculate the cosine of half the maximum field of view. We'll use this for // fast testing of object visibility. diff --git a/src/celengine/render.cpp b/src/celengine/render.cpp index c0cbe2e66e..fd1a8a635f 100644 --- a/src/celengine/render.cpp +++ b/src/celengine/render.cpp @@ -1531,7 +1531,7 @@ void Renderer::draw(const Observer& observer, m_cameraOrientation = Quaterniond(m_cameraTransform) * observer.getOrientation(); // Get the view frustum used for culling in camera space. - auto frustum = projectionMode->getFrustum(MinNearPlaneDistance, std::numeric_limits::infinity(), zoom); + auto frustum = projectionMode->getFrustum(MinNearPlaneDistance, std::nullopt, zoom); // Get the transformed frustum, used for culling in the astrocentric coordinate // system. @@ -3939,7 +3939,7 @@ void Renderer::renderDeepSkyObjects(const Universe& universe, dsoRenderer.renderFlags = renderFlags; dsoRenderer.labelMode = labelMode; - dsoRenderer.frustum = projectionMode->getFrustum(MinNearPlaneDistance, std::numeric_limits::infinity(), observer.getZoom()); + dsoRenderer.frustum = projectionMode->getFrustum(MinNearPlaneDistance, std::nullopt, observer.getZoom()); // Use pixelSize * screenDpi instead of FoV, to eliminate windowHeight dependence. // = 1.0 at startup float effDistanceToScreen = mmToInches((float) REF_DISTANCE_TO_SCREEN) * pixelSize * getScreenDpi(); diff --git a/src/celengine/solarsys.cpp b/src/celengine/solarsys.cpp index 49283ae976..e7f1170c64 100644 --- a/src/celengine/solarsys.cpp +++ b/src/celengine/solarsys.cpp @@ -272,24 +272,30 @@ TimelinePhase::SharedConstPtr CreateTimelinePhase(Body* body, const ReferenceFrame::SharedConstPtr& defaultBodyFrame, bool isFirstPhase, bool isLastPhase, - double previousPhaseEnd) + std::optional previousPhaseEnd) { - double beginning = previousPhaseEnd; - double ending = std::numeric_limits::infinity(); + std::optional beginning = previousPhaseEnd; + std::optional ending = std::nullopt; // Beginning is optional for the first phase of a timeline, and not // allowed for the other phases, where beginning is always the ending // of the previous phase. - bool hasBeginning = ParseDate(phaseData, "Beginning", beginning); - if (!isFirstPhase && hasBeginning) + if (auto newBeginning = ParseDate(phaseData, "Beginning"); newBeginning.has_value()) { - GetLogger()->error("Error: Beginning can only be specified for initial phase of timeline.\n"); - return nullptr; + beginning = newBeginning.value(); + if (!isFirstPhase) + { + GetLogger()->error("Error: Beginning can only be specified for initial phase of timeline.\n"); + return nullptr; + } } // Ending is required for all phases except for the final one. - bool hasEnding = ParseDate(phaseData, "Ending", ending); - if (!isLastPhase && !hasEnding) + if (auto newEnding = ParseDate(phaseData, "Ending"); newEnding.has_value()) + { + ending = newEnding.value(); + } + else if (!isLastPhase) { GetLogger()->error("Error: Ending is required for all timeline phases other than the final one.\n"); return nullptr; @@ -375,7 +381,7 @@ Timeline* CreateTimelineFromArray(Body* body, const ReferenceFrame::SharedConstPtr& defaultBodyFrame) { auto timeline = std::make_unique(); - double previousEnding = -std::numeric_limits::infinity(); + std::optional previousEnding = std::nullopt; if (timelineArray->empty()) { @@ -487,8 +493,8 @@ bool CreateTimeline(Body* body, ReferenceFrame::SharedConstPtr bodyFrame; celestia::ephem::Orbit* orbit = nullptr; celestia::ephem::RotationModel* rotationModel = nullptr; - double beginning = -std::numeric_limits::infinity(); - double ending = std::numeric_limits::infinity(); + std::optional beginning = std::nullopt; + std::optional ending = std::nullopt; // If any new timeline values are specified, we need to overrideOldTimeline will // be set to true. @@ -601,10 +607,16 @@ bool CreateTimeline(Body* body, rotationModel = CreateDefaultRotationModel(syncRotationPeriod); } - if (ParseDate(planetData, "Beginning", beginning)) + if (auto newBeginning = ParseDate(planetData, "Beginning"); newBeginning.has_value()) + { + beginning = newBeginning.value(); overrideOldTimeline = true; - if (ParseDate(planetData, "Ending", ending)) + } + if (auto newEnding = ParseDate(planetData, "Ending"); newEnding.has_value()) + { + ending = newEnding.value(); overrideOldTimeline = true; + } // Something went wrong if the disposition isn't modify and no timeline // is to be created. @@ -612,7 +624,7 @@ bool CreateTimeline(Body* body, if (overrideOldTimeline) { - if (beginning >= ending) + if (beginning.has_value() && ending.has_value() && beginning.value() >= ending.value()) { GetLogger()->error("Beginning time must be before Ending time.\n"); delete rotationModel; diff --git a/src/celengine/timeline.cpp b/src/celengine/timeline.cpp index 8dee834bab..aa422e6379 100644 --- a/src/celengine/timeline.cpp +++ b/src/celengine/timeline.cpp @@ -40,7 +40,8 @@ Timeline::appendPhase(TimelinePhase::SharedConstPtr &phase) // no gaps and no overlaps. if (!phases.empty()) { - if (phase->startTime() != phases.back()->endTime()) + auto startTime = phase->startTime(); + if (!startTime.has_value() || startTime.value() != phases.back()->endTime()) return false; } @@ -64,7 +65,8 @@ Timeline::findPhase(double t) const { for (const auto& phase : phases) { - if (t < phase->endTime()) + auto endTime = phase->endTime(); + if (!endTime.has_value() || t < endTime.value()) return phase; } @@ -92,14 +94,14 @@ Timeline::phaseCount() const } -double +std::optional Timeline::startTime() const { return phases.front()->startTime(); } -double +std::optional Timeline::endTime() const { return phases.back()->endTime(); @@ -114,7 +116,11 @@ Timeline::endTime() const bool Timeline::includes(double t) const { - return phases.front()->startTime() <= t && t <= phases.back()->endTime(); + if (auto startTime = phases.front()->startTime(); startTime.has_value() && t < startTime.value()) + return false; + if (auto endTime = phases.back()->endTime(); endTime.has_value() && t > endTime.value()) + return false; + return true; } diff --git a/src/celengine/timeline.h b/src/celengine/timeline.h index 6fb32dc339..261aaf22a4 100644 --- a/src/celengine/timeline.h +++ b/src/celengine/timeline.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include "timelinephase.h" @@ -27,8 +28,8 @@ class Timeline const TimelinePhase::SharedConstPtr& getPhase(unsigned int n) const; unsigned int phaseCount() const; - double startTime() const; - double endTime() const; + std::optional startTime() const; + std::optional endTime() const; bool includes(double t) const; void markChanged(); diff --git a/src/celengine/timelinephase.cpp b/src/celengine/timelinephase.cpp index c6c3d84c56..d456e434e2 100644 --- a/src/celengine/timelinephase.cpp +++ b/src/celengine/timelinephase.cpp @@ -23,8 +23,8 @@ using namespace std; TimelinePhase::TimelinePhase(Body* _body, - double _startTime, - double _endTime, + std::optional _startTime, + std::optional _endTime, const ReferenceFrame::SharedConstPtr& _orbitFrame, celestia::ephem::Orbit* _orbit, const ReferenceFrame::SharedConstPtr& _bodyFrame, @@ -47,15 +47,15 @@ TimelinePhase::TimelinePhase(Body* _body, TimelinePhase::SharedConstPtr TimelinePhase::CreateTimelinePhase(Universe& universe, Body* body, - double startTime, - double endTime, + std::optional startTime, + std::optional endTime, const ReferenceFrame::SharedConstPtr& orbitFrame, celestia::ephem::Orbit& orbit, const ReferenceFrame::SharedConstPtr& bodyFrame, celestia::ephem::RotationModel& rotationModel) { // Validate the time range. - if (endTime <= startTime) + if (endTime.has_value() && startTime.has_value() && endTime.value() <= startTime.value()) return nullptr; // Get the frame tree to add the new phase to. Verify that the reference frame diff --git a/src/celengine/timelinephase.h b/src/celengine/timelinephase.h index 0b375d1690..562f7c6509 100644 --- a/src/celengine/timelinephase.h +++ b/src/celengine/timelinephase.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include "frame.h" class FrameTree; @@ -36,12 +37,12 @@ class TimelinePhase return m_body; } - double startTime() const + std::optional startTime() const { return m_startTime; } - double endTime() const + std::optional endTime() const { return m_endTime; } @@ -79,13 +80,26 @@ class TimelinePhase */ bool includes(double t) const { - return m_startTime <= t && t < m_endTime; + if (m_startTime.has_value() && t < m_startTime.value()) + return false; + if (m_endTime.has_value() && t >= m_endTime.value()) + return false; + return true; + } + + double clamp(double t) const + { + if (m_startTime.has_value() && t < m_startTime.value()) + return m_startTime.value(); + if (m_endTime.has_value() && t > m_endTime.value()) + return m_endTime.value(); + return t; } static TimelinePhase::SharedConstPtr CreateTimelinePhase(Universe& universe, Body* body, - double startTime, - double endTime, + std::optional startTime, + std::optional endTime, const ReferenceFrame::SharedConstPtr& orbitFrame, celestia::ephem::Orbit& orbit, const ReferenceFrame::SharedConstPtr& bodyFrame, @@ -94,8 +108,8 @@ class TimelinePhase ~TimelinePhase() = default; TimelinePhase(Body* _body, - double _startTime, - double _endTime, + std::optional _startTime, + std::optional _endTime, const ReferenceFrame::SharedConstPtr& _orbitFrame, celestia::ephem::Orbit* _orbit, const ReferenceFrame::SharedConstPtr& _bodyFrame, @@ -108,8 +122,8 @@ class TimelinePhase private: Body* m_body; - double m_startTime; - double m_endTime; + std::optional m_startTime; + std::optional m_endTime; ReferenceFrame::SharedConstPtr m_orbitFrame; celestia::ephem::Orbit* m_orbit; diff --git a/src/celestia/qt/qtinfopanel.cpp b/src/celestia/qt/qtinfopanel.cpp index 2e688d63d9..63f7ed1ce8 100644 --- a/src/celestia/qt/qtinfopanel.cpp +++ b/src/celestia/qt/qtinfopanel.cpp @@ -226,15 +226,15 @@ void InfoPanel::buildSolarSystemBodyPage(const Body* body, stream << QString(_("Has atmosphere")) << "
\n"; // Start and end dates - double startTime = 0.0; - double endTime = 0.0; + std::optional startTime = std::nullopt; + std::optional endTime = std::nullopt; body->getLifespan(startTime, endTime); - if (startTime > -1.0e9) - stream << "
" << QString(_("Start: %1")).arg(astro::TDBtoUTC(startTime).toCStr()) << "
\n"; + if (startTime.has_value()) + stream << "
" << QString(_("Start: %1")).arg(astro::TDBtoUTC(startTime.value()).toCStr()) << "
\n"; - if (endTime < 1.0e9) - stream << "
" << QString(_("End: %1")).arg(astro::TDBtoUTC(endTime).toCStr()) << "
\n"; + if (endTime.has_value()) + stream << "
" << QString(_("End: %1")).arg(astro::TDBtoUTC(endTime.value()).toCStr()) << "
\n"; stream << "
" << QString(_("Orbit information")) << "
\n"; stream << QString(_("Osculating elements for %1")).arg(astro::TDBtoUTC(t).toCStr()) << "
\n"; diff --git a/src/celestia/qt/qtselectionpopup.cpp b/src/celestia/qt/qtselectionpopup.cpp index a6cfb60cf5..7ce4eb63a1 100644 --- a/src/celestia/qt/qtselectionpopup.cpp +++ b/src/celestia/qt/qtselectionpopup.cpp @@ -65,26 +65,26 @@ SelectionPopup::SelectionPopup(const Selection& sel, addAction(boldTextItem(QString::fromStdString(sel.body()->getName(true)))); // Start and end dates - double startTime = 0.0; - double endTime = 0.0; + std::optional startTime = std::nullopt; + std::optional endTime = std::nullopt; sel.body()->getLifespan(startTime, endTime); - if (startTime > -1.0e9 || endTime < 1.0e9) + if (startTime.has_value() || endTime.has_value()) { addSeparator(); - if (startTime > -1.0e9) + if (startTime.has_value()) { - QString startDateStr = QString(_("Start: %1")).arg(astro::TDBtoUTC(startTime).toCStr()); + QString startDateStr = QString(_("Start: %1")).arg(astro::TDBtoUTC(startTime.value()).toCStr()); QAction* startDateAct = new QAction(startDateStr, this); connect(startDateAct, SIGNAL(triggered()), this, SLOT(slotGotoStartDate())); addAction(startDateAct); } - if (endTime < 1.0e9) + if (endTime.has_value()) { - QString endDateStr = QString(_("End: %1")).arg(astro::TDBtoUTC(endTime).toCStr()); + QString endDateStr = QString(_("End: %1")).arg(astro::TDBtoUTC(endTime.value()).toCStr()); QAction* endDateAct = new QAction(endDateStr, this); connect(endDateAct, SIGNAL(triggered()), this, SLOT(slotGotoEndDate())); @@ -646,20 +646,22 @@ void SelectionPopup::slotToggleTerminator() void SelectionPopup::slotGotoStartDate() { assert(selection.body() != nullptr); - double startDate = 0.0; - double endDate = 0.0; + std::optional startDate = std::nullopt; + std::optional endDate = std::nullopt; selection.body()->getLifespan(startDate, endDate); - appCore->getSimulation()->setTime(startDate); + if (startDate.has_value()) + appCore->getSimulation()->setTime(startDate.value()); } void SelectionPopup::slotGotoEndDate() { assert(selection.body() != nullptr); - double startDate = 0.0; - double endDate = 0.0; + std::optional startDate = std::nullopt; + std::optional endDate = std::nullopt; selection.body()->getLifespan(startDate, endDate); - appCore->getSimulation()->setTime(endDate); + if (endDate.has_value()) + appCore->getSimulation()->setTime(endDate.value()); } diff --git a/src/celmath/frustum.cpp b/src/celmath/frustum.cpp index fe5a742bf3..df35f71ed4 100644 --- a/src/celmath/frustum.cpp +++ b/src/celmath/frustum.cpp @@ -23,16 +23,16 @@ Frustum::Frustum(float fov, float aspectRatio, float n) : init(fov, aspectRatio, n, n); } -Frustum::Frustum(float fov, float aspectRatio, float n, float f) : - infinite(std::isinf(f)) +Frustum::Frustum(float fov, float aspectRatio, float n, std::optional f) : + infinite(!f.has_value()) { - init(fov, aspectRatio, n, infinite ? n : f); + init(fov, aspectRatio, n, infinite ? n : f.value()); } -Frustum::Frustum(float l, float r, float t, float b, float n, float f) : - infinite(std::isinf(f)) +Frustum::Frustum(float l, float r, float t, float b, float n, std::optional f) : + infinite(!f.has_value()) { - init(l, r, t, b, n, infinite ? n : f); + init(l, r, t, b, n, infinite ? n : f.value()); } void Frustum::init(float fov, float aspectRatio, float n, float f) diff --git a/src/celmath/frustum.h b/src/celmath/frustum.h index e379f404d2..939ef34f3d 100644 --- a/src/celmath/frustum.h +++ b/src/celmath/frustum.h @@ -12,6 +12,7 @@ #include #include +#include namespace celmath { @@ -22,8 +23,8 @@ class Frustum using PlaneType = Eigen::Hyperplane; Frustum(float fov, float aspectRatio, float nearDist); - Frustum(float fov, float aspectRatio, float nearDist, float farDist); - Frustum(float left, float right, float top, float bottom, float nearDist, float farDist); + Frustum(float fov, float aspectRatio, float nearDist, std::optional farDist); + Frustum(float left, float right, float top, float bottom, float nearDist, std::optional farDist); inline Eigen::Hyperplane plane(unsigned int which) const { diff --git a/src/celscript/lua/celx_object.cpp b/src/celscript/lua/celx_object.cpp index 40f057bdf8..f7ece01b52 100644 --- a/src/celscript/lua/celx_object.cpp +++ b/src/celscript/lua/celx_object.cpp @@ -670,10 +670,11 @@ static int object_getinfo(lua_State* l) float eqRadius = max(semiAxes.x(), semiAxes.z()); celx.setTable("oblateness", (eqRadius - polarRadius) / eqRadius); - double lifespanStart, lifespanEnd; + std::optional lifespanStart; + std::optional lifespanEnd; body->getLifespan(lifespanStart, lifespanEnd); - celx.setTable("lifespanStart", (lua_Number)lifespanStart); - celx.setTable("lifespanEnd", (lua_Number)lifespanEnd); + celx.setTable("lifespanStart", static_cast(lifespanStart.value_or(-std::numeric_limits::infinity()))); + celx.setTable("lifespanEnd", static_cast(lifespanEnd.value_or(std::numeric_limits::infinity()))); // TODO: atmosphere, surfaces ? PlanetarySystem* system = body->getSystem(); diff --git a/src/celscript/lua/celx_phase.cpp b/src/celscript/lua/celx_phase.cpp index 46254503cd..7feb861ec5 100644 --- a/src/celscript/lua/celx_phase.cpp +++ b/src/celscript/lua/celx_phase.cpp @@ -76,7 +76,7 @@ static int phase_timespan(lua_State* l) celx.checkArgs(1, 1, "No arguments allowed for to phase:timespan"); auto phase = this_phase(l); - celx.push(phase->startTime(), phase->endTime()); + celx.push(phase->startTime().value_or(-std::numeric_limits::infinity()), phase->endTime().value_or(std::numeric_limits::infinity())); //lua_pushnumber(l, phase->startTime()); //lua_pushnumber(l, phase->endTime()); @@ -135,10 +135,7 @@ static int phase_getposition(lua_State* l) auto phase = this_phase(l); double tdb = celx.safeGetNumber(2, WrongType, "Argument to phase:getposition() must be number", 0.0); - if (tdb < phase->startTime()) - tdb = phase->startTime(); - else if (tdb > phase->endTime()) - tdb = phase->endTime(); + tdb = phase->clamp(tdb); celx.newPosition(UniversalCoord(phase->orbit()->positionAtTime(tdb) * astro::kilometersToMicroLightYears(1.0))); return 1; @@ -160,10 +157,7 @@ static int phase_getorientation(lua_State* l) auto phase = this_phase(l); double tdb = celx.safeGetNumber(2, WrongType, "Argument to phase:getorientation() must be number", 0.0); - if (tdb < phase->startTime()) - tdb = phase->startTime(); - else if (tdb > phase->endTime()) - tdb = phase->endTime(); + tdb = phase->clamp(tdb); celx.newRotation(phase->rotationModel()->orientationAtTime(tdb)); return 1;