[comp.sources.misc] v03i055: A sunview program to draw "roses"

igp@camcon.UUCP (Ian Phillipps) (06/15/88)

comp.sources.misc: Volume 3, Issue 55
Submitted-By: "Ian Phillipps" <igp@camcon.UUCP>
Archive-Name: rose

This is an amusing toy for Sun console users. If you want to convert it to
some other windowing system, please do. The guts of the mathematics is about
five lines in redraw() - the rest is padding.


Shell archive - cut here - send the rest to sh, type "make".
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  rose.c
#	  Makefile
#
sed 's/^X//' << 'SHAR_EOF' > rose.c &&
X/* A pretty pixture-drawer @(#)rose.c	1.9
X   This program is supplied as-is, and is certainly not suitable for any
X   purpose.
X   My thanks to Colin Attenborough, whose version on a 6502-based home
X   computer prompted my question "How fast would that run on a Sun?";
X   to the Guardian newspaper for drawing Colin's attention to the algorithm,
X   and to Peter M Maurer of A T & T, whose article "A Rose is a Rose..."
X   in the American Mathematical Monthly (Oct 87, p 631) started it all.
X
X   Ian Phillipps (igp@camcon.uucp), 15 June 1988
X
X   Tested on Sun 3 (SunOS 3.5) and Sun 4 (SunOS 3.2).
X */
X
X#include <stdio.h>
X#include <math.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <suntool/panel.h>
X
X/* A greater variety of drawing types is obtained if QUANTUM is composite
X   360 does just fine - it has nothing to do directly with degrees.  */
X#define QUANTUM 360	/* Number of increments in a revolution */
X
X/* Size and Slider_length should be related for a sensible panel layout */
X#define SIZE 700	/* Initial size of canvas (square) */
X#define SLIDER_LENGTH ((QUANTUM-2)/1)
X#define FILL_SCALE	9/10	/* Note absence of brackets (kludge) */
X
Xstatic Frame frame;
Xstatic Panel_item panel_n, panel_d;
Xstatic Canvas canvas;
Xstatic Pixwin *pw;
X
Xstatic double sinx[QUANTUM], cosx[QUANTUM];	/* trig tables */
X
Xenum rect_type { PIXWIN, PIXRECT };
X
Xredraw( type, pw, width, height )
X    enum rect_type type;
X    Pixwin *pw;
X    int width, height;
X{
X    int xoffset = width / 2;
X    int n = (int)panel_get_value( panel_n );
X    int d = (int)panel_get_value( panel_d );
X    int a = 0;
X    int yoffset = height /2;
X    int xscale = xoffset * FILL_SCALE;
X    int yscale = yoffset * FILL_SCALE;
X    int x = xoffset;
X    int y = yoffset;
X    double r = 0.0;
X    int newx = xoffset;
X    int newy = yoffset;
X    /* Black marks to Sun for having two different animals - pixwin and
X       pixrect - which makes this kludge necessary. Maybe you can get a pixwin
X       from a pixrect or vice-versa? */
X    if ( type == PIXWIN )
X	{
X	pw_batch_on( pw );
X	/* clear the window */
X	pw_writebackground(pw, 0, 0, width, height, PIX_SRC );
X	}
X    else
X	pr_rop((struct pixrect*)pw, 0, 0, width, height, PIX_CLR,
X		    (struct pixrect*)0, 0, 0 );
X    /* This is the kernel of the whole thing: draw the lines */
X    do
X	{
X	x = newx;
X	y = newy;
X	a = ( a + d ) % QUANTUM;
X	r = sinx[ (n * a ) % QUANTUM ];
X	newx = xoffset + xscale * r * sinx[a];
X	newy = yoffset + yscale * r * cosx[a];
X	if ( type == PIXWIN )
X	    pw_vector( pw, x, y, newx, newy, PIX_SRC, 1 );
X	else
X	    pr_vector( (struct pixrect*)pw, x, y, newx, newy, PIX_SRC, 1 );
X	}
X	while ( a != 0 );
X    /* unbatch */
X    if ( type == PIXWIN )
X	pw_batch_off( pw );
X}
X
Xredraw_proc()
X{
X    int width = (int)window_get( canvas, WIN_WIDTH );
X    int height = (int)window_get( canvas, WIN_HEIGHT );
X    redraw( PIXWIN, pw, width, height );
X    /* It would be faster to redraw the icon only when necessary - however
X       this makes the program *2 more complicated - need to get involved
X       with Notifiers and all that */
X    redraw_icon();
X}
X
Xredraw_icon()
X{
X    /* get pixrect for icon */
X    Icon icon = (Icon) window_get( frame, FRAME_ICON );
X    Pixrect *pr = (Pixrect*) icon_get( icon, ICON_IMAGE );
X    redraw( PIXRECT, pr, pr->pr_size.x, pr->pr_size.y );
X    icon_set( icon, ICON_IMAGE, pr, 0 );
X    window_set( frame, FRAME_ICON, icon, 0 );
X}
X
X/* procedures to adjust the sliders one step at a time */
Xn_down_proc()
X{
X    int n = (int) panel_get_value( panel_n );
X    panel_set_value( panel_n, (caddr_t)(n-1) );
X    redraw_proc();
X}
X
Xn_up_proc()
X{
X    int n = (int) panel_get_value( panel_n );
X    panel_set_value( panel_n, (caddr_t)(n+1) );
X    redraw_proc();
X}
X
Xd_down_proc()
X{
X    int d = (int) panel_get_value( panel_d );
X    panel_set_value( panel_d, (caddr_t)(d-1) );
X    redraw_proc();
X}
X
Xd_up_proc()
X{
X    int d = (int) panel_get_value( panel_d );
X    panel_set_value( panel_d, (caddr_t)(d+1) );
X    redraw_proc();
X}
X
X
Xquit_proc()
X{
X    exit(0);
X}
X
Xmain( argc, argv )
X    int argc; char **argv;
X{
X    /* open the canvas */
X    Panel panel;
X    struct pixrect *icon_pr = mem_create ( 64, 64, 1 );
X    Icon icon = icon_create( ICON_IMAGE, icon_pr, 0 );
X    frame = window_create( NULL, FRAME,
X					WIN_HEIGHT, SIZE + 100,
X					WIN_WIDTH, SIZE,
X					FRAME_ARGS, argc, argv,
X	FRAME_LABEL, "Rose display program by igp@camcon.uucp  Version 1.9",
X					FRAME_ICON, icon,
X					0 );
X    panel = window_create( frame, PANEL,
X					WIN_WIDTH, SIZE,
X					0 );
X    /* draw a panel */
X    srand( time((long*)0));
X    panel_n = panel_create_item( panel, PANEL_SLIDER,
X				PANEL_LABEL_STRING, "N ",
X				PANEL_MIN_VALUE, 1,
X				PANEL_SLIDER_WIDTH, SLIDER_LENGTH,
X				PANEL_MAX_VALUE, QUANTUM-1,
X				PANEL_NOTIFY_PROC, redraw_proc,
X				PANEL_VALUE, (rand()/256)%(QUANTUM-2) + 1,
X				0 );
X    panel_create_item( panel, PANEL_BUTTON,
X				PANEL_LABEL_IMAGE,
X			panel_button_image( panel, "down", 0, (Pixfont *) 0 ),
X				PANEL_NOTIFY_PROC, n_down_proc,
X				0 );
X    panel_create_item( panel, PANEL_BUTTON,
X				PANEL_LABEL_IMAGE,
X			panel_button_image( panel, "up", 0, (Pixfont *) 0 ),
X				PANEL_NOTIFY_PROC, n_up_proc,
X				0 );
X    panel_d = panel_create_item( panel, PANEL_SLIDER,
X				PANEL_LABEL_STRING, "D ",
X				PANEL_MIN_VALUE, 1,
X				PANEL_SLIDER_WIDTH, SLIDER_LENGTH,
X				PANEL_MAX_VALUE, QUANTUM-1,
X				PANEL_VALUE, (rand()/256)%(QUANTUM-2) + 1,
X				PANEL_NOTIFY_PROC, redraw_proc,
X				0 );
X    panel_create_item( panel, PANEL_BUTTON,
X				PANEL_LABEL_IMAGE,
X			panel_button_image( panel, "down", 0, (Pixfont *) 0 ),
X				PANEL_NOTIFY_PROC, d_down_proc,
X				0 );
X    panel_create_item( panel, PANEL_BUTTON,
X				PANEL_LABEL_IMAGE,
X			panel_button_image( panel, "up", 0, (Pixfont *) 0 ),
X				PANEL_NOTIFY_PROC, d_up_proc,
X				0 );
X    panel_create_item(panel, PANEL_BUTTON,
X                      PANEL_LABEL_IMAGE,
X                      panel_button_image(panel, "quit", 0, (Pixfont *) 0),
X                      PANEL_NOTIFY_PROC, quit_proc,
X                      0);
X    window_fit_height( panel );
X    canvas = window_create( frame, CANVAS,
X				WIN_BELOW, panel,
X				WIN_X, 0,
X				WIN_HEIGHT, SIZE,
X				WIN_WIDTH, SIZE,
X				CANVAS_FIXED_IMAGE, FALSE,
X				CANVAS_REPAINT_PROC, redraw_proc,
X				0 );
X    pw = canvas_pixwin( canvas );
X    window_fit(frame);
X    /* precompute trig stuff */
X    { int i;
X	for ( i=0; i<QUANTUM; i++ )
X	{
X	    sinx[i] = sin(i*(2*M_PI/QUANTUM));
X	    cosx[i] = cos(i*(2*M_PI/QUANTUM));
X	}
X    }
X    redraw_icon();
X    window_main_loop(frame);
X    exit(0);
X}
SHAR_EOF
chmod 0644 rose.c || echo "restore of rose.c fails"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
XLDFLAGS=-lsuntool -lsunwindow -lpixrect -lm
XCFLAGS=-O
X
X# This is only necessary because of a stupidity in Sun's default.mk which
X# puts LDFLAGS too early in the line
Xrose: rose.c
X	$(CC) $(CFLAGS) -o $@ $? $(LDFLAGS)
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
exit 0
-- 
UUCP:  ...!ukc!camcon!igp | Cambridge Consultants Ltd  |  Ian Phillipps
or:    igp@camcon.uucp    | Science Park, Milton Road  |-----------------
Phone: +44 223 358855     | Cambridge CB4 4DW, England |