public SolverTask(RCSSolverKey key, Vector3 direction, Vector3 rotation) { this.key = key; this.direction = direction; this.rotation = rotation; this.timeSubmitted = DateTime.Now; }
// Throttles RCS thrusters to keep a vessel balanced during translation. protected void AdjustRCSThrottles(FlightCtrlState s) { bool cutThrottles = false; if (s.X == 0 && s.Y == 0 && s.Z == 0) { solverThread.ResetThrusterForces(); } // Note that FlightCtrlState doesn't use the same axes as the // vehicle's reference frame. FlightCtrlState coordinates are right- // handed, with vessel prograde being -Z. Vessel coordinates // are left-handed, with vessel prograde being +Y. Here's how // FlightCtrlState relates to various ship directions (and their // default keyboard shortcuts): // up (i): y -1 // down (k): y +1 // left (j): x +1 // right (l): x -1 // forward (h): z -1 // backward (n): z +1 // To turn this vector into a vessel-relative one, we need to negate // each value and also swap the Y and Z values. Vector3 direction = new Vector3(-s.X, -s.Z, -s.Y); // RCS balancing on rotation isn't supported. //Vector3 rotation = new Vector3(s.pitch, s.roll, s.yaw); RCSSolverKey.SetPrecision(calcPrecision); GetThrottles(direction, out throttles, out thrusters); // If the throttles we got were bad (due to the threaded // calculation not having completed yet), cut throttles. It's // better to not move at all than move in the wrong direction. if (throttles.Length != thrusters.Count) { throttles = new double[thrusters.Count]; cutThrottles = true; } if (cutThrottles) { for (int i = 0; i < throttles.Length; i++) { throttles[i] = 0; } } // Apply the calculated throttles to all RCS parts. for (int i = 0; i < thrusters.Count; i++) { thrusters[i].partModule.thrusterPower = (float)throttles[i]; } }
// The list of throttles is ordered under the assumption that you iterate // over the vessel as follows: // foreach part in vessel.parts: // foreach rcsModule in part.Modules.OfType<ModuleRCS>: // ... // Note that rotation balancing is not supported at the moment. public void GetThrottles(Vessel vessel, VesselState state, Vector3 direction, out double[] throttles, out List <RCSSolver.Thruster> thrustersOut) { thrustersOut = callerThrusters; Vector3 rotation = Vector3.zero; var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal; // Update vessel info if needed. CheckVessel(vessel, state); Vector3 dir = direction.normalized; RCSSolverKey key = new RCSSolverKey(ref dir, rotation); if (thrusters.Count == 0) { throttles = double0; } else if (direction == Vector3.zero) { throttles = originalThrottles; } else if (results.TryGetValue(key, out throttles)) { cacheHits++; } else { // This task hasn't been calculated. We'll handle that here. // Meanwhile, TryGetValue() will have set 'throttles' to null, but // we'll make it a 0-element array instead to avoid null checks. cacheMisses++; throttles = double0; if (pending.Contains(key)) { // We've submitted this key before, so we need to check the // results queue. while (resultsQueue.Count > 0) { SolverResult sr = (SolverResult)resultsQueue.Dequeue(); results[sr.key] = sr.throttles; pending.Remove(sr.key); if (sr.key == key) { throttles = sr.throttles; } } } else { // This task was neither calculated nor pending, so we've never // submitted it. Do so! pending.Add(key); tasks.Enqueue(new SolverTask(key, dir, rotation)); workEvent.Set(); } } // Return a copy of the array to make sure ours isn't modified. throttles = (double[])throttles.Clone(); }
public SolverResult(RCSSolverKey key, double[] throttles) { this.key = key; this.throttles = throttles; }
// The list of throttles is ordered under the assumption that you iterate // over the vessel as follows: // foreach part in vessel.parts: // foreach rcsModule in part.Modules.OfType<ModuleRCS>: // ... // Note that rotation balancing is not supported at the moment. public void GetThrottles(Vessel vessel, VesselState state, Vector3 direction, out double[] throttles, out List<RCSSolver.Thruster> thrustersOut) { thrustersOut = callerThrusters; Vector3 rotation = Vector3.zero; var rcsBalancer = VesselExtensions.GetMasterMechJeb(vessel).rcsbal; // Update vessel info if needed. CheckVessel(vessel, state); Vector3 dir = direction.normalized; RCSSolverKey key = new RCSSolverKey(ref dir, rotation); if (thrusters.Count == 0) { throttles = double0; } else if (direction == Vector3.zero) { throttles = originalThrottles; } else if (results.TryGetValue(key, out throttles)) { cacheHits++; } else { // This task hasn't been calculated. We'll handle that here. // Meanwhile, TryGetValue() will have set 'throttles' to null, but // we'll make it a 0-element array instead to avoid null checks. cacheMisses++; throttles = double0; if (pending.Contains(key)) { // We've submitted this key before, so we need to check the // results queue. while (resultsQueue.Count > 0) { SolverResult sr = (SolverResult)resultsQueue.Dequeue(); results[sr.key] = sr.throttles; pending.Remove(sr.key); if (sr.key == key) { throttles = sr.throttles; } } } else { // This task was neither calculated nor pending, so we've never // submitted it. Do so! pending.Add(key); tasks.Enqueue(new SolverTask(key, dir, rotation)); workEvent.Set(); } } // Return a copy of the array to make sure ours isn't modified. throttles = (double[])throttles.Clone(); }