[comp.windows.news] Iterated Function Sequence Fractal Generator.

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