Mandelbrot Fractal Generator

 

package ui.mandelbrot;


/////////////////////////////////////////////////////////////////////////////////////////

// (c) Copyright 2009, Daniel P. Darnell

// This software is provided AS IS.

// Permission to use, copy and modify this software for any purpose and

// without fee is hereby granted provided that I am given credit for

// creating this original work.

//

// I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL

// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I

// BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY

// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER

// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING

// OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

//////////////////////////////////////////////////////////////////////////////////////////


import com.ibm.egl.rui.widgets.*;

import egl.javascript.Job;

import draw2d.*;


handler Main type RUIhandler{initialUI =[ui], onConstructionFunction=initialization}


    ui Div { backgroundColor="white", children =[buttonBox, d] };


    buttonBox Box { backgroundColor="gray", height = 30, width = 286, columns = 2,

        children =[startButton, messageLabel] };

   

    startButton Button { marginTop = 2, text = "New", onClick ::= clickStartButton };

   

    messageLabel TextField { width = 200, marginLeft = 10, marginTop = 5,

        borderWidth = 0, fontSize = 12, fontWeight = "bold", backgroundColor = "gray",

        text = "(May take several minutes)" };


    d Draw2D { borderStyle="solid", borderColor="lightgrey", borderWidth=3,

        zIndex = 1, width = 280, height = 320, onStartDrag = start, onDrag = drag,

        onDropOnTarget = drop };


    private const vwidth int = 280;

    private const vheight int = 320;

    private const voffset int = 30;


    // Mandlebrot formula variables

    private left, right, top, bottom float;

    private const iters int = 128; // Increase this for greater definition.

   

    function initialization()

        Document.body.appendChild(showDrag);

    end


    function clickStartButton(e Event in)

        // Default formula parameters

        left = -2.25;

        right = 1.75;

        top = 1.5;

        bottom = -2.5;


        startButton.setDisabled(true);

        buildMandelbrot();

    end


    /* -------------------------------------------------------------------------------

     * Drag and drop

     * ------------------------------------------------------------------------------- */

    showDragX, showDragY int;

    showDrag HTML { position = "absolute", visibility = "hidden",

        zIndex = 999, background = "lightgrey", opacity = 0.5, x = 0, y = 0 };


    private function start(w Widget in, startX int in, startY int in) returns(boolean)

        showDragX = startX;

        showDragY = startY;

        showDrag{visibility = "visible", x = startX, y = startY};


        return(true);

    end


    private function drag(w Widget in, dropw Widget in, dragX int in, dragY int in)

        showDrag.width = dragX - showDragX;

        showDrag.height = dragY - showDragY;

    end


    private function drop(w Widget in, dropw Widget in, dragX int in, dragY int in)

        showDrag.visibility = "hidden";


        if(dragX > showDragX and dragY > showDragY)

            xi float =(right - left) / vwidth;

            yi float =(bottom - top) / vheight;


            right = left +(dragX * xi);

            left = left +(showDragX * xi);


            bottom = top +((dragY - voffset) * yi);

            top = top +((showDragY - voffset) * yi);


            startButton.setDisabled(true);

            buildMandelbrot();

        end

    end


    /* -------------------------------------------------------------------------------

     * Build Mandelbrot: Set intial variables and then fire up scheduled job

     * to build image one vertical line at a time.

     * ------------------------------------------------------------------------------- */

    xi, yi float;


    xx1, yy1 float;  

    x0, y0 float;

    x1, y1 float;

    x2, y2 float;

    xz, yz, zz float;

    c float;


    j, k, l, zcolor, rcolor, gcolor, bcolor int;

    buildMandelbrotJob Job { runFunction = buildMandelbrotIteration };


    private function buildMandelbrot()

        d.clear();

        d.lineWidth = 1;


        // Calculate increment

        xi =(right - left) / vwidth;  // Width

        yi =(bottom - top) / vheight;  // Height

       

        // Set starting point back by increment

        xx1 = left - xi;

        yy1 = top - yi;


        j = 1;


        buildMandelbrotJob.repeat(1);

    end


    /* --------------------------------------------------------------------------------

     * Build and draw one vertical line of the image.

     *

     * Use job scheduling functionality to iterate so that other things can

     * happen too (like display of the progress icon).

     * ------------------------------------------------------------------------------- */

    private function buildMandelbrotIteration()

        if(j < vwidth)


            messageLabel.text = "("+(j*100/vwidth)as int+"% Complete)";


            xx1 = xx1 + xi;

            yy1 = top - yi;


            // Loop for height

            k = 1;

            lastk int = 1;

            lastColor String = "";

            while(k < vheight)


                yy1 = yy1 + yi;

                x1 = xx1;

                y1 = yy1;


                x0 = xx1;

                y0 = yy1;

                zcolor = 100;


                // Perform iterations

                l = 1;

                while(l < iters)


                    xz = x1 * x1;

                    yz = y1 * y1;

                    zz = xz + yz;


                    c = MathLib.sqrt(zz);

                    if(c > 2)

                        l = iters;

                    else

                        zcolor = zcolor + 5000;


                        x2 = xz +(yz * -1);

                        y2 =(x1 * y1) * 2;


                        // Set up for next iteration

                        x1 = x2 + x0;

                        y1 = y2 + y0;

                    end


                    l += 1;

                end


                bcolor = zcolor / 65536;

                gcolor =(zcolor -(65536 * bcolor)) / 256;

                rcolor = zcolor -(65536 * bcolor + 256 * gcolor);


                color string = "RGB(" + rcolor + "," + gcolor + "," + bcolor + ")";

                if (color != lastColor)

                    d.color = lastColor;

                    lastColor = color;

                    d.drawLine(j, lastK, j, k);

                    lastK = k;

                end


                k += 1;

                if (k == vheight)

                    d.color = color;

                    d.drawLine(j, lastK, j, k+1);

                end


            end


            j += 1;

        else

            buildMandelbrotJob.cancel();

            startButton.setDisabled(false);

            messageLabel.text = "Click and drag to zoom in";

        end

    end


end