X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgeometry%2Fshape.h;h=074c11b7289665fa88786aa43b5a4343c06e0741;hb=44bd1d1ab256d397be4e2169c4ca5efdd0569d31;hp=7b1d190b5a762b82c7213a012e58190c7ba8d66c;hpb=313e10c1dcf5504789cc145166aece93d8141212;p=libs%2Fmath.git diff --git a/source/geometry/shape.h b/source/geometry/shape.h index 7b1d190..074c11b 100644 --- a/source/geometry/shape.h +++ b/source/geometry/shape.h @@ -1,20 +1,22 @@ #ifndef MSP_GEOMETRY_SHAPE_H_ #define MSP_GEOMETRY_SHAPE_H_ +#include #include #include +#include "boundingbox.h" +#include "ray.h" +#include "surfacepoint.h" namespace Msp { namespace Geometry { -template -class HyperBox; - -template -class Ray; - -template -class SurfacePoint; +enum Coverage +{ + NO_COVERAGE, + PARTIAL_COVERAGE, + FULL_COVERAGE +}; /** Base class and interface for geometric shapes. Shapes may be bounded or @@ -25,20 +27,95 @@ template class Shape { protected: + struct CoverageCell + { + unsigned level; + BoundingBox bounding_box; + Coverage coverage; + }; + Shape() { } public: virtual ~Shape() { } virtual Shape *clone() const = 0; - virtual HyperBox get_axis_aligned_bounding_box() const = 0; + virtual BoundingBox get_axis_aligned_bounding_box(unsigned detail = 0) const = 0; +protected: + BoundingBox bisect_axis_aligned_bounding_box(unsigned) const; +public: virtual bool contains(const LinAl::Vector &) const = 0; bool check_intersection(const Ray &) const; 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; + virtual Coverage get_coverage(const BoundingBox &) const = 0; }; +template +inline BoundingBox Shape::bisect_axis_aligned_bounding_box(unsigned detail) const +{ + if(!detail) + throw std::invalid_argument("Shape::bisect_axis_aligned_bounding_box"); + + std::list 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 tight_min_pt = root.bounding_box.get_maximum_point(); + LinAl::Vector tight_max_pt = root.bounding_box.get_minimum_point(); + + while(!queue.empty()) + { + CoverageCell &cell = queue.front(); + + const LinAl::Vector &min_pt = cell.bounding_box.get_minimum_point(); + const LinAl::Vector &max_pt = cell.bounding_box.get_maximum_point(); + LinAl::Vector center = (min_pt+max_pt)/T(2); + + for(unsigned i=0; i<(1< child_min_pt = min_pt; + LinAl::Vector child_max_pt = max_pt; + for(unsigned j=0; j>j)&1) + child_min_pt[j] = center[j]; + else + child_max_pt[j] = center[j]; + } + child.bounding_box = BoundingBox(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(tight_min_pt, tight_max_pt); +} + template inline bool Shape::check_intersection(const Ray &ray) const {