]> git.tdb.fi Git - libs/math.git/commitdiff
Use the coverage function to calculate tighter bounding boxes
authorMikko Rasa <tdb@tdb.fi>
Tue, 18 Apr 2017 06:10:55 +0000 (09:10 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 18 Apr 2017 06:39:13 +0000 (09:39 +0300)
source/geometry/compositeshape.h
source/geometry/extrudedshape.h
source/geometry/halfspace.h
source/geometry/hyperbox.h
source/geometry/hypersphere.h
source/geometry/negation.h
source/geometry/shape.h
source/geometry/transformedshape.h

index 00ae55d0ad7b83e8d67a3f15867d75c6419a6903..5d0cd8c59532ed3b782c3cd60908c8ce96778b6c 100644 (file)
@@ -34,7 +34,7 @@ protected:
 public:
        virtual ~CompositeShape();
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return max_isect; }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -100,8 +100,11 @@ inline CompositeShape<T, D, O>::~CompositeShape()
 }
 
 template<typename T, unsigned D, typename O>
-inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> CompositeShape<T, D, O>::get_axis_aligned_bounding_box(unsigned detail) const
 {
+       if(detail)
+               return this->bisect_axis_aligned_bounding_box(detail);
+
        BoundingBox<T, D> aabb;
        for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
        {
index e702f90a7a0f844d93f417b53d38a8c6aea2359a..fd4597b9b1a5c935f50a3eb3a6e02296cd3f3a9f 100644 (file)
@@ -31,7 +31,7 @@ public:
        const Shape<T, D-1> &get_base() const { return *base; }
        T get_length() const { return length; }
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const;
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -75,9 +75,9 @@ inline ExtrudedShape<T, D> *ExtrudedShape<T, D>::clone() const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> ExtrudedShape<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
 {
-       BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box();
+       BoundingBox<T, D-1> base_bbox = base->get_axis_aligned_bounding_box(detail);
        T half_length = length/T(2);
        return BoundingBox<T, D>(compose(base_bbox.get_minimum_point(), -half_length),
                compose(base_bbox.get_maximum_point(), half_length));
index 09ec62ce600b9258b1044a0113a61251f5c424aa..9fdcdadfbd02b0dec41ef88c3e97539013cf2cbd 100644 (file)
@@ -24,7 +24,7 @@ public:
 
        const LinAl::Vector<T, D> &get_normal() const { return normal; }
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return 1; }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -49,7 +49,7 @@ inline HalfSpace<T, D> *HalfSpace<T, D>::clone() const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HalfSpace<T, D>::get_axis_aligned_bounding_box(unsigned) const
 {
        // XXX If the normal is aligned to an axis, should the bounding box reflect that?
        return ~BoundingBox<T, D>();
index c3bac57d97e3464d20535a66928106079777801a..e3236e8cfaf03d69877fdfe94f7a75dc8e9f811e 100644 (file)
@@ -29,7 +29,7 @@ public:
        const LinAl::Vector<T, D> &get_dimensions() const { return dimensions; }
        T get_dimension(unsigned) const;
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return 2; }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -65,7 +65,7 @@ inline T HyperBox<T, D>::get_dimension(unsigned i) const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> HyperBox<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HyperBox<T, D>::get_axis_aligned_bounding_box(unsigned) const
 {
        LinAl::Vector<T, D> half_dim = dimensions/T(2);
        return BoundingBox<T, D>(-half_dim, half_dim);
index 8f21db1d78f40689cda50c40d7ccd18cb3aa93b8..13e4278430b8b5e2a811974a1959d54dac8bd305 100644 (file)
@@ -27,7 +27,7 @@ public:
 
        T get_radius() const { return radius; }
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return 2; }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -49,7 +49,7 @@ inline HyperSphere<T, D> *HyperSphere<T, D>::clone() const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> HyperSphere<T, D>::get_axis_aligned_bounding_box(unsigned) const
 {
        LinAl::Vector<T, D> extent;
        for(unsigned i=0; i<D; ++i)
index d90c4deb5a7de767b2f36cb0ed165d53f8a5c851..91802f8bce9906cfdadcae3bc7382c6e193cb423 100644 (file)
@@ -26,7 +26,7 @@ public:
 
        const Shape<T, D> &get_shape() const { return *shape; }
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return shape->get_max_ray_intersections(); }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -64,9 +64,9 @@ inline Negation<T, D> *Negation<T, D>::clone() const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> Negation<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
 {
-       return ~shape->get_axis_aligned_bounding_box();
+       return ~shape->get_axis_aligned_bounding_box(detail);
 }
 
 template<typename T, unsigned D>
index ded8f13d8b7464b896e8d0510fe8146de2e68a85..074c11b7289665fa88786aa43b5a4343c06e0741 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_GEOMETRY_SHAPE_H_
 #define MSP_GEOMETRY_SHAPE_H_
 
+#include <list>
 #include <vector>
 #include <msp/linal/vector.h>
 #include "boundingbox.h"
@@ -26,13 +27,23 @@ template<typename T, unsigned D>
 class Shape
 {
 protected:
+       struct CoverageCell
+       {
+               unsigned level;
+               BoundingBox<T, D> bounding_box;
+               Coverage coverage;
+       };
+
        Shape() { }
 public:
        virtual ~Shape() { }
 
        virtual Shape *clone() const = 0;
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const = 0;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned detail = 0) const = 0;
+protected:
+       BoundingBox<T, D> bisect_axis_aligned_bounding_box(unsigned) const;
+public:
        virtual bool contains(const LinAl::Vector<T, D> &) const = 0;
        bool check_intersection(const Ray<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const = 0;
@@ -41,6 +52,70 @@ public:
        virtual Coverage get_coverage(const BoundingBox<T, D> &) const = 0;
 };
 
+template<typename T, unsigned D>
+inline BoundingBox<T, D> Shape<T, D>::bisect_axis_aligned_bounding_box(unsigned detail) const
+{
+       if(!detail)
+               throw std::invalid_argument("Shape::bisect_axis_aligned_bounding_box");
+
+       std::list<CoverageCell> queue;
+       queue.push_back(CoverageCell());
+       CoverageCell &root = queue.front();
+       root.level = 0;
+       root.bounding_box = get_axis_aligned_bounding_box();
+       if(root.bounding_box.is_space())
+               return root.bounding_box;
+
+       root.coverage = get_coverage(root.bounding_box);
+       if(root.coverage==FULL_COVERAGE)
+               return root.bounding_box;
+
+       LinAl::Vector<T, D> tight_min_pt = root.bounding_box.get_maximum_point();
+       LinAl::Vector<T, D> tight_max_pt = root.bounding_box.get_minimum_point();
+
+       while(!queue.empty())
+       {
+               CoverageCell &cell = queue.front();
+
+               const LinAl::Vector<T, D> &min_pt = cell.bounding_box.get_minimum_point();
+               const LinAl::Vector<T, D> &max_pt = cell.bounding_box.get_maximum_point();
+               LinAl::Vector<T, D> center = (min_pt+max_pt)/T(2);
+
+               for(unsigned i=0; i<(1<<D); ++i)
+               {
+                       CoverageCell child;
+                       child.level = cell.level+1;
+
+                       LinAl::Vector<T, D> child_min_pt = min_pt;
+                       LinAl::Vector<T, D> child_max_pt = max_pt;
+                       for(unsigned j=0; j<D; ++j)
+                       {
+                               if((i>>j)&1)
+                                       child_min_pt[j] = center[j];
+                               else
+                                       child_max_pt[j] = center[j];
+                       }
+                       child.bounding_box = BoundingBox<T, D>(child_min_pt, child_max_pt);
+
+                       child.coverage = get_coverage(child.bounding_box);
+                       if(child.coverage==FULL_COVERAGE || (child.level==detail && child.coverage!=NO_COVERAGE))
+                       {
+                               for(unsigned j=0; j<D; ++j)
+                               {
+                                       tight_min_pt[j] = std::min(tight_min_pt[j], child_min_pt[j]);
+                                       tight_max_pt[j] = std::max(tight_max_pt[j], child_max_pt[j]);
+                               }
+                       }
+                       else if(child.coverage==PARTIAL_COVERAGE)
+                               queue.push_back(child);
+               }
+
+               queue.pop_front();
+       }
+
+       return BoundingBox<T, D>(tight_min_pt, tight_max_pt);
+}
+
 template<typename T, unsigned D>
 inline bool Shape<T, D>::check_intersection(const Ray<T, D> &ray) const
 {
index 91790fc77276fd8aedbb75f318b856d775334cd2..002f3c1a1cc859485decd5830f940137f33fda16 100644 (file)
@@ -29,7 +29,7 @@ public:
        const Shape<T, D> &get_shape() const { return *shape; }
        const AffineTransformation<T, D> &get_transformation() const { return transformation; }
 
-       virtual BoundingBox<T, D> get_axis_aligned_bounding_box() const;
+       virtual BoundingBox<T, D> get_axis_aligned_bounding_box(unsigned = 0) const;
        virtual bool contains(const LinAl::Vector<T, D> &) const;
        virtual unsigned get_max_ray_intersections() const { return shape->get_max_ray_intersections(); }
        virtual unsigned get_intersections(const Ray<T, D> &, SurfacePoint<T, D> *, unsigned) const;
@@ -72,8 +72,11 @@ inline TransformedShape<T, D> *TransformedShape<T, D>::clone() const
 }
 
 template<typename T, unsigned D>
-inline BoundingBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box() const
+inline BoundingBox<T, D> TransformedShape<T, D>::get_axis_aligned_bounding_box(unsigned detail) const
 {
+       if(detail)
+               return this->bisect_axis_aligned_bounding_box(detail);
+
        return transformation.transform(shape->get_axis_aligned_bounding_box());
 }