private void generate_ordered(List <Vector3> knots, bool generate_fine = false)
    {
        OrderedPoints = new List <Vector3>();
        var path = new CubicBezierPath(knots.ToArray());

        var mindist = 0.06f;
        var spacing = 0.08f;
        var max     = (float)(knots.Count - 1) - 0.12f;
        var i       = 0.12f;
        var last    = P1;

        while (i < max)
        {
            var pt = path.GetPoint(i);

            if (Vector3.Distance(pt, last) >= mindist)
            {
                OrderedPoints.Add(pt);
                last = pt;
            }

            i += spacing;
        }

        if (!generate_fine)
        {
            return;
        }

        OrderedFinePoints = new List <Vector3>();

        mindist = 0.04f;
        spacing = 0.03f;
        max     = (float)(knots.Count - 1) - 0.04f;
        i       = 0.04f;
        last    = P1;

        while (i < max)
        {
            var pt = path.GetPoint(i);

            if (Vector3.Distance(pt, last) >= mindist)
            {
                OrderedFinePoints.Add(pt);
                last = pt;
            }

            i += spacing;
        }

        var mid_start = (P1 + OrderedFinePoints[0]) * 0.5f;
        var mid_end   = (P2 + OrderedFinePoints[OrderedFinePoints.Count - 1]) * 0.5f;

        OrderedFinePoints.Insert(0, mid_start);
        OrderedFinePoints.Add(mid_end);
    }
    private List <Vector3> get_contour(PolyBorder pb, float min_lat, float max_lat)
    {
        var dist    = 0.08f;
        var pts     = new List <Vector3>();
        var norm    = (pb.P2 - pb.P1).normalized;
        var prev    = pb.P1;
        var lateral = Vector3.zero;

        for (var i = 0; i < pb.OrderedPoints.Count - 1; i++)
        {
            var pt = pb.OrderedPoints[i];

            if (Vector3.Distance(prev, pt) < dist)
            {
                continue;
            }

            var behind  = pb.OrderedPoints[Mathf.Max(i - 1, 0)];
            var forward = pb.OrderedPoints[Mathf.Min(i + 1, pb.OrderedPoints.Count - 1)];

            dist = UnityEngine.Random.Range(0.04f, 0.16f);

            var dir      = (pt - behind).normalized;
            var lateral1 = Vector3.Cross(dir, Vector3.forward);
            dir = (forward - pt).normalized;
            var lateral2 = Vector3.Cross(dir, Vector3.forward);
            var true_lat = (lateral1 + lateral2) * 0.5f;

            if (i == 0)
            {
                true_lat = lateral2;
            }
            else if (i == pb.OrderedPoints.Count - 1)
            {
                true_lat = lateral1;
            }

            var shift = pt + true_lat * UnityEngine.Random.Range(min_lat, max_lat);
            pts.Add(shift);

            lateral = true_lat;
            prev    = pt;
        }

        var endpt  = pb.P2 + norm * 0.04f + lateral * min_lat;
        var endpt2 = pb.P2 + norm * 0.04f - lateral * min_lat;

        pts.Add(endpt);
        pts.Add(endpt2);
        prev = endpt;
        dist = 0.08f;

        var ordered = pb.Reversed().OrderedPoints;

        for (var i = 0; i < ordered.Count - 1; i++)
        {
            var pt = ordered[i];

            if (Vector3.Distance(prev, pt) < dist)
            {
                continue;
            }

            var behind  = ordered[Mathf.Max(i - 1, 0)];
            var forward = ordered[Mathf.Min(i + 1, ordered.Count - 1)];

            dist = UnityEngine.Random.Range(0.04f, 0.16f);

            var dir      = (pt - behind).normalized;
            var lateral1 = Vector3.Cross(dir, Vector3.forward);
            dir = (forward - pt).normalized;
            var lateral2 = Vector3.Cross(dir, Vector3.forward);
            var true_lat = (lateral1 + lateral2) * 0.5f;

            if (i == 0)
            {
                true_lat = lateral2;
            }
            else if (i == ordered.Count - 1)
            {
                true_lat = lateral1;
            }

            var shift = pt + true_lat * UnityEngine.Random.Range(min_lat, max_lat);
            pts.Add(shift);

            lateral = true_lat;
            prev    = pt;
        }

        endpt  = pb.P1 - norm * 0.04f + lateral * min_lat;
        endpt2 = pb.P1 - norm * 0.04f - lateral * min_lat;

        pts.Add(endpt);
        pts.Add(endpt2);
        pts.Add(pts[0]);

        var path = new CubicBezierPath(pts.ToArray());

        var max     = (float)(pts.Count - 1) - 0.04f;
        var j       = 0.04f;
        var spacing = 0.04f;
        var last    = pb.P1;

        ordered = new List <Vector3>();

        while (j < max)
        {
            var pt = path.GetPoint(j);

            if (Vector3.Distance(pt, last) >= spacing)
            {
                ordered.Add(pt);
                last = pt;
            }

            j += 0.04f;
        }

        return(ordered);
    }