public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLevel,
                            int accuracy, bool staticRendering = true)
        {
            var vertices    = GetCentralCurve(dragPoints, tableDetailLevel, accuracy, staticRendering);
            var numVertices = vertices.Length;

            Cross        = new bool[numVertices + 1];
            MiddlePoints = new Vertex2D[numVertices + 1];
            RgvLocal     = new Vertex2D[(numVertices + 1) * 2];

            for (var i = 0; i < numVertices; i++)
            {
                // prev and next wrap around as rubbers always loop
                var prev   = vertices[i > 0 ? i - 1 : numVertices - 1];
                var next   = vertices[i < numVertices - 1 ? i + 1 : 0];
                var middle = vertices[i];

                Cross[i] = middle.IsControlPoint;
                Vertex2D normal;

                // Get normal at this point
                // Notice that these values equal the ones in the line
                // equation and could probably be substituted by them.
                var normal1 = new Vertex2D(prev.Y - middle.Y, middle.X - prev.X);                 // vector vmiddle-vprev rotated RIGHT
                var normal2 = new Vertex2D(middle.Y - next.Y, next.X - middle.X);                 // vector vnext-vmiddle rotated RIGHT

                // not needed special start/end handling as rubbers always loop, except for the case where there are only 2 control points
                if (numVertices == 2 && i == numVertices - 1)
                {
                    normal1.Normalize();
                    normal = normal1;
                }
                else if (numVertices == 2 && i == 0)
                {
                    normal2.Normalize();
                    normal = normal2;
                }
                else
                {
                    normal1.Normalize();
                    normal2.Normalize();

                    if (MathF.Abs(normal1.X - normal2.X) < 0.0001 && MathF.Abs(normal1.Y - normal2.Y) < 0.0001)
                    {
                        // Two parallel segments
                        normal = normal1;
                    }
                    else
                    {
                        // Find intersection of the two edges meeting this points, but
                        // shift those lines outwards along their normals

                        // First line
                        var a = prev.Y - middle.Y;
                        var b = middle.X - prev.X;

                        // Shift line along the normal
                        var c = a * (normal1.X - prev.X) + b * (normal1.Y - prev.Y);

                        // Second line
                        var d = next.Y - middle.Y;
                        var e = middle.X - next.X;

                        // Shift line along the normal
                        var f = d * (normal2.X - next.X) + e * (normal2.Y - next.Y);

                        var det    = a * e - b * d;
                        var invDet = det != 0.0f ? 1.0f / det : 0.0f;

                        var intersectX = (b * f - e * c) * invDet;
                        var intersectY = (c * d - a * f) * invDet;

                        normal = new Vertex2D(middle.X - intersectX, middle.Y - intersectY);
                    }
                }

                var widthCur = thickness;

                MiddlePoints[i] = middle;

                // vmiddle + (widthcur * 0.5) * vnormal;
                RgvLocal[i] = middle.Clone().Add(normal.Clone().MultiplyScalar(widthCur * 0.5f));

                // vmiddle - (widthcur*0.5f) * vnormal;
                RgvLocal[(numVertices + 1) * 2 - i - 1] =
                    middle.Clone().Sub(normal.Clone().MultiplyScalar(widthCur * 0.5f));

                if (i == 0)
                {
                    RgvLocal[numVertices] = RgvLocal[0];
                    RgvLocal[(numVertices + 1) * 2 - numVertices - 1] = RgvLocal[(numVertices + 1) * 2 - 1];
                }
            }

            Cross[numVertices]        = vertices[0].IsControlPoint;
            MiddlePoints[numVertices] = MiddlePoints[0];
            VertexCount = numVertices + 1;
        }
Пример #2
0
        public RampVertex GetRampVertex(float tableHeight, float accuracy, bool incWidth)
        {
            var result = new RampVertex();

            // vvertex are the 2D vertices forming the central curve of the ramp as seen from above
            var vertex = GetCentralCurve(accuracy);

            var numVertices = vertex.Length;

            result.VertexCount  = numVertices;
            result.PointHeights = new float[numVertices];
            result.Cross        = new bool[numVertices];
            result.PointRatios  = new float[numVertices];
            result.MiddlePoints = new Vertex2D[numVertices];
            result.RgvLocal     = new Vertex2D[_data.Type != RampType.RampTypeFlat ? (numVertices + 1) * 2 : numVertices * 2];

            // Compute an approximation to the length of the central curve
            // by adding up the lengths of the line segments.
            var totalLength  = 0f;
            var bottomHeight = _data.HeightBottom + tableHeight;
            var topHeight    = _data.HeightTop + tableHeight;

            for (var i = 0; i < numVertices - 1; i++)
            {
                var v1 = vertex[i];
                var v2 = vertex[i + 1];

                var dx     = v1.X - v2.X;
                var dy     = v1.Y - v2.Y;
                var length = MathF.Sqrt(dx * dx + dy * dy);

                totalLength += length;
            }

            var currentLength = 0f;

            for (var i = 0; i < numVertices; i++)
            {
                // clamp next and prev as ramps do not loop
                var prev   = vertex[i > 0 ? i - 1 : i];
                var next   = vertex[i < numVertices - 1 ? i + 1 : i];
                var middle = vertex[i];

                result.Cross[i] = middle.IsControlPoint;

                var normal = new Vertex2D();
                // Get normal at this point
                // Notice that these values equal the ones in the line
                // equation and could probably be substituted by them.
                var v1Normal = new Vertex2D(prev.Y - middle.Y, middle.X - prev.X);                 // vector vmiddle-vprev rotated RIGHT
                var v2Normal = new Vertex2D(middle.Y - next.Y, next.X - middle.X);                 // vector vnext-vmiddle rotated RIGHT

                // special handling for beginning and end of the ramp, as ramps do not loop
                if (i == numVertices - 1)
                {
                    v1Normal.Normalize();
                    normal = v1Normal;
                }
                else if (i == 0)
                {
                    v2Normal.Normalize();
                    normal = v2Normal;
                }
                else
                {
                    v1Normal.Normalize();
                    v2Normal.Normalize();

                    if (MathF.Abs(v1Normal.X - v2Normal.X) < 0.0001 && MathF.Abs(v1Normal.Y - v2Normal.Y) < 0.0001)
                    {
                        // Two parallel segments
                        normal = v1Normal;
                    }
                    else
                    {
                        // Find intersection of the two edges meeting this points, but
                        // shift those lines outwards along their normals

                        // First line
                        var a = prev.Y - middle.Y;
                        var b = middle.X - prev.X;

                        // Shift line along the normal
                        var c = -(a * (prev.X - v1Normal.X) + b * (prev.Y - v1Normal.Y));

                        // Second line
                        var d = next.Y - middle.Y;
                        var e = middle.X - next.X;

                        // Shift line along the normal
                        var f = -(d * (next.X - v2Normal.X) + e * (next.Y - v2Normal.Y));

                        var det    = a * e - b * d;
                        var invDet = det != 0.0 ? 1.0f / det : 0.0f;

                        var intersectX = (b * f - e * c) * invDet;
                        var intersectY = (c * d - a * f) * invDet;

                        normal.X = middle.X - intersectX;
                        normal.Y = middle.Y - intersectY;
                    }
                }

                // Update current length along the ramp.
                var dx     = prev.X - middle.X;
                var dy     = prev.Y - middle.Y;
                var length = MathF.Sqrt(dx * dx + dy * dy);

                currentLength += length;

                var percentage   = currentLength / totalLength;
                var currentWidth = percentage * (_data.WidthTop - _data.WidthBottom) + _data.WidthBottom;
                result.PointHeights[i] = middle.Z + percentage * (topHeight - bottomHeight) + bottomHeight;

                AssignHeightToControlPoint(new Vertex2D(vertex[i].X, vertex[i].Y), middle.Z + percentage * (topHeight - bottomHeight) + bottomHeight);
                result.PointRatios[i] = 1.0f - percentage;

                // only change the width if we want to create vertices for rendering or for the editor
                // the collision engine uses flat type ramps
                if (IsHabitrail() && _data.Type != RampType.RampType1Wire)
                {
                    currentWidth = _data.WireDistanceX;
                    if (incWidth)
                    {
                        currentWidth += 20.0f;
                    }
                }
                else if (_data.Type == RampType.RampType1Wire)
                {
                    currentWidth = _data.WireDiameter;
                }

                result.MiddlePoints[i] = new Vertex2D(middle.X, middle.Y) + normal;
                result.RgvLocal[i]     = new Vertex2D(middle.X, middle.Y) + currentWidth * 0.5f * normal;
                result.RgvLocal[numVertices * 2 - i - 1] = new Vertex2D(middle.X, middle.Y) - currentWidth * 0.5f * normal;
            }

            return(result);
        }
Пример #3
0
        public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLevel, float accuracy, bool staticRendering = true, float margin = 0f, bool loop = true)
        {
            var vertices    = GetCentralCurve(dragPoints, tableDetailLevel, accuracy, staticRendering, loop: loop);
            var numVertices = vertices.Length;

            Cross        = new bool[numVertices + 1];
            MiddlePoints = new Vertex2D[numVertices + 1];
            RgvLocal     = new Vertex2D[(numVertices + 1) * 2];

            for (var i = 0; i < numVertices; i++)
            {
                // prev and next wrap around in loops
                var prev = vertices[i > 0 ? i - 1 : numVertices - 1];
                var next = vertices[i < numVertices - 1 ? i + 1 : 0];

                // .. but have to be corrected at start and end with "virtual vertices" continuing the spline when not looping, so cuts perpendicular to the tangents
                // maybe fix ramps after that that also hat the same problem.
                if (!loop && i == 0)
                {
                    prev = new RenderVertex2D(vertices[0].X * 2 - vertices[1].X, vertices[0].Y * 2 - vertices[1].Y);
                }
                if (!loop && i == (numVertices - 1))
                {
                    next = new RenderVertex2D(vertices[numVertices - 1].X * 2 - vertices[numVertices - 2].X, vertices[numVertices - 1].Y * 2 - vertices[numVertices - 2].Y);
                }

                var middle = vertices[i];

                Cross[i] = middle.IsControlPoint;
                Vertex2D normal;

                // Get normal at this point
                // Notice that these values equal the ones in the line
                // equation and could probably be substituted by them.
                var normal1 = new Vertex2D(prev.Y - middle.Y, middle.X - prev.X);                 // vector vmiddle-vprev rotated RIGHT
                var normal2 = new Vertex2D(middle.Y - next.Y, next.X - middle.X);                 // vector vnext-vmiddle rotated RIGHT

                // not needed special start/end handling as rubbers always loop, except for the case where there are only 2 control points
                // I guess this does not work as intended, but could not figure out what was wrong. i think that somehow the normal of Node 1 is wrong. /cupiii
                if (numVertices == 2 && i == numVertices - 1)
                {
                    normal1.Normalize();
                    normal = normal1;
                }
                else if (numVertices == 2 && i == 0)
                {
                    normal2.Normalize();
                    normal = normal2;
                }
                else
                {
                    normal1.Normalize();
                    normal2.Normalize();

                    if (MathF.Abs(normal1.X - normal2.X) < 0.0001 && MathF.Abs(normal1.Y - normal2.Y) < 0.0001)
                    {
                        // Two parallel segments
                        normal = normal1;
                    }
                    else
                    {
                        // Find intersection of the two edges meeting this points, but
                        // shift those lines outwards along their normals

                        // First line
                        var a = prev.Y - middle.Y;
                        var b = middle.X - prev.X;

                        // Shift line along the normal
                        var c = a * (normal1.X - prev.X) + b * (normal1.Y - prev.Y);

                        // Second line
                        var d = next.Y - middle.Y;
                        var e = middle.X - next.X;

                        // Shift line along the normal
                        var f = d * (normal2.X - next.X) + e * (normal2.Y - next.Y);

                        var det    = a * e - b * d;
                        var invDet = det != 0.0f ? 1.0f / det : 0.0f;

                        var intersectX = (b * f - e * c) * invDet;
                        var intersectY = (c * d - a * f) * invDet;

                        normal = new Vertex2D(middle.X - intersectX, middle.Y - intersectY);
                    }
                }

                var widthCur = thickness + margin;

                MiddlePoints[i] = new Vertex2D(middle.X, middle.Y);

                RgvLocal[i] = new Vertex2D(middle.X, middle.Y) + widthCur * 0.5f * normal;
                RgvLocal[(numVertices + 1) * 2 - i - 1] = new Vertex2D(middle.X, middle.Y) - widthCur * 0.5f * normal;

                if (i == 0)
                {
                    RgvLocal[numVertices] = RgvLocal[0];
                    RgvLocal[(numVertices + 1) * 2 - numVertices - 1] = RgvLocal[(numVertices + 1) * 2 - 1];
                }
            }

            if (loop)
            {
                VertexCount = numVertices;
            }
            else
            {
                MiddlePoints[numVertices] = MiddlePoints[0];
                Cross[numVertices]        = vertices[0].IsControlPoint;
                VertexCount = numVertices + 1;
            }
        }