#include #include #include #include #include #include #include "ImageFmtc.h" #define SQR(x) ((x)*(x)) #define NELEM(a) ((int)(sizeof (a) / sizeof (*(a)))) struct Node { int idx; double coord_x; double coord_y; }; void fuzzyline(unsigned char *image, int w, int h, double x1, double y1, double x2, double y2); void get_string(char **dst, const char *src); void get_node(struct Node *dst, const char *src); void get_index(int *dst, const char *src); void do_error(const char *fmat, ...); int main(int argc, char **argv) { FILE *parfp, *tourfp, *probfp; char *tourfname = NULL; char *probfname = NULL; double scale_factor; char buf[1000]; int num_nodes = 0; struct Node *nodes; int *indices; int i; if (argc != 3) do_error("usage: imagetour "); scale_factor = strtod(argv[2], NULL); if (scale_factor <= 1e-10) do_error("Scale factor %g too small!", scale_factor); if ((parfp = fopen(argv[1], "r")) == NULL) do_error("Can't open parfile '%s'!", argv[1]); while (fgets(buf, sizeof buf, parfp) != NULL) { buf[strlen(buf)-1] = '\0'; if (0 == strncmp(buf, "TOUR_FILE", strlen("TOUR_FILE"))) { get_string(&tourfname, buf); } else if (0 == strncmp(buf, "PROBLEM_FILE", strlen("PROBLEM_FILE"))) { get_string(&probfname, buf); } } if (!probfname || !tourfname) do_error("Can't find input filenames!"); if ((tourfp = fopen(tourfname, "r")) == NULL) do_error("Can't open tourfile '%s'!", tourfname); if ((probfp = fopen(probfname, "r")) == NULL) do_error("Can't open probfile '%s'!", probfname); /* Get the problem. */ while (fgets(buf, sizeof buf, probfp) != NULL) { buf[strlen(buf)-1] = '\0'; if (0 == strncmp(buf, "DIMENSION", strlen("DIMENSION"))) { char *tmp; get_string(&tmp, buf); num_nodes = atoi(tmp); if (num_nodes <= 0) do_error("Bad dimension!"); } else if (0 == strncmp(buf, "NODE_COORD_SECTION", strlen("NODE_COORD_SECTION"))) { break; } } if (feof(probfp)) do_error("No nodes found!"); if (num_nodes <= 0) do_error("No dimension found before NODE_COORD_SECTION!"); nodes = malloc(num_nodes * sizeof *nodes); for (i=0; i < num_nodes; ++i) { if (fgets(buf, sizeof buf, probfp) == NULL) do_error("Unexpected end of file in NODE_COORD_SECTION!"); get_node(&nodes[i], buf); } printf("Read %d nodes.\n", num_nodes); /* Get the tour. */ while (fgets(buf, sizeof buf, tourfp) != NULL) { buf[strlen(buf)-1] = '\0'; if (0 == strncmp(buf, "DIMENSION", strlen("DIMENSION"))) { char *tmp; get_string(&tmp, buf); if (atoi(tmp) != num_nodes) do_error("Tour dimension doesn't match problem dimension!"); } else if (0 == strncmp(buf, "TOUR_SECTION", strlen("TOUR_SECTION"))) { break; } } if (feof(tourfp)) do_error("No nodes found!"); indices = malloc(num_nodes * sizeof *indices); for (i=0; i < num_nodes; ++i) { if (fgets(buf, sizeof buf, tourfp) == NULL) do_error("Unexpected end of file in TOUR_SECTION!"); get_index(&indices[i], buf); } printf("Read %d nodes in the tour, too!\n", num_nodes); { double minx, miny, maxx, maxy; double x_range, y_range; int w, h; unsigned char *image; minx = maxx = nodes[0].coord_x; miny = maxy = nodes[0].coord_y; for (i=1; i < num_nodes; ++i) { if (nodes[i].coord_x < minx) minx = nodes[i].coord_x; if (nodes[i].coord_y < miny) miny = nodes[i].coord_y; if (nodes[i].coord_x > maxx) maxx = nodes[i].coord_x; if (nodes[i].coord_y > maxy) maxy = nodes[i].coord_y; } x_range = maxx-minx; y_range = maxy-miny; w = (int)(10.5 + scale_factor*x_range); h = (int)(10.5 + scale_factor*y_range); printf("x_range=%g y_range=%g\n", x_range, y_range); printf("Scale factor=%g\n", scale_factor); printf("Image width=%d, height=%d\n", w, h); if ((image = calloc(w*h, sizeof *image)) == NULL) do_error("Out of memory!"); for (i=0; i < num_nodes-1; ++i) { fuzzyline(image, w, h, 5+scale_factor*(nodes[indices[i]-1].coord_x-minx), 5+scale_factor*(nodes[indices[i]-1].coord_y-miny), 5+scale_factor*(nodes[indices[i+1]-1].coord_x-minx), 5+scale_factor*(nodes[indices[i+1]-1].coord_y-miny) ); } fuzzyline(image, w, h, 5+scale_factor*(nodes[indices[i]-1].coord_x-minx), 5+scale_factor*(nodes[indices[i]-1].coord_y-miny), 5+scale_factor*(nodes[indices[0]-1].coord_x-minx), 5+scale_factor*(nodes[indices[0]-1].coord_y-miny) ); puts("Writing image..."); WritePGM5("imagetour.pgm", image, w, h); free(image); } free(nodes); free(indices); return 0; } void get_string(char **dst, const char *src) { static char buffers[10][100]; static int bufidx = 0; int i=0; while (!isspace(src[i])) ++i; while (isspace(src[i]) || ispunct(src[i])) ++i; strncpy(buffers[bufidx], src+i, sizeof buffers[bufidx]); *dst = buffers[bufidx]; bufidx = (bufidx+1) % NELEM(buffers); return; } void get_node(struct Node *dst, const char *src) { sscanf(src, "%d%lf%lf", &dst->idx, &dst->coord_x, &dst->coord_y); return; } void get_index(int *dst, const char *src) { sscanf(src, "%d", dst); return; } void fuzzyline(unsigned char *image, int w, int h, double x1, double y1, double x2, double y2) { int minx = (x1 < x2)? x1-2: x2-2; int maxx = (x1 > x2)? x1+3: x2+3; int miny = (y1 < y2)? y1-2: y2-2; int maxy = (y1 > y2)? y1+3: y2+3; int i, j; const double SQRTPI2 = sqrt(3.14/2); const double ux = x2-x1; const double uy = y2-y1; if (minx < 0) minx = 0; if (miny < 0) miny = 0; if (maxx > w) maxx = w; if (maxy > h) maxy = h; for (j=miny; j < maxy; ++j) { for (i=minx; i < maxx; ++i) { const double vx = i-x1; const double vy = j-y1; double dist2; int to_add, result; if (fabs(ux) < 1e-10 && fabs(uy) < 1e-10) { dist2 = SQR(vx)+SQR(vy); } else { double q = (vx*ux + vy*uy) / (SQR(ux)+SQR(uy)); if (q < 0.0) q = 0.0; else if (q > 1.0) q = 1.0; dist2 = SQR(i - ((1-q)*x1 + q*x2)) + SQR(j - ((1-q)*y1 + q*y2)); } to_add = (dist2 >= SQRTPI2)? 0: 255*(1.0-sin(dist2)); result = (image[j*w+i] > to_add)? image[j*w+i]: to_add; image[j*w+i] = (result > 255)? 255: result; } } } void do_error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); putchar('\n'); va_end(ap); exit(EXIT_FAILURE); }