Author Topic: Mandelbrot generator  (Read 4447 times)

0 Members and 1 Guest are viewing this topic.

Offline Richard Frost

  • Seasoned Forum Regular
  • Posts: 316
  • Needle nardle noo. - Peter Sellers
    • View Profile
Mandelbrot generator
« on: February 29, 2020, 08:14:23 pm »
1) Why is this "fuzzy" despite using double precision floats?
2) Why can't I save actual colors?  (SaveImage modified from a sub I got here)

Code: QB64: [Select]
  1. _TITLE "Mandelbrots"
  2.  
  3. ' Keys detected while image generating - no need to wait to end
  4.  
  5. ' arrow keys - move image
  6. ' +/- zoom in/out
  7. ' c to change colors
  8. ' o for master set
  9. ' z color band
  10. ' s save image
  11. ' spacebar start new
  12.  
  13. DEFINT A-Z
  14. COMMON SHARED xm, ym
  15. DIM SHARED cp&(256), c(2), d(2)
  16. GOSUB init
  17. it1& = 100: it2& = 100
  18.     begin:
  19.     it0& = it1&
  20.     GOSUB GenNums
  21.     it0& = it2&
  22.     b2:
  23.     IF restart = 0 THEN GOSUB ChangeColors
  24.     restart = 0
  25.     CLS
  26.     lr = 0: ud = 0
  27.     FOR y = 0 TO ym
  28.         FOR x = 0 TO xm
  29.             GOSUB set
  30.         NEXT x
  31.         GOSUB Scan
  32.         IF restart THEN GOTO b2
  33.         IF i$ = " " THEN GOTO begin
  34.         IF i$ = "c" THEN GOTO b2
  35.         IF i$ = "z" THEN sp = sp XOR 1: GOTO b2
  36.     NEXT y
  37.     GOSUB ShowPoint
  38.     DO: _LIMIT 10
  39.         GOSUB Scan
  40.         IF restart THEN GOTO b2
  41.         IF i$ = "c" THEN GOTO b2
  42.         IF i$ = "s" THEN GOSUB SaveIt
  43.         IF i$ = "z" THEN sp = sp XOR 1: GOTO b2
  44.     LOOP UNTIL (i$ = CHR$(13)) OR (i$ = CHR$(32))
  45. ' ------------------------------------------------------------------------------------------------------------
  46. Scan:
  47. i$ = INKEY$
  48. IF LEN(i$) = 1 THEN
  49.     IF i$ = CHR$(27) THEN SYSTEM
  50.     IF INSTR("+-", i$) THEN
  51.         xm## = (x1## + x2##) / 2
  52.         ym## = (y1## + y2##) / 2
  53.         xd## = ABS(x2## - x1##)
  54.         yd## = ABS(y2## - y1##)
  55.         IF i$ = "-" THEN
  56.             x1## = xm## - xd##: x2## = xm## + xd##
  57.             y1## = ym## - yd##: y2## = ym## + yd##
  58.         ELSE
  59.             WINDOW SCREEN(x1##, y1##)-(x2##, y2##)
  60.             x1## = xm## - xd## / 8: x2## = xm## + xd## / 8
  61.             y1## = ym## - yd## / 8: y2## = ym## + yd## / 8
  62.             LINE (x1##, y1##)-(x2##, y2##), _RGB(255, 255, 255), B
  63.             WINDOW
  64.             w! = TIMER + 2
  65.             DO: _LIMIT 10
  66.                 i$ = INKEY$
  67.             LOOP UNTIL (TIMER > w!) OR (LEN(i$) > 0)
  68.             IF i$ = CHR$(27) THEN END
  69.         END IF
  70.         xd## = (x2## - x1##) / xm
  71.         yd## = (y2## - y1##) / ym
  72.         restart = 1
  73.     END IF
  74.     IF i$ = "o" THEN
  75.         x1## = mx1!
  76.         x2## = mx2!
  77.         y1## = my1!
  78.         y2## = my2!
  79.         xd## = (x2## - x1##) / xm
  80.         yd## = (y2## - y1##) / ym
  81.         restart = 1
  82.     END IF
  83. IF LEN(i$) = 2 THEN
  84.     k = ASC(RIGHT$(i$, 1))
  85.     lr = (k = 77) - (k = 75) '                   left/right arrows
  86.     ud = (k = 80) - (k = 72) '                   up and down arrow
  87.     IF lr OR ud THEN
  88.         x1## = x1## + xd## / 10 * lr * xm
  89.         y1## = y1## + yd## / 10 * ud * ym
  90.         restart = 1
  91.     END IF
  92. ' ------------------------------------------------------------------------------------------------------------
  93. GenNums:
  94. x1## = mx1! + RND * (mx2! - mx1!)
  95. y1## = my1! + RND * (my2! - my1!)
  96. q = RND * 999 + 100
  97. x2## = x1## + (1 / q)
  98. y2## = y1## + (1 / q)
  99. xd## = (x2## - x1##) / xm
  100. yd## = (y2## - y1##) / ym
  101. y = 400: oc = -1: nc = 0
  102. FOR z = -320 TO 320 STEP 20
  103.     x = 640 + z
  104.     GOSUB set
  105.     GOSUB Scan
  106.     IF c <> oc THEN oc = c: nc = nc + 1
  107. IF nc < 10 THEN GOTO GenNums '                   must detect 10 color changes to exit
  108. ' ------------------------------------------------------------------------------------------------------------
  109. init:
  110. mx1! = -2
  111. mx2! = .6
  112. my1! = -1.25
  113. my2! = 1.25
  114. xm = 1280: ym = 800
  115. SCREEN _NEWIMAGE(xm, ym, 256)
  116. GOSUB ChangeColors
  117. ' ------------------------------------------------------------------------------------------------------------
  118. set:
  119. MandelX## = x1## + x * xd##
  120. MandelY## = y1## + y * yd##
  121. Real## = 0
  122. Imag## = 0
  123. Size## = -1
  124. iter& = it0&
  125.     iter& = iter& - 1
  126.     hold## = Imag##
  127.     Imag## = Real## * Imag## * 2 + MandelY##
  128.     Real## = Real## * Real## - hold## * hold## + MandelX##
  129.     Size## = (Real## * Real## + Imag## * Imag##) - 99
  130. LOOP UNTIL (iter& = 0) OR (Size## >= 0)
  131. c = (iter& MOD 255) + 1
  132. IF iter& = 0 THEN c = 0
  133. PSET (x, y), cp&(c)
  134. ' ------------------------------------------------------------------------------------------------------------
  135. ChangeColors:
  136. IF sp THEN nn = 2 ELSE nn = 20
  137. FOR i = 0 TO 2
  138.     c(i) = RND * 250 + 2
  139.     d(i) = RND * nn + 1
  140. FOR i = 1 TO 255
  141.     FOR j = 0 TO 2
  142.         c(j) = c(j) + d(j)
  143.         IF (c(j) < 0) OR (c(j) > 255) THEN
  144.             d(j) = -d(j)
  145.             c(j) = c(j) + d(j)
  146.         END IF
  147.     NEXT j
  148.     cp&(i) = _RGB32(c(0), c(1), c(2))
  149. ' ------------------------------------------------------------------------------------------------------------
  150. SaveIt:
  151. image = image + 1
  152. f$ = "fra" + RIGHT$("00000" + LTRIM$(STR$(image)), 5) + ".bmp"
  153. IF _FILEEXISTS(f$) THEN GOTO SaveIt
  154. SaveImage f$
  155. SOUND 3000, 1
  156. ' ------------------------------------------------------------------------------------------------------------
  157. ShowPoint:
  158. qq = 8
  159. xm = xm / qq: ym = ym / qq
  160. sx1## = x1##: sx2## = x2##: sy1## = y1##: sy2## = y2##: sxd## = xd##: syd## = yd##
  161. xm## = (x1## + x2##) / 2
  162. ym## = (y1## + y2##) / 2
  163. x1## = -2
  164. x2## = .6
  165. y1## = -1.25
  166. y2## = 1.25
  167. xd## = (x2## - x1##) / xm
  168. yd## = (y2## - y1##) / ym
  169. it0& = it1&
  170. FOR y = 0 TO ym
  171.     FOR x = 0 TO xm
  172.         GOSUB set
  173.     NEXT x
  174. it0& = it2&
  175. LINE (0, 0)-(xm, ym), _RGB(255, 255, 255), B
  176. WINDOW SCREEN(x1##, y1##)-(x2##, y2##)
  177. tx = PMAP(xm##, 0) \ qq
  178. ty = PMAP(ym##, 1) \ qq
  179. LINE (tx - 4, ty - 4)-(tx + 4, ty + 4), _RGB(255, 255, 255), B
  180. xm = 1280: ym = 800 '
  181. x1## = sx1##: x2## = sx2##: y1## = sy1##: y2## = sy2##: xd## = sxd##: yd## = syd##
  182. ' -----------------------------------------------------------------------------------------------------------------
  183. SUB SaveImage (f$)
  184.     b$ = "BM????_RGF????" + MKL$(40) + MKL$(xm) + MKL$(ym) + MKI$(1) + MKI$(8) + MKL$(0) + "????" + STRING$(16, 0)
  185.     FOR i = 0 TO 255
  186.         c& = cp&(i) '                                                save a little typing for next line
  187.         b$ = b$ + CHR$(_BLUE32(c&)) + CHR$(_GREEN32(c&)) + CHR$(_RED32(c&)) + CHR$(0) 'spacer byte
  188.     NEXT
  189.     MID$(b$, 11, 4) = MKL$(LEN(b$)) '                                image pixel data offset (BMP header)
  190.     FOR py = ym - 1 TO 0 STEP -1
  191.         z$ = ""
  192.         FOR px = 0 TO xm - 1
  193.             c& = POINT(px, py)
  194.             IF if_I_had_a_brain THEN '                               attempt to save ACTUAL colors (doesn't work!)
  195.                 FOR i = 0 TO 255
  196.                     IF c& = cp&(i) THEN hit = i: EXIT FOR
  197.                 NEXT i
  198.                 z$ = z$ + CHR$(hit)
  199.             ELSE
  200.                 z$ = z$ + CHR$(ABS(c&) MOD 256)
  201.             END IF
  202.         NEXT px
  203.         d$ = d$ + z$
  204.     NEXT py
  205.     MID$(b$, 35, 4) = MKL$(LEN(d$)) '                                image size (BMP header)
  206.     b$ = b$ + d$ '                                                   total file data bytes to create file
  207.     MID$(b$, 3, 4) = MKL$(LEN(b$)) '                                 size of data file (BMP header)
  208.     f& = FREEFILE
  209.     OPEN f$ FOR OUTPUT AS #f&: CLOSE #f& '                           erases an existing file
  210.     OPEN f$ FOR BINARY AS #f&
  211.     PUT #f&, , b$
  212.     CLOSE #f&
  213.  
« Last Edit: March 02, 2020, 12:30:15 am by Richard Frost »
It works better if you plug it in.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Mandelbrot generator
« Reply #1 on: February 29, 2020, 09:02:46 pm »
Quote
1) Why is this "fuzzy" despite using double precision floats?

Are the WINDOW width, height commands you are using for zooming staying proportional to the actual screen width and height? The thumbnail map is definitely getting stretched along x axis compared to y.

BTW it's a pretty nice program.
« Last Edit: February 29, 2020, 09:07:54 pm by bplus »

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: Mandelbrot generator
« Reply #2 on: March 02, 2020, 12:43:06 am »
here is mine, it is mouse driven: left, right mouse zoom in out, +/- increase decrease iterations, scrollwheel change zoom window

Code: [Select]
defint a-z

const sw = 640
const sh = 480

dim shared mx,my,mbl,mbr,mw

dim u as double, v as double
dim uu as double, vv as double
dim xx as double, yy as double
dim x0 as double, y0 as double
dim z as double, zz as double
z = 0.01
zz = 0.1

dim p1 as long
p1 = _newimage(sw, sh, 32)
screen _newimage(sw, sh, 32)

redraw = -1
iter = 100

dim c(100) as long, cc as long

for i=0 to iter-1
        if i < iter/6 then
                r = 155
                g = (i mod (iter/6))*(255/(iter/6))
                b = 0
        elseif i < 2*iter/6 then
                r = 155 - (i mod (iter/6))*(255/(iter/6))
                g = 155
                b = 0
        elseif i < 3*iter/6 then
                r = 0
                g = 155
                b = (i mod (iter/6))*(255/(iter/6))
        elseif i < 4*iter/6 then
                r = 0
                g = 155 - (i mod (iter/6))*(255/(iter/6))
                b = 155
        elseif i < 5*iter/6 then
                r = (i mod (iter/6))*(255/(iter/6))
                g = 0
                b = 155
        else
                r = 155
                g = 0
                b = 155 - (i mod (iter/6))*(255/(iter/6))
        end if
        c(i) = _rgb(r, g, b)
next

do
        mw = 0
        getmouse

        if redraw then
                for y = 0 to sh-1
                for x = 0 to sw-1
                        u = 0
                        v = 0

                        xx = (x - sw/2)*z + x0
                        yy = (y - sh/2)*z + y0
                        for i = 0 to iter
                                '''mandelbrot
                                u = u
                                v = v
                                uu = u*u - v*v + xx
                                vv = 2*u*v + yy
                                '''

                                '''burning ship
                                'u = abs(u)
                                'v = abs(v)
                                'uu = u*u - v*v + xx
                                'vv = 2*u*v + yy
                                '''

                                '''tricorn
                                'u = u
                                'v = -v
                                'uu = u*u - v*v + xx
                                'vv = 2*u*v + yy
                                '''

                                '''tetration
                                'u = u
                                'v = v
                                'cexp uu, vv, u, v, u, v
                                'cexp uu, vv, uu, vv, xx, yy
                                '''

                                u = uu
                                v = vv

                                if (u*u + v*v) > 4 then exit for
                        next
                        if i > iter then
                                pset(x, y), _rgb(0,0,0)
                        else
                                pset(x, y), c(i mod 100)
                        end if
                next
                next

                'locate 1,1
                'print "iter =";iter
                _title str$(iter)

                _dest p1
                _putimage , 0
                _dest 0

                _putimage , p1
                _autodisplay

                redraw = 0
        end if

        if mw < 0 then
                zz = zz + 0.01
        elseif mw > 0 then
                if zz > 0.01 then zz = zz - 0.01
        end if

        'draw box
        if omx <> mx or omy <> my or mw <> 0 then
                _putimage , p1
                line (mx - (sw*zz/2), my - (sh*zz/2))-step(sw*zz,sh*zz),_rgb(255,255,255),b
                _autodisplay

                omx = mx
                omy = my
        end if

        if mbl then
                do
                        getMouse
                loop while mbl

                x0 = x0 + (mx - sw/2)*z
                y0 = y0 - (sh/2 - my)*z
                z = z*zz
                redraw = -1
        elseif mbr then
                do
                        getMouse
                loop while mbr

                x0 = x0 + (mx - sw/2)*z
                y0 = y0 - (sh/2 - my)*z
                z = z/zz
                redraw = -1
        end if

        k = _keyhit
        if k = 43 then
                iter = iter + 50
                redraw = -1
        elseif k = 45 then
                if iter > 50 then iter = iter - 50
                redraw = -1
        end if

loop until k = 27
system

sub getmouse ()
        do
                mx = _mousex
                my = _mousey
                mbl = _mousebutton(1)
                mbr = _mousebutton(2)
                mw = mw + _mousewheel
        loop while _mouseinput
end sub

'u + iv = (x + iy) ^ (a + ib)
sub cexp (u as double, v as double, x as double, y as double, a as double, b as double)
        dim mag as double, arg as double
        dim lnz as double, argz as double

        lnz = 0.5*log((x*x + y*y)+0.00001)
        argz = _atan2(y, x)

        mag = exp(a*lnz - b*argz)
        arg = a*argz + b*lnz

        u = mag * cos(arg)
        v = mag * sin(arg)
end sub

Offline Richard Frost

  • Seasoned Forum Regular
  • Posts: 316
  • Needle nardle noo. - Peter Sellers
    • View Profile
Re: Mandelbrot generator
« Reply #3 on: March 02, 2020, 01:19:22 am »
Adding "/ 1.6" to line 103 makes it proportional, and it's still fuzzy.  I didn't change the code here. 

Thanks for the idea.  I sure don't have a clue.
It works better if you plug it in.

Offline Richard Frost

  • Seasoned Forum Regular
  • Posts: 316
  • Needle nardle noo. - Peter Sellers
    • View Profile
Re: Mandelbrot generator
« Reply #4 on: March 02, 2020, 02:47:07 am »
A super fast and option laden Mandelbrot generator that Vince suggested to
me (Kalle's) is also fuzzy, even after drastically upping the iterations.

Yet I see lots of images online that are NOT fuzzy. 

So it appears there's nothing wrong my code.  It's the whole approach!

There must be a better way, and Vince seems to have it.  His is much less fuzzy.
I think it's his color selection.  Fewer, yet smarter?   Haven't figured it out yet.

Likely the Kalle program's defaults do not give good results....


« Last Edit: March 02, 2020, 02:58:08 am by Richard Frost »
It works better if you plug it in.

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: Mandelbrot generator
« Reply #5 on: March 02, 2020, 09:58:18 am »
Here's that program i brought up in chat: https://mathr.co.uk/kf/kf.html, it is the best program for exploring the mandelbrot set. It is amazing because you can zoom in practically forever. With the superficial method, you will eventually run out of floating point precision requiring the use of a arbitrary precision routines or library (GMP, etc) but it would be too slow to do for every point. So the program uses a technique to calculate just one arbitrary precision point and series approximates the rest of the screen, more on this: https://mathr.co.uk/mandelbrot/perturbation.pdf.

I guess the reason it looks 'fuzzy' is because it will do a sort of rough 'digital zoom' to keep up with your zooming before it fills it in with detail, mine will render it entirely for every zoom.

Edit: I've noticed disabling _FULLSCREEN makes it look right, not "fuzzy"
« Last Edit: March 02, 2020, 08:04:37 pm by _vince »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Mandelbrot generator
« Reply #6 on: March 02, 2020, 11:17:16 pm »
Oh man it was on _FULLSCREEN? I looked for that, yeah much better without!