#include "length.h" #include "grid.h" #include #include #include #include struct input { grid data; depth data_zsize; int x, y, z, xsize, ysize, zsize; input(): x(0), y(0), z(0), xsize(0), ysize(0), zsize(0) { } }; void read_input(char* arg, input* in) { read_pgm(strtok(arg, "@"), &in->data, &in->data_zsize); while (char* param = strtok(NULL, ",")) { if (!strncmp(param, "x=", 2)) in->x = parse_length(param + 2); else if (!strncmp(param, "y=", 2)) in->y = parse_length(param + 2); else if (!strncmp(param, "z=", 2)) in->z = parse_length(param + 2); else if (!strncmp(param, "xsize=", 6)) in->xsize = parse_length(param + 6); else if (!strncmp(param, "ysize=", 6)) in->ysize = parse_length(param + 6); else if (!strncmp(param, "zsize=", 6)) in->zsize = parse_length(param + 6); else { fprintf(stderr, "invalid parameter: %s\n", param); exit(2); } if (in->xsize < 0 || in->ysize < 0 || in->zsize < 0) { fprintf(stderr, "negative size: %s\n", param); exit(2); } } // infer image dimensions from the sizes provided if (in->xsize) { if (!in->ysize) in->ysize = in->xsize * ysize(in->data) / xsize(in->data); if (!in->zsize) in->zsize = in->xsize * in->data_zsize / xsize(in->data); } else if (in->ysize) { if (!in->xsize) in->xsize = in->ysize * xsize(in->data) / ysize(in->data); if (!in->zsize) in->zsize = in->ysize * in->data_zsize / ysize(in->data); } else if (in->zsize) { if (!in->xsize) in->xsize = in->zsize * xsize(in->data) / in->data_zsize; if (!in->ysize) in->ysize = in->zsize * xsize(in->data) / in->data_zsize; } else { in->xsize = xsize(in->data); in->ysize = ysize(in->data); in->zsize = in->data_zsize; } } // add image "in" on top of image "out" void add_input(input const& in, grid* out) { // expand the target image, if necessary resize(std::max(in.x + in.xsize, xsize(*out)), std::max(in.y + in.ysize, ysize(*out)), out); int in_max_x = xsize(in.data) - 1, max_x = in.xsize - 1; int in_max_y = ysize(in.data) - 1, max_y = in.ysize - 1; double zscale = 0; if (in.data_zsize > 1) zscale = double(in.zsize - 1) / (in.data_zsize - 1); // should really do something better than linear interpolation. for (int x = std::max(0, -in.x); x <= max_x; ++x) { for (int y = std::max(0, -in.y); y <= max_y; ++y) { int in_x = max_x ? x * in_max_x / max_x : 0; int in_y = max_y ? y * in_max_y / max_y : 0; int dx = max_x ? x * in_max_x % max_x : 0; int dy = max_y ? y * in_max_y % max_y : 0; double sum = 0, weight = 0; if (in.data[in_x][in_y] < BOTTOM) { sum += double(in.data[in_x][in_y]) * (max_x - dx) * (max_y - dy); weight += (max_x - dx) * (max_y - dy); } if (dx && in.data[in_x + 1][in_y] < BOTTOM) { sum += double(in.data[in_x + 1][in_y]) * dx * (max_y - dy); weight += dx * (max_y - dy); } if (dy && in.data[in_x][in_y + 1] < BOTTOM) { sum += double(in.data[in_x][in_y + 1]) * (max_x - dx) * dy; weight += (max_x - dx) * dy; } if (dx && dy && in.data[in_x + 1][in_y + 1] < BOTTOM) { sum += double(in.data[in_x + 1][in_y + 1]) * dx * dy; weight += dx * dy; } if (weight) { depth* pixel = &(*out)[x + in.x][y + in.y]; *pixel = std::min(*pixel, depth(in.z + sum / weight * zscale)); } } } } int main(int argc, char** argv) { if (argc < 2) { fprintf(stderr, "usage: %s input.pgm@placement ... > out.pgm\n" "placement: x=N,y=N,z=N,xsize=N,ysize=N,zsize=N\n" "coordinates: +x=right, +y=back (image up), +z=down (image darker)\n" "units for N: px (default), mm, in\n", argv[0]); return 2; } grid out; for (int i = 1; i < argc; ++i) { input in; read_input(argv[i], &in); add_input(in, &out); } write_pgm(out, NULL); return 0; }