home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / sci / fractals / 561 < prev    next >
Encoding:
Text File  |  1993-01-08  |  7.1 KB  |  304 lines

  1. Xref: sparky sci.fractals:561 comp.sys.mac.programmer:20963
  2. Newsgroups: sci.fractals,comp.sys.mac.programmer
  3. Path: sparky!uunet!mcsun!sun4nl!dutrun!donau!dutecai!reinoud
  4. From: reinoud@dutecai.et.tudelft.nl (R. Lamberts)
  5. Subject: Julia's Dream algorithm + example code
  6. Message-ID: <1993Jan08.052718.5389@donau.et.tudelft.nl>
  7. Originator: reinoud@dutecai.et.tudelft.nl
  8. Sender: news@donau.et.tudelft.nl (UseNet News System)
  9. Nntp-Posting-Host: dutecai.et.tudelft.nl
  10. Reply-To: reinoud@dutecai.et.tudelft.nl (R. Lamberts)
  11. Organization: Delft University of Technology, Dept. of Electrical Engineering
  12. Date: Fri, 08 Jan 1993 05:27:18 GMT
  13. Lines: 289
  14.  
  15.  
  16. Hi there!
  17.  
  18. This is for all of you who remember Julia's Dream (JD), a Mac
  19. application which calculates Julia sets really fast. Many
  20. people asked me how it works, but I'm not that good at
  21. explaining these things, so a lot of you must have been
  22. dissappointed. I humbly apologise for never having written a
  23. decent piece about the algorithm! However, here's a simplified
  24. implementation of JD written in C, and before that another
  25. attempt at explaining it.
  26.  
  27.  
  28. The idea of Julia's Dream is very simple, even though I think
  29. it's not easy to explain. Maybe it's best to have a look at the
  30. source below if you don't like vague stories ;-). This code is
  31. based on the same idea as the Mac version, though the
  32. implementation is quite different.
  33.  
  34. The idea of JD is that with the escape-time algorithm, each
  35. iteration is essentially independent of its context. It does
  36. not make any difference whether a certain point in an orbit is
  37. an intermediate position or it is a starting position
  38. corresponding to a pixel. This is true for Julia sets, but not
  39. for the Mandelbrot set, where the (c or mu) parameter varies
  40. with the starting point (pixel). Now, because for a Julia set
  41. each intermediate point in an orbit may also be considered as a
  42. starting point, if a pixel is associated with each intermediate
  43. orbit point, the calculation of a pixel value effectively
  44. requires just one iteration.
  45.  
  46. There are various algorithms possible to implement this idea.
  47. One way is to calculate an orbit for a certain starting point,
  48. and assign pixel locations and values to each point in the
  49. orbit afterwards. This is used in the code below. The original
  50. Mac version of JD did calculations with each orbit point
  51. rounded to a pixel location each iteration, allowing for
  52. significant speed-up if the CPU is slow relative to memory
  53. access.
  54.  
  55. If you want to see the Mac code, let me know. It's a lot of
  56. hairy 68020 assembly code though...
  57.  
  58. To improve accuracy around the origin, some pixels are
  59. calculated using the good old escape-time algorithm there.
  60. There are probably more elegant ways to do this, but I didn't
  61. exercise the options.
  62.  
  63. The code below compiles on a SGI Indigo with entry (8-bit)
  64. graphics (sorry, I didn't even initialise the colormap). It
  65. uses the GL, not X. This is *not* finished code, especially the
  66. user interface is a quick hack. I've included the GL stuff with
  67. the hope that a concrete example may be easier to understand
  68. for some. Sorry about the lack of comments, this was really an
  69. experiment to see how well the JD algorithm would work out in C
  70. with straightforward FP calculations.
  71.  
  72.  
  73. Well, I hope this is of any help (or interest, if you didn't
  74. know JD). Many thanks to all who contacted me about this! If
  75. you have ideas for (algorithmic) improvement, spiffy programs,
  76. or further questions, I'd very much like to know.
  77.  
  78. Have fun,
  79.  
  80. - Reinoud
  81.  
  82.  
  83. /*
  84.  *  Julia's Dream II  (XP hack version)
  85.  *  
  86.  *  The nightmare continues...
  87.  * 
  88.  *  Copyright (c) 1992 Reinoud Lamberts, all rights reserved
  89.  * 
  90.  *  You are free to use this stuff as you like, as long as
  91.  *  you give credit where credit is due.
  92.  * 
  93.  * 
  94.  *  Reinoud Lamberts
  95.  *  Oldambt 69
  96.  *  3524 BD Utrecht
  97.  *  The Netherlands
  98.  * 
  99.  *  Phone (int'l code 31) 30 896775
  100.  *  
  101.  *  reinoud@duteca.et.tudelft.nl
  102.  *  reinoud@knoware.ruu.nl (UUCP)
  103.  *  reinoud%knoware.ruu.nl@accucx.cc.ruu.nl
  104.  * 
  105.  */
  106.  
  107.  
  108. #include <stdlib.h>
  109. #include <gl/gl.h>
  110. #include <gl/device.h>
  111.  
  112.  
  113. #define XRES 256            /* better be power of 2 */
  114. #define YRES 256
  115. #define XLOG 8                /* shift amount i.s.o multiply */
  116.  
  117.  
  118. typedef unsigned char byte;        /* should be 8 bits (and int 32) */
  119. typedef double fl;            /* optimise for performance */
  120.  
  121.  
  122. byte *ospmap;                /* things happen in here */
  123.  
  124.  
  125. main()
  126. {
  127.     int xi, yi, ospindex, it, i, ospwsiz, bhsiz, jinx;
  128.     fl deltax, deltay, idx, idy;
  129.     fl xc, yc, sqre, sqim, sqyc, re, im, cre, cim;
  130.     int orb[10000];
  131.     int bound, empty, hitval;
  132.     int pro, con;
  133.  
  134. /*
  135.  *  yeah, let's arrange for some accomodation or something
  136.  */
  137.  
  138.     ospmap=malloc(YRES*XRES);
  139.     if (ospmap==NULL)
  140.       exit(1);
  141.  
  142. /*
  143.  *  let's do the window thing now
  144.  */
  145.  
  146.     prefsize(XRES, YRES);
  147.     winopen("Julia's Dream II  XP hack version  (c) 1992 Reinoud Lamberts");
  148.     pixmode(PM_SIZE, 8);        /* 8 bits offscreen*/
  149.  
  150. /*
  151.  *  now let's start talking business
  152.  */
  153.  
  154.  
  155. /*  constants */
  156.  
  157.     deltax=4.0/(XRES-1);            /* section of c plane is fixed */
  158.     deltay=4.0/(YRES-1);
  159.     idx=1/deltax;
  160.     idy=1/deltay;
  161.     
  162.     ospwsiz=((YRES*XRES)>>2);
  163.     bhsiz=XRES>>4;
  164.     
  165.     do
  166.     {
  167.     
  168.       /* init */
  169.   
  170.       cre=-2+getvaluator(MOUSEX)*deltax;
  171.       cim=-2+getvaluator(MOUSEY)*deltax;
  172.     
  173.       for (i=((YRES>>1)*XRES)>>2; i<ospwsiz; i++)
  174.     ((int *) ospmap)[i]=0;
  175.     
  176.       /* enter the black hole */
  177.   
  178.       yc=deltay*0.5;
  179.   
  180.       for (yi=(YRES>>1); yi<(YRES>>1)+bhsiz; yi++)
  181.       {
  182.         xc=-(bhsiz+0.5)*deltax;
  183.     sqyc=yc*yc;
  184.     ospindex=(yi<<XLOG)+(XRES>>1)-1-bhsiz;
  185.     
  186.     for(xi=(XRES>>1)-1-bhsiz; xi<((XRES>>1)+bhsiz); xi++)
  187.     {
  188.       sqim=sqyc;
  189.       sqre=xc*xc;
  190.       re=xc;
  191.       im=yc;
  192.       it=0;
  193.       
  194.       while( (bound=((sqre+sqim)<4.0))&&(it<64) )
  195.       {
  196.        im=2.0*re*im+cim;
  197.        re=sqre-sqim+cre;
  198.        sqre=re*re;
  199.        sqim=im*im;
  200.        
  201.        it++;
  202.       }
  203.       
  204.       if (!bound)
  205.         ospmap[ospindex]=255-it;
  206.       else
  207.         ospmap[ospindex]=255;
  208.       
  209.       xc+=deltax;
  210.       ospindex++;
  211.     }
  212.     
  213.     yc+=deltay;
  214.       }
  215.  
  216.       /* explore outer space */
  217.  
  218.       ospindex=(YRES>>1)*XRES;
  219.       yc=deltay*0.5;
  220.       
  221.       /* okay, here it goes */
  222.   
  223.       for (yi=(YRES>>1); yi<YRES; yi++)
  224.       {
  225.     xc=-2.0;
  226.     sqyc=yc*yc;
  227.     
  228.     for (xi=0; xi<XRES; xi++)
  229.     {
  230.       sqim=sqyc;
  231.       sqre=xc*xc;
  232.       re=xc;
  233.       im=yc;
  234.       it=0;
  235.       jinx=ospindex;
  236.       
  237.       while ( (bound=((sqre+sqim)<4.0)) &&
  238.               (empty=((hitval=ospmap[jinx])==0)) && (it<10000)
  239.         )
  240.       {
  241.         orb[it]=jinx;
  242.         ospmap[jinx]=255;
  243.       
  244.         im=2.0*re*im+cim;
  245.         re=sqre-sqim+cre;
  246.         if (im<0)
  247.         {
  248.           im=-im;
  249.           re=-re;
  250.         }
  251.         sqre=re*re;
  252.         sqim=im*im;
  253.        
  254.         jinx=( ((int) ((im+2.0)*idy+0.5)) <<XLOG)+(re+2.0)*idx+0.5;
  255.         it++;        
  256.       }
  257.       if (it!=0)
  258.       {
  259.         if ((!empty)&&(hitval!=255))
  260.           do
  261.           {
  262.         if (--hitval==0)
  263.           hitval=254;
  264.         ospmap[orb[--it]]=hitval;
  265.           }
  266.           while (it>0);
  267.         else
  268.         if (!bound)
  269.         {
  270.           hitval=255;
  271.           do
  272.           {
  273.         if (--hitval==0)
  274.           hitval=254;
  275.         ospmap[orb[--it]]=hitval;
  276.           }
  277.           while (it>0);
  278.         }
  279.       }
  280.       
  281.       xc+=deltax;
  282.       ospindex++;
  283.     }
  284.     
  285.     yc+=deltay;
  286.       }
  287.       
  288.       pro=0;
  289.       con=YRES*XRES-1;
  290.       do
  291.       {
  292.     ospmap[pro++]=ospmap[con--];
  293.       }
  294.       while(pro<=con);
  295.       
  296.       lrectwrite(0, 0, XRES-1, YRES-1, (unsigned long *) ospmap);
  297.  
  298.     }
  299.     while (1);
  300.  
  301.     return 0;                /* easy on the compiler */
  302. }
  303.  
  304.