diff --git a/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory.cpp b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory.cpp index 8d57ff88f..e75b36685 100644 --- a/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory.cpp +++ b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory.cpp @@ -11,6 +11,7 @@ #include #include #include +#include inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory(pybind11::module& aModule) { @@ -56,6 +57,7 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory(pybind11::module& aModule OpenSpaceToolkitAstrodynamicsPy_Trajectory_LocalOrbitalFrameDirection(trajectory); OpenSpaceToolkitAstrodynamicsPy_Trajectory_State(trajectory); + OpenSpaceToolkitAstrodynamicsPy_Trajectory_StateBuilder(trajectory); OpenSpaceToolkitAstrodynamicsPy_Trajectory_Orbit(trajectory); OpenSpaceToolkitAstrodynamicsPy_Trajectory_Model(trajectory); OpenSpaceToolkitAstrodynamicsPy_Trajectory_Propagator(trajectory); diff --git a/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/StateBuilder.cpp b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/StateBuilder.cpp new file mode 100644 index 000000000..cd81df008 --- /dev/null +++ b/bindings/python/src/OpenSpaceToolkitAstrodynamicsPy/Trajectory/StateBuilder.cpp @@ -0,0 +1,47 @@ +/// Apache License 2.0 + +#include + +inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_StateBuilder(pybind11::module& aModule) +{ + using namespace pybind11; + + using ostk::core::types::Shared; + using ostk::core::ctnr::Array; + + using ostk::physics::coord::Frame; + + using ostk::astro::trajectory::State; + using ostk::astro::trajectory::StateBuilder; + using ostk::astro::trajectory::state::CoordinatesBroker; + + class_(aModule, "StateBuilder") + + .def( + init&, const Array>&>(), + arg("frame"), + arg("coordinates_subsets") + ) + .def( + init&, const Shared&>(), + arg("frame"), + arg("coordinates_broker") + ) + + .def(self == self) + .def(self != self) + + .def("__str__", &(shiftToString)) + .def("__repr__", &(shiftToString)) + + .def("is_defined", &StateBuilder::isDefined) + + .def("build_state", &StateBuilder::buildState) + + .def("get_coordinates_subsets", &StateBuilder::getCoordinatesSubsets) + .def("get_frame", &StateBuilder::getFrame) + + .def_static("undefined", &StateBuilder::Undefined) + + ; +} diff --git a/bindings/python/test/trajectory/test_propagator.py b/bindings/python/test/trajectory/test_propagator.py index ca6430562..29b066796 100644 --- a/bindings/python/test/trajectory/test_propagator.py +++ b/bindings/python/test/trajectory/test_propagator.py @@ -98,7 +98,18 @@ def environment(earth) -> Environment: @pytest.fixture -def coordinates_broker(): +def coordinates_broker_7d(): + return CoordinatesBroker( + [ + CartesianPosition.default(), + CartesianVelocity.default(), + CoordinatesSubset.mass(), + ] + ) + + +@pytest.fixture +def coordinates_broker_9d(): return CoordinatesBroker( [ CartesianPosition.default(), @@ -112,7 +123,7 @@ def coordinates_broker(): @pytest.fixture def state( - satellite_system: SatelliteSystem, coordinates_broker: CoordinatesBroker + satellite_system: SatelliteSystem, coordinates_broker_7d: CoordinatesBroker ) -> State: instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC) @@ -128,12 +139,12 @@ def state( satellite_system.get_mass().in_kilograms() + propellant_mass, ] - return State(instant, coordinates, Frame.GCRF(), coordinates_broker) + return State(instant, coordinates, Frame.GCRF(), coordinates_broker_7d) @pytest.fixture def state_low_altitude( - satellite_system: SatelliteSystem, coordinates_broker: CoordinatesBroker + satellite_system: SatelliteSystem, coordinates_broker_9d: CoordinatesBroker ) -> State: instant: Instant = Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC) @@ -153,7 +164,7 @@ def state_low_altitude( cd, ] - return State(instant, coordinates, Frame.GCRF(), coordinates_broker) + return State(instant, coordinates, Frame.GCRF(), coordinates_broker_9d) @pytest.fixture diff --git a/bindings/python/test/trajectory/test_state_builder.py b/bindings/python/test/trajectory/test_state_builder.py new file mode 100644 index 000000000..84c956242 --- /dev/null +++ b/bindings/python/test/trajectory/test_state_builder.py @@ -0,0 +1,99 @@ +# Apache License 2.0 + +import pytest + +import numpy as np + +from ostk.physics.time import Instant +from ostk.physics.time import DateTime +from ostk.physics.time import Scale +from ostk.physics.coordinate import Frame + +from ostk.astrodynamics.trajectory import ( + State, + StateBuilder, +) +from ostk.astrodynamics.trajectory.state import ( + CoordinatesBroker, + CoordinatesSubset, +) +from ostk.astrodynamics.trajectory.state.coordinates_subset import ( + CartesianPosition, + CartesianVelocity, +) + + +@pytest.fixture() +def instant() -> Instant: + return Instant.date_time(DateTime(2018, 1, 1, 0, 0, 0), Scale.UTC) + + +@pytest.fixture +def frame() -> Frame: + return Frame.GCRF() + + +@pytest.fixture +def coordinates_subsets() -> list[CoordinatesSubset]: + return [CartesianPosition.default(), CartesianVelocity.default()] + + +@pytest.fixture +def coordinates_broker(coordinates_subsets: list[CoordinatesSubset]) -> CoordinatesBroker: + return CoordinatesBroker(coordinates_subsets) + + +@pytest.fixture +def state_builder(frame: Frame, coordinates_broker: CoordinatesBroker) -> State: + return StateBuilder(frame, coordinates_broker) + + +class TestState: + def test_broker_constructor( + self, + frame: Frame, + coordinates_broker: CoordinatesBroker, + ): + builder = StateBuilder(frame, coordinates_broker) + assert builder is not None + assert isinstance(builder, StateBuilder) + assert builder.is_defined() + + def test_subsets_constructor( + self, + frame: Frame, + coordinates_subsets: list[CoordinatesSubset], + ): + builder = StateBuilder(frame, coordinates_subsets) + assert builder is not None + assert isinstance(builder, StateBuilder) + assert builder.is_defined() + + def test_comparators(self, state_builder: StateBuilder): + assert (state_builder == state_builder) is True + assert (state_builder != state_builder) is False + + def test_build_state( + self, + instant: Instant, + state_builder: StateBuilder, + ): + coordinates = [1, 2, 3, 1, 2, 3] + state: State = state_builder.build_state(instant, coordinates) + + assert state is not None + assert isinstance(state, State) + assert state.is_defined() + assert state.get_instant() == instant + assert (state.get_coordinates() == coordinates).all() + assert state.get_frame() == state_builder.get_frame() + assert state.get_coordinates_subsets() == state_builder.get_coordinates_subsets() + + def test_getters( + self, + state_builder: StateBuilder, + frame: Frame, + coordinates_broker: CoordinatesBroker, + ): + assert state_builder.get_frame() == frame + assert state_builder.get_coordinates_subsets() == coordinates_broker.get_subsets() diff --git a/include/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.hpp b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.hpp new file mode 100644 index 000000000..90abcbf28 --- /dev/null +++ b/include/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.hpp @@ -0,0 +1,142 @@ +/// Apache License 2.0 + +#ifndef __OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder__ +#define __OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder__ + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +namespace ostk +{ +namespace astro +{ +namespace trajectory +{ + +using ostk::core::types::Shared; +using ostk::core::ctnr::Array; + +using ostk::math::obj::VectorXd; + +using ostk::physics::coord::Frame; + +using ostk::physics::time::Instant; + +using ostk::astro::trajectory::State; +using ostk::astro::trajectory::state::CoordinatesBroker; +using ostk::astro::trajectory::state::CoordinatesSubset; + +/// @brief Factory class to generate States with common reference frame and coordinates subsets + +class StateBuilder +{ + public: + /// @brief Constructor. + /// + /// @param [in] aFrameSPtr The reference frame in which the coordinates are referenced to and + /// resolved in + /// @param [in] aCoordinatesSubsetsArray The array of coordinates subsets defining the output + /// States + + StateBuilder( + const Shared& aFrameSPtr, const Array>& aCoordinatesSubsetsArray + ); + + /// @brief Constructor. + /// + /// @param [in] aFrameSPtr The reference frame in which the coordinates are referenced to and + /// resolved in + /// @param [in] aCoordinatesBroker Shared pointer to an existing Coordinates Broker + + StateBuilder(const Shared& aFrameSPtr, const Shared& aCoordinatesBrokerSPtr); + + /// @brief Equality operator. + /// + /// @param [in] aStateBuilder The StateBuilder to compare to + /// @return True if the StateBuilders are equal, false otherwise + + bool operator==(const StateBuilder& aStateBuilder) const; + + /// @brief Inequality operator. + /// + /// @param [in] aStateBuilder The StateBuilder to compare to + /// @return True if the StateBuilders are not equal, false otherwise + + bool operator!=(const StateBuilder& aStateBuilder) const; + + /// @brief Stream insertion operator. + /// + /// @param [in] anOutputStream The output stream to insert into + /// @param [in] aStateBuilder The StateBuilder to insert + /// @return The output stream with the StateBuilder inserted + + friend std::ostream& operator<<(std::ostream& anOutputStream, const StateBuilder& aStateBuilder); + + /// @brief Check if the StateBuilder is defined. + /// + /// @return True if the StateBuilder is defined, false otherwise + + bool isDefined() const; + + /// @brief Produce a State linked to the Frame and Coordinates Broker of the StateBuilder. + /// + /// @return A State linked to the Frame and Coordinates Broker of the StateBuilder + + const State buildState(const Instant& anInstant, const VectorXd& aCoordinates) const; + + /// @brief Accessor for the reference frame. + /// + /// @return The reference frame + + const Shared accessFrame() const; + + /// @brief Access the coordinates broker associated with the StateBuilder. + /// + /// @return The coordinates broker associated to the State + + const Shared& accessCoordinatesBroker() const; + + /// @brief Get the reference frame associated with the StateBuilder. + /// + /// @return The reference frame + + Shared getFrame() const; + + /// @brief Get the coordinates subsets of the StateBuilder. + /// + /// @return The coordinates subsets + + const Array> getCoordinatesSubsets() const; + + /// @brief Print the StateBuilder to an output stream. + /// + /// @param [in] anOutputStream The output stream to print to + /// @param [in] displayDecorator Whether or not to display the decorator + + void print(std::ostream& anOutputStream, bool displayDecorator = true) const; + + /// @brief Get an undefined StateBuilder. + /// + /// @return An undefined StateBuilder + + static StateBuilder Undefined(); + + private: + Shared frameSPtr_; + Shared coordinatesBrokerSPtr_; +}; + +} // namespace trajectory +} // namespace astro +} // namespace ostk + +#endif diff --git a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/State.cpp b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/State.cpp index f10656c4a..f562cad1a 100644 --- a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/State.cpp +++ b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/State.cpp @@ -1,7 +1,5 @@ /// Apache License 2.0 -// #include - #include #include @@ -34,6 +32,10 @@ State::State( frameSPtr_(aFrameSPtr), coordinatesBrokerSPtr_(aCoordinatesBrokerSPtr) { + if (coordinatesBrokerSPtr_ && (Size)coordinates_.size() != coordinatesBrokerSPtr_->getNumberOfCoordinates()) + { + throw ostk::core::error::runtime::Wrong("Number of Coordinates"); + } } State::State( diff --git a/src/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.cpp b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.cpp new file mode 100644 index 000000000..68c418fd5 --- /dev/null +++ b/src/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.cpp @@ -0,0 +1,144 @@ +/// Apache License 2.0 + +#include + +#include + +namespace ostk +{ +namespace astro +{ +namespace trajectory +{ + +StateBuilder::StateBuilder( + const Shared& aFrameSPtr, const Array>& aCoordinatesSubsetsArray +) + : frameSPtr_(aFrameSPtr), + coordinatesBrokerSPtr_(std::make_shared(CoordinatesBroker(aCoordinatesSubsetsArray))) +{ +} + +StateBuilder::StateBuilder( + const Shared& aFrameSPtr, const Shared& aCoordinatesBrokerSPtr +) + : frameSPtr_(aFrameSPtr), + coordinatesBrokerSPtr_(aCoordinatesBrokerSPtr) +{ +} + +bool StateBuilder::operator==(const StateBuilder& aStateBuilder) const +{ + if ((!this->isDefined()) || (!aStateBuilder.isDefined())) + { + return false; + } + + if (this->frameSPtr_ != aStateBuilder.frameSPtr_) + { + return false; + } + + if ((*this->coordinatesBrokerSPtr_) != (*aStateBuilder.coordinatesBrokerSPtr_)) + { + return false; + } + + return true; +} + +bool StateBuilder::operator!=(const StateBuilder& aStateBuilder) const +{ + return !((*this) == aStateBuilder); +} + +std::ostream& operator<<(std::ostream& anOutputStream, const StateBuilder& aStateBuilder) +{ + aStateBuilder.print(anOutputStream); + + return anOutputStream; +} + +bool StateBuilder::isDefined() const +{ + return (this->frameSPtr_ != nullptr) && this->frameSPtr_->isDefined() && (this->coordinatesBrokerSPtr_ != nullptr); +} + +const State StateBuilder::buildState(const Instant& anInstant, const VectorXd& aCoordinates) const +{ + if (!this->isDefined()) + { + throw ostk::core::error::runtime::Undefined("StateBuilder"); + } + + return {anInstant, aCoordinates, this->frameSPtr_, this->coordinatesBrokerSPtr_}; +} + +const Shared StateBuilder::accessFrame() const +{ + if (!this->isDefined()) + { + throw ostk::core::error::runtime::Undefined("StateBuilder"); + } + + return this->frameSPtr_; +} + +const Shared& StateBuilder::accessCoordinatesBroker() const +{ + if (!this->isDefined()) + { + throw ostk::core::error::runtime::Undefined("StateBuilder"); + } + + return this->coordinatesBrokerSPtr_; +} + +Shared StateBuilder::getFrame() const +{ + return this->accessFrame(); +} + +const Array> StateBuilder::getCoordinatesSubsets() const +{ + if (!this->isDefined()) + { + throw ostk::core::error::runtime::Undefined("StateBuilder"); + } + + return this->coordinatesBrokerSPtr_->getSubsets(); +} + +void StateBuilder::print(std::ostream& anOutputStream, bool displayDecorator) const +{ + using ostk::core::types::String; + + displayDecorator ? ostk::core::utils::Print::Header(anOutputStream, "Trajectory :: StateBuilder") : void(); + + ostk::core::utils::Print::Line(anOutputStream) + << "Frame:" << (this->frameSPtr_->isDefined() ? this->frameSPtr_->getName() : "Undefined"); + + if (!this->isDefined()) + { + ostk::core::utils::Print::Line(anOutputStream) << "Coordinates Subsets: Undefined"; + } + else + { + const Array> subsets = this->coordinatesBrokerSPtr_->getSubsets(); + + for (const auto& subset : subsets) + { + ostk::core::utils::Print::Line(anOutputStream) << subset->getName(); + } + } + displayDecorator ? ostk::core::utils::Print::Footer(anOutputStream) : void(); +} + +StateBuilder StateBuilder::Undefined() +{ + return {Frame::Undefined(), nullptr}; +} + +} // namespace trajectory +} // namespace astro +} // namespace ostk diff --git a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/AngularCondition.test.cpp b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/AngularCondition.test.cpp index f1e244e78..d217c2643 100644 --- a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/AngularCondition.test.cpp +++ b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/AngularCondition.test.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include @@ -30,6 +32,7 @@ using ostk::physics::units::Angle; using ostk::astro::eventcondition::AngularCondition; using ostk::astro::trajectory::State; +using ostk::astro::trajectory::StateBuilder; using ostk::astro::trajectory::state::CoordinatesBroker; using ostk::astro::trajectory::state::CoordinatesSubset; @@ -48,15 +51,17 @@ class OpenSpaceToolkit_Astrodynamics_EventCondition_AngularCondition : public :: defaultName_, defaultCriterion_, defaultEvaluator_, defaultTargetAngle_ }; + const Array> defaultSubsets_ = { + std::make_shared(CoordinatesSubset("ANGLE", 1)) + }; + const StateBuilder defaultStateBuilder_ = StateBuilder(Frame::GCRF(), defaultSubsets_); + const State generateState(const Real& coordinate) { - VectorXd coordinates; - coordinates.resize(1); + VectorXd coordinates(1); coordinates << coordinate; - const Shared defaultCoordinatesBroker = - std::make_shared(CoordinatesBroker(Array>::Empty())); - return State(Instant::J2000(), coordinates, Frame::GCRF(), defaultCoordinatesBroker); + return defaultStateBuilder_.buildState(Instant::J2000(), coordinates); } }; diff --git a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/BooleanCondition.test.cpp b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/BooleanCondition.test.cpp index 3489106bd..9371c85be 100644 --- a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/BooleanCondition.test.cpp +++ b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/BooleanCondition.test.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include @@ -28,6 +30,7 @@ using ostk::physics::coord::Frame; using ostk::astro::eventcondition::BooleanCondition; using ostk::astro::trajectory::State; +using ostk::astro::trajectory::StateBuilder; using ostk::astro::trajectory::state::CoordinatesBroker; using ostk::astro::trajectory::state::CoordinatesSubset; @@ -52,12 +55,17 @@ class OpenSpaceToolkit_Astrodynamics_EventCondition_BooleanCondition : public :: const Shared defaultCoordinatesBroker_ = std::make_shared(CoordinatesBroker(Array>::Empty())); + const Array> defaultSubsets_ = { + std::make_shared(CoordinatesSubset("ANGLE", 1)) + }; + const StateBuilder defaultStateBuilder_ = StateBuilder(defaultFrame_, defaultSubsets_); + const State generateState(const Real& coordinate) { - VectorXd coordinates; - coordinates.resize(1); + VectorXd coordinates(1); coordinates << coordinate; - return State(defaultInstant_, coordinates, defaultFrame_, defaultCoordinatesBroker_); + + return defaultStateBuilder_.buildState(defaultInstant_, coordinates); } }; diff --git a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/RealCondition.test.cpp b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/RealCondition.test.cpp index 97e5e569f..c1bca020d 100644 --- a/test/OpenSpaceToolkit/Astrodynamics/EventCondition/RealCondition.test.cpp +++ b/test/OpenSpaceToolkit/Astrodynamics/EventCondition/RealCondition.test.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include @@ -28,6 +30,7 @@ using ostk::physics::coord::Frame; using ostk::astro::eventcondition::RealCondition; using ostk::astro::trajectory::State; +using ostk::astro::trajectory::StateBuilder; using ostk::astro::trajectory::state::CoordinatesBroker; using ostk::astro::trajectory::state::CoordinatesSubset; @@ -47,12 +50,17 @@ class OpenSpaceToolkit_Astrodynamics_EventCondition_RealCondition : public ::tes const Shared defaultCoordinatesBroker_ = std::make_shared(CoordinatesBroker(Array>::Empty())); + const Array> defaultSubsets_ = { + std::make_shared(CoordinatesSubset("REAL", 1)) + }; + const StateBuilder defaultStateBuilder_ = StateBuilder(defaultFrame_, defaultSubsets_); + const State generateState(const Real& coordinate) { - VectorXd coordinates; - coordinates.resize(1); + VectorXd coordinates(1); coordinates << coordinate; - return State(defaultInstant_, coordinates, defaultFrame_, defaultCoordinatesBroker_); + + return defaultStateBuilder_.buildState(defaultInstant_, coordinates); } }; diff --git a/test/OpenSpaceToolkit/Astrodynamics/Trajectory/State.test.cpp b/test/OpenSpaceToolkit/Astrodynamics/Trajectory/State.test.cpp index c7721120c..98d1a30bc 100644 --- a/test/OpenSpaceToolkit/Astrodynamics/Trajectory/State.test.cpp +++ b/test/OpenSpaceToolkit/Astrodynamics/Trajectory/State.test.cpp @@ -54,6 +54,17 @@ TEST(OpenSpaceToolkit_Astrodynamics_Trajectory_State, Constructor) EXPECT_EQ(state.extractCoordinates(CartesianVelocity::Default()), coordinates.segment(3, 3)); } + { + const Instant instant = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates(3); + coordinates << 1.0, 2.0, 3.0; + const Shared brokerSPtr = std::make_shared( + CoordinatesBroker({CartesianPosition::Default(), CartesianVelocity::Default()}) + ); + + EXPECT_THROW(State state(instant, coordinates, Frame::GCRF(), brokerSPtr), ostk::core::error::runtime::Wrong); + } + { const Instant instant = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); const Position position = Position::Meters({1.2, 3.4, 5.6}, Frame::GCRF()); diff --git a/test/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.test.cpp b/test/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.test.cpp new file mode 100644 index 000000000..71ff97234 --- /dev/null +++ b/test/OpenSpaceToolkit/Astrodynamics/Trajectory/StateBuilder.test.cpp @@ -0,0 +1,366 @@ +/// Apache License 2.0 + +#include +#include +#include + +#include + +using ostk::core::types::Shared; +using ostk::core::ctnr::Array; + +using ostk::math::obj::VectorXd; + +using ostk::physics::coord::Frame; +using ostk::physics::time::DateTime; +using ostk::physics::time::Instant; +using ostk::physics::time::Scale; + +using ostk::astro::trajectory::State; +using ostk::astro::trajectory::StateBuilder; +using ostk::astro::trajectory::state::CoordinatesBroker; +using ostk::astro::trajectory::state::CoordinatesSubset; +using ostk::astro::trajectory::state::coordinatessubsets::CartesianPosition; +using ostk::astro::trajectory::state::coordinatessubsets::CartesianVelocity; + +class OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder : public ::testing::Test +{ + protected: + const Array> posVelSubsets = { + CartesianPosition::Default(), CartesianVelocity::Default() + }; + + const Array> posVelMassSubsets = { + CartesianPosition::Default(), + CartesianVelocity::Default(), + CoordinatesSubset::Mass(), + }; + + const Shared posVelBrokerSPtr = + std::make_shared(CoordinatesBroker(posVelSubsets)); + + const Shared posVelMassBrokerSPtr = + std::make_shared(CoordinatesBroker(posVelMassSubsets)); +}; + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, Constructor) +{ + { + EXPECT_NO_THROW(StateBuilder builder(Frame::GCRF(), posVelBrokerSPtr)); + } + + { + EXPECT_NO_THROW(StateBuilder builder(Frame::GCRF(), posVelSubsets);); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, EqualToOperator) +{ + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelSubsets}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::ITRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelMassBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Shared posVelBrokerSPtr2 = std::make_shared( + CoordinatesBroker({CartesianPosition::Default(), CartesianVelocity::Default()}) + ); + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr2}; + + EXPECT_TRUE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Shared velPosBrokerSPtr = std::make_shared( + CoordinatesBroker({CartesianVelocity::Default(), CartesianPosition::Default()}) + ); + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), velPosBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(stateBuilder == stateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder == anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(StateBuilder::Undefined() == aStateBuilder); + EXPECT_FALSE(aStateBuilder == StateBuilder::Undefined()); + EXPECT_FALSE(StateBuilder::Undefined() == StateBuilder::Undefined()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, NotEqualToOperator) +{ + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelSubsets}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::ITRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelMassBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Shared posVelBrokerSPtr2 = std::make_shared( + CoordinatesBroker({CartesianPosition::Default(), CartesianVelocity::Default()}) + ); + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr2}; + + EXPECT_FALSE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Shared velPosBrokerSPtr = std::make_shared( + CoordinatesBroker({CartesianVelocity::Default(), CartesianPosition::Default()}) + ); + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), velPosBrokerSPtr}; + + EXPECT_TRUE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(stateBuilder != stateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const StateBuilder anotherStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_FALSE(aStateBuilder != anotherStateBuilder); + } + + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_TRUE(StateBuilder::Undefined() != aStateBuilder); + EXPECT_TRUE(aStateBuilder != StateBuilder::Undefined()); + EXPECT_TRUE(StateBuilder::Undefined() != StateBuilder::Undefined()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, StreamOperator) +{ + { + const StateBuilder aStateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + testing::internal::CaptureStdout(); + + EXPECT_NO_THROW(std::cout << aStateBuilder << std::endl); + + EXPECT_FALSE(testing::internal::GetCapturedStdout().empty()); + } + + { + testing::internal::CaptureStdout(); + + EXPECT_NO_THROW(std::cout << StateBuilder::Undefined() << std::endl); + + EXPECT_FALSE(testing::internal::GetCapturedStdout().empty()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, BuildState) +{ + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Instant instant = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates(6); + coordinates << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0; + + const State state = stateBuilder.buildState(instant, coordinates); + + EXPECT_EQ(instant, state.accessInstant()); + EXPECT_EQ(coordinates, state.accessCoordinates()); + EXPECT_EQ(Frame::GCRF(), state.accessFrame()); + EXPECT_EQ(posVelBrokerSPtr, state.accessCoordinatesBroker()); + + EXPECT_EQ(stateBuilder.accessFrame(), state.accessFrame()); + EXPECT_EQ(stateBuilder.accessCoordinatesBroker(), state.accessCoordinatesBroker()); + } + + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Instant instant1 = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates1(6); + coordinates1 << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0; + + const State state1 = stateBuilder.buildState(instant1, coordinates1); + + const Instant instant2 = Instant::DateTime(DateTime(2019, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates2(6); + coordinates2 << 2.0, 3.0, 4.0, 5.0, 6.0, 7.0; + + const State state2 = stateBuilder.buildState(instant2, coordinates2); + + EXPECT_NE(state1.accessInstant(), state2.accessInstant()); + EXPECT_NE(state1.accessCoordinates(), state2.accessCoordinates()); + + EXPECT_EQ(state1.accessFrame(), state2.accessFrame()); + EXPECT_EQ(state1.accessCoordinatesBroker(), state2.accessCoordinatesBroker()); + } + + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + const Instant instant = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates(3); + coordinates << 1.0, 2.0, 3.0; + + EXPECT_ANY_THROW(stateBuilder.buildState(instant, coordinates)); + } + + { + const Instant instant = Instant::DateTime(DateTime(2018, 1, 1, 0, 0, 0), Scale::UTC); + VectorXd coordinates(6); + coordinates << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0; + + EXPECT_ANY_THROW(StateBuilder::Undefined().buildState(instant, coordinates)); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, Accessors) +{ + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelBrokerSPtr}; + + EXPECT_EQ(Frame::GCRF(), stateBuilder.accessFrame()); + EXPECT_EQ(posVelBrokerSPtr, stateBuilder.accessCoordinatesBroker()); + } + + { + const StateBuilder stateBuilder = {Frame::GCRF(), posVelSubsets}; + + EXPECT_EQ(Frame::GCRF(), stateBuilder.accessFrame()); + EXPECT_EQ(posVelSubsets, stateBuilder.accessCoordinatesBroker()->getSubsets()); + } + + { + EXPECT_ANY_THROW(StateBuilder::Undefined().accessFrame()); + EXPECT_ANY_THROW(StateBuilder::Undefined().accessCoordinatesBroker()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, Getters) +{ + { + const StateBuilder stateBuilder = StateBuilder(Frame::GCRF(), posVelBrokerSPtr); + + EXPECT_EQ(stateBuilder.getCoordinatesSubsets(), posVelBrokerSPtr->getSubsets()); + EXPECT_EQ(Frame::GCRF(), stateBuilder.getFrame()); + } + + { + EXPECT_ANY_THROW(StateBuilder::Undefined().getCoordinatesSubsets()); + EXPECT_ANY_THROW(StateBuilder::Undefined().getFrame()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, IsDefined) +{ + { + const StateBuilder stateBuilder = StateBuilder(Frame::GCRF(), posVelBrokerSPtr); + + EXPECT_TRUE(stateBuilder.isDefined()); + } + + { + const StateBuilder stateBuilder = StateBuilder(nullptr, posVelBrokerSPtr); + + EXPECT_FALSE(stateBuilder.isDefined()); + } + + { + const StateBuilder stateBuilder = StateBuilder(Frame::Undefined(), posVelBrokerSPtr); + + EXPECT_FALSE(stateBuilder.isDefined()); + } + + { + const StateBuilder stateBuilder = StateBuilder(Frame::GCRF(), nullptr); + + EXPECT_FALSE(stateBuilder.isDefined()); + } + + { + EXPECT_FALSE(StateBuilder::Undefined().isDefined()); + } +} + +TEST_F(OpenSpaceToolkit_Astrodynamics_Trajectory_StateBuilder, Undefined) +{ + { + EXPECT_NO_THROW(StateBuilder::Undefined()); + } +}