/* sulfate.c 1.1 */ /* Copyright 1992, 1993 O'Reilly and Associates, Inc. Permission to use, copy, and modify this program is hereby granted, as long as this copyright notice appears in each copy of the program source code. */ #include "book_utils.h" #define DEG_TO_RAD (M_PI/180) /* Atom and ion dimensions, all in Angstroms */ #define S_RADIUS 1.04 #define O_RADIUS 0.66 #define SO_BOND_LENGTH 1.44 #define SO_LENGTH (S_RADIUS + SO_BOND_LENGTH + O_RADIUS) /* The structure id. */ static PEXStructure sulfate; /* The atom locations are in spherical coordinates. */ typedef struct { double r, t, p; /* radius, theta, phi */ } Sphere_point; static Sphere_point pos[] = { {SO_LENGTH, 0, 0}, {SO_LENGTH, 0, (109 * DEG_TO_RAD)}, {SO_LENGTH, (120 * DEG_TO_RAD), (109 * DEG_TO_RAD)}, {SO_LENGTH, (240 * DEG_TO_RAD), (109 * DEG_TO_RAD)} }; void create_structure( dpy ) Display *dpy; { PEXListOfCoord sulfur, oxygen; PEXCoord bond_points[2]; PEXColor color; PEXMatrix translate, scale, rotate, global; PEXVector tr, sc; int i; /* Build the spheres for the sulfur and oxygen atoms. */ ora_build_sphere( S_RADIUS, &sulfur ); ora_build_sphere( O_RADIUS, &oxygen ); /* Create the structure. */ sulfate = PEXCreateStructure( dpy ); /* Compute the global scaling transform. */ sc.x = sc.y = sc.z = 1 / (3 * SO_LENGTH); PEXScale( &sc, scale ); /* Compute the global translation transform. */ tr.x = tr.y = tr.z = 0.5; PEXTranslate( &tr, translate ); /* Compose them and create the Set Global Transform. */ PEXMatrixMult( translate, scale, global ); /* g = t * s */ PEXSetGlobalTransform( dpy, sulfate, PEXOCStore, global ); /* Create the yellow sulfur atom. */ SET_COLOR( 1, 1, 0, color ); PEXSetLineColor( dpy, sulfate, PEXOCStore, PEXColorTypeRGB, &color ); PEXPolyline( dpy, sulfate, PEXOCStore, sulfur.count, sulfur.points ); /* Create the cyan oxygen atoms and position them with local * modeling transforms. */ SET_COLOR( 0, 1, 1, color ); PEXSetLineColor( dpy, sulfate, PEXOCStore, PEXColorTypeRGB, &color ); for ( i = 0; i < 4; i++ ) { /* Convert each position to Cartesion coordinates. */ tr.x = pos[i].r * sin( pos[i].t ) * sin( pos[i].p ); tr.y = pos[i].r * cos( pos[i].p ); tr.z = pos[i].r * cos( pos[i].t ) * sin( pos[i].p ); /* Build the matrix and set the transform. */ PEXTranslate( &tr, translate ); PEXSetLocalTransform( dpy, sulfate, PEXOCStore, PEXReplace, translate ); PEXPolyline( dpy, sulfate, PEXOCStore, oxygen.count, oxygen.points ); } /* Build the bonds, which are red. */ SET_COLOR( 1, 0, 0, color ); PEXSetLineColor( dpy, sulfate, PEXOCStore, PEXColorTypeRGB, &color ); /* Define the polyline along the Y axis. */ bond_points[0].x = bond_points[0].z = 0; bond_points[0].y = S_RADIUS; bond_points[1].x = bond_points[1].z = 0; bond_points[1].y = S_RADIUS + SO_BOND_LENGTH; /* Rotate the bond polyline into the correct positions. */ for ( i = 0; i < 4; i++ ) { PEXRotate( PEXYAxis, pos[i].t, rotate ); PEXSetLocalTransform( dpy, sulfate, PEXOCStore, PEXReplace, rotate ); PEXRotate( PEXXAxis, pos[i].p, rotate ); PEXSetLocalTransform( dpy, sulfate, PEXOCStore, PEXPreConcatenate, rotate ); PEXPolyline( dpy, sulfate, PEXOCStore, 2, bond_points ); } } static void redraw( dpy, window, renderer ) Display *dpy; Window window; PEXRenderer renderer; { XClearWindow( dpy, window ); PEXRenderNetwork( dpy, window, renderer, sulfate ); XFlush( dpy ); } #define WIN_GEOM "500x500+50+50" main( argc, argv ) int argc; char *argv[]; { Display *dpy; Window window; XEvent event; XVisualInfo vis_info; XColor bkgd_color; XStandardColormap cmap_info; PEXColorApproxEntry capx_info; PEXRenderer renderer; PEXRendererAttributes rattrs; PEXExtensionInfo *pexinfo; int done = 0; /* Open a display and initialize PEX. */ dpy = ora_init_pex( argv, &pexinfo ); if ( !dpy ) exit(1); /* Determine the best visual to use. */ ora_find_best_visual( dpy, &vis_info ); /* Get a standard colormap for the visual. */ if ( !ora_get_standard_colormap( dpy, &vis_info, &cmap_info ) ) { fprintf ( stderr, "Cannot find a standard colormap\n" ); exit(1); } ora_set_stdcmap_approx( &vis_info, &cmap_info, &capx_info ); /* Create the window, giving it a gray background. */ bkgd_color.red = bkgd_color.green = bkgd_color.blue = 0x5555; bkgd_color.flags = DoRed | DoGreen | DoBlue; window = ora_create_window( dpy, &vis_info, &cmap_info, WIN_GEOM, &bkgd_color ); if ( STRUCTURE_SPT( pexinfo ) ) { renderer = ora_setup_renderer( dpy, window, &capx_info, &rattrs ); create_structure( dpy ); } else { fprintf( stderr, "Structures not supported..\n" ); exit(1); } /* Read and respond to X events. */ XSelectInput( dpy, window, ExposureMask | ButtonPressMask ); while ( !done ) { XNextEvent( dpy, &event ); switch ( event.type ) { case Expose: /* Flush remaining Expose events, then redraw. */ while ( XCheckTypedWindowEvent( dpy, window, Expose, &event ) ) ; /* empty statement */ redraw( dpy, window, renderer ); break; case ButtonPress: done = 1; break; } } XCloseDisplay( dpy ); return 0; }