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