#include "ps_graph.h" #include #include #define TEMP_BUF_SIZE 128 /* rozměry grafu */ #define GRAPH_SIZE 400 #define HALF_GRAPH_SIZE (GRAPH_SIZE / 2) #define GRAPH_CENTER_X 306 #define GRAPH_CENTER_Y 500 /* písmo */ #define FONT "Helvetica" #define FONT_SIZE_HEADER 15 #define FONT_SIZE_LABEL 12 #define FONT_SIZE_VALUE 9 #define GRID_STEP (GRAPH_SIZE / 10) /* posuny popisků */ #define HEADER_OFFSET_Y (10) #define X_VAL_OFFSET_X (0) #define X_VAL_OFFSET_Y (-13) #define Y_VAL_OFFSET_X (-5) #define Y_VAL_OFFSET_Y (-3) #define X_LABEL_OFFSET_X (0) #define X_LABEL_OFFSET_Y (-30) #define Y_LABEL_OFFSET_X (-40) #define Y_LABEL_OFFSET_Y (-3) /* počet částí grafu funkce */ #define FUNCTION_SEGMENTS 1000 /* koeficienty pro zarovnání textu */ #define ALIGN_CENTER (-0.5) #define ALIGN_RIGHT (-1.0) static void generate_text_align(FILE *file, int x, int y, double alignment, const char *str) { fprintf(file, "newpath\n" /* posun na cílovou pozici */ "%d %d moveto\n" /* vložení dvou řetězců s popiskem */ "(%s) dup\n" /* zjištění šířky a výšky řetežce, odstranění výšky ze zásobníku (nezajímá) */ "stringwidth pop\n" /* koeficient pro zarovnání */ "%f mul\n" /* posun o šířku doleva */ "0 rmoveto\n" /* zobrazení řetězce */ "show\n" "\n", x, y, str, alignment ); } static void set_font(FILE *file, const char *font, int size) { fprintf(file, "/%s findfont\n" "%d scalefont\n" "setfont\n", font, size ); } static void generate_grid(FILE *file, const struct graph_range *range) { int i; fprintf(file, "2 setlinewidth\n" "/gridline {\n" " .5 setlinewidth\n" " .5 setgray\n" " [3 3] 0 setdash\n" " newpath\n" " moveto\n" " rlineto\n" " stroke\n" "} def\n" "\n" ); for (i = -HALF_GRAPH_SIZE + GRID_STEP; i < HALF_GRAPH_SIZE; i += GRID_STEP) { fprintf(file, "%5d 0 %5d %5d gridline\n", GRAPH_SIZE, -HALF_GRAPH_SIZE, i); fprintf(file, " 0 %5d %5d %5d gridline\n", GRAPH_SIZE, i, -HALF_GRAPH_SIZE); } set_font(file, FONT, FONT_SIZE_VALUE); /* hodnoty */ for (i = -HALF_GRAPH_SIZE; i <= HALF_GRAPH_SIZE; i += GRID_STEP) { double inorm = (double)i / (double)GRAPH_SIZE + 0.5; double xval = range->xmax * inorm + range->xmin * (1.0 - inorm); double yval = range->ymax * inorm + range->ymin * (1.0 - inorm); char buf[TEMP_BUF_SIZE]; /* hodnota osy y */ snprintf(buf, TEMP_BUF_SIZE, "%.2f", yval); generate_text_align(file, -HALF_GRAPH_SIZE + Y_VAL_OFFSET_X, i + Y_VAL_OFFSET_Y, ALIGN_RIGHT, buf); /* hodnota osy x */ snprintf(buf, TEMP_BUF_SIZE, "%.2f", xval); generate_text_align(file, i + X_VAL_OFFSET_X, -HALF_GRAPH_SIZE + X_VAL_OFFSET_Y, ALIGN_CENTER, buf); } /* popisky os */ set_font(file, FONT, FONT_SIZE_LABEL); generate_text_align(file, -HALF_GRAPH_SIZE + Y_LABEL_OFFSET_X, Y_LABEL_OFFSET_Y, ALIGN_RIGHT, "y"); generate_text_align(file, X_LABEL_OFFSET_X, -HALF_GRAPH_SIZE + X_LABEL_OFFSET_Y, ALIGN_CENTER, "x"); } static void generate_function(FILE *file, const struct expr_node *node, const struct graph_range *range) { int i; int first = 1; fprintf(file, "2 setlinewidth\n" "0 .3 .7 setrgbcolor\n" "newpath\n" ); for (i = 0; i < FUNCTION_SEGMENTS; ++i) { const char *cmd = "lineto"; double xpos, ypos; double x, y; x = range->xmin + (range->xmax - range->xmin) * (double)i / (double)FUNCTION_SEGMENTS; /* funkce není definována */ if (node_eval(node, x, &y) != EVAL_OK) { first = 1; continue; } xpos = (double)(-HALF_GRAPH_SIZE) + (x - range->xmin) / (range->xmax - range->xmin) * (double)GRAPH_SIZE; ypos = (double)(-HALF_GRAPH_SIZE) + (y - range->ymin) / (range->ymax - range->ymin) * (double)GRAPH_SIZE; if (first) { cmd = "moveto"; first = 0; } fprintf(file, "%.2f %.2f %s\n", xpos, ypos, cmd); } fprintf(file, "stroke\n" ); } void ps_generate_graph(FILE *file, const struct expr_node *node, const struct graph_range *range, const char *function) { char buf[TEMP_BUF_SIZE]; /* posun na střed */ fprintf(file, "%d %d translate\n", GRAPH_CENTER_X, GRAPH_CENTER_Y); /* hlavička */ if (function) { set_font(file, FONT, FONT_SIZE_HEADER); snprintf(buf, TEMP_BUF_SIZE, "y = %s", function); generate_text_align(file, 0, HALF_GRAPH_SIZE + HEADER_OFFSET_Y, ALIGN_CENTER, buf); } generate_grid(file, range); /* ořezová oblast pro graf */ fprintf(file, "[] 0 setdash\n" "newpath\n" "%d %d moveto\n" "%d 0 rlineto\n" "0 %d rlineto\n" "%d 0 rlineto\n" "closepath\n" "gsave\n" "clip\n", -HALF_GRAPH_SIZE, -HALF_GRAPH_SIZE, GRAPH_SIZE, GRAPH_SIZE, -GRAPH_SIZE ); /* samotný graf */ generate_function(file, node, range); /* rámeček */ fprintf(file, "grestore\n" "2 setlinewidth\n" "0 0 0 setrgbcolor\n" "stroke\n" ); }