static void GenerateJoining(JoiningInfo joinInfo, PathCorner corner, float halfThickness, float tippedCornerLimit, TessellationOptions tessellateOptions, List <Vector2> verts, List <UInt16> inds) { // The joining generates the vertices at both ends as well as the joining itself if (verts.Count == 0) { // Starting a path with a joining (meaning a loop) verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessEnd : joinInfo.InnerCornerVertex); verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessEnd); } System.Diagnostics.Debug.Assert(verts.Count >= 2); int indexStart = verts.Count - 2; // Using the last two vertices // Convert a tipped corner to a beveled one if tippedCornerLimit ratio is reached if (corner == PathCorner.Tipped && tippedCornerLimit >= 1.0f) { var theta = Vector2.Angle(-joinInfo.TanAtEnd, joinInfo.TanAtStart) * Mathf.Deg2Rad; var ratio = 1.0f / Mathf.Sin(theta / 2.0f); if (ratio > tippedCornerLimit) { corner = PathCorner.Beveled; } } if (joinInfo.SimpleJoin) { // TODO } else if (corner == PathCorner.Tipped) { verts.Add(joinInfo.PosThicknessClosingPoint); verts.Add(joinInfo.NegThicknessClosingPoint); verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessStart : joinInfo.InnerCornerVertex); verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessStart); // Ending to tip inds.Add((UInt16)(indexStart + 0)); inds.Add((UInt16)(indexStart + 3)); inds.Add((UInt16)(indexStart + 1)); inds.Add((UInt16)(indexStart + 0)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 3)); // Tip to starting inds.Add((UInt16)(indexStart + 4)); inds.Add((UInt16)(indexStart + 3)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 4)); inds.Add((UInt16)(indexStart + 5)); inds.Add((UInt16)(indexStart + 3)); return; } else if (corner == PathCorner.Beveled) { verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessEnd : joinInfo.InnerCornerVertex); // 2 verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessEnd); // 3 verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessStart : joinInfo.InnerCornerVertex); // 4 verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessStart); // 5 // Ending to tip inds.Add((UInt16)(indexStart + 0)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 1)); inds.Add((UInt16)(indexStart + 1)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 3)); // Bevel if (joinInfo.RoundPosThickness) { inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 4)); inds.Add((UInt16)(indexStart + 3)); } else { inds.Add((UInt16)(indexStart + 3)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + 5)); } return; } if (corner == PathCorner.Round) { float sweepAngle = Mathf.Acos(Vector2.Dot(joinInfo.NormAtEnd, joinInfo.NormAtStart)); bool flipArc = false; if (!PointOnTheLeftOfLine(Vector2.zero, joinInfo.NormAtEnd, joinInfo.NormAtStart)) { sweepAngle = -sweepAngle; flipArc = true; } UInt16 innerCornerVertexIndex = (UInt16)verts.Count; verts.Add(joinInfo.InnerCornerVertex); int arcSegments = CalculateArcSteps(halfThickness, 0, sweepAngle, tessellateOptions); for (int i = 0; i <= arcSegments; i++) { float angle = sweepAngle * (i / (float)arcSegments); Vector2 nrm = Matrix2D.RotateLH(angle) * joinInfo.NormAtEnd; if (flipArc) { nrm = -nrm; } verts.Add(nrm * halfThickness + joinInfo.JoinPos); if (i == 0) { inds.Add((UInt16)(indexStart + 0)); inds.Add((UInt16)(indexStart + 3)); inds.Add((UInt16)(indexStart + (joinInfo.RoundPosThickness ? 2 : 1))); inds.Add((UInt16)(indexStart + 0)); inds.Add((UInt16)(indexStart + 2)); inds.Add((UInt16)(indexStart + (joinInfo.RoundPosThickness ? 1 : 3))); } else { if (joinInfo.RoundPosThickness) { inds.Add((UInt16)(indexStart + i + (flipArc ? 3 : 2))); inds.Add((UInt16)(indexStart + i + (flipArc ? 2 : 3))); inds.Add(innerCornerVertexIndex); } else { inds.Add((UInt16)(indexStart + i + (flipArc ? 3 : 2))); inds.Add((UInt16)(indexStart + i + (flipArc ? 2 : 3))); inds.Add(innerCornerVertexIndex); } } } // Manually add the last segment, maintain the expected vertex positioning int endingVerticesIndex = verts.Count; if (joinInfo.RoundPosThickness) { verts.Add(joinInfo.PosThicknessStart); verts.Add(joinInfo.InnerCornerVertex); } else { verts.Add(joinInfo.InnerCornerVertex); verts.Add(joinInfo.NegThicknessStart); } inds.Add((UInt16)(endingVerticesIndex - 1)); inds.Add((UInt16)(endingVerticesIndex + 0)); inds.Add(innerCornerVertexIndex); } }
private static void BuildTestColumnWithProperties(float x, float width, PathEnding ending, PathCorner corners, VectorUtils.TessellationOptions options) { var sprites = new List <Sprite>(); var angles = new float[] { -Mathf.PI + Mathf.PI / 8, -Mathf.PI + Mathf.PI / 4, Mathf.PI - Mathf.PI / 4, Mathf.PI - Mathf.PI / 8 }; foreach (var angle in angles) { var path = LinesWithAngle(angle, width); var pathProps = path.PathProps; pathProps.Head = ending; pathProps.Tail = ending; pathProps.Corners = corners; path.PathProps = pathProps; var geoms = new List <VectorUtils.Geometry>(); TessellatePath(path.Contours[0], path.PathProps, geoms, options); sprites.Add(SpriteFromGeometry(geoms)); } var pos = new Vector2(x, 0.0f); foreach (var sprite in sprites) { var go = new GameObject("Path"); go.transform.position = pos; var sr = go.AddComponent <SpriteRenderer>(); sr.sprite = sprite; pos.y += 0.25f; } }