1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* apollonian --- Apollonian Circles */
5 static const char sccsid[] = "@(#)apollonian.c 5.02 2001/07/01 xlockmore";
9 * Copyright (c) 2000, 2001 by Allan R. Wilks <allan@research.att.com>.
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
23 * radius r = 1 / c (curvature)
25 * Descartes Circle Theorem: (a, b, c, d are curvatures of tangential circles)
26 * Let a, b, c, d be the curvatures of for mutually (externally) tangent
27 * circles in the plane. Then
28 * a^2 + b^2 + c^2 + d^2 = (a + b + c + d)^2 / 2
30 * Complex Descartes Theorem: If the oriented curvatues and (complex) centers
31 * of an oriented Descrates configuration in the plane are a, b, c, d and
32 * w, x, y, z respectively, then
33 * a^2*w^2 + b^2*x^2 + c^2*y^2 + d^2*z^2 = (aw + bx + cy + dz)^2 / 2
34 * In addition these quantities satisfy
35 * a^2*w + b^2*x + c^2*y + d^2*z = (aw + bx + cy + dz)(a + b + c + d) / 2
37 * Enumerate root integer Descartes quadruples (a,b,c,d) satisfying the
38 * Descartes condition:
39 * 2(a^2+b^2+c^2+d^2) = (a+b+c+d)^2
40 * i.e., quadruples for which no application of the "pollinate" operator
41 * z <- 2(a+b+c+d) - 3*z,
42 * where z is in {a,b,c,d}, gives a quad of strictly smaller sum. This
43 * is equivalent to the condition:
44 * sum(a,b,c,d) >= 2*max(a,b,c,d)
45 * which, because of the Descartes condition, is equivalent to
46 * sum(a^2,b^2,c^2,d^2) >= 2*max(a,b,c,d)^2
50 * 25-Jun-2001: Converted from C and Postscript code by David Bagley
51 * Original code by Allan R. Wilks <allan@research.att.com>.
53 * From Circle Math Science News April 21, 2001 VOL. 254-255
54 * http://www.sciencenews.org/20010421/toc.asp
55 * Apollonian Circle Packings Assorted papers from Ronald L Graham,
56 * Jeffrey Lagarias, Colin Mallows, Allan Wilks, Catherine Yan
57 * http://front.math.ucdavis.edu/math.NT/0009113
58 * http://front.math.ucdavis.edu/math.MG/0101066
59 * http://front.math.ucdavis.edu/math.MG/0010298
60 * http://front.math.ucdavis.edu/math.MG/0010302
61 * http://front.math.ucdavis.edu/math.MG/0010324
65 # define MODE_apollonian
66 # define DEFAULTS "*delay: 1000000 \n" \
70 "*font: sans-serif bold 16\n" \
72 "*fpsSolid: true \n" \
73 "*ignoreRotation: True" \
75 # define release_apollonian 0
76 # define reshape_apollonian 0
77 # define apollonian_handle_event 0
78 # include "xlockmore.h" /* in xscreensaver distribution */
79 #else /* STANDALONE */
80 # include "xlock.h" /* in xlockmore distribution */
81 #endif /* STANDALONE */
83 #ifdef MODE_apollonian
85 #define DEF_ALTGEOM "True"
86 #define DEF_LABEL "True"
91 static XrmOptionDescRec opts[] =
93 {"-altgeom", ".apollonian.altgeom", XrmoptionNoArg, "on"},
94 {"+altgeom", ".apollonian.altgeom", XrmoptionNoArg, "off"},
95 {"-label", ".apollonian.label", XrmoptionNoArg, "on"},
96 {"+label", ".apollonian.label", XrmoptionNoArg, "off"},
98 static argtype vars[] =
100 {&altgeom, "altgeom", "AltGeom", DEF_ALTGEOM, t_Bool},
101 {&label, "label", "Label", DEF_LABEL, t_Bool},
103 static OptionStruct desc[] =
105 {"-/+altgeom", "turn on/off alternate geometries (off euclidean space, on includes spherical and hyperbolic)"},
106 {"-/+label", "turn on/off alternate space and number labeling"},
109 ENTRYPOINT ModeSpecOpt apollonian_opts =
110 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
113 ModStruct apollonian_description =
114 {"apollonian", "init_apollonian", "draw_apollonian", (char *) NULL,
115 "init_apollonian", "init_apollonian", "free_apollonian", &apollonian_opts,
116 1000000, 64, 20, 1, 64, 1.0, "",
117 "Shows Apollonian Circles", 0, NULL};
123 } apollonian_quadruple;
126 double e; /* euclidean bend */
127 double s; /* spherical bend */
128 double h; /* hyperbolic bend */
129 double x, y; /* euclidean bend times euclidean position */
132 euclidean = 0, spherical, hyperbolic
135 static const char * space_string[] = {
142 Generate Apollonian packing starting with a quadruple of circles.
143 The four input lines each contain the 5-tuple (e,s,h,x,y) representing
144 the circle with radius 1/e and center (x/e,y/e). The s and h is propagated
145 like e, x and y, but can differ from e so as to represent different
146 geometries, spherical and hyperbolic, respectively. The "standard" picture,
147 for example (-1, 2, 2, 3), can be labeled for the three geometries.
148 Origins of circles z1, z2, z3, z4
151 c * z3 = (q123 + a * i)^2/(a*(a+b)) where q123 = sqrt(a*b+a*c+b*c)
152 d * z4 = (q124 + a * i)^2/(a*(a+b)) where q124 = q123 - a - b
153 If (e,x,y) represents the Euclidean circle (1/e,x/e,y/e) (so that e is
154 the label in the standard picture) then the "spherical label" is
155 (e^2+x^2+y^2-1)/(2*e) (an integer!) and the "hyperbolic label", is
156 calulated by h + s = e.
158 static circle examples[][4] = {
159 { /* double semi-bounded */
172 { /* next simplest */
173 {-2, -1, -1, 0.0, 0},
179 {-3, -2, -1, 0.0, 0},
180 { 4, 3, 1, 1.0 / 3.0, 0},
182 {13, 8, 5, -8.0 / 3.0, 2}
185 {-3, -2, -1, 0.0, 0},
186 { 5, 4, 1, 2.0 / 3.0, 0},
187 { 8, 5, 3, -4.0 / 3.0, -1},
188 { 8, 5, 3, -4.0 / 3.0, 1}
191 {-4, -3, -1, 0.00, 0},
193 {20, 13, 7, -4.00, 0},
194 {21, 14, 7, -3.75, 2}
197 {-4, -2, -2, 0.0, 0},
199 { 9, 5, 4, -0.75, -1},
203 {-5, -4, -1, 0.0, 0},
205 {18, 13, 5, -2.4, -1},
209 {-6, -5, -1, 0.0, 0},
210 { 7, 6, 1, 1.0 / 6.0, 0},
211 {42, 31, 11, -6.0, 0},
212 {43, 32, 11, -35.0 / 6.0, 2}
215 {-6, -3, -3, 0.0, 0},
216 {10, 5, 5, 2.0 / 3.0, 0},
218 {19, 10, 9, -5.0 / 6.0, 2}
221 {-6, -5, -1, 0.0, 0.0},
222 {11, 10, 1, 5.0 / 6.0, 0.0},
223 {14, 11, 3, -16.0 / 15.0, -0.8},
224 {15, 12, 3, -0.9, 1.2}
227 /* Non integer stuff */
228 #define DELTA 2.154700538 /* ((3+2*sqrt(3))/3) */
229 { /* 3 fold symmetric bounded (x, y calculated later) */
230 { -1, -1, -1, 0.0, 0.0},
231 {DELTA, DELTA, DELTA, 1.0, 0.0},
232 {DELTA, DELTA, DELTA, 1.0, -1.0},
233 {DELTA, DELTA, DELTA, -1.0, 1.0}
235 { /* semi-bounded (x, y calculated later) */
236 #define ALPHA 2.618033989 /* ((3+sqrt(5))/2) */
237 { 1.0, 1.0, 1.0, 0, 0},
238 { 0.0, 0.0, 0.0, 0, -1},
239 {1.0/(ALPHA*ALPHA), 1.0/(ALPHA*ALPHA), 1.0/(ALPHA*ALPHA), -1, 0},
240 { 1.0/ALPHA, 1.0/ALPHA, 1.0/ALPHA, -1, 0}
242 { /* unbounded (x, y calculated later) */
243 /* #define PHI 1.618033989 *//* ((1+sqrt(5))/2) */
244 #define BETA 2.890053638 /* (PHI+sqrt(PHI)) */
245 { 1.0, 1.0, 1.0, 0, 0},
246 {1.0/(BETA*BETA*BETA), 1.0/(BETA*BETA*BETA), 1.0/(BETA*BETA*BETA), 1, 0},
247 { 1.0/(BETA*BETA), 1.0/(BETA*BETA), 1.0/(BETA*BETA), 1, 0},
248 { 1.0/BETA, 1.0/BETA, 1.0/BETA, 1, 0}
252 #define PREDEF_CIRCLE_GAMES (sizeof (examples) / (4 * sizeof (circle)))
285 circle c1, c2, c3, c4;
289 apollonian_quadruple *quad;
297 static apollonianstruct *apollonians = (apollonianstruct *) NULL;
299 #define K 2.15470053837925152902 /* 1+2/sqrt(3) */
300 #define MAXBEND 100 /* Do not want configurable by user since it will take too
301 much time if increased. */
323 y = (int) (sqrt((double) n) + 0.5);
324 return ((n == y*y) ? y : -1);
328 dquad(int n, apollonian_quadruple *quad)
331 int counter = 0, B, C;
333 for (a = 0; a < MAXBEND; a++) {
335 for (b = a + 1; b <= B; b++) {
336 C = (int) (((a + b) * (a + b)) / (4.0 * (b - a)));
337 for (c = b; c <= C; c++) {
338 d = isqrt(b*c-a*(b+c));
339 if (d >= 0 && (gcd(a,gcd(b,c)) <= 1)) {
340 quad[counter].a = -a;
343 quad[counter].d = -a+b+c-2*d;
344 if (++counter >= n) {
351 (void) printf("found only %d below maximum bend of %d\n",
353 for (; counter < n; counter++) {
354 quad[counter].a = -1;
363 * Given a Descartes quadruple of bends (a,b,c,d), with a<0, find a
364 * quadruple of circles, represented by (bend,bend*x,bend*y), such
365 * that the circles have the given bends and the bends times the
366 * centers are integers.
368 * This just performs an exaustive search, assuming that the outer
369 * circle has center in the unit square.
371 * It is always sufficient to look in {(x,y):0<=y<=x<=1/2} for the
372 * center of the outer circle, but this may not lead to a packing
373 * that can be labelled with integer spherical and hyperbolic labels.
374 * To effect the smaller search, replace FOR(a) with
376 * for (pa = ea/2; pa <= 0; pa++) for (qa = pa; qa <= 0; qa++)
379 #define For(v,l,h) for (v = l; v <= h; v++)
380 #define FOR(z) For(p##z,lop##z,hip##z) For(q##z,loq##z,hiq##z)
381 #define H(z) ((e##z*e##z+p##z*p##z+q##z*q##z)%2)
382 #define UNIT(z) ((abs(e##z)-1)*(abs(e##z)-1) >= p##z*p##z+q##z*q##z)
383 #define T(z,w) is_tangent(e##z,p##z,q##z,e##w,p##w,q##w)
384 #define LO(r,z) lo##r##z = iceil(e##z*(r##a+1),ea)-1
385 #define HI(r,z) hi##r##z = iflor(e##z*(r##a-1),ea)-1
386 #define B(z) LO(p,z); HI(p,z); LO(q,z); HI(q,z)
389 is_quad(int a, int b, int c, int d)
394 return 2*(a*a+b*b+c*c+d*d) == s*s;
398 is_tangent(int e1, int p1, int q1, int e2, int p2, int q2)
405 return dx*dx + dy*dy == s*s;
414 (void) printf("iflor: b = 0\n");
420 return ((a<0)^(b<0)) ? -q-1 : q;
429 (void) printf("iceil: b = 0\n");
435 return ((a<0)^(b<0)) ? -q : 1+q;
439 geom(int geometry, int e, int p, int q)
441 int g = (geometry == spherical) ? -1 :
442 (geometry == hyperbolic) ? 1 : 0;
445 return (e*e + (1.0 - p*p - q*q) * g) / (2.0*e);
446 (void) printf("geom: g = 0\n");
451 cquad(circle *c1, circle *c2, circle *c3, circle *c4)
456 int lopa, lopb, lopc, lopd;
457 int hipa, hipb, hipc, hipd;
458 int loqa, loqb, loqc, loqd;
459 int hiqa, hiqb, hiqc, hiqd;
466 (void) printf("ea = %d\n", ea);
467 if (!is_quad(ea,eb,ec,ed))
468 (void) printf("Error not quad %d %d %d %d\n", ea, eb, ec, ed);
473 if (H(a) && UNIT(a)) FOR(b) {
474 if (H(b) && T(a,b)) FOR(c) {
475 if (H(c) && T(a,c) && T(b,c)) FOR(d) {
476 if (H(d) && T(a,d) && T(b,d) && T(c,d)) {
477 c1->s = geom(spherical, ea, pa, qa);
478 c1->h = geom(hyperbolic, ea, pa, qa);
479 c2->s = geom(spherical, eb, pb, qb);
480 c2->h = geom(hyperbolic, eb, pb, qb);
481 c3->s = geom(spherical, ec, pc, qc);
482 c3->h = geom(hyperbolic, ec, pc, qc);
483 c4->s = geom(spherical, ed, pd, qd);
484 c4->h = geom(hyperbolic, ed, pd, qd);
493 set_xft_color (ModeInfo *mi, XftColor *c, unsigned long pixel)
497 XQueryColor (MI_DISPLAY(mi), MI_COLORMAP(mi), &xc);
499 c->color.red = xc.red;
500 c->color.green = xc.green;
501 c->color.blue = xc.blue;
502 c->color.alpha = 0xFFFF;
507 p(ModeInfo *mi, circle c)
509 apollonianstruct *cp = &apollonians[MI_SCREEN(mi)];
516 (void) printf("c.e=%g c.s=%g c.h=%g c.x=%g c.y=%g\n",
517 c.e, c.s, c.h, c.x, c.y);
519 g = (cp->geometry == spherical) ? c.s : (cp->geometry == hyperbolic) ?
524 if (MI_NPIXELS(mi) <= 2)
525 pix = MI_WHITE_PIXEL(mi);
527 pix = MI_PIXEL(mi, ((int) ((g + cp->color_offset) * g))
529 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), pix);
530 set_xft_color (mi, &cp->xft_fg, pix);
531 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
532 ((int) (cp->size * (-cp->c1.e) * (c.x - 1.0) /
533 (-2.0 * c.e) + cp->size / 2.0 + cp->offset.x)),
534 ((int) (cp->size * (-cp->c1.e) * (c.y - 1.0) /
535 (-2.0 * c.e) + cp->size / 2.0 + cp->offset.y)),
536 (int) (cp->c1.e * cp->size / c.e),
537 (int) (cp->c1.e * cp->size / c.e), 0, 23040);
540 (void) printf("%g\n", -g);
545 sprintf(string, "%g", (g == 0.0) ? 0 : -g);
546 XftDrawStringUtf8 (cp->xftdraw, &cp->xft_fg, cp->font,
547 ((int) (cp->size * c.x / (2.0 * c.e))) +
548 cp->offset.x + cp->font->ascent * 2,
549 ((int) (cp->size * c.y / (2.0 * c.e))) +
550 cp->font->ascent * 4,
555 XftDrawStringUtf8 (cp->xftdraw, &cp->xft_fg, cp->font,
556 ((int) (cp->size * c.x / (2.0 * c.e) +
557 cp->offset.x)) + cp->font->ascent * 2,
558 ((int) (cp->size * c.y / (2.0 * c.e) +
559 MI_HEIGHT(mi) - cp->font->ascent * 4)),
560 (FcChar8 *) space_string[cp->geometry],
561 strlen(space_string[cp->geometry]));
564 if (MI_NPIXELS(mi) <= 2)
565 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
567 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
568 MI_PIXEL(mi, ((int) ((g + cp->color_offset) * g)) %
571 if (c.x == 0.0 && c.y != 0.0) {
572 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
573 0, (int) ((c.y + 1.0) * cp->size / 2.0 + cp->offset.y),
575 (int) ((c.y + 1.0) * cp->size / 2.0 + cp->offset.y));
576 } else if (c.y == 0.0 && c.x != 0.0) {
577 XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
578 (int) ((c.x + 1.0) * cp->size / 2.0 + cp->offset.x), 0,
579 (int) ((c.x + 1.0) * cp->size / 2.0 + cp->offset.x),
584 e = (cp->c1.e >= 0.0) ? 1.0 : -cp->c1.e;
585 XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
586 ((int) (cp->size * e * (c.x - 1.0) / (2.0 * c.e) +
587 cp->size / 2.0 + cp->offset.x)),
588 ((int) (cp->size * e * (c.y - 1.0) / (2.0 * c.e) +
589 cp->size / 2.0 + cp->offset.y)),
590 (int) (e * cp->size / c.e), (int) (e * cp->size / c.e),
594 (void) printf("%g\n", g);
598 if (MI_NPIXELS(mi) <= 2)
599 pix = MI_BLACK_PIXEL(mi);
601 pix = MI_PIXEL(mi, ((int) ((g + cp->color_offset) * g) +
602 MI_NPIXELS(mi) / 2) % MI_NPIXELS(mi));
603 g_width = (g < 10.0) ? 1: ((g < 100.0) ? 2 : 3);
604 if (c.e < e * cp->size / ((cp->font->ascent + cp->font->descent) * 2) &&
607 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), pix);
608 set_xft_color (mi, &cp->xft_fg, pix);
609 sprintf(string, "%g", g);
610 XftTextExtentsUtf8 (MI_DISPLAY(mi), cp->font,
611 (FcChar8 *) string, g_width, &overall);
612 XftDrawStringUtf8 (cp->xftdraw, &cp->xft_fg, cp->font,
613 ((int) (cp->size * e * c.x / (2.0 * c.e) +
614 cp->size / 2.0 + cp->offset.x)) -
616 ((int) (cp->size * e * c.y / (2.0 * c.e) +
617 cp->size / 2.0 + cp->offset.y)) +
618 cp->font->ascent / 2,
619 (FcChar8 *) string, g_width);
625 f(ModeInfo *mi, circle c1, circle c2, circle c3, circle c4, int depth)
627 apollonianstruct *cp = &apollonians[MI_SCREEN(mi)];
628 int e = (int) ((cp->c1.e >= 0.0) ? 1.0 : -cp->c1.e);
631 if (depth > mi->recursion_depth) mi->recursion_depth = depth;
633 c.e = 2*(c1.e+c2.e+c3.e) - c4.e;
634 c.s = 2*(c1.s+c2.s+c3.s) - c4.s;
635 c.h = 2*(c1.h+c2.h+c3.h) - c4.h;
636 c.x = 2*(c1.x+c2.x+c3.x) - c4.x;
637 c.y = 2*(c1.y+c2.y+c3.y) - c4.y;
639 c.e > cp->size * e || c.x / c.e > BIG || c.y / c.e > BIG ||
640 c.x / c.e < -BIG || c.y / c.e < -BIG)
643 f(mi, c2, c3, c, c1, depth+1);
644 f(mi, c1, c3, c, c2, depth+1);
645 f(mi, c1, c2, c, c3, depth+1);
649 free_apollonian (ModeInfo * mi)
651 apollonianstruct *cp = &apollonians[MI_SCREEN(mi)];
653 if (cp->quad != NULL) {
654 (void) free((void *) cp->quad);
655 cp->quad = (apollonian_quadruple *) NULL;
658 XftFontClose (MI_DISPLAY(mi), cp->font);
659 XftDrawDestroy (cp->xftdraw);
664 randomize_c(int randomize, circle * c)
681 init_apollonian (ModeInfo * mi)
683 apollonianstruct *cp;
687 MI_INIT (mi, apollonians);
688 cp = &apollonians[MI_SCREEN(mi)];
690 cp->size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
691 cp->offset.x = (MI_WIDTH(mi) - cp->size) / 2;
692 cp->offset.y = (MI_HEIGHT(mi) - cp->size) / 2;
693 cp->color_offset = NRAND(MI_NPIXELS(mi));
695 cp->font = load_xft_font_retry (MI_DISPLAY(mi), MI_SCREEN(mi),
696 get_string_resource (MI_DISPLAY(mi),
698 cp->xftdraw = XftDrawCreate (MI_DISPLAY(mi), MI_WINDOW(mi),
699 MI_VISUAL(mi), MI_COLORMAP(mi));
700 s = get_string_resource (MI_DISPLAY(mi), "foreground", "Foreground");
701 XftColorAllocName (MI_DISPLAY(mi), MI_VISUAL(mi), MI_COLORMAP(mi), s,
706 cp->altgeom = cp->label && altgeom;
708 if (cp->quad == NULL) {
709 cp->count = ABS(MI_COUNT(mi));
710 if ((cp->quad = (apollonian_quadruple *) malloc(cp->count *
711 sizeof (apollonian_quadruple))) == NULL) {
714 dquad(cp->count, cp->quad);
716 cp->game = NRAND(PREDEF_CIRCLE_GAMES + cp->count);
717 cp->geometry = (cp->game && cp->altgeom) ? NRAND(3) : 0;
719 if (cp->game < PREDEF_CIRCLE_GAMES) {
720 cp->c1 = examples[cp->game][0];
721 cp->c2 = examples[cp->game][1];
722 cp->c3 = examples[cp->game][2];
723 cp->c4 = examples[cp->game][3];
724 /* do not label non int */
725 cp->label = cp->label && (cp->c4.e == (int) cp->c4.e);
726 } else { /* uses results of dquad, all int */
727 i = cp->game - PREDEF_CIRCLE_GAMES;
728 cp->c1.e = cp->quad[i].a;
729 cp->c2.e = cp->quad[i].b;
730 cp->c3.e = cp->quad[i].c;
731 cp->c4.e = cp->quad[i].d;
733 cquad(&(cp->c1), &(cp->c2), &(cp->c3), &(cp->c4));
740 if (cp->c1.e == 0.0 || cp->c1.e == -cp->c2.e)
744 cp->c2.x = -(cp->c1.e + cp->c2.e) / cp->c1.e;
746 q123 = sqrt(cp->c1.e * cp->c2.e + cp->c1.e * cp->c3.e +
747 cp->c2.e * cp->c3.e);
749 (void) printf("q123 = %g, ", q123);
751 cp->c3.x = (cp->c1.e * cp->c1.e - q123 * q123) / (cp->c1.e *
752 (cp->c1.e + cp->c2.e));
753 cp->c3.y = -2.0 * q123 / (cp->c1.e + cp->c2.e);
754 q123 = -cp->c1.e - cp->c2.e + q123;
755 cp->c4.x = (cp->c1.e * cp->c1.e - q123 * q123) / (cp->c1.e *
756 (cp->c1.e + cp->c2.e));
757 cp->c4.y = -2.0 * q123 / (cp->c1.e + cp->c2.e);
759 (void) printf("q124 = %g\n", q123);
760 (void) printf("%g %g %g %g %g %g %g %g\n",
761 cp->c1.x, cp->c1.y, cp->c2.x, cp->c2.y,
762 cp->c3.x, cp->c3.y, cp->c4.x, cp->c4.y);
767 cp->c3.y = -cp->c3.y;
768 cp->c4.y = -cp->c4.y;
771 randomize_c(i, &(cp->c1));
772 randomize_c(i, &(cp->c2));
773 randomize_c(i, &(cp->c3));
774 randomize_c(i, &(cp->c4));
777 mi->recursion_depth = -1;
781 draw_apollonian (ModeInfo * mi)
783 apollonianstruct *cp;
785 if (apollonians == NULL)
787 cp = &apollonians[MI_SCREEN(mi)];
790 MI_IS_DRAWN(mi) = True;
801 f(mi, cp->c1, cp->c2, cp->c3, cp->c4, 0);
804 f(mi, cp->c1, cp->c2, cp->c4, cp->c3, 0);
807 f(mi, cp->c1, cp->c3, cp->c4, cp->c2, 0);
810 f(mi, cp->c2, cp->c3, cp->c4, cp->c1, 0);
813 if (++cp->time > MI_CYCLES(mi))
817 XSCREENSAVER_MODULE ("Apollonian", apollonian)
819 #endif /* MODE_apollonian */