View Full Version : Slices of Mandelbrot - the idea
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
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
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 :)
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
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
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.
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