/* sulfate2.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) #ifdef ROTATE_ION static int rotate_ion(); #endif /* The structure ids. */ static PEXStructure model, sulfate, sulfur, oxygen, sphere; /* 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_model( dpy ) Display *dpy; { PEXListOfCoord sphere_pts; PEXCoord bond_points[2], fp; PEXColor color; PEXMatrix translate, scale, global; PEXMatrix rotate_x, rotate_y, rotate; PEXVector tr, sc; int i; /*** Create the sphere structure. ***/ sphere = PEXCreateStructure( dpy ); ora_build_sphere( 1.0, &sphere_pts ); PEXPolyline( dpy, sphere, PEXOCStore, sphere_pts.count, sphere_pts.points ); /*** Create the sulfur atom. ***/ sulfur = PEXCreateStructure( dpy ); SET_COLOR( 1, 1, 0, color ) PEXSetLineColor( dpy, sulfur, PEXOCStore, PEXColorTypeRGB, &color ); /* Scale and execute the sphere. */ sc.x = sc.y = sc.z = S_RADIUS; PEXScale( &sc, scale ); PEXSetLocalTransform( dpy, sulfur, PEXOCStore, PEXReplace, scale ); PEXExecuteStructure( dpy, sulfur, PEXOCStore, sphere ); /*** Create the oxygen atom. ***/ oxygen = PEXCreateStructure( dpy ); SET_COLOR( 0, 1, 1, color ) PEXSetLineColor( dpy, oxygen, PEXOCStore, PEXColorTypeRGB, &color ); /* Scale and execute the sphere. */ sc.x = sc.y = sc.z = O_RADIUS; PEXScale( &sc, scale ); PEXSetLocalTransform( dpy, oxygen, PEXOCStore, PEXReplace, scale ); PEXExecuteStructure( dpy, oxygen, PEXOCStore, sphere ); /*** Create the sulfate structure. ***/ sulfate = PEXCreateStructure( dpy ); /* Instance the Sulfur atom. */ PEXExecuteStructure( dpy, sulfate, PEXOCStore, sulfur ); /* Position and instance the oxygen atoms. */ for ( i = 0; i < 4; i++ ) { /* Convert the 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 create the transform element. */ PEXTranslate( &tr, translate ); PEXSetLocalTransform( dpy, sulfate, PEXOCStore, PEXReplace, translate ); /* Instance the oxygen structure. */ PEXExecuteStructure( dpy, sulfate, PEXOCStore, oxygen ); } /* Build the bonds. */ SET_COLOR( 1, 0, 0, color ) PEXSetLineColor( dpy, sulfate, PEXOCStore, PEXColorTypeRGB, &color ); 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; for ( i = 0; i < 4; i++ ) { PEXRotate( PEXXAxis, pos[i].p, rotate_x ); PEXRotate( PEXYAxis, pos[i].t, rotate_y ); PEXMatrixMult( rotate_y, rotate_x, rotate ); PEXSetLocalTransform( dpy, sulfate, PEXOCStore, PEXReplace, rotate ); PEXPolyline( dpy, sulfate, PEXOCStore, 2, bond_points ); } /*** Build the top-level structure. ***/ model = PEXCreateStructure( dpy ); /* Use the global transform to scale and center the ion. */ sc.x = sc.y = sc.z = 1 / (3 * SO_LENGTH); tr.x = tr.y = tr.z = 0.5; fp.x = fp.y = fp.z = 0; PEXBuildTransform( &fp, &tr, 0.0, 0.0, 0.0, &sc, global ); PEXSetGlobalTransform( dpy, model, PEXOCStore, global ); #ifdef ROTATE_ION /* Use a local transform to rotate the model. */ PEXIdentityMatrix( rotate ); PEXSetLocalTransform( dpy, model, PEXOCStore, PEXReplace, rotate ); #endif /* Execute the sulfate ion. */ PEXExecuteStructure( dpy, model, PEXOCStore, sulfate ); } static void redraw( dpy, window, renderer ) Display *dpy; Window window; PEXRenderer renderer; { XClearWindow( dpy, window ); PEXRenderNetwork( dpy, window, renderer, model ); 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_model( 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: #ifdef ROTATE_ION switch ( event.xbutton.button ) { case Button1: rotate_ion( dpy, window, renderer ); break; default: done = 1; break; } #else done = 1; #endif break; } } XCloseDisplay( dpy ); return 0; } #ifdef ROTATE_ION static int rotate_ion( dpy, window, renderer ) Display *dpy; Window window; PEXRenderer renderer; { /* Use the modeling transform in the model structure to rotate */ /* the ion: set the edit mode to REPLACE, position the element */ /* pointer to the Set Local Transform element, then replace the */ /* element. */ double angle; PEXMatrix rotate; PEXSetEditingMode( dpy, model, PEXStructureReplace ); PEXSetElementPtr( dpy, model, PEXBeginning, 2 ); for ( angle = M_PI/100; angle <= 2*M_PI; angle += M_PI/100 ) { PEXRotate( PEXXAxis, angle, rotate ); PEXSetLocalTransform( dpy, model, PEXOCStore, PEXReplace, rotate ); redraw( dpy, window, renderer ); } } #endif