PDA

View Full Version : Slices of Mandelbrot - the idea



RobbeK
15-03-2014, 21:38
Hi all,

Exploring somewhat further the mandelbrot maps where the power may be a rational number ....
The intension is to make something decent from this -- a nice solid 3D object capturing the power n->m map.
Probably difficult ??
What is a good tutorial for such things ? (i know nothing about it)

t.i.advance

Rob (u can use the arrow and PgUP / DN keys)

Petr Schreiber
17-03-2014, 21:09
Hi Rob,

what you have is so called "cloud of points". To make it solid, there are various approaches.

The most dumb one is to start with one vertex, and seek 2 nearest neighbours, then connect them to triangle, and continue this crawling process untill all points are done.
It would be pretty computionally expensive for sure, but that is what we have Oxy for :D But smart approach would be preffered - internet is full of papers on visualizing cloud of points data, try to start from here.

Games solve this usually by layering textures, if it would be regular grid, maybe some marching cubes could come into play...


Petr

RobbeK
17-03-2014, 23:37
Hi Petr,

"cloud of points" -- ok , nowadays it's very important to know the correct nomenclature avoiding endless googling ...


thanks again

Raytracer and other things to make static displays ???? good ??

ReneMiner
19-03-2014, 14:21
I played Mandelbrot too today, that's the result- a little canvas-window-example:



Uses "UI"

Type t_vec2D
X As Double
Y As Double
End Type

'-----------------------------------------------------------
' "user-defineable"
'-----------------------------------------------------------

' size
Dim clientWidth As Long = 320
Dim clientHeight As Long = 240

' area
Dim low As t_vec2D
Dim high As t_vec2D

low.X = -0.7
high.X = 2.1

low.Y = -1.2
high.Y = 1.2

' detail
%maxDepth = 255


'-----------------------------------------------------------
' more variables
'-----------------------------------------------------------


Dim t1, t2 As Quad '-- time measuring

Dim x, y As Long '-- for-next counters

Dim hWin As DWord '-- handle of canvas window


Dim delta As t_vec2d '-- for calculation
Dim complex As t_vec2d
Dim current As t_vec2d
Dim now As t_vec2d
Dim lDepth As Long

Dim screenWidth As Long = Win_GetSystemMetrics(%SM_CXSCREEN)
Dim screenHeight As Long = Win_GetSystemMetrics(%SM_CYSCREEN)

'-----------------------------------------------------------
' Main program
'-----------------------------------------------------------
hWin = Canvas_Window("mandelbrot", screenwidth/2 - clientwidth/2, screenheight/2-clientHeight/2, clientWidth, clientHeight )

Canvas_Attach(hWin, 0, %TRUE) ' <- double buffer

'---Start timer
HiResTimer_Init
t1 = HiResTimer_Get

'---Init canvas
Canvas_Clear(%BLACK)
'---go
delta.X = (High.X - Low.X) / clientWidth
delta.Y = (High.Y - Low.Y) / clientHeight
complex.X = Low.X
complex.Y = Low.Y

For Y = 0 To clientHeight
For X = 0 To clientWidth
lDepth = 0
current.X = 0
current.Y = 0
now.x = 0
now.y = 0
While (lDepth < %maxDepth) And (now.X + now.Y < 8) And TRUE
current.Y = 2 * current.X * current.Y - complex.Y
current.X = now.X - now.Y - complex.X
now.X = Pow(current.X, 2)
now.Y = Pow(current.Y, 2)

lDepth += 1
Wend
If lDepth >= %maxDepth Then
Canvas_Color(%BLACK)

Else
Canvas_Color(get_color(lDepth))
End If
complex.X = complex.X + delta.X

Canvas_SetPixel(x, y)

Next X
complex.X = low.X
complex.Y = complex.Y + delta.Y

Canvas_Redraw

Next Y

'---Ending timer
t2 = HiResTimer_Get

Canvas_SetPos 10, clientHeight - 20
Canvas_Color(%WHITE, %BLACK)
Canvas_Print "Time: " + Format$((t2 - t1) / 1000000, "#.000") + " - Key to end -"

'---A last redraw
Canvas_Redraw

Canvas_WaitKey
Canvas_Window End



Function get_color(ByVal d As Long) As Long
' randomly create a palette for any depth

Static c(%maxDepth) As Long

If d = 0 Then Return %BLACK

If c(d) = 0 Then
Randomize
c(d) = Rgb( Rnd(30,255), Rnd(30,255), Rnd(30,255) )

EndIf
Function = c(d)

End Function

RobbeK
19-03-2014, 18:51
Thanks Reneminer ,

good example of clean code IMO ... mine, sometimes is somewhat messy by (some/mosttimes) avoiding types (& objects).
( well, hm , most of the time, I know what I'm doing, but it is not so communicative towards others )


best Rob

ReneMiner
19-03-2014, 20:13
I prefer clear readeable code for eductional purposes - saves a lot of comments ;)

I also like those mandelbrot-visualizations where you seem to fly in another world but mine is far away. I exaggerated a little and ran it with a little more detail:


'-----------------------------------------------------------
' "user-defineable"
'-----------------------------------------------------------

' size
Dim clientWidth As Long = 1024
Dim clientHeight As Long = 768

' area
Dim low As t_vec2D
Dim high As t_vec2D

low.X = -0.441
high.X = -0.399

low.Y = -0.235
high.Y = -0.196

' detail
%maxDepth = 65535


It took "slightly a few seconds more" - any ideas to speed this up?
time for messy code :)

RobbeK
19-03-2014, 20:57
Hi ReneMiner,

Oxygen and bitmap copying speed up a lot.
Attached a few of my "Düsenjäger"

The first one is a Mandelbrot map of the complex Golden Ratio fractal z²+zc-c² , in the second one the powers of 2 that can be extended - by a slider (but only natural numbers -- the slices of ... do rational numbers, but the calculations are much more complex (uses De Moivre formula -- and there are some mathematical problems - you need Riemann surfaces to do so, the reason I love to have a solid 3D object (but if you look carefully you can see the "tears" in the drawings ).
Also I must mention a lot of code goes into the inside of the fractal (Mike and I were working on something - but it is hard to find something that is fast and also beautiful - it's the log(log) of the orbit with should give smooth surfaces - however (once again) my escape sequence is hyperbolic (not as yours x²+y² which generates circle arcs (from there the trident like glow))) ok enough

Rob (easy to convert in clean code ;-)

-- added ... A3C which generates circular gradients ( mod(z) ) , it's nicer (the code took only 5 sec to convert ;-)

ReneMiner
20-03-2014, 15:17
This morning I tried to "port" my example above just to use O2 for the calculation.
But I have to admit- I gave up after 2 hours trying - I don't know why but the use of O2 always makes me lose overview and I had a problem to create the random colors because I did not find out how to use RND-function for oxygen :D

RobbeK
20-03-2014, 17:14
Hi,

If you still have the code, possibly I can help ...
And because you know much more about UI than I do , I extended the Mandelbrot a little - you can zoom in/out with a slider now and center the image by just clicking on the canvas ..
However I can not manage to get immediate the coordinates from the canvas - I always get absolute screen positions (so I have to calculate them towards the canvas - but this only works if the window stays as the same place -- how can I read these coordinates - any coordinate will do also the main window... ?

(it's at line 229 -- program runs in real time, fast not ???? )

best Rob

ReneMiner
20-03-2014, 17:39
However I can not manage to get immediate the coordinates from the canvas - I always get absolute screen positions (so I have to calculate them towards the canvas...


I have some piece of all purpose-code for this:


' this explains the type
Type t_Mouse
X As Long
Y As Long
LButton As Long
MButton As Long
RButton As Long
Wheel As Long
End Type

Dim Mouse As t_Mouse ' here I will put the results

' for the buttons I have the states as values:
' -1 just released
' 0 button not used
' 1 button down
' 2 button held

' assume now "myCanvas" -variable holds your canvas-measurements

' this is inside the DIALOGs (!!!)-callback then:
'...
Select Case (CBMSG)
'...
Case %WM_MOUSEWHEEL
Mouse.Wheel = Sgn(HI(Integer, CBWPARAM))
' -1 = "Wheel: Down"
' 1 = "Wheel: Up"

Case %WM_LBUTTONDOWN
Mouse.LButton = 1
Case %WM_LBUTTONUP
Mouse.LButton = -1
Case %WM_MBUTTONDOWN
Mouse.MButton = 1
Case %WM_MBUTTONUP
Mouse.MButton = -1
Case %WM_RBUTTONDOWN
Mouse.RButton = 1
Case %WM_RBUTTONUP
Mouse.RButton = -1
Case %WM_MOUSEMOVE
' this retrieves position inside canvas then:
Mouse.X = LO(Integer, CBLPARAM) - myCanvas.X1 ' subtract canvas-left-position (in relation to window) here
Mouse.Y = HI(Integer, CBLPARAM) - myCanvas.Y1 ' subtract canvas-top-position

Mouse.LButton = IIf((CBWPARAM And %MK_LBUTTON), 2, 0)
Mouse.MButton = IIf((CBWPARAM And %MK_MBUTTON), 2, 0)
Mouse.RButton = IIf((CBWPARAM And %MK_RBUTTON), 2, 0)
' Dialog Set Text CBHNDL, "Mouse:" + Str$(Mouse.X) + "," + Str$(Mouse.Y)
If All (_
Between( Mouse.X, 1, myCanvas.Width), _
Between( Mouse.Y, 1, myCanvas.Height) _
) Then
' we are inside canvas-area:
MousePtr 2 ' haircross
Else
MousePtr 1 ' arrow
EndIf

'...
End Select

ReneMiner
21-03-2014, 11:14
EDIT: I made the mandelbrot once again, using TBGL this time and i draw onto some texture, buffered in a string

+ added: now you can click a position (when done drawing) and it will zoom in at this position



Uses "TBGL"

Type t_vec2D
X As Double
Y As Double
End Type


'-----------------------------------------------------------
' "user-defineable" globals
'-----------------------------------------------------------

' size
Dim clientWidth As Long = 320
Dim clientHeight As Long = 240

' area
Dim low As t_vec2D
Dim high As t_vec2D

low.X = -0.7
high.X = 2.1

low.Y = -1.2
high.Y = 1.2

' detail
%maxDepth = 500

' quality
%TEXTURE_Quality = %TBGL_TEX_MIPMAP ' use some medium quality

'-----------------------------------------------------------
' more variables
'-----------------------------------------------------------

Dim sTextureBuffer As String = $SPC(clientwidth * clientHeight * SizeOf(TBGL_TRGBA))

Dim keepRunning As Boolean = TRUE '-- run while True

Dim startingTime As Quad
Dim neededTime As Quad

%TextureID = 1 ' use texture-slot #1



'-----------------------------------------------------------
' Main program
'-----------------------------------------------------------

Function TBMain()

Local scrWidth, scrHeight, scrDepth As Long '-- screen-info
Local hWin As DWord '-- handle of window

Local LMouseBtn As Long '-- check left Mousebutton


TBGL_GetDesktopInfo(ScrWidth, ScrHeight, ScrDepth)

hWin = TBGL_CreateWindowEx( "mandelbrot in TBGL, ESC to quit", _
clientWidth, clientHeight, scrDepth, _
%TBGL_WS_WINDOWED Or %TBGL_WS_DONTSIZE Or %TBGL_WS_CLOSEBOX _
)
' -- create & activate some default-font at font-slot 1
TBGL_SetActiveFont TBGL_BuildFont TBGL_FontHandle("Lucida Console", 12), 1

' -- Resets status of all keys
TBGL_ResetKeyState()
' -- open the window
TBGL_ShowWindow

TBGL_RenderMatrix2D(0, clientHeight, clientWidth, 0) ' init matrix since it does not change...
TBGL_DepthFunc( %TBGL_ALWAYS ) ' draw from back to front

If TBGL_IsWindow(hWin) Then


HiResTimer_Init
run_Mandelbrot(hWin)

EndIf


' keep the window alive until esc-key
While TBGL_IsWindow(hWin) And keepRunning And TRUE
If TBGL_GetWindowKeyState(hWin, %VK_LBUTTON) Then
If Not lMouseBtn Then
If click_Mandelbrot(TBGL_MouseGetPosX, TBGL_MouseGetPosY) Then
run_Mandelbrot(hWin)
EndIf
lMouseBtn = 1
EndIf
Else
lMouseBtn = 0
EndIf

keepRunning = ( TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) = 0 )

Wend

' end of main-program
End Function

Sub draw_Mandelbrot()

' just displays the texture on some quadratical shape
Static sOut As String

TBGL_ClearFrame

TBGL_UseTexturing TRUE
TBGL_BindTexture(%TextureID)
TBGL_Color 255, 255, 255

TBGL_BeginPoly %GL_QUADS
TBGL_TexCoord2D 0, 0
TBGL_Vertex 0, clientHeight
TBGL_TexCoord2D 1, 0
TBGL_Vertex clientWidth, clientHeight
TBGL_TexCoord2D 1, 1
TBGL_Vertex clientWidth, 0
TBGL_TexCoord2D 0, 1
TBGL_Vertex 0, 0
TBGL_EndPoly

TBGL_UseTexturing FALSE

If neededTime = 0 Then
sOut = "Time elapsed: " + Format$((HiResTimer_Get - startingTime) / 1000000, "#.000")
Else
sOut = "Time needed: " + Format$(neededTime / 1000000, "#.000")
EndIf

TBGL_Color 32, 32, 32
TBGL_PrintFont2D sOut, 21, 33
TBGL_Color 255, 255, 128
TBGL_PrintFont2D sOut, 20, 32

TBGL_DrawFrame

End Sub

Sub run_Mandelbrot(ByVal hWin As DWord)

neededTime = 0

'--starting timer
startingTime = HiResTimer_Get

calculate_Mandelbrot(hWin) ' pass hWin to check for input while calculation

'--ending timer
neededTime = HiResTimer_Get - startingTime

'-- final draw
draw_Mandelbrot

End Sub

Function click_Mandelbrot(ByVal X As Long, ByVal Y As Long) As Boolean

Local total As t_vec2D
Local delta As t_vec2D
Local center As t_vec2D

If X < 1 Or Y < 1 Then Return FALSE

total.X = Abs(high.X - low.X)
total.Y = Abs(high.Y - low.Y)

delta.X = total.X / clientWidth
delta.Y = total.Y / clientHeight

center.X = low.X + X * delta.X
center.Y = low.Y + Y * delta.Y

low.X = center.X - total.X * 0.25
high.X = center.X + total.X * 0.25

low.Y = center.Y - total.Y * 0.25
high.Y = center.Y + total.Y * 0.25

Function = TRUE

End Function


Sub calculate_Mandelbrot(ByVal hWin As DWord)

Local x, y As Long '-- for-next counters
Local delta As t_vec2d '-- for calculation
Local complex As t_vec2d
Local current As t_vec2d
Local now As t_vec2d

Local lDepth As Long
Local lColor As Long

' place some layover upon texture-buffer
Local Texture(clientWidth, clientHeight) As Long At StrPtr(sTexturebuffer)
Array Fill Texture With lColor ' -- make all pixels 0,0,0,0 (black)


delta.X = (High.X - Low.X) / clientWidth
delta.Y = (High.Y - Low.Y) / clientHeight
complex.X = Low.X
complex.Y = Low.Y

For Y = clientHeight To 1 Step -1
For X = 1 To clientWidth
lDepth = 0
current.X = 0
current.Y = 0
now.x = 0
now.y = 0
While (lDepth < %maxDepth) And (now.X + now.Y < 8) And TRUE
current.Y = 2 * current.X * current.Y - complex.Y
current.X = now.X - now.Y - complex.X
now.X = Pow(current.X, 2)
now.Y = Pow(current.Y, 2)

lDepth += 1
Wend
If lDepth >= %maxDepth Then
lColor = %RGB_BLACK
Else
lColor = get_color(lDepth)
End If
complex.X = complex.X + delta.X

Texture(x, y) = lColor

If TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) Then
' slows down but allows to cancel any time
keepRunning = FALSE
Exit Sub
EndIf

Next X
complex.X = low.X
complex.Y = complex.Y + delta.Y

' "refresh" the texture

TBGL_MakeTexture sTextureBuffer, %TBGL_DATA_RGBA, clientWidth, clientHeight, %TextureID, %TEXTURE_Quality
draw_Mandelbrot

Next Y


End Sub


Function get_color(ByVal d As Long) As Long
' randomly create a palette for any depth

Static c(%maxDepth) As Long

If d = 0 Then Return %RGB_BLACK

If c(d) = 0 Then
Randomize
c(d) = CVL( MKBYT$( Rnd(16,255), Rnd(16,255), Rnd(16, 255) ) )

EndIf
Function = c(d)

End Function

RobbeK
23-03-2014, 14:40
Looking good ReneMiner !

(May I add some O2 to speed it up ?? )

best Rob

ReneMiner
23-03-2014, 14:46
Sure, why not? Maybe I could learn something about O2 then :)

Btw. I changed the type t_vec2D in the script on my PC a little to t_vec2E - using Ext-variable-type instead of double. When "zooming in" it's more precise for a longer time.

RobbeK
24-03-2014, 23:48
OK, I should have some time tomorrow

ReneMiner
29-03-2014, 13:33
I had some time today...

It's gone 3d now, make use of some camera-unit-file because I was lazy,
needs maybe 10 to 15 seconds on my pc to calculate in the pre-set size, (save some time doing y below and above 0 at once)

use arrow-keys, page up and page down
or
use mouse + left button / mouse + right button
to move point of view

hold additional shift-key to control the camera

EDIT: became some more colorful & lighted correctly