Why is my dragon fractal incomplete [closed]
Asked Answered
A

1

9

I have translated the code from javascript to c# which can be found by going to this excellent demo at http://fractal.qfox.nl/dragon.js

My translation is intended to produce just a single dragon upon clicking the button but I think I have missed something in my version.
See the Wikipedia article: Dragon Curve for more information.

Incomplete dragon fractal output: sickly dragon Code:

public partial class MainPage : UserControl
{
    PointCollection pc;

    Int32[] pattern = new Int32[] { 1, 1, 0, 2, 1, 0, 0, 3 };
    Int32[] position = new Int32[] { 0, 0, 0, 0, 0, 0, 0, 0 };
    Boolean toggle;
    Char r = default(Char);

    Int32 distance = 10; // line length
    Int32 step = 100; // paints per step
    Int32 skip = 10; // folds per paint

    Double x = 0;
    Double y = 0;
    Int32 a = 90;


    public MainPage()
    {
        InitializeComponent();
    }


    private void btnFire_Click(object sender, RoutedEventArgs e)
    {

        x = canvas.ActualWidth / 3;
        y = canvas.ActualHeight / 1.5;

        pc = new PointCollection();

        var n = step;
        while (--n > 0)
        {
            List<Char> s = getS(skip);
            draw(s);
        }

        Polyline p = new Polyline();
        p.Stroke = new SolidColorBrush(Colors.Red);
        p.StrokeThickness = 0.5;

        p.Points = pc;
        canvas.Children.Add(p);
    }


    List<Char> getS(Int32 n)
    {
        List<Char> s1 = new List<Char>();
        while (n-- > 0) s1.Add(getNext(0));
        return s1;
    }


    void draw(List<Char> s)
    {        
        pc.Add(new Point(x, y));
        for (Int32 i = 0, n = s.Count; i < n; i++)
        {
            pc.Add(new Point(x, y));
            Int32 j;
            if (int.TryParse(s[i].ToString(), out j) && j != 0)
            {
                if ((a + 90) % 360 != 0)
                {
                    a = (a + 90) % 360;
                }
                else
                {
                    a = 360; // Right
                }
            }
            else
            {
                if (a - 90 != 0)
                {
                    a = a - 90;
                }
                else
                {
                    a = 360; // Right
                }
            }
            // new target
            if (a == 0 || a == 360)
            {
                y -= distance;
            }
            else if (a == 90)
            {
                x += distance;
            }
            else if (a == 180)
            {
                y += distance;
            }
            else if (a == 270)
            {
                x -= distance;
            }

            // move
            pc.Add(new Point(x, y));
        }

    }

    Char getNext(Int32 n)
    {
        if (position[n] == 7)
        {
            r = getNext(n + 1);
            position[n] = 0;
        }
        else
        {
            var x = position[n] > 0 ? pattern[position[n]] : pattern[0];

            switch (x)
            {
                case 0:
                    r = '0';
                    break;
                case 1:
                    r = '1';
                    break;
                case 2:
                    if (!toggle)
                    {
                        r = '1';
                    }
                    else
                    {
                        r = '0';
                    }
                    toggle = !toggle;
                    break;
            }
            position[n] = position[n] + 1;                
        }

        return r;
    }

}
Antipodes answered 9/10, 2011 at 10:44 Comment(2)
Possibly, better fit for codereview.stackexchange.comLazybones
@Lazybones Definately not. This is non-working code, it does not achieve what it set out to do. (that is a dragon curve fractal.)Beloved
S
4

I cleaned up the code, and tried to get how the pattern and position arrays should work to produce the correct sequence, but I couldn't figure it out. The last item in the pattern array is for example never used...

There is however a simpler method implementing the getNext method using just a counter:

bool getNext() {
  cnt++;
  return (cnt & ((cnt & -cnt) << 1)) != 0;
}

I have used that method before (about 20 years ago), and I found this implementation on the dragon curve wikipedia page.

The cleaned up code with this getNext implementation looks like this:

public partial class MainPage : UserControl {
    PointCollection pc;

    int cnt = 0;

    int distance = 10; // line length
    int steps = 1024; // number of paints

    int x = 0;
    int y = 0;
    int a = 90;


    public MainPage() {
        InitializeComponent();
    }


    private void btnFire_Click(object sender, RoutedEventArgs e) {

        x = (int)(canvas.ActualWidth / 3);
        y = (int)(canvas.ActualHeight / 1.5);

        pc = new PointCollection();

        draw(getS(steps));

        Polyline p = new Polyline();
        p.Stroke = new SolidColorBrush(Colors.Red);
        p.StrokeThickness = 0.5;

        p.Points = pc;
        canvas.Children.Add(p);
    }


    List<bool> getS(int n) {
        List<bool> s1 = new List<bool>();
        while (n-- > 0) {
            s1.Add(getNext());
        }
        return s1;
    }


    void draw(List<bool> s) {
        pc.Add(new Point(x, y));
        foreach (bool z in s) {

            a = (a + (z ? 90 : 270)) % 360;

            // new target
            switch (a) {
                case 90: x += distance; break;
                case 180: y += distance; break;
                case 270: x -= distance; break;
                default: y -= distance; break;
            }

            // move
            pc.Add(new Point(x, y));
        }

    }

    bool getNext() {
        cnt++;
        return (cnt & ((cnt & -cnt) << 1)) != 0;
    }

}
Schematize answered 9/10, 2011 at 12:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.