/* * Shape.cpp * * Created on: Jun 18, 2010 * Author: crueger */ #include "Shape.hpp" #include "Shape_impl.hpp" #include "Helpers/Assert.hpp" Shape::Shape(const Shape& src) : impl(src.getImpl()) {} Shape::~Shape(){} bool Shape::isInside(const Vector &point) const{ return impl->isInside(point); } bool Shape::isOnSurface(const Vector &point) const{ return impl->isOnSurface(point); } Vector Shape::getNormal(const Vector &point) const throw (NotOnSurfaceException){ return impl->getNormal(point); } Shape::Shape(Shape::impl_ptr _impl) : impl(_impl) {} Shape &Shape::operator=(const Shape& rhs){ if(&rhs!=this){ impl=rhs.getImpl(); } return *this; } Shape::impl_ptr Shape::getImpl() const{ return impl; } // allows arbitrary friendship, but only if implementation is known Shape::impl_ptr getShapeImpl(const Shape &shape){ return shape.getImpl(); } /***************************** Some simple Shapes ***************************/ Shape Everywhere(){ static Shape::impl_ptr impl = Shape::impl_ptr(new Everywhere_impl()); return Shape(impl); } Shape Nowhere(){ static Shape::impl_ptr impl = Shape::impl_ptr(new Nowhere_impl()); return Shape(impl); } /****************************** Operators ***********************************/ // AND AndShape_impl::AndShape_impl(const Shape::impl_ptr &_lhs, const Shape::impl_ptr &_rhs) : lhs(_lhs),rhs(_rhs) {} AndShape_impl::~AndShape_impl(){} bool AndShape_impl::isInside(const Vector &point){ return lhs->isInside(point) && rhs->isInside(point); } bool AndShape_impl::isOnSurface(const Vector &point){ // check the number of surfaces that this point is on int surfaces =0; surfaces += lhs->isOnSurface(point); surfaces += rhs->isOnSurface(point); switch(surfaces){ case 0: return false; // no break necessary case 1: // if it is inside for the object where it does not lie on // the surface the whole point lies inside return (lhs->isOnSurface(point) && rhs->isInside(point)) || (rhs->isOnSurface(point) && lhs->isInside(point)); // no break necessary case 2: { // it lies on both Shapes... could be an edge or an inner point // test the direction of the normals Vector direction=lhs->getNormal(point)+rhs->getNormal(point); // if the directions are opposite we lie on the inside return !direction.IsZero(); } // no break necessary default: // if this happens there is something wrong ASSERT(0,"Default case should have never been used"); } return false; // never reached } Vector AndShape_impl::getNormal(const Vector &point) throw (NotOnSurfaceException){ Vector res; if(!isOnSurface(point)){ throw NotOnSurfaceException(__FILE__,__LINE__); } res += lhs->isOnSurface(point)?lhs->getNormal(point):zeroVec; res += rhs->isOnSurface(point)?rhs->getNormal(point):zeroVec; res.Normalize(); return res; } Shape operator&&(const Shape &lhs,const Shape &rhs){ Shape::impl_ptr newImpl = Shape::impl_ptr(new AndShape_impl(getShapeImpl(lhs),getShapeImpl(rhs))); return Shape(newImpl); } // OR OrShape_impl::OrShape_impl(const Shape::impl_ptr &_lhs, const Shape::impl_ptr &_rhs) : lhs(_lhs),rhs(_rhs) {} OrShape_impl::~OrShape_impl(){} bool OrShape_impl::isInside(const Vector &point){ return rhs->isInside(point) || lhs->isInside(point); } bool OrShape_impl::isOnSurface(const Vector &point){ // check the number of surfaces that this point is on int surfaces =0; surfaces += lhs->isOnSurface(point); surfaces += rhs->isOnSurface(point); switch(surfaces){ case 0: return false; // no break necessary case 1: // if it is inside for the object where it does not lie on // the surface the whole point lies inside return (lhs->isOnSurface(point) && !rhs->isInside(point)) || (rhs->isOnSurface(point) && !lhs->isInside(point)); // no break necessary case 2: { // it lies on both Shapes... could be an edge or an inner point // test the direction of the normals Vector direction=lhs->getNormal(point)+rhs->getNormal(point); // if the directions are opposite we lie on the inside return !direction.IsZero(); } // no break necessary default: // if this happens there is something wrong ASSERT(0,"Default case should have never been used"); } return false; // never reached } Vector OrShape_impl::getNormal(const Vector &point) throw (NotOnSurfaceException){ Vector res; if(!isOnSurface(point)){ throw NotOnSurfaceException(__FILE__,__LINE__); } res += lhs->isOnSurface(point)?lhs->getNormal(point):zeroVec; res += rhs->isOnSurface(point)?rhs->getNormal(point):zeroVec; res.Normalize(); return res; } Shape operator||(const Shape &lhs,const Shape &rhs){ Shape::impl_ptr newImpl = Shape::impl_ptr(new OrShape_impl(getShapeImpl(lhs),getShapeImpl(rhs))); return Shape(newImpl); } // NOT NotShape_impl::NotShape_impl(const Shape::impl_ptr &_arg) : arg(_arg) {} NotShape_impl::~NotShape_impl(){} bool NotShape_impl::isInside(const Vector &point){ return !arg->isInside(point); } bool NotShape_impl::isOnSurface(const Vector &point){ return arg->isOnSurface(point); } Vector NotShape_impl::getNormal(const Vector &point) throw(NotOnSurfaceException){ return -1*arg->getNormal(point); } Shape operator!(const Shape &arg){ Shape::impl_ptr newImpl = Shape::impl_ptr(new NotShape_impl(getShapeImpl(arg))); return Shape(newImpl); }