#include #include #include #include #include "picture.h" #include "putable.h" using namespace std; const int picture::dmax; const double picture::visible = sqrt(2 * picture::cmax); /* iMicro projects a rectangle of 383 x 223 pixels. On the dome, this rectangle is stretched vertically to 62.75 x 49.5 degrees (maybe 70 x 49.333). Stretch it horizontally to compensate. */ const double picture::stretch = (383 * 49.5) / (223 * 62.75); #if 0 void picture::drawline(double x0, double y0, double x1, double y1) { if (x0 == x1 && y0 == y1) { drawpoint(x0, y0); } else if (x0 != x1 && abs((y1 - y0) / (x1 - x0)) <= 1) { int xbegin, xend; double ybase; if (x0 < x1) { xbegin = round(x0); xend = round(x1); ybase = y0; } else { xbegin = round(x1); xend = round(x0); ybase = y1; } for (int x = xbegin; x <= xend; ++x) { drawpoint(x, ybase + (y1 - y0) * (x - x0) / (x1 - x0)); } } else { int ybegin, yend; double xbase; if (y0 < y1) { ybegin = round(y0); yend = round(y1); xbase = x0; } else { ybegin = round(y1); yend = round(y0); xbase = x1; } for (int y = ybegin; y <= yend; ++y) { drawpoint(xbase + (x1 - x0) * (y - y0) / (y1 - y0), y); } } } void picture::fillcircle(double x0, double y0, double radius) { const double r2 = radius * radius; for (int x = picture::xmin; x <= picture::xmax; ++x) { for (int y = picture::ymin; y <= picture::ymax; ++y) { if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <= r2) { drawpoint(x, y); } } } } void picture::drawcircle(double x0, double y0, double radius) { const double d = radius / sqrt(2.0); const double r2 = radius * radius; for (int x = round(x0 - d); x <= round(x0 + d); ++x) { const double s = sqrt(r2 - x * x); drawpoint(x, y0 + s); drawpoint(x, y0 - s); } for (int y = round(y0 - d); y <= round(y0 + d); ++y) { const double s = sqrt(r2 - y * y); drawpoint(x0 + s, y); drawpoint(x0 - s, y); } } #endif void picture::plotpoint(xyz point, unsigned char red, unsigned char green, unsigned char blue) { point -= viewpoint; xyz dir = direction - viewpoint; //Now we can program as if the viewpoint were (0, 0, 0). /* Rotate left or right? dtheta is positive to rotate camera to the right. This will move objects to the left. */ double dtheta = dir.z != 0 ? atan2(dir.x, -dir.z) : dir.x == 0 ? 0 : dir.x > 0 ? pi / 2 : -pi / 2; point.yrot(dtheta); /* Rotate up or down? dtheta is positive to rotate camera up. This will move objects down. */ dtheta = dir.z != 0 ? atan2(dir.y, -dir.z) : dir.y == 0 ? 0 : dir.y > 0 ? pi / 2 : -pi / 2; point.xrot(-dtheta); //Now we can program as if the direction were (0, 0, -1). if (point.z <= 0) { //if the point is not behind us const double distance = sqrt(point.x * point.x + point.y * point.y + point.z * point.z); const double factor = max(distance / d, 1.0); const double x = -point.x * d / point.z; const double y = -point.y * d / point.z; drawpoint(x, y, round(red / (factor * factor)), round(green / (factor * factor)), round(blue / (factor * factor)) ); } } picture& operator<<(picture& pict, const putable& put) { for (unsigned i = 0; i < put.npoints(); ++i) { pict.plotpoint(put.point(i, pict.frameno, pict.nframes)); } return pict; } ostream& operator<<(ostream& ost, const picture& p) { system("rm -f temp.ppm"); ofstream ofs("temp.ppm"); if (!ofs) { cerr << "couldn't open temp.ppm\n"; exit(EXIT_FAILURE); } ofs << "P6\n" //magic number << picture::width << " " << picture::height << "\n" << static_cast(picture::cmax) << "\n"; //max color val for (int y = picture::height - 1; y >= 0; --y) { for (size_t x = 0; x < picture::width; ++x) { for (size_t color = 0; color < 3; ++color) { ofs << p.a[x][y][color]; } } } ofs.close(); system( "rm -f temp.gif;" "/opt/sfw/netpbm/bin/ppmquant -quiet 256 < temp.ppm | " "ppmtogif -quiet > temp.gif;" //"ppmtogif -quiet < temp.ppm > temp.gif;" "rm -f temp.ppm" ); ifstream ifs("temp.gif"); if (!ifs) { cerr << "couldn't open temp.gif\n"; exit(EXIT_FAILURE); } char c; while (ifs.get(c)) { ost.put(c); } ifs.close(); system("rm -f temp.gif"); return ost; } void picture::write(const char *outfilename, const char *comment) const { { ostringstream os; os << "rm -f " << outfilename; system(os.str().c_str()); } ofstream ofs(outfilename); if (!ofs) { cerr << "couldn't open " << outfilename << "\n"; exit(EXIT_FAILURE); } ofs << *this; ofs.close(); if (*comment != '\0') { ostringstream os; os << "gifsicle-1.44/src/gifsicle " << "--batch " //<< "--colors 256 " << "--comment='" << comment << "' " << outfilename; system(os.str().c_str()); } string original = outfilename; string filename = outfilename; const string::size_type pos = filename.rfind(".gif"); if (pos == string::npos) { cerr << "filename " << outfilename << " has no \".gif\".\n"; exit(EXIT_FAILURE); } filename.insert(pos, "_r"); //reverse system(string("rm -f " + filename + ";" "ln " + original + " " + filename + ";").c_str()); ostringstream os; os << "chmod 444 " << outfilename; system(os.str().c_str()); system(string("chmod 444 " + filename).c_str()); }