📄 graphics.c
字号:
* of the page and increase upwards and to the right. For 8.5 x 11 * * sheet, coordinates go from (0,0) to (612,792). Spacing is 1/72 inch.* * I'm leaving a minimum of half an inch (36 units) of border around * * each edge. */ float ps_width, ps_height; ps_width = 540.; /* 72 * 7.5 */ ps_height = 720.; /* 72 * 10 */ ps_xmult = ps_width / (xright - xleft); ps_ymult = ps_height / (ytop - ybot);/* Need to use same scaling factor to preserve aspect ratio. * * I show exactly as much on paper as the screen window shows, * * or the user specifies. */ if (fabs(ps_xmult) <= fabs(ps_ymult)) { ps_left = 36.; ps_right = 36. + ps_width; ps_bot = 396. - fabs(ps_xmult * (ytop - ybot))/2.; ps_top = 396. + fabs(ps_xmult * (ytop - ybot))/2.;/* Maintain aspect ratio but watch signs */ ps_ymult = (ps_xmult*ps_ymult < 0) ? -ps_xmult : ps_xmult; } else { ps_bot = 36.; ps_top = 36. + ps_height; ps_left = 306. - fabs(ps_ymult * (xright - xleft))/2.; ps_right = 306. + fabs(ps_ymult * (xright - xleft))/2.;/* Maintain aspect ratio but watch signs */ ps_xmult = (ps_xmult*ps_ymult < 0) ? -ps_ymult : ps_ymult; }}void event_loop (void (*act_on_button) (float x, float y), void (*drawscreen) (void)) {/* The program's main event loop. Must be passed a user routine * * drawscreen which redraws the screen. It handles all window resizing * * zooming etc. itself. If the user clicks a button in the graphics * * (toplevel) area, the act_on_button routine passed in is called. */ XEvent report; int bnum; float x, y;#define OFF 1#define ON 0 turn_on_off (ON); while (1) { XNextEvent (display, &report); switch (report.type) { case Expose:#ifdef VERBOSE printf("Got an expose event.\n"); printf("Count is: %d.\n",report.xexpose.count); printf("Window ID is: %d.\n",report.xexpose.window);#endif if (report.xexpose.count != 0) break; if (report.xexpose.window == menu) drawmenu(); else if (report.xexpose.window == toplevel) drawscreen(); else if (report.xexpose.window == textarea) draw_message(); break; case ConfigureNotify: top_width = report.xconfigure.width; top_height = report.xconfigure.height; update_transform();#ifdef VERBOSE printf("Got a ConfigureNotify.\n"); printf("New width: %d New height: %d.\n",top_width,top_height);#endif break; case ButtonPress:#ifdef VERBOSE printf("Got a buttonpress.\n"); printf("Window ID is: %d.\n",report.xbutton.window);#endif if (report.xbutton.window == toplevel) { x = XTOWORLD(report.xbutton.x); y = YTOWORLD(report.xbutton.y); act_on_button (x, y); } else { /* A menu button was pressed. */ bnum = which_button(report.xbutton.window);#ifdef VERBOSE printf("Button number is %d\n",bnum);#endif button[bnum].ispressed = 1; drawbut(bnum); XFlush(display); /* Flash the button */ button[bnum].fcn (drawscreen); button[bnum].ispressed = 0; drawbut(bnum); if (button[bnum].fcn == proceed) { turn_on_off(OFF); flushinput (); return; /* Rather clumsy way of returning * * control to the simulator */ } } break; } }}void clearscreen (void) { int savecolor; if (disp_type == SCREEN) { XClearWindow (display, toplevel); } else {/* erases current page. Don't use erasepage, since this will erase * * everything, (even stuff outside the clipping path) causing * * problems if this picture is incorporated into a larger document. */ savecolor = currentcolor; setcolor (WHITE); fprintf(ps,"clippath fill\n\n"); setcolor (savecolor); }}static int rect_off_screen (float x1, float y1, float x2, float y2) {/* Return 1 if I can quarantee no part of this rectangle will * * lie within the user drawing area. Otherwise return 0. * * Note: this routine is only used to help speed (and to shrink ps * * files) -- it will be highly effective when the graphics are zoomed * * in and lots are off-screen. I don't have to pre-clip for * * correctness. */ float xmin, xmax, ymin, ymax; xmin = min (xleft, xright); if (x1 < xmin && x2 < xmin) return (1); xmax = max (xleft, xright); if (x1 > xmax && x2 > xmax) return (1); ymin = min (ytop, ybot); if (y1 < ymin && y2 < ymin) return (1); ymax = max (ytop, ybot); if (y1 > ymax && y2 > ymax) return (1); return (0);} void drawline (float x1, float y1, float x2, float y2) {/* Draw a line from (x1,y1) to (x2,y2) in the user-drawable area. * * Coordinates are in world (user) space. */ if (rect_off_screen(x1,y1,x2,y2)) return; if (disp_type == SCREEN) { /* Xlib.h prototype has x2 and y1 mixed up. */ XDrawLine(display, toplevel, gc, xcoord(x1), ycoord(y1), xcoord(x2), ycoord(y2)); } else { fprintf(ps,"%.2f %.2f %.2f %.2f drawline\n",XPOST(x1),YPOST(y1), XPOST(x2),YPOST(y2)); }}void drawrect (float x1, float y1, float x2, float y2) {/* (x1,y1) and (x2,y2) are diagonally opposed corners, in world coords. */ unsigned int width, height; int xw1, yw1, xw2, yw2, xl, yt; if (rect_off_screen(x1,y1,x2,y2)) return; if (disp_type == SCREEN) { /* translate to X Windows calling convention. */ xw1 = xcoord(x1); xw2 = xcoord(x2); yw1 = ycoord(y1); yw2 = ycoord(y2); xl = min(xw1,xw2); yt = min(yw1,yw2); width = abs (xw1-xw2); height = abs (yw1-yw2); XDrawRectangle(display, toplevel, gc, xl, yt, width, height); } else { fprintf(ps,"%.2f %.2f %.2f %.2f drawrect\n",XPOST(x1),YPOST(y1), XPOST(x2),YPOST(y2)); }}void fillrect (float x1, float y1, float x2, float y2) {/* (x1,y1) and (x2,y2) are diagonally opposed corners in world coords. */ unsigned int width, height; int xw1, yw1, xw2, yw2, xl, yt; if (rect_off_screen(x1,y1,x2,y2)) return; if (disp_type == SCREEN) {/* translate to X Windows calling convention. */ xw1 = xcoord(x1); xw2 = xcoord(x2); yw1 = ycoord(y1); yw2 = ycoord(y2); xl = min(xw1,xw2); yt = min(yw1,yw2); width = abs (xw1-xw2); height = abs (yw1-yw2); XFillRectangle(display, toplevel, gc, xl, yt, width, height); } else { fprintf(ps,"%.2f %.2f %.2f %.2f fillrect\n",XPOST(x1),YPOST(y1), XPOST(x2),YPOST(y2)); }}static float angnorm (float ang) {/* Normalizes an angle to be between 0 and 360 degrees. */ int scale; if (ang < 0) { scale = (int) (ang / 360. - 1); } else { scale = (int) (ang / 360.); } ang = ang - scale * 360.; return (ang);}void drawarc (float xc, float yc, float rad, float startang, float angextent) {/* Draws a circular arc. X11 can do elliptical arcs quite simply, and * * PostScript could do them by scaling the coordinate axes. Too much * * work for now, and probably too complex an object for users to draw * * much, so I'm just doing circular arcs. Startang is relative to the * * Window's positive x direction. Angles in degrees. */ int xl, yt; unsigned int width, height;/* Conservative (but fast) clip test -- check containing rectangle of * * a circle. */ if (rect_off_screen (xc-rad,yc-rad,xc+rad,yc+rad)) return;/* X Windows has trouble with very large angles. (Over 360). * * Do following to prevent its inaccurate (overflow?) problems. */ if (fabs(angextent) > 360.) angextent = 360.; startang = angnorm (startang); if (disp_type == SCREEN) { xl = (int) (xcoord(xc) - fabs(xmult*rad)); yt = (int) (ycoord(yc) - fabs(ymult*rad)); width = (unsigned int) (2*fabs(xmult*rad)); height = width; XDrawArc (display, toplevel, gc, xl, yt, width, height, (int) (startang*64), (int) (angextent*64)); } else { fprintf(ps,"%.2f %.2f %.2f %.2f %.2f %s stroke\n", XPOST(xc), YPOST(yc), fabs(rad*ps_xmult), startang, startang+angextent, (angextent < 0) ? "drawarcn" : "drawarc") ; }}void fillarc (float xc, float yc, float rad, float startang, float angextent) {/* Fills a circular arc. Startang is relative to the Window's positive x * * direction. Angles in degrees. */ int xl, yt; unsigned int width, height;/* Conservative (but fast) clip test -- check containing rectangle of * * a circle. */ if (rect_off_screen (xc-rad,yc-rad,xc+rad,yc+rad)) return;/* X Windows has trouble with very large angles. (Over 360). * * Do following to prevent its inaccurate (overflow?) problems. */ if (fabs(angextent) > 360.) angextent = 360.; startang = angnorm (startang); if (disp_type == SCREEN) { xl = (int) (xcoord(xc) - fabs(xmult*rad)); yt = (int) (ycoord(yc) - fabs(ymult*rad)); width = (unsigned int) (2*fabs(xmult*rad)); height = width; XFillArc (display, toplevel, gc, xl, yt, width, height, (int) (startang*64), (int) (angextent*64)); } else { fprintf(ps,"%.2f %.2f %.2f %.2f %.2f %s\n", fabs(rad*ps_xmult), startang, startang+angextent, XPOST(xc), YPOST(yc), (angextent < 0) ? "fillarcn" : "fillarc") ; }}void fillpoly (t_point *points, int npoints) { XPoint transpoints[MAXPTS]; int i; float xmin, ymin, xmax, ymax; if (npoints > MAXPTS) { printf("Error in fillpoly: Only %d points allowed per polygon.\n", MAXPTS); printf("%d points were requested. Polygon is not drawn.\n",npoints); return; }/* Conservative (but fast) clip test -- check containing rectangle of * * polygon. */ xmin = xmax = points[0].x; ymin = ymax = points[0].y; for (i=1;i<npoints;i++) { xmin = min (xmin,points[i].x); xmax = max (xmax,points[i].x); ymin = min (ymin,points[i].y); ymax = max (ymax,points[i].y); } if (rect_off_screen(xmin,ymin,xmax,ymax)) return; if (disp_type == SCREEN) { for (i=0;i<npoints;i++) { transpoints[i].x = (short) xcoord (points[i].x); transpoints[i].y = (short) ycoord (points[i].y); } XFillPolygon(display, toplevel, gc, transpoints, npoints, Complex, CoordModeOrigin); } else { fprintf(ps,"\n"); for (i=npoints-1;i>=0;i--) fprintf (ps, "%.2f %.2f\n", XPOST(points[i].x), YPOST(points[i].y)); fprintf (ps, "%d fillpoly\n", npoints); }}void drawtext (float xc, float yc, char *text, float boundx) {/* Draws text centered on xc,yc if it fits in boundx */ int len, width, xw_off, yw_off; len = strlen(text); width = XTextWidth(font_info[currentfontsize], text, len); if (width > fabs(boundx*xmult)) return; /* Don't draw if it won't fit */ xw_off = width/(2.*xmult); /* NB: sign doesn't matter. *//* NB: 2 * descent makes this slightly conservative but simplifies code. */ yw_off = (font_info[currentfontsize]->ascent + 2 * font_info[currentfontsize]->descent)/(2.*ymult); /* Note: text can be clipped when a little bit of it would be visible * * right now. Perhaps X doesn't return extremely accurate width and * * ascent values, etc? Could remove this completely by multiplying * * xw_off and yw_off by, 1.2 or 1.5. */ if (rect_off_screen(xc-xw_off, yc-yw_off, xc+xw_off, yc+yw_off)) return; if (disp_type == SCREEN) { XDrawString(display, toplevel, gc, xcoord(xc)-width/2, ycoord(yc) + (font_info[currentfontsize]->ascent - font_info[currentfontsize]->descent)/2, text, len); } else { fprintf(ps,"(%s) %.2f %.2f censhow\n",text,XPOST(xc),YPOST(yc)); }}void flushinput (void) { if (disp_type != SCREEN) return; XFlush(display);}void init_world (float x1, float y1, float x2, float y2) {/* Sets the coordinate system the user wants to draw into. */ xleft = x1; xright = x2; ytop = y1; ybot = y2; saved_xleft = xleft; /* Save initial world coordinates to allow full */ saved_xright = xright; /* view button to zoom all the way out. */ saved_ytop = ytop; saved_ybot = ybot; if (disp_type == SCREEN) { update_transform(); } else { update_ps_transform(); }}void draw_message (void) {/* Draw the current message in the text area at the screen bottom. */ int len, width, savefontsize, savecolor; float ylow; if (disp_type == SCREEN) { XClearWindow (display, textarea); len = strlen (message); width = XTextWidth(font_info[menu_font_size], message, len); XSetForeground(display, gc_menus,colors[BLACK]); XDrawString(display, textarea, gc_menus, (top_width - MWIDTH - width)/2, (T_AREA_HEIGHT - 4)/2 + (font_info[menu_font_size]->ascent - font_info[menu_font_size]->descent)/2, message, len); } else {/* Draw the message in the bottom margin. Printer's generally can't * * print on the bottom 1/4" (area with y < 18 in PostScript coords.) */ savecolor = currentcolor; setcolor (BLACK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -