/* boxgraph.cpp - line graph program Copyright (C) 2004, Matt Mahoney. This program is distributed without warranty under terms of the GNU general public license. See http://www.gnu.org/licenses/gpl.txt To compile: g++ boxgraph.cpp Usage: boxgraph [n=0 [size=400]] < file Input consists of x, rx, y, ry coordinates in 2 columns or x, rx, y, ry, z, rz coordinates in 3 columns, where x,y,z reprsent centers of boxes and rx, ry, rz reprsent radii (1/2 width). Output is a 2-D or 3-D graph, boxgraph.bmp, with successive boxes going from red to blue. The first n boxes are black. The size defaults to 400 by 400 pixels. */ #include #include #include #include #include #include #include #include using namespace std; template inline int size(const T& t) {return t.size();} // Image - can be drawn to, and saved as a .bmp file class Image { public: // Construct with size w by h pixels with initial color 0=black, 255=white Image(int w, int h, int color=255): pixels(w*h*3), width(w), height(h) { fill(pixels.begin(), pixels.end(), color); } void saveBMP(const char *filename); // Save as .bmp file // Add colors (-255 to 255) to pixel at x,y (origin at lower left) void put(int x, int y, int red, int green, int blue) { if (x<0 || x>=width || y<0 || y>=width) return; const int i=(y*width+x)*3; int c=pixels[i]+blue; pixels[i]=c>255?255:c<0?0:c; c=pixels[i+1]+green; pixels[i+1]=c>255?255:c<0?0:c; c=pixels[i+2]+red; pixels[i+2]=c>255?255:c<0?0:c; } void put(int x, int y, int color) {put(x, y, color, color, color);} int getwidth() const {return width;} // in pixels int getheight() const {return height;} // in pixels private: vector pixels; // width * height * blue-green-red (3 bytes) int width, height; // Image size in pixels void out2(FILE *f, int x) {fprintf(f, "%c%c", x, x>>8);} // Write 2 bytes void out4(FILE *f, unsigned long x) // Write 4 bytes, LSB first {fprintf(f, "%c%c%c%c", int(x), int(x>>8), int(x>>16), int(x>>24));} }; // Save as a .bmp file void Image::saveBMP(const char *filename) { FILE *f=fopen(filename, "wb"); if (!f) { perror(filename); return; } fprintf(f,"BM"); // magic number for .bmp files out4(f, 54+pixels.size()); // file size out4(f, 0); // reserved out4(f, 54); // offset to start of image (no palette) out4(f, 40); // info header size out4(f, width); // image size in pixels out4(f, height); out2(f, 1); // image planes out2(f, 24); // output bits per pixel out4(f, 0); // no compression out4(f, width*height*3); // image size in bytes out4(f, 3000); // x pixels per meter out4(f, 3000); // y pixels per meter out4(f, 0x1000000); // colors out4(f, 0x1000000); // important colors for (int i=0; i0) { const double step=1/(len*(1+g.getwidth()+g.getheight())); for (double t=0; t<=1; t+=step) drawpoint(g, t*x1+(1-t)*x2, t*y1+(1-t)*y2, red, green, blue); } } // Draw in 3-D perspective from (x1,y1,z1) to (x2,y2,z2) void draw3d(Image& g, double x1, double y1, double z1, double x2, double y2, double z2, int red, int green, int blue) { const double ZX=0.3, ZY=0.2; // perspective angle const double len=0.25*sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)); drawline(g, x1*(1-ZX)+(z1)*ZX, y1*(1-ZY)+(z1)*ZY, x2*(1-ZX)+(z2)*ZX, y2*(1-ZY)+(z2)*ZY, red, green, blue); // line drawline(g, x1*(1-ZX)+(z1)*ZX, (z1)*ZY, x2*(1-ZX)+(z2)*ZX, (z2)*ZY, red/8, green/8, blue/8); // shadow drawline(g, x1*(1-ZX)+(z1)*ZX, y1*(1-ZY)+(z1)*ZY, x1*(1-ZX)+(z1)*ZX, (z1)*ZY, int(red*len), int(green*len), int(blue*len)); // projection to shadow } void drawbox(Image& g, double x, double y, double rx, double ry, int red, int green, int blue) { drawline(g, x-rx, y-ry, x+rx, y-ry, red, green, blue); drawline(g, x-rx, y-ry, x-rx, y+ry, red, green, blue); drawline(g, x+rx, y+ry, x+rx, y-ry, red, green, blue); drawline(g, x+rx, y+ry, x-rx, y+ry, red, green, blue); } void draw3dbox(Image& g, double x, double y, double z, double rx, double ry, double rz, int red, int green, int blue) { draw3d(g, x-rx, y-ry, z-rz, x+rx, y-ry, z-rz, red, green, blue); draw3d(g, x-rx, y-ry, z-rz, x-rx, y+ry, z-rz, red, green, blue); draw3d(g, x-rx, y-ry, z-rz, x-rx, y-ry, z+rz, red, green, blue); draw3d(g, x+rx, y-ry, z-rz, x+rx, y+ry, z-rz, red, green, blue); draw3d(g, x+rx, y-ry, z-rz, x+rx, y-ry, z+rz, red, green, blue); draw3d(g, x-rx, y+ry, z-rz, x+rx, y+ry, z-rz, red, green, blue); draw3d(g, x-rx, y+ry, z-rz, x-rx, y+ry, z+rz, red, green, blue); draw3d(g, x-rx, y-ry, z+rz, x+rx, y-ry, z+rz, red, green, blue); draw3d(g, x-rx, y-ry, z+rz, x-rx, y+ry, z+rz, red, green, blue); draw3d(g, x+rx, y+ry, z-rz, x+rx, y+ry, z+rz, red, green, blue); draw3d(g, x-rx, y+ry, z+rz, x+rx, y+ry, z+rz, red, green, blue); draw3d(g, x+rx, y-ry, z+rz, x+rx, y+ry, z+rz, red, green, blue); } int main(int argc, char** argv) { const int n=argc>1?atoi(argv[1]):0; // number of black lines const int image_size=argc>2?atoi(argv[2]):400; // image size bool three_d=false; // 3D? // Read data into v[n][6] vector x(6); vector > v; while (read6num(stdin, x[0], x[1], x[2], x[3], x[4], x[5])) v.push_back(x); if (size(v)<1) { printf("No input data\n"); return 1; } // Scale to range 0-1 for (int i=0; i<6; i+=2) { double xmin=v[0][i]-v[0][i+1], xmax=v[0][i]+v[0][i+1]; for (int j=1; jxmin) { scale=1/(xmax-xmin); if (i==4) three_d=true; } printf("scale=%f xmin=%f xmax=%f\n", scale, xmin, xmax); for (int j=0; j0) draw3d(g, v[i-1][0], v[i-1][2], v[i-1][4], v[i][0], v[i][2], v[i][4], red, green, blue); draw3dbox(g, v[i][0], v[i][2], v[i][4], v[i][1], v[i][3], v[i][5], red, green, blue); } else { if (i>0) drawline(g, v[i-1][0], v[i-1][2], v[i][0], v[i][2], red, green, blue); drawbox(g, v[i][0], v[i][2], v[i][1], v[i][3], red, green, blue); } } g.saveBMP("boxgraph.bmp"); fprintf(stderr, "Created boxgraph.bmp\n"); return 0; }