diff --git a/include/hpp/manipulation/graph/edge.hh b/include/hpp/manipulation/graph/edge.hh
index 6d60864568fe6c09ecb17f423748f11884f5cb5d..b8e06466eff02cfd29f20482b401cca23332f520 100644
--- a/include/hpp/manipulation/graph/edge.hh
+++ b/include/hpp/manipulation/graph/edge.hh
@@ -216,18 +216,13 @@ namespace hpp {
       /// \note
       ///   Implementation details: let's say, between the two states \f$N_f\f$ and \f$N_t\f$,
       ///   two waypoints are required:
-      ///   \f$ N_f \xrightarrow{e_0} n_0 \xrightarrow{e_1} n_1 \xrightarrow{E} N_t\f$.
-      ///   The outmost WaypointEdg contains:
+      ///   \f$ N_f \xrightarrow{e_0} n_0 \xrightarrow{e_1} n_1 \xrightarrow{e_2} N_t\f$.
+      ///   The WaypointEdge contains:
       ///   \li from: \f$N_f\f$,
       ///   \li to: \f$N_t\f$,
-      ///   \li constraints: those of edge \f$E\f$,
-      ///   \li waypoint: \f$(E_1, n_1)\f$.
-      ///
-      ///   where \f$E_1\f$ is an instance of class WaypointEdge containing:
-      ///   \li from: \f$N_f\f$,
-      ///   \li to: \f$n_1\f$,
-      ///   \li constraints: those of edge \f$e_1\f$,
-      ///   \li waypoint: \f$(e_0, n_0)\f$.
+      ///   \li states: \f$(n_0, n_1)\f$
+      ///   \li transitions: \f$(e_0, e_1, e_2)\f$
+      ///   \li constraints: any calls to the constraints throw,
       class HPP_MANIPULATION_DLLAPI WaypointEdge : public Edge
       {
         public:
@@ -258,7 +253,7 @@ namespace hpp {
 
           std::size_t nbWaypoints () const
           {
-            return waypoints_.size ();
+            return edges_.size () - 1;
           }
 
           /// Set waypoint index with wEdge and wTo.
@@ -278,14 +273,10 @@ namespace hpp {
           virtual std::ostream& print (std::ostream& os) const;
 
         private:
-          typedef std::pair < EdgePtr_t, StatePtr_t > Waypoint_t;
-          typedef std::vector <Waypoint_t> Waypoints_t;
-
-          Waypoints_t waypoints_;
+          Edges_t edges_;
+          States_t states_;
 
-          mutable Configuration_t init_;
           mutable matrix_t configs_;
-          mutable Configuration_t result_;
 
           WaypointEdgeWkPtr_t wkPtr_;
       }; // class WaypointEdge
diff --git a/src/graph/edge.cc b/src/graph/edge.cc
index dec99c8906da10137efe733aabbe80eaf354d430..bacf320cd8d78454ad0bace5e9793cdca80b2a79 100644
--- a/src/graph/edge.cc
+++ b/src/graph/edge.cc
@@ -337,13 +337,16 @@ namespace hpp {
 			       const StateWkPtr_t& to)
       {
         Edge::init (weak, graph, from, to);
+        nbWaypoints(0);
         wkPtr_ = weak;
       }
 
       bool WaypointEdge::canConnect (ConfigurationIn_t q1, ConfigurationIn_t q2) const
       {
         /// TODO: This is not correct
-        return waypoints_.back().first->canConnect (q1, q2) && Edge::canConnect (q1, q2);
+        for (std::size_t i = 0; i < edges_.size (); ++i)
+          if (!edges_[i]->canConnect(q1, q2)) return false;
+        return true;
       }
 
       bool WaypointEdge::build (core::PathPtr_t& path, ConfigurationIn_t q1,
@@ -355,34 +358,23 @@ namespace hpp {
            graph_.lock ()->robot ()->numberDof ());
         // Many times, this will be called rigth after WaypointEdge::applyConstraints so config_
         // already satisfies the constraints.
-        bool useCache = init_.isApprox (q1) && result_.isApprox (q2);
-        if (!useCache) configs_.col (0) = q2;
-
-        assert (waypoints_[0].first);
-        if (!waypoints_[0].first->applyConstraints (q1, configs_.col (0))) {
-          hppDout (info, "Waypoint edge " << name() << ": applyConstraints failed at waypoint 0."
-              << "\nUse cache: " << useCache
-              );
-          return false;
+        size_type n = edges_.size() - 1;
+        bool useCache = configs_.col(0).isApprox (q1)
+          &&            configs_.col(n).isApprox (q2);
+        if (!useCache) {
+          configs_.col(0) = q1;
+          configs_.col(n) = q2;
         }
-        if (!waypoints_[0].first->build (p, q1, configs_.col (0))) {
-          hppDout (info, "Waypoint edge " << name() << ": build failed at waypoint 0."
-              << "\nUse cache: " << useCache
-              );
-          return false;
-        }
-        pv->appendPath (p);
 
-        for (std::size_t i = 1; i < waypoints_.size (); ++i) {
-          assert (waypoints_[i].first);
-          if (!useCache) configs_.col (i) = q2;
-          if (!waypoints_[i].first->applyConstraints (configs_.col(i-1), configs_.col (i))) {
+        for (std::size_t i = 0; i < edges_.size (); ++i) {
+          if (!useCache) configs_.col (i+1) = q2;
+          if (!edges_[i]->applyConstraints (configs_.col(i), configs_.col (i+1))) {
             hppDout (info, "Waypoint edge " << name() << ": applyConstraints failed at waypoint " << i << "."
                 << "\nUse cache: " << useCache
                 );
             return false;
           }
-          if (!waypoints_[i].first->build (p, configs_.col(i-1), configs_.col (i))) {
+          if (!edges_[i]->build (p, configs_.col(i), configs_.col (i+1))) {
             hppDout (info, "Waypoint edge " << name() << ": build failed at waypoint " << i << "."
                 << "\nUse cache: " << useCache
                 );
@@ -391,65 +383,60 @@ namespace hpp {
           pv->appendPath (p);
         }
 
-        if (!Edge::build (p, configs_.col (configs_.cols()-1), q2))
-          return false;
-        pv->appendPath (p);
-
         path = pv;
         return true;
       }
 
       bool WaypointEdge::applyConstraints (ConfigurationIn_t qoffset, ConfigurationOut_t q) const
       {
-        assert (waypoints_[0].first);
-        configs_.col (0) = q;
-        if (!waypoints_[0].first->applyConstraints (qoffset, configs_.col (0))) {
-          q = configs_.col(0);
-          return false;
-        }
-        for (std::size_t i = 1; i < waypoints_.size (); ++i) {
-          assert (waypoints_[i].first);
-          configs_.col (i) = q;
-          if (!waypoints_[i].first->applyConstraints (configs_.col(i-1), configs_.col (i))) {
-            q = configs_.col(i);
+        assert (configs_.cols() == size_type(edges_.size() + 1));
+        configs_.col(0) = qoffset;
+        for (std::size_t i = 0; i < edges_.size (); ++i) {
+          configs_.col (i+1) = q;
+          if (!edges_[i]->applyConstraints (configs_.col(i), configs_.col (i+1))) {
+            q = configs_.col(i+1);
             return false;
           }
         }
-        bool success = Edge::applyConstraints (configs_.col (configs_.cols()-1), q);
-        init_ = qoffset;
-        result_ = q;
-        return success;
+        q = configs_.col(edges_.size());
+        return true;
       }
 
       void WaypointEdge::nbWaypoints (const size_type number)
       {
-        waypoints_.resize (number);
+        edges_.resize (number + 1);
+        states_.resize (number + 1);
+        states_.back() = to();
         const size_type nbDof = graph_.lock ()->robot ()->configSize ();
-        configs_ = matrix_t (nbDof, number);
-        init_   = Configuration_t (nbDof);
-        result_ = Configuration_t (nbDof);
+        configs_ = matrix_t (nbDof, number + 2);
       }
 
       void WaypointEdge::setWaypoint (const std::size_t index,
 				      const EdgePtr_t wEdge,
 				      const StatePtr_t wTo)
       {
-        assert (index < waypoints_.size());
-        waypoints_[index] = Waypoint_t (wEdge, wTo);
+        assert (edges_.size() == states_.size());
+        assert (index < edges_.size());
+        if (index == states_.size() - 1) {
+          assert (!wTo || wTo == to());
+        } else {
+          states_[index] = wTo;
+        }
+        edges_[index] = wEdge;
       }
 
       template <>
       EdgePtr_t WaypointEdge::waypoint <Edge> (const std::size_t index) const
       {
-        assert (index < waypoints_.size()); 
-        return waypoints_[index].first;
+        assert (index < edges_.size()); 
+        return edges_[index];
       }
 
       template <>
       WaypointEdgePtr_t WaypointEdge::waypoint <WaypointEdge> (const std::size_t index) const
       {
-        assert (index < waypoints_.size()); 
-        return HPP_DYNAMIC_PTR_CAST (WaypointEdge, waypoints_[index].first);
+        assert (index < edges_.size()); 
+        return HPP_DYNAMIC_PTR_CAST (WaypointEdge, edges_[index]);
       }
 
       std::ostream& WaypointEdge::print (std::ostream& os) const
@@ -464,29 +451,18 @@ namespace hpp {
       {
         // First print the waypoint node, then the first edge.
         da ["style"]="dashed";
-        for (std::size_t i = 0; i < waypoints_.size (); ++i)
-          waypoints_[i].second->dotPrint (os, da);
+        for (std::size_t i = 0; i < states_.size () - 1; ++i)
+          states_[i]->dotPrint (os, da);
 
         da ["style"]="solid";
-        for (std::size_t i = 0; i < waypoints_.size (); ++i)
-          waypoints_[i].first->dotPrint (os, da) << std::endl;
+        for (std::size_t i = 0; i < edges_.size (); ++i)
+          edges_[i]->dotPrint (os, da) << std::endl;
 
         da ["style"]="dotted";
         da ["dir"] = "both";
         da ["arrowtail"]="dot";
-        // TODO: This is very ugly. There ought to be a better way of 
-        // getting the real from() Node.
-        // We should be using Edge::dotPrint (...) instead of the following
-        // paragraph.
-        da.insert ("shape", "onormal");
-        da.insertWithQuote ("label", name());
-        dot::Tooltip tp; tp.addLine ("Edge constains:");
-        populateTooltip (tp);
-        da.insertWithQuote ("tooltip", tp.toStr());
-        da.insertWithQuote ("labeltooltip", tp.toStr());
-        os << waypoints_.back().second->id () << " -> " << to()->id () << " " << da << ";";
 
-        return os;
+        return Edge::dotPrint (os, da);
       }
 
       std::ostream& LevelSetEdge::print (std::ostream& os) const