Esempio n. 1
0
        public void recalcShape()
        {
            var scan = scanPayload();

            //  Check for reversed bases (inline fairings).

            float topY   = 0;
            float topRad = 0;

            AttachNode topSideNode = null;

            bool isInline = false;

            var adapter = part.GetComponent <ProceduralFairingAdapter>();

            if (adapter)
            {
                isInline = true;

                topY = adapter.height + adapter.extraHeight;

                if (topY < scan.ofs)
                {
                    topY = scan.ofs;
                }

                topRad = adapter.topRadius;
            }
            else if (scan.targets.Count > 0)
            {
                isInline = true;

                var topBase = scan.targets [0].GetComponent <ProceduralFairingBase>();

                topY = scan.w2l.MultiplyPoint3x4(topBase.part.transform.position).y;

                if (topY < scan.ofs)
                {
                    topY = scan.ofs;
                }

                topSideNode = HasNodeComponent <ProceduralFairingSide>(topBase.part.FindAttachNodes("connect"));

                topRad = topBase.baseSize * 0.5f;
            }

            //  No payload case.

            if (scan.profile.Count <= 0)
            {
                scan.profile.Add(extraRadius);
            }

            //  Fill profile outline (for debugging).

            if (line)
            {
                line.positionCount = scan.profile.Count * 2 + 2;

                float prevRad = 0;

                int hi = 0;

                for (int i = 0; i < scan.profile.Count; i++)
                {
                    var r = scan.profile [i];

                    line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0));
                    line.SetPosition(hi * 2 + 1, new Vector3(r, hi * verticalStep + scan.ofs, 0));

                    hi++; prevRad = r;
                }

                line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0));
                line.SetPosition(hi * 2 + 1, new Vector3(0, hi * verticalStep + scan.ofs, 0));
            }

            //  Check for attached side parts.

            var attached = part.FindAttachNodes("connect");

            //  Get the number of available fairing attachment nodes from NodeNumberTweaker.

            var nnt = part.GetComponent <KzNodeNumberTweaker>();

            int numSideParts = nnt.numNodes;

            var sideNode = HasNodeComponent <ProceduralFairingSide>(attached);

            var baseConeShape = new Vector4(0, 0, 0, 0);
            var noseConeShape = new Vector4(0, 0, 0, 0);
            var mappingScale  = new Vector2(1024, 1024);
            var stripMapping  = new Vector2(992, 1024);
            var horMapping    = new Vector4(0, 480, 512, 992);
            var vertMapping   = new Vector4(0, 160, 704, 1024);

            float baseCurveStartX = 0;
            float baseCurveStartY = 0;
            float baseCurveEndX   = 0;
            float baseCurveEndY   = 0;

            int baseConeSegments = 1;

            float noseCurveStartX = 0;
            float noseCurveStartY = 0;
            float noseCurveEndX   = 0;
            float noseCurveEndY   = 0;

            int   noseConeSegments = 1;
            float noseHeightRatio  = 1;
            float minBaseConeAngle = 20;

            float density = 0;

            if (sideNode != null)
            {
                var sf = sideNode.attachedPart.GetComponent <ProceduralFairingSide>();

                mappingScale     = sf.mappingScale;
                stripMapping     = sf.stripMapping;
                horMapping       = sf.horMapping;
                vertMapping      = sf.vertMapping;
                noseHeightRatio  = sf.noseHeightRatio;
                minBaseConeAngle = sf.minBaseConeAngle;
                baseConeShape    = sf.baseConeShape;
                baseCurveStartX  = sf.baseCurveStartX;
                baseCurveStartY  = sf.baseCurveStartY;
                baseCurveEndX    = sf.baseCurveEndX;
                baseCurveEndY    = sf.baseCurveEndY;
                baseConeSegments = (int)sf.baseConeSegments;
                noseConeShape    = sf.noseConeShape;
                noseCurveStartX  = sf.noseCurveStartX;
                noseCurveStartY  = sf.noseCurveStartY;
                noseCurveEndX    = sf.noseCurveEndX;
                noseCurveEndY    = sf.noseCurveEndY;
                noseConeSegments = (int)sf.noseConeSegments;
                density          = sf.density;
            }

            //   Compute the fairing shape.

            float baseRad        = baseSize * 0.5f;
            float minBaseConeTan = Mathf.Tan(minBaseConeAngle * Mathf.Deg2Rad);

            float cylStart = 0;
            float maxRad;

            int profTop = scan.profile.Count;

            if (isInline)
            {
                profTop = Mathf.CeilToInt((topY - scan.ofs) / verticalStep);

                if (profTop > scan.profile.Count)
                {
                    profTop = scan.profile.Count;
                }

                maxRad = 0;

                for (int i = 0; i < profTop; ++i)
                {
                    maxRad = Mathf.Max(maxRad, scan.profile [i]);
                }

                maxRad = Mathf.Max(maxRad, topRad);
            }
            else
            {
                maxRad = PFUtils.GetMaxValueFromList(scan.profile);
            }

            if (maxRad > baseRad)
            {
                //  Try to fit the base cone as high as possible.

                cylStart = scan.ofs;

                for (int i = 1; i < scan.profile.Count; ++i)
                {
                    float y  = i * verticalStep + scan.ofs;
                    float r0 = baseRad;
                    float k  = (maxRad - r0) / y;

                    if (k < minBaseConeTan)
                    {
                        break;
                    }

                    bool ok = true;

                    float r = r0 + k * scan.ofs;

                    for (int j = 0; j < i; ++j, r += k * verticalStep)
                    {
                        if (scan.profile [j] > r)
                        {
                            ok = false;

                            break;
                        }
                    }

                    if (!ok)
                    {
                        break;
                    }

                    cylStart = y;
                }
            }
            else
            {
                //  No base cone, just a cylinder and a nose.

                maxRad = baseRad;
            }

            float cylEnd = scan.profile.Count * verticalStep + scan.ofs;

            if (isInline)
            {
                float r0 = topRad;

                if (profTop > 0 && profTop < scan.profile.Count)
                {
                    r0 = Mathf.Max(r0, scan.profile [profTop - 1]);

                    if (profTop - 2 >= 0)
                    {
                        r0 = Mathf.Max(r0, scan.profile [profTop - 2]);
                    }
                }

                if (maxRad > r0)
                {
                    if (cylEnd > topY)
                    {
                        cylEnd = topY - verticalStep;
                    }

                    //  Try to fit the top cone as low as possible.

                    for (int i = profTop - 1; i >= 0; --i)
                    {
                        float y = i * verticalStep + scan.ofs;
                        float k = (maxRad - r0) / (y - topY);

                        bool ok = true;

                        float r = maxRad + k * verticalStep;

                        for (int j = i; j < profTop; ++j, r += k * verticalStep)
                        {
                            if (r < r0)
                            {
                                r = r0;
                            }

                            if (scan.profile [j] > r)
                            {
                                ok = false;

                                break;
                            }
                        }

                        if (!ok)
                        {
                            break;
                        }

                        cylEnd = y;
                    }
                }
                else
                {
                    cylEnd = topY;
                }
            }
            else
            {
                //  Try to fit the nose cone as low as possible.

                for (int i = scan.profile.Count - 1; i >= 0; --i)
                {
                    float s = verticalStep / noseHeightRatio;

                    bool ok = true;

                    float r = maxRad - s;

                    for (int j = i; j < scan.profile.Count; ++j, r -= s)
                    {
                        if (scan.profile [j] > r)
                        {
                            ok = false;

                            break;
                        }
                    }

                    if (!ok)
                    {
                        break;
                    }

                    float y = i * verticalStep + scan.ofs;

                    cylEnd = y;
                }
            }

            if (autoShape)
            {
                manualMaxSize  = maxRad * 2;
                manualCylStart = cylStart;
                manualCylEnd   = cylEnd;
            }
            else
            {
                maxRad   = manualMaxSize * 0.5f;
                cylStart = manualCylStart;
                cylEnd   = manualCylEnd;
            }

            if (cylStart > cylEnd)
            {
                cylStart = cylEnd;
            }

            //  Build the fairing shape line.

            Vector3 [] shape;

            if (isInline)
            {
                shape = buildInlineFairingShape(baseRad, maxRad, topRad, cylStart, cylEnd, topY, baseConeShape, baseConeSegments, vertMapping, mappingScale.y);
            }
            else
            {
                shape = buildFairingShape(baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, baseConeShape, noseConeShape, baseConeSegments, noseConeSegments, vertMapping, mappingScale.y);
            }

            if (sideNode == null && topSideNode == null)
            {
                //  No side parts - fill fairing outlines.

                for (int j = 0; j < outline.Count; j++)
                {
                    var lr = outline [j];

                    lr.positionCount = shape.Length;

                    for (int i = 0; i < shape.Length; ++i)
                    {
                        lr.SetPosition(i, new Vector3(shape [i].x, shape [i].y));
                    }
                }
            }
            else
            {
                for (int j = 0; j < outline.Count; j++)
                {
                    var lr = outline [j];

                    lr.positionCount = 0;
                }
            }

            //  Rebuild the side parts.

            int numSegs = circleSegments / numSideParts;

            if (numSegs < 2)
            {
                numSegs = 2;
            }

            for (int i = 0; i < attached.Length; i++)
            {
                var sn = attached [i];
                var sp = sn.attachedPart;

                if (!sp)
                {
                    continue;
                }

                var sf = sp.GetComponent <ProceduralFairingSide>();

                if (!sf)
                {
                    continue;
                }

                if (sf.shapeLock)
                {
                    continue;
                }

                var mf = sp.FindModelComponent <MeshFilter>("model");

                if (!mf)
                {
                    Debug.LogError("[PF]: No model in side fairing!", sp);

                    continue;
                }

                var nodePos = sn.position;

                mf.transform.position = part.transform.position;
                mf.transform.rotation = part.transform.rotation;

                float ra = Mathf.Atan2(-nodePos.z, nodePos.x) * Mathf.Rad2Deg;

                mf.transform.Rotate(0, ra, 0);

                if (sf.meshPos == mf.transform.localPosition &&
                    sf.meshRot == mf.transform.localRotation &&
                    sf.numSegs == numSegs &&
                    sf.numSideParts == numSideParts &&
                    sf.baseRad.Equals(baseRad) &&
                    sf.maxRad.Equals(maxRad) &&
                    sf.cylStart.Equals(cylStart) &&
                    sf.cylEnd.Equals(cylEnd) &&
                    sf.topRad.Equals(topRad) &&
                    sf.inlineHeight.Equals(topY) &&
                    sf.sideThickness.Equals(sideThickness) &&
                    !sf.baseCurveStartX.Equals(baseCurveStartX) &&
                    !sf.baseCurveStartY.Equals(baseCurveStartY) &&
                    !sf.baseCurveEndX.Equals(baseCurveEndX) &&
                    !sf.baseCurveEndY.Equals(baseCurveEndY) &&
                    !sf.baseConeSegments.Equals(baseConeSegments) &&
                    !sf.noseCurveStartX.Equals(noseCurveStartX) &&
                    !sf.noseCurveStartY.Equals(noseCurveStartY) &&
                    !sf.noseCurveEndX.Equals(noseCurveEndX) &&
                    !sf.noseCurveEndY.Equals(noseCurveEndY) &&
                    !sf.noseConeSegments.Equals(noseConeSegments) &&
                    !sf.noseHeightRatio.Equals(noseHeightRatio) &&
                    !sf.density.Equals(density))
                {
                    continue;
                }

                sf.meshPos          = mf.transform.localPosition;
                sf.meshRot          = mf.transform.localRotation;
                sf.numSegs          = numSegs;
                sf.numSideParts     = numSideParts;
                sf.baseRad          = baseRad;
                sf.maxRad           = maxRad;
                sf.cylStart         = cylStart;
                sf.cylEnd           = cylEnd;
                sf.topRad           = topRad;
                sf.inlineHeight     = topY;
                sf.sideThickness    = sideThickness;
                sf.baseCurveStartX  = baseCurveStartX;
                sf.baseCurveStartY  = baseCurveStartY;
                sf.baseCurveEndX    = baseCurveEndX;
                sf.baseCurveEndY    = baseCurveEndY;
                sf.baseConeSegments = baseConeSegments;
                sf.noseCurveStartX  = noseCurveStartX;
                sf.noseCurveStartY  = noseCurveStartY;
                sf.noseCurveEndX    = noseCurveEndX;
                sf.noseCurveEndY    = noseCurveEndY;
                sf.noseConeSegments = noseConeSegments;
                sf.noseHeightRatio  = noseHeightRatio;
                sf.density          = density;

                sf.rebuildMesh();
            }

            var shielding = part.GetComponent <KzFairingBaseShielding>();

            if (shielding)
            {
                shielding.reset();
            }
        }