+
+
+Disc::Disc()
+{
+ radius = 1.0;
+}
+
+Disc::Disc(const Vec3 &pt, const Vec3 &normal, float rad)
+ : Plane(pt, normal)
+{
+ radius = rad;
+}
+
+Disc::Disc(const Vec3 &normal, float dist, float rad)
+ : Plane(normal, dist)
+{
+ radius = rad;
+}
+
+bool Disc::intersect(const Ray &ray, HitPoint *hit) const
+{
+ HitPoint phit;
+ if(Plane::intersect(ray, &phit)) {
+ if(length_sq(phit.pos - pt) <= radius * radius) {
+ *hit = phit;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Disc::contains(const Vec3 &pt) const
+{
+ Vec3 pj = proj_point_plane(pt, *this);
+ return length_sq(pj - this->pt) <= radius * radius;
+}
+
+float Disc::distance(const Vec3 &v) const
+{
+ return 0.0; // TODO
+}
+
+float Disc::signed_distance(const Vec3 &v) const
+{
+ return 0.0; // TODO
+}
+
+
+Vec3 proj_point_plane(const Vec3 &pt, const Plane &plane)
+{
+ float dist = plane.signed_distance(pt);
+ return pt - plane.normal * dist;
+}
+
+// ---- bounding sphere calculations ----
+
+bool calc_bounding_sphere(Sphere *sph, const GeomObject *obj)
+{
+ switch(obj->type) {
+ case GOBJ_SPHERE:
+ *sph = *(Sphere*)obj;
+ break;
+
+ case GOBJ_AABOX:
+ sph->center = (AABOX(obj)->min + AABOX(obj)->max) * 0.5;
+ sph->radius = length(AABOX(obj)->max - AABOX(obj)->min) * 0.5;
+ break;
+
+ case GOBJ_BOX:
+ sph->center = (BOX(obj)->min + BOX(obj)->max) * 0.5 + BOX(obj)->xform.get_translation();
+ sph->radius = length(BOX(obj)->max - BOX(obj)->min) * 0.5;
+ break;
+
+ case GOBJ_PLANE:
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool calc_bounding_sphere(Sphere *sph, const GeomObject *a, const GeomObject *b)
+{
+ Sphere bsa, bsb;
+
+ if(!calc_bounding_sphere(&bsa, a) || !calc_bounding_sphere(&bsb, b)) {
+ return false;
+ }
+
+ float dist = length(bsa.center - bsb.center);
+ float surf_dist = dist - (bsa.radius + bsb.radius);
+ float d1 = bsa.radius + surf_dist / 2.0;
+ float d2 = bsb.radius + surf_dist / 2.0;
+ float t = d1 / (d1 + d2);
+
+ if(t < 0.0) t = 0.0;
+ if(t > 1.0) t = 1.0;
+
+ sph->center = bsa.center * t + bsb.center * (1.0 - t);
+ sph->radius = std::max(dist * t + bsb.radius, dist * (1.0f - t) + bsa.radius);
+ return true;
+}
+
+bool calc_bounding_sphere(Sphere *sph, const GeomObject **objv, int num)
+{
+ if(num <= 0) return false;
+
+ if(!calc_bounding_sphere(sph, objv[0])) {
+ return false;
+ }
+
+ for(int i=1; i<num; i++) {
+ if(!calc_bounding_sphere(sph, sph, objv[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool calc_bounding_sphere(Sphere *sph, const Vec3 *v, int num, const Mat4 &xform)
+{
+ if(num <= 0) return false;
+
+ sph->center = Vec3(0.0, 0.0, 0.0);
+ for(int i=0; i<num; i++) {
+ sph->center += xform * v[i];
+ }
+ sph->center /= (float)num;
+
+ float rad_sq = 0.0f;
+ for(int i=0; i<num; i++) {
+ Vec3 dir = xform * v[i] - sph->center;
+ rad_sq = std::max(rad_sq, dot(dir, dir));
+ }
+ sph->radius = sqrt(rad_sq);
+ return true;
+}
+
+bool calc_bounding_aabox(AABox *box, const GeomObject *obj)
+{
+ switch(obj->type) {
+ case GOBJ_AABOX:
+ *box = *(AABox*)obj;
+ break;
+
+ case GOBJ_BOX:
+ {
+ Vec3 v[8];
+ for(int i=0; i<8; i++) {
+ v[i] = BOX(obj)->get_corner(i);
+ }
+ calc_bounding_aabox(box, v, 8);
+ }
+ break;
+
+ case GOBJ_SPHERE:
+ {
+ float r = SPHERE(obj)->radius;
+ box->min = SPHERE(obj)->center - Vec3(r, r, r);
+ box->max = SPHERE(obj)->center + Vec3(r, r, r);
+ }
+ break;
+
+ case GOBJ_PLANE:
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool calc_bounding_aabox(AABox *box, const GeomObject *a, const GeomObject *b)
+{
+ AABox bba, bbb;
+
+ if(!calc_bounding_aabox(&bba, a) || !calc_bounding_aabox(&bbb, b)) {
+ return false;
+ }
+
+ for(int i=0; i<3; i++) {
+ box->min[i] = std::min(bba.min[i], bbb.min[i]);
+ box->max[i] = std::max(bba.max[i], bbb.max[i]);
+ }
+ return true;
+}
+
+bool calc_bounding_aabox(AABox *box, const GeomObject **objv, int num)
+{
+ if(num <= 0) return false;
+
+ if(!calc_bounding_aabox(box, objv[0])) {
+ return false;
+ }
+
+ for(int i=1; i<num; i++) {
+ if(!calc_bounding_aabox(box, box, objv[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool calc_bounding_aabox(AABox *box, const Vec3 *v, int num, const Mat4 &xform)
+{
+ if(num <= 0) return false;
+
+ box->min = box->max = xform * v[0];
+ for(int i=1; i<num; i++) {
+ Vec3 p = xform * v[i];
+
+ for(int j=0; j<3; j++) {
+ box->min[j] = std::min(box->min[j], p[j]);
+ box->max[j] = std::max(box->max[j], p[j]);
+ }
+ }
+ return true;
+}
+
+bool intersect_sphere_sphere(Disc *result, const Sphere &a, const Sphere &b)
+{
+ Vec3 dir = b.center - a.center;
+
+ float dist_sq = length_sq(dir);
+ if(dist_sq <= 1e-8) return false;
+
+ float rsum = a.radius + b.radius;
+ float rdif = fabs(a.radius - b.radius);
+ if(dist_sq > rsum * rsum || dist_sq < rdif * rdif) {
+ return false;
+ }
+
+ float dist = sqrt(dist_sq);
+ float t = (dist_sq + a.radius * a.radius - b.radius * b.radius) / (2.0 * sqrt(dist_sq));
+
+ result->pt = a.center + dir * t;
+ result->normal = dir / dist;
+ result->radius = sin(acos(t)) * a.radius;
+ return true;
+}
+
+bool intersect_plane_plane(Ray *result, const Plane &a, const Plane &b)
+{
+ return false; // TODO
+}
+
+bool intersect_sphere_plane(Sphere *result, const Sphere &s, const Plane &p)
+{
+ return false; // TODO
+}
+
+bool intersect_plane_sphere(Sphere *result, const Plane &p, const Sphere &s)
+{
+ return false; // TODO
+}
+
+bool intersect_aabox_aabox(AABox *res, const AABox &a, const AABox &b)
+{
+ for(int i=0; i<3; i++) {
+ res->min[i] = std::max(a.min[i], b.min[i]);
+ res->max[i] = std::min(a.max[i], b.max[i]);
+
+ if(res->max[i] < res->min[i]) {
+ res->max[i] = res->min[i];
+ }
+ }
+ return res->min.x != res->max.x && res->min.y != res->max.y && res->min.z != res->max.z;
+}