1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* crystal --- polygons moving according to plane group rules */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)crystal.c 4.12 98/09/10 xlockmore";
10 * Copyright (c) 1997 by Jouk Jansen <joukj@crys.chem.uva.nl>
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 * The author should like to be notified if changes have been made to the
25 * routine. Response will only be guaranteed when a VMS version of the
26 * program is available.
28 * A moving polygon-mode. The polygons obey 2D-planegroup symmetry.
30 * The groupings of the cells fall in 3 categories:
31 * oblique groups 1 and 2 where the angle gamma ranges from 60 to 120 degrees
32 * square groups 3 through 11 where the angle gamma is 90 degrees
33 * hexagonal groups 12 through 17 where the angle gamma is 120 degrees
36 * 03-Dec-98: Random inversion of y-axis included to simulate hexagonal groups
37 * with an angle of 60 degrees.
38 * 10-Sep-98: new colour scheme
39 * 24-Feb-98: added option centre which turns on/off forcing the centre of
40 * the screen to be used
41 * added option maxsize which forces the dimensions to be chasen
42 * in such ua way that the largest possible part of the screen is
44 * When only one unit cell is drawn, it is chosen at random
45 * 18-Feb-98: added support for negative numbers with -nx and -ny meaning
46 * "random" choice with given maximum
47 * added +/-grid option. If -cell is specified this option
48 * determines if one or all unit cells are drawn.
49 * -batchcount is now a parameter for all the objects on the screen
50 * instead of the number of "unique" objects
51 * The maximum size of the objects now scales with the part
53 * fixed "size" problem. Now very small non-vissable objects
55 * 13-Feb-98: randomized the unit cell size
56 * runtime options -/+cell (turn on/off unit cell drawing)
57 * -nx num (number of translational symmetries in x-direction
58 * -ny num (idem y-direction but ignored for square and
59 * hexagonal space groups
60 * i.e. try xlock -mode crystal -nx 3 -ny 2
61 * Fullrandom overrules the -/+cell option.
62 * 05-Feb-98: Revision + bug repairs
64 * use part of the screen for unit cell
65 * in hexagonal and square groups a&b axis forced to be equal
66 * cell angle for oblique groups randomly chosen between 60 and 120
67 * bugs solved: planegroups with cell angles <> 90.0 now work properly
68 * 19-Sep-97: Added remaining hexagonal groups
73 # define PROGCLASS "Crystal"
74 # define HACK_INIT init_crystal
75 # define HACK_DRAW draw_crystal
76 # define crystal_opts xlockmore_opts
77 # define DEFAULTS "*delay: 60000 \n" \
82 "*fullrandom: True \n" \
84 # include "xlockmore.h" /* in xscreensaver distribution */
85 #else /* STANDALONE */
86 # include "xlock.h" /* in xlockmore distribution */
88 #endif /* STANDALONE */
90 #define DEF_CELL "True" /* Draw unit cell */
91 #define DEF_GRID "False" /* Draw unit all cell if DEF_CELL is True */
92 #define DEF_NX "-3" /* number of unit cells in x-direction */
93 #define DEF_NX1 1 /* number of unit cells in x-direction */
94 #define DEF_NY "-3" /* number of unit cells in y-direction */
95 #define DEF_NY1 1 /* number of unit cells in y-direction */
96 #define DEF_CENTRE "False"
97 #define DEF_MAXSIZE "False"
98 #define DEF_CYCLE "True"
100 #define min(a,b) ((a) <= (b) ? (a) : (b))
103 void release_crystal(ModeInfo * mi);
108 static Bool unit_cell, grid_cell, centre, maxsize, cycle_p;
110 static XrmOptionDescRec opts[] =
112 {"-nx", "crystal.nx", XrmoptionSepArg, (caddr_t) NULL},
113 {"-ny", "crystal.ny", XrmoptionSepArg, (caddr_t) NULL},
114 {"-centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "on"},
115 {"+centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "off"},
116 {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "on"},
117 {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "off"},
118 {"-cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "on"},
119 {"+cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "off"},
120 {"-grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "on"},
121 {"+grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "off"},
122 {"-shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "on"},
123 {"+shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "off"}
126 static argtype vars[] =
128 {(caddr_t *) & nx, "nx", "nx", DEF_NX, t_Int},
129 {(caddr_t *) & ny, "ny", "ny", DEF_NY, t_Int},
130 {(caddr_t *) & centre, "centre", "Centre", DEF_CENTRE, t_Bool},
131 {(caddr_t *) & maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
132 {(caddr_t *) & unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
133 {(caddr_t *) & grid_cell, "grid", "Grid", DEF_GRID, t_Bool},
134 {(caddr_t *) & cycle_p, "shift", "Shift", DEF_CYCLE, t_Bool}
136 static OptionStruct desc[] =
138 {"-nx num", "Number of unit cells in x-direction"},
139 {"-ny num", "Number of unit cells in y-direction"},
140 {"-/+centre", "turn on/off centering on screen"},
141 {"-/+maxsize", "turn on/off use of maximum part of screen"},
142 {"-/+cell", "turn on/off drawing of unit cell"},
143 {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"},
144 {"-/+shift", "turn on/off colour cycling"}
147 ModeSpecOpt crystal_opts =
148 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
151 ModStruct crystal_description =
152 {"crystal", "init_crystal", "draw_crystal", "release_crystal",
153 "refresh_crystal", "init_crystal", NULL, &crystal_opts,
154 60000, -40, 200, -15, 64, 1.0, "",
155 "Shows polygons in 2D plane groups", 0, NULL};
159 #define DEF_NUM_ATOM 10
161 #define DEF_SIZ_ATOM 10
163 #define PI_RAD (M_PI / 180.0)
165 static Bool centro[17] =
186 static Bool primitive[17] =
207 static short numops[34] =
228 static short operation[114] =
252 unsigned long colour;
253 int x0, y0, velocity[2];
254 float angle, velocity_a;
255 int num_point, at_type, size_at;
261 int win_width, win_height, num_atom;
262 int planegroup, a, b, offset_w, offset_h, nx, ny;
266 Bool unit_cell, grid_cell;
270 Bool cycle_p, mono_p, no_colors;
271 unsigned long blackpixel, whitepixel, fg, bg;
272 int direction, invert;
275 static crystalstruct *crystals = NULL;
278 trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
283 for (i = 0; i <= num_points; i++) {
284 new_xyp[i].x = xyp[i].x +
285 (int) (xyp[i].y * sin((gamma - 90.0) * PI_RAD));
286 new_xyp[i].y = (int) (xyp[i].y / cos((gamma - 90.0) * PI_RAD));
291 trans_coor_back(XPoint * xyp, XPoint * new_xyp,
292 int num_points, float gamma, int offset_w, int offset_h ,
293 int winheight , int invert )
297 for (i = 0; i <= num_points; i++) {
298 new_xyp[i].y = (int) (xyp[i].y * cos((gamma - 90) * PI_RAD)) +
300 new_xyp[i].x = xyp[i].x - (int) (xyp[i].y * sin((gamma - 90.0)
301 * PI_RAD)) + offset_w;
302 if ( invert ) new_xyp[i].y = winheight - new_xyp[i].y;
307 crystal_setupatom(crystalatom * atom0, float gamma)
312 y0 = (int) (atom0->y0 * cos((gamma - 90) * PI_RAD));
313 x0 = atom0->x0 - (int) (atom0->y0 * sin((gamma - 90.0) * PI_RAD));
314 switch (atom0->at_type) {
315 case 0: /* rectangles */
316 xy[0].x = x0 + (int) (2 * atom0->size_at *
318 (int) (atom0->size_at * sin(atom0->angle));
319 xy[0].y = y0 + (int) (atom0->size_at *
321 (int) (2 * atom0->size_at * sin(atom0->angle));
322 xy[1].x = x0 + (int) (2 * atom0->size_at *
324 (int) (atom0->size_at * sin(atom0->angle));
325 xy[1].y = y0 - (int) (atom0->size_at *
327 (int) (2 * atom0->size_at * sin(atom0->angle));
328 xy[2].x = x0 - (int) (2 * atom0->size_at *
330 (int) (atom0->size_at * sin(atom0->angle));
331 xy[2].y = y0 - (int) (atom0->size_at *
333 (int) (2 * atom0->size_at * sin(atom0->angle));
334 xy[3].x = x0 - (int) (2 * atom0->size_at *
336 (int) (atom0->size_at * sin(atom0->angle));
337 xy[3].y = y0 + (int) (atom0->size_at *
339 (int) (2 * atom0->size_at *
343 trans_coor(xy, atom0->xy, 4, gamma);
345 case 1: /* squares */
346 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
348 (int) (1.5 * atom0->size_at *
350 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
352 (int) (1.5 * atom0->size_at *
354 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
356 (int) (1.5 * atom0->size_at *
358 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
360 (int) (1.5 * atom0->size_at *
362 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
364 (int) (1.5 * atom0->size_at *
366 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
368 (int) (1.5 * atom0->size_at *
370 xy[3].x = x0 - (int) (1.5 * atom0->size_at *
372 (int) (1.5 * atom0->size_at *
374 xy[3].y = y0 + (int) (1.5 * atom0->size_at *
376 (int) (1.5 * atom0->size_at *
380 trans_coor(xy, atom0->xy, 4, gamma);
382 case 2: /* triangles */
383 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
385 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
387 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
389 (int) (1.5 * atom0->size_at *
391 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
393 (int) (1.5 * atom0->size_at *
395 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
397 (int) (1.5 * atom0->size_at *
399 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
401 (int) (1.5 * atom0->size_at *
405 trans_coor(xy, atom0->xy, 3, gamma);
411 crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
413 crystalstruct *cryst;
414 Display *display = MI_DISPLAY(mi);
415 Window window = MI_WINDOW(mi);
418 cryst = &crystals[MI_SCREEN(mi)];
419 for (j = numops[2 * cryst->planegroup + 1];
420 j < numops[2 * cryst->planegroup]; j++) {
421 XPoint xy[5], new_xy[5];
425 xtrans = operation[j * 6] * atom0->x0 + operation[j * 6 + 1] *
426 atom0->y0 + (int) (operation[j * 6 + 4] * cryst->a /
428 ytrans = operation[j * 6 + 2] * atom0->x0 + operation[j * 6 +
429 3] * atom0->y0 + (int) (operation[j * 6 + 5] *
432 if (xtrans < -cryst->a)
433 xtrans = 2 * cryst->a;
436 } else if (xtrans >= cryst->a)
442 else if (ytrans >= cryst->b)
446 for (k = 0; k < atom0->num_point; k++) {
447 xy[k].x = operation[j * 6] * atom0->xy[k].x +
448 operation[j * 6 + 1] *
449 atom0->xy[k].y + (int) (operation[j * 6 + 4] *
452 xy[k].y = operation[j * 6 + 2] * atom0->xy[k].x +
453 operation[j * 6 + 3] *
454 atom0->xy[k].y + (int) (operation[j * 6 + 5] *
458 xy[atom0->num_point].x = xy[0].x;
459 xy[atom0->num_point].y = xy[0].y;
460 for (l = 0; l < cryst->nx; l++) {
461 for (m = 0; m < cryst->ny; m++) {
463 for (k = 0; k <= atom0->num_point; k++) {
464 xy_1[k].x = xy[k].x + l * cryst->a;
465 xy_1[k].y = xy[k].y + m * cryst->b;
467 trans_coor_back(xy_1, new_xy, atom0->num_point,
468 cryst->gamma, cryst->offset_w,
472 XFillPolygon(display, window, cryst->gc, new_xy,
473 atom0->num_point, Convex, CoordModeOrigin);
476 if (centro[cryst->planegroup] == True) {
477 for (k = 0; k <= atom0->num_point; k++) {
478 xy[k].x = cryst->a - xy[k].x;
479 xy[k].y = cryst->b - xy[k].y;
481 for (l = 0; l < cryst->nx; l++) {
482 for (m = 0; m < cryst->ny; m++) {
484 for (k = 0; k <= atom0->num_point; k++) {
485 xy_1[k].x = xy[k].x + l * cryst->a;
486 xy_1[k].y = xy[k].y + m * cryst->b;
488 trans_coor_back(xy_1, new_xy, atom0->num_point,
494 XFillPolygon(display, window, cryst->gc,
496 atom0->num_point, Convex,
501 if (primitive[cryst->planegroup] == False) {
502 if (xy[atom0->num_point].x >= (int) (cryst->a / 2.0))
503 xtrans = (int) (-cryst->a / 2.0);
505 xtrans = (int) (cryst->a / 2.0);
506 if (xy[atom0->num_point].y >= (int) (cryst->b / 2.0))
507 ytrans = (int) (-cryst->b / 2.0);
509 ytrans = (int) (cryst->b / 2.0);
510 for (k = 0; k <= atom0->num_point; k++) {
511 xy[k].x = xy[k].x + xtrans;
512 xy[k].y = xy[k].y + ytrans;
514 for (l = 0; l < cryst->nx; l++) {
515 for (m = 0; m < cryst->ny; m++) {
517 for (k = 0; k <= atom0->num_point; k++) {
518 xy_1[k].x = xy[k].x + l * cryst->a;
519 xy_1[k].y = xy[k].y + m * cryst->b;
521 trans_coor_back(xy_1, new_xy, atom0->num_point,
527 XFillPolygon(display, window, cryst->gc,
529 atom0->num_point, Convex,
533 if (centro[cryst->planegroup] == True) {
536 for (k = 0; k <= atom0->num_point; k++) {
537 xy1[k].x = cryst->a - xy[k].x;
538 xy1[k].y = cryst->b - xy[k].y;
540 for (l = 0; l < cryst->nx; l++) {
541 for (m = 0; m < cryst->ny; m++) {
543 for (k = 0; k <= atom0->num_point; k++) {
544 xy_1[k].x = xy1[k].x + l * cryst->a;
545 xy_1[k].y = xy1[k].y + m * cryst->b;
547 trans_coor_back(xy_1, new_xy, atom0->num_point,
553 XFillPolygon(display, window,
555 new_xy, atom0->num_point,
556 Convex, CoordModeOrigin);
565 draw_crystal(ModeInfo * mi)
567 Display *display = MI_DISPLAY(mi);
568 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
571 if (cryst->no_colors) {
576 cryst->painted = True;
577 MI_IS_DRAWN(mi) = True;
578 XSetFunction(display, cryst->gc, GXxor);
581 if (cryst->cycle_p) {
582 rotate_colors(display, cryst->cmap, cryst->colors, cryst->ncolors,
584 if (!(LRAND() % 1000))
585 cryst->direction = -cryst->direction;
587 for (i = 0; i < cryst->num_atom; i++) {
590 atom0 = &cryst->atom[i];
592 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
593 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
595 XSetForeground(display, cryst->gc, atom0->colour);
597 crystal_drawatom(mi, atom0);
598 atom0->velocity[0] += NRAND(3) - 1;
599 atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
600 atom0->velocity[1] += NRAND(3) - 1;
601 atom0->velocity[1] = MAX(-20, MIN(20, atom0->velocity[1]));
602 atom0->x0 += atom0->velocity[0];
603 /*if (cryst->gamma == 90.0) { */
605 atom0->x0 += cryst->a;
606 else if (atom0->x0 >= cryst->a)
607 atom0->x0 -= cryst->a;
608 atom0->y0 += atom0->velocity[1];
610 atom0->y0 += cryst->b;
611 else if (atom0->y0 >= cryst->b)
612 atom0->y0 -= cryst->b;
614 atom0->velocity_a += ((float) NRAND(1001) - 500.0) / 2000.0;
615 atom0->angle += atom0->velocity_a;
616 crystal_setupatom(atom0, cryst->gamma);
617 crystal_drawatom(mi, atom0);
619 XSetFunction(display, cryst->gc, GXcopy);
623 refresh_crystal(ModeInfo * mi)
625 Display *display = MI_DISPLAY(mi);
626 Window window = MI_WINDOW(mi);
627 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
633 XSetFunction(display, cryst->gc, GXxor);
635 if (cryst->unit_cell) {
636 int y_coor1 , y_coor2;
638 if (MI_NPIXELS(mi) > 2)
639 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
641 XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
642 if (cryst->grid_cell) {
646 y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
648 y_coor1 = y_coor2 = cryst->offset_h;
649 XDrawLine(display, window, cryst->gc, cryst->offset_w,
650 y_coor1, cryst->offset_w + cryst->nx * cryst->a,
654 y_coor1 = cryst->win_height - cryst->offset_h;
655 y_coor2 = cryst->win_height - (int) (cryst->ny *
657 cos((cryst->gamma - 90) * PI_RAD)) -
662 y_coor1 = cryst->offset_h;
663 y_coor2 = (int) (cryst->ny * cryst->b *
664 cos((cryst->gamma - 90) * PI_RAD)) +
667 XDrawLine(display, window, cryst->gc, cryst->offset_w,
668 y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
669 sin((cryst->gamma - 90) * PI_RAD)),
672 for (iny = 1; iny <= cryst->ny; iny++) {
675 y_coor1 = cryst->win_height -
676 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
677 PI_RAD)) - cryst->offset_h;
678 y_coor2 = cryst->win_height -
679 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
685 y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
686 PI_RAD)) + cryst->offset_h;
687 y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
690 XDrawLine(display, window, cryst->gc,
691 (int) (cryst->offset_w +
692 inx * cryst->a - (int) (iny * cryst->b *
693 sin((cryst->gamma - 90) * PI_RAD))),
695 (int) (cryst->offset_w - iny * cryst->b *
696 sin((cryst->gamma - 90) * PI_RAD)),
700 for (inx = 1; inx <= cryst->nx; inx++) {
703 y_coor1 =cryst->win_height -
704 (int) (iny * cryst->b *
705 cos((cryst->gamma - 90) *
706 PI_RAD)) - cryst->offset_h;
707 y_coor2 =cryst->win_height - cryst->offset_h;
711 y_coor1 =(int) (iny * cryst->b *
712 cos((cryst->gamma - 90) *
713 PI_RAD)) + cryst->offset_h;
714 y_coor2 =cryst->offset_h;
716 XDrawLine(display, window, cryst->gc,
717 (int) (cryst->offset_w +
718 inx * cryst->a - (int) (iny * cryst->b *
719 sin((cryst->gamma - 90) * PI_RAD))),
721 cryst->offset_w + inx * cryst->a,
727 inx = NRAND(cryst->nx);
728 iny = NRAND(cryst->ny);
731 y_coor1 =cryst->win_height -
732 (int) (iny * cryst->b *
733 cos((cryst->gamma - 90) *
736 y_coor2 =cryst->win_height -
737 (int) ( ( iny + 1 ) * cryst->b *
738 cos((cryst->gamma - 90) *
744 y_coor1 =(int) (iny * cryst->b *
745 cos((cryst->gamma - 90) *
748 y_coor2 =(int) (( iny + 1 ) * cryst->b *
749 cos((cryst->gamma - 90) *
753 XDrawLine(display, window, cryst->gc,
754 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
756 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
758 XDrawLine(display, window, cryst->gc,
759 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
761 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
763 XDrawLine(display, window, cryst->gc,
764 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
766 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
768 XDrawLine(display, window, cryst->gc,
769 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
771 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
775 for (i = 0; i < cryst->num_atom; i++) {
778 atom0 = &cryst->atom[i];
779 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
780 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
782 XSetForeground(display, cryst->gc, atom0->colour);
784 crystal_drawatom(mi, atom0);
786 XSetFunction(display, cryst->gc, GXcopy);
790 release_crystal(ModeInfo * mi)
792 Display *display = MI_DISPLAY(mi);
794 if (crystals != NULL) {
797 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
798 crystalstruct *cryst = &crystals[screen];
800 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
801 MI_WHITE_PIXEL(mi) = cryst->whitepixel;
802 MI_BLACK_PIXEL(mi) = cryst->blackpixel;
804 MI_FG_PIXEL(mi) = cryst->fg;
805 MI_BG_PIXEL(mi) = cryst->bg;
807 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
808 free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
810 (void) free((void *) cryst->colors);
811 #if 0 /* #### wrong! -jwz */
812 XFreeColormap(display, cryst->cmap);
815 if (cryst->gc != NULL)
816 XFreeGC(display, cryst->gc);
817 if (cryst->atom != NULL)
818 (void) free((void *) cryst->atom);
820 (void) free((void *) crystals);
826 init_crystal(ModeInfo * mi)
828 Display *display = MI_DISPLAY(mi);
829 Window window = MI_WINDOW(mi);
830 crystalstruct *cryst;
831 int i, max_atoms, size_atom, neqv;
837 if (crystals == NULL) {
838 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
839 sizeof (crystalstruct))) == NULL)
842 cryst = &crystals[MI_SCREEN(mi)];
845 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
849 extern char *background;
850 extern char *foreground;
852 cryst->fg = MI_FG_PIXEL(mi);
853 cryst->bg = MI_BG_PIXEL(mi);
855 cryst->blackpixel = MI_BLACK_PIXEL(mi);
856 cryst->whitepixel = MI_WHITE_PIXEL(mi);
857 #if 0 /* #### wrong! -jwz */
858 cryst->cmap = XCreateColormap(display, window,
859 MI_VISUAL(mi), AllocNone);
860 XSetWindowColormap(display, window, cryst->cmap);
862 cryst->cmap = mi->xgwa.colormap;
864 (void) XParseColor(display, cryst->cmap, "black", &color);
865 (void) XAllocColor(display, cryst->cmap, &color);
866 MI_BLACK_PIXEL(mi) = color.pixel;
867 (void) XParseColor(display, cryst->cmap, "white", &color);
868 (void) XAllocColor(display, cryst->cmap, &color);
869 MI_WHITE_PIXEL(mi) = color.pixel;
871 (void) XParseColor(display, cryst->cmap, background, &color);
872 (void) XAllocColor(display, cryst->cmap, &color);
873 MI_BG_PIXEL(mi) = color.pixel;
874 (void) XParseColor(display, cryst->cmap, foreground, &color);
875 (void) XAllocColor(display, cryst->cmap, &color);
876 MI_FG_PIXEL(mi) = color.pixel;
881 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
882 (unsigned long) 0, (XGCValues *) NULL)) == None)
887 cryst->painted = False;
888 XSetFunction(display, cryst->gc, GXxor);
891 /*Set up crystal data */
892 cryst->direction = (LRAND() & 1) ? 1 : -1;
893 if (MI_IS_FULLRANDOM(mi)) {
895 cryst->unit_cell = True;
897 cryst->unit_cell = False;
899 cryst->unit_cell = unit_cell;
900 if (cryst->unit_cell) {
901 if (MI_IS_FULLRANDOM(mi)) {
903 cryst->grid_cell = True;
905 cryst->grid_cell = False;
907 cryst->grid_cell = grid_cell;
909 cryst->win_width = MI_WIDTH(mi);
910 cryst->win_height = MI_HEIGHT(mi);
911 cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
912 cell_min = min(cell_min, cryst->win_height / 2 + 1);
913 cryst->planegroup = NRAND(17);
914 cryst->invert = NRAND(2);
915 if (MI_IS_VERBOSE(mi))
916 (void) fprintf(stdout, "Selected plane group no %d\n",
917 cryst->planegroup + 1);
918 if (cryst->planegroup > 11)
919 cryst->gamma = 120.0;
920 else if (cryst->planegroup < 2)
921 cryst->gamma = 60.0 + NRAND(60);
924 neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
925 if (centro[cryst->planegroup] == True)
927 if (primitive[cryst->planegroup] == False)
934 cryst->nx = NRAND(-nx) + 1;
937 if (cryst->planegroup > 8)
938 cryst->ny = cryst->nx;
942 cryst->ny = NRAND(-ny) + 1;
945 neqv = neqv * cryst->nx * cryst->ny;
947 cryst->num_atom = MI_COUNT(mi);
948 max_atoms = MI_COUNT(mi);
949 if (cryst->num_atom == 0) {
950 cryst->num_atom = DEF_NUM_ATOM;
951 max_atoms = DEF_NUM_ATOM;
952 } else if (cryst->num_atom < 0) {
953 max_atoms = -cryst->num_atom;
954 cryst->num_atom = NRAND(-cryst->num_atom) + 1;
957 cryst->num_atom = cryst->num_atom / neqv + 1;
959 if (cryst->atom == NULL)
960 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
964 if (cryst->planegroup < 13) {
968 if (cryst->planegroup < 10) {
969 cryst->b = cryst->win_height;
970 cryst->a = cryst->win_width;
972 cryst->b = min(cryst->win_height, cryst->win_width);
976 cryst->gamma = 120.0;
977 cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
979 cryst->offset_h = (int) (cryst->b * 0.25 *
980 cos((cryst->gamma - 90) * PI_RAD));
981 cryst->offset_w = (int) (cryst->b * 0.5);
984 cryst->offset_w = -1;
985 while (cryst->offset_w < 4 || (int) (cryst->offset_w - cryst->b *
986 sin((cryst->gamma - 90) * PI_RAD)) < 4) {
987 cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
988 PI_RAD))) - cell_min) + cell_min;
989 if (cryst->planegroup > 8)
992 cryst->a = NRAND(cryst->win_width - cell_min) + cell_min;
993 cryst->offset_w = (int) ((cryst->win_width - (cryst->a - cryst->b *
994 sin((cryst->gamma - 90) *
997 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
998 cryst->gamma - 90) * PI_RAD)) / 2.0);
1000 if (cryst->offset_h > 0)
1001 cryst->offset_h = NRAND(2 * cryst->offset_h);
1002 cryst->offset_w = (int) (cryst->win_width - cryst->a -
1004 fabs(sin((cryst->gamma - 90) * PI_RAD)));
1005 if (cryst->gamma > 90.0) {
1006 if (cryst->offset_w > 0)
1007 cryst->offset_w = NRAND(cryst->offset_w) +
1008 (int) (cryst->b * sin((cryst->gamma - 90) * PI_RAD));
1010 cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
1012 } else if (cryst->offset_w > 0)
1013 cryst->offset_w = NRAND(cryst->offset_w);
1015 cryst->offset_w = 0;
1019 size_atom = min((int) ((float) (cryst->a) / 40.) + 1,
1020 (int) ((float) (cryst->b) / 40.) + 1);
1021 if (MI_SIZE(mi) < size_atom) {
1022 if (MI_SIZE(mi) < -size_atom)
1023 size_atom = -size_atom;
1025 size_atom = MI_SIZE(mi);
1027 cryst->a = cryst->a / cryst->nx;
1028 cryst->b = cryst->b / cryst->ny;
1029 if (cryst->unit_cell) {
1030 int y_coor1 , y_coor2;
1032 if (MI_NPIXELS(mi) > 2)
1033 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
1035 XSetForeground(display, cryst->gc, MI_WHITE_PIXEL(mi));
1036 if (cryst->grid_cell) {
1039 if ( cryst->invert )
1040 y_coor1 = y_coor2 = cryst->win_height - cryst->offset_h;
1042 y_coor1 = y_coor2 = cryst->offset_h;
1043 XDrawLine(display, window, cryst->gc, cryst->offset_w,
1044 y_coor1, cryst->offset_w + cryst->nx * cryst->a,
1046 if ( cryst->invert )
1048 y_coor1 = cryst->win_height - cryst->offset_h;
1049 y_coor2 = cryst->win_height - (int) (cryst->ny *
1051 cos((cryst->gamma - 90) * PI_RAD)) -
1056 y_coor1 = cryst->offset_h;
1057 y_coor2 = (int) (cryst->ny * cryst->b *
1058 cos((cryst->gamma - 90) * PI_RAD)) +
1061 XDrawLine(display, window, cryst->gc, cryst->offset_w,
1062 y_coor1, (int) (cryst->offset_w - cryst->ny * cryst->b *
1063 sin((cryst->gamma - 90) * PI_RAD)),
1066 for (iny = 1; iny <= cryst->ny; iny++) {
1067 if ( cryst->invert )
1069 y_coor1 = cryst->win_height -
1070 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1071 PI_RAD)) - cryst->offset_h;
1072 y_coor2 = cryst->win_height -
1073 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1079 y_coor1 = (int) (iny * cryst->b * cos((cryst->gamma - 90) *
1080 PI_RAD)) + cryst->offset_h;
1081 y_coor2 = (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
1084 XDrawLine(display, window, cryst->gc,
1085 (int) (cryst->offset_w +
1086 inx * cryst->a - (int) (iny * cryst->b *
1087 sin((cryst->gamma - 90) * PI_RAD))),
1089 (int) (cryst->offset_w - iny * cryst->b *
1090 sin((cryst->gamma - 90) * PI_RAD)),
1094 for (inx = 1; inx <= cryst->nx; inx++) {
1095 if ( cryst->invert )
1097 y_coor1 =cryst->win_height -
1098 (int) (iny * cryst->b *
1099 cos((cryst->gamma - 90) *
1100 PI_RAD)) - cryst->offset_h;
1101 y_coor2 =cryst->win_height - cryst->offset_h;
1105 y_coor1 =(int) (iny * cryst->b *
1106 cos((cryst->gamma - 90) *
1107 PI_RAD)) + cryst->offset_h;
1108 y_coor2 =cryst->offset_h;
1110 XDrawLine(display, window, cryst->gc,
1111 (int) (cryst->offset_w +
1112 inx * cryst->a - (int) (iny * cryst->b *
1113 sin((cryst->gamma - 90) * PI_RAD))),
1115 cryst->offset_w + inx * cryst->a,
1121 inx = NRAND(cryst->nx);
1122 iny = NRAND(cryst->ny);
1123 if ( cryst->invert )
1125 y_coor1 =cryst->win_height -
1126 (int) (iny * cryst->b *
1127 cos((cryst->gamma - 90) *
1130 y_coor2 =cryst->win_height -
1131 (int) ( ( iny + 1 ) * cryst->b *
1132 cos((cryst->gamma - 90) *
1138 y_coor1 =(int) (iny * cryst->b *
1139 cos((cryst->gamma - 90) *
1142 y_coor2 =(int) (( iny + 1 ) * cryst->b *
1143 cos((cryst->gamma - 90) *
1147 XDrawLine(display, window, cryst->gc,
1148 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1150 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1152 XDrawLine(display, window, cryst->gc,
1153 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1155 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1157 XDrawLine(display, window, cryst->gc,
1158 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1160 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1162 XDrawLine(display, window, cryst->gc,
1163 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1165 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
1169 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1170 /* Set up colour map */
1171 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
1172 free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
1174 (void) free((void *) cryst->colors);
1176 cryst->ncolors = MI_NCOLORS(mi);
1177 if (cryst->ncolors < 2)
1179 if (cryst->ncolors <= 2)
1180 cryst->mono_p = True;
1182 cryst->mono_p = False;
1187 cryst->colors = (XColor *) malloc(sizeof (*cryst->colors) * (cryst->ncolors + 1));
1188 cryst->cycle_p = has_writable_cells(mi->xgwa.screen, MI_VISUAL(mi));
1189 if (cryst->cycle_p) {
1190 if (MI_IS_FULLRANDOM(mi)) {
1192 cryst->cycle_p = False;
1194 cryst->cycle_p = True;
1196 cryst->cycle_p = cycle_p;
1199 if (!cryst->mono_p) {
1200 if (!(LRAND() % 10))
1201 make_random_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1202 True, True, &cryst->cycle_p, True);
1203 else if (!(LRAND() % 2))
1204 make_uniform_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1205 True, &cryst->cycle_p, True);
1207 make_smooth_colormap(MI_DISPLAY(mi), MI_VISUAL(mi), cryst->cmap, cryst->colors, &cryst->ncolors,
1208 True, &cryst->cycle_p, True);
1210 #if 0 /* #### wrong! -jwz */
1211 XInstallColormap(display, cryst->cmap);
1213 if (cryst->ncolors < 2) {
1215 cryst->no_colors = True;
1217 cryst->no_colors = False;
1218 if (cryst->ncolors <= 2)
1219 cryst->mono_p = True;
1222 cryst->cycle_p = False;
1225 for (i = 0; i < cryst->num_atom; i++) {
1228 atom0 = &cryst->atom[i];
1229 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
1230 if (cryst->ncolors > 2)
1231 atom0->colour = NRAND(cryst->ncolors - 2) + 2;
1233 atom0->colour = 1; /* Just in case */
1234 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
1236 if (MI_NPIXELS(mi) > 2)
1237 atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
1239 atom0->colour = 1; /*Xor'red so WHITE may not be appropriate */
1240 XSetForeground(display, cryst->gc, atom0->colour);
1242 atom0->x0 = NRAND(cryst->a);
1243 atom0->y0 = NRAND(cryst->b);
1244 atom0->velocity[0] = NRAND(7) - 3;
1245 atom0->velocity[1] = NRAND(7) - 3;
1246 atom0->velocity_a = (NRAND(7) - 3) * PI_RAD;
1247 atom0->angle = NRAND(90) * PI_RAD;
1248 atom0->at_type = NRAND(3);
1250 atom0->size_at = DEF_SIZ_ATOM;
1251 else if (size_atom > 0)
1252 atom0->size_at = size_atom;
1254 atom0->size_at = NRAND(-size_atom) + 1;
1256 if (atom0->at_type == 2)
1257 atom0->num_point = 3;
1259 atom0->num_point = 4;
1260 crystal_setupatom(atom0, cryst->gamma);
1261 crystal_drawatom(mi, atom0);
1263 XSync(display, False);
1264 XSetFunction(display, cryst->gc, GXcopy);