예제 #1
0
        private void AoAOffsetFromControl()
        {
            AoAdesired = 0;
            if ((object)vessel != null && vessel.staticPressure > 0)
            {
                if (pitchaxis)
                {
                    AoAdesired += PitchLocation * vessel.ctrlState.pitch;
                }
                if (yawaxis)
                {
                    AoAdesired += YawLocation * vessel.ctrlState.yaw;
                }
                if (rollaxis)
                {
                    AoAdesired += RollLocation * vessel.ctrlState.roll;
                }

                AoAdesired *= AoAsign * maxdeflect;
                AoAdesired  = FARMathUtil.Clamp(AoAdesired, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
                AoAdesired += AoAfromflap;
            }
            ChangeDeflection(timeConstant);

            DeflectionAnimation();
        }
예제 #2
0
        public override double CalculateAoA(Vector3d velocity)
        {
            // Use the vector computed by DeflectionAnimation
            Vector3d perp         = part_transform.TransformDirection(deflectedNormal);
            double   PerpVelocity = Vector3d.Dot(perp, velocity.normalized);

            return(Math.Asin(FARMathUtil.Clamp(PerpVelocity, -1, 1)));
        }
예제 #3
0
        // Had to add this one since the parent class don't use AoAoffset and adding it would break GetWingInFrontOf
        public double CalculateAoA(Vector3d velocity, double AoAoffset)
        {
            double  radAoAoffset = AoAoffset * FARMathUtil.deg2rad * ctrlSurfFrac;
            Vector3 perp         = part_transform.TransformDirection(new Vector3d(0, Math.Sin(radAoAoffset), Math.Cos(radAoAoffset)));
            double  PerpVelocity = Vector3d.Dot(perp, velocity.normalized);

            return(Math.Asin(FARMathUtil.Clamp(PerpVelocity, -1, 1)));
        }
예제 #4
0
        public void SetControlStateEditor(Vector3 CoM, Vector3 velocityVec, float pitch, float yaw, float roll, int flap, bool brake)
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                Transform partTransform = part.partTransform;
                Transform rootTransform = EditorLogic.RootPart.partTransform;

                Vector3 CoMoffset = (partTransform.position - CoM);
                PitchLocation     = Vector3.Dot(partTransform.forward, rootTransform.forward) * Math.Sign(Vector3.Dot(CoMoffset, rootTransform.up));
                YawLocation       = -Vector3.Dot(partTransform.forward, rootTransform.right) * Math.Sign(Vector3.Dot(CoMoffset, rootTransform.up));
                RollLocation      = Vector3.Dot(partTransform.forward, rootTransform.forward) * Math.Sign(Vector3.Dot(CoMoffset, -rootTransform.right));
                AoAsign           = Math.Sign(Vector3.Dot(partTransform.up, rootTransform.up));
                AoAdesiredControl = 0;
                if (pitchaxis != 0.0)
                {
                    AoAdesiredControl += PitchLocation * pitch * pitchaxis * 0.01;
                }
                if (yawaxis != 0.0)
                {
                    AoAdesiredControl += YawLocation * yaw * yawaxis * 0.01;
                }
                if (rollaxis != 0.0)
                {
                    AoAdesiredControl += RollLocation * roll * rollaxis * 0.01;
                }
                AoAdesiredControl *= maxdeflect;
                if (pitchaxisDueToAoA != 0.0)
                {
                    Vector3 tmpVec = rootTransform.up * Vector3.Dot(rootTransform.up, velocityVec) + rootTransform.forward * Vector3.Dot(rootTransform.forward, velocityVec); //velocity vector projected onto a plane that divides the airplane into left and right halves
                    double  AoA    = base.CalculateAoA(tmpVec.normalized);                                                                                                    //using base.CalculateAoA gets the deflection using WingAeroModel's code, which does not account for deflection; this gives us the AoA that the surface _would_ be at if it hadn't deflected at all.
                    AoA = FARMathUtil.rad2deg * AoA;
                    if (double.IsNaN(AoA))
                    {
                        AoA = 0;
                    }
                    AoAdesiredControl += AoA * pitchaxisDueToAoA * 0.01;
                }

                AoAdesiredControl *= AoAsign;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
                AoAcurrentControl  = AoAdesiredControl;
                AoAcurrentFlap     = 0;
                if (isFlap == true)
                {
                    int flapDeflectionLevel = flap;
                    flapLocation    = (int)Math.Sign(Vector3.Dot(rootTransform.forward, partTransform.forward));   //figure out which way is up
                    AoAcurrentFlap += maxdeflectFlap * flapLocation * flapDeflectionLevel * 0.3333333333333;
                }
                else if (isSpoiler == true)
                {
                    flapLocation    = -(int)Math.Sign(Vector3.Dot(rootTransform.forward, partTransform.forward));   //figure out which way is up
                    AoAcurrentFlap += brake ? maxdeflectFlap * flapLocation : 0;
                }
                AoAdesiredFlap = AoAcurrentFlap;
                AoAoffset      = AoAcurrentFlap + AoAcurrentControl;
                DeflectionAnimation();
            }
        }
예제 #5
0
        private double WingInterference(Vector3 rayDirection, List <Part> PartList, float dist)
        {
            double interferencevalue = 1;

            Ray ray = new Ray();

            ray.origin    = parentWingModule.WingCentroid();
            ray.direction = rayDirection;

            RaycastHit hit = new RaycastHit();

            bool gotSomething = false;

            hit.distance = 0;
            RaycastHit[] hits = Physics.RaycastAll(ray, dist, FARAeroUtil.RaycastMask);
            for (int i = 0; i < hits.Length; i++)
            {
                RaycastHit h = hits[i];
                if (h.collider != null)
                {
                    for (int j = 0; j < PartList.Count; j++)
                    {
                        Part p = PartList[j];

                        if (p == parentWingPart)
                        {
                            continue;
                        }

                        FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>();

                        if ((object)w != null)
                        {
                            Collider[] colliders = w.PartColliders;

                            for (int k = 0; k < colliders.Length; k++)
                            {
                                if (h.collider == colliders[k] && h.distance > 0)
                                {
                                    double tmp = h.distance / dist;
                                    tmp = FARMathUtil.Clamp(tmp, 0, 1);
                                    interferencevalue = Math.Min(tmp, interferencevalue);
                                    gotSomething      = true;

                                    break;
                                }
                            }
                        }
                        if (gotSomething)
                        {
                            break;
                        }
                    }
                }
            }
            return(interferencevalue);
        }
        public void SetControlStateEditor(Vector3 CoM, Vector3 velocityVec, float pitch, float yaw, float roll, int flap, bool brake)
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                Vector3 CoMoffset = (part.transform.position - CoM).normalized;
                PitchLocation     = Vector3.Dot(part.transform.forward, EditorLogic.RootPart.transform.forward) * Mathf.Sign(Vector3.Dot(CoMoffset, EditorLogic.RootPart.transform.up));
                YawLocation       = -Vector3.Dot(part.transform.forward, EditorLogic.RootPart.transform.right) * Mathf.Sign(Vector3.Dot(CoMoffset, EditorLogic.RootPart.transform.up));
                RollLocation      = Vector3.Dot(part.transform.forward, EditorLogic.RootPart.transform.forward) * Mathf.Sign(Vector3.Dot(CoMoffset, -EditorLogic.RootPart.transform.right));
                AoAsign           = Math.Sign(Vector3.Dot(part.transform.up, EditorLogic.RootPart.transform.up));
                AoAdesiredControl = 0;
                if (pitchaxis != 0.0)
                {
                    AoAdesiredControl += PitchLocation * pitch * pitchaxis * 0.01;
                }
                if (yawaxis != 0.0)
                {
                    AoAdesiredControl += YawLocation * yaw * yawaxis * 0.01;
                }
                if (rollaxis != 0.0)
                {
                    AoAdesiredControl += RollLocation * roll * rollaxis * 0.01;
                }
                AoAdesiredControl *= maxdeflect;
                if (pitchaxisDueToAoA != 0.0)
                {
                    Vector3 tmpVec = EditorLogic.RootPart.transform.up * Vector3.Dot(EditorLogic.RootPart.transform.up, velocityVec) + EditorLogic.RootPart.transform.forward * Vector3.Dot(EditorLogic.RootPart.transform.forward, velocityVec);   //velocity vector projected onto a plane that divides the airplane into left and right halves
                    double  AoA    = Vector3.Dot(tmpVec.normalized, EditorLogic.RootPart.transform.forward);
                    AoA = FARMathUtil.rad2deg * Math.Asin(AoA);
                    if (double.IsNaN(AoA))
                    {
                        AoA = 0;
                    }
                    AoAdesiredControl += PitchLocation * AoA * pitchaxisDueToAoA * 0.01;
                }

                AoAdesiredControl *= AoAsign;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
                AoAcurrentFlap     = 0;
                if (isFlap == true)
                {
                    int flapDeflectionLevel = flap;
                    flapLocation    = (int)Math.Sign(Vector3.Dot(EditorLogic.RootPart.transform.forward, part.transform.forward));   //figure out which way is up
                    AoAcurrentFlap += maxdeflectFlap * flapLocation * flapDeflectionLevel * 0.3333333333333;
                }
                else if (isSpoiler == true)
                {
                    flapLocation    = -(int)Math.Sign(Vector3.Dot(EditorLogic.RootPart.transform.forward, part.transform.forward));   //figure out which way is up
                    AoAcurrentFlap += brake ? maxdeflectFlap * flapLocation : 0;
                }
                AoAdesiredFlap = AoAcurrentFlap;
                AoAoffset      = AoAdesiredFlap + AoAdesiredControl;
                DeflectionAnimation();
            }
        }
예제 #7
0
 private void AoAOffsetFromSpoilerDeflection()
 {
     if (brake)
     {
         AoAdesiredFlap = maxdeflectFlap * spoilerLocation;
     }
     else
     {
         AoAdesiredFlap = 0;
     }
     AoAdesiredFlap = FARMathUtil.Clamp(AoAdesiredFlap, -Math.Abs(maxdeflectFlap), Math.Abs(maxdeflectFlap));
 }
예제 #8
0
        //DaMichel: Factored the time evolution for deflection AoA into this function. This one results into an exponential asympotic
        //"decay" towards the desired value. Good for stick inputs, i suppose, and the original method.
        private static double BlendDeflectionExp(double current, double desired, double timeConstant, bool forceSetToDesired)
        {
            double error = desired - current;

            if (!forceSetToDesired && Math.Abs(error) >= 0.1)  // DaMichel: i changed the threshold since i noticed a "bump" at max deflection
            {
                double recip_timeconstant = 1 / timeConstant;
                double tmp1 = error * recip_timeconstant;
                current += FARMathUtil.Clamp((double)TimeWarp.fixedDeltaTime * tmp1, -Math.Abs(0.6 * error), Math.Abs(0.6 * error));
            }
            else
            {
                current = desired;
            }
            return(current);
        }
예제 #9
0
        //DaMichel: Similarly, this is used for constant rate movment towards the desired value. I presume it is more realistic for
        //for slow moving flaps and spoilers. It looks better anyways.
        private static double BlendDeflectionLinear(double current, double desired, double timeConstant, bool forceSetToDesired)
        {
            double error = desired - current;

            if (!forceSetToDesired && Math.Abs(error) >= 0.1)
            {
                double recip_timeconstant = 1 / timeConstant;
                double tmp1 = Math.Sign(error) * recip_timeconstant;
                current += FARMathUtil.Clamp((double)TimeWarp.deltaTime * tmp1, -Math.Abs(0.6 * error), Math.Abs(0.6 * error));
            }
            else
            {
                current = desired;
            }
            return(current);
        }
예제 #10
0
 private void ChangeDeflection(double timeconstant)
 {
     if (AoAoffset != AoAdesired)
     {
         double error = AoAdesired - AoAoffset;
         if (!justStarted && Math.Abs(error) >= 0.5)
         {
             double recip_timeconstant = 1 / timeconstant;
             double tmp1 = error * recip_timeconstant;
             //float tmp2 = (error + TimeWarp.deltaTime * tmp1) * recip_timeconstant;
             AoAoffset += FARMathUtil.Clamp((double)TimeWarp.deltaTime * tmp1, -Math.Abs(0.6 * error), Math.Abs(0.6 * error));
         }
         else
         {
             AoAoffset = AoAdesired;
         }
     }
 }
예제 #11
0
        private void AoAOffsetFromControl()
        {
            AoAdesiredControl = 0;
            if ((object)vessel != null && vessel.atmDensity > 0)
            {
                if (!pitchaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += PitchLocation * vessel.ctrlState.pitch * pitchaxis * 0.01;
                }
                if (!yawaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += YawLocation * vessel.ctrlState.yaw * yawaxis * 0.01;
                }
                if (!rollaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += RollLocation * vessel.ctrlState.roll * rollaxis * 0.01;
                }
                if (!brakeRudder.NearlyEqual(0))
                {
                    AoAdesiredControl += BrakeRudderLocation * Math.Max(0.0, BrakeRudderSide * vessel.ctrlState.yaw) * brakeRudder * 0.01;
                }
                AoAdesiredControl *= maxdeflect;
                if (pitchaxisDueToAoA != 0.0)
                {
                    Vector3d vel    = this.GetVelocity();
                    double   velMag = vel.magnitude;
                    if (velMag > 5)
                    {
                        //Vector3 tmpVec = vessel.ReferenceTransform.up * Vector3.Dot(vessel.ReferenceTransform.up, vel) + vessel.ReferenceTransform.forward * Vector3.Dot(vessel.ReferenceTransform.forward, vel);   //velocity vector projected onto a plane that divides the airplane into left and right halves
                        //double AoA = Vector3.Dot(tmpVec.normalized, vessel.ReferenceTransform.forward);
                        double AoA = base.CalculateAoA(vel);      //using base.CalculateAoA gets the deflection using WingAeroModel's code, which does not account for deflection; this gives us the AoA that the surface _would_ be at if it hadn't deflected at all.
                        AoA = FARMathUtil.rad2deg * AoA;
                        if (double.IsNaN(AoA))
                        {
                            AoA = 0;
                        }
                        AoAdesiredControl += AoA * pitchaxisDueToAoA * 0.01;
                    }
                }

                AoAdesiredControl *= AoAsign;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
            }
        }
예제 #12
0
 public void SetControlStateEditor(Vector3 CoM, float pitch, float yaw, float roll, int flap, bool brake)
 {
     if (HighLogic.LoadedSceneIsEditor)
     {
         Vector3 CoMoffset = (part.transform.position - CoM).normalized;
         PitchLocation     = Vector3.Dot(part.transform.forward, EditorLogic.startPod.transform.forward) * Mathf.Sign(Vector3.Dot(CoMoffset, EditorLogic.startPod.transform.up));
         YawLocation       = -Vector3.Dot(part.transform.forward, EditorLogic.startPod.transform.right) * Mathf.Sign(Vector3.Dot(CoMoffset, EditorLogic.startPod.transform.up));
         RollLocation      = Vector3.Dot(part.transform.forward, EditorLogic.startPod.transform.forward) * Mathf.Sign(Vector3.Dot(CoMoffset, -EditorLogic.startPod.transform.right));
         AoAcurrentControl = 0;
         if (pitchaxis == true)
         {
             AoAcurrentControl += PitchLocation * pitch;
         }
         if (yawaxis == true)
         {
             AoAcurrentControl += YawLocation * yaw;
         }
         if (rollaxis == true)
         {
             AoAcurrentControl += RollLocation * roll;
         }
         AoAcurrentControl = AoAdesiredControl = FARMathUtil.Clamp(AoAcurrentControl, -1, 1) * maxdeflect;
         AoAcurrentFlap    = 0;
         if (isFlap == true)
         {
             int flapDeflectionLevel = flap;
             flapLocation    = (int)Math.Sign(Vector3.Dot(EditorLogic.startPod.transform.forward, part.transform.forward));   //figure out which way is up
             AoAcurrentFlap += maxdeflectFlap * flapLocation * flapDeflectionLevel * 0.3333333333333;
         }
         else if (isSpoiler == true)
         {
             flapLocation    = -(int)Math.Sign(Vector3.Dot(EditorLogic.startPod.transform.forward, part.transform.forward));   //figure out which way is up
             AoAcurrentFlap += brake ? maxdeflectFlap * flapLocation : 0;
         }
         AoAdesiredFlap = AoAcurrentFlap;
         AoAoffset      = AoAdesiredFlap + AoAdesiredControl;
         DeflectionAnimation();
     }
 }
예제 #13
0
        private void AoAOffsetFromControl()
        {
            AoAdesiredControl = 0;
            if ((object)vessel != null && vessel.staticPressure > 0)
            {
                if (pitchaxis)
                {
                    AoAdesiredControl += PitchLocation * vessel.ctrlState.pitch;
                }
                if (yawaxis)
                {
                    AoAdesiredControl += YawLocation * vessel.ctrlState.yaw;
                }
                if (rollaxis)
                {
                    AoAdesiredControl += RollLocation * vessel.ctrlState.roll;
                }

                AoAdesiredControl *= AoAsign * maxdeflect;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
            }
        }
        private void AoAOffsetFromControl()
        {
            AoAdesiredControl = 0;
            if ((object)vessel != null && vessel.staticPressure > 0)
            {
                if (pitchaxis != 0.0)
                {
                    AoAdesiredControl += PitchLocation * vessel.ctrlState.pitch * pitchaxis * 0.01;
                }
                if (yawaxis != 0.0)
                {
                    AoAdesiredControl += YawLocation * vessel.ctrlState.yaw * yawaxis * 0.01;
                }
                if (rollaxis != 0.0)
                {
                    AoAdesiredControl += RollLocation * vessel.ctrlState.roll * rollaxis * 0.01;
                }
                AoAdesiredControl *= maxdeflect;
                if (pitchaxisDueToAoA != 0.0)
                {
                    Vector3d vel = this.GetVelocity();
                    //Vector3 tmpVec = vessel.ReferenceTransform.up * Vector3.Dot(vessel.ReferenceTransform.up, vel) + vessel.ReferenceTransform.forward * Vector3.Dot(vessel.ReferenceTransform.forward, vel);   //velocity vector projected onto a plane that divides the airplane into left and right halves
                    //double AoA = Vector3.Dot(tmpVec.normalized, vessel.ReferenceTransform.forward);
                    double AoA = base.CalculateAoA(vel.normalized);
                    AoA = FARMathUtil.rad2deg * Math.Asin(AoA);
                    if (double.IsNaN(AoA))
                    {
                        AoA = 0;
                    }
                    AoAdesiredControl += AoA * pitchaxisDueToAoA * 0.01;
                }

                AoAdesiredControl *= AoAsign;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
            }
        }
예제 #15
0
        //DaMichel: Similarly, this is used for constant rate movment towards the desired value. I presume it is more realistic for
        //for slow moving flaps and spoilers. It looks better anyways.
        //ferram4: The time constant specifies the time it would take for a first-order system to reach its steady-state value,
        //assuming that it was proportional to only the initial error, not the error as a function of time
        private static double BlendDeflectionLinear(double current, double desired, double maximumDeflection, double timeConstant, bool forceSetToDesired)
        {
            double error = desired - current;

            if (!forceSetToDesired && Math.Abs(error) >= 0.1)
            {
                double degreesPerSecond = Math.Max(Math.Abs(maximumDeflection), Math.Abs(current)) / timeConstant;
                double tmp = current + (double)TimeWarp.fixedDeltaTime * degreesPerSecond * Math.Sign(desired - current);
                if (error > 0)
                {
                    current = FARMathUtil.Clamp(tmp, current, desired);
                }
                else
                {
                    current = FARMathUtil.Clamp(tmp, desired, current);
                }
            }
            else
            {
                return(desired);
            }

            return(current);
        }
예제 #16
0
        public Vector3d RunDragCalculation(Vector3d velocity, double MachNumber, double rho)
        {
            if (isShielded)
            {
                Cl = Cd = Cm = 0;
                return(Vector3d.zero);
            }

            double v_scalar = velocity.magnitude;

            if (v_scalar > 0.1)         //Don't Bother if it's not moving or in space
            {
                CoDshift = Vector3d.zero;
                Cd       = 0;

                Vector3d velocity_normalized = velocity / v_scalar;
                //float Parallel = Vector3.Dot(upVector, velocity_normalized);

                Vector3d upVector = part_transform.TransformDirection(localUpVector);
                perp    = Vector3d.Cross(upVector, velocity).normalized;
                liftDir = Vector3d.Cross(velocity, perp).normalized;

                Vector3d local_velocity = part_transform.InverseTransformDirection(velocity_normalized);
                DragModel(local_velocity, MachNumber);

                //if(gear && start != StartState.Editor)
                //    if(gear.gearState != ModuleLandingGear.GearStates.RETRACTED)
                //        Cd += 0.1f;

                /* if(anim)
                 *   if (anim.Progress > 0.5f)
                 *       Cd *= 1.5f;*/



                double   qS           = 0.5 * rho * v_scalar * v_scalar * S; //dynamic pressure, q
                Vector3d D            = velocity_normalized * (-qS * Cd);    //drag
                Vector3d L            = liftDir * (qS * Cl);
                Vector3d force        = (L + D) * 0.001;
                double   force_scalar = force.magnitude;
                currentDrag = (float)force_scalar;
                Vector3d moment = perp * (qS * Cm * 0.001);

                Rigidbody rb = part.Rigidbody;

                if (start != StartState.Editor && rb)
                {
                    if (rb.angularVelocity.sqrMagnitude != 0)
                    {
                        Vector3d rot = Vector3d.Exclude(velocity_normalized, rb.angularVelocity);  //This prevents aerodynamic damping a spinning object if its spin axis is aligned with the velocity axis

                        rot *= (-0.00001 * qS);

                        // This seems redundant due to the moment addition below?

                        /*
                         * if(!float.IsNaN(rot.sqrMagnitude))
                         *  part.Rigidbody.AddTorque(rot);
                         */

                        moment += rot;
                    }
                    //moment = (moment + lastMoment) / 2;
                    //lastMoment = moment;
//                    CoDshift += CenterOfDrag;
                }

                //Must handle aero-structural failure before transforming CoD pos and adding pitching moment to forces or else parts with blunt body drag fall apart too easily
                if (Math.Abs(Vector3d.Dot(force, upVector)) > YmaxForce || Vector3d.Exclude(upVector, force).magnitude > XZmaxForce)
                {
                    if (part.parent && !vessel.packed)
                    {
                        part.SendEvent("AerodynamicFailureStatus");
                        FlightLogger.eventLog.Add("[" + FARMathUtil.FormatTime(vessel.missionTime) + "] Joint between " + part.partInfo.title + " and " + part.parent.partInfo.title + " failed due to aerodynamic stresses.");
                        part.decouple(25);
                    }
                }

                globalCoDShift = Vector3d.Cross(force, moment) / (force_scalar * force_scalar);

                if (double.IsNaN(force_scalar) || double.IsNaN(moment.sqrMagnitude) || double.IsNaN(globalCoDShift.sqrMagnitude))
                {
                    Debug.LogWarning("FAR Error: Aerodynamic force = " + force.magnitude + " Aerodynamic moment = " + moment.magnitude + " CoD Local = " + CoDshift.magnitude + " CoD Global = " + globalCoDShift.magnitude + " " + part.partInfo.title);
                    force = moment = CoDshift = globalCoDShift = Vector3.zero;
                    return(force);
                }


                //part.Rigidbody.AddTorque(moment);
                return(force);
            }
            else
            {
                return(Vector3d.zero);
            }
        }
예제 #17
0
        public void SetControlStateEditor(Vector3 CoM, Vector3 velocityVec, float pitch, float yaw, float roll, int flap, bool brake)
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                Transform partTransform = part.partTransform;
                Transform rootTransform = EditorLogic.RootPart.partTransform;

                // cache transform vectors
                Vector3 partPosition = partTransform.position;
                Vector3 CoMoffset    = partPosition - CoM;

                Vector3 partForward = partTransform.forward;
                Vector3 forward     = rootTransform.forward;
                Vector3 up          = rootTransform.up;
                Vector3 right       = rootTransform.right;

                PitchLocation       = Vector3.Dot(partForward, forward) * Math.Sign(Vector3.Dot(CoMoffset, up));
                YawLocation         = -Vector3.Dot(partForward, right) * Math.Sign(Vector3.Dot(CoMoffset, up));
                RollLocation        = Vector3.Dot(partForward, forward) * Math.Sign(Vector3.Dot(CoMoffset, -right));
                BrakeRudderLocation = Vector3.Dot(partForward, forward);
                BrakeRudderSide     = Mathf.Sign(Vector3.Dot(CoMoffset, right));
                AoAsign             = Math.Sign(Vector3.Dot(partTransform.up, up));
                AoAdesiredControl   = 0;
                if (!pitchaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += PitchLocation * pitch * pitchaxis * 0.01;
                }
                if (!yawaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += YawLocation * yaw * yawaxis * 0.01;
                }
                if (!rollaxis.NearlyEqual(0))
                {
                    AoAdesiredControl += RollLocation * roll * rollaxis * 0.01;
                }
                if (!brakeRudder.NearlyEqual(0))
                {
                    AoAdesiredControl += BrakeRudderLocation * Math.Max(0.0, BrakeRudderSide * yawaxis) * brakeRudder * 0.01;
                }
                AoAdesiredControl *= maxdeflect;
                if (!pitchaxisDueToAoA.NearlyEqual(0))
                {
                    Vector3 tmpVec = up * Vector3.Dot(up, velocityVec) + forward * Vector3.Dot(forward, velocityVec); //velocity vector projected onto a plane that divides the airplane into left and right halves
                    double  AoA    = base.CalculateAoA(tmpVec);                                                       //using base.CalculateAoA gets the deflection using WingAeroModel's code, which does not account for deflection; this gives us the AoA that the surface _would_ be at if it hadn't deflected at all.
                    AoA = FARMathUtil.rad2deg * AoA;
                    if (double.IsNaN(AoA))
                    {
                        AoA = 0;
                    }
                    AoAdesiredControl += AoA * pitchaxisDueToAoA * 0.01;
                }

                AoAdesiredControl *= AoAsign;
                AoAdesiredControl  = FARMathUtil.Clamp(AoAdesiredControl, -Math.Abs(maxdeflect), Math.Abs(maxdeflect));
                AoAcurrentControl  = AoAdesiredControl;
                AoAcurrentFlap     = 0;

                if (part.symMethod == SymmetryMethod.Mirror || part.symmetryCounterparts.Count < 1)
                {
                    if (HighLogic.LoadedSceneIsFlight)
                    {
                        flapLocation = Math.Sign(Vector3.Dot(vessel.ReferenceTransform.forward, partForward));      //figure out which way is up
                    }
                    else
                    {
                        flapLocation = Math.Sign(Vector3.Dot(EditorLogic.RootPart.partTransform.forward, partForward));      //figure out which way is up
                    }
                    spoilerLocation = -flapLocation;
                }
                else if (part.parent != null)
                {
                    flapLocation    = Math.Sign(Vector3.Dot(partPosition - part.parent.partTransform.position, partForward));
                    spoilerLocation = flapLocation;
                }
                else
                {
                    flapLocation    = 1;
                    spoilerLocation = flapLocation;
                }

                if (isFlap)
                {
                    AoAcurrentFlap += maxdeflectFlap * flapLocation * flap * 0.3333333333333;
                }
                else if (isSpoiler)
                {
                    AoAcurrentFlap += brake ? maxdeflectFlap * spoilerLocation : 0;
                }

                AoAdesiredFlap = AoAcurrentFlap;
                AoAoffset      = AoAcurrentFlap + AoAcurrentControl;
                DeflectionAnimation();
            }
        }
예제 #18
0
 private void AoAOffsetFromFlapDeflection()
 {
     AoAdesiredFlap = maxdeflectFlap * flapLocation * flapDeflectionLevel * 0.33333333333;
     AoAdesiredFlap = FARMathUtil.Clamp(AoAdesiredFlap, -Math.Abs(maxdeflectFlap), Math.Abs(maxdeflectFlap));
 }
예제 #19
0
        public Vector3d RunDragCalculation(Vector3d velocity, double MachNumber, double rho, double failureForceScaling)
        {
            if (isShielded)
            {
                Cl = Cd = Cm = 0;
                return(Vector3d.zero);
            }

            double v_scalar = velocity.magnitude;

            if (v_scalar > 0.1)         //Don't Bother if it's not moving or in space
            {
                CoDshift = Vector3d.zero;
                Cd       = 0;

                Vector3d velocity_normalized = velocity / v_scalar;

                Vector3d upVector = part_transform.TransformDirection(localUpVector);
                perp    = Vector3d.Cross(upVector, velocity).normalized;
                liftDir = Vector3d.Cross(velocity, perp).normalized;

                Vector3d local_velocity = part_transform.InverseTransformDirection(velocity_normalized);
                DragModel(local_velocity, MachNumber, rho);

                double   qS           = 0.5 * rho * v_scalar * v_scalar * S; //dynamic pressure, q
                Vector3d D            = velocity_normalized * (-qS * Cd);    //drag
                Vector3d L            = liftDir * (qS * Cl);
                Vector3d force        = (L + D) * 0.001;
                double   force_scalar = force.magnitude;
                currentDrag = (float)force_scalar;
                Vector3d moment = perp * (qS * Cm * 0.001);

                Rigidbody rb = part.Rigidbody;

                if (HighLogic.LoadedSceneIsFlight && (object)rb != null)
                {
                    if (rb.angularVelocity.sqrMagnitude != 0)
                    {
                        Vector3d rot = Vector3d.Exclude(velocity_normalized, rb.angularVelocity);  //This prevents aerodynamic damping a spinning object if its spin axis is aligned with the velocity axis

                        rot *= (-0.00001 * qS);


                        moment += rot;
                    }
                }


                //Must handle aero-structural failure before transforming CoD pos and adding pitching moment to forces or else parts with blunt body drag fall apart too easily
                if (Math.Abs(Vector3d.Dot(force, upVector)) > YmaxForce * failureForceScaling || Vector3d.Exclude(upVector, force).magnitude > XZmaxForce * failureForceScaling)
                {
                    if (part.parent && !vessel.packed)
                    {
                        part.SendEvent("AerodynamicFailureStatus");
                        FlightLogger.eventLog.Add("[" + FARMathUtil.FormatTime(vessel.missionTime) + "] Joint between " + part.partInfo.title + " and " + part.parent.partInfo.title + " failed due to aerodynamic stresses.");
                        part.decouple(25);
                        if (FARDebugValues.aeroFailureExplosions)
                        {
                            FXMonger.Explode(part, GetCoDWithoutMomentShift(), 5);
                        }
                    }
                }

                globalCoDShift = Vector3d.Cross(force, moment) / (force_scalar * force_scalar);

                if (double.IsNaN(force_scalar) || double.IsNaN(moment.sqrMagnitude) || double.IsNaN(globalCoDShift.sqrMagnitude))
                {
                    Debug.LogWarning("FAR Error: Aerodynamic force = " + force.magnitude + " Aerodynamic moment = " + moment.magnitude + " CoD Local = " + CoDshift.magnitude + " CoD Global = " + globalCoDShift.magnitude + " " + part.partInfo.title);
                    force = moment = CoDshift = globalCoDShift = Vector3.zero;


                    return(force);
                }
                double numericalControlFactor = (rb.mass * v_scalar * 0.67) / (force_scalar * TimeWarp.fixedDeltaTime);
                force *= Math.Min(numericalControlFactor, 1);

                //part.Rigidbody.AddTorque(moment);
                return(force);
            }
            else
            {
                return(Vector3d.zero);
            }
        }
        /// <summary>
        /// Accounts for increments in lift due to camber changes from upstream wings, and returns changes for this wing part; returns true if there are wings in front of it
        /// </summary>
        /// <param name="thisWingAoA">AoA of this wing in rad</param>
        /// <param name="thisWingMachNumber">Mach Number of this wing in rad</param>
        /// <param name="ACWeight">Weighting value for applying ACshift</param>
        /// <param name="ACShift">Value used to shift the wing AC due to interactive effects</param>
        /// <param name="ClIncrementFromRear">Increase in Cl due to this</param>
        /// <returns></returns>
        public void CalculateEffectsOfUpstreamWing(double thisWingAoA, double thisWingMachNumber, Vector3d parallelInPlaneLocal,
                                                   ref double ACweight, ref double ACshift, ref double ClIncrementFromRear)
        {
            double thisWingMAC, thisWingb_2;

            thisWingMAC = parentWingModule.GetMAC();
            thisWingb_2 = parentWingModule.Getb_2();

            effectiveUpstreamMAC  = 0;
            effectiveUpstreamb_2  = 0;
            effectiveUpstreamArea = 0;

            effectiveUpstreamLiftSlope     = 0;
            effectiveUpstreamStall         = 0;
            effectiveUpstreamCosSweepAngle = 0;
            effectiveUpstreamAoAMax        = 0;
            effectiveUpstreamAoA           = 0;
            effectiveUpstreamCd0           = 0;
            effectiveUpstreamInfluence     = 0;

            double wingForwardDir   = parallelInPlaneLocal.y;
            double wingRightwardDir = parallelInPlaneLocal.x * srfAttachFlipped;

            if (wingForwardDir > 0)
            {
                wingForwardDir *= wingForwardDir;
                UpdateUpstreamValuesFromWingModules(nearbyWingModulesForwardList, nearbyWingModulesForwardInfluence, wingForwardDir, thisWingAoA);
            }
            else
            {
                wingForwardDir *= wingForwardDir;
                UpdateUpstreamValuesFromWingModules(nearbyWingModulesBackwardList, nearbyWingModulesBackwardInfluence, wingForwardDir, thisWingAoA);
            }

            if (wingRightwardDir > 0)
            {
                wingRightwardDir *= wingRightwardDir;
                UpdateUpstreamValuesFromWingModules(nearbyWingModulesRightwardList, nearbyWingModulesRightwardInfluence, wingRightwardDir, thisWingAoA);
            }
            else
            {
                wingRightwardDir *= wingRightwardDir;
                UpdateUpstreamValuesFromWingModules(nearbyWingModulesLeftwardList, nearbyWingModulesLeftwardInfluence, wingRightwardDir, thisWingAoA);
            }

            double MachCoeff = FARMathUtil.Clamp(1 - thisWingMachNumber * thisWingMachNumber, 0, 1);

            if (MachCoeff != 0)
            {
                double flapRatio     = FARMathUtil.Clamp(thisWingMAC / (thisWingMAC + effectiveUpstreamMAC), 0, 1);
                float  flt_flapRatio = (float)flapRatio;
                double flapFactor    = wingCamberFactor.Evaluate(flt_flapRatio);     //Flap Effectiveness Factor
                double dCm_dCl       = wingCamberMoment.Evaluate(flt_flapRatio);     //Change in moment due to change in lift from flap

                //This accounts for the wing possibly having a longer span than the flap
                double WingFraction = FARMathUtil.Clamp(thisWingb_2 / effectiveUpstreamb_2, 0, 1);
                //This accounts for the flap possibly having a longer span than the wing it's attached to
                double FlapFraction = FARMathUtil.Clamp(effectiveUpstreamb_2 / thisWingb_2, 0, 1);

                double ClIncrement = flapFactor * effectiveUpstreamLiftSlope * effectiveUpstreamAoA;                            //Lift created by the flap interaction
                ClIncrement *= (parentWingModule.S * FlapFraction + effectiveUpstreamArea * WingFraction) / parentWingModule.S; //Increase the Cl so that even though we're working with the flap's area, it accounts for the added lift across the entire object

                ACweight = ClIncrement * MachCoeff;                                                                             // Total flap Cl for the purpose of applying ACshift, including the bit subtracted below

                ClIncrement -= FlapFraction * effectiveUpstreamLiftSlope * effectiveUpstreamAoA;                                //Removing additional angle so that lift of the flap is calculated as lift at wing angle + lift due to flap interaction rather than being greater

                ACshift = (dCm_dCl + 0.75 * (1 - flapRatio)) * (thisWingMAC + effectiveUpstreamMAC);                            //Change in Cm with change in Cl

                ClIncrementFromRear = ClIncrement * MachCoeff;
            }
        }
예제 #21
0
        private void UpdateAttachGroupDrag(List <AttachNode> attachNodeGroup, AttachGroupType attachGroupType, Transform[] ThisPartModelTransforms, Transform[] AllVesselModelTransforms)
        {
            //This is standard single node; the blunt area is to be determined by everything near it
            if (attachGroupType == AttachGroupType.INDEPENDENT_NODE)
            {
                //Get area represented by current node
                Vector2 bounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, ThisPartModelTransforms);

                double area = (bounds.x + bounds.y);
                area *= 0.5;
                area *= area;
                area *= Math.PI;       //Calculate area based on circular cross-section

                //Get area covered by other parts
                Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms);
                Vector2     otherBounds     = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms);

                double opposedArea = (otherBounds.x + otherBounds.y);
                opposedArea *= 0.5f;
                opposedArea *= opposedArea;
                opposedArea *= Math.PI;       //Calculate area based on circular cross-section

                //Debug.Log(part.partInfo.title + " Area: " + area + " Opposed area: " + opposedArea + " OtherTransforms: " + OtherTransforms.Length);

                area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity);


                //Update attachNodeDragDict with new data
                attachNodeData newAttachNodeData = new attachNodeData();
                newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                Vector3 orientation = attachNodeGroup[0].position;

                if (Vector3d.Dot(orientation, localUpVector) > 1)
                {
                    newAttachNodeData.pitchesAwayFromUpVec = true;
                }
                else
                {
                    newAttachNodeData.pitchesAwayFromUpVec = false;
                }


                if (attachNodeDragDict.ContainsKey(orientation))
                {
                    attachNodeData tmp = attachNodeDragDict[orientation];
                    tmp.areaValue += newAttachNodeData.areaValue;
                    attachNodeDragDict[orientation] = tmp;
                }
                else
                {
                    attachNodeDragDict.Add(orientation, newAttachNodeData);
                }


                return;
            }
            //This is a group of nodes that can be used for clustered tanks/engines; the area calculated must be divided over them
            else if (attachGroupType == AttachGroupType.PARALLEL_NODES)
            {
                //Get area represented by current nodes
                Vector2 bounds = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, ThisPartModelTransforms);

                double area = (bounds.x + bounds.y);
                area *= 0.5;
                area *= area;
                area *= Math.PI;       //Calculate area based on circular cross-section

                //Get area covered by other parts
                Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms);
                Vector2     otherBounds     = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms);

                double opposedArea = (otherBounds.x + otherBounds.y);
                opposedArea *= 0.5;
                opposedArea *= opposedArea;
                opposedArea *= Mathf.PI;       //Calculate area based on circular cross-section

                //Debug.Log(part.partInfo.title + " Area: " + area + " Opposed area: " + opposedArea + " OtherTransforms: " + OtherTransforms.Length);

                area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity);

                //Update attachNodeDragDict with new data
                attachNodeData newAttachNodeData = new attachNodeData();
                newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                Vector3 orientation = Vector3.zero;
                foreach (AttachNode attach in attachNodeGroup)
                {
                    orientation += attach.position;
                }
                orientation /= attachNodeGroup.Count;

                if (Vector3d.Dot(orientation, localUpVector) > 1)
                {
                    newAttachNodeData.pitchesAwayFromUpVec = true;
                }
                else
                {
                    newAttachNodeData.pitchesAwayFromUpVec = false;
                }


                if (attachNodeDragDict.ContainsKey(orientation))
                {
                    attachNodeData tmp = attachNodeDragDict[orientation];
                    tmp.areaValue += newAttachNodeData.areaValue;
                    attachNodeDragDict[orientation] = tmp;
                }
                else
                {
                    attachNodeDragDict.Add(orientation, newAttachNodeData);
                }


                return;
            }
            //This represents a vertical stack of nodes, for different payload heights, multiple payload fairings, etc.  One node being used means that they are all used
            else if (attachGroupType == AttachGroupType.VERTICAL_NODES)
            {
                double     area = 0;
                AttachNode usedNode;
                Vector2    bounds      = Vector2.zero;
                Vector3    orientation = Vector3.zero;

                foreach (AttachNode attach in attachNodeGroup)
                {
                    //Get area represented by current node
                    bounds = FARGeoUtil.NodeBoundaries(part, attach, Vector3.zero, 0.05f, ThisPartModelTransforms);

                    double tmpArea = (bounds.x + bounds.y);
                    tmpArea *= 0.5;
                    tmpArea *= tmpArea;
                    tmpArea *= Math.PI;       //Calculate area based on circular cross-section

                    if (tmpArea > area)
                    {
                        area     = tmpArea;
                        usedNode = attach;
                    }
                    orientation += attach.position;
                }
                //Get area covered by other parts
                Transform[] OtherTransforms = FARGeoUtil.ChooseNearbyModelTransforms(part, attachNodeGroup, bounds, ThisPartModelTransforms, AllVesselModelTransforms);
                Vector2     otherBounds     = FARGeoUtil.NodeBoundaries(part, attachNodeGroup, Vector3.zero, 0.05f, OtherTransforms);

                double opposedArea = (otherBounds.x + otherBounds.y);
                opposedArea *= 0.5;
                opposedArea *= opposedArea;
                opposedArea *= Math.PI;       //Calculate area based on circular cross-section

                area = FARMathUtil.Clamp(area - opposedArea, 0, double.PositiveInfinity);

                //Update attachNodeDragDict with new data
                attachNodeData newAttachNodeData = new attachNodeData();
                newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                orientation /= attachNodeGroup.Count;

                if (Vector3d.Dot(orientation, localUpVector) > 1)
                {
                    newAttachNodeData.pitchesAwayFromUpVec = true;
                }
                else
                {
                    newAttachNodeData.pitchesAwayFromUpVec = false;
                }


                if (attachNodeDragDict.ContainsKey(orientation))
                {
                    attachNodeData tmp = attachNodeDragDict[orientation];
                    tmp.areaValue += newAttachNodeData.areaValue;
                    attachNodeDragDict[orientation] = tmp;
                }
                else
                {
                    attachNodeDragDict.Add(orientation, newAttachNodeData);
                }

                return;
            }
        }
예제 #22
0
        private void UpdateNonAttachBluntEnds(Dictionary <string, List <AttachNode> > attachNodeGroups, Dictionary <string, AttachGroupType> attachNodeType, Matrix4x4 partUpMatrix, Transform[] ModelTransforms, Transform[] VesselModelTransforms)
        {
            bool upperEndHandled = false;
            bool lowerEndHandled = false;

            Vector2 verticalPartMeshBounds = FARGeoUtil.PartLengthBounds(part, Vector3.zero, partUpMatrix, ModelTransforms);

            foreach (KeyValuePair <string, List <AttachNode> > pair in attachNodeGroups)
            {
                Vector3 avgPos    = Vector3.zero;
                Vector3 avgOrient = Vector3.zero;
                foreach (AttachNode node in pair.Value)
                {
                    avgPos    += node.position;
                    avgOrient += node.orientation;
                }
                avgPos /= pair.Value.Count;
                avgOrient.Normalize();

                if (Mathf.Abs(avgPos.y - verticalPartMeshBounds.x) <= 0.3f)
                {
                    upperEndHandled = true;
                }
                if (Mathf.Abs(avgPos.y - verticalPartMeshBounds.y) <= 0.3f)
                {
                    lowerEndHandled = true;
                }

                if (upperEndHandled && lowerEndHandled)
                {
                    break;
                }
            }

            if (!upperEndHandled)
            {
                Vector3 position = Vector3.up * verticalPartMeshBounds.x;

                Vector2 bounds = FARGeoUtil.NodeBoundaries(part, position, position, Vector3.zero, 0.05f, ModelTransforms);

                double area = (bounds.x + bounds.y);
                area *= 0.5;
                area *= area;
                area *= Math.PI;       //Calculate area based on circular cross-section


                area = FARMathUtil.Clamp(area, 0, double.PositiveInfinity);


                //Update attachNodeDragDict with new data
                attachNodeData newAttachNodeData = new attachNodeData();
                newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                Vector3 orientation = position;

                if (Vector3d.Dot(orientation, localUpVector) > 1)
                {
                    newAttachNodeData.pitchesAwayFromUpVec = true;
                }
                else
                {
                    newAttachNodeData.pitchesAwayFromUpVec = false;
                }


                if (attachNodeDragDict.ContainsKey(orientation))
                {
                    attachNodeData tmp = attachNodeDragDict[orientation];
                    tmp.areaValue += newAttachNodeData.areaValue;
                    attachNodeDragDict[orientation] = tmp;
                }
                else
                {
                    attachNodeDragDict.Add(orientation, newAttachNodeData);
                }
            }

            if (!lowerEndHandled)
            {
                Vector3 position = Vector3.up * verticalPartMeshBounds.y;

                Vector2 bounds = FARGeoUtil.NodeBoundaries(part, position, position, Vector3.zero, 0.05f, ModelTransforms);

                double area = (bounds.x + bounds.y);
                area *= 0.5;
                area *= area;
                area *= Math.PI;       //Calculate area based on circular cross-section


                area = FARMathUtil.Clamp(area, 0, double.PositiveInfinity);


                //Update attachNodeDragDict with new data
                attachNodeData newAttachNodeData = new attachNodeData();
                newAttachNodeData.areaValue = area / FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                Vector3 orientation = position;

                if (Vector3d.Dot(orientation, localUpVector) > 1)
                {
                    newAttachNodeData.pitchesAwayFromUpVec = true;
                }
                else
                {
                    newAttachNodeData.pitchesAwayFromUpVec = false;
                }


                if (attachNodeDragDict.ContainsKey(orientation))
                {
                    attachNodeData tmp = attachNodeDragDict[orientation];
                    tmp.areaValue += newAttachNodeData.areaValue;
                    attachNodeDragDict[orientation] = tmp;
                }
                else
                {
                    attachNodeDragDict.Add(orientation, newAttachNodeData);
                }
            }
        }
예제 #23
0
        private void AttachNodeCdAdjust()
        {
            if (part.Modules.Contains("FARPayloadFairingModule"))       //This doesn't apply blunt drag drag to fairing parts if one of their "exempt" attach nodes is used, indicating attached fairings
            {
                return;
            }
            if (VesselPartList == null)
            {
                UpdateShipPartsList();
            }

            if (attachNodeDragList == null)
            {
                attachNodeDragList = new List <attachNodeData>();
            }

            attachNodeDragList.Clear();

            Transform transform = part.partTransform;

            if (transform == null)
            {
                transform = part.transform;
            }
            if (transform == null)
            {
                Debug.LogError("Part " + part.partInfo.title + " has null transform; drag interactions cannot be applied.");
                return;
            }

            SPlusAttachArea = S;

            Vector3d partUpVector = transform.TransformDirection(localUpVector);

            Bounds[] rendererBounds = part.GetRendererBounds();

            //print("Updating drag for " + part.partInfo.title);
            foreach (AttachNode Attach in part.attachNodes)
            {
                if (Attach.nodeType == AttachNode.NodeType.Stack)
                {
                    if (Attach.id.ToLowerInvariant() == "strut")
                    {
                        continue;
                    }

                    Vector3d relPos = Attach.position + Attach.offset;

                    if (part.Modules.Contains("FARCargoBayModule"))
                    {
                        FARCargoBayModule bay = (FARCargoBayModule)part.Modules["FARCargoBayModule"];

                        Vector3d maxBounds = bay.maxBounds;
                        Vector3d minBounds = bay.minBounds;

                        if (relPos.x < maxBounds.x && relPos.y < maxBounds.y && relPos.z < maxBounds.z && relPos.x > minBounds.x && relPos.y > minBounds.y && relPos.z > minBounds.z)
                        {
                            continue;
                        }
                    }

                    if (Attach.attachedPart != null)
                    {
                        if (AttachedPartIsNotClipping(Attach.attachedPart, rendererBounds))
                        {
                            continue;
                        }
                    }

                    Vector3d origToNode = transform.localToWorldMatrix.MultiplyVector(relPos);
                    double   attachSize = FARMathUtil.Clamp(Attach.size, 0.5, double.PositiveInfinity);

                    if (UnattachedPartRightAgainstNode(origToNode, attachSize, relPos, Attach.attachedPart))
                    {
                        continue;
                    }

                    attachNodeData newAttachNodeData = new attachNodeData();

                    double exposedAttachArea = attachSize * FARAeroUtil.attachNodeRadiusFactor;

                    newAttachNodeData.recipDiameter = 1 / (2 * exposedAttachArea);

                    exposedAttachArea *= exposedAttachArea;
                    exposedAttachArea *= Math.PI * FARAeroUtil.areaFactor;

                    SPlusAttachArea += exposedAttachArea;

                    exposedAttachArea /= FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                    newAttachNodeData.areaValue = exposedAttachArea;
                    if (Vector3d.Dot(origToNode, partUpVector) > 1)
                    {
                        newAttachNodeData.pitchesAwayFromUpVec = true;
                    }
                    else
                    {
                        newAttachNodeData.pitchesAwayFromUpVec = false;
                    }

                    newAttachNodeData.location = transform.worldToLocalMatrix.MultiplyVector(origToNode);

                    attachNodeDragList.Add(newAttachNodeData);
                }
            }
        }
예제 #24
0
        private void AttachNodeCdAdjust()
        {
            //BaseCd = 0;
//            if (!part.Modules.Contains("FARPayloadFairingModule"))
//            {
            if (part.Modules.Contains("FARPayloadFairingModule"))       //This doesn't apply blunt drag drag to fairing parts if one of their "exempt" attach nodes is used, indicating attached fairings
            {
                return;
            }

            if (VesselPartList == null)
            {
                UpdateShipPartsList();
            }

            if (attachNodeDragDict == null)
            {
                attachNodeDragDict = new Dictionary <Vector3d, attachNodeData>();
            }

            attachNodeDragDict.Clear();

            Transform transform = part.partTransform;

            Vector3d partUpVector = transform.TransformDirection(localUpVector);

            //print("Updating drag for " + part.partInfo.title);
            foreach (AttachNode Attach in part.attachNodes)
            {
                if (Attach.nodeType == AttachNode.NodeType.Stack)
                {
                    if (Attach.attachedPart != null)
                    {
                        continue;
                    }
                    if (Attach.id.ToLowerInvariant() == "strut")
                    {
                        continue;
                    }

/*                    string attachId = Attach.id.ToLowerInvariant();
 *                  bool leaveAttachLoop = false;
 *                  foreach (string s in FARMiscData.exemptAttachNodes)
 *                      if (attachId.Contains(s))
 *                      {
 *                          leaveAttachLoop = true;
 *                          break;
 *                      }
 *                  if (leaveAttachLoop)
 *                      continue;*/


                    Ray ray = new Ray();

                    Vector3d relPos = Attach.position + Attach.offset;

                    if (part.Modules.Contains("FARCargoBayModule"))
                    {
                        FARCargoBayModule bay = (FARCargoBayModule)part.Modules["FARCargoBayModule"];

                        Vector3d maxBounds = bay.maxBounds;
                        Vector3d minBounds = bay.minBounds;

                        if (relPos.x < maxBounds.x && relPos.y < maxBounds.y && relPos.z < maxBounds.z && relPos.x > minBounds.x && relPos.y > minBounds.y && relPos.z > minBounds.z)
                        {
                            return;
                        }
                    }

                    Vector3d origToNode = transform.localToWorldMatrix.MultiplyVector(relPos);

                    double mag = (origToNode).magnitude;



                    //print(part.partInfo.title + " Part Loc: " + part.transform.position + " Attach Loc: " + (origToNode + part.transform.position) + " Dist: " + mag);

                    ray.direction = origToNode;
                    ray.origin    = transform.position;

                    double attachSize = FARMathUtil.Clamp(Attach.size, 0.5, double.PositiveInfinity);

                    bool         gotIt = false;
                    RaycastHit[] hits  = Physics.RaycastAll(ray, (float)(mag + attachSize), FARAeroUtil.RaycastMask);
                    foreach (RaycastHit h in hits)
                    {
                        if (h.collider == part.collider)
                        {
                            continue;
                        }
                        if (h.distance < (mag + attachSize) && h.distance > (mag - attachSize))
                        {
                            foreach (Part p in VesselPartList)
                            {
                                if (p.collider == h.collider)
                                {
                                    gotIt = true;
                                    break;
                                }
                            }
                        }
                        if (gotIt)
                        {
                            break;
                        }
                    }

                    if (!gotIt)
                    {
//                            float exposedAttachArea = (Mathf.PI * Mathf.Pow(attachSize * FARAeroUtil.attachNodeRadiusFactor, 2) / Mathf.Clamp(S, 0.01f, Mathf.Infinity));
                        double exposedAttachArea = attachSize * FARAeroUtil.attachNodeRadiusFactor;
                        exposedAttachArea *= exposedAttachArea;
                        exposedAttachArea *= Math.PI * FARAeroUtil.areaFactor;
                        exposedAttachArea /= FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                        attachNodeData newAttachNodeData = new attachNodeData();
                        newAttachNodeData.areaValue = exposedAttachArea;
                        if (Vector3d.Dot(origToNode, partUpVector) > 1)
                        {
                            newAttachNodeData.pitchesAwayFromUpVec = true;
                        }
                        else
                        {
                            newAttachNodeData.pitchesAwayFromUpVec = false;
                        }


                        if (attachNodeDragDict.ContainsKey(transform.worldToLocalMatrix.MultiplyVector(origToNode)))
                        {
                            attachNodeData tmp = attachNodeDragDict[transform.worldToLocalMatrix.MultiplyVector(origToNode)];
                            tmp.areaValue += newAttachNodeData.areaValue;
                            attachNodeDragDict[transform.worldToLocalMatrix.MultiplyVector(origToNode)] = tmp;
                        }
                        else
                        {
                            attachNodeDragDict.Add(part.transform.worldToLocalMatrix.MultiplyVector(origToNode), newAttachNodeData);
                        }
                    }
                }
            }
//            }

            //print(part.partInfo.title + " Num unused Attach Nodes: " + attachNodeDragDict.Count);
        }
예제 #25
0
        private void AttachNodeCdAdjust()
        {
            if (part.Modules.Contains("FARPayloadFairingModule"))       //This doesn't apply blunt drag drag to fairing parts if one of their "exempt" attach nodes is used, indicating attached fairings
            {
                return;
            }
            if (VesselPartList == null)
            {
                UpdateShipPartsList();
            }

            if (attachNodeDragList == null)
            {
                attachNodeDragList = new List <attachNodeData>();
            }

            attachNodeDragList.Clear();

            Transform transform = part.transform;

            if (transform == null)
            {
                transform = part.transform;
            }
            if (transform == null)
            {
                Debug.LogError("Part " + part.partInfo.title + " has null transform; drag interactions cannot be applied.");
                return;
            }

            SPlusAttachArea = S;

            Vector3d partUpVector = transform.TransformDirection(localUpVector);

            //print("Updating drag for " + part.partInfo.title);
            foreach (AttachNode attach in part.attachNodes)
            {
                if (attach.nodeType == AttachNode.NodeType.Stack)
                {
                    if (attach.id.ToLowerInvariant() == "strut")
                    {
                        continue;
                    }

                    Vector3d relPos = attach.position;// +Attach.offset;

                    if (part.Modules.Contains("FARCargoBayModule"))
                    {
                        FARCargoBayModule bay = (FARCargoBayModule)part.Modules["FARCargoBayModule"];

                        if (bay.bayBounds.Contains(relPos))
                        {
                            continue;
                        }
                    }

                    Vector3d origToNode = transform.localToWorldMatrix.MultiplyVector(relPos);
                    double   attachSize = FARMathUtil.Clamp(attach.size, 0.5, double.PositiveInfinity);

                    if (attach.attachedPart != null)
                    {
                        Vector3           location = attach.attachedPart.transform.position;
                        FARBasicDragModel d        = attach.attachedPart.GetComponent <FARBasicDragModel>();
                        if (d != null)
                        {
                            location += attach.attachedPart.transform.localToWorldMatrix.MultiplyVector(d.CenterOfDrag);
                        }

                        //Debug.Log(Attach.attachedPart.partInfo.title + " " + location + " " + Attach.attachedPart.transform.position + " " + (origToNode + part.transform.position));

                        if (AttachedPartCoDIsFurtherThanAttachLocation(location, origToNode))
                        {
                            continue;
                        }
                        if (AttachedPartIsNotClipping(location, PartBounds))
                        {
                            if (d != null)
                            {
                                location  = this.part.transform.localToWorldMatrix.MultiplyVector(this.CenterOfDrag);
                                location += this.part.transform.position;
                                if (d.AttachedPartIsNotClipping(location, d.PartBounds))
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                continue;
                            }
                        }
                        //this is a bit of a hack to make intakes function slightly better, since very thin ones seem to have issues.
                        ModuleResourceIntake intake = attach.attachedPart.GetComponent <ModuleResourceIntake>();
                        if (intake != null)
                        {
                            Transform intakeTrans = attach.attachedPart.FindModelTransform(intake.intakeTransformName);
                            if ((object)intakeTrans != null)
                            {
                                Vector3 intakeForwardVec = (intakeTrans.forward);
                                //Vector3 attachOrientation = this.part.transform.localToWorldMatrix.MultiplyVector(attach.orientation);

                                int intakeOrientSign = Math.Sign(Vector3.Dot((Vector3)origToNode, intakeForwardVec));
                                //int attachLocSign = Math.Sign(Vector3.Dot(attachOrientation, (Vector3)origToNode));
                                //int intakeOrientationSign = Math.Sign(Vector3.Dot(intakeForwardVec, (Vector3)origToNode));
                                if (intakeOrientSign > 0)
                                {
                                    continue;
                                }
                            }
                        }
                    }


                    if (UnattachedPartRightAgainstNode(origToNode, attachSize, attach.attachedPart))
                    {
                        continue;
                    }

                    attachNodeData newAttachNodeData = new attachNodeData();

                    double exposedAttachArea = attachSize * FARAeroUtil.attachNodeRadiusFactor;

                    newAttachNodeData.recipDiameter = 1 / (2 * exposedAttachArea);

                    exposedAttachArea *= exposedAttachArea;
                    exposedAttachArea *= Math.PI * FARAeroUtil.areaFactor;

                    SPlusAttachArea += exposedAttachArea;

                    exposedAttachArea /= FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                    newAttachNodeData.areaValue = exposedAttachArea;
                    if (Vector3d.Dot(origToNode, partUpVector) > 0)
                    {
                        newAttachNodeData.pitchesAwayFromUpVec = true;
                    }
                    else
                    {
                        newAttachNodeData.pitchesAwayFromUpVec = false;
                    }

                    newAttachNodeData.location = relPos;
                    //Debug.Log(part.partInfo.title + " found open node");
                    attachNodeDragList.Add(newAttachNodeData);
                }
            }
        }
예제 #26
0
        private void AttachNodeCdAdjust()
        {
            if (part.Modules.Contains("FARPayloadFairingModule"))       //This doesn't apply blunt drag drag to fairing parts if one of their "exempt" attach nodes is used, indicating attached fairings
            {
                return;
            }
            if (VesselPartList == null)
            {
                UpdateShipPartsList();
            }

            if (attachNodeDragList == null)
            {
                attachNodeDragList = new List <attachNodeData>();
            }

            attachNodeDragList.Clear();

            Transform transform = part.partTransform;

            if (transform == null)
            {
                transform = part.transform;
            }
            if (transform == null)
            {
                Debug.LogError("Part " + part.partInfo.title + " has null transform; drag interactions cannot be applied.");
                return;
            }

            SPlusAttachArea = S;

            Vector3d partUpVector = transform.TransformDirection(localUpVector);

            //print("Updating drag for " + part.partInfo.title);
            foreach (AttachNode Attach in part.attachNodes)
            {
                if (Attach.nodeType == AttachNode.NodeType.Stack)
                {
                    if (Attach.attachedPart != null)
                    {
                        continue;
                    }
                    if (Attach.id.ToLowerInvariant() == "strut")
                    {
                        continue;
                    }

                    Ray ray = new Ray();

                    Vector3d relPos = Attach.position + Attach.offset;

                    if (part.Modules.Contains("FARCargoBayModule"))
                    {
                        FARCargoBayModule bay = (FARCargoBayModule)part.Modules["FARCargoBayModule"];

                        Vector3d maxBounds = bay.maxBounds;
                        Vector3d minBounds = bay.minBounds;

                        if (relPos.x < maxBounds.x && relPos.y < maxBounds.y && relPos.z < maxBounds.z && relPos.x > minBounds.x && relPos.y > minBounds.y && relPos.z > minBounds.z)
                        {
                            return;
                        }
                    }

                    Vector3d origToNode = transform.localToWorldMatrix.MultiplyVector(relPos);

                    double mag = (origToNode).magnitude;



                    //print(part.partInfo.title + " Part Loc: " + part.transform.position + " Attach Loc: " + (origToNode + part.transform.position) + " Dist: " + mag);

                    ray.direction = origToNode;
                    ray.origin    = transform.position;

                    double attachSize = FARMathUtil.Clamp(Attach.size, 0.5, double.PositiveInfinity);

                    bool         gotIt = false;
                    RaycastHit[] hits  = Physics.RaycastAll(ray, (float)(mag + attachSize), FARAeroUtil.RaycastMask);
                    foreach (RaycastHit h in hits)
                    {
                        if (h.collider == part.collider)
                        {
                            continue;
                        }
                        if (h.distance < (mag + attachSize) && h.distance > (mag - attachSize))
                        {
                            foreach (Part p in VesselPartList)
                            {
                                if (p.collider == h.collider)
                                {
                                    gotIt = true;
                                    break;
                                }
                            }
                        }
                        if (gotIt)
                        {
                            break;
                        }
                    }

                    if (!gotIt)
                    {
                        double exposedAttachArea = attachSize * FARAeroUtil.attachNodeRadiusFactor;
                        exposedAttachArea *= exposedAttachArea;
                        exposedAttachArea *= Math.PI * FARAeroUtil.areaFactor;

                        SPlusAttachArea += exposedAttachArea;

                        exposedAttachArea /= FARMathUtil.Clamp(S, 0.01, double.PositiveInfinity);

                        attachNodeData newAttachNodeData = new attachNodeData();
                        newAttachNodeData.areaValue = exposedAttachArea;
                        if (Vector3d.Dot(origToNode, partUpVector) > 1)
                        {
                            newAttachNodeData.pitchesAwayFromUpVec = true;
                        }
                        else
                        {
                            newAttachNodeData.pitchesAwayFromUpVec = false;
                        }

                        newAttachNodeData.location = transform.worldToLocalMatrix.MultiplyVector(origToNode);

                        attachNodeDragList.Add(newAttachNodeData);
                    }
                }
            }
        }