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.07 97/11/24 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 * 24-Feb-98: added option centre which turns on/off forcing the centre of
32 * the screen to be used
33 * added option maxsize which forces the dimensions to be chasen
34 * in such ua way that the largest possible part of the screen is
36 * When only one unit cell is drawn, it is chosen at random
37 * 18-Feb-98: added support for negative numbers with -nx and -ny meaning
38 * "random" choice with geiven maximum
39 * added +/-grid option. If -cell is specified this option
40 * determines if one or all unit cells are drawn.
41 * -batchcount is now a parameter for all the objects on the screen
42 * instead of the number of "unique" objects
43 * The maximum size of the objects now scales with the part
45 * fixed "size" problem. Now very small non-vissable objects
47 * 13-Feb-98: randomized the unit cell size
48 * runtime options -/+cell (turn on/off unit cell drawing)
49 * -nx num (number of translational symmetries in x-direction
50 * -ny num (idem y-direction but ignored for square and
51 * hexagonal space groups
52 * i.e. try xlock -mode crystal -nx 3 -ny 2
53 * Fullrandom overrules the -/+cell option.
54 * 05-Feb-98: Revision + bug repairs
56 * use part of the screen for unit cell
57 * in hexagonal and square groups a&b axis forced to be equal
58 * cell angle for oblique groups randomly chosen between 60 and 120
59 * bugs solved: planegroups with cell angles <> 90.0 now work properly
60 * 19-Sep-97: Added remaining hexagonal groups
65 # define PROGCLASS "Crystal"
66 # define HACK_INIT init_crystal
67 # define HACK_DRAW draw_crystal
68 # define crystal_opts xlockmore_opts
69 # define DEFAULTS "*delay: 60000 \n" \
74 "*fullrandom: True \n" \
76 # include "xlockmore.h" /* in xscreensaver distribution */
77 #else /* STANDALONE */
78 # include "xlock.h" /* in xlockmore distribution */
79 #endif /* STANDALONE */
81 #define DEF_CELL "True" /* Draw unit cell */
82 #define DEF_GRID "False" /* Draw unit all cell if DEF_CELL is True */
83 #define DEF_NX "-3" /* number of unit cells in x-direction */
84 #define DEF_NX1 1 /* number of unit cells in x-direction */
85 #define DEF_NY "-3" /* number of unit cells in y-direction */
86 #define DEF_NY1 1 /* number of unit cells in y-direction */
87 #define DEF_CENTRE "False"
88 #define DEF_MAXSIZE "False"
90 #define min(a,b) ((a) <= (b) ? (a) : (b))
94 static Bool unit_cell, grid_cell, centre, maxsize;
96 static XrmOptionDescRec opts[] =
98 {"-nx", "crystal.nx", XrmoptionSepArg, (caddr_t) NULL},
99 {"-ny", "crystal.ny", XrmoptionSepArg, (caddr_t) NULL},
100 {"-centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "on"},
101 {"+centre", ".crystal.centre", XrmoptionNoArg, (caddr_t) "off"},
102 {"-maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "on"},
103 {"+maxsize", ".crystal.maxsize", XrmoptionNoArg, (caddr_t) "off"},
104 {"-cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "on"},
105 {"+cell", ".crystal.cell", XrmoptionNoArg, (caddr_t) "off"},
106 {"-grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "on"},
107 {"+grid", ".crystal.grid", XrmoptionNoArg, (caddr_t) "off"}
110 static argtype vars[] =
112 {(caddr_t *) & nx, "nx", "nx", DEF_NX, t_Int},
113 {(caddr_t *) & ny, "ny", "ny", DEF_NY, t_Int},
114 {(caddr_t *) & centre, "centre", "Centre", DEF_CENTRE, t_Bool},
115 {(caddr_t *) & maxsize, "maxsize", "Maxsize", DEF_MAXSIZE, t_Bool},
116 {(caddr_t *) & unit_cell, "cell", "Cell", DEF_CELL, t_Bool},
117 {(caddr_t *) & grid_cell, "grid", "Grid", DEF_GRID, t_Bool}
119 static OptionStruct desc[] =
121 {"-nx num", "Number of unit cells in x-direction"},
122 {"-ny num", "Number of unit cells in y-direction"},
123 {"-/+centre", "turn on/off cenetering on screen"},
124 {"-/+maxsize", "turn on/off use of maximum part of screen"},
125 {"-/+cell", "turn on/off drawing of unit cell"},
126 {"-/+grid", "turn on/off drawing of grid of unit cells (if -cell is on)"}
129 ModeSpecOpt crystal_opts =
130 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
133 ModStruct crystal_description =
134 {"crystal", "init_crystal", "draw_crystal", "release_crystal",
135 "refresh_crystal", "init_crystal", NULL, &crystal_opts,
136 60000, -40, 200, -15, 64, 1.0, "",
137 "Shows polygons in 2D plane groups", 0, NULL};
141 #define DEF_NUM_ATOM 10
143 #define DEF_SIZ_ATOM 10
145 #define PI_RAD (M_PI / 180.0)
147 static Bool centro[17] =
168 static Bool primitive[17] =
189 static short numops[34] =
210 static short operation[114] =
234 unsigned long colour;
235 int x0, y0, velocity[2];
236 float angle, velocity_a;
237 int num_point, at_type, size_at;
243 int win_width, win_height, num_atom;
244 int planegroup, a, b, offset_w, offset_h, nx, ny;
248 Bool unit_cell, grid_cell;
251 static crystalstruct *crystals = NULL;
254 trans_coor(XPoint * xyp, XPoint * new_xyp, int num_points,
259 for (i = 0; i <= num_points; i++) {
260 new_xyp[i].x = xyp[i].x +
261 (int) (xyp[i].y * sin((gamma - 90.0) * PI_RAD));
262 new_xyp[i].y = (int) (xyp[i].y / cos((gamma - 90.0) * PI_RAD));
267 trans_coor_back(XPoint * xyp, XPoint * new_xyp,
268 int num_points, float gamma, int offset_w, int offset_h)
272 for (i = 0; i <= num_points; i++) {
273 new_xyp[i].y = (int) (xyp[i].y * cos((gamma - 90) * PI_RAD)) +
275 new_xyp[i].x = xyp[i].x - (int) (xyp[i].y * sin((gamma - 90.0)
276 * PI_RAD)) + offset_w;
281 crystal_setupatom(crystalatom * atom0, float gamma)
286 y0 = (int) (atom0->y0 * cos((gamma - 90) * PI_RAD));
287 x0 = atom0->x0 - (int) (atom0->y0 * sin((gamma - 90.0) * PI_RAD));
288 switch (atom0->at_type) {
289 case 0: /* rectangles */
290 xy[0].x = x0 + (int) (2 * atom0->size_at *
292 (int) (atom0->size_at * sin(atom0->angle));
293 xy[0].y = y0 + (int) (atom0->size_at *
295 (int) (2 * atom0->size_at * sin(atom0->angle));
296 xy[1].x = x0 + (int) (2 * atom0->size_at *
298 (int) (atom0->size_at * sin(atom0->angle));
299 xy[1].y = y0 - (int) (atom0->size_at *
301 (int) (2 * atom0->size_at * sin(atom0->angle));
302 xy[2].x = x0 - (int) (2 * atom0->size_at *
304 (int) (atom0->size_at * sin(atom0->angle));
305 xy[2].y = y0 - (int) (atom0->size_at *
307 (int) (2 * atom0->size_at * sin(atom0->angle));
308 xy[3].x = x0 - (int) (2 * atom0->size_at *
310 (int) (atom0->size_at * sin(atom0->angle));
311 xy[3].y = y0 + (int) (atom0->size_at *
313 (int) (2 * atom0->size_at *
317 trans_coor(xy, atom0->xy, 4, gamma);
319 case 1: /* squares */
320 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
322 (int) (1.5 * atom0->size_at *
324 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
326 (int) (1.5 * atom0->size_at *
328 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
330 (int) (1.5 * atom0->size_at *
332 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
334 (int) (1.5 * atom0->size_at *
336 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
338 (int) (1.5 * atom0->size_at *
340 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
342 (int) (1.5 * atom0->size_at *
344 xy[3].x = x0 - (int) (1.5 * atom0->size_at *
346 (int) (1.5 * atom0->size_at *
348 xy[3].y = y0 + (int) (1.5 * atom0->size_at *
350 (int) (1.5 * atom0->size_at *
354 trans_coor(xy, atom0->xy, 4, gamma);
356 case 2: /* triangles */
357 xy[0].x = x0 + (int) (1.5 * atom0->size_at *
359 xy[0].y = y0 + (int) (1.5 * atom0->size_at *
361 xy[1].x = x0 + (int) (1.5 * atom0->size_at *
363 (int) (1.5 * atom0->size_at *
365 xy[1].y = y0 - (int) (1.5 * atom0->size_at *
367 (int) (1.5 * atom0->size_at *
369 xy[2].x = x0 - (int) (1.5 * atom0->size_at *
371 (int) (1.5 * atom0->size_at *
373 xy[2].y = y0 - (int) (1.5 * atom0->size_at *
375 (int) (1.5 * atom0->size_at *
379 trans_coor(xy, atom0->xy, 3, gamma);
385 crystal_drawatom(ModeInfo * mi, crystalatom * atom0)
387 crystalstruct *cryst;
388 Display *display = MI_DISPLAY(mi);
389 Window window = MI_WINDOW(mi);
392 cryst = &crystals[MI_SCREEN(mi)];
393 for (j = numops[2 * cryst->planegroup + 1];
394 j < numops[2 * cryst->planegroup]; j++) {
395 XPoint xy[5], new_xy[5];
399 xtrans = operation[j * 6] * atom0->x0 + operation[j * 6 + 1] *
400 atom0->y0 + (int) (operation[j * 6 + 4] * cryst->a /
402 ytrans = operation[j * 6 + 2] * atom0->x0 + operation[j * 6 +
403 3] * atom0->y0 + (int) (operation[j * 6 + 5] *
406 if (xtrans < -cryst->a)
407 xtrans = 2 * cryst->a;
410 } else if (xtrans >= cryst->a)
416 else if (ytrans >= cryst->b)
420 for (k = 0; k < atom0->num_point; k++) {
421 xy[k].x = operation[j * 6] * atom0->xy[k].x +
422 operation[j * 6 + 1] *
423 atom0->xy[k].y + (int) (operation[j * 6 + 4] *
426 xy[k].y = operation[j * 6 + 2] * atom0->xy[k].x +
427 operation[j * 6 + 3] *
428 atom0->xy[k].y + (int) (operation[j * 6 + 5] *
432 xy[atom0->num_point].x = xy[0].x;
433 xy[atom0->num_point].y = xy[0].y;
434 for (l = 0; l < cryst->nx; l++) {
435 for (m = 0; m < cryst->ny; m++) {
437 for (k = 0; k <= atom0->num_point; k++) {
438 xy_1[k].x = xy[k].x + l * cryst->a;
439 xy_1[k].y = xy[k].y + m * cryst->b;
441 trans_coor_back(xy_1, new_xy, atom0->num_point,
442 cryst->gamma, cryst->offset_w, cryst->offset_h);
443 XFillPolygon(display, window, cryst->gc, new_xy,
444 atom0->num_point, Convex, CoordModeOrigin);
447 if (centro[cryst->planegroup] == True) {
448 for (k = 0; k <= atom0->num_point; k++) {
449 xy[k].x = cryst->a - xy[k].x;
450 xy[k].y = cryst->b - xy[k].y;
452 for (l = 0; l < cryst->nx; l++) {
453 for (m = 0; m < cryst->ny; m++) {
455 for (k = 0; k <= atom0->num_point; k++) {
456 xy_1[k].x = xy[k].x + l * cryst->a;
457 xy_1[k].y = xy[k].y + m * cryst->b;
459 trans_coor_back(xy_1, new_xy, atom0->num_point,
460 cryst->gamma, cryst->offset_w, cryst->offset_h);
461 XFillPolygon(display, window, cryst->gc,
463 atom0->num_point, Convex,
468 if (primitive[cryst->planegroup] == False) {
469 if (xy[atom0->num_point].x >= (int) (cryst->a / 2.0))
470 xtrans = (int) (-cryst->a / 2.0);
472 xtrans = (int) (cryst->a / 2.0);
473 if (xy[atom0->num_point].y >= (int) (cryst->b / 2.0))
474 ytrans = (int) (-cryst->b / 2.0);
476 ytrans = (int) (cryst->b / 2.0);
477 for (k = 0; k <= atom0->num_point; k++) {
478 xy[k].x = xy[k].x + xtrans;
479 xy[k].y = xy[k].y + ytrans;
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,
489 cryst->gamma, cryst->offset_w, cryst->offset_h);
490 XFillPolygon(display, window, cryst->gc,
492 atom0->num_point, Convex,
496 if (centro[cryst->planegroup] == True) {
499 for (k = 0; k <= atom0->num_point; k++) {
500 xy1[k].x = cryst->a - xy[k].x;
501 xy1[k].y = cryst->b - xy[k].y;
503 for (l = 0; l < cryst->nx; l++) {
504 for (m = 0; m < cryst->ny; m++) {
506 for (k = 0; k <= atom0->num_point; k++) {
507 xy_1[k].x = xy1[k].x + l * cryst->a;
508 xy_1[k].y = xy1[k].y + m * cryst->b;
510 trans_coor_back(xy_1, new_xy, atom0->num_point,
511 cryst->gamma, cryst->offset_w, cryst->offset_h);
512 XFillPolygon(display, window,
514 new_xy, atom0->num_point,
515 Convex, CoordModeOrigin);
524 draw_crystal(ModeInfo * mi)
526 Display *display = MI_DISPLAY(mi);
527 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
530 cryst->painted = True;
531 XSetFunction(display, cryst->gc, GXxor);
532 for (i = 0; i < cryst->num_atom; i++) {
535 atom0 = &cryst->atom[i];
536 XSetForeground(display, cryst->gc, atom0->colour);
537 crystal_drawatom(mi, atom0);
538 atom0->velocity[0] += NRAND(3) - 1;
539 atom0->velocity[0] = MAX(-20, MIN(20, atom0->velocity[0]));
540 atom0->velocity[1] += NRAND(3) - 1;
541 atom0->velocity[1] = MAX(-20, MIN(20, atom0->velocity[1]));
542 atom0->x0 += atom0->velocity[0];
543 /*if (cryst->gamma == 90.0) { */
545 atom0->x0 += cryst->a;
546 else if (atom0->x0 >= cryst->a)
547 atom0->x0 -= cryst->a;
548 atom0->y0 += atom0->velocity[1];
550 atom0->y0 += cryst->b;
551 else if (atom0->y0 >= cryst->b)
552 atom0->y0 -= cryst->b;
554 atom0->velocity_a += ((float) NRAND(1001) - 500.0) / 2000.0;
555 atom0->angle += atom0->velocity_a;
556 crystal_setupatom(atom0, cryst->gamma);
557 crystal_drawatom(mi, atom0);
559 XSetFunction(display, cryst->gc, GXcopy);
563 refresh_crystal(ModeInfo * mi)
565 Display *display = MI_DISPLAY(mi);
566 Window window = MI_WINDOW(mi);
567 crystalstruct *cryst = &crystals[MI_SCREEN(mi)];
573 XSetFunction(display, cryst->gc, GXxor);
575 if (cryst->unit_cell) {
576 if (MI_NPIXELS(mi) > 2)
577 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
579 XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
580 if (cryst->grid_cell) {
583 XDrawLine(display, window, cryst->gc, cryst->offset_w,
584 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
586 XDrawLine(display, window, cryst->gc, cryst->offset_w,
587 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
588 sin((cryst->gamma - 90) * PI_RAD)),
589 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
591 for (iny = 1; iny <= cryst->ny; iny++) {
592 XDrawLine(display, window, cryst->gc,
593 (int) (cryst->offset_w +
594 inx * cryst->a - (int) (iny * cryst->b *
595 sin((cryst->gamma - 90) * PI_RAD))),
596 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
597 PI_RAD)) + cryst->offset_h,
598 (int) (cryst->offset_w - iny * cryst->b *
599 sin((cryst->gamma - 90) * PI_RAD)),
600 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
604 for (inx = 1; inx <= cryst->nx; inx++) {
605 XDrawLine(display, window, cryst->gc,
606 (int) (cryst->offset_w +
607 inx * cryst->a - (int) (iny * cryst->b *
608 sin((cryst->gamma - 90) * PI_RAD))),
609 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
610 cryst->offset_w + inx * cryst->a, cryst->offset_h);
615 inx = NRAND(cryst->nx);
616 iny = NRAND(cryst->ny);
617 XDrawLine(display, window, cryst->gc,
618 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
619 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
620 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
621 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
622 XDrawLine(display, window, cryst->gc,
623 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
624 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
625 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
626 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
627 XDrawLine(display, window, cryst->gc,
628 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
629 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
630 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
631 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
632 XDrawLine(display, window, cryst->gc,
633 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
634 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
635 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
636 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
639 for (i = 0; i < cryst->num_atom; i++) {
642 atom0 = &cryst->atom[i];
643 XSetForeground(display, cryst->gc, atom0->colour);
644 crystal_drawatom(mi, atom0);
646 XSetFunction(display, cryst->gc, GXcopy);
650 release_crystal(ModeInfo * mi)
652 Display *display = MI_DISPLAY(mi);
654 if (crystals != NULL) {
657 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
658 crystalstruct *cryst = &crystals[screen];
660 if (cryst->gc != NULL)
661 XFreeGC(display, cryst->gc);
662 if (cryst->atom != NULL)
663 (void) free((void *) cryst->atom);
665 (void) free((void *) crystals);
671 init_crystal(ModeInfo * mi)
673 Display *display = MI_DISPLAY(mi);
674 Window window = MI_WINDOW(mi);
675 crystalstruct *cryst;
676 int i, max_atoms, size_atom, neqv;
682 if (crystals == NULL) {
683 if ((crystals = (crystalstruct *) calloc(MI_NUM_SCREENS(mi),
684 sizeof (crystalstruct))) == NULL)
687 cryst = &crystals[MI_SCREEN(mi)];
690 if ((cryst->gc = XCreateGC(display, MI_WINDOW(mi),
691 (unsigned long) 0, (XGCValues *) NULL)) == None)
696 cryst->painted = False;
697 XSetFunction(display, cryst->gc, GXxor);
699 /*Set up crystal data */
700 if (MI_IS_FULLRANDOM(mi)) {
702 cryst->unit_cell = True;
704 cryst->unit_cell = False;
706 cryst->unit_cell = unit_cell;
707 if (cryst->unit_cell) {
708 if (MI_IS_FULLRANDOM(mi)) {
710 cryst->grid_cell = True;
712 cryst->grid_cell = False;
714 cryst->grid_cell = grid_cell;
716 cryst->win_width = MI_WIDTH(mi);
717 cryst->win_height = MI_HEIGHT(mi);
718 cell_min = min(cryst->win_width / 2 + 1, MIN_CELL);
719 cell_min = min(cell_min, cryst->win_height / 2 + 1);
720 cryst->planegroup = NRAND(17);
721 if (MI_IS_VERBOSE(mi))
722 (void) fprintf(stdout, "Selected plane group no %d\n",
723 cryst->planegroup + 1);
724 if (cryst->planegroup > 11)
725 cryst->gamma = 120.0;
726 else if (cryst->planegroup < 2)
727 cryst->gamma = 60.0 + NRAND(60);
730 neqv = numops[2 * cryst->planegroup] - numops[2 * cryst->planegroup + 1];
731 if (centro[cryst->planegroup] == True)
733 if (primitive[cryst->planegroup] == False)
740 cryst->nx = NRAND(-nx) + 1;
743 if (cryst->planegroup > 8)
744 cryst->ny = cryst->nx;
748 cryst->ny = NRAND(-ny) + 1;
751 neqv = neqv * cryst->nx * cryst->ny;
753 cryst->num_atom = MI_COUNT(mi);
754 max_atoms = MI_COUNT(mi);
755 if (cryst->num_atom == 0) {
756 cryst->num_atom = DEF_NUM_ATOM;
757 max_atoms = DEF_NUM_ATOM;
758 } else if (cryst->num_atom < 0) {
759 max_atoms = -cryst->num_atom;
760 cryst->num_atom = NRAND(-cryst->num_atom) + 1;
763 cryst->num_atom = cryst->num_atom / neqv + 1;
765 if (cryst->atom == NULL)
766 cryst->atom = (crystalatom *) calloc(max_atoms, sizeof (
770 if (cryst->planegroup < 13) {
774 if (cryst->planegroup < 10) {
775 cryst->b = cryst->win_height;
776 cryst->a = cryst->win_width;
778 cryst->b = min(cryst->win_height, cryst->win_width);
782 cryst->gamma = 120.0;
783 cryst->a = (int) (cryst->win_width * 2.0 / 3.0);
785 cryst->offset_h = (int) (cryst->b * 0.25 *
786 cos((cryst->gamma - 90) * PI_RAD));
787 cryst->offset_w = (int) (cryst->b * 0.5);
790 cryst->offset_w = -1;
791 while (cryst->offset_w < 4 || (int) (cryst->offset_w - cryst->b *
792 sin((cryst->gamma - 90) * PI_RAD)) < 4) {
793 cryst->b = NRAND((int) (cryst->win_height / (cos((cryst->gamma - 90) *
794 PI_RAD))) - cell_min) + cell_min;
795 if (cryst->planegroup > 8)
798 cryst->a = NRAND(cryst->win_width - cell_min) + cell_min;
799 cryst->offset_w = (int) ((cryst->win_width - (cryst->a - cryst->b *
800 sin((cryst->gamma - 90) *
803 cryst->offset_h = (int) ((cryst->win_height - cryst->b * cos((
804 cryst->gamma - 90) * PI_RAD)) / 2.0);
806 if (cryst->offset_h > 0)
807 cryst->offset_h = NRAND(2 * cryst->offset_h);
808 cryst->offset_w = (int) (cryst->win_width - cryst->a -
810 fabs(sin((cryst->gamma - 90) * PI_RAD)));
811 if (cryst->gamma > 90.0) {
812 if (cryst->offset_w > 0)
813 cryst->offset_w = NRAND(cryst->offset_w) +
814 cryst->b * sin((cryst->gamma - 90) * PI_RAD);
816 cryst->offset_w = (int) (cryst->b * sin((cryst->gamma - 90) *
818 } else if (cryst->offset_w > 0)
819 cryst->offset_w = NRAND(cryst->offset_w);
825 size_atom = min((int) ((float) (cryst->a) / 40.) + 1,
826 (int) ((float) (cryst->b) / 40.) + 1);
827 if (MI_SIZE(mi) < size_atom) {
828 if (MI_SIZE(mi) < -size_atom)
829 size_atom = -size_atom;
831 size_atom = MI_SIZE(mi);
833 cryst->a = cryst->a / cryst->nx;
834 cryst->b = cryst->b / cryst->ny;
835 if (cryst->unit_cell) {
836 if (MI_NPIXELS(mi) > 2)
837 XSetForeground(display, cryst->gc, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
839 XSetForeground(display, cryst->gc, MI_BLACK_PIXEL(mi));
840 if (cryst->grid_cell) {
843 XDrawLine(display, window, cryst->gc, cryst->offset_w,
844 cryst->offset_h, cryst->offset_w + cryst->nx * cryst->a,
846 XDrawLine(display, window, cryst->gc, cryst->offset_w,
847 cryst->offset_h, (int) (cryst->offset_w - cryst->ny * cryst->b *
848 sin((cryst->gamma - 90) * PI_RAD)),
849 (int) (cryst->ny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
851 for (iny = 1; iny <= cryst->ny; iny++) {
852 XDrawLine(display, window, cryst->gc,
853 (int) (cryst->offset_w +
854 inx * cryst->a - (int) (iny * cryst->b *
855 sin((cryst->gamma - 90) * PI_RAD))),
856 (int) (iny * cryst->b * cos((cryst->gamma - 90) *
857 PI_RAD)) + cryst->offset_h,
858 (int) (cryst->offset_w - iny * cryst->b *
859 sin((cryst->gamma - 90) * PI_RAD)),
860 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) +
864 for (inx = 1; inx <= cryst->nx; inx++) {
865 XDrawLine(display, window, cryst->gc,
866 (int) (cryst->offset_w +
867 inx * cryst->a - (int) (iny * cryst->b *
868 sin((cryst->gamma - 90) * PI_RAD))),
869 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
870 cryst->offset_w + inx * cryst->a, cryst->offset_h);
875 inx = NRAND(cryst->nx);
876 iny = NRAND(cryst->ny);
877 XDrawLine(display, window, cryst->gc,
878 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
879 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
880 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
881 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
882 XDrawLine(display, window, cryst->gc,
883 cryst->offset_w + inx * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
884 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
885 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
886 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
887 XDrawLine(display, window, cryst->gc,
888 cryst->offset_w + (inx + 1) * cryst->a - (int) (iny * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
889 (int) (iny * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
890 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
891 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
892 XDrawLine(display, window, cryst->gc,
893 cryst->offset_w + inx * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
894 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h,
895 cryst->offset_w + (inx + 1) * cryst->a - (int) ((iny + 1) * cryst->b * sin((cryst->gamma - 90) * PI_RAD)),
896 (int) ((iny + 1) * cryst->b * cos((cryst->gamma - 90) * PI_RAD)) + cryst->offset_h);
899 for (i = 0; i < cryst->num_atom; i++) {
902 atom0 = &cryst->atom[i];
903 if (MI_NPIXELS(mi) > 2)
904 atom0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
906 atom0->colour = 1; /*Xor'red so WHITE may not be appropriate */
907 XSetForeground(display, cryst->gc, atom0->colour);
908 atom0->x0 = NRAND(cryst->a);
909 atom0->y0 = NRAND(cryst->b);
910 atom0->velocity[0] = NRAND(7) - 3;
911 atom0->velocity[1] = NRAND(7) - 3;
912 atom0->velocity_a = (NRAND(7) - 3) * PI_RAD;
913 atom0->angle = NRAND(90) * PI_RAD;
914 atom0->at_type = NRAND(3);
916 atom0->size_at = DEF_SIZ_ATOM;
917 else if (size_atom > 0)
918 atom0->size_at = size_atom;
920 atom0->size_at = NRAND(-size_atom) + 1;
922 if (atom0->at_type == 2)
923 atom0->num_point = 3;
925 atom0->num_point = 4;
926 crystal_setupatom(atom0, cryst->gamma);
927 crystal_drawatom(mi, atom0);
929 XSetFunction(display, cryst->gc, GXcopy);