Drawing points along path spirally

119 views Asked by At

Well, I'm trying to optimize what I did here (Smoothing noises with different amplitudes (Part 2)).

By this reason, I did a new implementation from scratch (https://youtu.be/o7pVEXhh3TI) to draw the path:

    private void Start()
    {
        Polygon pol = File.ReadAllText(PolyPath).Deserialize<Polygon>();

        // Create tex object

        var list = pol.Vertices.AsEnumerable();
        tex = list.CreateTextureObject(pol.Position, offset);

        exampleTexture = new Texture2D(tex.Width, tex.Height);
        exampleTexture.SetPixels32(new Color32[tex.Width * tex.Height]);
        exampleTexture.Apply();

        vertices = pol.Vertices.Select(v => (v - pol.Position) + offset).Clone().ToList();

        _ss = new List<Segment>(pol.Segments.Select(s => new Segment((s.start + pol.Center - pol.Position) + offset, (s.end + pol.Center - pol.Position) + offset)));

        foreach (Segment curSeg in _ss)
            for (int i = -effectDistance; i < effectDistance; ++i)
            {
                Vector2 perp = Vector2.Perpendicular(((Vector2)curSeg.start - (Vector2)curSeg.end)).normalized;

                segments.Add((Vector2)curSeg.start + perp * i);

                F.DrawLine((Vector2)curSeg.start + perp * i, (Vector2)curSeg.end + perp * i, (x, y) => layers.Add(new Point(x, y)));
            }

        Debug.Log("Layer Count: " + layers.Count);

        drawPath = true;
    }

    private void OnGUI()
    {
        if (exampleTexture == null)
            return;

        GUI.DrawTexture(new Rect((Screen.width - tex.Width) / 2, (Screen.height - tex.Height) / 2, tex.Width, tex.Height), exampleTexture);

        if (drawPath)
        {
            {
                Point? cur = layers.Count > 0 ? (Point?)layers.First() : null;

                if (cur.HasValue)
                {
                    exampleTexture.SetPixel(cur.Value.x, cur.Value.y, new Color32(170, 0, 0, 255));
                    exampleTexture.Apply();

                    layers.Remove(cur.Value);
                }
            }

            {
                Point? cur = segments.Count > 0 ? (Point?)segments.First() : null;

                if (cur.HasValue)
                {
                    exampleTexture.SetPixel(cur.Value.x, cur.Value.y, new Color32(0, 170, 0, 255));
                    exampleTexture.Apply();

                    segments.Remove(cur.Value);
                }
            }

            {
                Point? cur = vertices.Count > 0 ? (Point?)vertices.First() : null;

                //Debug.Log(cur);

                if (cur.HasValue)
                {
                    exampleTexture.SetPixel(cur.Value.x, cur.Value.y, new Color32(255, 128, 0, 255));
                    exampleTexture.Apply();

                    vertices.Remove(cur.Value);
                }
            }

            if (vertices.Count == 0 && segments.Count == 0 && layers.Count == 0)
                drawPath = false;
        }
    }

This is what DrawLines actually do:

public static class F 
{
    public static void DrawLine(Point p1, Point p2, Action<int, int> action)
    {
        DrawLine(p1.x, p1.y, p2.x, p2.y, action);
    }

    public static void DrawLine(int x0, int y0, int x1, int y1, Action<int, int> action)
    {
        int sx = 0,
            sy = 0;

        int dx = Mathf.Abs(x1 - x0),
            dy = Mathf.Abs(y1 - y0);

        if (x0 < x1) { sx = 1; } else { sx = -1; }
        if (y0 < y1) { sy = 1; } else { sy = -1; }

        int err = dx - dy,
            e2 = 0;

        while (true)
        {
            action?.Invoke(x0, y0);

            if ((x0 == x1) && (y0 == y1))
                break;

            e2 = 2 * err;

            if (e2 > -dy)
            {
                err = err - dy;
                x0 = x0 + sx;
            }
            if (e2 < dx)
            {
                err = err + dx;
                y0 = y0 + sy;
            }
        }
    }
}

This is an implemenentation of Bresenham algorithm.

This implementation is better because I have lowered iterations from 280k to 6k, but there is an issue as you can see this is innacurate...

The way this works first is getting the perpendicular of each segment on the shape (green pixels) and then drawing lines between the start and the end point of that segment. Segmenents are obtained using Ramer-Douglas-Peucker algorithm.

So I was thinking on draw the "orange" path spirally. I don't know how to explain this, basically, obtaining the same path but, with an scale (Translating/transforming? list of points from its center with an offset/distance) but I think I will have the same innacuracy.

Any guide will be appreciated. What algorithm could I use to draw the path with "layers"?

1

There are 1 answers

1
Ruzihm On

Following some of the information here, you might be able to use "inward/outward polygon offsetting" (aka "polygon buffering") to get the result you are interested in.

A tool such as Clipper can help.

Once you have a way to outwardly offset your shape, do the following:

First, draw the outer shape (black region below), then offset the inner shape outwards as far as you need it to go, and draw it on top of the outer shape (brown region below) using an appropriate noise/color scheme:

gradient 1/3

Then, apply a smaller offset, then draw that shape on top using a different noise/colorscheme (orange region below).

gradient 2/3

Repeat until you have as many gradients as you need:

all gradients

Finally, draw the inner shape without any offsetting with its noise/color scheme:

gradient plus inner shape