From 68389c29cf88d6522dcfa00b5e2a5166e3947210 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 21 May 2013 18:39:37 +0300 Subject: [PATCH] Add shapes representing set operations --- source/geometry/compositeshape.h | 146 +++++++++++++++++++++++++++++++ source/geometry/dummy.cpp | 3 + source/geometry/intersection.h | 62 +++++++++++++ source/geometry/negation.h | 75 ++++++++++++++++ source/geometry/union.h | 62 +++++++++++++ 5 files changed, 348 insertions(+) create mode 100644 source/geometry/compositeshape.h create mode 100644 source/geometry/intersection.h create mode 100644 source/geometry/negation.h create mode 100644 source/geometry/union.h diff --git a/source/geometry/compositeshape.h b/source/geometry/compositeshape.h new file mode 100644 index 0000000..fd55c8e --- /dev/null +++ b/source/geometry/compositeshape.h @@ -0,0 +1,146 @@ +#ifndef MSP_GEOMETRY_COMPOSITESHAPE_H_ +#define MSP_GEOMETRY_COMPOSITESHAPE_H_ + +#include +#include "shape.h" + +namespace Msp { +namespace Geometry { + +/** +Common operations for shapes composed of other shapes. +*/ +template +class CompositeShape: public Shape +{ +protected: + typedef O Ops; + typedef std::vector *> ShapeArray; + + ShapeArray shapes; + + CompositeShape(const Shape &, const Shape &); + CompositeShape(const ShapeArray &); + CompositeShape(const CompositeShape &); + CompositeShape &operator=(const CompositeShape &); +public: + virtual ~CompositeShape(); + + 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; + virtual unsigned get_intersections(const Ray &, SurfacePoint *, unsigned) const; +}; + +template +inline CompositeShape::CompositeShape(const Shape &s1, const Shape &s2) +{ + shapes.reserve(2); + shapes.push_back(s1.clone()); + shapes.push_back(s2.clone()); +} + +template +inline CompositeShape::CompositeShape(const ShapeArray &s) +{ + if(s.empty()) + throw std::invalid_argument("CompositeShape::CompositeShape"); + + shapes.reserve(s.size()); + for(typename ShapeArray::const_iterator i=s.begin(); i!=s.end(); ++i) + shapes.push_back((*i)->clone()); +} + +template +inline CompositeShape::~CompositeShape() +{ + for(typename ShapeArray::iterator i=shapes.begin(); i!=shapes.end(); ++i) + delete *i; +} + +template +inline HyperBox CompositeShape::get_axis_aligned_bounding_box() const +{ + HyperBox aabb; + for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i) + { + if(i==shapes.begin()) + aabb = (*i)->get_axis_aligned_bounding_box(); + else + aabb = Ops::combine_aabb(aabb, (*i)->get_axis_aligned_bounding_box()); + } + return aabb; +} + +template +inline bool CompositeShape::contains(const LinAl::Vector &point) const +{ + bool inside = Ops::init_inside(); + for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i) + { + inside = Ops::combine_inside(inside, (*i)->contains(point)); + if(Ops::is_inside_decided(inside)) + break; + } + return inside; +} + +template +inline bool CompositeShape::check_intersection(const Ray &ray) const +{ + return get_intersections(ray, 0, 1); +} + +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 +{ + unsigned n = 0; + for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i) + { + unsigned base = n; + unsigned count = (*i)->get_intersections(ray, points+base, size-base); + for(unsigned j=0; j pt = points[base+j]; + + bool surface = Ops::init_surface(); + for(typename ShapeArray::const_iterator k=shapes.begin(); k!=shapes.end(); ++k) + if(k!=i) + surface = Ops::combine_surface(surface, (*k)->contains(pt.position)); + + if(surface) + { + if(points) + { + unsigned k; + for(k=n; (k>0 && points[k-1].distance>pt.distance); --k) + points[k] = points[k-1]; + if(base+j!=k) + points[k] = pt; + } + + ++n; + if(n==size) + return n; + } + } + } + + return n; +} + +} // namespace Geometry +} // namespace Msp + +#endif diff --git a/source/geometry/dummy.cpp b/source/geometry/dummy.cpp index cc7e2ba..ed9c219 100644 --- a/source/geometry/dummy.cpp +++ b/source/geometry/dummy.cpp @@ -4,7 +4,10 @@ #include "circle.h" #include "hyperbox.h" #include "hypersphere.h" +#include "intersection.h" +#include "negation.h" #include "ray.h" #include "rectangle.h" #include "shape.h" #include "transformedshape.h" +#include "union.h" diff --git a/source/geometry/intersection.h b/source/geometry/intersection.h new file mode 100644 index 0000000..53c25c2 --- /dev/null +++ b/source/geometry/intersection.h @@ -0,0 +1,62 @@ +#ifndef MSP_GEOMETRY_INTERSECTION_H_ +#define MSP_GEOMETRY_INTERSECTION_H_ + +#include "compositeshape.h" + +namespace Msp { +namespace Geometry { + +/** +Forms a shape from the common parts of component shapes. +*/ +template +struct IntersectionOps +{ + static HyperBox combine_aabb(const HyperBox &, const HyperBox &); + static bool init_inside() { return true; } + static bool combine_inside(bool a, bool b) { return a && b; } + static bool is_inside_decided(bool a) { return !a; } + static bool init_surface() { return true; } + static bool combine_surface(bool a, bool b) { return a && b; } +}; + +template +class Intersection: public CompositeShape > +{ +public: + Intersection(const Shape &, const Shape &); + Intersection(const std::vector *> &); + + virtual Intersection *clone() const; +}; + +template +Intersection::Intersection(const Shape &s1, const Shape &s2): + CompositeShape >(s1, s2) +{ } + +template +Intersection::Intersection(const std::vector *> &s): + CompositeShape >(s) +{ } + +template +Intersection *Intersection::clone() const +{ + return new Intersection(this->shapes); +} + + +template +inline HyperBox IntersectionOps::combine_aabb(const HyperBox &box1, const HyperBox &box2) +{ + LinAl::Vector dimensions; + for(unsigned i=0; i(dimensions); +} + +} // namespace Geometry +} // namespace Msp + +#endif diff --git a/source/geometry/negation.h b/source/geometry/negation.h new file mode 100644 index 0000000..0fc0196 --- /dev/null +++ b/source/geometry/negation.h @@ -0,0 +1,75 @@ +#ifndef MSP_GEOMETRY_NEGATION_H_ +#define MSP_GEOMETRY_NEGATION_H_ + +#include "shape.h" + +namespace Msp { +namespace Geometry { + +/** +Negates a shape. Not particulary useful on its own, but can be used together +with Intersection to cut holes. +*/ +template +class Negation: public Shape +{ +private: + Shape *shape; + +public: + Negation(const Shape &); + + virtual Negation *clone() const; + + const Shape &get_shape() const { return *shape; } + + 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 +inline Negation::Negation(const Shape &s): + shape(s.clone()) +{ } + +template +inline Negation *Negation::clone() const +{ + return new Negation(*shape); +} + +template +inline HyperBox Negation::get_axis_aligned_bounding_box() const +{ + // XXX How do we handle this correctly? In particular negation of a negation? + return HyperBox(); +} + +template +inline bool Negation::contains(const LinAl::Vector &point) const +{ + return !shape->contains(point); +} + +template +inline bool Negation::check_intersection(const Ray &ray) const +{ + return get_intersections(ray, 0, 1); +} + +template +inline unsigned Negation::get_intersections(const Ray &ray, SurfacePoint *points, unsigned size) const +{ + unsigned count = shape->get_intersections(ray, points, size); + for(unsigned i=0; i +struct UnionOps +{ + static HyperBox combine_aabb(const HyperBox &, const HyperBox &); + static bool init_inside() { return false; } + static bool combine_inside(bool a, bool b) { return a || b; } + static bool is_inside_decided(bool a) { return a; } + static bool init_surface() { return true; } + static bool combine_surface(bool a, bool b) { return a && !b; } +}; + +template +class Union: public CompositeShape > +{ +public: + Union(const Shape &, const Shape &); + Union(const std::vector *> &); + + virtual Union *clone() const; +}; + +template +inline Union::Union(const Shape &s1, const Shape &s2): + CompositeShape >(s1, s2) +{ } + +template +inline Union::Union(const std::vector *> &s): + CompositeShape >(s) +{ } + +template +inline Union *Union::clone() const +{ + return new Union(this->shapes); +} + + +template +inline HyperBox UnionOps::combine_aabb(const HyperBox &box1, const HyperBox &box2) +{ + LinAl::Vector dimensions; + for(unsigned i=0; i(dimensions); +} + +} // namespace Geometry +} // namespace Msp + +#endif -- 2.43.0