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 == null) { continue; } if (p == parentWingPart) { continue; } FARWingAerodynamicModel w = p.GetComponent <FARWingAerodynamicModel>(); if (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); double tmp2 = Math.Abs(Vector3.Dot(parentWingPart.partTransform.forward, w.part.partTransform.forward)); tmp = 1 - (1 - tmp) * tmp2; interferencevalue = Math.Min(tmp, interferencevalue); gotSomething = true; break; } } } if (gotSomething) { break; } } } } return(interferencevalue); }
/// <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.NearlyEqual(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; } }
private void AoAOffsetFromFlapDeflection() { AoAdesiredFlap = maxdeflectFlap * flapLocation * flapDeflectionLevel * 0.33333333333; AoAdesiredFlap = FARMathUtil.Clamp(AoAdesiredFlap, -Math.Abs(maxdeflectFlap), Math.Abs(maxdeflectFlap)); }
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)); BrakeRudderLocation = Vector3.Dot(partTransform.forward, rootTransform.forward); BrakeRudderSide = Mathf.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; } if (brakeRudder != 0.0) { AoAdesiredControl += BrakeRudderLocation * Math.Max(0.0, BrakeRudderSide * yawaxis) * brakeRudder * 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 (part.symMethod == SymmetryMethod.Mirror || part.symmetryCounterparts.Count < 1) { if (HighLogic.LoadedSceneIsFlight) { flapLocation = Math.Sign(Vector3.Dot(vessel.ReferenceTransform.forward, part.partTransform.forward)); //figure out which way is up } else { flapLocation = Math.Sign(Vector3.Dot(EditorLogic.RootPart.partTransform.forward, part.partTransform.forward)); //figure out which way is up } spoilerLocation = -flapLocation; } else if (part.parent != null) { flapLocation = Math.Sign(Vector3.Dot(part.partTransform.position - part.parent.partTransform.position, part.partTransform.forward)); 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(); } }
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); } } } }