/* pvt.c 1.2 */ /* 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" /* Globals. */ static PEXStructure model, surface, borders; static Display *dpy; static Window window; static PEXRenderer renderer; /* Define the projection viewports for the four views. */ static PEXNPCSubVolume vports[] = { /* x-min, y-min, z-min, x-max, y-max, z-max */ {{ 0.5, 0.5, 0},{ 1, 1, 1}}, /* view 1 */ {{ 0.5, 0, 0},{ 1, 0.5, 1}}, /* view 2 */ {{ 0, 0, 0},{ 0.5, 0.5, 1}}, /* view 3 */ {{ 0, 0.5, 0},{ 0.5, 1, 1}} /* view 4 */ }; static void initialize_views( view_table ) PEXLookupTable view_table; { PEXCoord vrp; PEXVector vup, vpn; PEXCoord2D view_window[2]; double view_plane, front_plane, back_plane; PEXCoord prp; PEXViewEntry view; int err, perspective; /* Set the view paramters that most views use. */ vrp.x = 0.5; vrp.y = 0.5; vrp.z = 0.5; vup.x = 0; vup.y = 1; vup.z = 0; perspective = False; view_plane = 0; prp.x = 0; prp.y = 0; prp.z = 10; view_window[0].x = -1; view_window[1].x = 1; view_window[0].y = -1; view_window[1].y = 1; back_plane = -1; front_plane = 1; view.clip_flags = PEXClippingAll; /* Right-side -- view 2. Put it in lower-right corner. */ vpn.x = 1; vpn.y = 0; vpn.z = 0; err = PEXViewOrientationMatrix( &vrp, &vpn, &vup, view.orientation ); err = PEXViewMappingMatrix( view_window, &vports[1], perspective, &prp, view_plane, back_plane, front_plane, view.mapping ); view.clip_limits = vports[1]; PEXSetTableEntries( dpy, view_table, 2, 1, PEXLUTView, &view ); /* Front -- view 3. Put it in lower-left corner. */ vpn.x = 0; vpn.y = 0; vpn.z = 1; err = PEXViewOrientationMatrix( &vrp, &vpn, &vup, view.orientation ); err = PEXViewMappingMatrix( view_window, &vports[2], perspective, &prp, view_plane, back_plane, front_plane, view.mapping ); view.clip_limits = vports[2]; PEXSetTableEntries( dpy, view_table, 3, 1, PEXLUTView, &view ); /* Top -- view 4. Put it in upper-left corner. */ vpn.x = 0; vpn.y = 1; vpn.z = 0; vup.x = 0; vup.y = 0; vup.z = -1; err = PEXViewOrientationMatrix( &vrp, &vpn, &vup, view.orientation ); err = PEXViewMappingMatrix( view_window, &vports[3], perspective, &prp, view_plane, back_plane, front_plane, view.mapping ); view.clip_limits = vports[3]; PEXSetTableEntries( dpy, view_table, 4, 1, PEXLUTView, &view ); /* Off-axis -- view 1. Put it in upper-right corner. */ vpn.x = 1; vpn.y = 0.1; vpn.z = 1; vup.x = 0; vup.y = 1; vup.z = 0; err = PEXViewOrientationMatrix( &vrp, &vpn, &vup, view.orientation ); err = PEXViewMappingMatrix( view_window, &vports[0], perspective, &prp, view_plane, back_plane, front_plane, view.mapping ); view.clip_limits = vports[0]; PEXSetTableEntries( dpy, view_table, 1, 1, PEXLUTView, &view ); } static void create_borders() { PEXCoord2D pts[5]; PEXColor color; int i; borders = PEXCreateStructure( dpy ); /* Use view 0 for the borders. */ PEXSetViewIndex( dpy, borders, PEXOCStore, 0 ); /* Draw a polyline around each viewport. */ SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetLineColor( dpy, borders, PEXOCStore, PEXColorTypeRGB, &color ); PEXSetLineWidth( dpy, borders, PEXOCStore, 2.0 ); for ( i = 0; i < 4; i++ ) { pts[0].x = vports[i].min.x; pts[0].y = vports[i].min.y; pts[1].x = vports[i].max.x; pts[1].y = vports[i].min.y; pts[2].x = vports[i].max.x; pts[2].y = vports[i].max.y; pts[3].x = vports[i].min.x; pts[3].y = vports[i].max.y; pts[4].x = vports[i].min.x; pts[4].y = vports[i].min.y; PEXPolyline2D( dpy, borders, PEXOCStore, 5, pts ); } } #define NUM_POINTS 13 #define TMAX 1000.0 #define VMAX 1.0 #define BASE_HEIGHT 0.1 static PEXCoord base_vertices[2][4] = { {{0,0,1}, {1,0,1}, {1,BASE_HEIGHT,1}, {0,BASE_HEIGHT,1}}, {{1,0,1}, {1,0,0}, {1,BASE_HEIGHT,0}, {1, BASE_HEIGHT, 1}}}; static void create_ideal_gas_surface() { PEXStructure labels; PEXCoord vertices[NUM_POINTS * (NUM_POINTS + 1)]; PEXArrayOfVertex surface_vdata; PEXArrayOfFacetData dummy; PEXCoord text_pt, offset; PEXVector2D anno_up_vec; PEXTextAlignment text_align; PEXVector scale, translate, text_dir[2]; PEXMatrix xscale, xtranslate, xform; PEXColor color; float V, dV, T, dT, maxP; int i, j, index; /* Generate the points for the surface: P = T/V. */ dV = VMAX / (NUM_POINTS - 1); dT = TMAX / (NUM_POINTS - 1); maxP = 4 * TMAX / VMAX; for ( i = 0, V = 0; i < NUM_POINTS + 1; i++, V += dV ) { for ( j = 0, T = 0; j < NUM_POINTS; j++, T += dT ) { index = i * NUM_POINTS + j; vertices[index].x = V; vertices[index].z = TMAX - T; if ( V == 0 ) { /* Clamp 0 volume to maximum pressure. */ vertices[index].y = maxP; } else if ( i == NUM_POINTS ) { /* Truncate last row to 0 pressure. */ vertices[index].x = VMAX; vertices[index].y = 0; } else { /* Compute the pressure. */ vertices[index].y = T / V; if ( vertices[index].y > maxP ) vertices[index].y = maxP; } } } /* Create the structure for the labels. */ labels = PEXCreateStructure( dpy ); /* Border the volume and temperature labels. */ for ( i = 0; i < 2; i++ ) { PEXFillArea( dpy, labels, PEXOCStore, PEXShapeConvex, True, 4, base_vertices[i] ); } /* Ensure that all text attributes are applied. */ PEXSetTextPrecision( dpy, labels, PEXOCStore, PEXStrokePrecision ); /* Create the labels. */ SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetTextColor( dpy, labels, PEXOCStore, PEXColorTypeRGB, &color ); PEXSetCharHeight( dpy, labels, PEXOCStore, 0.05 ); PEXSetTextAlignment( dpy, labels, PEXOCStore, PEXHAlignCenter, PEXVAlignHalf ); text_pt.x = 0.5; text_pt.y = 0.05; text_pt.z = 1; text_dir[0].x = 1; text_dir[0].y = 0; text_dir[0].z = 0; text_dir[1].x = 0; text_dir[1].y = 1; text_dir[1].z = 0; PEXText( dpy, labels, PEXOCStore, &text_pt, &text_dir[0], &text_dir[1], strlen("Volume"), "Volume" ); text_pt.x = 1; text_pt.y = 0.05; text_pt.z = 0.5; text_dir[0].x = 0; text_dir[0].y = 0; text_dir[0].z = -1; PEXText( dpy, labels, PEXOCStore, &text_pt, &text_dir[0], &text_dir[1], strlen("Temperature"), "Temperature" ); /* Use annotation text for the "Pressure" label. */ PEXSetATextHeight( dpy, labels, PEXOCStore, 0.02 ); PEXSetATextAlignment( dpy, labels, PEXOCStore, PEXHAlignCenter, PEXVAlignHalf ); anno_up_vec.x = -1; anno_up_vec.y = 0; PEXSetATextUpVector( dpy, labels, PEXOCStore, &anno_up_vec ); text_pt.x = 0.05; text_pt.y = 0.5; text_pt.z = 0.95; offset.x = offset.y = offset.z = 0; PEXAnnotationText( dpy, labels, PEXOCStore, &text_pt, &offset, strlen("Pressure"), "Pressure" ); /* Create the structure to hold the surface. */ surface = PEXCreateStructure( dpy ); SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetSurfaceColor( dpy, surface, PEXOCStore, PEXColorTypeRGB, &color ); /* Draw the labels. */ PEXExecuteStructure( dpy, surface, PEXOCStore, labels ); /* Scale the surface into a reasonable volume and center it. */ scale.x = 0.8/VMAX; scale.y = 0.8/maxP; scale.z = 0.8/TMAX; PEXScale( &scale, xscale ); translate.x = translate.y = translate.z = 0.1; PEXTranslate( &translate, xtranslate ); PEXMatrixMult( xtranslate, xscale, xform ); PEXSetLocalTransform( dpy, surface, PEXOCStore, PEXReplace, xform ); /* Create the quadrilateral mesh element for the surface. */ surface_vdata.no_data = vertices; PEXQuadrilateralMesh( dpy, surface, PEXOCStore, PEXShapeUnknown, PEXGANone, PEXGANone, PEXColorTypeRGB, dummy, NUM_POINTS, NUM_POINTS + 1, surface_vdata ); } static void redraw() { XClearWindow( dpy, window ); PEXRenderNetwork( dpy, window, renderer, model ); XFlush( dpy ); } #define WIN_GEOM "800x800+50+50" main( argc, argv ) int argc; char *argv[]; { XEvent event; XVisualInfo vis_info; XStandardColormap cmap_info; PEXColorApproxEntry capx_info; PEXRendererAttributes rattrs; PEXExtensionInfo *pexinfo; XColor bkgd_color; 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. */ bkgd_color.red = bkgd_color.green = bkgd_color.blue = 0; bkgd_color.flags = DoRed | DoGreen | DoBlue; window = ora_create_window( dpy, &vis_info, &cmap_info, WIN_GEOM, &bkgd_color ); /* Create the model and set up the PEX renderer. */ if ( STRUCTURE_SPT( pexinfo ) ) { renderer = ora_setup_renderer( dpy, window, &capx_info, &rattrs ); } else { fprintf( stderr, "Structures not supported.\n" ); exit(1); } /* Initialize the view. */ initialize_views( rattrs.view_table ); /* create the surface. */ create_ideal_gas_surface(); /* Create the top-level structure. */ model = PEXCreateStructure( dpy ); /* Create and execute the borders. */ create_borders(); PEXExecuteStructure( dpy, model, PEXOCStore, borders ); /* Execute the surface once for each view. */ PEXSetViewIndex( dpy, model, PEXOCStore, 1 ); PEXExecuteStructure( dpy, model, PEXOCStore, surface ); PEXSetViewIndex( dpy, model, PEXOCStore, 2 ); PEXExecuteStructure( dpy, model, PEXOCStore, surface ); PEXSetViewIndex( dpy, model, PEXOCStore, 3 ); PEXExecuteStructure( dpy, model, PEXOCStore, surface ); PEXSetViewIndex( dpy, model, PEXOCStore, 4 ); PEXExecuteStructure( dpy, model, PEXOCStore, surface ); /* Read and respond to X events. */ XSelectInput( dpy, window, ButtonPressMask | ExposureMask ); while ( !done ) { XNextEvent( dpy, &event ); switch ( event.type ) { case ButtonPress: done = 1; break; case Expose: /* Flush remaining Expose events, then redraw. */ while ( XCheckTypedWindowEvent( dpy, window, Expose, &event ) ) ; /* empty statement */ redraw(); break; } } XCloseDisplay( dpy ); return 0; }