Program Listing for File bodies.h

Return to documentation for file (/tmp/ws/src/geometric_shapes/include/geometric_shapes/bodies.h)

// Copyright 2008 Willow Garage, Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the Willow Garage, Inc. nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/* Author: Ioan Sucan, E. Gil Jones */

#ifndef GEOMETRIC_SHAPES_BODIES_
#define GEOMETRIC_SHAPES_BODIES_

#define _USE_MATH_DEFINES
#include "geometric_shapes/aabb.h"
#include "geometric_shapes/shapes.h"
#include <eigen_stl_containers/eigen_stl_containers.h>
#include <random_numbers/random_numbers.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <memory>
#include <vector>

namespace bodies
{
struct BoundingSphere
{
  Eigen::Vector3d center;
  double radius;

  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

struct BoundingCylinder
{
  Eigen::Isometry3d pose;
  double radius;
  double length;
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class Body;

typedef std::shared_ptr<Body> BodyPtr;

typedef std::shared_ptr<const Body> BodyConstPtr;

class Body
{
public:
  Body() : scale_(1.0), padding_(0.0), type_(shapes::UNKNOWN_SHAPE)
  {
    pose_.setIdentity();
  }

  virtual ~Body() = default;

  inline shapes::ShapeType getType() const
  {
    return type_;
  }

  inline void setScaleDirty(double scale)
  {
    scale_ = scale;
  }

  inline void setScale(double scale)
  {
    setScaleDirty(scale);
    updateInternalData();
  }

  inline double getScale() const
  {
    return scale_;
  }

  inline void setPaddingDirty(double padd)
  {
    padding_ = padd;
  }

  inline void setPadding(double padd)
  {
    setPaddingDirty(padd);
    updateInternalData();
  }

  inline double getPadding() const
  {
    return padding_;
  }

  inline void setPoseDirty(const Eigen::Isometry3d& pose)
  {
    pose_ = pose;
  }

  inline void setPose(const Eigen::Isometry3d& pose)
  {
    setPoseDirty(pose);
    updateInternalData();
  }

  inline const Eigen::Isometry3d& getPose() const
  {
    return pose_;
  }

  inline void setDimensionsDirty(const shapes::Shape* shape)
  {
    useDimensions(shape);
  }

  virtual std::vector<double> getDimensions() const = 0;

  virtual std::vector<double> getScaledDimensions() const = 0;

  inline void setDimensions(const shapes::Shape* shape)
  {
    setDimensionsDirty(shape);
    updateInternalData();
  }

  inline bool containsPoint(double x, double y, double z, bool verbose = false) const
  {
    Eigen::Vector3d pt(x, y, z);
    return containsPoint(pt, verbose);
  }

  virtual bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const = 0;

  virtual bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir,
                             EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const = 0;

  virtual double computeVolume() const = 0;

  virtual bool samplePointInside(random_numbers::RandomNumberGenerator& rng, unsigned int max_attempts,
                                 Eigen::Vector3d& result) const;

  virtual void computeBoundingSphere(BoundingSphere& sphere) const = 0;

  virtual void computeBoundingCylinder(BoundingCylinder& cylinder) const = 0;

  virtual void computeBoundingBox(AABB& bbox) const = 0;

  inline BodyPtr cloneAt(const Eigen::Isometry3d& pose) const
  {
    return cloneAt(pose, padding_, scale_);
  }

  virtual BodyPtr cloneAt(const Eigen::Isometry3d& pose, double padding, double scaling) const = 0;

  virtual void updateInternalData() = 0;

protected:
  virtual void useDimensions(const shapes::Shape* shape) = 0;

  double scale_;

  double padding_;

  shapes::ShapeType type_;

  Eigen::Isometry3d pose_;

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class Sphere : public Body
{
public:
  Sphere() : Body()
  {
    type_ = shapes::SPHERE;
  }

  Sphere(const shapes::Shape* shape) : Body()
  {
    type_ = shapes::SPHERE;
    setDimensions(shape);
  }

  explicit Sphere(const BoundingSphere& sphere);

  ~Sphere() override = default;

  std::vector<double> getDimensions() const override;
  std::vector<double> getScaledDimensions() const override;

  bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const override;
  double computeVolume() const override;
  bool samplePointInside(random_numbers::RandomNumberGenerator& rng, unsigned int max_attempts,
                         Eigen::Vector3d& result) const override;
  void computeBoundingSphere(BoundingSphere& sphere) const override;
  void computeBoundingCylinder(BoundingCylinder& cylinder) const override;
  void computeBoundingBox(AABB& bbox) const override;
  bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir,
                     EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const override;

  BodyPtr cloneAt(const Eigen::Isometry3d& pose, double padding, double scale) const override;

  void updateInternalData() override;

protected:
  void useDimensions(const shapes::Shape* shape) override;

  // shape-dependent data
  double radius_;

  // pose/padding/scaling-dependent values & values computed for convenience and fast upcoming computations
  Eigen::Vector3d center_;
  double radiusU_;
  double radius2_;

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class Cylinder : public Body
{
public:
  Cylinder() : Body()
  {
    type_ = shapes::CYLINDER;
  }

  Cylinder(const shapes::Shape* shape) : Body()
  {
    type_ = shapes::CYLINDER;
    setDimensions(shape);
  }

  explicit Cylinder(const BoundingCylinder& cylinder);

  ~Cylinder() override = default;

  std::vector<double> getDimensions() const override;
  std::vector<double> getScaledDimensions() const override;

  bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const override;
  double computeVolume() const override;
  bool samplePointInside(random_numbers::RandomNumberGenerator& rng, unsigned int max_attempts,
                         Eigen::Vector3d& result) const override;
  void computeBoundingSphere(BoundingSphere& sphere) const override;
  void computeBoundingCylinder(BoundingCylinder& cylinder) const override;
  void computeBoundingBox(AABB& bbox) const override;
  bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir,
                     EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const override;

  BodyPtr cloneAt(const Eigen::Isometry3d& pose, double padding, double scale) const override;

  void updateInternalData() override;

protected:
  void useDimensions(const shapes::Shape* shape) override;

  // shape-dependent data
  double length_;
  double radius_;

  // pose/padding/scaling-dependent values & values computed for convenience and fast upcoming computations
  Eigen::Vector3d center_;
  Eigen::Vector3d normalH_;
  Eigen::Vector3d normalB1_;
  Eigen::Vector3d normalB2_;

  double length2_;
  double radiusU_;
  double radiusB_;
  double radiusBSqr_;
  double radius2_;
  double d1_;
  double d2_;

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class Box : public Body
{
public:
  Box() : Body()
  {
    type_ = shapes::BOX;
  }

  Box(const shapes::Shape* shape) : Body()
  {
    type_ = shapes::BOX;
    setDimensions(shape);
  }

  explicit Box(const AABB& aabb);

  ~Box() override = default;

  std::vector<double> getDimensions() const override;
  std::vector<double> getScaledDimensions() const override;

  bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const override;
  double computeVolume() const override;
  bool samplePointInside(random_numbers::RandomNumberGenerator& rng, unsigned int max_attempts,
                         Eigen::Vector3d& result) const override;
  void computeBoundingSphere(BoundingSphere& sphere) const override;
  void computeBoundingCylinder(BoundingCylinder& cylinder) const override;
  void computeBoundingBox(AABB& bbox) const override;
  bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir,
                     EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const override;

  BodyPtr cloneAt(const Eigen::Isometry3d& pose, double padding, double scale) const override;

  void updateInternalData() override;

protected:
  void useDimensions(const shapes::Shape* shape) override;  // (x, y, z) = (length, width, height)

  // shape-dependent data
  double length_;
  double width_;
  double height_;

  // pose/padding/scaling-dependent values & values computed for convenience and fast upcoming computations
  Eigen::Vector3d center_;
  Eigen::Matrix3d invRot_;

  Eigen::Vector3d minCorner_;
  Eigen::Vector3d maxCorner_;

  double length2_;
  double width2_;
  double height2_;
  double radiusB_;
  double radius2_;

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class ConvexMesh : public Body
{
public:
  ConvexMesh() : Body()
  {
    type_ = shapes::MESH;
    scaled_vertices_ = nullptr;
  }

  ConvexMesh(const shapes::Shape* shape) : Body()
  {
    type_ = shapes::MESH;
    scaled_vertices_ = nullptr;
    setDimensions(shape);
  }

  ~ConvexMesh() override = default;

  std::vector<double> getDimensions() const override;
  std::vector<double> getScaledDimensions() const override;

  bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const override;
  double computeVolume() const override;

  void computeBoundingSphere(BoundingSphere& sphere) const override;
  void computeBoundingCylinder(BoundingCylinder& cylinder) const override;
  void computeBoundingBox(AABB& bbox) const override;
  bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir,
                     EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const override;

  const std::vector<unsigned int>& getTriangles() const;
  const EigenSTL::vector_Vector3d& getVertices() const;
  const EigenSTL::vector_Vector3d& getScaledVertices() const;

  const EigenSTL::vector_Vector4d& getPlanes() const;

  BodyPtr cloneAt(const Eigen::Isometry3d& pose, double padding, double scale) const override;

  void computeScaledVerticesFromPlaneProjections();

  void correctVertexOrderFromPlanes();

  void updateInternalData() override;

protected:
  void useDimensions(const shapes::Shape* shape) override;

  unsigned int countVerticesBehindPlane(const Eigen::Vector4f& planeNormal) const;

  bool isPointInsidePlanes(const Eigen::Vector3d& point) const;

  // PIMPL structure
  struct MeshData;

  // shape-dependent data; keep this in one struct so that a cheap pointer copy can be done in cloneAt()
  std::shared_ptr<MeshData> mesh_data_;

  // pose/padding/scaling-dependent values & values computed for convenience and fast upcoming computations
  Eigen::Isometry3d i_pose_;
  Eigen::Vector3d center_;
  double radiusB_;
  double radiusBSqr_;
  Box bounding_box_;

  // pointer to an array of scaled vertices
  // If the padding is 0 & scaling is 1, then there is no need to have scaled vertices;
  // we can just point to the vertices in mesh_data_.
  // Otherwise, point to scaled_vertices_storage_
  EigenSTL::vector_Vector3d* scaled_vertices_;

private:
  std::unique_ptr<EigenSTL::vector_Vector3d> scaled_vertices_storage_;

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

class BodyVector
{
public:
  BodyVector();

  BodyVector(const std::vector<shapes::Shape*>& shapes, const EigenSTL::vector_Isometry3d& poses, double padding = 0.0);

  ~BodyVector();

  void addBody(Body* body);

  void addBody(const shapes::Shape* shape, const Eigen::Isometry3d& pose, double padding = 0.0);

  void clear();

  void setPose(unsigned int i, const Eigen::Isometry3d& pose);

  std::size_t getCount() const;

  bool containsPoint(const Eigen::Vector3d& p, bool verbose = false) const;

  bool containsPoint(const Eigen::Vector3d& p, std::size_t& index, bool verbose = false) const;

  bool intersectsRay(const Eigen::Vector3d& origin, const Eigen::Vector3d& dir, std::size_t& index,
                     EigenSTL::vector_Vector3d* intersections = nullptr, unsigned int count = 0) const;

  const Body* getBody(unsigned int i) const;

private:
  std::vector<Body*> bodies_;
};

typedef std::shared_ptr<Body> BodyPtr;

typedef std::shared_ptr<const Body> BodyConstPtr;
}  // namespace bodies

#endif