X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgeometry%2Fshape.h;h=074c11b7289665fa88786aa43b5a4343c06e0741;hb=44bd1d1ab256d397be4e2169c4ca5efdd0569d31;hp=528a77ca6d97d42e748bb4a47a17f88508394bfa;hpb=6ff13022b53830d35283905d562c2ef3af198cc1;p=libs%2Fmath.git diff --git a/source/geometry/shape.h b/source/geometry/shape.h index 528a77c..074c11b 100644 --- a/source/geometry/shape.h +++ b/source/geometry/shape.h @@ -1,29 +1,137 @@ #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; +enum Coverage +{ + NO_COVERAGE, + PARTIAL_COVERAGE, + FULL_COVERAGE +}; +/** +Base class and interface for geometric shapes. Shapes may be bounded or +unbounded. They are always considered to be solid, i.e. have a distinct inside +and an outside. +*/ 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 bool check_intersection(const Ray &) 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 +{ + return get_intersections(ray, 0, 1); +} + +template +inline 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