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