From: Mikko Rasa Date: Wed, 22 May 2013 20:03:07 +0000 (+0300) Subject: Make CompositeShape::get_intersections work with null points X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=39626a640e3b6a1ff8894e0cf47db68540d669b2;p=libs%2Fmath.git Make CompositeShape::get_intersections work with null points This was a bit tricky, since it's necessary to inspect the points returned by component shapes to see if they're actually on the composite surface. To that end, a temporary buffer is allocated. This is most likely used in interactive point-and-pick situations, so the performance loss should not be significant. --- diff --git a/source/geometry/compositeshape.h b/source/geometry/compositeshape.h index 55467d7..f0b1f52 100644 --- a/source/geometry/compositeshape.h +++ b/source/geometry/compositeshape.h @@ -1,6 +1,7 @@ #ifndef MSP_GEOMETRY_COMPOSITESHAPE_H_ #define MSP_GEOMETRY_COMPOSITESHAPE_H_ +#include #include #include #include "shape.h" @@ -19,11 +20,16 @@ protected: typedef std::vector *> ShapeArray; ShapeArray shapes; + unsigned max_isect; + unsigned min_scratch; CompositeShape() { } CompositeShape(const Shape &, const Shape &); template void init_from_iter_range(const Iter &, const Iter &); +private: + void init(); +protected: CompositeShape(const CompositeShape &); CompositeShape &operator=(const CompositeShape &); public: @@ -31,7 +37,7 @@ public: virtual BoundingBox get_axis_aligned_bounding_box() const; virtual bool contains(const LinAl::Vector &) const; - virtual unsigned get_max_ray_intersections() const; + virtual unsigned get_max_ray_intersections() const { return max_isect; } virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const; }; @@ -41,6 +47,7 @@ inline CompositeShape::CompositeShape(const Shape &s1, const Shap shapes.reserve(2); shapes.push_back(s1.clone()); shapes.push_back(s2.clone()); + init(); } template @@ -52,11 +59,27 @@ inline void CompositeShape::init_from_iter_range(const Iter &begin, con for(Iter i=begin; i!=end; ++i) shapes.push_back((*i)->clone()); + init(); +} + +template +inline void CompositeShape::init() +{ + max_isect = 0; + min_scratch = 0; + for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i) + { + unsigned mi = (*i)->get_max_ray_intersections(); + max_isect += mi; + min_scratch = std::max(min_scratch, mi); + } } template inline CompositeShape::CompositeShape(const CompositeShape &other): - shapes(other.shapes) + shapes(other.shapes), + max_isect(other.max_isect), + min_scratch(other.min_scratch) { for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i) *i = (*i)->clone(); @@ -71,6 +94,9 @@ inline CompositeShape &CompositeShape::operator=(const Composi shapes = other.shapes; for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i) *i = (*i)->clone(); + + max_isect = other.max_isect; + min_scratch = other.min_scratch; } template @@ -107,26 +133,25 @@ inline bool CompositeShape::contains(const LinAl::Vector &point) return inside; } -template -inline unsigned CompositeShape::get_max_ray_intersections() const -{ - unsigned max_isect = 0; - for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i) - max_isect += (*i)->get_max_ray_intersections(); - return max_isect; -} - template inline unsigned CompositeShape::get_intersections(const Ray &ray, SurfacePoint *points, unsigned size) const { + SurfacePoint *buffer = points; + unsigned buf_size = size; + if(!points) + { + buffer = new SurfacePoint[min_scratch]; + buf_size = min_scratch; + } + unsigned n = 0; for(typename ShapeArray::const_iterator i=shapes.begin(); (nget_intersections(ray, points+base, size-base); + unsigned base = (points ? n : 0); + unsigned count = (*i)->get_intersections(ray, buffer+base, buf_size-base); for(unsigned j=0; (n &pt = points[base+j]; + SurfacePoint &pt = buffer[base+j]; bool surface = Ops::init_surface(); for(typename ShapeArray::const_iterator k=shapes.begin(); k!=shapes.end(); ++k) @@ -143,7 +168,10 @@ inline unsigned CompositeShape::get_intersections(const Ray &ray, } } - sort_points(points, n); + if(points) + sort_points(points, n); + else + delete[] buffer; return n; }