/* * Despite the name, this file actually implements a set of * primitive shapes, deriving from the abstract shape class * defined in 'shape.h' * Actually, just go see 'shape.h'; it'll clearly everything * right up... :-) * */ #include #include #include #include #include "shape.h" using namespace std; /* * Utility function */ int Shape::rgbToInt( const Vec3D v ) { int r = int(255*v[0]); int g = int(255*v[1]); int b = int(255*v[2]); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; if (r < 0) r = 0; if (g < 0) g = 0; if (b < 0) b = 0; return (r << 16) + (g << 8) + b; } //********* SPHERE *********************************************************// /* * Default constructor * Does nothing, so you better not use it :-) */ Sphere::Sphere() {} /* * Constructor, colour not specified */ Sphere::Sphere(double _cx, double _cy, double _cz, double _radius) { #ifdef DEBUG cout << "No colour constructor" << endl; #endif c.setValues(_cx, _cy, _cz); radius = _radius; // Assign a random colour srand(time(NULL)); double r = (rand()/(RAND_MAX+1.0)); double g = (rand()/(RAND_MAX+1.0)); double b = (rand()/(RAND_MAX+1.0)); col = Vec3D(r,g,b); ref = 0.7; setTexture(0,NULL); #ifdef DEBUG cout << "Sphere colour: " << r << ":" << g << ":" << b << endl; #endif } /* * Constructor, everything given */ Sphere::Sphere(double _cx, double _cy, double _cz, double _radius, double _r, double _g, double _b) { #ifdef DEBUG cout << "Colour constructor" << endl; #endif c.setValues(_cx, _cy, _cz); radius = _radius; col = Vec3D(_r,_g,_b); ref = 0.2; srand(time(NULL)); double **tx = new double*[64]; for (int i=0; i<64; ++i) { tx[i] = new double[64]; for (int j=0; j<64; ++j) tx[i][j] = double(i ^ j) / 64; } setTexture(64,tx); } void Sphere::print() { cout << "[Sphere "; c.print(); cout <<" radius:"<print(); cout << " intersects "; ray.print(); cout << " at "; res->print(); cout << endl; #endif #endif return res; } double Sphere::intensityAt( const Vec3D p ) const { // all n values should lie on [0,1) if (tex == NULL || texSize == 0) return 1; Vec3D n = (normalAt( p ).norm() + Vec3D(1,1,1)) / 2; int u = int(n[0]*texSize); if (u >= texSize) u = texSize-1; if (u < 0) u = 0; int v = int(n[1]*texSize); if (v >= texSize) v = texSize-1; if (v < 0) v = 0; return tex[u][v]; } //********* PLANE **********************************************************// /* * Default constructor * Does nothing, so you better not use it :-) */ Plane::Plane() {} /* * Constructor, colour not specified */ Plane::Plane(Vec3D _p1, Vec3D _p2, Vec3D _p3, Vec3D _p4) { p1 = _p1, p2 = _p2, p3 = _p3, p4 = _p4; // Assign a random colour srand(time(NULL)); double r = (rand()/(RAND_MAX+1.0)); double g = (rand()/(RAND_MAX+1.0)); double b = (rand()/(RAND_MAX+1.0)); col = Vec3D(r,g,b); #ifdef DEBUG cout << "Plane colour: " << r << ":" << g << ":" << b << endl; #endif } /* * Constructor, everything given */ Plane::Plane(Vec3D _p1, Vec3D _p2, Vec3D _p3, Vec3D _p4, double _r, double _g, double _b) { p1 = _p1, p2 = _p2, p3 = _p3, p4 = _p4; col = Vec3D(_r,_g,_b); } void Plane::print() { cout << "[Plane "; p1.print(); cout << " "; p2.print(); cout << " "; p3.print(); cout << " "; p4.print(); cout << "]"; } /* * Returns intersection point iff the given ray intersects me (a plane) * otherwise returns NULL */ Vec3D* Plane::rayIntersectsMe(const Ray& ray) { Vec3D* res = NULL; // poi must lie on ray, then poi = o + t(d - o) for some t // point must also lie on plane, i.e. (poi - p1) dot normal = 0 Vec3D n = normalAt(p1).norm(); Vec3D o = ray.getOrig(); Vec3D d = ray.getDir(); double den = (d - o).dot(n); if (fabs(den) < 1e-9) return res; // no intersection double num = (p1 - o).dot(n); res = new Vec3D(o + (d - o)*(num/den)); // make sure res is within patch Vec3D resp1 = (p1 - *res).norm(); Vec3D resp2 = (p2 - *res).norm(); Vec3D resp3 = (p3 - *res).norm(); Vec3D resp4 = (p4 - *res).norm(); double ang = (acos(resp1.dot(resp2)) + acos(resp2.dot(resp3)) + acos(resp3.dot(resp4)) + acos(resp4.dot(resp1)))*180.0/3.1415926535; if (ang < 360) return NULL; return res; } //********* CYLINDER *******************************************************// /* * Default constructor * Does nothing, so you better not use it :-) */ Cylinder::Cylinder() {} /* * Constructor, colour not specified */ Cylinder::Cylinder(double _z, double _radius, double _uy, double _ly) { z = _z, radius = _radius, uy = _uy, ly = _ly; // Assign a random colour srand(time(NULL)); double r = (rand()/(RAND_MAX+1.0)); double g = (rand()/(RAND_MAX+1.0)); double b = (rand()/(RAND_MAX+1.0)); col = Vec3D(r,g,b); #ifdef DEBUG cout << "Cylinder colour: " << r << ":" << g << ":" << b << endl; #endif } /* * Constructor, everything given */ Cylinder::Cylinder(double _z, double _radius, double _uy, double _ly, double _r, double _g, double _b) { z = _z, radius = _radius, uy = _uy, ly = _ly; col = Vec3D(_r,_g,_b); ref = 0.3; print(); } void Cylinder::print() { cout << "[Cylinder z: " << z << " radius: " << radius; cout<< " uy: " << uy << " ly: " << ly << "]" << endl; } /* * Returns intersection point iff the given ray intersects me (a cylinder) * otherwise returns NULL */ Vec3D* Cylinder::rayIntersectsMe(const Ray& ray) { Vec3D o = ray.getOrig(); Vec3D d = ray.getDir(); double a = pow(d.getV0(), 2) + pow(d.getV2(), 2); double b = 2*o.getV0()*d.getV0() + 2*o.getV2()*d.getV2(); double c = pow(o.getV0(), 2) + pow(o.getV2(), 2) - radius*radius; // solve quadratic double disc = b*b - 4*a*c; if (disc < 0) return NULL; //no intersection double t1 = (b*-1 + pow(disc, 0.5))/(2*a); double t2 = (b*-1 - pow(disc, 0.5))/(2*a); // see if these give answers within cylinder Vec3D * res1, * res2; res1 = new Vec3D((o + (d - o)*t1)); res2 = new Vec3D((o + (d - o)*t2)); //cout << "res1: "; res1->print(); cout << endl; //cout << "res2: "; res2->print(); cout << endl; double y1 = res1->getV1(), y2 = res1->getV1(); if (y2 <= uy && y2 >= ly && y1 <= uy && y1 >= ly) { if (res1->getV2() < res2->getV2()) return res1; else return res2; } if (y1 <= uy && y1 >= ly && !(y2 <= uy && y2 >= ly)) { return res1; } else if (y2 <= uy && y2 >= ly && !(y1 <= uy && y1 >= ly)) { return res2; } return NULL; }