Пример #1
0
        /// <summary>
        /// These are just a few different attempts to figure drag for various blunt bodies
        /// </summary>
        private void DragModel(Vector3d local_velocity, double M, double rho)
        {
            // Has the same x/y/z as the vertices in PartMaxBoundaries etc
            Vector3d model_velocity = to_model_rotation * local_velocity;

            double viscousLift, potentialLift, newtonianLift;

            viscousLift = potentialLift = newtonianLift = 0;
            double CdAdd = 0;
            //float AxialProportion = Vector3.Dot(localUpVector, local_velocity);
            double AxialProportion     = model_velocity.y;
            float  AxialProportion_flt = (float)model_velocity.y;
            double AxialProportion_2   = AxialProportion * AxialProportion;
            double OneMinusAxial_2     = Math.Abs(1 - AxialProportion_2);
            double M_2       = M * M;
            double M_2_recip = 1 / M_2;
            double maxPressureCoeff;

            if (FARDebugValues.useSplinesForSupersonicMath)
            {
                maxPressureCoeff = FARAeroUtil.MaxPressureCoefficient.Evaluate((float)M);
            }
            else
            {
                maxPressureCoeff = FARAeroUtil.MaxPressureCoefficientCalc(M);
            }

            double sepFlowCd = SeparatedFlowDrag(M, M_2, M_2_recip);

            //This handles elliptical and other non-circular cross sections
            //float crossflowParameter = Vector3.Dot(localForwardVector, Vector3.Exclude(localUpVector, local_velocity).normalized);
            //crossflowParameter *= crossflowParameter;
            double crossflowParameter = model_velocity.z * model_velocity.z;
            double crossflow          = model_velocity.x * model_velocity.x + crossflowParameter;

            if (crossflow != 0)
            {
                crossflowParameter /= crossflow;
            }

            crossflowParameter = crossflowParameter * majorMinorAxisRatio + (1 - crossflowParameter) / majorMinorAxisRatio;
            if (AxialProportion_2 > 0.98)
            {
                crossflowParameter *= 50 * OneMinusAxial_2;
            }

            Cd += CdCurve.Evaluate(AxialProportion_flt);



            viscousLift = ClViscousCurve.Evaluate(AxialProportion_flt);

            double axialDirectionFactor = cosAngleCutoff * AxialProportion;

            if (axialDirectionFactor > 0)
            {
                Cd = Math.Min(Cd, sepFlowCd * taperCrossSectionAreaRatio) * AxialProportion_2 + Cd * OneMinusAxial_2;
            }
            else
            {
                Cd = Math.Min(Cd, maxPressureCoeff * taperCrossSectionAreaRatio) * AxialProportion_2 + Cd * OneMinusAxial_2;
            }

            if (M_2 > 1)
            {
                potentialLift = ClPotentialCurve.Evaluate(AxialProportion_flt) * M_2_recip;
            }
            else
            {
                potentialLift = ClPotentialCurve.Evaluate(AxialProportion_flt);
            }


            Cm = CmCurve.Evaluate(AxialProportion_flt) * 0.1;

            CoDshift = CenterOfDrag;

            double MachMultiplier = MachDragEffect(M);

            Cd *= MachMultiplier;

            if (HighLogic.LoadedSceneIsFlight)
            {
                Cd += FARAeroUtil.SkinFrictionDrag(rho, lengthScale, local_velocity.magnitude, M, FlightGlobals.getExternalTemperature(part.transform.position) + FARAeroUtil.currentBodyTemp);       //Skin friction drag
            }
            else
            {
                Cd += 0.005;
            }

            for (int i = 0; i < attachNodeDragList.Count; i++)
            {
                attachNodeData node = attachNodeDragList[i];

                double dotProd = Vector3d.Dot(node.location.normalized, local_velocity);
                double tmp     = 0;
                double Cltmp   = 0;
                if (dotProd < 0)
                {
                    dotProd *= dotProd;
                    tmp      = sepFlowCd;

                    //                    Cltmp = tmp * (dotProd - 1);
                    //                    Cltmp *= pair.Value;

                    tmp *= node.areaValue * dotProd;


                    //                    Vector3 CoDshiftOffset = -Vector3.Exclude(pair.Key, part.transform.worldToLocalMatrix.MultiplyVector(velocity.normalized)).normalized;
                    //                    CoDshiftOffset *= Mathf.Sqrt(Mathf.Clamp01(1 - dotProd));
                    //                    CoDshiftOffset *= Mathf.Sqrt(1.5f * pair.Value);

                    CoDshift += node.location * (tmp / (tmp + Cd));
                }
                else
                {
                    Vector3d worldPairVec = part_transform.TransformDirection(node.location.normalized);
                    double   dotProd_2    = dotProd * dotProd;
                    double   liftProd_2   = 1 - dotProd_2;
                    double   liftProd     = Vector3d.Dot(worldPairVec, liftDir);

                    double forceCoefficient = dotProd_2 * bluntBodyCosForceParameter;
                    forceCoefficient += liftProd_2 * bluntBodySinForceParameter;
                    forceCoefficient *= maxPressureCoeff * node.areaValue;      //force applied perependicular to the flat end of the node

                    tmp   = forceCoefficient * dotProd;
                    Cltmp = -forceCoefficient * liftProd;       //negative because lift is in opposite direction of projection of velocity vector onto node direction

                    double Cmtmp = dotProd * liftProd * bluntBodyMomentParameter;
                    Cmtmp *= node.areaValue * node.recipDiameter;

                    if (!node.pitchesAwayFromUpVec)
                    {
                        Cmtmp *= -1;
                    }

                    Cm += Cmtmp;

                    double tmpCdCl = Math.Sqrt(tmp * tmp + Cltmp * Cltmp);
                    CoDshift += node.location * (tmpCdCl / (tmpCdCl + Math.Sqrt(Cd * Cd + Cl * Cl)));

                    /*double liftProd = Vector3d.Dot(worldPairVec, liftDir);
                     *
                     * tmp = maxPressureCoeff * dotProd_2 * dotProd;
                     * tmp *= node.areaValue;
                     *
                     * Cltmp = maxPressureCoeff * dotProd_2 * liftProd;
                     * Cltmp *= -node.areaValue;
                     *
                     * double radius = Math.Sqrt(node.areaValue / Math.PI);
                     * Vector3 CoDshiftOffset = Vector3.Exclude(node.location, local_velocity).normalized;
                     * CoDshiftOffset *= (float)(Math.Abs(liftProd) * radius * 0.4);
                     *
                     * double Cmtmp;
                     * if (node.pitchesAwayFromUpVec)
                     *  Cmtmp = -0.325 * radius * node.areaValue / S * Math.Abs(liftProd);
                     * else
                     *  Cmtmp = 0.325 * radius * node.areaValue / S * Math.Abs(liftProd);
                     *
                     * double tmpCdCl = Math.Sqrt(tmp * tmp + Cltmp * Cltmp);
                     *
                     * CoDshift += node.location * (tmpCdCl / (tmpCdCl + Math.Sqrt(Cd * Cd + Cl * Cl))) + CoDshiftOffset;
                     *
                     * Cm += Cmtmp;*/
                }

                CdAdd         += tmp;
                newtonianLift += Cltmp;
            }


            viscousLift *= MachMultiplier;
            Cd          += CdAdd;
            Cl           = viscousLift + potentialLift;
            Cl          *= crossflowParameter;
            Cm          *= crossflowParameter;

            Cl += newtonianLift;

//            Debug.Log("Cd = " + Cd + " Cl = " + Cl + " Cm = " + Cm + "\nPot Lift = " + potentialLift + " Visc Lift = " + viscousLift + " Newt Lift = " + newtonianLift + "\nCdAdd = " + CdAdd + " sepFlowCd = " + sepFlowCd + " maxPressureCoeff = " + maxPressureCoeff + "\ntaperCrossSectionAreaRatio = " + taperCrossSectionAreaRatio + " crossflowParameter = " + crossflowParameter);
        }
Пример #2
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);
                }
            }
        }
Пример #3
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);
                }
            }
        }
Пример #4
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);
                }
            }
        }
Пример #5
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);
        }
Пример #6
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;
            }
        }
        /*
        private Dictionary<string, List<AttachNode>> GetAttachNodeGroups()
        {
            Dictionary<string, List<AttachNode>> attachNodeGroups = new Dictionary<string, List<AttachNode>>();

            List<AttachNode> rawNodeList = part.attachNodes;

            foreach (AttachNode attach in rawNodeList)
            {
                if (attach.nodeType == AttachNode.NodeType.Stack)
                {
                    string attachName = attach.id;
                    attachName = Regex.Match(attachName, @"^[^\d]+").Value;

                    List<AttachNode> tmpAttachNodeList;
                    bool groupExists = attachNodeGroups.TryGetValue(attachName, out tmpAttachNodeList);

                    if (groupExists)
                    {
                        tmpAttachNodeList.Add(attach);
                        attachNodeGroups[attachName] = tmpAttachNodeList;
                    }
                    else
                    {
                        tmpAttachNodeList = new List<AttachNode>();
                        tmpAttachNodeList.Add(attach);
                        attachNodeGroups[attachName] = tmpAttachNodeList;
                    }
                }
            }
            return attachNodeGroups;
        }

        private Dictionary<string, AttachGroupType> GetAttachGroupTypes(Dictionary<string, List<AttachNode>> attachNodeGroups)
        {
            Dictionary<string, AttachGroupType> attachGroupTypes = new Dictionary<string, AttachGroupType>();

            foreach (KeyValuePair<string, List<AttachNode>> nodeGroup in attachNodeGroups)
            {
                //A single node in the group means that it is an independent node
                if (nodeGroup.Value.Count <= 1)
                {
                    attachGroupTypes.Add(nodeGroup.Key, AttachGroupType.INDEPENDENT_NODE);
                    continue;
                }

                Vector3 avgPos = Vector3.zero;

                foreach (AttachNode attach in nodeGroup.Value)
                {
                    avgPos += attach.position;
                }
                avgPos /= nodeGroup.Value.Count;

                float groupingFactor = 0;

                foreach (AttachNode attach in nodeGroup.Value)
                {
                    groupingFactor += Mathf.Abs(Vector3.Dot(attach.position - avgPos, attach.orientation));
                }
                groupingFactor /= nodeGroup.Value.Count;

                if (groupingFactor > 0.8f)      //Node group is mainly aligned; vertical node group
                {
                    attachGroupTypes.Add(nodeGroup.Key, AttachGroupType.VERTICAL_NODES);
                    continue;
                }
                else
                {
                    attachGroupTypes.Add(nodeGroup.Key, AttachGroupType.PARALLEL_NODES);
                    continue;
                }

            }

            return attachGroupTypes;
        }

        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;
            }
        }

        private void HandleAttachNodeCd()
        {
            if(VesselPartList == null)
                UpdateShipPartsList();

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

            attachNodeDragDict.Clear();

            Dictionary<string, List<AttachNode>> attachNodeGroups = GetAttachNodeGroups();
            Dictionary<string, AttachGroupType> attachNodeType = GetAttachGroupTypes(attachNodeGroups);

            if (VesselModelTransforms == null)
            {
                if (HighLogic.LoadedScene == GameScenes.EDITOR)
                    VesselModelTransforms = FARGeoUtil.VesselModelTransforms(EditorLogic.SortedShipList);
                else
                    VesselModelTransforms = FARGeoUtil.VesselModelTransforms(vessel);

                foreach (Part p in VesselPartList)
                    foreach(PartModule m in p.Modules)
                        if (m is FARBasicDragModel)
                        {
                            (m as FARBasicDragModel).VesselModelTransforms = this.VesselModelTransforms;
                            continue;
                        }
            }

            foreach (KeyValuePair<string, List<AttachNode>> attachGroup in attachNodeGroups)
            {
                UpdateAttachGroupDrag(attachGroup.Value, attachNodeType[attachGroup.Key], PartModelTransforms, VesselModelTransforms);
            }

            //UpdateNonAttachBluntEnds(attachNodeGroups, attachNodeType, FARGeoUtil.WorldToPartUpMatrix(part), PartModelTransforms, VesselModelTransforms);
            VesselModelTransforms = null;
        }

        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);
            }

        }
        */
        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;

            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;

                        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);
                    }
                }
            }
        }
        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);
            }
        }
        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;
            }
        }
Пример #10
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);
                    }
                }
            }
        }