1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* flow --- flow of strange bees */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)flow.c 4.10 98/04/24 xlockmore";
10 * Copyright (c) 1996 by Tim Auckland <Tim.Auckland@Sun.COM>
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
24 * "flow" shows a variety of continuous phase-space flows around strange
25 * attractors. It includes the well-known Lorentz mask (the "Butterfly"
26 * of chaos fame), two forms of Rossler's "Folded Band" and a Poincare'
27 * section of the "Bagel".
30 * 09-Apr-97: Ported to xlockmore-4
31 * 18-Jul-96: Adapted from swarm.c Copyright (c) 1991 by Patrick J. Naughton.
32 * 31-Aug-90: Adapted from xswarm by Jeff Butterworth. (butterwo@ncsc.org)
36 # define PROGCLASS "Flow"
37 # define HACK_INIT init_flow
38 # define HACK_DRAW draw_flow
39 # define flow_opts xlockmore_opts
40 # define DEFAULTS "*delay: 1000 \n" \
44 # define SMOOTH_COLORS
45 # include "xlockmore.h" /* in xscreensaver distribution */
48 #else /* STANDALONE */
49 # include "xlock.h" /* in xlockmore distribution */
50 #endif /* STANDALONE */
52 ModeSpecOpt flow_opts =
53 {0, NULL, 0, NULL, NULL};
56 ModStruct flow_description =
57 {"flow", "init_flow", "draw_flow", "release_flow",
58 "refresh_flow", "init_flow", NULL, &flow_opts,
59 1000, 1024, 3000, 1, 64, 1.0, "",
60 "Shows dynamic strange attractors", 0, NULL};
64 #define TIMES 2 /* number of time positions recorded */
77 #define X(t,b) (sp->p[(t)*sp->beecount+(b)].x)
78 #define Y(t,b) (sp->p[(t)*sp->beecount+(b)].y)
79 #define Z(t,b) (sp->p[(t)*sp->beecount+(b)].z)
80 #define balance_rand(v) ((LRAND()/MAXRAND*(v))-((v)/2)) /* random number around 0 */
89 int beecount; /* number of bees */
90 XSegment *csegs; /* bee lines */
92 XSegment *old_segs; /* old bee lines */
94 dvector c; /* centre */
95 dvector *p; /* bee positions x[time][bee#] */
101 void (*ODE) (Par par,
102 double *dx, double *dy, double *dz,
103 double x, double y, double z,
108 static flowstruct *flows = NULL;
112 double *dx, double *dy, double *dz,
113 double x, double y, double z,
116 *dx = par.a * (y - x);
117 *dy = x * (par.b - z) - y;
118 *dz = x * y - par.c * z;
123 double *dx, double *dy, double *dz,
124 double x, double y, double z,
127 *dx = -(y + par.a * z);
129 *dz = par.c + z * (x - 5.7);
134 double *dx, double *dy, double *dz,
135 double x, double y, double z,
138 *dx = -(y + par.a * z);
139 *dy = x + y * par.b - z * z * par.c;
140 *dz = 0.2 + z * (x - 5.7);
145 double *dx, double *dy, double *dz,
146 double x, double y, double z,
149 *dx = -y + par.b * sin(par.c * t);
150 *dy = 0.7 * x + par.a * y * (0.1 - x * x);
155 init_flow(ModeInfo * mi)
162 if ((flows = (flowstruct *) calloc(MI_NUM_SCREENS(mi),
163 sizeof (flowstruct))) == NULL)
166 sp = &flows[MI_SCREEN(mi)];
168 sp->beecount = MI_COUNT(mi);
169 if (sp->beecount < 0) {
170 /* if sp->beecount is random ... the size can change */
171 if (sp->csegs != NULL) {
172 (void) free((void *) sp->csegs);
175 if (sp->cnsegs != NULL) {
176 (void) free((void *) sp->cnsegs);
179 if (sp->old_segs != NULL) {
180 (void) free((void *) sp->old_segs);
184 (void) free((void *) sp->p);
188 (void) free((void *) sp->t);
191 sp->beecount = NRAND(-sp->beecount) + 1; /* Add 1 so its not too boring */
195 sp->width = MI_WIDTH(mi);
196 sp->height = MI_HEIGHT(mi);
198 sp->theta = balance_rand(M_PI);
199 sp->phi = balance_rand(M_PI);
213 sp->par.a = 10 + balance_rand(5);
214 sp->par.b = 28 + balance_rand(5);
215 sp->par.c = 2 + balance_rand(1);
227 sp->par.a = 2 + balance_rand(1);
228 sp->par.b = 0.2 + balance_rand(0.1);
229 sp->par.c = 0.2 + balance_rand(0.1);
232 sp->ODE = RosslerCone;
243 sp->par.c = 0.25 + balance_rand(0.09);
250 sp->c.x = 0 /*-1.0*/ ;
256 sp->par.a = 10 + balance_rand(5);
257 sp->par.b = 0.35 + balance_rand(0.25);
261 sp->dtheta = 0 /*sp->par.c*sp->step */ ;
266 /* Clear the background. */
269 /* Allocate memory. */
272 sp->csegs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount
274 sp->cnsegs = (int *) malloc(sizeof (int) * MI_NPIXELS(mi));
276 sp->old_segs = (XSegment *) malloc(sizeof (XSegment) * sp->beecount);
277 sp->p = (dvector *) malloc(sizeof (dvector) * sp->beecount * TIMES);
278 sp->t = (double *) malloc(sizeof (double) * sp->beecount);
280 /* Initialize point positions, velocities, etc. */
283 for (b = 0; b < sp->beecount; b++) {
284 X(0, b) = balance_rand(range.x);
286 Y(0, b) = balance_rand(range.y);
288 Z(0, b) = balance_rand(range.z);
296 draw_flow(ModeInfo * mi)
298 Display *display = MI_DISPLAY(mi);
299 Window window = MI_WINDOW(mi);
301 flowstruct *sp = &flows[MI_SCREEN(mi)];
304 double sint, cost, sinp, cosp;
306 sp->theta += sp->dtheta;
308 sint = sin(sp->theta);
309 cost = cos(sp->theta);
312 for (col = 0; col < MI_NPIXELS(mi); col++)
316 for (b = 0; b < sp->beecount; b++) {
317 /* Age the arrays. */
322 /* 2nd order Kunge Kutta */
324 double k1x, k1y, k1z;
325 double k2x, k2y, k2z;
327 sp->t[b] += sp->step; /* tick */
328 sp->ODE(sp->par, &k1x, &k1y, &k1z,
329 X(1, b), Y(1, b), Z(1, b), sp->t[b]);
333 sp->ODE(sp->par, &k2x, &k2y, &k2z,
334 X(1, b) + k1x, Y(1, b) + k1y, Z(1, b) + k1z, sp->t[b]);
338 X(0, b) = X(1, b) + (k1x + k2x) / 2.0;
339 Y(0, b) = Y(1, b) + (k1y + k2y) / 2.0;
340 Z(0, b) = Z(1, b) + (k1z + k2z) / 2.0;
343 /* Fill the segment lists. */
347 #define DISPLAYX(A) (sp->width/2+sp->width/sp->size* \
348 ((X((A),b)-sp->c.x)*cost \
349 -(Y((A),b)-sp->c.y)*sint*cosp \
350 +(Z((A),b)-sp->c.z)*sint*sinp))
351 #define DISPLAYY(A) (sp->height/2-sp->height/sp->size* \
352 ((X((A),b)-sp->c.x)*sint \
353 +(Y((A),b)-sp->c.y)*cost*cosp \
354 -(Z((A),b)-sp->c.z)*cost*sinp))
356 /* Colour according to bee */
357 col = b % (MI_NPIXELS(mi) - 1);
359 ix = col * sp->beecount + sp->cnsegs[col];
360 sp->csegs[ix].x1 = DISPLAYX(0);
361 sp->csegs[ix].y1 = DISPLAYY(0);
362 sp->csegs[ix].x2 = DISPLAYX(1);
363 sp->csegs[ix].y2 = DISPLAYY(1);
367 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
368 XDrawSegments(display, window, gc, sp->old_segs, sp->beecount);
370 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
371 if (MI_NPIXELS(mi) > 2) {
372 for (col = 0; col < MI_NPIXELS(mi); col++) {
373 if (sp->cnsegs[col] > 0) {
374 XSetForeground(display, gc, MI_PIXEL(mi, col));
375 XDrawSegments(display, window, gc,
376 sp->csegs + col * sp->beecount,
382 XSetForeground(display, gc, MI_PIXEL(mi, 1));
383 XDrawSegments(display, window, gc,
384 sp->csegs + col * sp->beecount,
387 for (col = 0, c = 0; col < MI_NPIXELS(mi); col++)
388 for (b = 0; b < sp->cnsegs[col]; b++) {
389 XSegment s = (sp->csegs + col * sp->beecount)[b];
391 sp->old_segs[c].x1 = s.x1;
392 sp->old_segs[c].y1 = s.y1;
393 sp->old_segs[c].x2 = s.x2;
394 sp->old_segs[c].y2 = s.y2;
397 if (++sp->count > MI_CYCLES(mi)) {
403 release_flow(ModeInfo * mi)
408 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
409 flowstruct *sp = &flows[screen];
411 if (sp->csegs != NULL)
412 (void) free((void *) sp->csegs);
413 if (sp->cnsegs != NULL)
414 (void) free((void *) sp->cnsegs);
415 if (sp->old_segs != NULL)
416 (void) free((void *) sp->old_segs);
418 (void) free((void *) sp->p);
420 (void) free((void *) sp->t);
422 (void) free((void *) flows);
428 refresh_flow(ModeInfo * mi)