### Author Topic: Fractals !  (Read 2146 times)

#### PhoenixII54 ##### Fractals !
« on: September 15, 2017, 11:10:58 am »
No, you didn't misread, what i'm about to give you is a series of scripts normally used in mathematics.
They don't desserve any porpose other than having fun with the engine, so enjoy !

1. the Mandelbrot set
Code: ( lua) [Select]
`--[[A useless-thus-indispensable Mandelbrot set rendererHow it works : the Mandelbrod set consists of a 2d grid of complex numbers,which are an extension of real numbers and are written in, the form :a+b*i, where a and b are two real numbers, and i is the square root of -1,also called the imaginary nuimber.For each point of the grid, let(s call it c, we gererate a new complex, number called z by applying the following formula :initial z value : 0new z = (z to the power of <whatever you want>) + cthen we compare the new value to (2 to the power of <the same exponent as before>then, we continue in one of the wollowing cases :   if z is lower than the powered 2, then we do the above steps again, unless we reached the maximum number if iterations   if, however, we are equal or higher than the powered 2,   then we stop iterating since the next calculated numbers wil keep growing forever, namely, we escaped the 2-range stability areaAnyway, once we have finished calculatins the final value for a given number, we color it according to it's behaviour :-if we escaped, then we color the corresponding point using the number of cleared iterations to index the color from a palettetaking the mod from table size-else, we color it pitch blackthis process goes on and on until all visible points are rendered.For more information, feel free to check on the Wiki or any math articleHow to use :1. create a map of the size of your choice2. copy/paste this whole code in the map script.3. setup the config table with your own parameters4. Run the map !--]]local map = ...local game = map:get_game()-- the configuration tablelocal config={  -- Size of the rendering area in game pixels.  -- Must be lower than the map size to render properly  grid={    width=401,    height=401  },  -- the maximum number of iterations for each point.  maxIterations=1000,  -- the calculation power. Defaulr : 2  powerExponent=2,  -- the starting complex numbers boundaries  numberBoundaries={    x={      min=-2,      max=2,    },    y={      min=-2,      max=2,    },  },  step={},}local start_time-- returns the module of any complex number, aka the length of the vector represented by this numberlocal function get_module(c)  return c.real*c.real+c.imag*c.imagend--calculates z^N with z=real+i*imag and N>0local function complex_power(c, exponent)  local squaredModule=get_module(c)  local newModule=math.pow(squaredModule,exponent/2)  local argument=math.atan2(c.imag,c.real)  return {    real=math.cos(exponent*argument)*newModule,    imag=math.sin(exponent*argument)*newModule,  }endlocal currentNumber={  real=config.numberBoundaries.x.min,  imag=config.numberBoundaries.y.max,}local currentPoint={  x=0,  y=0,}-- a 1*1 surface used as a pixel, to compensate the lack of proper API pixel manipulatinf functionslocal pixel=sol.surface.create(1,1)local fractalRender=sol.surface.create(config.grid.width,config.grid.height)-- the actual color palette. Feel free to modify it with your own colors (any size will work)local color_palette={  {255,255,0},  {255,223,31},  {255,191,63},  {255,159,95},  {255,127,127},  {255,95,159},  {255,63,191},  {255,31,223},  {223,0,255},  {255,31,255},  {191,63,255},  {159,95,255},  {127,127,255},  {95,159,255},  {63,191,255},  {31,223,255},  {0,255,255},  {31,255,223},  {63,255,191},  {95,255,159},  {127,255,127},  {159,255,95},  {191,255,63},  {223,255,31},}-- the rendering calllocal function draw_point(x,y,i)  local color  if i==config.maxIterations then    color={0,0,0}  else    local index=(i%#color_palette)+1    color=color_palette[index]  end  pixel:fill_color(color)  pixel:draw(fractalRender,x,y)end-- the core functions. Called once per map update.-- i don't use for loops to get each point, but increase indices at the end of this function instead.-- to save the engine from lagging/crashinglocal function calculateNextPoint()  local z={    real=0,    imag=0,  }  local real=currentNumber.real  local imag=currentNumber.imag  local i=0  local e=config.powerExponent  --The core calculation loop. see the explaination at the beginning of the script  while (i<config.maxIterations and get_module(z)<=math.pow(2,e)) do    local temp=complex_power(z,e)    z.real=temp.real+real    z.imag=temp.imag+imag    i=i+1  end  --render point  draw_point(currentPoint.x,currentPoint.y,i)  --Prepare for next loop  currentPoint.x=currentPoint.x+1  currentNumber.real = real + config.step.x  --End of horizontal line  if real > config.numberBoundaries.x.max then    currentNumber.real = config.numberBoundaries.x.min    currentNumber.imag = imag-config.step.y    currentPoint.x=0    currentPoint.y=currentPoint.y+1  end    if imag<config.numberBoundaries.y.min then  --All points have been processed. We can stop the function from starting again    --Debug lines for render time benchmarking? uncomment the next two lines to activate    --print("done !")    --print("time elapsed :"..os.clock()-start_time .."s")    return false  end  return trueendfunction map:on_started()  map:get_hero():set_visible(false)endfunction map:on_finished()  map:get_hero():set_visible(true)end-- starting the whole processfunction map:on_opening_transition_finished()  config.step.x=(config.numberBoundaries.x.max-config.numberBoundaries.x.min)/(config.grid.width-1)  config.step.y=(config.numberBoundaries.y.max-config.numberBoundaries.y.min)/(config.grid.height-1)  --print("step X="..config.step.x..",step Y="..config.step.y)  --getting the current time for later usage, if you want to benchmark the rendering duration, just uncomment the next line  --start_time=os.clock()  sol.timer.start(1, calculateNextPoint)endfunction map:on_draw(dst)  local camera=map:get_camera()  local x,y=camera:get_position()  local w,h=sol.video.get_quest_size()  fractalRender:draw_region(x,y,w,h,dst)end`Here is a screenshot of a render using the default exponent (2) : 2. the Sierpinsky Triangle
Code: ( lua) [Select]
`--[[The Sierpinsky triangle.On of the well known fractals, often used as a demonstration for calculators programmingWhen rendered, it shows a Triforce-like shape, with each triangle being a raduction of the base figure.like this       /\      /--\     /\  /\    /__\/__\   /\      /\  /__\    /__\ /\  /\  /\  /\/__\/__\/__\/__\For more information, feel free to check on the Wiki or any math article How to use :1. create a map of the size of your choice2. copy/paste this whole code in the map script.3. setup the config variables with your own parameters4. Run the map !--]]local map = ...-- Must be lower or equel to map size to render properlylocal grid={  width=200,  height=200}local maxIterations=10000-- the outer triangle summitslocal summits={   {0,0},   {grid.width,0},   {grid.width/2,grid.height},}local point-- initial positionlocal x=grid.width/2local y=grid.height/2local iterlocal fractalRender= sol.surface.create(grid.width,grid.height)local pixel=sol.surface.create(1,1)pixel:fill_color({0,0,0})local game = map:get_game()-- Event called at initialization time, as soon as this map becomes is loaded.function map:on_started()  map:get_hero():set_visible(false)  iter=0  --print("initial point : X="..x..", Y="..y)endfunction map:on_finished()  map:get_hero():set_visible(true)endfunction map:on_update()  if iter <maxIterations then    --these three lines are all the calculation. Yes, this fractal is very easy to setup.    --Note, they directly come from internet, so feel free to change to your own.    point=summits[math.random(3)]    x=(x+point)/2    y=(y+point)/2      --[[    -- my calculator's example script from the instruction book. Kept here for historical reasons, feel free to remove.    random=math.random(999)    --local random    --print("random number : "..random)    if random<=333 then      x=x/2      y=y/2    elseif random >333 and random <=666 then      x=(x+(base_size/2))/2      y=(y+base_size)/2    else       x=(x+base_size)/2      y=y/2    end      --]]  --print("new point on cycle "..count..": X="..x..", Y="..y)  pixel:draw(fractalRender, x,grid.height-y)  iter=iter+1  endendfunction map:on_draw(dst)  fractalRender:draw(dst)end`Screenshot of the render : That's all for now! More to come later.... maybe !
Feel free to test, but be warned : it can, and will, take some time to get a full render, depending of your computer power and the parameters you chose.
if you have suggestions for improvements, feel free to.
Enjoy !

Edit (2017/09/21) : Added screenshots of the renders.
« Last Edit: September 21, 2017, 10:47:28 am by PhoenixII54 »

#### Diarandor

• Hero Member
•     • • Posts: 1061
• Cats are cool! （ΦωΦ） ##### Re: Fractals !
« Reply #1 on: September 15, 2017, 05:26:44 pm »
Thanks a lot for sharing these scripts. Fractals are very interesting and beautiful. Although we are a bit unlucky that pixel art is really bad to draw a fractal... But now we can easily draw triforces with your Sierpinsky script “If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you.”

#### froggy77 ##### Re: Fractals !
« Reply #2 on: September 19, 2017, 07:43:54 pm »

#### MetalZelda

• Hero Member
•     • • Posts: 551 ##### Re: Fractals !
« Reply #3 on: September 24, 2017, 11:36:16 pm »
Interesting concept, I've always been amazed by fractals

#### froggy77 ##### Re: Fractals !
« Reply #4 on: November 03, 2017, 07:13:58 pm »
Indeed, it is an interesting concept. Thank you for having added images.
I tested the first script; ouch! "time elapsed :95.834s" to display the result. 