diff --git a/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/Segment.cpp b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/Segment.cpp index b5fd6dbd5..2cee78545 100644 --- a/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/Segment.cpp +++ b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/Segment.cpp @@ -7,6 +7,7 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& using namespace pybind11; using ostk::core::container::Array; + using ostk::core::type::Integer; using ostk::core::type::Shared; using ostk::core::type::String; @@ -216,6 +217,21 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& )doc" ) + .def( + "get_maneuver_intervals", + &Segment::Solution::getManeuverIntervals, + R"doc( + Get the intervals of maneuvers in the segment. + + If maneuvers are already cached, returns their intervals directly. + Otherwise, extracts maneuvers using the GCRF frame and returns the intervals. + + Returns: + list[Interval]: The list of maneuver intervals. + + )doc" + ) + .def( "calculate_states_at", &Segment::Solution::calculateStatesAt, @@ -407,6 +423,9 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& arg("thruster_dynamics"), arg("dynamics"), arg("numerical_solver"), + arg_v("minimum_maneuver_duration", Duration::Undefined(), "Duration.undefined()"), + arg_v("minimum_maneuver_gap", Duration::Undefined(), "Duration.undefined()"), + arg_v("maximum_maneuver_count", Integer::Undefined(), "Integer.undefined()"), R"doc( Create a maneuver segment. @@ -416,6 +435,9 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& thruster_dynamics (ThrusterDynamics): The thruster dynamics. dynamics (Dynamics): The dynamics. numerical_solver (NumericalSolver): The numerical solver. + minimum_maneuver_duration (Duration, optional): The minimum maneuver duration. Defaults to Duration.undefined(). + minimum_maneuver_gap (Duration, optional): The minimum gap between maneuvers. Defaults to Duration.undefined(). + maximum_maneuver_count (Integer, optional): The maximum maneuver count. Defaults to Integer.undefined(). Returns: Segment: The maneuver segment. @@ -432,6 +454,9 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& arg("numerical_solver"), arg("local_orbital_frame_factory"), arg_v("maximum_allowed_angular_offset", Angle::Undefined(), "Angle.Undefined()"), + arg_v("minimum_maneuver_duration", Duration::Undefined(), "Duration.undefined()"), + arg_v("minimum_maneuver_gap", Duration::Undefined(), "Duration.undefined()"), + arg_v("maximum_maneuver_count", Integer::Undefined(), "Integer.undefined()"), R"doc( Create a maneuvering segment that produces maneuvers with a constant direction in the local orbital frame. @@ -450,6 +475,9 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Segment(pybind11::module& numerical_solver (NumericalSolver): The numerical solver. local_orbital_frame_factory (LocalOrbitalFrameFactory): The local orbital frame factory. maximum_allowed_angular_offset (Angle, optional): The maximum allowed angular offset to consider (if any). Defaults to Angle.undefined(). + minimum_maneuver_duration (Duration, optional): The minimum maneuver duration. Defaults to Duration.undefined(). + minimum_maneuver_gap (Duration, optional): The minimum gap between maneuvers. Defaults to Duration.undefined(). + maximum_maneuver_count (Integer, optional): The maximum maneuver count. Defaults to Integer.undefined(). Returns: Segment: The maneuver segment. diff --git a/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.hpp b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.hpp index e52f4cbe1..ed25b5a1a 100644 --- a/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.hpp +++ b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,8 @@ #include #include +#include + namespace ostk { namespace astrodynamics @@ -34,12 +37,14 @@ namespace trajectory using ostk::core::container::Array; using ostk::core::container::Map; +using ostk::core::container::Pair; using ostk::core::type::Integer; using ostk::core::type::Shared; using ostk::core::type::String; using ostk::mathematics::object::MatrixXd; +using ostk::physics::coordinate::Frame; using ostk::physics::time::Duration; using ostk::physics::time::Instant; using ostk::physics::time::Interval; @@ -124,6 +129,11 @@ class Segment /// @return Array of maneuvers Array extractManeuvers(const Shared& aFrameSPtr) const; + /// @brief Get maneuver intervals + /// + /// @return Array of intervals + Array getManeuverIntervals() const; + /// @brief Calculate intermediate states at specified Instants using the provided Numerical Solver /// /// @param aNumericalSolver a numerical solver to use for the propagation between states @@ -178,6 +188,9 @@ class Segment Array states; // Array of states for the segment. bool conditionIsSatisfied; // True if the event condition is satisfied. Segment::Type segmentType; // Type of segment. + + private: + mutable Pair, Array> cachedManeuvers_; // Cached maneuvers with frame }; /// @brief Output stream operator @@ -253,13 +266,19 @@ class Segment /// @param aThrusterDynamics Dynamics for the thruster /// @param aDynamicsArray Array of dynamics /// @param aNumericalSolver Numerical solver + /// @param aMinimumManeuverDuration Minimum maneuver duration (optional) + /// @param aMinimumManeuverGap Minimum gap between maneuvers (optional) + /// @param aMaximumManeuverCount Maximum maneuver count (optional) /// @return A Segment for maneuvering static Segment Maneuver( const String& aName, const Shared& anEventConditionSPtr, const Shared& aThrusterDynamics, const Array>& aDynamicsArray, - const NumericalSolver& aNumericalSolver + const NumericalSolver& aNumericalSolver, + const Duration& aMinimumManeuverDuration = Duration::Undefined(), + const Duration& aMinimumManeuverGap = Duration::Undefined(), + const Integer& aMaximumManeuverCount = Integer::Undefined() ); /// @brief Create a maneuvering segment that produces maneuvers with a constant direction in the local orbital @@ -280,6 +299,9 @@ class Segment /// @param aLocalOrbitalFrameFactory A local orbital frame factory. /// @param aMaximumAllowedAngularOffset A maximum allowed angular offset to consider (if any). Defaults /// to Undefined. + /// @param aMinimumManeuverDuration Minimum maneuver duration (optional) + /// @param aMinimumManeuverGap Minimum gap between maneuvers (optional) + /// @param aMaximumManeuverCount Maximum maneuver count (optional) static Segment ConstantLocalOrbitalFrameDirectionManeuver( const String& aName, const Shared& anEventConditionSPtr, @@ -287,7 +309,10 @@ class Segment const Array>& aDynamicsArray, const NumericalSolver& aNumericalSolver, const Shared& aLocalOrbitalFrameFactory, - const Angle& aMaximumAllowedAngularOffset = Angle::Undefined() + const Angle& aMaximumAllowedAngularOffset = Angle::Undefined(), + const Duration& aMinimumManeuverDuration = Duration::Undefined(), + const Duration& aMinimumManeuverGap = Duration::Undefined(), + const Integer& aMaximumManeuverCount = Integer::Undefined() ); private: @@ -298,6 +323,9 @@ class Segment NumericalSolver numericalSolver_; Shared constantManeuverDirectionLocalOrbitalFrameFactory_; Angle constantManeuverDirectionMaximumAllowedAngularOffset_; + Duration minimumManeuverDuration_; + Duration minimumManeuverGap_; + Integer maximumManeuverCount_; /// @brief Constructor /// @@ -306,12 +334,22 @@ class Segment /// @param anEventConditionSPtr The event condition /// @param aDynamicsArray The dynamics array /// @param aNumericalSolver The numerical solver + /// @param aLocalOrbitalFrameFactory Local orbital frame factory for constant maneuver direction (optional) + /// @param aMaximumAllowedAngularOffset Maximum allowed angular offset for constant maneuver direction (optional) + /// @param aMinimumManeuverDuration Minimum maneuver duration (optional) + /// @param aMinimumManeuverGap Minimum gap between maneuvers (optional) + /// @param aMaximumManeuverCount Maximum maneuver count (optional) Segment( const String& aName, const Type& aType, const Shared& anEventConditionSPtr, const Array>& aDynamicsArray, - const NumericalSolver& aNumericalSolver + const NumericalSolver& aNumericalSolver, + const Shared& aLocalOrbitalFrameFactory = nullptr, + const Angle& aMaximumAllowedAngularOffset = Angle::Undefined(), + const Duration& aMinimumManeuverDuration = Duration::Undefined(), + const Duration& aMinimumManeuverGap = Duration::Undefined(), + const Integer& aMaximumManeuverCount = Integer::Undefined() ); /// @brief Solve the segment using the given dynamics and event condition diff --git a/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp index f33a7abf8..19caa7e17 100644 --- a/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp +++ b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp @@ -234,6 +234,22 @@ class Sequence Array> dynamics_; Duration segmentPropagationDurationLimit_; Duration minimumManeuverDuration_; + + /// @brief Process a single segment and add it to the solution array + /// + /// @param aSegment The segment to process + /// @param aSegmentSolutions Array to add the segment solution to + /// @param anInitialState The initial state for the segment + /// @param aSegmentPropagationLimit The propagation duration limit for this segment + /// @param aSegmentNameSuffix Suffix to add to the segment solution name + /// @return True if segment was processed successfully, false if segment condition not satisfied + bool solve_( + const Segment& aSegment, + Array& aSegmentSolutions, + State& anInitialState, + const Duration& aSegmentPropagationLimit, + const String& aSegmentNameSuffix + ) const; }; } // namespace trajectory diff --git a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.cpp b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.cpp index 33aaa4f20..716886670 100644 --- a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.cpp +++ b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Segment.cpp @@ -47,7 +47,8 @@ Segment::Solution::Solution( dynamics(aDynamicsArray), states(aStateArray), conditionIsSatisfied(aConditionIsSatisfied), - segmentType(aSegmentType) + segmentType(aSegmentType), + cachedManeuvers_({nullptr, Array::Empty()}) { } @@ -145,6 +146,12 @@ Array Segment::Solution::extractManeuvers(const Shared thrusterDynamics = FindThrusterDynamics(this->dynamics); const MatrixXd fullSegmentContributions = this->getDynamicsContribution( @@ -231,9 +238,30 @@ Array Segment::Solution::extractManeuvers(const Shared Segment::Solution::getManeuverIntervals() const +{ + if (cachedManeuvers_.second.isEmpty()) + { + this->extractManeuvers(Frame::GCRF()); + } + + Array intervals = Array::Empty(); + intervals.reserve(cachedManeuvers_.second.getSize()); + + for (const flightManeuver& maneuver : cachedManeuvers_.second) + { + intervals.add(maneuver.getInterval()); + } + + return intervals; +} + Array Segment::Solution::calculateStatesAt( const Array& anInstantArray, const NumericalSolver& aNumericalSolver ) const @@ -424,15 +452,23 @@ Segment::Segment( const Segment::Type& aType, const Shared& anEventConditionSPtr, const Array>& aDynamicsArray, - const NumericalSolver& aNumericalSolver + const NumericalSolver& aNumericalSolver, + const Shared& aLocalOrbitalFrameFactory, + const Angle& aMaximumAllowedAngularOffset, + const Duration& aMinimumManeuverDuration, + const Duration& aMinimumManeuverGap, + const Integer& aMaximumManeuverCount ) : name_(aName), type_(aType), eventCondition_(anEventConditionSPtr), dynamics_(aDynamicsArray), numericalSolver_(aNumericalSolver), - constantManeuverDirectionLocalOrbitalFrameFactory_(nullptr), - constantManeuverDirectionMaximumAllowedAngularOffset_(Angle::Undefined()) + constantManeuverDirectionLocalOrbitalFrameFactory_(aLocalOrbitalFrameFactory), + constantManeuverDirectionMaximumAllowedAngularOffset_(aMaximumAllowedAngularOffset), + minimumManeuverDuration_(aMinimumManeuverDuration), + minimumManeuverGap_(aMinimumManeuverGap), + maximumManeuverCount_(aMaximumManeuverCount) { if (eventCondition_ == nullptr) { @@ -592,6 +628,11 @@ Segment Segment::Coast( anEventConditionSPtr, aDynamicsArray, aNumericalSolver, + nullptr, + Angle::Undefined(), + Duration::Undefined(), + Duration::Undefined(), + Integer::Undefined(), }; } @@ -600,7 +641,10 @@ Segment Segment::Maneuver( const Shared& anEventConditionSPtr, const Shared& aThrusterDynamics, const Array>& aDynamicsArray, - const NumericalSolver& aNumericalSolver + const NumericalSolver& aNumericalSolver, + const Duration& aMinimumManeuverDuration, + const Duration& aMinimumManeuverGap, + const Integer& aMaximumManeuverCount ) { return { @@ -609,6 +653,11 @@ Segment Segment::Maneuver( anEventConditionSPtr, aDynamicsArray + Array> {aThrusterDynamics}, aNumericalSolver, + nullptr, + Angle::Undefined(), + aMinimumManeuverDuration, + aMinimumManeuverGap, + aMaximumManeuverCount, }; } @@ -619,21 +668,24 @@ Segment Segment::ConstantLocalOrbitalFrameDirectionManeuver( const Array>& aDynamicsArray, const NumericalSolver& aNumericalSolver, const Shared& aLocalOrbitalFrameFactory, - const Angle& aMaximumAllowedAngularOffset + const Angle& aMaximumAllowedAngularOffset, + const Duration& aMinimumManeuverDuration, + const Duration& aMinimumManeuverGap, + const Integer& aMaximumManeuverCount ) { - Segment segment = { + return { aName, Segment::Type::Maneuver, anEventConditionSPtr, aDynamicsArray + Array> {aThrusterDynamics}, aNumericalSolver, + aLocalOrbitalFrameFactory, + aMaximumAllowedAngularOffset, + aMinimumManeuverDuration, + aMinimumManeuverGap, + aMaximumManeuverCount, }; - - segment.constantManeuverDirectionLocalOrbitalFrameFactory_ = aLocalOrbitalFrameFactory; - segment.constantManeuverDirectionMaximumAllowedAngularOffset_ = aMaximumAllowedAngularOffset; - - return segment; } Segment::Solution Segment::Solve_( @@ -663,6 +715,97 @@ Segment::Solution Segment::Solve_( states.add(stateBuilder.expand(state.inFrame(aState.accessFrame()), aState)); } + // Check maneuver constraints if applicable + if (type_ == Segment::Type::Maneuver && + (minimumManeuverDuration_.isDefined() || minimumManeuverGap_.isDefined() || maximumManeuverCount_.isDefined())) + { + // Create preliminary solution to extract maneuvers + const Segment::Solution preliminarySolution = { + name_, + aDynamicsArray, + states, + conditionSolution.conditionIsSatisfied, + type_, + }; + + const Array maneuvers = preliminarySolution.extractManeuvers(aState.accessFrame()); + + // Check if we need to truncate based on constraints + Size maneuverCountLimit = maneuvers.getSize(); + + for (Size i = 0; i < maneuvers.getSize(); ++i) + { + const flightManeuver& currentManeuver = maneuvers[i]; + + // Check minimum maneuver duration + if (minimumManeuverDuration_.isDefined()) + { + const Duration maneuverDuration = currentManeuver.getInterval().getDuration(); + if (maneuverDuration < minimumManeuverDuration_) + { + maneuverCountLimit = i; + break; + } + } + + // Check minimum maneuver gap (if not the first maneuver) + if (minimumManeuverGap_.isDefined() && i > 0) + { + const Instant previousManeuverEnd = maneuvers[i - 1].getInterval().accessEnd(); + const Instant currentManeuverStart = currentManeuver.getInterval().accessStart(); + const Duration gap = currentManeuverStart - previousManeuverEnd; + + if (gap < minimumManeuverGap_) + { + maneuverCountLimit = i; + break; + } + } + + // Check maximum maneuver count + if (maximumManeuverCount_.isDefined() && (i + 1) > static_cast(maximumManeuverCount_)) + { + maneuverCountLimit = i; + break; + } + } + + // Truncate states if necessary + if (maneuverCountLimit < maneuvers.getSize()) + { + // Find the first instant of the first excluded maneuver + const Instant firstExcludedManeuverStart = maneuvers[maneuverCountLimit].getInterval().accessStart(); + + // Find the first state at or after the excluded maneuver start + Size truncationIndex = 0; + for (Size j = 0; j < states.getSize(); ++j) + { + if (states[j].accessInstant() >= firstExcludedManeuverStart) + { + truncationIndex = j; + break; + } + } + + // Truncate the states array to exclude the first excluded maneuver and everything after + Array truncatedStates = Array::Empty(); + if (truncationIndex > 0) + { + truncatedStates.reserve(truncationIndex); + for (Size j = 0; j < truncationIndex; ++j) + { + truncatedStates.add(states[j]); + } + } + else + { + // If the first excluded maneuver starts at or before the first state, return only the initial state + truncatedStates.add(states.accessFirst()); + } + states = truncatedStates; + } + } + return { name_, aDynamicsArray, diff --git a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.cpp b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.cpp index b0a44a9c2..6dbe9dd33 100644 --- a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.cpp +++ b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.cpp @@ -295,48 +295,18 @@ Sequence::Solution Sequence::solve(const State& aState, const Size& aRepetitionC } Array segmentSolutions = Array::Empty(); - State initialState = aState; - State finalState = State::Undefined(); for (Size i = 0; i < aRepetitionCount; ++i) { for (const Segment& segment : segments_) { - segment.accessEventCondition()->updateTarget(initialState); - - BOOST_LOG_TRIVIAL(debug) << "Solving Segment:\n" << segment << std::endl; - - Segment::Solution segmentSolution = segment.solve(initialState, segmentPropagationDurationLimit_); - - segmentSolution.name = - String::Format("{} - {} - {}", segmentSolution.name, segment.getEventCondition()->getName(), i); - - BOOST_LOG_TRIVIAL(debug) << "\n" << segmentSolution << std::endl; - - if (segment.getType() == Segment::Type::Maneuver && minimumManeuverDuration_.isDefined()) + const String segmentNameSuffix = String::Format(" - {}", i); + + if (!solve_(segment, segmentSolutions, initialState, segmentPropagationDurationLimit_, segmentNameSuffix)) { - if (segmentSolution.getPropagationDuration() < minimumManeuverDuration_) - { - BOOST_LOG_TRIVIAL(debug) - << "Maneuver duration is less than the minimum maneuver duration. Skipping this maneuver." - << std::endl; - - continue; - } - } - - segmentSolutions.add(segmentSolution); - - // Terminate Sequence unsuccessfully if the segment condition was not satisfied - if (!segmentSolution.conditionIsSatisfied) - { - BOOST_LOG_TRIVIAL(warning) << "Segment condition is not satisfied." << std::endl; - return {segmentSolutions, false}; } - - initialState = segmentSolution.states.accessLast(); } } @@ -348,12 +318,8 @@ Sequence::Solution Sequence::solveToCondition( ) const { Array segmentSolutions = Array::Empty(); - State initialState = aState; - State finalState = State::Undefined(); - bool eventConditionIsSatisfied = false; - Duration propagationDuration = Duration::Zero(); const Unique sequenceCondition(anEventCondition.clone()); @@ -363,55 +329,31 @@ Sequence::Solution Sequence::solveToCondition( { for (const Segment& segment : segments_) { - segment.accessEventCondition()->updateTarget(initialState); - - BOOST_LOG_TRIVIAL(debug) << "Solving Segment:\n" << segment << std::endl; - const Duration segmentPropagationDurationLimit = std::min(segmentPropagationDurationLimit_, aMaximumPropagationDuration - propagationDuration); - Segment::Solution segmentSolution = segment.solve(initialState, segmentPropagationDurationLimit); - - segmentSolution.name = - String::Format("{} - {}", segmentSolution.name, segment.getEventCondition()->getName()); - - BOOST_LOG_TRIVIAL(debug) << "\n" << segmentSolution << std::endl; - - // Skip maneuver if it is less than the minimum maneuver duration - if (segment.getType() == Segment::Type::Maneuver && minimumManeuverDuration_.isDefined()) + const Size segmentSolutionSizeBefore = segmentSolutions.getSize(); + + if (!solve_(segment, segmentSolutions, initialState, segmentPropagationDurationLimit, "")) { - if (segmentSolution.getPropagationDuration() < minimumManeuverDuration_) - { - BOOST_LOG_TRIVIAL(debug) - << "Maneuver duration is less than the minimum maneuver duration. Skipping this maneuver." - << std::endl; - - continue; - } + return {segmentSolutions, false}; } - segmentSolutions.add(segmentSolution); - - // Terminate Sequence unsuccessfully if the segment condition was not satisfied - if (!segmentSolution.conditionIsSatisfied) + // Check if a segment solution was added (it might have been skipped due to minimum maneuver duration) + if (segmentSolutions.getSize() > segmentSolutionSizeBefore) { - BOOST_LOG_TRIVIAL(warning) << "Segment condition is not satisfied." << std::endl; + const Segment::Solution& segmentSolution = segmentSolutions.accessLast(); - return {segmentSolutions, false}; - } + eventConditionIsSatisfied = sequenceCondition->isSatisfied(segmentSolution.states.accessLast(), initialState); - eventConditionIsSatisfied = - sequenceCondition->isSatisfied(segmentSolution.states.accessLast(), initialState); + // Terminate Sequence successfully if the provided event condition was satisfied + if (eventConditionIsSatisfied) + { + return {segmentSolutions, true}; + } - // Terminate Sequence successfully if a provided event condition was satisfied - if (eventConditionIsSatisfied) - { - return {segmentSolutions, true}; + propagationDuration += segmentSolution.getPropagationDuration(); } - - propagationDuration += segmentSolution.getPropagationDuration(); - - initialState = segmentSolution.states.accessLast(); } } @@ -459,6 +401,55 @@ void Sequence::print(std::ostream& anOutputStream, bool displayDecorator) const } } +bool Sequence::solve_( + const Segment& aSegment, + Array& aSegmentSolutions, + State& anInitialState, + const Duration& aSegmentPropagationLimit, + const String& aSegmentNameSuffix +) const +{ + aSegment.accessEventCondition()->updateTarget(anInitialState); + + BOOST_LOG_TRIVIAL(debug) << "Solving Segment:\n" << aSegment << std::endl; + + Segment::Solution segmentSolution = aSegment.solve(anInitialState, aSegmentPropagationLimit); + + segmentSolution.name = String::Format("{} - {}{}", segmentSolution.name, aSegment.getEventCondition()->getName(), aSegmentNameSuffix); + + BOOST_LOG_TRIVIAL(debug) << "\n" << segmentSolution << std::endl; + + // Skip maneuver if any maneuver interval is less than the minimum maneuver duration + if (aSegment.getType() == Segment::Type::Maneuver && minimumManeuverDuration_.isDefined()) + { + const Array maneuverIntervals = segmentSolution.getManeuverIntervals(); + + for (const Interval& interval : maneuverIntervals) + { + if (interval.getDuration() < minimumManeuverDuration_) + { + BOOST_LOG_TRIVIAL(debug) + << "Maneuver duration is less than the minimum maneuver duration. Skipping this maneuver." + << std::endl; + + return true; // Continue to next segment + } + } + } + + aSegmentSolutions.add(segmentSolution); + + // Terminate if the segment condition was not satisfied + if (!segmentSolution.conditionIsSatisfied) + { + BOOST_LOG_TRIVIAL(warning) << "Segment condition is not satisfied." << std::endl; + return false; // Don't continue + } + + anInitialState = segmentSolution.states.accessLast(); + return true; // Continue to next segment +} + } // namespace trajectory } // namespace astrodynamics } // namespace ostk