/* xygraph.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++ xygraph.cpp Usage: xygraph n size < file Input consists of x,y coordinates in 2 columns or x,y,z coordinates in 3 columns. Output is a line graph file, xygraph.bmp The first n points are black. The size defaults to 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=2*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/2, green/2, blue/2); // 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 } 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][3] vector x(3); vector > v; while (read3num(stdin, x[0], x[1], x[2])) 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<3; ++i) { double xmin=v[0][i], xmax=xmin; for (int j=1; jxmin) { scale=1/(xmax-xmin); if (i==2) three_d=true; } printf("scale=%f xmin=%f xmax=%f\n", scale, xmin, xmax); for (int j=0; j