Skip to content

Commit 44284f3

Browse files
authored
Merge pull request #4619 from pleroy/4608
Add support for specifying the burn in spherical coordinates to the C++ code
2 parents 618d51e + dcae119 commit 44284f3

23 files changed

Lines changed: 539 additions & 149 deletions

geometry/permutation.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class Permutation : public LinearMap<Permutation<FromFrame, ToFrame>,
6969

7070
Sign Determinant() const;
7171

72+
// Only use for interchange.
73+
CoordinatePermutation coordinate_permutation() const;
74+
7275
Permutation<ToFrame, FromFrame> Inverse() const;
7376

7477
template<typename Scalar>

geometry/permutation_body.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@ Permutation<FromFrame, ToFrame>::Permutation(
2929
: coordinate_permutation_(coordinate_permutation) {}
3030

3131
template<typename FromFrame, typename ToFrame>
32-
inline Sign Permutation<FromFrame, ToFrame>::Determinant() const {
32+
Sign Permutation<FromFrame, ToFrame>::Determinant() const {
3333
return Sign::OfNonZero(static_cast<int>(coordinate_permutation_));
3434
}
3535

36+
template<typename FromFrame, typename ToFrame>
37+
typename Permutation<FromFrame, ToFrame>::CoordinatePermutation
38+
Permutation<FromFrame, ToFrame>::coordinate_permutation() const {
39+
return coordinate_permutation_;
40+
}
41+
3642
template<typename FromFrame, typename ToFrame>
3743
Permutation<ToFrame, FromFrame>
3844
Permutation<FromFrame, ToFrame>::Inverse() const {

geometry/r3_element.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ struct SphericalCoordinates final {
9999

100100
// Uses the x-y plane as the equator, the x-axis as the reference direction on
101101
// the equator, and the z-axis as the north pole.
102-
R3Element<Scalar> ToCartesian();
102+
R3Element<Scalar> ToCartesian() const;
103+
104+
void WriteToMessage(
105+
not_null<serialization::SphericalCoordinates*> message) const;
106+
static SphericalCoordinates ReadFromMessage(
107+
serialization::SphericalCoordinates const& message);
103108

104109
Scalar radius;
105110
Angle latitude;

geometry/r3_element_body.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,32 @@ R3Element<Scalar> R3Element<Scalar>::ReadFromMessage(
210210
}
211211

212212
template<typename Scalar>
213-
R3Element<Scalar> SphericalCoordinates<Scalar>::ToCartesian() {
213+
R3Element<Scalar> SphericalCoordinates<Scalar>::ToCartesian() const {
214214
auto const [sin_latitude, cos_latitude] = SinCos(latitude);
215215
auto const [sin_longitude, cos_longitude] = SinCos(longitude);
216216
return {radius * cos_longitude * cos_latitude,
217217
radius * sin_longitude * cos_latitude,
218218
radius * sin_latitude};
219219
}
220220

221+
template<typename Scalar>
222+
void SphericalCoordinates<Scalar>::WriteToMessage(
223+
not_null<serialization::SphericalCoordinates*> const message) const {
224+
radius.WriteToMessage(message->mutable_radius());
225+
latitude.WriteToMessage(message->mutable_latitude());
226+
longitude.WriteToMessage(message->mutable_longitude());
227+
}
228+
229+
template<typename Scalar>
230+
SphericalCoordinates<Scalar> SphericalCoordinates<Scalar>::ReadFromMessage(
231+
serialization::SphericalCoordinates const& message) {
232+
SphericalCoordinates<Scalar> result;
233+
result.radius = Scalar::ReadFromMessage(message.radius());
234+
result.latitude = Angle::ReadFromMessage(message.latitude());
235+
result.longitude = Angle::ReadFromMessage(message.longitude());
236+
return result;
237+
}
238+
221239
template<typename Scalar>
222240
SphericalCoordinates<Scalar> RadiusLatitudeLongitude(Scalar const& radius,
223241
Angle const& latitude,

journal/profiles.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ using interface::ConfigurationAdaptiveStepParameters;
3333
using interface::ConfigurationDownsamplingParameters;
3434
using interface::ConfigurationFixedStepParameters;
3535
using interface::CoordinateSystem;
36-
using interface::DeltaV;
3736
using interface::EquatorialCrossings;
3837
using interface::FlightPlanAdaptiveStepParameters;
38+
using interface::Intensity;
3939
using interface::Interval;
4040
using interface::Iterator;
4141
using interface::KeplerianElements;

ksp_plugin/flight_plan_optimizer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ NavigationManœuvre::Burn FlightPlanOptimizer::UpdatedBurn(
784784
NavigationManœuvre const& manœuvre) {
785785
auto const argument = Dehomogeneize(homogeneous_argument);
786786
NavigationManœuvre::Burn burn = manœuvre.burn();
787-
burn.intensity = {.Δv = manœuvre.Δv() + argument.ΔΔv};
787+
burn.intensity.set_Δv(burn.intensity.Δv() + argument.ΔΔv);
788788
burn.timing = {.initial_time =
789789
manœuvre.initial_time() + argument.Δinitial_time};
790790
return burn;

ksp_plugin/interface.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ std::unique_ptr<T[]> TakeOwnershipArray(T** pointer);
8787
bool operator==(AdaptiveStepParameters const& left,
8888
AdaptiveStepParameters const& right);
8989
bool operator==(Burn const& left, Burn const& right);
90-
bool operator==(DeltaV const& left, DeltaV const& right);
9190
bool operator==(EquatorialCrossings const& left,
9291
EquatorialCrossings const& right);
9392
bool operator==(FlightPlanAdaptiveStepParameters const& left,
9493
FlightPlanAdaptiveStepParameters const& right);
94+
bool operator==(Intensity const& left, Intensity const& right);
9595
bool operator==(Interval const& left, Interval const& right);
9696
bool operator==(NavigationFrameParameters const& left,
9797
NavigationFrameParameters const& right);
@@ -165,6 +165,8 @@ FlightPlanAdaptiveStepParameters ToFlightPlanAdaptiveStepParameters(
165165
Barycentric>::GeneralizedAdaptiveStepParameters const&
166166
generalized_adaptive_step_parameters);
167167

168+
Intensity ToIntensity(NavigationManœuvre::Intensity const& intensity);
169+
168170
KeplerianElements ToKeplerianElements(
169171
physics::_kepler_orbit::KeplerianElements<Barycentric> const&
170172
keplerian_elements);
@@ -178,11 +180,17 @@ QP ToQP(RelativeDegreesOfFreedom<AliceSun> const& relative_dof);
178180
// Ownership of the status and its message is transferred to the caller.
179181
Status* ToNewStatus(absl::Status const& status);
180182

183+
// Ownership of the object is transferred to the caller.
184+
SphericalCoordinates* ToNewSphericalCoordinates(
185+
geometry::_r3_element::SphericalCoordinates<Speed> const&
186+
spherical_coordinates);
187+
181188
WXYZ ToWXYZ(Quaternion const& quaternion);
182189

183190
XY ToXY(RP2Point<Length, Camera> const& rp2_point);
184191

185192
XYZ ToXYZ(R3Element<double> const& r3_element);
193+
XYZ ToXYZ(R3Element<Speed> const& r3_element);
186194
XYZ ToXYZ(Position<World> const& position);
187195
XYZ ToXYZ(Vector<double, World> const& direction);
188196
XYZ ToXYZ(Velocity<Frenet<NavigationFrame>> const& velocity);

ksp_plugin/interface_body.hpp

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "absl/strings/str_split.h"
1414
#include "base/array.hpp"
1515
#include "geometry/orthogonal_map.hpp"
16+
#include "geometry/permutation.hpp"
1617
#include "geometry/r3x3_matrix.hpp"
1718
#include "geometry/rotation.hpp"
1819
#include "geometry/sign.hpp"
@@ -33,6 +34,7 @@ namespace interface {
3334

3435
using namespace principia::base::_array;
3536
using namespace principia::geometry::_orthogonal_map;
37+
using namespace principia::geometry::_permutation;
3638
using namespace principia::geometry::_r3x3_matrix;
3739
using namespace principia::geometry::_rotation;
3840
using namespace principia::geometry::_sign;
@@ -168,6 +170,16 @@ struct XYZConverter<R3Element<MomentOfInertia>> {
168170
}
169171
};
170172

173+
template<>
174+
struct XYZConverter<R3Element<Speed>> {
175+
static constexpr Speed mts_unit = Metre / Second;
176+
static R3Element<Speed> FromXYZ(XYZ const& xyz) {
177+
return R3Element<Speed>(xyz.x * (Metre / Second),
178+
xyz.y * (Metre / Second),
179+
xyz.z * (Metre / Second));
180+
}
181+
};
182+
171183
inline bool NaNIndependentEq(double const left, double const right) {
172184
return (left == right) || (std::isnan(left) && std::isnan(right));
173185
}
@@ -205,16 +217,7 @@ inline bool operator==(Burn const& left, Burn const& right) {
205217
right.specific_impulse_in_seconds_g0) &&
206218
left.frame == right.frame &&
207219
NaNIndependentEq(left.initial_time, right.initial_time) &&
208-
left.delta_v == right.delta_v;
209-
}
210-
211-
inline bool operator==(DeltaV const& left, DeltaV const& right) {
212-
return left.coordinate_system == right.coordinate_system &&
213-
((left.spherical_coordinates != nullptr &&
214-
right.spherical_coordinates != nullptr &&
215-
*left.spherical_coordinates == *right.spherical_coordinates) ||
216-
(left.xyz != nullptr && right.xyz != nullptr &&
217-
*left.xyz == *right.xyz));
220+
left.intensity == right.intensity;
218221
}
219222

220223
inline bool operator==(FlightPlanAdaptiveStepParameters const& left,
@@ -229,6 +232,15 @@ inline bool operator==(FlightPlanAdaptiveStepParameters const& left,
229232
right.speed_integration_tolerance);
230233
}
231234

235+
inline bool operator==(Intensity const& left, Intensity const& right) {
236+
return left.coordinate_system == right.coordinate_system &&
237+
((left.spherical_coordinates != nullptr &&
238+
right.spherical_coordinates != nullptr &&
239+
*left.spherical_coordinates == *right.spherical_coordinates) ||
240+
(left.xyz != nullptr && right.xyz != nullptr &&
241+
*left.xyz == *right.xyz));
242+
}
243+
232244
inline bool operator==(Interval const& left, Interval const& right) {
233245
return NaNIndependentEq(left.min, right.min) &&
234246
NaNIndependentEq(left.max, right.max);
@@ -522,6 +534,12 @@ inline FromXYZ<R3Element<MomentOfInertia>>(XYZ const& xyz) {
522534
return XYZConverter<R3Element<MomentOfInertia>>::FromXYZ(xyz);
523535
}
524536

537+
template<>
538+
R3Element<Speed>
539+
inline FromXYZ<R3Element<Speed>>(XYZ const& xyz) {
540+
return XYZConverter<R3Element<Speed>>::FromXYZ(xyz);
541+
}
542+
525543
inline AdaptiveStepParameters ToAdaptiveStepParameters(
526544
physics::_ephemeris::Ephemeris<Barycentric>::AdaptiveStepParameters const&
527545
adaptive_step_parameters) {
@@ -557,6 +575,33 @@ inline FlightPlanAdaptiveStepParameters ToFlightPlanAdaptiveStepParameters(
557575
(Metre / Second)};
558576
}
559577

578+
inline Intensity ToIntensity(NavigationManœuvre::Intensity const& intensity) {
579+
if (intensity.has_spherical_coordinates()) {
580+
switch (intensity.permutation().coordinate_permutation()) {
581+
case EvenPermutation::XYZ:
582+
return {.coordinate_system = CoordinateSystem::SPHERICAL_TNB,
583+
.xyz = nullptr,
584+
.spherical_coordinates = ToNewSphericalCoordinates(
585+
intensity.Δv_spherical_coordinates())};
586+
case EvenPermutation::YZX:
587+
return {.coordinate_system = CoordinateSystem::SPHERICAL_NBT,
588+
.xyz = nullptr,
589+
.spherical_coordinates = ToNewSphericalCoordinates(
590+
intensity.Δv_spherical_coordinates())};
591+
case EvenPermutation::ZXY:
592+
return {.coordinate_system = CoordinateSystem::SPHERICAL_BTN,
593+
.xyz = nullptr,
594+
.spherical_coordinates = ToNewSphericalCoordinates(
595+
intensity.Δv_spherical_coordinates())};
596+
}
597+
LOG(FATAL) << "Unexpected permutation: " << intensity.permutation();
598+
} else {
599+
return {.coordinate_system = CoordinateSystem::CARTESIAN_TNB,
600+
.xyz = new XYZ(ToXYZ(intensity.Δv_cartesian_coordinates())),
601+
.spherical_coordinates = nullptr};
602+
}
603+
}
604+
560605
inline KeplerianElements ToKeplerianElements(
561606
physics::_kepler_orbit::KeplerianElements<Barycentric> const&
562607
keplerian_elements) {
@@ -636,6 +681,15 @@ inline Status* ToNewStatus(absl::Status const& status) {
636681
}
637682
}
638683

684+
inline SphericalCoordinates* ToNewSphericalCoordinates(
685+
geometry::_r3_element::SphericalCoordinates<Speed> const&
686+
spherical_coordinates) {
687+
return new SphericalCoordinates{
688+
.radius = spherical_coordinates.radius / (Metre / Second),
689+
.latitude_in_degrees = spherical_coordinates.latitude / Degree,
690+
.longitude_in_degrees = spherical_coordinates.longitude / Degree};
691+
}
692+
639693
inline WXYZ ToWXYZ(Quaternion const& quaternion) {
640694
return {.w = quaternion.real_part(),
641695
.x = quaternion.imaginary_part().x,
@@ -651,6 +705,12 @@ inline XYZ ToXYZ(R3Element<double> const& r3_element) {
651705
return {.x = r3_element.x, .y = r3_element.y, .z = r3_element.z};
652706
}
653707

708+
inline XYZ ToXYZ(R3Element<Speed> const& r3_element) {
709+
return {.x = r3_element.x / (Metre / Second),
710+
.y = r3_element.y / (Metre / Second),
711+
.z = r3_element.z / (Metre / Second)};
712+
}
713+
654714
inline XYZ ToXYZ(Position<World> const& position) {
655715
return XYZConverter<Position<World>>::ToXYZ(position);
656716
}

ksp_plugin/interface_flight_plan.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "base/not_null.hpp"
1010
#include "geometry/grassmann.hpp"
1111
#include "geometry/orthogonal_map.hpp"
12+
#include "geometry/permutation.hpp"
13+
#include "geometry/r3_element.hpp"
1214
#include "journal/method.hpp"
1315
#include "journal/profiles.hpp" // 🧙 For generated profiles.
1416
#include "ksp_plugin/flight_plan.hpp"
@@ -34,6 +36,8 @@ namespace interface {
3436
using namespace principia::base::_not_null;
3537
using namespace principia::geometry::_grassmann;
3638
using namespace principia::geometry::_orthogonal_map;
39+
using namespace principia::geometry::_permutation;
40+
using namespace principia::geometry::_r3_element;
3741
using namespace principia::journal::_method;
3842
using namespace principia::ksp_plugin::_flight_plan;
3943
using namespace principia::ksp_plugin::_flight_plan_optimization_driver;
@@ -56,11 +60,43 @@ namespace {
5660

5761
NavigationManœuvre::Burn FromInterfaceBurn(Plugin const& plugin,
5862
Burn const& burn) {
59-
NavigationManœuvre::Intensity intensity;
60-
intensity.Δv = FromXYZ<Velocity<Frenet<NavigationFrame>>>(burn.delta_v);
63+
std::optional<NavigationManœuvre::Intensity> navigation_manœuvre_intensity;
64+
auto const& intensity = burn.intensity;
65+
switch (intensity.coordinate_system) {
66+
case CoordinateSystem::CARTESIAN_TNB: {
67+
navigation_manœuvre_intensity = NavigationManœuvre::Intensity(
68+
FromXYZ<R3Element<Speed>>(*intensity.xyz));
69+
break;
70+
}
71+
case CoordinateSystem::SPHERICAL_TNB:
72+
case CoordinateSystem::SPHERICAL_NBT:
73+
case CoordinateSystem::SPHERICAL_BTN: {
74+
EvenPermutation coordinate_permutation;
75+
switch (intensity.coordinate_system) {
76+
case CoordinateSystem::SPHERICAL_TNB:
77+
coordinate_permutation = EvenPermutation::XYZ;
78+
break;
79+
case CoordinateSystem::SPHERICAL_BTN:
80+
coordinate_permutation = EvenPermutation::YZX;
81+
break;
82+
case CoordinateSystem::SPHERICAL_NBT:
83+
coordinate_permutation = EvenPermutation::ZXY;
84+
break;
85+
}
86+
auto const& spherical_coordinates = *intensity.spherical_coordinates;
87+
navigation_manœuvre_intensity = NavigationManœuvre::Intensity(
88+
Permutation<PermutedFrenet<Navigation>, Frenet<Navigation>>(
89+
coordinate_permutation),
90+
RadiusLatitudeLongitude<Speed>(
91+
spherical_coordinates.radius * (Metre / Second),
92+
spherical_coordinates.latitude_in_degrees * Degree,
93+
spherical_coordinates.longitude_in_degrees * Degree));
94+
break;
95+
}
96+
}
6197
NavigationManœuvre::Timing timing;
6298
timing.initial_time = FromGameTime(plugin, burn.initial_time);
63-
return {.intensity = intensity,
99+
return {.intensity = *navigation_manœuvre_intensity,
64100
.timing = timing,
65101
.thrust = burn.thrust_in_kilonewtons * Kilo(Newton),
66102
.specific_impulse =
@@ -149,7 +185,7 @@ Burn GetBurn(Plugin const& plugin,
149185
manœuvre.specific_impulse() / (Second * StandardGravity),
150186
.frame = parameters,
151187
.initial_time = ToGameTime(plugin, manœuvre.initial_time()),
152-
.delta_v = ToXYZ(manœuvre.Δv()),
188+
.intensity = ToIntensity(manœuvre.intensity()),
153189
.is_inertially_fixed = manœuvre.is_inertially_fixed()};
154190
}
155191

0 commit comments

Comments
 (0)