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.
31 * 10-Sep-98: new colour scheme
32 * 24-Feb-98: added option centre which turns on/off forcing the centre of
33 * the screen to be used
34 * added option maxsize which forces the dimensions to be chasen
35 * in such ua way that the largest possible part of the screen is
37 * When only one unit cell is drawn, it is chosen at random
38 * 18-Feb-98: added support for negative numbers with -nx and -ny meaning
39 * "random" choice with given maximum
40 * added +/-grid option. If -cell is specified this option
41 * determines if one or all unit cells are drawn.
42 * -batchcount is now a parameter for all the objects on the screen
43 * instead of the number of "unique" objects
44 * The maximum size of the objects now scales with the part
46 * fixed "size" problem. Now very small non-vissable objects
48 * 13-Feb-98: randomized the unit cell size
49 * runtime options -/+cell (turn on/off unit cell drawing)
50 * -nx num (number of translational symmetries in x-direction
51 * -ny num (idem y-direction but ignored for square and
52 * hexagonal space groups
53 * i.e. try xlock -mode crystal -nx 3 -ny 2
54 * Fullrandom overrules the -/+cell option.
55 * 05-Feb-98: Revision + bug repairs
57 * use part of the screen for unit cell
58 * in hexagonal and square groups a&b axis forced to be equal
59 * cell angle for oblique groups randomly chosen between 60 and 120
60 * bugs solved: planegroups with cell angles <> 90.0 now work properly
61 * 19-Sep-97: Added remaining hexagonal groups
66 # define PROGCLASS "Crystal"
67 # define HACK_INIT init_crystal
68 # define HACK_DRAW draw_crystal
69 # define crystal_opts xlockmore_opts
70 # define DEFAULTS "*delay: 60000 \n" \
75 "*fullrandom: True \n" \
77 # include "xlockmore.h" /* in xscreensaver distribution */
78 #else /* STANDALONE */
79 # include "xlock.h" /* in xlockmore distribution */
80 #endif /* STANDALONE */
82 #define DEF_CELL "True" /* Draw unit cell */
83 #define DEF_GRID "False" /* Draw unit all cell if DEF_CELL is True */
84 #define DEF_NX "-3" /* number of unit cells in x-direction */
85 #define DEF_NX1 1 /* number of unit cells in x-direction */
86 #define DEF_NY "-3" /* number of unit cells in y-direction */
87 #define DEF_NY1 1 /* number of unit cells in y-direction */
88 #define DEF_CENTRE "False"
89 #define DEF_MAXSIZE "False"
90 #define DEF_CYCLE "True"
92 #define min(a,b) ((a) <= (b) ? (a) : (b))
94 void release_crystal(ModeInfo * mi);
98 static Bool unit_cell, grid_cell, centre, maxsize, cycle_p;
100 static XrmOptionDescRec opts[] =
102 {"-nx", "crystal.nx", XrmoptionSepArg, (caddr_t) NULL},
103 {"-ny", "crystal.ny", XrmoptionSepArg, (caddr_t) NULL},
104 {"-centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "on"},
105 {"+centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "off"},
106 {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "on"},
107 {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "off"},
108 {"-cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "on"},
109 {"+cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "off"},
110 {"-grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "on"},
111 {"+grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "off"},
112 {"-shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "on"},
113 {"+shift", ".crystal.shift", XrmoptionNoArg, (caddr_t) "off"}
116 static argtype vars[] =
118 {(caddr_t *) & nx, "nx", "nx", DEF_NX, t_Int},
119 {(caddr_t *) & ny, "ny", "ny", DEF_NY, t_Int},
120 {(caddr_t *) & centre, "centre", "Centre", DEF_CENTRE, t_Bool},
121 {(caddr_t *) & maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
122 {(caddr_t *) & unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
123 {(caddr_t *) & grid_cell, "grid", "Grid", DEF_GRID, t_Bool},
124 {(caddr_t *) & cycle_p, "shift", "Shift", DEF_CYCLE, t_Bool}
126 static OptionStruct desc[] =
128 {"-nx num", "Number of unit cells in x-direction"},
129 {"-ny num", "Number of unit cells in y-direction"},
130 {"-/+centre", "turn on/off centering on screen"},
131 {"-/+maxsize", "turn on/off use of maximum part of screen"},
132 {"-/+cell", "turn on/off drawing of unit cell"},
133 {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"},
134 {"-/+shift", "turn on/off colour cycling"}
137 ModeSpecOpt crystal_opts =
138 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
141 ModStruct crystal_description =
142 {"crystal", "init_crystal", "draw_crystal", "release_crystal",
143 "refresh_crystal", "init_crystal", NULL, &crystal_opts,
144 60000, -40, 200, -15, 64, 1.0, "",
145 "Shows polygons in 2D plane groups", 0, NULL};
149 #define DEF_NUM_ATOM 10
151 #define DEF_SIZ_ATOM 10
153 #define PI_RAD (M_PI / 180.0)
155 static Bool centro[17] =
176 static Bool primitive[17] =
197 static short numops[34] =
218 static short operation[114] =
242 unsigned long colour;
243 int x0, y0, velocity[2];
244 float angle, velocity_a;
245 int num_point, at_type, size_at;
251 int win_width, win_height, num_atom;
252 int planegroup, a, b, offset_w, offset_h, nx, ny;
256 Bool unit_cell, grid_cell;
260 Bool cycle_p, mono_p, no_colors;
261 unsigned long blackpixel, whitepixel, fg, bg;
265 static crystalstruct *crystals = NULL;
268 trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
273 for (i = 0; i <= num_points; i++) {
274 new_xyp[i].x = xyp[i].x +
275 (int) (xyp[i].y * sin((gamma - 90.0) * PI_RAD));
276 new_xyp[i].y = (int) (xyp[i].y / cos((gamma - 90.0) * PI_RAD));
281 trans_coor_back(XPoint * xyp, XPoint * new_xyp,
282 int num_points, float gamma, int offset_w, int offset_h)
286 for (i = 0; i <= num_points; i++) {
287 new_xyp[i].y = (int) (xyp[i].y * cos((gamma - 90) * PI_RAD)) +
289 new_xyp[i].x = xyp[i].x - (int) (xyp[i].y * sin((gamma - 90.0)
290 * PI_RAD)) + offset_w;
295 crystal_setupatom(crystalatom * atom0, float gamma)
300 y0 = (int) (atom0->y0 * cos((gamma - 90) * PI_RAD));
301 x0 = atom0->x0 - (int) (atom0->y0 * sin((gamma - 90.0) * PI_RAD));
302 switch (atom0->at_type) {
303 case 0: /* rectangles */
304 xy[0].x = x0 + (int) (2 * atom0->size_at *
306 (int) (atom0->size_at * sin(atom0->angle));
307 xy[0].y = y0 + (int) (atom0->size_at *
309 (int) (2 * atom0->size_at * sin(atom0->angle));
310 xy[1].x = x0 + (int) (2 * atom0->size_at *
312 (int) (atom0->size_at * sin(atom0->angle));
313 xy[1].y = y0 - (int) (atom0->size_at *
315 (int) (2 * atom0->size_at * sin(atom0->angle));
316 xy[2].x = x0 - (int) (2 * atom0->size_at *
318 (int) (atom0->size_at * sin(atom0->angle));
319 xy[2].y = y0 - (int) (atom0->size_at *
321 (int) (2 * atom0->size_at * sin(atom0->angle));
322 xy[3].x = x0 - (int) (2 * atom0->size_at *
324 (int) (atom0->size_at * sin(atom0->angle));
325 xy[3].y = y0 + (int) (atom0->size_at *
327 (int) (2 * atom0->size_at *
331 trans_coor(xy, atom0->xy, 4, gamma);
333 case 1: /* squares */
334 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
336 (int) (1.5 * atom0->size_at *
338 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
340 (int) (1.5 * atom0->size_at *
342 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
344 (int) (1.5 * atom0->size_at *
346 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
348 (int) (1.5 * atom0->size_at *
350 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
352 (int) (1.5 * atom0->size_at *
354 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
356 (int) (1.5 * atom0->size_at *
358 xy[3].x = x0 - (int) (1.5 * atom0->size_at *
360 (int) (1.5 * atom0->size_at *
362 xy[3].y = y0 + (int) (1.5 * atom0->size_at *
364 (int) (1.5 * atom0->size_at *
368 trans_coor(xy, atom0->xy, 4, gamma);
370 case 2: /* triangles */
371 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
373 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
375 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
377 (int) (1.5 * atom0->size_at *
379 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
381 (int) (1.5 * atom0->size_at *
383 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
385 (int) (1.5 * atom0->size_at *
387 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
389 (int) (1.5 * atom0->size_at *
393 trans_coor(xy, atom0->xy, 3, gamma);
399 crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
401 crystalstruct *cryst;
402 Display *display = MI_DISPLAY(mi);
403 Window window = MI_WINDOW(mi);
406 cryst = &crystals[MI_SCREEN(mi)];
407 for (j = numops[2 * cryst->planegroup + 1];
408 j < numops[2 * cryst->planegroup]; j++) {
409 XPoint xy[5], new_xy[5];
413 xtrans = operation[j * 6] * atom0->x0 + operation[j * 6 + 1] *
414 atom0->y0 + (int) (operation[j * 6 + 4] * cryst->a /
416 ytrans = operation[j * 6 + 2] * atom0->x0 + operation[j * 6 +
417 3] * atom0->y0 + (int) (operation[j * 6 + 5] *
420 if (xtrans < -cryst->a)
421 xtrans = 2 * cryst->a;
424 } else if (xtrans >= cryst->a)
430 else if (ytrans >= cryst->b)
434 for (k = 0; k < atom0->num_point; k++) {
435 xy[k].x = operation[j * 6] * atom0->xy[k].x +
436 operation[j * 6 + 1] *
437 atom0->xy[k].y + (int) (operation[j * 6 + 4] *
440 xy[k].y = operation[j * 6 + 2] * atom0->xy[k].x +
441 operation[j * 6 + 3] *
442 atom0->xy[k].y + (int) (operation[j * 6 + 5] *
446 xy[atom0->num_point].x = xy[0].x;
447 xy[atom0->num_point].y = xy[0].y;
448 for (l = 0; l < cryst->nx; l++) {
449 for (m = 0; m < cryst->ny; m++) {
451 for (k = 0; k <= atom0->num_point; k++) {
452 xy_1[k].x = xy[k].x + l * cryst->a;
453 xy_1[k].y = xy[k].y + m * cryst->b;
455 trans_coor_back(xy_1, new_xy, atom0->num_point,
456 cryst->gamma, cryst->offset_w, cryst->offset_h);
457 XFillPolygon(display, window, cryst->gc, new_xy,
458 atom0->num_point, Convex, CoordModeOrigin);
461 if (centro[cryst->planegroup] == True) {
462 for (k = 0; k <= atom0->num_point; k++) {
463 xy[k].x = cryst->a - xy[k].x;
464 xy[k].y = cryst->b - xy[k].y;
466 for (l = 0; l < cryst->nx; l++) {
467 for (m = 0; m < cryst->ny; m++) {
469 for (k = 0; k <= atom0->num_point; k++) {
470 xy_1[k].x = xy[k].x + l * cryst->a;
471 xy_1[k].y = xy[k].y + m * cryst->b;
473 trans_coor_back(xy_1, new_xy, atom0->num_point,
474 cryst->gamma, cryst->offset_w, cryst->offset_h);
475 XFillPolygon(display, window, cryst->gc,
477 atom0->num_point, Convex,
482 if (primitive[cryst->planegroup] == False) {
483 if (xy[atom0->num_point].x >= (int) (cryst->a / 2.0))
484 xtrans = (int) (-cryst->a / 2.0);
486 xtrans = (int) (cryst->a / 2.0);
487 if (xy[atom0->num_point].y >= (int) (cryst->b / 2.0))
488 ytrans = (int) (-cryst->b / 2.0);
490 ytrans = (int) (cryst->b / 2.0);
491 for (k = 0; k <= atom0->num_point; k++) {
492 xy[k].x = xy[k].x + xtrans;
493 xy[k].y = xy[k].y + ytrans;
495 for (l = 0; l < cryst->nx; l++) {
496 for (m = 0; m < cryst->ny; m++) {
498 for (k = 0; k <= atom0->num_point; k++) {
499 xy_1[k].x = xy[k].x + l * cryst->a;
500 xy_1[k].y = xy[k].y + m * cryst->b;
502 trans_coor_back(xy_1, new_xy, atom0->num_point,
503 cryst->gamma, cryst->offset_w, cryst->offset_h);
504 XFillPolygon(display, window, cryst->gc,
506 atom0->num_point, Convex,
510 if (centro[cryst->planegroup] == True) {
513 for (k = 0; k <= atom0->num_point; k++) {
514 xy1[k].x = cryst->a - xy[k].x;
515 xy1[k].y = cryst->b - xy[k].y;
517 for (l = 0; l < cryst->nx; l++) {
518 for (m = 0; m < cryst->ny; m++) {
520 for (k = 0; k <= atom0->num_point; k++) {
521 xy_1[k].x = xy1[k].x + l * cryst->a;
522 xy_1[k].y = xy1[k].y + m * cryst->b;
524 trans_coor_back(xy_1, new_xy, atom0->num_point,
525 cryst->gamma, cryst->offset_w, cryst->offset_h);
526 XFillPolygon(display, window,
528 new_xy, atom0->num_point,
529 Convex, CoordModeOrigin);
538 draw_crystal(ModeInfo * mi)
540 Display *display = MI_DISPLAY(mi);
541 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
544 if (cryst->no_colors) {
549 cryst->painted = True;
550 MI_IS_DRAWN(mi) = True;
551 XSetFunction(display, cryst->gc, GXxor);
554 if (cryst->cycle_p) {
555 rotate_colors(display, cryst->cmap, cryst->colors, cryst->ncolors,
557 if (!(LRAND() % 1000))
558 cryst->direction = -cryst->direction;
560 for (i = 0; i < cryst->num_atom; i++) {
563 atom0 = &cryst->atom[i];
564 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
565 crystal_drawatom(mi, atom0);
566 atom0->velocity[0] += NRAND(3) - 1;
567 atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
568 atom0->velocity[1] += NRAND(3) - 1;
569 atom0->velocity[1] = MAX(-20, MIN(20, atom0->velocity[1]));
570 atom0->x0 += atom0->velocity[0];
571 /*if (cryst->gamma == 90.0) { */
573 atom0->x0 += cryst->a;
574 else if (atom0->x0 >= cryst->a)
575 atom0->x0 -= cryst->a;
576 atom0->y0 += atom0->velocity[1];
578 atom0->y0 += cryst->b;
579 else if (atom0->y0 >= cryst->b)
580 atom0->y0 -= cryst->b;
582 atom0->velocity_a += ((float) NRAND(1001) - 500.0) / 2000.0;
583 atom0->angle += atom0->velocity_a;
584 crystal_setupatom(atom0, cryst->gamma);
585 crystal_drawatom(mi, atom0);
587 XSetFunction(display, cryst->gc, GXcopy);
591 refresh_crystal(ModeInfo * mi)
593 Display *display = MI_DISPLAY(mi);
594 Window window = MI_WINDOW(mi);
595 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
601 XSetFunction(display, cryst->gc, GXxor);
603 if (cryst->unit_cell) {
604 if (MI_NPIXELS(mi) > 2)
605 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
607 XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
608 if (cryst->grid_cell) {
611 XDrawLine(display, window, cryst->gc, cryst->offset_w,
612 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
614 XDrawLine(display, window, cryst->gc, cryst->offset_w,
615 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
616 sin((cryst->gamma - 90) * PI_RAD)),
617 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
619 for (iny = 1; iny <= cryst->ny; iny++) {
620 XDrawLine(display, window, cryst->gc,
621 (int) (cryst->offset_w +
622 inx * cryst->a - (int) (iny * cryst->b *
623 sin((cryst->gamma - 90) * PI_RAD))),
624 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
625 PI_RAD)) + cryst->offset_h,
626 (int) (cryst->offset_w - iny * cryst->b *
627 sin((cryst->gamma - 90) * PI_RAD)),
628 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
632 for (inx = 1; inx <= cryst->nx; inx++) {
633 XDrawLine(display, window, cryst->gc,
634 (int) (cryst->offset_w +
635 inx * cryst->a - (int) (iny * cryst->b *
636 sin((cryst->gamma - 90) * PI_RAD))),
637 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
638 cryst->offset_w + inx * cryst->a, cryst->offset_h);
643 inx = NRAND(cryst->nx);
644 iny = NRAND(cryst->ny);
645 XDrawLine(display, window, cryst->gc,
646 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
647 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
648 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
649 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
650 XDrawLine(display, window, cryst->gc,
651 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
652 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
653 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
654 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
655 XDrawLine(display, window, cryst->gc,
656 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
657 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
658 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
659 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
660 XDrawLine(display, window, cryst->gc,
661 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
662 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
663 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
664 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
667 for (i = 0; i < cryst->num_atom; i++) {
670 atom0 = &cryst->atom[i];
671 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
672 crystal_drawatom(mi, atom0);
674 XSetFunction(display, cryst->gc, GXcopy);
678 release_crystal(ModeInfo * mi)
680 Display *display = MI_DISPLAY(mi);
682 if (crystals != NULL) {
685 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
686 crystalstruct *cryst = &crystals[screen];
688 MI_WHITE_PIXEL(mi) = cryst->whitepixel;
689 MI_BLACK_PIXEL(mi) = cryst->blackpixel;
691 MI_FG_PIXEL(mi) = cryst->fg;
692 MI_BG_PIXEL(mi) = cryst->bg;
694 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
695 free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
697 (void) free((void *) cryst->colors);
698 XFreeColormap(display, cryst->cmap);
699 if (cryst->gc != NULL)
700 XFreeGC(display, cryst->gc);
701 if (cryst->atom != NULL)
702 (void) free((void *) cryst->atom);
704 (void) free((void *) crystals);
710 init_crystal(ModeInfo * mi)
712 Display *display = MI_DISPLAY(mi);
713 Window window = MI_WINDOW(mi);
714 crystalstruct *cryst;
715 int i, max_atoms, size_atom, neqv;
721 if (crystals == NULL) {
722 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
723 sizeof (crystalstruct))) == NULL)
726 cryst = &crystals[MI_SCREEN(mi)];
732 extern char *background;
733 extern char *foreground;
735 cryst->fg = MI_FG_PIXEL(mi);
736 cryst->bg = MI_BG_PIXEL(mi);
738 cryst->blackpixel = MI_BLACK_PIXEL(mi);
739 cryst->whitepixel = MI_WHITE_PIXEL(mi);
742 cryst->cmap = mi->xgwa.colormap;
743 #else /* !STANDALONE */
744 cryst->cmap = XCreateColormap(display, window,
745 MI_VISUAL(mi), AllocNone);
746 XSetWindowColormap(display, window, cryst->cmap);
748 (void) XParseColor(display, cryst->cmap, "black", &color);
749 (void) XAllocColor(display, cryst->cmap, &color);
750 MI_BLACK_PIXEL(mi) = color.pixel;
751 (void) XParseColor(display, cryst->cmap, "white", &color);
752 (void) XAllocColor(display, cryst->cmap, &color);
753 MI_WHITE_PIXEL(mi) = color.pixel;
755 (void) XParseColor(display, cryst->cmap, background, &color);
756 (void) XAllocColor(display, cryst->cmap, &color);
757 MI_BG_PIXEL(mi) = color.pixel;
758 (void) XParseColor(display, cryst->cmap, foreground, &color);
759 (void) XAllocColor(display, cryst->cmap, &color);
760 MI_FG_PIXEL(mi) = color.pixel;
761 #endif /* !STANDALONE */
765 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
766 (unsigned long) 0, (XGCValues *) NULL)) == None)
771 cryst->painted = False;
772 XSetFunction(display, cryst->gc, GXxor);
775 /*Set up crystal data */
776 cryst->direction = (LRAND() & 1) ? 1 : -1;
777 if (MI_IS_FULLRANDOM(mi)) {
779 cryst->unit_cell = True;
781 cryst->unit_cell = False;
783 cryst->unit_cell = unit_cell;
784 if (cryst->unit_cell) {
785 if (MI_IS_FULLRANDOM(mi)) {
787 cryst->grid_cell = True;
789 cryst->grid_cell = False;
791 cryst->grid_cell = grid_cell;
793 cryst->win_width = MI_WIDTH(mi);
794 cryst->win_height = MI_HEIGHT(mi);
795 cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
796 cell_min = min(cell_min, cryst->win_height / 2 + 1);
797 cryst->planegroup = NRAND(17);
798 if (MI_IS_VERBOSE(mi))
799 (void) fprintf(stdout, "Selected plane group no %d\n",
800 cryst->planegroup + 1);
801 if (cryst->planegroup > 11)
802 cryst->gamma = 120.0;
803 else if (cryst->planegroup < 2)
804 cryst->gamma = 60.0 + NRAND(60);
807 neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
808 if (centro[cryst->planegroup] == True)
810 if (primitive[cryst->planegroup] == False)
817 cryst->nx = NRAND(-nx) + 1;
820 if (cryst->planegroup > 8)
821 cryst->ny = cryst->nx;
825 cryst->ny = NRAND(-ny) + 1;
828 neqv = neqv * cryst->nx * cryst->ny;
830 cryst->num_atom = MI_COUNT(mi);
831 max_atoms = MI_COUNT(mi);
832 if (cryst->num_atom == 0) {
833 cryst->num_atom = DEF_NUM_ATOM;
834 max_atoms = DEF_NUM_ATOM;
835 } else if (cryst->num_atom < 0) {
836 max_atoms = -cryst->num_atom;
837 cryst->num_atom = NRAND(-cryst->num_atom) + 1;
840 cryst->num_atom = cryst->num_atom / neqv + 1;
842 if (cryst->atom == NULL)
843 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
847 if (cryst->planegroup < 13) {
851 if (cryst->planegroup < 10) {
852 cryst->b = cryst->win_height;
853 cryst->a = cryst->win_width;
855 cryst->b = min(cryst->win_height, cryst->win_width);
859 cryst->gamma = 120.0;
860 cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
862 cryst->offset_h = (int) (cryst->b * 0.25 *
863 cos((cryst->gamma - 90) * PI_RAD));
864 cryst->offset_w = (int) (cryst->b * 0.5);
867 cryst->offset_w = -1;
868 while (cryst->offset_w < 4 || (int) (cryst->offset_w - cryst->b *
869 sin((cryst->gamma - 90) * PI_RAD)) < 4) {
870 cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
871 PI_RAD))) - cell_min) + cell_min;
872 if (cryst->planegroup > 8)
875 cryst->a = NRAND(cryst->win_width - cell_min) + cell_min;
876 cryst->offset_w = (int) ((cryst->win_width - (cryst->a - cryst->b *
877 sin((cryst->gamma - 90) *
880 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
881 cryst->gamma - 90) * PI_RAD)) / 2.0);
883 if (cryst->offset_h > 0)
884 cryst->offset_h = NRAND(2 * cryst->offset_h);
885 cryst->offset_w = (int) (cryst->win_width - cryst->a -
887 fabs(sin((cryst->gamma - 90) * PI_RAD)));
888 if (cryst->gamma > 90.0) {
889 if (cryst->offset_w > 0)
890 cryst->offset_w = NRAND(cryst->offset_w) +
891 (int) (cryst->b * sin((cryst->gamma - 90) * PI_RAD));
893 cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
895 } else if (cryst->offset_w > 0)
896 cryst->offset_w = NRAND(cryst->offset_w);
902 size_atom = min((int) ((float) (cryst->a) / 40.) + 1,
903 (int) ((float) (cryst->b) / 40.) + 1);
904 if (MI_SIZE(mi) < size_atom) {
905 if (MI_SIZE(mi) < -size_atom)
906 size_atom = -size_atom;
908 size_atom = MI_SIZE(mi);
910 cryst->a = cryst->a / cryst->nx;
911 cryst->b = cryst->b / cryst->ny;
912 if (cryst->unit_cell) {
913 if (MI_NPIXELS(mi) > 2)
914 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
916 XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
917 if (cryst->grid_cell) {
920 XDrawLine(display, window, cryst->gc, cryst->offset_w,
921 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
923 XDrawLine(display, window, cryst->gc, cryst->offset_w,
924 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
925 sin((cryst->gamma - 90) * PI_RAD)),
926 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
928 for (iny = 1; iny <= cryst->ny; iny++) {
929 XDrawLine(display, window, cryst->gc,
930 (int) (cryst->offset_w +
931 inx * cryst->a - (int) (iny * cryst->b *
932 sin((cryst->gamma - 90) * PI_RAD))),
933 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
934 PI_RAD)) + cryst->offset_h,
935 (int) (cryst->offset_w - iny * cryst->b *
936 sin((cryst->gamma - 90) * PI_RAD)),
937 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
941 for (inx = 1; inx <= cryst->nx; inx++) {
942 XDrawLine(display, window, cryst->gc,
943 (int) (cryst->offset_w +
944 inx * cryst->a - (int) (iny * cryst->b *
945 sin((cryst->gamma - 90) * PI_RAD))),
946 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
947 cryst->offset_w + inx * cryst->a, cryst->offset_h);
952 inx = NRAND(cryst->nx);
953 iny = NRAND(cryst->ny);
954 XDrawLine(display, window, cryst->gc,
955 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
956 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
957 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
958 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
959 XDrawLine(display, window, cryst->gc,
960 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
961 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
962 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
963 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
964 XDrawLine(display, window, cryst->gc,
965 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
966 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
967 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
968 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
969 XDrawLine(display, window, cryst->gc,
970 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
971 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
972 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
973 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
976 /* Set up colour map */
977 if (cryst->colors && cryst->ncolors && !cryst->no_colors)
978 free_colors(display, cryst->cmap, cryst->colors, cryst->ncolors);
980 (void) free((void *) cryst->colors);
983 cryst->ncolors = get_integer_resource("ncolors", "Integer");
985 cryst->ncolors = MI_NCOLORS(mi);
987 if (cryst->ncolors < 2)
989 if (cryst->ncolors <= 2)
990 cryst->mono_p = True;
992 cryst->mono_p = False;
997 cryst->colors = (XColor *) malloc(sizeof (*cryst->colors) * (cryst->ncolors + 1));
999 cryst->cycle_p = has_writable_cells(mi->xgwa.screen, mi->xgwa.visual);
1001 cryst->cycle_p = has_writable_cells(mi);
1003 if (cryst->cycle_p) {
1004 if (MI_IS_FULLRANDOM(mi)) {
1006 cryst->cycle_p = False;
1008 cryst->cycle_p = True;
1010 cryst->cycle_p = cycle_p;
1013 if (!cryst->mono_p) {
1014 if (!(LRAND() % 10))
1015 make_random_colormap(
1017 mi->dpy, mi->xgwa.visual,
1021 cryst->cmap, cryst->colors, &cryst->ncolors,
1022 True, True, &cryst->cycle_p
1027 else if (!(LRAND() % 2))
1028 make_uniform_colormap(
1030 mi->dpy, mi->xgwa.visual,
1034 cryst->cmap, cryst->colors, &cryst->ncolors,
1035 True, &cryst->cycle_p
1041 make_smooth_colormap(
1043 mi->dpy, mi->xgwa.visual,
1047 cryst->cmap, cryst->colors, &cryst->ncolors,
1048 True, &cryst->cycle_p
1054 XInstallColormap(display, cryst->cmap);
1055 if (cryst->ncolors < 2) {
1057 cryst->no_colors = True;
1059 cryst->no_colors = False;
1060 if (cryst->ncolors <= 2)
1061 cryst->mono_p = True;
1064 cryst->cycle_p = False;
1066 for (i = 0; i < cryst->num_atom; i++) {
1069 atom0 = &cryst->atom[i];
1070 if (cryst->ncolors > 2)
1071 atom0->colour = NRAND(cryst->ncolors - 2) + 2;
1073 atom0->colour = 1; /*Xor'red so WHITE may not be appropriate */
1074 XSetForeground(display, cryst->gc, cryst->colors[atom0->colour].pixel);
1075 atom0->x0 = NRAND(cryst->a);
1076 atom0->y0 = NRAND(cryst->b);
1077 atom0->velocity[0] = NRAND(7) - 3;
1078 atom0->velocity[1] = NRAND(7) - 3;
1079 atom0->velocity_a = (NRAND(7) - 3) * PI_RAD;
1080 atom0->angle = NRAND(90) * PI_RAD;
1081 atom0->at_type = NRAND(3);
1083 atom0->size_at = DEF_SIZ_ATOM;
1084 else if (size_atom > 0)
1085 atom0->size_at = size_atom;
1087 atom0->size_at = NRAND(-size_atom) + 1;
1089 if (atom0->at_type == 2)
1090 atom0->num_point = 3;
1092 atom0->num_point = 4;
1093 crystal_setupatom(atom0, cryst->gamma);
1094 crystal_drawatom(mi, atom0);
1096 XSync(display, False);
1097 XSetFunction(display, cryst->gc, GXcopy);