Improve/fix system map

- add a "static" orbit for bodies that are not moving anywhere
- now bodies in a rotating frame and also in the spaceport frame have
  such "static" orbits
- add display of the orbits of objects moving strictly to the star or
  from the star
- fix compile warning for possibly uninitiated variable in
  LuaSystemView.cpp
- fix an issue where smooth animation sometimes have a hard time
  catching up with a newly selected object

Fixes #5062
master
Gliese852 2021-01-19 23:00:24 +03:00 committed by Webster Sheets
parent 23772169d3
commit 5004b09483
5 changed files with 66 additions and 27 deletions

View File

@ -371,7 +371,12 @@ bool DynamicBody::OnCollision(Body *o, Uint32 flags, double relVel)
// return parameters for orbit of any body, gives both elliptic and hyperbolic trajectories
Orbit DynamicBody::ComputeOrbit() const
{
FrameId nrFrameId = Frame::GetFrame(GetFrame())->GetNonRotFrame();
auto f = Frame::GetFrame(GetFrame());
// if we are in a rotating frame, then dynamic body currently under the
// influence of a rotational frame, therefore getting the orbital parameters
// is not appropriate, return the orbit as a fixed point
if (f->IsRotFrame()) return Orbit::ForStaticBody(GetPosition());
FrameId nrFrameId = f->GetId();
const Frame *nrFrame = Frame::GetFrame(nrFrameId);
const double mass = nrFrame->GetSystemBody()->GetMass();

View File

@ -166,6 +166,7 @@ double Orbit::MeanAnomalyAtTime(double time) const
vector3d Orbit::OrbitalPosAtTime(double t) const
{
if (is_zero_general(m_semiMajorAxis)) return m_positionForStaticBody;
double cos_v, sin_v, r;
calc_position_from_mean_anomaly(MeanAnomalyAtTime(t), m_eccentricity, m_semiMajorAxis, cos_v, sin_v, &r);
return m_orient * vector3d(-cos_v * r, sin_v * r, 0);
@ -298,31 +299,44 @@ void Orbit::SetShapeAroundPrimary(double semiMajorAxis, double centralMass, doub
m_velocityAreaPerSecond = calc_velocity_area_per_sec(semiMajorAxis, centralMass, eccentricity);
}
Orbit Orbit::FromBodyState(const vector3d &pos, const vector3d &vel, double centralMass)
Orbit Orbit::ForStaticBody(const vector3d &position)
{
Orbit ret;
// just remember the current position of the body, and we will return it, for any t
ret.m_positionForStaticBody = position;
return ret;
}
const double r_now = pos.Length() + 1e-12;
const double v_now = vel.Length() + 1e-12;
Orbit Orbit::FromBodyState(const vector3d &pos, const vector3d &vel_raw, double centralMass)
{
Orbit ret;
// standard gravitational parameter
const double u = centralMass * G;
// maybe we will adjust the speed a little now
vector3d vel = vel_raw;
// angular momentum
const vector3d ang = pos.Cross(vel);
vector3d ang = pos.Cross(vel);
// quite a rare case - the speed is directed strictly to the star or away from the star
// let's make a small disturbance to the velocity, so as not to calculate the radial orbit
if (is_zero_general(ang.LengthSqr()) && !is_zero_general(centralMass)) {
if (is_zero_general(pos.x) && is_zero_general(pos.y)) // even rarer case, the body lies strictly on the z-axis
vel.x += 0.001;
else
vel.z += 0.001;
ang = pos.Cross(vel); // recalculate angular momentum
}
const double r_now = pos.Length();
const double LLSqr = ang.LengthSqr();
// total energy
const double EE = vel.LengthSqr() / 2.0 - u / r_now;
if (is_zero_general(centralMass) || is_zero_general(r_now) || is_zero_general(v_now) || is_zero_general(EE) || (ang.z * ang.z / LLSqr > 1.0)) {
ret.m_eccentricity = 0.0;
ret.m_semiMajorAxis = 0.0;
ret.m_velocityAreaPerSecond = 0.0;
ret.m_orbitalPhaseAtStart = 0.0;
ret.m_orient = matrix3x3d::Identity();
return ret;
}
if (is_zero_general(centralMass) || is_zero_general(EE) || (ang.z * ang.z / LLSqr > 1.0))
return Orbit::ForStaticBody(pos);
// http://en.wikipedia.org/wiki/Orbital_eccentricity
ret.m_eccentricity = 1 + 2 * EE * LLSqr / (u * u);

View File

@ -16,6 +16,7 @@ public:
// note: the resulting Orbit is at the given position at t=0
static Orbit FromBodyState(const vector3d &position, const vector3d &velocity, double central_mass);
static Orbit ForStaticBody(const vector3d &position);
Orbit() :
m_eccentricity(0.0),
@ -58,6 +59,7 @@ private:
double MeanAnomalyFromTrueAnomaly(double trueAnomaly) const;
double MeanAnomalyAtTime(double time) const;
vector3d m_positionForStaticBody;
double m_eccentricity;
double m_semiMajorAxis;
double m_orbitalPhaseAtStart; // 0 to 2 pi radians

View File

@ -107,6 +107,7 @@ void SystemView::ResetViewpoint()
m_zoomTo = 1.0f / float(AU);
m_timeStep = 1.0f;
m_time = m_game->GetTime();
m_transTo *= 0.0;
m_animateTransition = MAX_TRANSITION_FRAMES;
}
@ -263,6 +264,11 @@ void SystemView::GetTransformTo(const SystemBody *b, vector3d &pos)
void SystemView::GetTransformTo(Projectable &p, vector3d &pos)
{
if (m_selectedObject.type == Projectable::NONE) {
// notning selected
pos *= 0.0;
return;
}
// accept only real objects (no orbit icons or lagrange points)
assert(p.type == Projectable::OBJECT);
pos = vector3d(0., 0., 0.);
@ -285,16 +291,15 @@ void SystemView::CalculateShipPositionAtTime(const Ship *s, Orbit o, double t, v
pos = vector3d(0., 0., 0.);
FrameId shipFrameId = s->GetFrame();
FrameId shipNonRotFrameId = Frame::GetFrame(shipFrameId)->GetNonRotFrame();
if (s->GetFlightState() != Ship::FlightState::FLYING) {
// if the ship is in a rotating frame, we will rotate it with the frame
if (Frame::GetFrame(shipFrameId)->IsRotFrame()) {
vector3d rpos(0.0);
if (Frame::GetFrame(shipFrameId)->IsRotFrame()) {
Frame *rotframe = Frame::GetFrame(shipFrameId);
if (t == m_game->GetTime()) {
pos = s->GetPositionRelTo(m_game->GetSpace()->GetRootFrame());
return;
} else
rpos = s->GetPositionRelTo(shipNonRotFrameId) * rotframe->GetOrient() * matrix3x3d::RotateY(rotframe->GetAngSpeed() * (t - m_game->GetTime())) * rotframe->GetOrient().Transpose();
}
Frame *rotframe = Frame::GetFrame(shipFrameId);
if (t == m_game->GetTime()) {
pos = s->GetPositionRelTo(m_game->GetSpace()->GetRootFrame());
return;
} else
rpos = s->GetPositionRelTo(shipNonRotFrameId) * rotframe->GetOrient() * matrix3x3d::RotateY(rotframe->GetAngSpeed() * (t - m_game->GetTime())) * rotframe->GetOrient().Transpose();
vector3d fpos(0.0);
CalculateFramePositionAtTime(shipNonRotFrameId, t, fpos);
pos += fpos + rpos;
@ -388,16 +393,21 @@ void SystemView::Draw3D()
m_renderer->SetTransform(m_cameraSpace);
// smooth transition animation
m_transTo *= 0.0;
if (m_selectedObject.type != Projectable::NONE) GetTransformTo(m_selectedObject, m_transTo);
if (m_animateTransition) {
// since the object being approached can move, we need to compensate for its movement
// making an imprint of the old value (from previous frame)
m_trans -= m_transTo;
// calculate the new value
GetTransformTo(m_selectedObject, m_transTo);
// now the difference between the new and the old value is added to m_trans
m_trans += m_transTo;
const float ft = Pi::GetFrameTime();
m_animateTransition--;
AnimationCurves::Approach(m_trans.x, m_transTo.x, ft);
AnimationCurves::Approach(m_trans.y, m_transTo.y, ft);
AnimationCurves::Approach(m_trans.z, m_transTo.z, ft);
} else {
m_trans = m_transTo;
GetTransformTo(m_selectedObject, m_trans);
}
vector3d pos = m_trans;
@ -537,7 +547,7 @@ void SystemView::DrawShips(const double t, const vector3d &offset)
AddProjected<Body>(Projectable::OBJECT, Projectable::SHIP, static_cast<Body *>((*s).first), pos);
if (m_shipDrawing == ORBITS && (*s).first->GetFlightState() == Ship::FlightState::FLYING) {
vector3d framepos(0.0);
CalculateFramePositionAtTime(Frame::GetFrame((*s).first->GetFrame())->GetNonRotFrame(), m_time, framepos);
CalculateFramePositionAtTime((*s).first->GetFrame(), m_time, framepos);
PutOrbit<Body>(Projectable::SHIP, static_cast<Body *>((*s).first), &(*s).second, offset + framepos, isSelected ? svColor[SELECTED_SHIP_ORBIT] : svColor[SHIP_ORBIT], 0);
}
}
@ -649,6 +659,10 @@ void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases b
m_selectedObject.type = type;
m_selectedObject.base = base;
m_selectedObject.ref.sbody = sb;
// we will immediately determine the coordinates of the selected body so that
// there is a correct starting point of the transition animation, otherwise
// there may be an unwanted shift in the next frame
GetTransformTo(m_selectedObject, m_transTo);
m_animateTransition = MAX_TRANSITION_FRAMES;
}
@ -657,6 +671,10 @@ void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases b
m_selectedObject.type = type;
m_selectedObject.base = base;
m_selectedObject.ref.body = b;
// we will immediately determine the coordinates of the selected body so that
// there is a correct starting point of the transition animation, otherwise
// there may be an unwanted shift in the next frame
GetTransformTo(m_selectedObject, m_transTo);
m_animateTransition = MAX_TRANSITION_FRAMES;
}

View File

@ -218,7 +218,7 @@ static int l_systemview_get_projected_grouped(lua_State *l)
touchedGroups.push_back(&group);
//now select the nearest group (if have)
if (touchedGroups.size()) {
GroupInfo *nearest;
GroupInfo *nearest = nullptr;
double min_length = 1e64;
for (GroupInfo *&g : touchedGroups) {
double this_length = (g->m_mainObject.screenpos - special_object[object_type]->screenpos).Length();