/* * Copyright (C) 1996, Christopher John Kline * Electronic mail: ckline@acm.org * * This software may be freely copied, modified, and redistributed * for academic purposes and by not-for-profit organizations, provided that * this copyright notice is preserved on all copies, and that the source * code is included or notice is given informing the end-user that the source * code is publicly available under the terms described here. * * Persons or organizations wishing to use this code or any modified version * of this code in a commercial and/or for-profit manner must contact the * author via electronic mail (preferred) or other method to arrange the terms * of usage. These terms may be as simple as giving the author visible credit * in the final product. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * If you use this software the author politely requests that you inform him via * electronic mail. * */ #include "Obstacle.h" #include #include //---------------- CLASS OBSTACLE ------------------------------ //---------------- CLASS POLYGON ------------------------------ int operator==(const Polygon &a, const Polygon &b) { int i, test; if (a.numvertices != b.numvertices) return 0; // definitely different // Check if all vertices are the same vertices. for (i=0, test=1; test && (i < a.numvertices); i++) test = test && (a.vertex[i]==b.vertex[i]); return(test); } Polygon::Polygon(const Polygon &p) { d = p.d; i1 = p.i1; i2 = p.i2; normal = p.normal; // copy all the vertices over numvertices = p.numvertices; vertex = new Vector[numvertices]; for (int i = 0; i < numvertices; i++) vertex[i] = p.vertex[i]; } Polygon::Polygon(int numverts, const Vector v0, const Vector v1, const Vector v2, ...) { Vector p; va_list arg_ptr; int i; // Set the number of vertices in the polygon and allocate the array // of vertices numvertices = numverts; vertex = new Vector[numvertices]; // set up the first 3 required vertices vertex[0] = v0; vertex[1] = v1; vertex[2] = v2; // cross product provides normal to poly normal = (vertex[1] - vertex[0]) % (vertex[2] - vertex[0]); normal.Normalize(); // plane of polygon is: (normal dot vertex[0]) + d = 0 d = -vertex[0] * normal; // Find find dominant axis of normal vector, and put the indices // of the plane perpendicular to that axis into i1 and i2. // This tells us what the closest major plane to the polygon is. // (i.e., i1==0 and i2==2 means closest plane is xz-plane) if (fabs(normal.x) > fabs(normal.y) && fabs(normal.x) > fabs(normal.z)) { i1 = 1; i2 = 2; } else if (fabs(normal.y) >= fabs(normal.x) && fabs(normal.y) >= fabs(normal.z)) { i1 = 0; i2 = 2; } else { i1 = 0; i2 = 1; } // set up the rest of them va_start(arg_ptr, v2); for (i=3; i= 0.0) && (beta <= 1.0)) { alpha = (v0 - beta*v2)/v1; inside = ((alpha >= 0.0) && (alpha+beta <= 1.0)); } } else { beta = (v0*u1 - u0*v1)/(v2*u1 - u2*v1); if ((beta >= 0.0)&&(beta <= 1.0)) { alpha = (u0 - beta*u2)/u1; inside = ((alpha >= 0.0)&&((alpha+beta) <= 1.0)); } } i++; } while ((inside == 0) && (i < numvertices)); // Ok, so there was an intersection with the polygon's plane, // but we only care if the intersection was inside the polygon data.intersectionflag = inside; // make sure to return the normal of the poly that there the ray // might be intersecting. data.normal = normal; return(data); } ostream & Polygon::Disp(ostream &strm) const { strm << "[Polygon] " << numvertices << " vertices: "; for (int i=0; iDoesRayIntersect(raydirection, rayorigin); if (data.intersectionflag == 1) { #ifdef DEBUG_OBSTACLES cerr << "Found Isect in box\n"; #endif // Find closest intersection, since the ray could intersect multiple // sides. double temp = Magnitude(data.point - rayorigin); if (temp < distToClosestIntersect) { distToClosestIntersect = temp; closestIntersect = data; #ifdef DEBUG_OBSTACLES cerr << "Closest intersect at " << closestIntersect.point << " Normal " << closestIntersect.normal << "\n"; #endif } } } return closestIntersect; } //---------------- CLASS SPHERE------------------------------ ISectData Sphere::IntersectionWithRay(const Vector &raydirection, const Vector &rayorigin) const { ISectData data; Vector rdirection = Direction(raydirection); // only want a unit vector // If the ray starts at the sphere's origin, then calculations // are trivial if (rayorigin == origin) { data.intersectionflag = 1; // The ray MUST intersect the sphere! data.point = radius*rdirection; data.normal = Direction(origin - data.point); return data; // bail out early and save time } data.intersectionflag = 0; // no intersection as default // If ray has no direction, then try to handle this // gracefully by returning with no intersection. // This situation shouldn't happen, though if (rdirection == Vector(0,0,0)) return data; // The stuff below is Adapted by Chris Kline 11/28/95 from : // // Intersection Of A Ray With A Sphere // by James Hultquist // from "Graphics Gems", Academic Press, 1990 // // Modified to handle special case when the rayorigin is // inside the sphere, which Hultquist didn't consider (because // he was only interested in raytracing the outside of spheres). // Find component of the ray from rayorigin to the // sphere's origin in the direction specified by // rdirection double v = (origin - rayorigin) * rdirection; // Find the square of the distance from the ray-sphere // intersection to the point on the ray closest to the // sphere's origin double d = pow(radius, 2) - pow(Magnitude(origin - rayorigin), 2) + pow(v, 2); // If d < 0 then there is no intersection if (d < 0) return data; // Otherwise find the intersection point if (Magnitude(rayorigin - origin) < radius) data.point = (v + sqrt(d)) * rdirection + rayorigin; /* inside sphere */ else data.point = (v - sqrt(d)) * rdirection + rayorigin; /* outside sphere */ // An intersection with the ray occured data.intersectionflag = 1; // set the normal at the point of ray-sphere intersection // (the outward-pointing normal) data.normal = Direction(data.point - origin); return data; } //---------------- CLASS OBSTACLELIST------------------------------ Obstacle * ObstacleList::Add(const Obstacle &o) { // Copies o and adds the copy to the front of the list. Returns a pointer // to the COPY (not o) obnode *n = new obnode; n->obj = o.Clone(); // tell object to make a copy of itself n->next = head; head = n; // link in new obnode return(n->obj); } Obstacle * ObstacleList::Delete(Obstacle *o) { // Deletes o from the list, and returns o if successful, or NULL // to indicate failure obnode *n, *prevn; // remove the object from the list of objects prevn = n = head; while (n) { if (n->obj == o) { (n == head) ? (head = n->next) : (prevn->next = n->next); break; } prevn = n; n = n->next; } if (n) { delete n; return(o); } else { return(NULL); // failure } }