/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #ifndef _MOOF_SPHERE_HH_ #define _MOOF_SPHERE_HH_ /** * \file sphere.hh * A round shape like a circle or sphere. * TODO: This class needs some work. */ #include #include #include #include #include #include #include namespace moof { /** * A round object. */ template struct sphere : public cullable, public drawable, public shape { typedef moof::vector< scalar, fixed > vector; vector point; scalar radius; sphere() {} sphere(const vector& p, scalar r) : point(p), radius(r) {} void init(const vector& p, scalar r) { point = p; radius = r; } void init(const vector& p, const vector& o) { point = p; radius = (o - p).length(); } //void enclose_vertices(const vector vertices[], unsigned count); //void draw(scalar alpha = 0.0) const; //bool is_visible(const frustum& frustum) const; void enclose_vertices(const vector vertices[], unsigned count) { // TODO } void draw(scalar alpha = 0.0) const; bool is_visible(const frustum& frustum) const { return true; } bool intersect(const sphere& sphere, contact& hit) const { vector n = sphere.point - point; scalar distance = n.length(); scalar limit = radius + sphere.radius; if (distance > limit) return false; hit.normal = n.normalize(); hit.distance = limit - distance; hit.point = hit.normal * radius; return true; } bool intersect(const vector& point2, contact& hit) const { vector n = point2 - point; scalar distance = n.length(); if (distance > radius) return false; hit.normal = n.normalize(); hit.distance = radius - distance; hit.point = point2; return true; } // a ray inside the sphere will not intersect on its way out bool intersect(const ray& ray, typename moof::ray::contact& hit) const { vector b = point - ray.point; scalar z = dot(b, ray.direction); // check if the ball is behind the ray if (z < SCALAR(0.0)) return false; scalar d2 = dot(b, b) - z*z; scalar r2 = radius * radius; // check for an intersection if (d2 > r2) return false; hit.distance = z - std::sqrt(r2 - d2); if (hit.distance < SCALAR(0.0)) return false; vector surfacePoint; ray.solve(surfacePoint, hit.distance); hit.normal = surfacePoint - point; return true; } }; template <> inline bool sphere<3>::is_visible(const frustum& frustum) const { return frustum.contains(*this); } template <> inline void sphere<2>::draw(scalar alpha) const { GLUquadricObj* sphereObj = gluNewQuadric(); gluQuadricDrawStyle(sphereObj, GLU_LINE); glPushMatrix(); glTranslate(promote(point)); gluSphere(sphereObj, GLdouble(radius), 16, 16); glPopMatrix(); gluDeleteQuadric(sphereObj); } template <> inline void sphere<3>::draw(scalar alpha) const { GLUquadricObj* sphereObj = gluNewQuadric(); gluQuadricDrawStyle(sphereObj, GLU_LINE); glPushMatrix(); glTranslate(point); gluSphere(sphereObj, GLdouble(radius), 16, 16); glPopMatrix(); gluDeleteQuadric(sphereObj); } template inline bool checkCollision(const sphere& a, const sphere& b) { scalar d = (a.point - b.point).length(); return d < (a.radius + b.radius); } typedef sphere<2> sphere2; typedef sphere2 circle; typedef sphere<3> sphere3; } // namespace moof #endif // _MOOF_SPHERE_HH_