Hi all :)

I'm having a few problems with this assignment I'm working on. Its a Java - C# conversion of a Mandelbrot program.

What I'm trying to do, is draw the Mandelbrot to a Bitmap, and then print it onto the Windows form. So far I've been able to just draw aqua lines on the bitmap/ellipses etc if I've wanted too, I just can't seem to get the mandelbrot on there!

Code is here:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Assignment
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

        }

        public struct HSBColor
        {
            float h;
            float s;
            float b;
            int a;

            public HSBColor(float h, float s, float b)
            {
                this.a = 0xff;
                this.h = Math.Min(Math.Max(h, 0), 255);
                this.s = Math.Min(Math.Max(s, 0), 255);
                this.b = Math.Min(Math.Max(b, 0), 255);
            }

            public HSBColor(int a, float h, float s, float b)
            {
                this.a = a;
                this.h = Math.Min(Math.Max(h, 0), 255);
                this.s = Math.Min(Math.Max(s, 0), 255);
                this.b = Math.Min(Math.Max(b, 0), 255);
            }

            public float H
            {
                get { return h; }
            }

            public float S
            {
                get { return s; }
            }

            public float B
            {
                get { return b; }
            }

            public int A
            {
                get { return a; }
            }

            public Color Color
            {
                get
                {
                    return FromHSB(this);
                }
            }

            public static Color FromHSB(HSBColor hsbColor)
            {
                float r = hsbColor.b;
                float g = hsbColor.b;
                float b = hsbColor.b;
                if (hsbColor.s != 0)
                {
                    float max = hsbColor.b;
                    float dif = hsbColor.b * hsbColor.s / 255f;
                    float min = hsbColor.b - dif;

                    float h = hsbColor.h * 360f / 255f;

                    if (h < 60f)
                    {
                        r = max;
                        g = h * dif / 60f + min;
                        b = min;
                    }
                    else if (h < 120f)
                    {
                        r = -(h - 120f) * dif / 60f + min;
                        g = max;
                        b = min;
                    }
                    else if (h < 180f)
                    {
                        r = min;
                        g = max;
                        b = (h - 120f) * dif / 60f + min;
                    }
                    else if (h < 240f)
                    {
                        r = min;
                        g = -(h - 240f) * dif / 60f + min;
                        b = max;
                    }
                    else if (h < 300f)
                    {
                        r = (h - 240f) * dif / 60f + min;
                        g = min;
                        b = max;
                    }
                    else if (h <= 360f)
                    {
                        r = max;
                        g = min;
                        b = -(h - 360f) * dif / 60 + min;
                    }
                    else
                    {
                        r = 0;
                        g = 0;
                        b = 0;
                    }
                }

                return Color.FromArgb
                    (
                        hsbColor.a,
                        (int)Math.Round(Math.Min(Math.Max(r, 0), 255)),
                        (int)Math.Round(Math.Min(Math.Max(g, 0), 255)),
                        (int)Math.Round(Math.Min(Math.Max(b, 0), 255))
                        );
            }

        }
       

        private const int MAX = 256;      // max iterations
        private const double SX = -2.025; // start value real
        private const double SY = -1.125; // start value imaginary
        private const double EX = 0.6;    // end value real
        private const double EY = 1.125;  // end value imaginary
        private static int x1, y1, xs, ys, xe, ye;
        private static double xstart, ystart, xende, yende, xzoom, yzoom;
        private static Boolean action, rectangle, finished;
        private static float xy;

        //private Image picture;
        private System.Drawing.Bitmap myBitmap;
        
        private Graphics g1;
        private Cursor c1, c2;
        //private HSB HSBcol = new HSB();

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            //Paint bitmap on load
            g1 = e.Graphics;

            g1.DrawImage(myBitmap, 0, 0, x1, y1);

            g1.Dispose();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Paint to bitmap on load
            init();
            mandelbrot();
        }

        public void init() // all instances will be prepared
        {
            //HSBcol = new HSB();
            //setSize(640, 480);

            finished = false;

            //addMouseListener(this);
            //addMouseMotionListener(this);

            //c1 = new Cursor(Cursor.WAIT_CURSOR);
            //c2 = new Cursor(Cursor.CROSSHAIR_CURSOR);

            //x1 = getSize().width;
            x1 = 640;
            
            //y1 = getSize().height;
            y1 = 480;

            xy = (float)x1 / (float)y1;
            
            //picture = createImage(x1, y1);
            myBitmap = new Bitmap(x1, y1);


            g1 = Graphics.FromImage(myBitmap);
            //g1 = picture.getGraphics();
            
            finished = true; 
        }

        public void destroy() // delete all instances 
        {
            if (finished)
            {
               // removeMouseListener(this);
               // removeMouseMotionListener(this);

                //picture = null;

                g1 = null;
                c1 = null;
                c2 = null;
                GC.Collect(); // garbage collection
            }
        }

        public void start()
	    {
		action = false;
		rectangle = false;
		initvalues();
		xzoom = (xende - xstart) / (double)x1;
		yzoom = (yende - ystart) / (double)y1;
		mandelbrot();
	    }

        public void stop()
        {
        }

        public void paint(Graphics g)
        {
            update(g);
        }

        public void update(Graphics g)
        {
        /*    g.drawImage(picture, 0, 0, this);
            if (rectangle)
            {
                g.setColor(Color.white);
                if (xs < xe)
                {
                    if (ys < ye) g.drawRect(xs, ys, (xe - xs), (ye - ys));
                    else g.drawRect(xs, ye, (xe - xs), (ys - ye));
                }
                else
                {
                    if (ys < ye) g.drawRect(xe, ys, (xs - xe), (ye - ys));
                    else g.drawRect(xe, ye, (xs - xe), (ys - ye));
                }
            }*/
        }

        private void mandelbrot() // calculate all points
        {
            int x, y;
            float h, b, alt = 0.0f;

            action = false;
            //setCursor(c1);
            //showStatus("Mandelbrot-Set will be produced - please wait...");
            for (x = 0; x < x1; x += 2)

                for (y = 0; y < y1; y++)
                {
                    h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); // color value
                    if (h != alt)
                    {
                        b = 1.0f - h * h; // brightnes
                       
                        ///djm added
                        //HSBcol.fromHSB(h,0.8f,b); //convert hsb to rgb then make a Java Color
                       // Color col = new Color(0,HSBcol.rChan,HSBcol.gChan,HSBcol.bChan);
                       // g1.setColor(col);
                        //djm end
                        //djm added to convert to RGB from HSB

                       // g1.setColor(Color.getHSBColor(h, 0.8f, b));
                        //djm test
                      //  Color col = Color.getHSBColor(h, 0.8f, b);
                      //  int red = col.getRed();
                       // int green = col.getGreen();
                      //  int blue = col.getBlue();
                        //djm 
                        alt = h;
                    }
                    Pen mypen = new Pen(System.Drawing.Color.Aqua);
                    g1.DrawLine(mypen, x, y, x + 1, y);
                }
            //showStatus("Mandelbrot-Set ready - please select zoom area with pressed mouse.");
            //setCursor(c2);
            action = true;
        }

        private float pointcolour(double xwert, double ywert) // color value from 0.0 to 1.0 by iterations
        {
            double r = 0.0, i = 0.0, m = 0.0;
            int j = 0;

            while ((j < MAX) && (m < 4.0))
            {
                j++;
                m = r * r - i * i;
                i = 2.0 * r * i + ywert;
                r = m + xwert;
            }
            return (float)j / (float)MAX;
        }

        private void initvalues() // reset start values
        {
            xstart = SX;
            ystart = SY;
            xende = EX;
            yende = EY;
            if ((float)((xende - xstart) / (yende - ystart)) != xy)
                xstart = xende - (yende - ystart) * (double)xy;
        }  
           
    }
       
}

Now that code will just produce an Aqua box, which was a test I put in to see if I'm writing to the bitmap.

Also: Some of the variables aren't being used yet, there's some extra functionality I need to add once I have this working!

I found this Mandelbrot method online, it helps by converting the colours (I'm British, that's how we spell color :P) So they work, I just can't get it to write to the Bitmap.

private void mandelbrot() // calculate all points
        {
            int x, y;
            float h, b, alt = 0.0f;

            action = false;
            for (x = 0; x < x1; x += 2)
                for (y = 0; y < y1; y++)
                {
                    h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); // color value
                    if (h != alt)
                    {
                        b = 1.0f - h * h; // brightnes

                        Color color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255)); // VERY IMPORTANT
                        //djm
                        alt = h;
                        Pen pen = new Pen(color);
                        g1.DrawLine(pen, x, y, x + 1, y);
                    }
                }
            action = true;
        }

Does anyone have any suggestions as to how I can get this Mandelbrot onto my Bitmap?

-Erslich

There is no longer "real life" - only AFK

I saw that one before I posted, using that code and editing it I can get it to create a small mandelbrot-like-thing!

Sadly, I can't use that thread to help me print my mandelbrot to a bitmap and then to the form :(

-Erslich

I am not sure what it is supposed to do but pointcolour is always returning 1.0f.
[Edit] This means that if (h != alt) is only true on the first iteration!

Edited 6 Years Ago by nick.crane: n/a

It's part of the original Java Program, I think its to set the colour of the Mandelbrot.

Here is the original Java code for the Mandelbrot:

private void mandelbrot() // calculate all points
	{
		int x, y;
		float h, b, alt = 0.0f;
		
		action = false;
		setCursor(c1);
		showStatus("Mandelbrot-Set will be produced - please wait...");
		for (x = 0; x < x1; x+=2)
			for (y = 0; y < y1; y++)
			{
				h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); // color value
				if (h != alt)
				{
					b = 1.0f - h * h; // brightnes
					///djm added
					///HSBcol.fromHSB(h,0.8f,b); //convert hsb to rgb then make a Java Color
					///Color col = new Color(0,HSBcol.rChan,HSBcol.gChan,HSBcol.bChan);
					///g1.setColor(col);
					//djm end
					//djm added to convert to RGB from HSB
					
					g1.setColor(Color.getHSBColor(h, 0.8f, b));
					//djm test
				Color col = Color.getHSBColor(h,0.8f,b);
				int red = col.getRed();
				int green = col.getGreen();
				int blue = col.getBlue();
					//djm 
					alt = h;
				}           
				g1.drawLine(x, y, x + 1, y);
			}
		showStatus("Mandelbrot-Set ready - please select zoom area with pressed mouse.");
		setCursor(c2);
		action = true;
	}

Another thing I noticed is that you are drawing a line of length one.
You could get rid of the graphics object for the bitmap and just set the pixels on the image directly.
E.g. myBitmap.SetPixel(x, y, color); This worked when I ran it in your Aqua test.

Edited 6 Years Ago by nick.crane: n/a

Got it!
xzoom and yzoom are not being initialised.
Try calling start() in form load instead of mandelbrot().

private void Form1_Load(object sender, EventArgs e)
        {
            //Paint to bitmap on load
            init();
            start();
        }

Sorry that the other one was posted twice it error-ed on me :-(

And yeah sure, its the same as the C#, the only time the method is called is inside the mandelbrot

private float pointcolour(double xwert, double ywert) // color value from 0.0 to 1.0 by iterations
	{
		double r = 0.0, i = 0.0, m = 0.0;
		int j = 0;
		
		while ((j < MAX) && (m < 4.0))
		{
			j++;
			m = r * r - i * i;
			i = 2.0 * r * i + ywert;
			r = m + xwert;
		}
		return (float)j / (float)MAX;
	}

Edited 6 Years Ago by Erslich: n/a

THANK YOU!!! It works! I have my Mandelbrot displaying! Wow, I have been bashing my head against the screen all day and it's now sorted :)

I owe you one :)

No problem.
The default control back colour means my mandelbrot is a bit washed out.
What backcolor do you have on your form?

No problem.
The default control back colour means my mandelbrot is a bit washed out.
What backcolor do you have on your form?

I currently don't have a colour on the back of my form, I was thinking of just having the back of it as black...

Although I've looked at the Java Fractal (attached) and it's got an orange-esque background and then a black background in another section. I'm not sure how to achieve both of these.

Erslich

Edited 6 Years Ago by Erslich: n/a

Attachments frac2.jpg 64.16 KB

You are only drawing to your bitmap inside the if (h != alt) block.
Look at the java code again.
You will also need to keep track of the current colour between iterations.

[Edit] I have mine looking like the above image.

Edited 6 Years Ago by nick.crane: n/a

Comments
Fine contribution!

In the Java I can see the line:

g1.setColor(Color.getHSBColor(h, 0.8f, b));

This is the colour of the background(?), I'm missing this from my code.

I can convert this like so (I believe, I'm trying as I type)

Color background = HSBColor.FromHSB(new HSBColor(h, 0.8f, b));

Now obviously Java has a nice and simple way for setting the colour with "g1.setColour"... I'm not sure what the C# equivalent is? I've had a look at the available alternatives in Visual Studio (g1.FillRegion etc) but can't find the correct one... I will keep trying and googling.

Am I going in the right direction?

Still no break through :-/ I've tried various things after g1.

Color background = HSBColor.FromHSB(new HSBColor(h, 0.8f, b));
Pen penbg = new Pen(background);
//g1....

FillRegion doesn't work, unless I specify g1 as a region! I have also tried to set the individual pixels, but this doesn't work.

I have tried searching for a c# setColor equivalent but I can't find one.

Any suggestions on how to continue?

If you look at the original java code it always executes the draw, but only changes the colour when h changes ( if (h != alt) ).

You need to move the declaration of your color and pen variables outside the for loops so that you can keep track of the current colour.

Also, move the g1.DrawLine(pen, x, y, x + 1, y); below the if (h != alt) { } code block (but still inside the for loops).

This should give you the black to red colour transition.

Thanks for the response.

I have moved it around like so (see below) but there are 2 errors with "Use of unassigned local variable "b" and "h"".

The code still compiles and runs, however there is still no background colour to the Mandelbrot.

Color color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255)); 
            Pen pen = new Pen(color);

            for (x = 0; x < x1; x += 2)

                for (y = 0; y < y1; y++)
                {
                    h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); 

                    if (h != alt)
                    {
                        b = 1.0f - h * h; // brightness
                        //Color background = HSBColor.FromHSB(new HSBColor(h, 0.8f, b));
                        //g1.FillRegion
                        alt = h;
                        
                       
                    }
                    g1.DrawLine(pen, x, y, x + 1, y);
                }
            action = true;

Hold that! I've got it! It needs tidying but seems to be working, I will do some more testing and report back :)

Essentially I just took the Java "If" statement out, and it compiles and produces it with the brightness. Did you do the same or something similar to resolve?

for (y = 0; y < y1; y++)
                {
                    h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); 
                    b = 1.0f - h * h; // brightness
                    Color color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255)); 
                    Pen pen = new Pen(color);

                    /*if (h != alt)
                    {
                        b = 1.0f - h * h; // brightness
                        //Color background = HSBColor.FromHSB(new HSBColor(h, 0.8f, b));
                        //g1.FillRegion
                        Color color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255)); 
                        
                        alt = h;
                        Pen pen = new Pen(color);
                        g1.DrawLine(pen, x, y, x + 1, y);
                    }*/
                    g1.DrawLine(pen, x, y, x + 1, y);
                }
           
            action = true;
        }

Edited 6 Years Ago by Erslich: n/a

The Java "if" block is there for optimisation. It only does the HSB to RGB colour convertion if the colour (h) has changed.
This is more like the code I ended up with when I got it working.

// variables to hold current colour (initialised to prevent "Use of unassigned variable" errors)
Color color = Color.Black;
Pen pen = new Pen(color);

for (x = 0; x < x1; x += 2)
    for (y = 0; y < y1; y++)
    {
        // get colour value for this x,y point
        h = pointcolour(xstart + xzoom * (double)x, ystart + yzoom * (double)y); 
        // if colour value changed then calculate new colour
        if (h != alt)
        {
            // calculate brightness
            b = 1.0f - h * h;
            // calculate colour from HSB
            color = HSBColor.FromHSB(new HSBColor(h * 255, 0.8f * 255, b * 255)); 
            // get drawing pen for this colour
            pen = new Pen(color);
            // keep track of last colour value
            alt = h;
        }
        // draw line of length 1 in current colour
        g1.DrawLine(pen, x, y, x + 1, y);
    }

That makes a lot more sense :)

Thanks again for all your help, Really appreciated it! I'm not going to get a "zoomable" function working with my Mandelbrot! Wish me luck! lol!

New problem now with the "Zoomable" function, I will post it on here, but it might need a new thread.

I am zooming in by selecting an area, my methods are:

private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            if (action)
            {
                xe = Control.MousePosition.X;
                ye = Control.MousePosition.Y;
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            int z, w;

            
            if (action)
            {
                xe = Control.MousePosition.X;
                ye = Control.MousePosition.Y;
                if (xs > xe)
                {
                    z = xs;
                    xs = xe;
                    xe = z;
                }
                if (ys > ye)
                {
                    z = ys;
                    ys = ye;
                    ye = z;
                }
                w = (xe - xs);
                z = (ye - ys);
                if ((w < 2) && (z < 2)) initvalues();
                else
                {
                    if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
                    else xe = (int)((float)xs + (float)z * xy);
                    xende = xstart + xzoom * (double)xe;
                    yende = ystart + yzoom * (double)ye;
                    xstart += xzoom * (double)xs;
                    ystart += yzoom * (double)ys;
                }
                xzoom = (xende - xstart) / (double)x1;
                yzoom = (yende - ystart) / (double)y1;
                mandelbrot();
                rectangle = false;
                //repaint();
            }

I have debugged, and it works FINE taking the mouse values and everything. Up until we enter the mandelbrot method again, and we receive an error on the g1.drawline... line :(

I'm going to continue working on this, and try to get it solved, but any suggestions on where the code starts falling apart would be appreciated.

-Erslich

That makes a lot more sense :)

Thanks again for all your help, Really appreciated it! I'm not going to get a "zoomable" function working with my Mandelbrot! Wish me luck! lol!

How did you get to this point? can you post code show?

This question has already been answered. Start a new discussion instead.