-#include <assert.h>
-#include <float.h>
#include <algorithm>
+#include <float.h>
#include "geom.h"
GeomObject::~GeomObject()
this->radius = radius;
}
-void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
+GeomObjectType Sphere::get_type() const
{
- const Sphere *sph1 = dynamic_cast<const Sphere*>(obj1);
- const Sphere *sph2 = dynamic_cast<const Sphere*>(obj2);
+ return GOBJ_SPHERE;
+}
- if(!sph1 || !sph2) {
+void Sphere::set_union(const GeomObject *obj1, const GeomObject *obj2)
+{
+ if(obj1->get_type() != GOBJ_SPHERE || obj2->get_type() != GOBJ_SPHERE) {
fprintf(stderr, "Sphere::set_union: arguments must be spheres");
return;
}
+ const Sphere *sph1 = (const Sphere*)obj1;
+ const Sphere *sph2 = (const Sphere*)obj2;
float dist = length(sph1->center - sph2->center);
float surf_dist = dist - (sph1->radius + sph2->radius);
return true;
}
+bool Sphere::contains(const Vec3 &pt) const
+{
+ return length_sq(pt - center) <= radius * radius;
+}
+
+float Sphere::distance(const Vec3 &v) const
+{
+ return length(v - center) - radius;
+}
AABox::AABox()
{
{
}
-void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
+GeomObjectType AABox::get_type() const
{
- const AABox *box1 = dynamic_cast<const AABox*>(obj1);
- const AABox *box2 = dynamic_cast<const AABox*>(obj2);
+ return GOBJ_AABOX;
+}
- if(!box1 || !box2) {
+void AABox::set_union(const GeomObject *obj1, const GeomObject *obj2)
+{
+ if(obj1->get_type() != GOBJ_AABOX || obj2->get_type() != GOBJ_AABOX) {
fprintf(stderr, "AABox::set_union: arguments must be AABoxes too\n");
return;
}
+ const AABox *box1 = (const AABox*)obj1;
+ const AABox *box2 = (const AABox*)obj2;
min.x = std::min(box1->min.x, box2->min.x);
min.y = std::min(box1->min.y, box2->min.y);
void AABox::set_intersection(const GeomObject *obj1, const GeomObject *obj2)
{
- const AABox *box1 = dynamic_cast<const AABox*>(obj1);
- const AABox *box2 = dynamic_cast<const AABox*>(obj2);
-
- if(!box1 || !box2) {
+ if(obj1->get_type() != GOBJ_AABOX || obj2->get_type() != GOBJ_AABOX) {
fprintf(stderr, "AABox::set_intersection: arguments must be AABoxes too\n");
return;
}
+ const AABox *box1 = (const AABox*)obj1;
+ const AABox *box2 = (const AABox*)obj2;
for(int i=0; i<3; i++) {
min[i] = std::max(box1->min[i], box2->min[i]);
return true;
}
return false;
+}
+
+bool AABox::contains(const Vec3 &v) const
+{
+ return v.x >= min.x && v.y >= min.y && v.z >= min.z &&
+ v.x <= max.x && v.y <= max.y && v.z <= max.z;
+}
+float AABox::distance(const Vec3 &v) const
+{
+ return 0.0; // TODO
}
+
Plane::Plane()
: normal(0.0, 1.0, 0.0)
{
pt = this->normal * dist;
}
+GeomObjectType Plane::get_type() const
+{
+ return GOBJ_PLANE;
+}
+
void Plane::set_union(const GeomObject *obj1, const GeomObject *obj2)
{
fprintf(stderr, "Plane::set_union undefined\n");
return true;
}
-float sphere_distance(const Vec3 ¢, float rad, const Vec3 &pt)
-{
- return length(pt - cent) - rad;
-}
-
-// TODO version which takes both radii into account
-float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt)
+bool Plane::contains(const Vec3 &v) const
{
- Vec3 ab_dir = b - a;
- float ab_len_sq = length_sq(ab_dir);
-
- if(fabs(ab_len_sq) < 1e-5) {
- // if a == b, the capsule is a sphere with radius the maximum of the capsule radii
- return sphere_distance(a, std::max(ra, rb), pt);
- }
- float ab_len = sqrt(ab_len_sq);
-
- Vec3 ap_dir = pt - a;
-
- float t = dot(ap_dir, ab_dir / ab_len) / ab_len;
- if(t < 0.0) {
- return sphere_distance(a, ra, pt);
- }
- if(t >= 1.0) {
- return sphere_distance(b, rb, pt);
- }
-
- Vec3 pproj = a + ab_dir * t;
- return length(pproj - pt) - ra;
+ return dot(v, normal) <= 0.0;
}
-#if 0
-float capsule_distance(const Vec3 &a, float ra, const Vec3 &b, float rb, const Vec3 &pt)
+float Plane::distance(const Vec3 &v) const
{
- Vec3 ab_dir = b - a;
-
- if(fabs(length_sq(ab_dir)) < 1e-5) {
- // if a == b, the capsule is a sphere with radius the maximum of the capsule radii
- return sphere_distance(a, std::max(ra, rb), pt);
- }
- float ab_len = length(ab_dir);
-
- Vec3 ap_dir = pt - a;
- Vec3 rotaxis = normalize(cross(ab_dir, ap_dir));
-
- Mat4 rmat;
- rmat.set_rotation(rotaxis, M_PI / 2.0);
- Vec3 right = rmat * ab_dir / ab_len;
-
- // XXX I think this check is redundant, always false, due to the cross product order
- //assert(dot(right, ab_dir) >= 0.0);
- if(dot(right, ab_dir) < 0.0) {
- right = -right;
- }
- Vec3 aa = a + right * ra;
- Vec3 bb = b + right * rb;
-
- // project pt to the line segment bb-aa, see if the projection lies within the interval [0, 1)
- Vec3 aabb_dir = bb - aa;
- float aabb_len = length(aabb_dir);
- Vec3 aap_dir = pt - aa;
-
- float t = dot(aap_dir, aabb_dir / aabb_len) / aabb_len;
- if(t < 0.0) {
- return sphere_distance(a, ra, pt);
- }
- if(t >= 1.0) {
- return sphere_distance(b, rb, pt);
- }
-
- Vec3 ppt = aa + aabb_dir * t;
- Vec3 norm = ppt - pt;
- float dist = length(norm);
-
- if(dot(norm, right) < 0.0) {
- // inside the cone
- dist = -dist;
- }
- return dist;
+ return dot(v - pt, normal);
}
-#endif