Skip to content
Snippets Groups Projects
helper.cc 39.1 KiB
Newer Older
Joseph Mirabel's avatar
Joseph Mirabel committed
// Copyright (c) 2016, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-manipulation.
// hpp-manipulation is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-manipulation is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-manipulation. If not, see <http://www.gnu.org/licenses/>.

#include <hpp/manipulation/graph/helper.hh>

#include <boost/array.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
#include <hpp/util/debug.hh>

Joseph Mirabel's avatar
Joseph Mirabel committed
#include <hpp/model/gripper.hh>

#include <hpp/constraints/differentiable-function.hh>

#include <hpp/manipulation/handle.hh>
Joseph Mirabel's avatar
Joseph Mirabel committed
#include <hpp/manipulation/graph/node.hh>
#include <hpp/manipulation/graph/edge.hh>
#include <hpp/manipulation/graph/node-selector.hh>
#include <hpp/manipulation/graph/guided-node-selector.hh>
#include <hpp/manipulation/problem-solver.hh>
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
namespace hpp {
  namespace manipulation {
    namespace graph {
Joseph Mirabel's avatar
Joseph Mirabel committed
      namespace helper {
        template <bool forPath>
          void NumericalConstraintsAndPassiveDofs::addToComp
          (GraphComponentPtr_t comp) const
        {
          if (nc.empty ()) return;
          NodePtr_t n;
          if (forPath) {
            n = HPP_DYNAMIC_PTR_CAST (Node, comp);
            if (!n) throw std::logic_error ("Wrong type: expect a Node");
          }
          NumericalConstraints_t::const_iterator it;
          IntervalsContainer_t::const_iterator itpdof = pdof.begin ();
          for (it = nc.begin (); it != nc.end (); ++it) {
            if (*it) {
              if (forPath) n->addNumericalConstraintForPath (*it, *itpdof);
              else      comp->addNumericalConstraint (*it, *itpdof);
            }
Joseph Mirabel's avatar
Joseph Mirabel committed
            ++itpdof;
          }
          assert (itpdof == pdof.end ());
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        template <bool param>
          void NumericalConstraintsAndPassiveDofs::specifyFoliation
          (LevelSetEdgePtr_t lse) const
        {
          NumericalConstraints_t::const_iterator it;
          IntervalsContainer_t::const_iterator itpdof = pdof.begin ();
          for (it = nc.begin (); it != nc.end (); ++it) {
            if (*it) {
              if (param) lse->insertParamConstraint (*it, *itpdof);
              else   lse->insertConditionConstraint (*it, *itpdof);
            }
Joseph Mirabel's avatar
Joseph Mirabel committed
            ++itpdof;
          }
          assert (itpdof == pdof.end ());
        }

        void FoliatedManifold::addToNode (NodePtr_t comp) const
        {
          nc.addToComp <false> (comp);
          for (LockedJoints_t::const_iterator it = lj.begin ();
              it != lj.end (); ++it)
            if (*it && (*it)->numberDof() > 0)
              comp->addLockedJointConstraint (*it);
Joseph Mirabel's avatar
Joseph Mirabel committed
          nc_path.addToComp <true> (comp);
        }

        void FoliatedManifold::addToEdge (EdgePtr_t comp) const
        {
          nc_fol.addToComp <false> (comp);
          for (LockedJoints_t::const_iterator it = lj_fol.begin ();
              it != lj_fol.end (); ++it)
              comp->addLockedJointConstraint (*it);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        void FoliatedManifold::specifyFoliation (LevelSetEdgePtr_t lse) const
        {
          nc.specifyFoliation <false> (lse);
          for (LockedJoints_t::const_iterator it = lj.begin ();
              it != lj.end (); ++it)
            if (*it && (*it)->numberDof() > 0)
              lse->insertConditionConstraint (*it);
Joseph Mirabel's avatar
Joseph Mirabel committed

          nc_fol.specifyFoliation <true> (lse);
          for (LockedJoints_t::const_iterator it = lj_fol.begin ();
              it != lj_fol.end (); ++it)
            lse->insertParamConstraint (*it);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }
Joseph Mirabel's avatar
Joseph Mirabel committed

        namespace {
Joseph Mirabel's avatar
Joseph Mirabel committed
          template <int gCase>
            struct CaseTraits {
              static const bool pregrasp = (gCase & WithPreGrasp);
              static const bool intersec = !((gCase & NoGrasp) || (gCase & NoPlace));
              static const bool preplace = (gCase & WithPrePlace);
              static const bool valid = !(gCase == (NoGrasp | NoPlace));

Joseph Mirabel's avatar
Joseph Mirabel committed
              static const std::size_t nbWaypoints = (pregrasp?1:0) + (intersec?1:0) + (preplace?1:0);
              static const std::size_t Nnodes = 2 + nbWaypoints;
              static const std::size_t Nedges = 1 + nbWaypoints;
              // static const std::size_t iNpregrasp = pregrasp?1 + 1:nbWaypoints;
              // static const std::size_t iNpreplace = pregrasp?1 + 1:nbWaypoints;
              typedef boost::array <NodePtr_t, Nnodes> NodeArray;
              typedef boost::array <EdgePtr_t, Nedges> EdgeArray;

              static inline const NodePtr_t& Npregrasp (const NodeArray& n)
              {
                assert (pregrasp); return n[1];
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline const NodePtr_t& Nintersec (const NodeArray& n)
              {
                assert (intersec); return n[1 + (pregrasp?1:0)];
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline const NodePtr_t& Npreplace (const NodeArray& n)
              {
                assert (preplace); return n[1 + (pregrasp?1:0) + (intersec?1:0)];
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline EdgePtr_t makeWE (
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::string& name,
                  const NodePtr_t& from, const NodePtr_t& to,
                  const size_type& w)
              {
Joseph Mirabel's avatar
Joseph Mirabel committed
                if (Nedges > 1) {
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                      (from->linkTo (name, to, w, WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  return we;
                } else return from->linkTo (name, to, w, Edge::create);
Joseph Mirabel's avatar
Joseph Mirabel committed
              }

              static inline NodeArray makeWaypoints (
                  const NodePtr_t& from, const NodePtr_t& to,
                  const std::string& name)
              {
                NodeSelectorPtr_t ns = from->parentGraph ()->nodeSelector ();
                NodeArray nodes;
                std::size_t r = 0;
                nodes[r] = from; ++r;
                if (pregrasp) {
                  nodes[r] = ns->createNode (name + "_pregrasp", true); ++r;
                }
                if (intersec) {
                  nodes[r] = ns->createNode (name + "_intersec", true); ++r;
                }
                if (preplace) {
                  nodes[r] = ns->createNode (name + "_preplace", true); ++r;
                }
                nodes[r] = to;
                return nodes;
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              static inline EdgePtr_t makeLSEgrasp (const std::string& name,
                  const NodeArray& n, const EdgeArray& e,
                  const size_type w, LevelSetEdgePtr_t& gls)
              {
                if (Nedges > 1) {
                  const std::size_t T = (pregrasp?1:0) + (intersec?1:0);
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                    (n.front()->linkTo (name + "_ls", n.back(), w,
                                        WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  gls = linkWaypoint <LevelSetEdge> (n, T-1, T, name, "ls");
                  for (std::size_t i = 0; i < Nedges - 1; ++i)
                    we->setWaypoint (Nedges - 1 - i, e[i], n[i]);
                  we->setWaypoint (T-1, gls, n[T]);
                  gls->node (n.front());
                  gls->setShort (preplace);
                  return we;
                } else {
                  assert (gCase == (GraspOnly | NoPlace)
                      && "Cannot implement a LevelSetEdge for grasping");
                  gls = boost::static_pointer_cast <LevelSetEdge>
                    (n.front()->linkTo (name + "_ls", n.back(), w,
                                        LevelSetEdge::create));
                  return gls;
                }
              }

              static inline EdgePtr_t makeLSEplace (const std::string& name,
                  const NodeArray& n, const EdgeArray& e,
                  const size_type w, LevelSetEdgePtr_t& pls)
              {
                if (Nedges > 1) {
                  const std::size_t T = (pregrasp?1:0) + (intersec?1:0);
                  WaypointEdgePtr_t we = boost::static_pointer_cast <WaypointEdge>
                    (n.back()->linkTo (name + "_ls", n.front(), w,
                                       WaypointEdge::create));
                  we->nbWaypoints (nbWaypoints);
                  pls = linkWaypoint <LevelSetEdge> (n, T+1, T, name, "ls");
                  for (std::size_t i = Nedges - 1; i != 0; --i)
                    we->setWaypoint (Nedges - 1 - i, e[i], n[i]);
                  we->setWaypoint (Nedges - 1 - T, pls, n[T]);
                  pls->node (n.back ());
                  pls->setShort (preplace);
                  return we;
                } else {
                  assert (gCase == (GraspOnly | NoPlace)
                      && "Cannot implement a LevelSetEdge for grasping");
                  pls = boost::static_pointer_cast <LevelSetEdge>
                    (n.back()->linkTo (name + "_ls", n.front(), w,
                                       LevelSetEdge::create));
                  return pls;
                }
              }

Joseph Mirabel's avatar
Joseph Mirabel committed
              template <typename EdgeType>
              static inline boost::shared_ptr<EdgeType> linkWaypoint (
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const NodeArray& nodes,
                  const std::size_t& iF, const std::size_t& iT,
                  const std::string& prefix,
                  const std::string& suffix = "")
              {
                std::stringstream ss;
                ss << prefix << "_" << iF << iT;
                if (suffix.length () > 0) ss << "_" << suffix;
                return boost::static_pointer_cast <EdgeType>
                    (nodes[iF]->linkTo (ss.str(), nodes[iT], -1, EdgeType::create));
              }
Joseph Mirabel's avatar
Joseph Mirabel committed

              template <bool forward>
              static inline EdgeArray linkWaypoints (
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const NodeArray& nodes, const EdgePtr_t& edge,
Joseph Mirabel's avatar
Joseph Mirabel committed
                  const std::string& name)
              {
                EdgeArray e;
Joseph Mirabel's avatar
Joseph Mirabel committed
                WaypointEdgePtr_t we = HPP_DYNAMIC_PTR_CAST(WaypointEdge, edge);
Joseph Mirabel's avatar
Joseph Mirabel committed
                if (forward)
                  for (std::size_t i = 0; i < Nedges - 1; ++i) {
                    e[i] = linkWaypoint <Edge> (nodes, i, i + 1, name);
                    we->setWaypoint (i, e[i], nodes[i+1]);
                  }
                else
                  for (std::size_t i = Nedges - 1; i != 0; --i) {
                    e[i] = linkWaypoint <Edge> (nodes, i + 1, i, name);
                    we->setWaypoint (Nedges - 1 - i, e[i], nodes[i]);
                  }
                e[(forward?Nedges - 1:0)] = we;
                return e;
              }

              static inline void setNodeConstraints (const NodeArray& n,
                  const FoliatedManifold& g, const FoliatedManifold& pg,
                  const FoliatedManifold& p, const FoliatedManifold& pp,
                  const FoliatedManifold& m)
Joseph Mirabel's avatar
Joseph Mirabel committed
              {
                // From and to are not populated automatically
                // to avoid duplicates.
                if (pregrasp) {
                  p .addToNode (Npregrasp (n));
                  pg.addToNode (Npregrasp (n));
                  m .addToNode (Npregrasp (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (intersec) {
                  p .addToNode (Nintersec (n));
                  g .addToNode (Nintersec (n));
                  m .addToNode (Nintersec (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
                if (preplace) {
                  pp.addToNode (Npreplace (n));
                  g .addToNode (Npreplace (n));
                  m .addToNode (Npreplace (n));
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
              }

              static inline void setEdgeConstraints (const EdgeArray& e,
                  const FoliatedManifold& g, const FoliatedManifold& p,
                  const FoliatedManifold& m)
              {
                // The border B
                const std::size_t B = (pregrasp?1:0) + (intersec?1:0);
                for (std::size_t i = 0; i < B     ; ++i) p.addToEdge (e[i]);
                for (std::size_t i = B; i < Nedges; ++i) g.addToEdge (e[i]);
                for (std::size_t i = 0; i < Nedges; ++i) m.addToEdge (e[i]);
              }

              template <bool forward>
              static inline void setEdgeProp
              (const EdgeArray& e, const NodeArray& n)
              {
                /// Last is short
                const std::size_t K = (forward?1:0);
                for (std::size_t i = K; i < Nedges - 1 + K; ++i)
                  e[i]->setShort (true);
                // The border B
                std::size_t B;
                if ((gCase & NoGrasp)) // There is no grasp
                  B = 0;
                else // There is a grasp
                  B = 1 + (pregrasp?1:0);
Joseph Mirabel's avatar
Joseph Mirabel committed
                for (std::size_t i = 0; i < B     ; ++i) e[i]->node (n[0]);
                for (std::size_t i = B; i < Nedges; ++i) e[i]->node (n[Nnodes-1]);
              }
            };
Joseph Mirabel's avatar
Joseph Mirabel committed
        template <int gCase> Edges_t createEdges (
Joseph Mirabel's avatar
Joseph Mirabel committed
              const std::string& forwName,   const std::string& backName,
              const NodePtr_t& from,         const NodePtr_t& to,
              const size_type& wForw,        const size_type& wBack,
              const FoliatedManifold& grasp, const FoliatedManifold& pregrasp,
              const FoliatedManifold& place, const FoliatedManifold& preplace,
              const bool levelSetGrasp,      const bool levelSetPlace,
              const FoliatedManifold& submanifoldDef)
          {
Joseph Mirabel's avatar
Joseph Mirabel committed
            typedef CaseTraits<gCase> T;
            assert (T::valid && "Not a valid case.");
            typedef typename T::NodeArray NodeArray;
            typedef typename T::EdgeArray EdgeArray;
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
            // Create the edges
            EdgePtr_t weForw = T::makeWE (forwName, from, to, wForw),
                      weBack = T::makeWE (backName, to, from, wBack),
                      weForwLs, weBackLs;
Joseph Mirabel's avatar
Joseph Mirabel committed

            std::string name = forwName;
Joseph Mirabel's avatar
Joseph Mirabel committed
            NodeArray n = T::makeWaypoints (from, to, name);
Joseph Mirabel's avatar
Joseph Mirabel committed
            EdgeArray eF = T::template linkWaypoints <true> (n, weForw, name);
Joseph Mirabel's avatar
Joseph Mirabel committed

            // Set the nodes constraints
            // Note that submanifold is not taken into account for nodes
            // because the edges constraints will enforce configuration to stay
            // in a leaf, and so in the manifold itself.
            T::setNodeConstraints (n, grasp, pregrasp, place, preplace,
                submanifoldDef);
Joseph Mirabel's avatar
Joseph Mirabel committed

            // Set the edges properties
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::template setEdgeProp <true> (eF, n);
Joseph Mirabel's avatar
Joseph Mirabel committed

            // Set the edges constraints
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::setEdgeConstraints (eF, grasp, place, submanifoldDef);
Joseph Mirabel's avatar
Joseph Mirabel committed

Joseph Mirabel's avatar
Joseph Mirabel committed
            LevelSetEdgePtr_t gls;
            if (levelSetGrasp)
              weForwLs = T::makeLSEgrasp (name, n, eF, 10*wForw, gls);

Joseph Mirabel's avatar
Joseph Mirabel committed
            // Populate bacward edge
Joseph Mirabel's avatar
Joseph Mirabel committed
            EdgeArray eB = T::template linkWaypoints <false> (n, weBack, name);
Joseph Mirabel's avatar
Joseph Mirabel committed
            T::template setEdgeProp <false> (eB, n);
Joseph Mirabel's avatar
Joseph Mirabel committed

            T::setEdgeConstraints (eB, grasp, place, submanifoldDef);
Joseph Mirabel's avatar
Joseph Mirabel committed
            LevelSetEdgePtr_t pls;
            if (levelSetPlace)
              weBackLs = T::makeLSEplace (name, n, eB, 10*wBack, pls);

            Edges_t ret = boost::assign::list_of (weForw)(weBack);
Joseph Mirabel's avatar
Joseph Mirabel committed

            if (levelSetPlace) {
Joseph Mirabel's avatar
Joseph Mirabel committed
              if (!place.foliated ()) {
Joseph Mirabel's avatar
Joseph Mirabel committed
                hppDout (warning, "You asked for a LevelSetEdge for placement, "
                    "but did not specify the target foliation. "
                    "It will have no effect");
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              grasp.addToEdge (pls);
              place.specifyFoliation (pls);
              submanifoldDef.addToEdge (pls);
              pls->buildHistogram ();
              place.addToEdge (weBackLs);
              submanifoldDef.addToEdge (weBackLs);
              ret.push_back (weBackLs);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
            if (levelSetGrasp) {
Joseph Mirabel's avatar
Joseph Mirabel committed
              if (!grasp.foliated ()) {
Joseph Mirabel's avatar
Joseph Mirabel committed
                hppDout (warning, "You asked for a LevelSetEdge for grasping, "
                    "but did not specify the target foliation. "
                    "It will have no effect");
              }
Joseph Mirabel's avatar
Joseph Mirabel committed
              place.addToEdge (gls);
              grasp.specifyFoliation (gls);
              submanifoldDef.addToEdge (gls);
              gls->buildHistogram ();
              grasp.addToEdge (weForwLs);
              submanifoldDef.addToEdge (weForwLs);
              ret.push_back (weForwLs);
            return ret;
        EdgePtr_t createLoopEdge (
              const std::string& loopName,
              const NodePtr_t& node,
              const size_type& w,
              const bool levelSet,
              const FoliatedManifold& submanifoldDef)
        {
          // Create the edges
          EdgePtr_t loop;
          if (levelSet)
               loop = node->linkTo (loopName, node, w, LevelSetEdge::create);
          else loop = node->linkTo (loopName, node, w, Edge::create);

          loop->node (node);
          submanifoldDef.addToEdge (loop);

          if (levelSet) {
            if (!submanifoldDef.foliated ()) {
              hppDout (warning, "You asked for a LevelSetEdge for looping, "
                  "but did not specify the target foliation. "
                  "It will have no effect");
            }
            LevelSetEdgePtr_t ls = HPP_DYNAMIC_PTR_CAST (LevelSetEdge, loop);
            submanifoldDef.specifyFoliation (ls);
            ls->buildHistogram ();
          }

          return loop;
        }

Joseph Mirabel's avatar
Joseph Mirabel committed
        void graspManifold (
            const GripperPtr_t& gripper, const HandlePtr_t& handle,
            FoliatedManifold& grasp, FoliatedManifold& pregrasp)
        {
          NumericalConstraintPtr_t gc  = handle->createGrasp (gripper);
          grasp.nc.nc.push_back (gc);
          grasp.nc.pdof.push_back (SizeIntervals_t ());
          grasp.nc_path.nc.push_back (gc);
          // TODO: see function declaration
          grasp.nc_path.pdof.push_back (SizeIntervals_t ());
          NumericalConstraintPtr_t gcc = handle->createGraspComplement (gripper);
          if (gcc->function ().outputSize () > 0) {
            grasp.nc_fol.nc.push_back (gcc);
            grasp.nc_fol.pdof.push_back (SizeIntervals_t());
          }

          const value_type c = handle->clearance () + gripper->clearance ();
          NumericalConstraintPtr_t pgc = handle->createPreGrasp (gripper, c);
          pregrasp.nc.nc.push_back (pgc);
          pregrasp.nc.pdof.push_back (SizeIntervals_t());
          pregrasp.nc_path.nc.push_back (pgc);
          pregrasp.nc_path.pdof.push_back (SizeIntervals_t());
        }

        void strictPlacementManifold (
            const NumericalConstraintPtr_t placement,
            const NumericalConstraintPtr_t preplacement,
            const NumericalConstraintPtr_t placementComplement,
            FoliatedManifold& place, FoliatedManifold& preplace)
        {
          place.nc.nc.push_back (placement);
          place.nc.pdof.push_back (SizeIntervals_t());
          place.nc_path.nc.push_back (placement);
          place.nc_path.pdof.push_back (SizeIntervals_t());
          if (placementComplement && placementComplement->function().outputSize () > 0) {
            place.nc_fol.nc.push_back (placementComplement);
            place.nc_fol.pdof.push_back (SizeIntervals_t());
          }

          preplace.nc.nc.push_back (preplacement);
          preplace.nc.pdof.push_back (SizeIntervals_t());
          preplace.nc_path.nc.push_back (preplacement);
          preplace.nc_path.pdof.push_back (SizeIntervals_t());
        }

        void relaxedPlacementManifold (
            const NumericalConstraintPtr_t placement,
            const NumericalConstraintPtr_t preplacement,
            const LockedJoints_t objectLocks,
            FoliatedManifold& place, FoliatedManifold& preplace)
        {
          if (placement) {
            place.nc.nc.push_back (placement);
            place.nc.pdof.push_back (SizeIntervals_t());
            // The placement constraints are not required in the path, as long as
            // they are satisfied at both ends and the object does not move. The
            // former condition is ensured by the placement constraints on both
            // ends and the latter is ensure by the LockedJoint constraints.
            place.nc_path.nc.push_back (placement);
            place.nc_path.pdof.push_back (SizeIntervals_t());
          std::copy (objectLocks.begin(), objectLocks.end(), std::back_inserter(place.lj_fol));
Joseph Mirabel's avatar
Joseph Mirabel committed

          if (placement && preplacement) {
            preplace.nc.nc.push_back (preplacement);
            preplace.nc.pdof.push_back (SizeIntervals_t());
            // preplace.nc_path.nc.push_back (preplacement);
            // preplace.nc_path.pdof.push_back (SizeIntervals_t());
          }
Joseph Mirabel's avatar
Joseph Mirabel committed
        namespace {
          typedef std::size_t index_t;
          typedef std::vector <index_t> IndexV_t;
          typedef std::list <index_t> IndexL_t;
          typedef std::pair <index_t, index_t> Grasp_t;
          typedef boost::tuple <NodePtr_t,
                  FoliatedManifold>
                    NodeAndManifold_t;
          //typedef std::vector <index_t, index_t> GraspV_t;
          /// GraspV_t corresponds to a unique ID of a  permutation.
          /// - its size is the number of grippers,
          /// - the values correpond to the index of the handle (0..nbHandle-1), or
          ///   nbHandle to mean no handle. 
          typedef std::vector <index_t> GraspV_t;

          struct Result {
            GraphPtr_t graph;
            std::vector<NodeAndManifold_t> nodes;
            std::vector< boost::array<NumericalConstraintPtr_t,3> > graspCs;
Joseph Mirabel's avatar
Joseph Mirabel committed
            index_t nG, nOH;
            GraspV_t dims;
            const Grippers_t& gs;
            const Objects_t& ohs;

            Result (const Grippers_t& grippers, const Objects_t& objects, GraphPtr_t g) :
              graph (g), nG (grippers.size ()), nOH (0), gs (grippers), ohs (objects)
            {
              BOOST_FOREACH (const Object_t& o, objects) {
                nOH += o.get<1>().size();
              }
              dims.resize (nG);
              dims[0] = nOH + 1;
              for (index_t i = 1; i < nG; ++i)
                dims[i] = dims[i-1] * (nOH + 1);
              nodes.resize (dims[nG-1] * (nOH + 1));
              graspCs.resize (nG * nOH);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }

            NodeAndManifold_t& operator() (const GraspV_t& iG)
            {
Joseph Mirabel's avatar
Joseph Mirabel committed
              for (index_t i = 1; i < nG; ++i)
                iGOH += dims[i] * (iG[i]);
              return nodes [iGOH];
            }

            inline boost::array<NumericalConstraintPtr_t,3>& graspConstraint (
                const index_t& iG, const index_t& iOH)
            {
              boost::array<NumericalConstraintPtr_t,3>& gcs =
                graspCs [iG * nOH + iOH];
              if (!gcs[0]) {
                hppDout (info, "Create grasps constraints for ("
                    << iG << ", " << iOH << ")");
                const GripperPtr_t& g (gs[iG]);
                const HandlePtr_t& h (handle (iOH));
                gcs[0] = h->createGrasp (g);
                gcs[1] = h->createGraspComplement (g);
                const value_type c = h->clearance () + g->clearance ();
                gcs[2] = h->createPreGrasp (g, c);
              }
              return gcs;
            }

Joseph Mirabel's avatar
Joseph Mirabel committed
            const Object_t& object (const index_t& iOH) const {
              index_t iH = iOH;
              BOOST_FOREACH (const Object_t& o, ohs) {
                if (iH < o.get<1>().size()) return o;
                iH -= o.get<1>().size();
              }
              throw std::out_of_range ("Handle index");
            }

            const HandlePtr_t& handle (const index_t& iOH) const {
              index_t iH = iOH;
              BOOST_FOREACH (const Object_t& o, ohs) {
                if (iH < o.get<1>().size()) return o.get<1>()[iH];
                iH -= o.get<1>().size();
              }
              throw std::out_of_range ("Handle index");
            }
Joseph Mirabel's avatar
Joseph Mirabel committed

            /// Check is an object is grasped by the GraspV_t
            bool isObjectGrasped (const GraspV_t& idxOH,
                const Object_t& o) const
            {
              assert (idxOH.size () == nG);
              for (std::size_t i = 0; i < idxOH.size (); ++i)
                if (idxOH[i] < nOH) // This grippers grasps an object
                  if (o.get<2>() == object(idxOH[i]).get<2>())
                    return true;
              return false;
            }

            /// Get a node name from a set of grasps
            std::string name (const GraspV_t& idxOH, bool abbrev = false) const {
              assert (idxOH.size () == nG);
              std::stringstream ss;
              bool first = true;
              std::string sepGOH = (abbrev?"-":" grasps "),
                          sep    = (abbrev?":":" : ");
              for (std::size_t i = 0; i < idxOH.size (); ++i) {
                if (idxOH[i] < nOH) { // This grippers grasps an object
                  if (first) first = false; else ss << sep; 
                  if (abbrev) ss << i << sepGOH << idxOH[i];
                  else
                    ss << gs[i]->name() << sepGOH << handle (idxOH[i])->name ();
                }
              }
              if (first) return (abbrev?"f":"free");
              return ss.str();
            }

            /// Get an edge name from a set of grasps
            std::pair<std::string, std::string> name
              (const GraspV_t& gFrom, const GraspV_t& gTo, const index_t iG)
            {
              const std::string nf (name (gFrom, true)),
                                nt (name (gTo, true));
              std::stringstream ssForw, ssBack;
              const char sep[] = " | ";
              ssForw << gs[iG]->name() << " > " << handle (gTo[iG])->name () << sep << nf;
              ssBack << gs[iG]->name() << " < " << handle (gTo[iG])->name () << sep << nt;
              return std::make_pair (ssForw.str(), ssBack.str ());
            }

            std::string nameLoopEdge (const GraspV_t& gFrom)
            {
              const std::string nf (name (gFrom, true));
              std::stringstream ss;
              const char sep[] = " | ";
              ss << "Loop" << sep << nf;
              return ss.str();
Joseph Mirabel's avatar
Joseph Mirabel committed
            }

            void graspManifold (const index_t& iG, const index_t& iOH,
                FoliatedManifold& grasp, FoliatedManifold& pregrasp)
            {
              boost::array<NumericalConstraintPtr_t,3>& gcs
                = graspConstraint (iG, iOH);
              grasp.nc.nc.push_back (gcs[0]);
              grasp.nc.pdof.push_back (SizeIntervals_t ());
              grasp.nc_path.nc.push_back (gcs[0]);
              // TODO: see function declaration
              grasp.nc_path.pdof.push_back (SizeIntervals_t ());
              if (gcs[1]->function ().outputSize () > 0) {
                grasp.nc_fol.nc.push_back (gcs[1]);
                grasp.nc_fol.pdof.push_back (SizeIntervals_t());
              }

              pregrasp.nc.nc.push_back (gcs[2]);
              pregrasp.nc.pdof.push_back (SizeIntervals_t());
              pregrasp.nc_path.nc.push_back (gcs[2]);
              pregrasp.nc_path.pdof.push_back (SizeIntervals_t());
            }
Joseph Mirabel's avatar
Joseph Mirabel committed
          };

          const NodeAndManifold_t& makeNode (Result& r, const GraspV_t& g,
              const int priority)
Joseph Mirabel's avatar
Joseph Mirabel committed
          {
            NodeAndManifold_t& nam = r (g);
            if (!nam.get<0>()) {
              hppDout (info, "Creating node " << r.name (g));
              nam.get<0>() = r.graph->nodeSelector ()->createNode
                (r.name (g), false, priority);
Joseph Mirabel's avatar
Joseph Mirabel committed
              // Loop over the grippers and create grasping constraints if required
              FoliatedManifold unused;
              std::set <index_t> idxsOH;
              for (index_t i = 0; i < r.nG; ++i) {
                if (g[i] < r.nOH) {
                  idxsOH.insert (g[i]);
                  r.graspManifold (i, g[i], nam.get<1>(), unused);
Joseph Mirabel's avatar
Joseph Mirabel committed
                }
              }
              index_t iOH = 0;
              BOOST_FOREACH (const Object_t& o, r.ohs) {
                bool oIsGrasped = false;
                // TODO: use the fact that the set is sorted.
                // BOOST_FOREACH (const HandlePtr_t& h, o.get<1>())
Joseph Mirabel's avatar
Joseph Mirabel committed
                for (index_t i = 0; i < o.get<1>().size(); ++i) {
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                  ++iOH;
                }
                if (!oIsGrasped)
                  relaxedPlacementManifold (o.get<0>().get<0>(),
                      o.get<0>().get<1>(),
                      o.get<0>().get<2>(),
                      nam.get<1>(), unused);
              }
              nam.get<1>().addToNode (nam.get<0>());

              createLoopEdge (r.nameLoopEdge (g),
                  false,
                  // TODO nam.get<1>().foliated(),
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
Joseph Mirabel's avatar
Joseph Mirabel committed

          /// Arguments are such that
          /// \li gTo[iG] != gFrom[iG]
          /// \li for all i != iG, gTo[iG] == gFrom[iG]
          void makeEdge (Result& r,
              const GraspV_t& gFrom, const GraspV_t& gTo,
              const index_t iG, const int priority)
            const NodeAndManifold_t& from = makeNode (r, gFrom, priority),
                                     to   = makeNode (r, gTo, priority+1);
            const Object_t& o = r.object (gTo[iG]);

            /// Detect when grasping an object already grasped.
            bool noPlace = r.isObjectGrasped (gFrom, o);

            FoliatedManifold grasp, pregrasp, place, preplace,
                             submanifold;
            r.graspManifold (iG, gTo[iG], grasp, pregrasp);
            if (!noPlace) {
              relaxedPlacementManifold (o.get<0>().get<0>(),
                  o.get<0>().get<1>(),
                  o.get<0>().get<2>(),
                  place, preplace);
            }
            std::pair<std::string, std::string> names =
              r.name (gFrom, gTo, iG);
            {
              FoliatedManifold unused;
              std::set <index_t> idxsOH;
              for (index_t i = 0; i < r.nG; ++i) {
                if (gFrom[i] < r.nOH) {
                  idxsOH.insert (gFrom[i]);
                  r.graspManifold (i, gFrom[i], submanifold, unused);
                }
              }
              index_t iOH = 0;
              BOOST_FOREACH (const Object_t& o, r.ohs) {
                bool oIsGrasped = false;
                const index_t iOHstart = iOH;
                for (; iOH < iOHstart + o.get<1>().size(); ++iOH) {
                  if (iOH == gTo [iG]) {
                    oIsGrasped = true;
                    iOH = iOHstart + o.get<1>().size();
                    break;
                  }
                  if (idxsOH.erase (iOH) == 1) oIsGrasped = true;
                }
                if (!oIsGrasped)
                  relaxedPlacementManifold (o.get<0>().get<0>(),
                      o.get<0>().get<1>(),
                      o.get<0>().get<2>(),
                      submanifold, unused);
              }
            }
            if (pregrasp.empty ()) {
              if (noPlace)
                createEdges <GraspOnly | NoPlace> (
                    names.first           , names.second,
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <GraspOnly | PlaceOnly> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else {
                hppDout (error, "GraspOnly | WithPrePlace not implemeted yet");
                /*
                   createEdges <GraspOnly | WithPrePlace> (
                   from.get<0> ()        , to.get<0>(),
                   1                     , 1,
                   grasp                 , pregrasp,
                   place                 , preplace,
                   grasp.foliated ()     , place.foliated(),
                   submanifold); // */
Joseph Mirabel's avatar
Joseph Mirabel committed
              }
              if (noPlace)
                createEdges <WithPreGrasp | NoPlace> (
                    names.first           , names.second,
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else if (preplace.empty ())
                createEdges <WithPreGrasp | PlaceOnly> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
              else
                createEdges <WithPreGrasp | WithPrePlace> (
                    from.get<0> ()        , to.get<0>(),
                    1                     , 1,
                    grasp                 , pregrasp,
                    place                 , preplace,
                    grasp.foliated ()     , place.foliated(),
                    submanifold);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
Joseph Mirabel's avatar
Joseph Mirabel committed

          /// idx are the available grippers
          void recurseGrippers (Result& r,
              const IndexV_t& idx_g, const IndexV_t& idx_oh,
              const GraspV_t& grasps, const int depth)
            if (idx_g.empty () || idx_oh.empty ()) return;
            IndexV_t nIdx_g (idx_g.size() - 1);
            IndexV_t nIdx_oh (idx_oh.size() - 1);
            for (IndexV_t::const_iterator itx_g = idx_g.begin ();
                itx_g != idx_g.end (); ++itx_g) {
              // Copy all element except itx_g
              std::copy (boost::next (itx_g), idx_g.end (),
                  std::copy (idx_g.begin (), itx_g, nIdx_g.begin ())
Joseph Mirabel's avatar
Joseph Mirabel committed
                  );
              for (IndexV_t::const_iterator itx_oh = idx_oh.begin ();
                  itx_oh != idx_oh.end (); ++itx_oh) {
                // Create the edge for the selected grasp
                GraspV_t nGrasps = grasps;
                nGrasps [*itx_g] = *itx_oh;
                makeEdge (r, grasps, nGrasps, *itx_g, depth);
                // Copy all element except itx_oh
                std::copy (boost::next (itx_oh), idx_oh.end (),
                    std::copy (idx_oh.begin (), itx_oh, nIdx_oh.begin ())
                    );
                // Do all the possible combination below this new grasp
                recurseGrippers (r, nIdx_g, nIdx_oh, nGrasps, depth + 2);
Joseph Mirabel's avatar
Joseph Mirabel committed
            }
          }
        }

        void graphBuilder (
            const Objects_t& objects,
            const Grippers_t& grippers,
            GraphPtr_t graph)
        {
          if (!graph) throw std::logic_error ("The graph must be initialized");
          NodeSelectorPtr_t ns = graph->nodeSelector ();
          if (!ns) throw std::logic_error ("The graph does not have a NodeSelector");

Joseph Mirabel's avatar
Joseph Mirabel committed
          Result r (grippers, objects, graph);

          IndexV_t availG (r.nG), availOH (r.nOH);
          for (index_t i = 0; i < r.nG; ++i) availG[i] = i;
          for (index_t i = 0; i < r.nOH; ++i) availOH[i] = i;

          GraspV_t iG (r.nG, r.nOH);

          recurseGrippers (r, availG, availOH, iG, 0);
Joseph Mirabel's avatar
Joseph Mirabel committed
        }

        GraphPtr_t graphBuilder (
            const ProblemSolverPtr_t& ps,
            const std::string& graphName,
            const StringList_t& griNames,
            const std::list <ObjectDef_t>& objs,
            const StringList_t& envNames,
	    const std::vector <Rule>& rules,
            const value_type& prePlaceWidth)
        {
          const Device& robot = *(ps->robot ());
          Grippers_t grippers (griNames.size());
          index_t i = 0;
          BOOST_FOREACH (const std::string& gn, griNames) {
            grippers[i] = robot.get <GripperPtr_t> (gn);
            ++i;
          }
          Objects_t objects (objs.size());
          i = 0;
          const value_type margin = 1e-3;
          bool prePlace = (prePlaceWidth > 0);
          BOOST_FOREACH (const ObjectDef_t& od, objs) {
            // Create handles
            objects[i].get<1> ().resize (od.handles.size());
            Handles_t::iterator it = objects[i].get<1> ().begin();
            BOOST_FOREACH (const std::string hn, od.handles) {
              *it = robot.get <HandlePtr_t> (hn);
              ++it;
            }
            // Create placement
            if (!envNames.empty() && !od.shapes.empty ()) {
              const std::string placeN = "place_" + od.name;
              ps->createPlacementConstraint (placeN,
                  od.shapes, envNames, margin);
              objects[i].get<0> ().get<0> () =
                ps->core::ProblemSolver::get <NumericalConstraintPtr_t> (placeN);
              if (prePlace) {
                ps->createPrePlacementConstraint ("pre" + placeN,
                    od.shapes, envNames, margin, prePlaceWidth);
                objects[i].get<0> ().get<1> () =
                  ps->core::ProblemSolver::get <NumericalConstraintPtr_t> ("pre" + placeN);
              }
            }
            // Create object lock
            using model::JointVector_t;
            assert (robot.has <JointVector_t> (od.name));
            BOOST_FOREACH (const JointPtr_t& oj, robot.get<JointVector_t> (od.name)) {
              LockedJointPtr_t lj = core::LockedJoint::create (oj,
                  robot.currentConfiguration()
                  .segment (oj->rankInConfiguration (), oj->configSize ()));
              ps->ProblemSolver::ThisC_t::add <LockedJointPtr_t> ("lock_" + oj->name (), lj);
              objects[i].get<0> ().get<2> ().push_back (lj);
            }
            ++i;
          }
          GraphPtr_t graph = Graph::create (graphName,
              ps->robot(), ps->problem());
          graph->nodeSelector (
              GuidedNodeSelector::create ("nodeSelector",
              ps->roadmap ()));
          graph->maxIterations  (ps->maxIterations ());
          graph->errorThreshold (ps->errorThreshold ());

          graphBuilder (objects, grippers, graph);
          ps->constraintGraph (graph);
          return graph;
        }
Joseph Mirabel's avatar
Joseph Mirabel committed
      } // namespace helper
Joseph Mirabel's avatar
Joseph Mirabel committed
    } // namespace graph
  } // namespace manipulation
} // namespace hpp