sjs@jcricket.ctt.bellcore.com (Stan Switzer) (10/06/88)
Pointalist Fractals. I'd like to point out that this program would run alot faster if the "x y matrix => x' y'" version of "transform" actually worked. As ALLways, Enjoy! Stan Switzer "Thou shalt not have no idea." sjs@ctt.bellcore.com P.S.: Please note that my news poster insists on building a bogus "from" field. Mail only to the address in my signature line. P.P.S.: Maybe someday I'll post something useful. ----------------------------------------------------- #!/bin/sh # # ifs: "Iterated Function Sequence" fractals # # Copyright (C) 1988 by Stan Switzer. All rights reserved. # This program is provided for unrestricted use, provided that this # copyright message is preserved. There is no warranty, and no author # or distributer accepts responsibility for any damage caused by this # program. # # Stan Switzer sjs@ctt.bellcore.com # # Invocation: # ifs [fern|square|tree|tri] # # The default fractal patern is the name of the command (supposing # it is linked to "tree", for instance), and failing that "fern". # The fern looks best when the window is somewhat taller than wide. # # If you prefer, you can have it draw in the icon when closed by setting # /DrawInIcon? to true. This has the disadvantage of using CPU cycles # when the window is closed. Caveat Hacktor. # # The idea for this came from an article in "Byte." For the record, I # do not usually read that magazine. Details below. if test -z "$1"; then set `basename $0`; fi case "$1" in *tri*|[Ss]ier*) X=SierpinskiTriangle;; *squ*) X=Square;; *tree*) X=Tree;; *fern*|*) X=Fern;; esac # the arrays below work as follows: # /name [ [view-transform] # [ transform-1 prob-1 ] # [ transform-2 prob-2 ] # . . . # [ transform-n prob-n ] # ] def # # An iterated function sequence simply iterates the transformations # beginning with some random point according to the specified probabilities. # The first 20 iterations are thrown away in order to allow it to # converge. Basically, the transformations describe the self-similarities # and the probabilities are essentially the ratios of the areas of the # parts to the whole. # # Note that there were typos in the article in the transforms for the # fern. I have also made some aesthetic imporvements to the "tree" to # give the trunk some width. # # Finally, I'd like to comment that this program would really scream if # NeWS implemented the "x y matrix => x' y'" for of transform. I have # to do this the hard way instead. { cat <<-! /DrawInIcon? false def /SierpinskiTriangle [ [ .45 0 0 .9 .05 .05 ] [ 0.50 0.00 0.00 0.50 0.00 0.00 0.33 ] [ 0.50 0.00 0.00 0.50 1.00 0.00 0.33 ] [ 0.50 0.00 0.00 0.50 0.50 0.50 0.33 ] ] def /Fern [ [ -.15 0 0 .095 .5 0 ] [ 0.85 0.04 -0.04 0.85 0.00 1.60 0.85 ] [ 0.20 -0.26 0.23 0.22 0.00 1.60 0.07 ] [ -0.15 -0.28 -0.26 0.24 0.00 0.44 0.07 ] [ 0.00 0.00 0.00 0.16 0.00 0.00 0.01 ] ] def /Tree [ [ 1.75 0 0 2 .5 0 ] [ 0.42 -0.42 0.42 0.42 0.00 0.20 0.40 ] [ 0.42 0.42 -0.42 0.42 0.00 0.20 0.40 ] %[ 0.10 0.00 0.00 0.10 0.00 0.20 0.15 ] %[ 0.02 0.02 0.02 0.50 0.00 0.00 0.05 ] [ 0.02 0.01 0.01 0.50 0.00 0.00 0.10 ] [ 0.03 0.01 0.01 -0.40 0.00 0.20 0.10 ] ] def /Square [ [ .5 0 0 .5 .25 .25 ] [ 0.50 0.00 0.00 0.50 0.00 0.00 0.25 ] [ 0.50 0.00 0.00 0.50 0.50 0.00 0.25 ] [ 0.50 0.00 0.00 0.50 0.00 0.50 0.25 ] [ 0.50 0.00 0.00 0.50 0.50 0.50 0.25 ] ] def /SetCode { % codearray dup dup length 1 sub 1 exch getinterval [ exch { [ exch dup 6 get exch 0 6 getinterval ] } forall ] /codes exch def codes dup length 1 sub get 0 1000 put 0 get /viewxform exch def } def /choosecode { random codes { % 0-1 code dup 0 get 3 -1 roll exch sub dup 0 le { pop exit } if exch pop } forall 1 get } def /xfm /transform load def /xfm { % x y mat 2 index 1 index 0 get mul % x y mat xa 2 index 2 index 2 get mul add % x y mat xa+yc 1 index 4 get add % x y mat x' 3 index 2 index 1 get mul % x y mat x' xb 3 index 3 index 3 get mul add % x y mat x' xb+yd 2 index 5 get add % x y mat x' y' 5 2 roll pop pop pop } def /X { choosecode xfm } def /P { moveto 0 0 rlineto stroke } def /IFSWindow DefaultWindow dictbegin /reshaped? false def /rescale? false def /drawproc null def dictend classbegin /reshape { /reshape super send /reshaped? true store } def /flipiconic { /flipiconic super send DrawInIcon? { /rescale? true store } { drawproc Iconic? { stop-it } { start-it } ifelse } ifelse } def DrawInIcon? { /CreateIconCanvas { /CreateIconCanvas super send IconCanvas begin /Transparent false def /Retained true def end } def } if /CreateFrameCanvas { /CreateFrameCanvas super send FrameCanvas begin /Transparent false def /Retained true def end } def /DrawingCanvas { Iconic? IconCanvas ClientCanvas ifelse } def /stop-it { drawproc null ne { drawproc killprocess } if /drawproc null def } def /start-it { stop-it /rescale? true def /drawproc { random random 20 /X load repeat % iterate initial random pt { reshaped? { /rescale? true def } if rescale? { DrawingCanvas win send setcanvas clippath pathbbox scale pop pop viewxform concat /rescale? false store } if reshaped? { ClientFillColor fillcanvas 0 setgray /reshaped? false store } if 5 { X 2 copy P } repeat pause } loop } fork store } def classend def /main { /reshaped? false def /win framebuffer /new IFSWindow send def % Create a window { /IconLabel DrawInIcon? { pop pop } { exch def } ifelse /FrameLabel exch def } win send /reshapefromuser win send % Shape it. /map win send % Map the window. (Damage causes PaintClient to be called) /start-it win send } def /Go { SetCode main } def ! echo "(IFS Fractal: $X) ($X) $X Go" } | psh