private bool TesellateCap(Rect area, bool left, Edge edge, Vector2 verticalNormal, Vector3 offset)
        {
            if (!ShouldCloseEdge(edge, left) || area.Equals(default(Rect)))
            {
                return(false);
            }

            var capUv   = Terrain.UvMapping.ToUV(area);
            var capSize = new Vector2(area.Max.X / Terrain.PixelsPerUnit, area.Max.Y / Terrain.PixelsPerUnit);

            var top    = (left ? edge.Begin : edge.End) + verticalNormal * (capSize.Y / 2) + verticalNormal * offset.Y;
            var bottom = (left ? edge.Begin : edge.End) - verticalNormal * (capSize.Y / 2) + verticalNormal * offset.Y;

            var horizontalNormal = (bottom - top).Normal();

            top    += horizontalNormal * offset.X * (left ? -1 : 1);
            bottom += horizontalNormal * offset.X * (left ? -1 : 1);

            var capOffset   = horizontalNormal * capSize.X;
            var otherTop    = left ? top - capOffset : top + capOffset;
            var otherBottom = left ? bottom - capOffset : bottom + capOffset;

            if (left)
            {
                Utils.Swap(ref top, ref otherTop);
                Utils.Swap(ref bottom, ref otherBottom);
            }

            EdgeData.AddQuad(
                new Vector3(bottom.X, bottom.Y, offset.Z),
                new Vector3(top.X, top.Y, offset.Z),
                new Vector3(otherTop.X, otherTop.Y, offset.Z),
                new Vector3(otherBottom.X, otherBottom.Y, offset.Z),
                capUv.BottomLeft(), capUv.TopLeft(), capUv.TopRight(), capUv.BottomRight());

            return(true);
        }
        private void TesellateEdges(out List <Vector2> centralPoints)
        {
            centralPoints = new List <Vector2>();

            var normalStart   = (Vector2?)null;
            var firstCapDone  = (bool?)null;
            var pixelsPerUnit = Terrain.PixelsPerUnit;

            var batches = (IsInverted ? Edges.Reverse() : Edges).BatchOfTakeUntil(e => ShouldCloseEdge(e, false)).ToArray();
            var begin   = batches[0][0].Begin;

            foreach (var batch in batches)
            {
                if (Terrain.SplitWhenDifferent ||
                    batch[0].Split == SplitMode.Left || batch[0].Split == SplitMode.Both ||
                    batch[0].PrevSplit == SplitMode.Both || batch[0].PrevSplit == SplitMode.Right)
                {
                    normalStart   = null;
                    batch[0].Prev = null;
                }
                var lst = batch.Length - 1;
                if (Terrain.SplitWhenDifferent ||
                    batch[lst].Split == SplitMode.Right || batch[lst].Split == SplitMode.Both ||
                    batch[lst].NextSplit == SplitMode.Both || batch[lst].NextSplit == SplitMode.Left)
                {
                    batch[lst].Next = null;
                }

                float[] edgesLengths;
                var     segmentMapping          = SegmentFor(batch[0].Direction);
                var     smoothFactor            = batch.Length == 1 && batch[0].Prev == null && batch[lst].Next == null ? 1 : Terrain.SmoothFactor;
                var     totalLength             = InterpolateLength(Terrain.InterpolationMode, batch, smoothFactor * 5, out edgesLengths);
                var     bodyCount               = (float)Math.Max((int)Math.Round(totalLength / (segmentMapping.BodySize.X / pixelsPerUnit) + Terrain.StrechThreshold), 1);
                var     finalBodySize           = new Vector2(totalLength / bodyCount, segmentMapping.BodySize.Y / pixelsPerUnit);
                var     halfFinalBodySizeHeight = finalBodySize.Y / 2;
                var     incLength               = finalBodySize.X / smoothFactor;
                var     currentLength           = incLength;
                var     first   = true;
                var     offsets = segmentMapping.Offsets;
                offsets = new Vector3(offsets.X / pixelsPerUnit, offsets.Y / pixelsPerUnit, offsets.Z / pixelsPerUnit);


                for (int i = 0; i < bodyCount; i++)
                {
                    var bodyUV = Terrain.UvMapping.ToUV(new Rect(segmentMapping.Bodies[Math.Abs(begin.GetHashCode() % segmentMapping.Bodies.Count)], segmentMapping.BodySize));
                    bodyUV.Max.X = bodyUV.Max.X / smoothFactor;

                    for (int j = 0; j < smoothFactor; j++, currentLength += incLength)
                    {
                        var end         = Interpolate(Terrain.InterpolationMode, batch, edgesLengths, currentLength);
                        var normalEnd   = (end - begin).Normal();
                        var endOffset   = normalEnd * halfFinalBodySizeHeight;
                        var beginOffset = (normalStart ?? normalEnd) * halfFinalBodySizeHeight;

                        var yOffset         = (normalStart ?? normalEnd) * offsets.Y;
                        var localBottomLeft = begin - beginOffset + yOffset;
                        var localTopLeft    = begin + beginOffset + yOffset;

                        yOffset = normalEnd * offsets.Y;
                        var localBottomRight = end - endOffset + yOffset;
                        var localTopRight    = end + endOffset + yOffset;

                        EdgeData.AddQuad(
                            new Vector3(localBottomLeft.X, localBottomLeft.Y, offsets.Z),
                            new Vector3(localTopLeft.X, localTopLeft.Y, offsets.Z),
                            new Vector3(localTopRight.X, localTopRight.Y, offsets.Z),
                            new Vector3(localBottomRight.X, localBottomRight.Y, offsets.Z),
                            bodyUV.BottomLeft(), bodyUV.TopLeft(), bodyUV.TopRight(), bodyUV.BottomRight());

                        if (first)
                        {
                            first        = TesellateCap(new Rect(segmentMapping.LeftCap, segmentMapping.CapSize), true, batch[0], normalStart ?? normalEnd, offsets);
                            firstCapDone = firstCapDone ?? first;
                            first        = false;
                        }

                        centralPoints.Add(begin);
                        normalStart  = normalEnd;
                        bodyUV.Min.X = bodyUV.Min.X + bodyUV.Max.X;
                        begin        = end;
                    }
                }
                TesellateCap(new Rect(segmentMapping.RightCap, segmentMapping.CapSize), false, batch[lst], normalStart.Value, offsets);
            }
        }