Skip to content

Commit

Permalink
Merge pull request #3400 from eggrobin/leitfaden
Browse files Browse the repository at this point in the history
Multiple flight plans
  • Loading branch information
eggrobin authored Jul 24, 2022
2 parents 83ae98c + f8b1d0f commit 38d1a0c
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 59 deletions.
31 changes: 31 additions & 0 deletions ksp_plugin/interface_flight_plan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ Status* __cdecl principia__FlightPlanInsert(Plugin const* const plugin,
.Insert(FromInterfaceBurn(*plugin, burn), index)));
}

int __cdecl principia__FlightPlanCount(Plugin const* const plugin,
char const* const vessel_guid) {
journal::Method<journal::FlightPlanCount> m({plugin, vessel_guid});
CHECK_NOTNULL(plugin);
return m.Return(plugin->GetVessel(vessel_guid)->flight_plan_count());
}

void __cdecl principia__FlightPlanCreate(Plugin const* const plugin,
char const* const vessel_guid,
double const final_time,
Expand All @@ -206,6 +213,14 @@ void __cdecl principia__FlightPlanDelete(Plugin const* const plugin,
return m.Return();
}

void __cdecl principia__FlightPlanDuplicate(Plugin const* const plugin,
char const* const vessel_guid) {
journal::Method<journal::FlightPlanDuplicate> m({plugin, vessel_guid});
CHECK_NOTNULL(plugin);
plugin->GetVessel(vessel_guid)->DuplicateFlightPlan();
return m.Return();
}

bool __cdecl principia__FlightPlanExists(
Plugin const* const plugin,
char const* const vessel_guid) {
Expand Down Expand Up @@ -524,6 +539,22 @@ Status* __cdecl principia__FlightPlanReplace(Plugin const* const plugin,
.Replace(FromInterfaceBurn(*plugin, burn), index)));
}

void __cdecl principia__FlightPlanSelect(Plugin const* const plugin,
char const* const vessel_guid,
int const index) {
journal::Method<journal::FlightPlanSelect> m({plugin, vessel_guid, index});
CHECK_NOTNULL(plugin);
plugin->GetVessel(vessel_guid)->SelectFlightPlan(index);
return m.Return();
}

int __cdecl principia__FlightPlanSelected(Plugin const* const plugin,
char const* const vessel_guid) {
journal::Method<journal::FlightPlanSelected> m({plugin, vessel_guid});
CHECK_NOTNULL(plugin);
return m.Return(plugin->GetVessel(vessel_guid)->selected_flight_plan_index());
}

Status* __cdecl principia__FlightPlanSetAdaptiveStepParameters(
Plugin const* const plugin,
char const* const vessel_guid,
Expand Down
118 changes: 91 additions & 27 deletions ksp_plugin/vessel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,20 +334,37 @@ Vessel::prediction_adaptive_step_parameters() const {
}

bool Vessel::has_flight_plan() const {
return has_deserialized_flight_plan() ||
std::holds_alternative<serialization::FlightPlan>(flight_plan_);
return !flight_plans_.empty();
}

int Vessel::flight_plan_count() const {
return flight_plans_.size();
}

int Vessel::selected_flight_plan_index() const {
return selected_flight_plan_index_;
}

void Vessel::SelectFlightPlan(int index) {
CHECK_GE(index, 0);
CHECK_LT(index, flight_plan_count());
selected_flight_plan_index_ = index;
}

FlightPlan& Vessel::flight_plan() const {
CHECK(has_deserialized_flight_plan());
auto& flight_plan = *std::get<std::unique_ptr<FlightPlan>>(flight_plan_);
auto& flight_plan =
*std::get<not_null<std::unique_ptr<FlightPlan>>>(selected_flight_plan());
return flight_plan;
}

void Vessel::ReadFlightPlanFromMessage() {
if (std::holds_alternative<serialization::FlightPlan>(flight_plan_)) {
auto const& message = std::get<serialization::FlightPlan>(flight_plan_);
flight_plan_ = FlightPlan::ReadFromMessage(message, ephemeris_);
if (!flight_plans_.empty() &&
std::holds_alternative<serialization::FlightPlan>(
selected_flight_plan())) {
auto const& message =
std::get<serialization::FlightPlan>(selected_flight_plan());
selected_flight_plan() = FlightPlan::ReadFromMessage(message, ephemeris_);
}
}

Expand Down Expand Up @@ -449,24 +466,51 @@ void Vessel::CreateFlightPlan(
Ephemeris<Barycentric>::GeneralizedAdaptiveStepParameters const&
flight_plan_generalized_adaptive_step_parameters) {
auto const flight_plan_start = backstory_->back();
flight_plan_ = std::make_unique<FlightPlan>(
flight_plans_.emplace_back(make_not_null_unique<FlightPlan>(
initial_mass,
/*initial_time=*/flight_plan_start.time,
/*initial_degrees_of_freedom=*/flight_plan_start.degrees_of_freedom,
final_time,
ephemeris_,
flight_plan_adaptive_step_parameters,
flight_plan_generalized_adaptive_step_parameters);
flight_plan_generalized_adaptive_step_parameters));
selected_flight_plan_index_ = flight_plans_.size() - 1;
}

void Vessel::DuplicateFlightPlan() {
auto const& original = selected_flight_plan();
auto const it = flight_plans_.begin() + selected_flight_plan_index_;
// There is no need to adjust either flight plan after the copy; in particular
// flight plans currently do not have a name, so there is no need to append a
// (Copy).
// If we needed to adjust something, it would probably be the original, to
// mimic the behaviour of adding a copy after the current tab and switching to
// that copy, even though behind the scenes we are inserting a copy before for
// the sake of laziness.
if (std::holds_alternative<serialization::FlightPlan>(original)) {
flight_plans_.emplace(it, std::get<serialization::FlightPlan>(original));
} else if (std::holds_alternative<not_null<std::unique_ptr<FlightPlan>>>(
original)) {
std::get<not_null<std::unique_ptr<FlightPlan>>>(original)->WriteToMessage(
&std::get<serialization::FlightPlan>(*flight_plans_.emplace(
it, std::in_place_type<serialization::FlightPlan>)));
} else {
LOG(FATAL) << "Unexpected flight plan variant " << original.index();
}
++selected_flight_plan_index_;
}

void Vessel::DeleteFlightPlan() {
flight_plan_.emplace<std::unique_ptr<FlightPlan>>();
flight_plans_.erase(flight_plans_.begin() + selected_flight_plan_index_);
if (selected_flight_plan_index_ == flight_plans_.size()) {
--selected_flight_plan_index_;
}
}

absl::Status Vessel::RebaseFlightPlan(Mass const& initial_mass) {
CHECK(has_deserialized_flight_plan());
auto& flight_plan =
std::get<std::unique_ptr<FlightPlan>>(flight_plan_);
std::get<not_null<std::unique_ptr<FlightPlan>>>(selected_flight_plan());
Instant const new_initial_time = backstory_->back().time;
int first_manœuvre_kept = 0;
for (int i = 0; i < flight_plan->number_of_manœuvres(); ++i) {
Expand Down Expand Up @@ -628,18 +672,20 @@ void Vessel::WriteToMessage(not_null<serialization::Vessel*> const message,
/*end=*/std::next(prediction_->begin()),
/*tracked=*/{backstory_, psychohistory_, prediction_},
/*exact=*/{});
if (std::holds_alternative<serialization::FlightPlan>(flight_plan_)) {
*message->mutable_flight_plan() =
std::get<serialization::FlightPlan>(flight_plan_);
} else if (std::holds_alternative<std::unique_ptr<FlightPlan>>(
flight_plan_)) {
auto& flight_plan = std::get<std::unique_ptr<FlightPlan>>(flight_plan_);
if (flight_plan != nullptr) {
flight_plan->WriteToMessage(message->mutable_flight_plan());
for (auto const& flight_plan : flight_plans_) {
if (std::holds_alternative<serialization::FlightPlan>(flight_plan)) {
*message->add_flight_plans() =
std::get<serialization::FlightPlan>(flight_plan);
} else if (std::holds_alternative<not_null<std::unique_ptr<FlightPlan>>>(
flight_plan)) {
auto& deserialized_flight_plan =
std::get<not_null<std::unique_ptr<FlightPlan>>>(flight_plan);
deserialized_flight_plan->WriteToMessage(message->add_flight_plans());
} else {
LOG(FATAL) << "Unexpected flight plan variant " << flight_plan.index();
}
} else {
LOG(FATAL) << "Unexpected flight plan variant " << flight_plan_.index();
}
message->set_selected_flight_plan_index(selected_flight_plan_index_);
message->set_is_collapsible(is_collapsible_);
checkpointer_->WriteToMessage(message->mutable_checkpoint());
LOG(INFO) << name_ << " " << NAMED(message->SpaceUsed()) << " "
Expand All @@ -657,13 +703,15 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
message.history().segment_size() == 0;
bool const is_pre_hamilton = message.history().segment_size() == 0;
bool const is_pre_हरीश_चंद्र = !message.has_is_collapsible();
LOG_IF(WARNING, is_pre_हरीश_चंद्र)
bool const is_pre_hilbert = !message.has_selected_flight_plan_index();
LOG_IF(WARNING, is_pre_hilbert)
<< "Reading pre-"
<< (is_pre_cesàro ? u8"Cesàro"
: is_pre_chasles ? "Chasles"
: is_pre_陈景润 ? u8"陈景润"
: is_pre_hamilton ? "Hamilton"
: u8"हरीश चंद्र") << " Vessel";
: is_pre_हरीश_चंद्र ? u8"हरीश चंद्र"
: "Hilbert") << " Vessel";

// NOTE(egg): for now we do not read the |MasslessBody| as it can contain no
// information.
Expand Down Expand Up @@ -769,11 +817,13 @@ not_null<std::unique_ptr<Vessel>> Vessel::ReadFromMessage(
DefaultDownsamplingParameters());
}

if (message.has_flight_plan()) {
for (const auto& flight_plan : message.flight_plans()) {
// Starting with हरीश चंद्र we deserialize the flight plan lazily.
vessel->flight_plan_
.emplace<serialization::FlightPlan>(message.flight_plan());
vessel->flight_plans_.emplace_back(flight_plan);
}
vessel->selected_flight_plan_index_ =
is_pre_hilbert ? static_cast<int>(vessel->flight_plans_.size()) - 1
: message.selected_flight_plan_index();

// Figure out which was the last checkpoint to be "reanimated" by reading the
// end of the trajectory from the serialized form. Interestingly enough, that
Expand Down Expand Up @@ -1126,8 +1176,22 @@ bool Vessel::IsCollapsible() const {
}

bool Vessel::has_deserialized_flight_plan() const {
return std::holds_alternative<std::unique_ptr<FlightPlan>>(flight_plan_) &&
std::get<std::unique_ptr<FlightPlan>>(flight_plan_) != nullptr;
return !flight_plans_.empty() &&
std::holds_alternative<not_null<std::unique_ptr<FlightPlan>>>(
selected_flight_plan());
}

Vessel::LazilyDeserializedFlightPlan& Vessel::selected_flight_plan() {
CHECK_GE(selected_flight_plan_index_, 0);
CHECK_LT(selected_flight_plan_index_, flight_plans_.size());
return flight_plans_[selected_flight_plan_index_];
}

Vessel::LazilyDeserializedFlightPlan const&
Vessel::selected_flight_plan() const {
CHECK_GE(selected_flight_plan_index_, 0);
CHECK_LT(selected_flight_plan_index_, flight_plans_.size());
return flight_plans_[selected_flight_plan_index_];
}

// Run the prognostication in both synchronous and asynchronous mode in tests to
Expand Down
32 changes: 30 additions & 2 deletions ksp_plugin/vessel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ class Vessel {
// fails.
virtual bool has_flight_plan() const;

// Returns the number of flight plans for this vessel. Never fails.
virtual int flight_plan_count() const;

// Returns the index of the currently-selected flight plan, or -1 if there is
// no flight plan.
virtual int selected_flight_plan_index() const;

// Selects the flight plan at the given index, which must lie within
// [0, flight_plan_count()[.
virtual void SelectFlightPlan(int index);

// If the flight plan has been deserialized, returns it. Fails if there is no
// flight plan or the flight plan has not been deserialized.
virtual FlightPlan& flight_plan() const;
Expand Down Expand Up @@ -185,6 +196,15 @@ class Vessel {
Ephemeris<Barycentric>::GeneralizedAdaptiveStepParameters const&
flight_plan_generalized_adaptive_step_parameters);

// Requires |has_flight_plan()|.
// Inserts a flight plan equivalent to the current one immediately before it.
// The current flight plan remains selected.
// Note that conceptually, this is equivalent to inserting an equivalent
// flight plan immediately after the current one and switching to it, but
// insertion before is lazier, as the newly added flight plan can remain
// serialized.
virtual void DuplicateFlightPlan();

// Deletes the |flight_plan_|. Performs no action unless |has_flight_plan()|.
virtual void DeleteFlightPlan();

Expand Down Expand Up @@ -266,6 +286,10 @@ class Vessel {
using TrajectoryIterator =
DiscreteTrajectory<Barycentric>::iterator (Part::*)();

using LazilyDeserializedFlightPlan =
std::variant<not_null<std::unique_ptr<FlightPlan>>,
serialization::FlightPlan>;

// Return functions that can be passed to a |Checkpointer| to write this
// vessel to a checkpoint or read it back.
Checkpointer<serialization::Vessel>::Writer
Expand Down Expand Up @@ -314,6 +338,9 @@ class Vessel {
// Returns true if this object holds a non-null deserialized flight plan.
bool has_deserialized_flight_plan() const;

LazilyDeserializedFlightPlan& selected_flight_plan();
LazilyDeserializedFlightPlan const& selected_flight_plan() const;

GUID const guid_;
std::string name_;

Expand Down Expand Up @@ -371,8 +398,9 @@ class Vessel {
RecurringThread<PrognosticatorParameters,
DiscreteTrajectory<Barycentric>> prognosticator_;

std::variant<std::unique_ptr<FlightPlan>,
serialization::FlightPlan> flight_plan_;
std::vector<std::variant<not_null<std::unique_ptr<FlightPlan>>,
serialization::FlightPlan>> flight_plans_;
int selected_flight_plan_index_ = -1;

std::optional<OrbitAnalyser> orbit_analyser_;

Expand Down
Loading

0 comments on commit 38d1a0c

Please sign in to comment.