The Dragon

I’ve been looking at the Dragon fractal, and wrote my own algorithm for it. Most of the examples online require a purely horizontal or vertical solution. I have generalized it to allow for a starting point/ending point for the initial line segment. I could probably allow rotational direction to be parameterized as well – but hey, I have real work to do.

dragon-fractal

The code is fairly simple. It is written in C#, using WPF, though much of the logic could  easily be abstracted into another language or windowed framework. It pretty much takes a count of iterations to produce the sequence of right/left turns. The original points determine the line-segment length. I’ve customized the display logic so that the curve remains within the boundaries of the canvas (and scrollable).

UPDATE: Here is a nicer image, done with more iterations and a smaller segment length…

dragon-fractal-15


The contents of Window1.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DragonFractal
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public enum Direction { Right, Left };
        public class ColoredDirection
        {
            public Direction Turn = Direction.Right;
            public SolidColorBrush Shade = Brushes.Black;

            public ColoredDirection(Direction turn, SolidColorBrush shade)
            {
                Turn = turn;
                Shade = shade;
            }
            public ColoredDirection(Direction turnRight)
            {
                Turn = turnRight;
            }
            public ColoredDirection()
            {
            }
        }

        public Window1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            SolidColorBrush brush = Brushes.DarkOliveGreen;

            Clear();

            List<ColoredDirection> list = new List<ColoredDirection>();
            for (int i = 0; i < int.Parse(Iterations.Text); i++)
            {
                List<ColoredDirection> nextList = new List<ColoredDirection>(list);

                nextList.Add(new ColoredDirection(Direction.Right,brush));

                list.Reverse();

                foreach (ColoredDirection direction in list)
                {
                    ColoredDirection newDirection = new ColoredDirection();
                    newDirection.Shade = brush;
                    if (direction.Turn == Direction.Right)
                    {
                        newDirection.Turn = Direction.Left;
                    }
                    else
                    {
                        newDirection.Turn = Direction.Right;
                    }

                    nextList.Add(newDirection);
                }
                list = nextList;

                Color color = new Color();
                color.R = brush.Color.B;
                color.B = brush.Color.G;
                color.G = brush.Color.R;
                color.A = brush.Color.A;
                brush = new SolidColorBrush(color);
            }
            ColoredDirection[] directions = list.ToArray();

            double x1 = double.Parse(X1.Text);
            minX = x1;
            maxX = x1;
            double y1 = double.Parse(Y1.Text);
            minY = y1;
            maxY = y1;
            double x2 = double.Parse(X2.Text);
            double y2 = double.Parse(Y2.Text);

            double segmentLength = Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2));

            DrawLine(Brushes.Black, x1, y1, x2, y2);

            for (int segment = 0; segment < directions.Length; segment++)
            {
                double lastAngleX = Math.Acos(Math.Round(x2 - x1,5) / segmentLength);
                double lastAngleY = Math.Asin(Math.Round(y2 - y1,5) / segmentLength);

                double currentAngle = (Math.Sign(lastAngleY) == -1.0) ? (360.0 * Math.PI / 180.0 - lastAngleX) : (lastAngleX);
                currentAngle = currentAngle + ((directions[segment].Turn==Direction.Left) ? 90 : -90) * Math.PI / 180.0;

                x1 = x2;
                y1 = y2;
                x2 = x1 + segmentLength * Math.Cos(currentAngle);
                y2 = y1 + segmentLength * Math.Sin(currentAngle);

                Line line = DrawLine(directions[segment].Shade, x1, y1, x2, y2);
            }

        }

        private Line DrawLine(SolidColorBrush brush,double x1, double y1, double x2, double y2)
        {
            Line myLine = new Line();
            myLine.Stroke = brush;
            myLine.X1 = x1;
            myLine.X2 = x2;
            myLine.Y1 = y1;
            myLine.Y2 = y2;
            myLine.StrokeThickness = 1;
            myLine.RenderTransformOrigin = new Point(0, 0);
            myLine.RenderTransform = Translator;
            canvas1.Children.Add(myLine);

            ManageDrawingArea(x2, y2);

            return myLine;
        }

        private void Clear()
        {
            canvas1.Children.Clear();

            minX = 0.0;
            minY = 0.0;
            maxX = 0.0;
            maxY = 0.0;

            Translator.X = 0;
            Translator.Y = 0;
        }

        TranslateTransform Translator = new TranslateTransform(0, 0);
        double minX = 0.0;
        double minY = 0.0;
        double maxX = 0.0;
        double maxY = 0.0;
        private void ManageDrawingArea(double x2, double y2)
        {
            if (x2 < minX) minX = x2;
            if (x2 > maxX) maxX = x2;
            if (y2 < minY) minY = y2;
            if (y2 > maxY) maxY = y2;

            if (minX < 0)
            {
                Translator.X = -minX + 10.0;
                canvas1.Width = maxX - minX + 10.0;
            }
            else
            {
                canvas1.Width = maxX;
            }

            if (minY < 0)
            {
                Translator.Y = -minY + 10.0;
                canvas1.Height = maxY - minY + 10.0;
            }
            else
            {
                canvas1.Height = maxY;
            }
        }
    }
}

The contents of Window1.xaml:

<Window x:Class="DragonFractal.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Button Height="23" Margin="10.829,0,0,76.636" Name="button1" VerticalAlignment="Bottom" Click="button1_Click" HorizontalAlignment="Left" Width="75.581">Run</Button>
        <TextBox Height="23" Margin="19.159,0,138.278,45.815" Name="X1" VerticalAlignment="Bottom">40</TextBox>
        <TextBox Height="23" HorizontalAlignment="Right" Margin="0,0,6.664,45.815" Name="Y1" VerticalAlignment="Bottom" Width="120">40</TextBox>
        <TextBox Height="23" Margin="19.159,0,138.278,17.493" Name="X2" VerticalAlignment="Bottom">50</TextBox>
        <TextBox Height="23" HorizontalAlignment="Right" Margin="0,0,6.664,17.493" Name="Y2" VerticalAlignment="Bottom" Width="120">50</TextBox>
        <TextBox Height="23" Margin="94.962,0,107.457,74.774" Name="Iterations" VerticalAlignment="Bottom">1</TextBox>
        <ScrollViewer Name="scrollViewer1" Margin="0,0,0,101.626" CanContentScroll="False" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Canvas Name="canvas1" ClipToBounds="False" Background="AntiqueWhite" HorizontalAlignment="Left" VerticalAlignment="Top" Height="158.27" Width="260.729"></Canvas>
        </ScrollViewer>
    </Grid>
</Window>
Advertisements

About George

I'm interested in theology, languages, translation and various sorts of fermentation.
This entry was posted in Code Samples, Mathematics and tagged , , . Bookmark the permalink.

2 Responses to The Dragon

  1. George says:

    Just to be clear – the code is setup for “Right” rotation, as compared to “Left”. However, The coordinate system in WPF sets (0,0) at the upper left hand corner, which means the representation on screen is upside down… giving the impression of “Left” rotation. I could probably skew the whole thing with a Transform in such a way as to reverse the effect, but did not do so.

  2. George says:

    Ok, went ahead and figured it out – how to flip the coordinate system (so to speak). It at least gets rotation in the expected direction.

    Hust add the following code in the Clear() method.

    canvas1.RenderTransformOrigin = new Point(0.5, 0.5);
    canvas1.RenderTransform = new ScaleTransform(1, -1);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s