1

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"?

Ruzihm
  • 19,749
  • 5
  • 36
  • 48
z3nth10n
  • 2,341
  • 2
  • 25
  • 49
  • https://stackoverflow.com/questions/1109536/an-algorithm-for-inflating-deflating-offsetting-buffering-polygons this might help – Ruzihm Nov 30 '18 at 16:45
  • 1
    Try using that to draw an inflated shape N times with decreasing levels of inflation, then draw the original shape. Then, you'll have a gradient with N steps going from your original shape outwards. – Ruzihm Nov 30 '18 at 17:21
  • I think I like clipper, this gives the same result as my previous questions: https://i.gyazo.com/a33f553d79aba52811b08986d8bcc784.png I will debug it to know how many iterations it does. – z3nth10n Dec 01 '18 at 13:28
  • Well, polygon offsetting are a little bit more effective than my method... But: https://i.gyazo.com/4899a6278d3f002f148179cc844f7c21.png – z3nth10n Dec 01 '18 at 14:03
  • @Ruzihm there is a problem. Now, I need a method that does the same as AddPath and FilPath (from Graphics2D) for Unity3D... – z3nth10n Dec 01 '18 at 14:51
  • Can you use clipper to fill in the polygon in addition to the outline? That way if you draw the outer-most polygon first (outline + fill same color) then draw the smaller polygon in the list, there won't be any gaps. – Ruzihm Dec 03 '18 at 20:16
  • I has been trying to use Triangulation (this how internally Graphics2D.GraphicsPath.FillPath works) (thanks to LilyPath), but... Poly2Tri, Ear Clipping Traingulation (I have tried like two different implementations) don't work... By this reason (and also, because I don't understand very well what you said/requested, sorry), if you post an answer explaining your comment it will be welcomed and maybe rewarded :P – z3nth10n Dec 03 '18 at 21:09

1 Answers1

1

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

Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • Sorry, I have been busy this week... Actually the problem is that I can't fill a offset polygon given by Clipper, I explain this better here: https://stackoverflow.com/questions/53731743/get-all-points-within-a-triangle-is-causing-an-overflow thanks! – z3nth10n Dec 11 '18 at 20:26