[net.sources] Fractal routines

davidk@dartvax.UUCP (David C. Kovar) (08/04/85)

This is a reposting of Jim Hutchison's fractal routines. I just made them
work under pixrect instead of suncore and added a trivial driver to run them
all. This may be of little interest to most, but it made life easier for me.
(Was having problems getting it running under SunCore ...) Hope it helps
someone out there....

Oh yea, some of the initialization stuff was taken from somewhere else,
but I can't remember where. Hope I did not offend anyone. (I *do* know that
it was not a commercial package....)

David C. Kovar    
	    USNET:      {linus|decvax|cornell|astrovax}!dartvax!davidk%amber
	    ARPA:	davidk%amber%dartmouth@csnet-relay
	    CSNET:	davidk%amber@dartmouth

-------------------------------- cut here ----------------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting Makefile'
sed 's/^X//' <<'//go.sysin dd *' >Makefile
GENOBJ = init.o sqrt.o plot.o
FRACTOBJ = general.o koch.o monkey.o gosper.o
LIB = -lm -lpixrect

fractals: main.o $(FRACTOBJ) $(GENOBJ)
	cc -o fractals -O main.o $(FRACTOBJ) $(GENOBJ) $(LIB)

koch.o: koch.c gen.h g.h
	cc -c koch.c

monkey.o: monkey.o gen.h g.h
	cc -c monkey.c

gosper.o: gosper.c gen.h g.h
	cc -c gosper.c

general.o: general.c gen.h g.h
	cc -c general.c

plot.o: plot.c g.h pix.h
	cc -c plot.c

sqrt.o: sqrt.c
	cc -c sqrt.c

init.o: init.c defs.h
	cc -c init.c

clean:
	rm *.o fractals
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 Makefile
	/bin/echo -n '	'; /bin/ls -ld Makefile
fi
/bin/echo 'Extracting README'
sed 's/^X//' <<'//go.sysin dd *' >README


     These files:
	      
	      defs.h		random definitions
	      pix.h		pixrect definitions
              g.h		few constants
              gen.h		generator structure

              general.c		a general curve generator
              gosper.c		gosper curve generator
              koch.c		koch curve generator
              monkey.c		monkey curve generator (My favorite)

              plot.c		plot a line relatively
	      main.c		trivial driver for all the routines
	      init.c		routines to setup screen under pixrect
	      sqrt.c		somehow the sqrt function got lost here ...

    Comprise  a collection of simple  fractal curve  generators.
    They  do not  generate nifty 3D dragons  or towers or archs,
    but  they  are  entertaining  and probably  good for tiling.

	 All I ask is that you not (how incredibly unlikely) try
    to  sell these for profit.  I can ofcourse assume no respon-
    sibility for how these work out for you.  They work fine for
    me  on a SUN (TM) workstation under 4.2 Unix (TM) using SUN-
    core. [Now under pixrect ... -David Kovar]

			 Jim Hutchison

			 hutch@sdcsvax

			 {ihnp4,ucbvax}!sdcsvax!hutch

//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 README
	/bin/echo -n '	'; /bin/ls -ld README
fi
/bin/echo 'Extracting defs.h'
sed 's/^X//' <<'//go.sysin dd *' >defs.h
#define LEFT    01
#define RIGHT   02

#define MINXPOS         50
#define MAXXPOS         (SCREEN_WIDTH-50)
#define MINYPOS         100
#define MAXYPOS         (SCREEN_HEIGHT-100)

#ifndef CTRL
# define CTRL(c)        ('c' & 037)
#endif

#define MAX(a,b)        ((a) > (b) ? (a) : (b))
#define ABS(d)          ((d) < 0 ? -(d) : (d))

extern int      errno, sys_nerr;
extern char     *sys_errlist[];

#define ERRSTR  (errno < sys_nerr ? sys_errlist[errno] : "Unknown Error")

#define MEM_WIDTH       32
#define MEM_HEIGHT      32

//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 defs.h
	/bin/echo -n '	'; /bin/ls -ld defs.h
fi
/bin/echo 'Extracting g.h'
sed 's/^X//' <<'//go.sysin dd *' >g.h
X/*
 * G.h
 * 
 * Constants for convenience when doing radial fractal work under SUNCORE
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 */

#define SQRT2		1.41421
#define PI		3.1415926536
#define PIO2		(PI / 2.0)
#define PIO3		(PI / 3.0)
#define PIO4		(PI / 4.0)
#define PIO6		(PI / 6.0)
#define TWOPIO3		(2.0 * PI / 3.0)
#define TWOPI		(2.0 * PI)
#define D_X	        5.0
#define D_Y	        5.0
#define GEN_SIDES	10

#define MOD(a,b)	while(a > b) a -= b	/* sad but true */
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 g.h
	/bin/echo -n '	'; /bin/ls -ld g.h
fi
/bin/echo 'Extracting gen.h'
sed 's/^X//' <<'//go.sysin dd *' >gen.h
X/*
 * Author: Jim Hutchison (hutch@sdcsvax)
 * Curve generators and initiators ( can be same structure )
 * Various and sundry generators and a very general one.
 */

typedef struct gen {		/* an initiator or generator */
    double	angle;	/* next turtle turn	      */
    int		flip;	/* Flip flop multiplier       */
    double	scale; 	/* scale factor for sides     */
    double	div; 	/* division factor for length */
} GEN;
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 gen.h
	/bin/echo -n '	'; /bin/ls -ld gen.h
fi
/bin/echo 'Extracting general.c'
sed 's/^X//' <<'//go.sysin dd *' >general.c
X/*
 * general()
 *
 * Draw a Generic Fractal curve.
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but credit me)
 */

#include <usercore.h>
#include <math.h>
#include "g.h"
#include "gen.h"

general(len,angle,min_len,scale,flip,shape,size)
double len,angle,min_len,scale;
int flip;
GEN *shape;
int size;
{
register int i;
GEN *gp;

    if (len > min_len) {				/* draw generator */
	gp = shape + ((flip == 1)? 0 : size );
	for(i = 0 ; i < GEN_SIDES ; i++, gp += flip)
	    general(len/gp->div,
		   angle + gp->angle,
		   min_len,
		   scale * gp->scale,
		   gp->flip * flip);

    } else			/* draw side */
	plot_line(len * scale, angle);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 general.c
	/bin/echo -n '	'; /bin/ls -ld general.c
fi
/bin/echo 'Extracting gosper.c'
sed 's/^X//' <<'//go.sysin dd *' >gosper.c
X/*
 * Gosper()
 *
 * Draw a Gosper curve according to Dr. Mandelbrot.
 * start with flip at 1 usually, but -1 is fine also.
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but credit me)
 */

#include <usercore.h>
#include <math.h>
#include "g.h"
#include "gen.h"

#ifdef GEN_SIDES
#undef GEN_SIDES
#endif
#define GEN_SIDES	7
#define GEN_MAX		GEN_SIDES - 1L
static GEN generator[GEN_SIDES] = {
    /* angle		flip */

    { 0.0,		 1 },
    { PIO3,		-1 },
    { PI,		-1 },
    { (2.0 * PIO3),	 1 },
    { 0.0,		 1 },
    { 0.0,		 1 },
    { (TWOPI - PIO3),	-1 }
};

gosper(len,angle,min_len,flip)
double len,angle,min_len;
int flip;
{
register int i;
register GEN *gp;

    if (len > min_len) {	/* draw generator */
	angle += (TWOPI - PIO6);/* tilt */
	gp = &generator[ (flip == 1)? 0 : GEN_MAX ];
	for(i = 0 ; i < GEN_SIDES ; i++, gp += flip)
	    gosper(len/2.0, angle + gp->angle, min_len, gp->flip * flip);
    }
    else			/* draw side */
	plot_line(len, angle);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 gosper.c
	/bin/echo -n '	'; /bin/ls -ld gosper.c
fi
/bin/echo 'Extracting init.c'
sed 's/^X//' <<'//go.sysin dd *' >init.c
#include <stdio.h>
#include <pixrect/pixrect_hs.h>
#include <sys/ioctl.h>
#include <sun/fbio.h>
#include <sys/file.h>

#include "defs.h"

char            *PR_DEVICE = "/dev/fb";         /* for console frame buffer */

struct pixrect  *px_screen;             /* console screen pixrect */
int             SCREEN_WIDTH, SCREEN_HEIGHT;

X/*
 *  Set up the screen for the subsequent screen graphics mmanipulations.
 *  All operations are done with the pixrect facilities of the SUN
 *  workstation 1.1 release.
 */

initpix()
{
        char    *getenv();

        if (init_screen())
                return(-1);

        pr_rop(px_screen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIX_SET, 
                (struct pixrect *)NULL, 0, 0);
        
        return(0);
}


X/*
 *  Initialize the pixrect from the whole screen.
 */

init_screen()
{
        int     fd;

        if ( (fd = open(PR_DEVICE, O_RDWR)) < 0 ) {
                fprintf(stderr, "Cannot open \"%s\": %s\n", PR_DEVICE, ERRSTR);
                return(-1);
        }
        if ( getsize(fd) )
                return(-1);
        close(fd);

        if ((px_screen = pr_open(PR_DEVICE)) == NULL) {
                fputs("Cannot open ", stderr);
                perror(PR_DEVICE);
                return(-1);
        }

        return(0);
}


X/*
 *  Get the number of pixels of the screen size.  If the size
 *  is zero, we assume an error.
 */

getsize(fd)
{
        struct fbtype fbt;

        if (ioctl(fd, FBIOGTYPE, (char *)&fbt) < 0) {
                perror("FBIOGTYPE ioctl");
                return(-1);
        }

        SCREEN_WIDTH = fbt.fb_width;
        SCREEN_HEIGHT = fbt.fb_height;

        if ( SCREEN_WIDTH <= 0  || SCREEN_HEIGHT <= 0 ) {
                fprintf(stderr, "Can't get the window size.\n");
                return(-1);
        }

        return(0);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 init.c
	/bin/echo -n '	'; /bin/ls -ld init.c
fi
/bin/echo 'Extracting koch.c'
sed 's/^X//' <<'//go.sysin dd *' >koch.c
X/*
 * koch()
 *
 * Draw a Koch lake according to Dr. Mandelbrot.
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but credit me)
 */

#include <usercore.h>
#include <math.h>
#include "g.h"
#include "gen.h"

koch(len,angle,min_len)
double len,angle,min_len;
{
int i;

    for (i = 0 ; i < 4 ; i++, angle += PIO2)	/* square seed */
	koch_side(len, angle, min_len);
}

#ifdef GEN_SIDES
#undef GEN_SIDES
#endif
#define GEN_SIDES	8

GEN genkoch[GEN_SIDES] = {
   /* Angle */
    { 0.0	},
    { PIO2	},
    { 0.0	},
    { - PIO2	},
    { - PIO2	},
    { 0.0	},
    { PIO2	},
    { 0.0	}
};

X/*
 *	Draw a side recursively.
 */

koch_side(len,angle,min_len)
double len,angle,min_len;
{
register int i;
GEN *gp;

    if (len > min_len)		/* draw generator */
	for(i = 0, gp = genkoch ; i < GEN_SIDES ; i++, gp++)
	    koch_side(len/2.0, angle + gp->angle, min_len);
    else			/* draw side */
	plot_line(len, angle);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 koch.c
	/bin/echo -n '	'; /bin/ls -ld koch.c
fi
/bin/echo 'Extracting main.c'
sed 's/^X//' <<'//go.sysin dd *' >main.c
#include <stdio.h>
main()
{
    int choice = 0;
    double len, angle, min_len, scale;
    int flip;
    
    while(choice < 1 || choice > 4) {
        printf("Choose a fractal: \n");
	printf("\t1) Monkey \n");
	printf("\t2) Koch lakes \n");
	printf("\t3) General (not handled yet)\n");
	printf("\t4) Gosper\n");

	printf("\nChoice? ");
	scanf("%d", &choice);
    }    
    
    printf("All values should be doubles (xxx.x) save for 'flip', an int.\n");
    printf("Reasonable values for monkey are: 10.0 0.0 1.0 1.0 1 \n");
    
switch (choice) {
    case 1: 			/* Monkey */
	printf ("Length, angle, min. length, scale, flip: ");
	scanf ("%lf %lf %lf %lf %d",
		&len, &angle, &min_len, &scale, &flip);
	initpix();
	monkey (len, angle, min_len, scale, flip);
	break;
    case 2: 			/* Koch lakes */
	printf ("Length, angle, minimum length: ");
	scanf ("%lf %lf %lf", &len, &angle, &min_len);
	initpix();
	koch (len, angle, min_len);
	break;
    case 3: 			/* General. Not handled yet */
	printf ("Not handled.\n");
	break;
    case 4: 
	printf ("Length, angle, minimum length, flip: ");
	scanf ("%lf %lf %lf %", &len, &angle, &min_len, &flip);
	initpix();
	gosper (len, angle, min_len, flip);
	break;
}
    
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 main.c
	/bin/echo -n '	'; /bin/ls -ld main.c
fi
/bin/echo 'Extracting monkey.c'
sed 's/^X//' <<'//go.sysin dd *' >monkey.c
X/*
 * Monkey()
 *
 * Draw a Monkey curve according to Dr. Mandelbrot.
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but credit me)
 */

#include <usercore.h>
#include <math.h>
#include "g.h"
#include "gen.h"

#ifdef GEN_SIDES
#undef GEN_SIDES
#endif
#define GEN_SIDES	11
#define GEN_MAX		GEN_SIDES - 1

GEN genmonkey[GEN_SIDES] = {
   /* Angle			Flip	Scale */

    { PIO3,			-1,	1.0 },	/* R */
    { PIO3,			 1,	1.0 },  /* L */
    { 0.0, 			 1,	1.0 },  /* L */
    { (TWOPI - PIO3),		 1,	1.0 },  /* L */

    { (2.0 * PIO3 + PIO6),	 1,	0.5 },  /* L */
    { (2.0 * PIO3 + PIO6),	-1,	0.5 },  /* R */
    { (PI + PIO6), 		-1,	0.5 },  /* R */
    { (TWOPI - PIO2),		-1,	0.5 },  /* R */
    { (TWOPI - PIO2),		 1,	0.5 },  /* L */

    { 0.0,			-1,	1.0 },  /* R */
    { 0.0,			 1,	1.0 }   /* L */
};

X/*
 *	Draw a monkey curve
 */

monkey(len,angle,min_len,scale,flip)
double len,angle,min_len,scale;
int flip;
{
register int i;
GEN *gp;

    if (len > min_len) {				/* draw generator */
	gp = &genmonkey[ (flip == 1)? 0 : GEN_MAX ];
	for(i = 0 ; i < GEN_SIDES ; i++, gp += flip)
	    monkey(len/2.0,
		   angle + gp->angle,
		   min_len,
		   scale * gp->scale,
		   gp->flip * flip);

    } else			/* draw side */
	plot_line(len * scale, angle);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 monkey.c
	/bin/echo -n '	'; /bin/ls -ld monkey.c
fi
/bin/echo 'Extracting pix.h'
sed 's/^X//' <<'//go.sysin dd *' >pix.h
X/*
 *  Basic operations on the screen as a whole pixrect.
 */

#include <pixrect/pixrect_hs.h>

extern struct pixrect   *px_screen;

#define OP_CLEAR        PIX_CLR
#define OP_SET          PIX_SET
#define OP_PAINT        (PIX_SRC|PIX_DST)
#define OP_WRITE        PIX_SRC
#define OP_MASK         (PIX_SRC&PIX_DST)
#define OP_ERASE        (PIX_NOT(PIX_SRC)&PIX_DST)
#define OP_INVERT       (PIX_NOT(PIX_SRC^PIX_DST))
#define OP_NOT(op)      PIX_NOT(op)

#define WHITE           CLEAR
#define BLACK           SET

extern int              SCREEN_WIDTH, SCREEN_HEIGHT;

#define point(x,y,op)           pr_put(px_screen, x, y, (op == PIX_CLR) ? 0 : 1)
#define line(x1,y1,x2,y2,op)    pr_vector(px_screen, x1, y1, x2, y2, op, 0)
#define block(x,y,w,h,op)       pr_rop(px_screen, x, y, w, h, op, \
                                        (struct pixrect *)0, 0, 0)
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 pix.h
	/bin/echo -n '	'; /bin/ls -ld pix.h
fi
/bin/echo 'Extracting plot.c'
sed 's/^X//' <<'//go.sysin dd *' >plot.c
X/*
 * Plot_line()
 *
 * Draw a line by length and angle relative to current x,y
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but dis/credit me)
 */

#include <math.h>
#include "g.h"
#include "pix.h"

static double crntx = D_X, crnty = D_Y;	/* or global for presetting */

set_coord(x,y)
double x,y;
{
    crntx = x;
    crnty = y;
}

X/*
 *	Plot a line by length and angle from current position
 */

plot_line(length,angle)
double length,angle;
{
double dx,dy;

    MOD(angle,TWOPI);

    dx = length * cos(angle);
    dy = length * sin(angle);

    line((int)(crntx * 10.0), (int)(crnty * 10.0),
	 (int)((crntx + dx) * 10.0), (int)((crnty + dy) * 10.0), OP_WRITE);
    crntx += dx;
    crnty += dy;
}


//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 plot.c
	/bin/echo -n '	'; /bin/ls -ld plot.c
fi
/bin/echo 'Extracting plot.fix'
sed 's/^X//' <<'//go.sysin dd *' >plot.fix
Relay-Version: version B 2.10.2 9/18/84; site dartvax.UUCP
Posting-Version: version B 2.10.2 9/18/84; site sdcsvax.UUCP
Path: dartvax!decvax!tektronix!hplabs!sdcrdcf!sdcsvax!hutch
From: hutch@sdcsvax.UUCP (Jim Hutchison)
Newsgroups: net.graphics
Subject: Fractal Plot (BUG)
Message-ID: <980@sdcsvax.UUCP>
Date: 11 Jul 85 21:19:38 GMT
Article-I.D.: sdcsvax.980
Posted: Thu Jul 11 17:19:38 1985
Date-Received: 15 Jul 85 11:02:17 GMT
Organization: UCSD EMU Project (Educational Microcomputer Unix)
Lines: 65

*** These Bugs do seem to creep in... ***

Plot.c had a small bug in it, i.e. it looked neat, but not right
for most normal cases.  For all those of you with headaches over
it, pardon.

in your main routine:

	openpl();
	space(-500,-500,500,500);
	set_coord(D_X, D_Y);		/* initial position */
	monkey(10.0, 0.0, 1.0, 1.0, 1);	/* for example */
	closepl();

The earlier version ran fine in atleast one particular case, so
if it works for you this fix is still a good idea.


X/*
 * Plot_line()
 *
 * Draw a line by length and angle relative to current x,y
 *
 * Author: Jim Hutchison (hutch@sdcsvax)
 * (this is free, but dis/credit me)
 */

#include <math.h>
#include "g.h"

static double crntx = 0.0, crnty = 0.0;	/* or global for presetting */

set_coord(x,y)
double x,y;
{
    crntx = x;
    crnty = y;
}

X/*
 *	Plot a line by length and angle from current position
 */

plot_line(length,angle)
double length,angle;
{
double dx,dy;

    MOD(angle,TWOPI);

    dx = length * cos(angle);
    dy = length * sin(angle);

    line((int)(crntx * 10.0), (int)(crnty * 10.0),
	 (int)((crntx + dx) * 10.0), (int)((crnty + dy) * 10.0));
    crntx += dx;
    crnty += dy;
}
-- 
X/*
	Jim Hutchison	UUCP:	{dcdwest,ucbvax}!sdcsvax!hutch
			ARPA:	hutch@sdcsvax

    < Ofcourse these statements are only mine, not my employers. >
*/


//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 plot.fix
	/bin/echo -n '	'; /bin/ls -ld plot.fix
fi
/bin/echo 'Extracting sqrt.c'
sed 's/^X//' <<'//go.sysin dd *' >sqrt.c
double sqrt()
{
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 sqrt.c
	/bin/echo -n '	'; /bin/ls -ld sqrt.c
fi
-- 
David C. Kovar    
	    USNET:      {linus|decvax|cornell|astrovax}!dartvax!davidk%amber
	    ARPA:	davidk%amber%dartmouth@csnet-relay
	    CSNET:	davidk%amber@dartmouth

"I felt like a punk who'd gone out for a switchblade and come back
 with a tactical nuke.

 'Shit', I thought. 'Screwed again. What good's a tactical nuke in a
  street fight?'"
			"Burning Chrome" by William Gibson