129 lines
3.1 KiB
C++
129 lines
3.1 KiB
C++
#ifndef SPHERE3_H
|
|
#define SPHERE3_H
|
|
|
|
#include "Point3.h"
|
|
#include "Ray3.h"
|
|
|
|
#include <vector>
|
|
|
|
|
|
struct Sphere3 {
|
|
|
|
Point3 center;
|
|
|
|
float radius;
|
|
|
|
/** empty ctor */
|
|
Sphere3() : center(), radius(0) {;}
|
|
|
|
/** ctor */
|
|
Sphere3(const Point3 center, const float radius) : center(center), radius(radius) {;}
|
|
|
|
/** create a sphere that fully contains the given point-set */
|
|
static Sphere3 around(const std::vector<Point3>& lst) {
|
|
|
|
// NOT OPTIMAL but fast
|
|
Point3 sum(0,0,0);
|
|
for (const Point3 p : lst) {sum += p;}
|
|
const Point3 center = sum / lst.size();
|
|
float radius = 0;
|
|
for (const Point3 p : lst) {
|
|
const float dist = center.getDistance(p);
|
|
if (dist > radius) {radius = dist;}
|
|
}
|
|
return Sphere3(center, radius);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Sphere3 join(const Sphere3& a, const Sphere3& b) {
|
|
|
|
if (a.contains(b)) {return a;}
|
|
if (b.contains(a)) {return b;}
|
|
|
|
Point3 newCen = (a.center + b.center) / 2;
|
|
float newRad = (a.center.getDistance(b.center) + std::max(a.radius, b.radius) * 2) / 2;
|
|
return Sphere3(newCen, newRad);
|
|
}
|
|
|
|
/** does this sphere contain the given sphere? */
|
|
bool contains(const Sphere3& o) const {
|
|
return (o.center.getDistance(this->center) + o.radius) < this->radius;
|
|
}
|
|
|
|
/** does the sphere contain the given point? */
|
|
bool contains(const Point3& p) const {
|
|
return center.getDistance(p) <= radius;
|
|
}
|
|
|
|
bool intersects(const Ray3& ray) const {
|
|
|
|
if (contains(ray.start)) {return true;}
|
|
|
|
/*
|
|
// https://stackoverflow.com/questions/6533856/ray-sphere-intersection
|
|
|
|
const float xA = ray.start.x;
|
|
const float yA = ray.start.y;
|
|
const float zA = ray.start.z;
|
|
|
|
const float xB = (ray.start + ray.dir).x;
|
|
const float yB = (ray.start + ray.dir).y;
|
|
const float zB = (ray.start + ray.dir).z;
|
|
|
|
const float xC = center.x;
|
|
const float yC = center.y;
|
|
const float zC = center.z;
|
|
|
|
const float a = (xB-xA)*(xB-xA)+(yB-yA)*(yB-yA)+(zB-zA)*(zB-zA);
|
|
const float b = 2*((xB-xA)*(xA-xC)+(yB-yA)*(yA-yC)+(zB-zA)*(zA-zC));
|
|
const float c = (xA-xC)*(xA-xC)+(yA-yC)*(yA-yC)+(zA-zC)*(zA-zC)-(radius*radius);
|
|
|
|
const float delta = (b*b) - (4*a*c);
|
|
|
|
// intersection?
|
|
return delta >= 0;
|
|
*/
|
|
|
|
|
|
// http://www.ccs.neu.edu/home/fell/CSU540/programs/RayTracingFormulas.htm
|
|
|
|
const double x0 = ray.start.x;
|
|
const double y0 = ray.start.y;
|
|
const double z0 = ray.start.z;
|
|
|
|
const double cx = center.x;
|
|
const double cy = center.y;
|
|
const double cz = center.z;
|
|
|
|
const double dx = ray.dir.x;
|
|
const double dy = ray.dir.y;
|
|
const double dz = ray.dir.z;
|
|
|
|
const double a = dx*dx + dy*dy + dz*dz;
|
|
const double b = 2*dx*(x0-cx) + 2*dy*(y0-cy) + 2*dz*(z0-cz);
|
|
const double c = cx*cx + cy*cy + cz*cz + x0*x0 + y0*y0 + z0*z0 + -2*(cx*x0 + cy*y0 + cz*z0) - radius*radius;
|
|
|
|
const double discriminant = (b*b) - (4*a*c);
|
|
return discriminant >= 0;
|
|
|
|
|
|
/*
|
|
// http://www.pixelnerve.com/v/2009/02/08/ray-sphere-intersection/
|
|
const float a = ray.dir.length();
|
|
//if (a == 0.0) return 0;
|
|
const float b = 2.0f * ( dot(ray.start, ray.dir) - dot(ray.dir, center)) ;
|
|
const Point3 tempDiff = center - ray.start;
|
|
const float c = tempDiff.length() - (radius*radius);
|
|
const float disc = b * b - 4 * a * c;
|
|
return disc >= 0.0f;
|
|
*/
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif // SPHERE3_H
|