/* truss-to-eps.c The function truss_to_eps() receives a Truss structure and writes an Encapsulated PostScript (EPS) file containing a drawing of the truss. Rouben Rostamian November 2003 */ #include #include #include "linked-list.h" #include "truss.h" #include "truss-to-eps.h" /* Truss image will be scaled to fit in a rectangular box of maximum width or height given by TRUSS_SIZE */ #define TRUSS_SIZE 400 /* Margin widths to add to the overall image */ #define H_MARGIN 25.0 #define V_MARGIN 25.0 /* Horizontal distance between the truss drawing area and the colorbar */ #define SCALE_GAP 25.0 /* Colorbar width */ #define SCALE_WIDTH 10.0 /* Longest arrow */ #define F_MAX 20.0 #define REDHUE(s) (huefunc((s)-23.0/64)) #define GREENHUE(s) (huefunc((s) -7.0/64)) #define BLUEHUE(s) (huefunc((s) +9.0/64)) /* Based on Matlab's `jet' colormap */ static float huefunc(float s) { if (s < 0) return 0.0; else if (s < 16.0/64) return 4.0*s; else if (s < 33.0/64) return 1.0; else if (s < 49.0/64) return 1.0 - 4.0*(s-33.0/64); else return 0.0; } static void draw_colorscale(FILE *fp, double height, double smax) { char buf[32]; int nboxes = 15; double bh = height/nboxes; /* box height */ int i; /* a tickmark for the center (zero) of the color scale */ fputs("gsave\n", fp); fputs("1 setlinewidth\n", fp); fprintf(fp, "newpath\n"); fprintf(fp, "%g %g moveto\n", -0.3*SCALE_WIDTH, height/2); fprintf(fp, "%g %g lineto\n", 1.3*SCALE_WIDTH, height/2); fprintf(fp, "stroke\n"); fputs("grestore\n", fp); /* draw the color boxes */ for (i=0; i\n", fp); fputs("%%BoundingBox: (atend)\n", fp); fputs("%%DocumentFonts: Times-Roman Times-Bold " "Times-Italic Helvetica\n", fp); fputs("%%EndComments\n", fp); fputs("\n", fp); fputs("% save original state\n", fp); fputs("/origstate save def\n", fp); fputs("\n", fp); fputs("% dictionary\n", fp); fputs("30 dict begin\n", fp); fputs("\n", fp); } /* If `labels' is TR_PLOT_WITH_LABELS, prints node and link labels */ void truss_to_eps(struct truss *truss, char *epsfile, int labels) { FILE *fp; conscell *p; double xmin, xmax, xwidth, ymin, ymax, ywidth, forcemax, scale; double stress_min, stress_max; double bbox_width, bbox_height; fp = fopen(epsfile, "w"); if (fp == NULL) { fprintf(stderr, "unable to open file %s for writing\n", epsfile); return; } /* calculate min and max stress */ stress_min = stress_max = ((struct link *)truss->links_list->data)->stress; for (p = truss->links_list; p != NULL; p = p->next) { struct link *link = p->data; double s = link->stress; if (s < stress_min) stress_min = s; else if (s > stress_max) stress_max = s; } /* symmetrize, so that center of color scale corresponds to zero */ stress_max = fmax(fabs(stress_min), fabs(stress_max)); stress_min = -stress_max; /* calculate range of (x,y) coordiantes and largest applied force */ xmin = xmax = ((struct node *)truss->nodes_list->data)->x; ymin = ymax = ((struct node *)truss->nodes_list->data)->y; forcemax = 0.0; for (p = truss->nodes_list; p != NULL; p = p->next) { struct node *node = p->data; if (node->x < xmin) xmin = node->x; else if (node->x > xmax) xmax = node->x; if (node->y < ymin) ymin = node->y; else if (node->y > ymax) ymax = node->y; if (fabs(node->fx) > forcemax) forcemax = fabs(node->fx); if (fabs(node->fy) > forcemax) forcemax = fabs(node->fy); } xwidth = xmax - xmin; ywidth = ymax - ymin; scale = TRUSS_SIZE / fmax(xwidth,ywidth); bbox_width = xwidth*scale + SCALE_GAP + SCALE_WIDTH + 2*H_MARGIN; bbox_height = ywidth*scale + 2*V_MARGIN; /* header and other initialization stuff */ header(fp); arrowdef(fp); hingedef(fp); fixedsupportdef(fp); rollersupportdef(fp); fprintf(fp, "%g %g translate\n", H_MARGIN, V_MARGIN); fprintf(fp, "%d setlinewidth\n", 3); fprintf(fp, "%d setlinecap\n", 1); for (p = truss->links_list; p != NULL; p = p->next) { struct link *link = p->data; double s, r, g, b; if (stress_max == stress_min) s = 0.5; else s = (link->stress - stress_min) / (stress_max - stress_min); s = 1.0 - s; /* reverse color scale */ r = REDHUE(s); g = GREENHUE(s); b = BLUEHUE(s); fprintf(fp, "%.3f %.3f %.3f setrgbcolor\n", r, g, b); fprintf(fp, "newpath %g %g moveto %g %g lineto stroke\n", (link->np1->x - xmin)*scale, (link->np1->y - ymin)*scale, (link->np2->x - xmin)*scale, (link->np2->y - ymin)*scale); } fputs("0 setgray\n", fp); fprintf(fp, "/Times-Bold findfont 14 scalefont setfont\n"); for (p = truss->nodes_list; p != NULL; p = p->next) { struct node *node = p->data; double x = (node->x - xmin)*scale; double y = (node->y - ymin)*scale; if (node->fx != 0 || node->fy != 0) fprintf(fp, "%g %g %g %g draw_arrow\n", x, y, F_MAX*node->fx/forcemax, F_MAX*node->fy/forcemax); if (node->xfixed && node->yfixed) fprintf(fp, "%g %g 0 draw_fixed_support\n", x, y); else if (node->xfixed) fprintf(fp, "%g %g 90 draw_roller_support\n", x, y); else if (node->yfixed) fprintf(fp, "%g %g 0 draw_roller_support\n", x, y); fprintf(fp, "%g %g draw_hinge\n", x, y); if (labels == TR_PLOT_WITH_LABELS) fprintf(fp, "%g %g moveto (%d) show\n", x+5, y+5, node->n); } if (labels==TR_PLOT_WITH_LABELS) { fputs("0.5 setgray\n", fp); fprintf(fp, "/Times-Italic findfont 14 scalefont setfont\n"); for (p = truss->links_list; p != NULL; p = p->next) { struct link *link = p->data; double x1 = (link->np1->x - xmin)*scale; double y1 = (link->np1->y - ymin)*scale; double x2 = (link->np2->x - xmin)*scale; double y2 = (link->np2->y - ymin)*scale; double x = 0.4*x1 + 0.6*x2; double y = 0.4*y1 + 0.6*y2; fprintf(fp, "%g %g moveto (%d) show\n", x, y, link->n); } } fprintf(fp, "%g %g translate\n", xwidth*scale + SCALE_GAP, 0.0); draw_colorscale(fp, ywidth*scale, stress_max); fputs("\n", fp); fputs("showpage\n", fp); fputs("\n", fp); fputs("% end dictionary\n", fp); fputs("end\n", fp); fputs("\n", fp); fputs("% restore original state\n", fp); fputs("origstate restore\n", fp); fputs("\n", fp); fputs("%%Trailer\n", fp); fputs("\n", fp); fprintf(fp, "%%%%BoundingBox: 0 0 %d %d\n", (int)(0.5+bbox_width), (int)(0.5+bbox_height)); fputs("%%EOF\n", fp); fclose(fp); }