From 9260eee3126731c1e6b54ce3407be757d0d71716 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 19 May 2013 21:32:09 +0300 Subject: [PATCH] Add more collision check functions for shapes --- source/geometry/hyperbox.h | 63 ++++++++++++++++++++++++++---- source/geometry/hypersphere.h | 44 +++++++++++++++++++-- source/geometry/shape.h | 20 ++++++++++ source/geometry/surfacepoint.h | 19 +++++++++ source/geometry/transformedshape.h | 28 +++++++++++++ 5 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 source/geometry/surfacepoint.h diff --git a/source/geometry/hyperbox.h b/source/geometry/hyperbox.h index 2ade28a..6248d6b 100644 --- a/source/geometry/hyperbox.h +++ b/source/geometry/hyperbox.h @@ -1,9 +1,12 @@ #ifndef MSP_GEOMETRY_HYPERBOX_H_ #define MSP_GEOMETRY_HYPERBOX_H_ +#include +#include #include #include "ray.h" #include "shape.h" +#include "surfacepoint.h" namespace Msp { namespace Geometry { @@ -24,7 +27,10 @@ public: T get_dimension(unsigned) const; virtual HyperBox get_axis_aligned_bounding_box() const { return *this; } + virtual bool contains(const LinAl::Vector &) const; virtual bool check_intersection(const Ray &) const; + virtual unsigned get_max_ray_intersections() const { return 2; } + virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const; }; template @@ -51,26 +57,67 @@ inline T HyperBox::get_dimension(unsigned i) const return dimensions[i]; } +template +inline bool HyperBox::contains(const LinAl::Vector &point) const +{ + for(unsigned i=0; idimensions[i]/2) + return false; + return true; +} + template inline bool HyperBox::check_intersection(const Ray &ray) const { + return get_intersections(ray, 0, 1); +} + +template +inline unsigned HyperBox::get_intersections(const Ray &ray, SurfacePoint *points, unsigned size) const +{ + using std::abs; + LinAl::Vector half_dim = dimensions/T(2); + unsigned n = 0; + T first_depth = T(); for(unsigned i=0; i0) + if(x<0) + continue; + + LinAl::Vector p = ray.get_start()+ray.get_direction()*x; + + bool inside = true; + for(unsigned k=0; (inside && k p = ray.get_start()+ray.get_direction()*x; - bool inside = true; - for(unsigned k=0; (inside && k=-half_dim[k] && p[k](); + points[n].normal[i] = j; + if(n==0) + first_depth = x; + else if(n==1 && x get_axis_aligned_bounding_box() const; + virtual bool contains(const LinAl::Vector &) const; virtual bool check_intersection(const Ray &) const; + virtual unsigned get_max_ray_intersections() const { return 2; } + virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const; }; template @@ -52,17 +56,51 @@ inline HyperBox HyperSphere::get_axis_aligned_bounding_box() const return HyperBox(dimensions); } +template +inline bool HyperSphere::contains(const LinAl::Vector &point) const +{ + return inner_product(point, point)<=radius*radius; +} + template inline bool HyperSphere::check_intersection(const Ray &ray) const { T x = inner_product(ray.get_direction(), ray.get_start()); if(x>0) - return inner_product(ray.get_start(), ray.get_start())<=radius*radius; + return contains(ray.get_start()); else + return contains(ray.get_start()-ray.get_direction()*x); +} + +template +inline unsigned HyperSphere::get_intersections(const Ray &ray, SurfacePoint *points, unsigned size) const +{ + T mid = -inner_product(ray.get_direction(), ray.get_start()); + LinAl::Vector nearest = ray.get_start()+ray.get_direction()*mid; + T offset_sq = radius*radius-inner_product(nearest, nearest); + if(offset_sq<0) + return 0; + T offset = sqrt(offset_sq); + + unsigned n = 0; + for(int i=-1; i<=1; i+=2) { - LinAl::Vector nearest = ray.get_start()-ray.get_direction()*x; - return inner_product(nearest, nearest)<=radius*radius; + T x = mid+offset*i; + if(x>0 && n +#include + namespace Msp { namespace Geometry { @@ -10,6 +13,9 @@ class HyperBox; template class Ray; +template +class SurfacePoint; + template class Shape { @@ -21,9 +27,23 @@ public: virtual Shape *clone() const = 0; virtual HyperBox get_axis_aligned_bounding_box() const = 0; + virtual bool contains(const LinAl::Vector &) const = 0; virtual bool check_intersection(const Ray &) const = 0; + virtual unsigned get_max_ray_intersections() const = 0; + virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const = 0; + std::vector > get_intersections(const Ray &) const; }; +template +std::vector > Shape::get_intersections(const Ray &ray) const +{ + unsigned max_isect = get_max_ray_intersections(); + std::vector > points(max_isect); + unsigned count = get_intersections(ray, &points[0], max_isect); + points.resize(count); + return points; +} + } // namespace Geometry } // namespace Msp diff --git a/source/geometry/surfacepoint.h b/source/geometry/surfacepoint.h new file mode 100644 index 0000000..3513ac8 --- /dev/null +++ b/source/geometry/surfacepoint.h @@ -0,0 +1,19 @@ +#ifndef MSP_GEOMETRY_SURFACEPOINT_H_ +#define MSP_GEOMETRY_SURFACEPOINT_H_ + +#include + +namespace Msp { +namespace Geometry { + +template +struct SurfacePoint +{ + LinAl::Vector position; + LinAl::Vector normal; +}; + +} // namespace Geometry +} // namespace Msp + +#endif diff --git a/source/geometry/transformedshape.h b/source/geometry/transformedshape.h index 2168126..ea7281f 100644 --- a/source/geometry/transformedshape.h +++ b/source/geometry/transformedshape.h @@ -28,7 +28,10 @@ public: const AffineTransformation &get_transformation() const { return transformation; } virtual HyperBox get_axis_aligned_bounding_box() const; + virtual bool contains(const LinAl::Vector &) const; virtual bool check_intersection(const Ray &) const; + virtual unsigned get_max_ray_intersections() const { return shape->get_max_ray_intersections(); } + virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const; }; template @@ -73,6 +76,12 @@ inline HyperBox TransformedShape::get_axis_aligned_bounding_box() co return shape->get_axis_aligned_bounding_box(); } +template +inline bool TransformedShape::contains(const LinAl::Vector &point) const +{ + return shape->contains(inverse_trans.transform(point)); +} + template inline bool TransformedShape::check_intersection(const Ray &ray) const { @@ -81,6 +90,25 @@ inline bool TransformedShape::check_intersection(const Ray &ray) con return shape->check_intersection(local_ray); } +template +inline unsigned TransformedShape::get_intersections(const Ray &ray, SurfacePoint *points, unsigned size) const +{ + Ray local_ray(inverse_trans.transform(ray.get_start()), + inverse_trans.transform_linear(ray.get_direction())); + unsigned count = shape->get_intersections(local_ray, points, size); + if(points) + { + for(unsigned i=0; i