//TODO: Finish these
            private static List<ThrustSet> GetZeroTorques(ThrustContribution[] used, double fuelToThrust, Point3D centerMass)
            {
                // Split the list into inline thrusters, and thrusters that produce torque.  So there could be 5 total, but if only 2
                // produce torque, only those 2 are used in the torque calculations
                List<ThrustContribution> noTorque = new List<ThrustContribution>();
                List<ThrustContribution> hasTorque = new List<ThrustContribution>();

                for (int cntr = 0; cntr < used.Length; cntr++)
                {
                    if (IsNearZeroTorque(used[cntr].Torque))
                    {
                        noTorque.Add(used[cntr]);
                    }
                    else
                    {
                        hasTorque.Add(used[cntr]);
                    }
                }

                List<ThrustSet> retVal = new List<ThrustSet>();

                if (hasTorque.Count == 0)
                {
                    // All zero torque
                    retVal.AddRange(GetZeroTorquesSprtZeroTorque(noTorque, fuelToThrust));
                }
                else if (hasTorque.Count == 2)
                {
                    // Two
                    retVal.AddRange(GetZeroTorquesSprtTwoTorque(noTorque, hasTorque, fuelToThrust));
                }
                else if (hasTorque.Count > 2)
                {
                    // Many
                    //retVal.AddRange(GetZeroTorquesSprtManyTorque1(noTorque, hasTorque, fuelToThrust));
                    retVal.AddRange(GetZeroTorquesSprtManyTorque5(noTorque, hasTorque, fuelToThrust, centerMass));
                }

                // Throw out any that have zero translation
                retVal = retVal.Where(o => !IsNearZeroTranslation(o.TranslationLength)).ToList();

                // Exit Function
                return retVal;
            }
 private static List<ThrustSet> GetZeroTranslations(ThrustContribution[] used, double fuelToThrust)
 {
     return new List<ThrustSet>();
 }
            private static Tuple<int, int>[] GetIllegalCombos(ThrustContribution[] thrusters)
            {
                List<Tuple<int, int>> retVal = new List<Tuple<int, int>>();

                for (int outer = 0; outer < thrusters.Length - 1; outer++)
                {
                    for (int inner = outer + 1; inner < thrusters.Length; inner++)
                    {
                        if (thrusters[outer].Thruster == thrusters[inner].Thruster)
                        {
                            Vector3D dir1 = thrusters[outer].Thruster.ThrusterDirectionsModel[thrusters[outer].Index];
                            Vector3D dir2 = thrusters[inner].Thruster.ThrusterDirectionsModel[thrusters[inner].Index];

                            if (Math1D.IsNearValue(Vector3D.DotProduct(dir1, dir2), -1d))
                            {
                                retVal.Add(new Tuple<int, int>(outer, inner));
                            }
                        }
                    }
                }

                return retVal.ToArray();
            }
            /// <summary>
            /// This taks a set of thrusters and tries to find combinations that will produce zero torque and combinations that will produce zero translation
            /// </summary>
            /// <returns>
            /// Item1=Torques
            /// Item2=Translations
            /// </returns>
            private static Tuple<ThrustSet[], ThrustSet[]> GetZeros(ThrustContribution[] all, int[] combo, double fuelToThrust, Point3D centerMass)
            {
                // Get an array of the referenced thrusters
                ThrustContribution[] used = new ThrustContribution[combo.Length];
                for (int cntr = 0; cntr < combo.Length; cntr++)
                {
                    used[cntr] = all[combo[cntr]];
                }

                //This is now done up front (more efficient)
                // Make sure this combo doesn't have the same thruster firing is opposite directions
                //if (!IsValidCombo(used))
                //{
                //    return null;
                //}

                // Try to find combinations of these thrusters that will produce zero torque and zero translation
                List<ThrustSet> torques = GetZeroTorques(used, fuelToThrust, centerMass);
                List<ThrustSet> translations = GetZeroTranslations(used, fuelToThrust);

                // Exit Function
                if (torques.Count == 0 && translations.Count == 0)
                {
                    return null;
                }
                else
                {
                    return new Tuple<ThrustSet[], ThrustSet[]>(torques.ToArray(), translations.ToArray());
                }
            }
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Rotate(Vector3D axis, ThrustContribution[] contributions, double maxAcceleration, MassMatrix inertia)
        {
            axis = axis.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TorqueUnit, axis);

                if (dot > .5d)
                {
                    //retVal.Add(new ThrusterSetting(contribution.Thruster, contribution.Index, 1));     // for now, just do 100%
                    retVal.Add(Tuple.Create(contribution, contribution.TorqueLength * dot));
                }
            }

            retVal = FilterThrusts(retVal);

            #region Reduce Percent

            double percent = 1;

            if (retVal.Count > 0)
            {
                double torque = retVal.Sum(o => o.Item2);

                // A=F/M
                //double accel = torque / (Vector3D.DotProduct(inertia.Inertia, axis) * inertia.Mass);
                double accel = torque / Math.Abs(Vector3D.DotProduct(inertia.Inertia, axis));

                if (accel > maxAcceleration)
                {
                    percent = maxAcceleration / accel;
                }
            }

            #endregion

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, percent)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }
        /// <summary>
        /// This overload will cut back the returned percents if the thrusters exceed the acceleration passed in
        /// </summary>
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Linear(Vector3D direction, ThrustContribution[] contributions, double maxAcceleration, double mass)
        {
            direction = direction.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TranslationForceUnit, direction);

                if (dot > .05d)
                {
                    retVal.Add(Tuple.Create(contribution, contribution.TranslationForceLength * dot));
                }
            }

            retVal = FilterThrusts(retVal);

            #region Reduce Percent

            double percent = 1;

            if (retVal.Count > 0)
            {
                double force = retVal.Sum(o => o.Item2);

                //F=MA, A=F/M
                double accel = force / mass;

                if (accel > maxAcceleration)
                {
                    percent = maxAcceleration / accel;
                }
            }

            #endregion

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, percent)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Rotate(Vector3D torque, ThrustContribution[] contributions)
        {
            torque = torque.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TorqueUnit, torque);

                if (dot > .5d)
                {
                    retVal.Add(Tuple.Create(contribution, contribution.TorqueLength * dot));
                }

                //if (dot > .05d)
                //{
                //    retVal.Add(new ThrusterSetting(thruster, cntr, dot));     // for now, use the dot as the percent
                //}
            }

            retVal = FilterThrusts(retVal, .05);

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, 1)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }