コード例 #1
0
        private ProfilePoint CreatePoint(float t, ref int colliderTri)
        {
            // ReSharper disable once InconsistentNaming
            // B(t) = (1-t)^3 p0 + t(1-t)^2 p1 + t^2(1-t) p2 + t^3 p3
            Vector2 Bt = B(t);

            // ReSharper disable once InconsistentNaming
            // B'(t) = (1-t)^2 (p1-p0) + t(1-t) (p2-p1) + t^2 (p3-p2)
            Vector2 Btdt = Bdt(t);

            // normalized perpendicular to tangent (derivative)
            Vector2 norm = new Vector2(Btdt.y, -Btdt.x / 2f).normalized;

            // Count the number of triangles
            CirclePoints colliderCirc = CirclePoints.ForDiameter(Bt.x, MaxCircleError * 4f, 4, 16);

            colliderTri += (colliderCirc.totVertexes + 1) * 2;

            //Debug.LogWarning(string.Format("Creating profile point t={0:F3} coord=({1:F3}, {2:F3})  normal=({3:F3}, {4:F3})", t, Bt.x, Bt.y, norm.x, norm.y));

            // We can have a maxium of 255 triangles in the collider. Will leave a bit of breathing room at the top.
            return(colliderTri <= 220 ?
                   new ProfilePoint(Bt.x, Bt.y, t, norm, colliderCirc: colliderCirc) :
                   new ProfilePoint(Bt.x, Bt.y, t, norm, inCollider: false));
        }
コード例 #2
0
        internal override void UpdateShape(bool forceUpdate = true)
        {
            part.CoMOffset = CoMOffset;
            Volume         = CalculateVolume();
            LinkedList <ProfilePoint> points = new LinkedList <ProfilePoint>();

            if (fillet == 0)
            {
                // Reduces down to a cylinder part.
                points.AddLast(new ProfilePoint(diameter, -0.5f * length, 0f, new Vector2(1, 0)));
                points.AddLast(new ProfilePoint(diameter, 0.5f * length, 1f, new Vector2(1, 0)));
            }
            else
            {
                float bodyLength   = length - fillet;
                float endDiameter  = diameter - fillet;
                float bodyDiameter = diameter;

                float filletLength = Mathf.PI * fillet * 0.5f;
                float totLength    = filletLength + bodyLength;
                float s1           = filletLength * 0.5f / totLength;

                CirclePoints cp = CirclePoints.ForDiameter(fillet, MaxCircleError, MinCircleVertexes);

                // We need to be careful with the number of points so we don't blow the 255 point budget for colliders
                CirclePoints collCp   = CirclePoints.ForDiameter(fillet, MaxCircleError, 0, 12);
                CirclePoints collEnds = CirclePoints.ForDiameter(endDiameter, MaxCircleError * 4f, 4, 12);
                CirclePoints collBody = CirclePoints.ForDiameter(bodyDiameter, MaxCircleError * 4f, 4, 16);

                points.AddLast(new ProfilePoint(endDiameter, -0.5f * length, 0f, new Vector2(0, -1), colliderCirc: collEnds));

                foreach (Vector3 xzu in cp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }

                points.AddLast(new ProfilePoint(bodyDiameter, -0.5f * bodyLength, s1, new Vector2(1, 0), colliderCirc: collBody));
                if (fillet < length)
                {
                    points.AddLast(new ProfilePoint(bodyDiameter, 0.5f * bodyLength, 1f - s1, new Vector2(1, 0), colliderCirc: collBody));
                }

                foreach (Vector3 xzu in cp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }
                points.AddLast(new ProfilePoint(endDiameter, 0.5f * length, 1f, new Vector2(0, 1), colliderCirc: collEnds));
            }

            WriteMeshes(points);
        }
コード例 #3
0
 public ProfilePoint(float dia, float y, float v, Vector2 norm, bool inRender = true, bool inCollider = true, CirclePoints circ = null, CirclePoints colliderCirc = null)
 {
     this.dia          = dia;
     this.y            = y;
     this.v            = v;
     this.norm         = norm;
     this.inRender     = inRender;
     this.inCollider   = inCollider;
     this.circ         = inRender ? (circ ?? CirclePoints.ForDiameter(dia, MaxCircleError, MinCircleVertexes)) : null;
     this.colliderCirc = inCollider ? (colliderCirc ?? this.circ ?? CirclePoints.ForDiameter(dia, MaxCircleError, MinCircleVertexes)) : null;
 }
コード例 #4
0
        protected override void UpdateShape(bool force)
        {
            // ReSharper disable CompareOfFloatsByEqualityOperator
            if (!force && oldDiameter == diameter && oldLength == length && oldFillet == fillet)
            {
                return;
            }

            if (HighLogic.LoadedSceneIsFlight)
            {
                Volume = CalcVolume();
            }
            else if (HighLogic.LoadedSceneIsEditor)
            {
                if (filletEdit == null)
                {
                    filletEdit = (UI_FloatEdit)Fields["fillet"].uiControlEditor;
                }

                if (length != oldLength)
                {
                    if (length < oldLength && fillet > length)
                    {
                        fillet = length;
                    }

                    float volExcess = MaxMinVolume();
                    if (volExcess != 0)
                    {
                        // Again using alpha, solve the volume equation below equation for l
                        // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for l
                        // l = (-3 (pi-4) pi d f^2+pi (3 pi-10) f^3+24 v)/(6 pi d^2)
                        length = (-3f * (Pi - 4f) * Pi * diameter * pow(fillet, 2) + Pi * (3f * Pi - 10f) * pow(fillet, 3) + 24f * Volume) / (6f * Pi * pow(diameter, 2));
                        length = (float)Math.Round(length, 3);

                        // We could iterate here with the fillet and push it back up if it's been pushed down
                        // but it's altogether too much bother. User will just have to suck it up and not be
                        // so darn agressive with short lengths. I mean, seriously... :)
                    }

                    filletEdit.maxValue = Mathf.Min(length, useEndDiameter ? PPart.diameterMax : diameter);
                }
                else if (diameter != oldDiameter)
                {
                    if (useEndDiameter)
                    {
                        if (diameter + fillet < PPart.diameterMin)
                        {
                            fillet = PPart.diameterMin - diameter;
                        }
                        else if (diameter + fillet > PPart.diameterMax)
                        {
                            fillet = PPart.diameterMax - diameter;
                        }
                    }
                    else
                    {
                        if (diameter < oldDiameter && fillet > diameter)
                        {
                            fillet = diameter;
                        }
                    }

                    float volExcess = MaxMinVolume();
                    if (volExcess != 0)
                    {
                        // Unfortunatly diameter is not as easily isolated, but its still possible.

                        // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for d
                        // simplify d = ((-3 pi^2 f^2+12 pi f^2) ± sqrt(3 pi) sqrt(3 pi^3 f^4-24 pi^2 f^4+48 pi f^4+24 pi^2 f^3 l-80 pi f^3 l+192 l v))/(12 pi l)
                        // d = (-3 (pi-4) pi f^2 ± sqrt(3 pi) sqrt(3 (pi-4)^2 pi f^4+8 pi (3 pi-10) f^3 l+192 l v)) / (12 pi l)

                        float t1 = -3 * (Pi - 4f) * Pi * fillet * fillet;
                        float t2 = sqrt(3f * Pi) * sqrt(3f * pow(Pi - 4f, 2) * Pi * pow(fillet, 4) + 8f * Pi * (3f * Pi - 10f) * pow(fillet, 3) * length + 192f * length * Volume);
                        float de = (12f * Pi * length);

                        // I'm pretty sure only the +ve value is required, but make the -ve possible too.
                        diameter = (t1 + t2) / de;
                        if (diameter < 0)
                        {
                            diameter = (t1 - t2) / de;
                        }

                        diameter = (float)Math.Round(diameter, 3);
                    }

                    filletEdit.maxValue = Mathf.Min(length, useEndDiameter ? PPart.diameterMax : diameter);
                }
                else if (fillet != oldFillet)
                {
                    if (useEndDiameter)
                    {
                        // Keep diameter + fillet within range.
                        if (diameter + fillet < PPart.diameterMin)
                        {
                            diameter = PPart.diameterMin - fillet;
                        }
                        else if (diameter + fillet > PPart.diameterMax)
                        {
                            diameter = PPart.diameterMax - fillet;
                        }
                    }

                    // Will do an iterative process for finding the value.
                    // The equation is far too complicated plug this into alpha and you'll see what I mean:
                    // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for f

                    float vol = CalcVolume();
                    float inc;

                    if (vol < PPart.volumeMin)
                    {
                        Volume = PPart.volumeMin;
                        inc    = -0.001f;
                    }
                    else if (vol > PPart.volumeMax)
                    {
                        Volume = PPart.volumeMax;
                        inc    = 0.001f;
                    }
                    else
                    {
                        Volume = vol;
                        goto goldilocks;
                    }

                    float lVol;
                    float lFillet;
                    do
                    {
                        lVol    = vol;
                        lFillet = fillet;
                        fillet += inc;
                        vol     = CalcVolume();
                    }while (Mathf.Abs(vol - Volume) < Mathf.Abs(lVol - Volume));
                    fillet = (float)Math.Round(lFillet, 3);
                    goldilocks :;
                }
            }

            LinkedList <ProfilePoint> points = new LinkedList <ProfilePoint>();

            if (fillet == 0)
            {
                // Reduces down to a cylinder part.
                points.AddLast(new ProfilePoint(diameter, -0.5f * length, 0f, new Vector2(1, 0)));
                points.AddLast(new ProfilePoint(diameter, 0.5f * length, 1f, new Vector2(1, 0)));
            }
            else
            {
                float bodyLength   = length - fillet;
                float endDiameter  = useEndDiameter ? diameter : (diameter - fillet);
                float bodyDiameter = useEndDiameter ? (fillet + diameter) : diameter;

                float filletLength = Mathf.PI * fillet * 0.5f;
                float totLength    = filletLength + bodyLength;
                float s1           = filletLength * 0.5f / totLength;

                CirclePoints cp = CirclePoints.ForDiameter(fillet, MaxCircleError, MinCircleVertexes);

                // We need to be careful with the number of points so we don't blow the 255 point budget for colliders
                CirclePoints collCp   = CirclePoints.ForDiameter(fillet, MaxCircleError, 0, 12);
                CirclePoints collEnds = CirclePoints.ForDiameter(endDiameter, MaxCircleError * 4f, 4, 12);
                CirclePoints collBody = CirclePoints.ForDiameter(bodyDiameter, MaxCircleError * 4f, 4, 16);

                points.AddLast(new ProfilePoint(endDiameter, -0.5f * length, 0f, new Vector2(0, -1), colliderCirc: collEnds));

                foreach (Vector3 xzu in cp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }

                points.AddLast(new ProfilePoint(bodyDiameter, -0.5f * bodyLength, s1, new Vector2(1, 0), colliderCirc: collBody));
                if (fillet < length)
                {
                    points.AddLast(new ProfilePoint(bodyDiameter, 0.5f * bodyLength, 1f - s1, new Vector2(1, 0), colliderCirc: collBody));
                }

                foreach (Vector3 xzu in cp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }
                points.AddLast(new ProfilePoint(endDiameter, 0.5f * length, 1f, new Vector2(0, 1), colliderCirc: collEnds));
            }

            WriteMeshes(points);

            oldDiameter = diameter;
            oldLength   = length;
            oldFillet   = fillet;
            // ReSharper restore CompareOfFloatsByEqualityOperator
            //RefreshPartEditorWindow();
            UpdateInterops();
        }