/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * Shape.cpp * * Created on: Jun 18, 2010 * Author: crueger */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Assert.hpp" #include "LinearAlgebra/Vector.hpp" #include "Shapes/Shape.hpp" #include "Shapes/Shape_impl.hpp" #include "Shapes/ShapeExceptions.hpp" #include 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); } LineSegmentSet Shape::getLineIntersections(const Line &line){ return impl->getLineIntersections(line); } std::vector Shape::getHomogeneousPointsOnSurface(const size_t N) const { return impl->getHomogeneousPointsOnSurface(N); } Shape::Shape(Shape::impl_ptr _impl) : impl(_impl) {} Shape &Shape::operator=(const Shape& rhs){ if(&rhs!=this){ impl=rhs.getImpl(); } return *this; } std::string Shape::toString() const{ return impl->toString(); } 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() << ShapeVector(&point); } res += lhs->isOnSurface(point)?lhs->getNormal(point):zeroVec; res += rhs->isOnSurface(point)?rhs->getNormal(point):zeroVec; res.Normalize(); return res; } LineSegmentSet AndShape_impl::getLineIntersections(const Line &line){ return intersect(lhs->getLineIntersections(line),rhs->getLineIntersections(line)); } string AndShape_impl::toString(){ return string("(") + lhs->toString() + string("&&") + rhs->toString() + string(")"); } std::vector AndShape_impl::getHomogeneousPointsOnSurface(const size_t N) const { std::vector PointsOnSurface_lhs = lhs->getHomogeneousPointsOnSurface(N); std::vector PointsOnSurface_rhs = rhs->getHomogeneousPointsOnSurface(N); std::vector PointsOnSurface; for (std::vector::const_iterator iter = PointsOnSurface_lhs.begin(); iter != PointsOnSurface_lhs.end(); ++iter) { if (rhs->isInside(*iter)) PointsOnSurface.push_back(*iter); } for (std::vector::const_iterator iter = PointsOnSurface_rhs.begin(); iter != PointsOnSurface_rhs.end(); ++iter) { if (lhs->isInside(*iter)) PointsOnSurface.push_back(*iter); } return PointsOnSurface; } 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() << ShapeVector(&point); } res += lhs->isOnSurface(point)?lhs->getNormal(point):zeroVec; res += rhs->isOnSurface(point)?rhs->getNormal(point):zeroVec; res.Normalize(); return res; } LineSegmentSet OrShape_impl::getLineIntersections(const Line &line){ return merge(lhs->getLineIntersections(line),rhs->getLineIntersections(line)); } string OrShape_impl::toString(){ return string("(") + lhs->toString() + string("||") + rhs->toString() + string(")"); } std::vector OrShape_impl::getHomogeneousPointsOnSurface(const size_t N) const { std::vector PointsOnSurface_lhs = lhs->getHomogeneousPointsOnSurface(N); std::vector PointsOnSurface_rhs = rhs->getHomogeneousPointsOnSurface(N); std::vector PointsOnSurface; for (std::vector::const_iterator iter = PointsOnSurface_lhs.begin(); iter != PointsOnSurface_lhs.end(); ++iter) { if (!rhs->isInside(*iter)) PointsOnSurface.push_back(*iter); } for (std::vector::const_iterator iter = PointsOnSurface_rhs.begin(); iter != PointsOnSurface_rhs.end(); ++iter) { if (!lhs->isInside(*iter)) PointsOnSurface.push_back(*iter); } return PointsOnSurface; } 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); } LineSegmentSet NotShape_impl::getLineIntersections(const Line &line){ return invert(arg->getLineIntersections(line)); } string NotShape_impl::toString(){ return string("!") + arg->toString(); } std::vector NotShape_impl::getHomogeneousPointsOnSurface(const size_t N) const { // surfaces are the same, only normal direction is different return arg->getHomogeneousPointsOnSurface(N); } Shape operator!(const Shape &arg){ Shape::impl_ptr newImpl = Shape::impl_ptr(new NotShape_impl(getShapeImpl(arg))); return Shape(newImpl); } /**************** global operations *********************************/ ostream &operator<<(ostream &ost,const Shape &shape){ ost << shape.toString(); return ost; }