From 9cd6813b079d65c5eada038f33d80ff145e1aa8b Mon Sep 17 00:00:00 2001 From: Joseph Mirabel <jmirabel@laas.fr> Date: Tue, 18 Nov 2014 10:18:02 +0100 Subject: [PATCH] Enhance DOT print functionality of the graph. --- CMakeLists.txt | 1 + include/hpp/manipulation/graph/dot.hh | 51 +++++++++++++++++++ include/hpp/manipulation/graph/edge.hh | 6 +-- .../hpp/manipulation/graph/graph-component.hh | 3 +- include/hpp/manipulation/graph/graph.hh | 2 +- .../hpp/manipulation/graph/node-selector.hh | 2 +- include/hpp/manipulation/graph/node.hh | 2 +- src/CMakeLists.txt | 2 + src/graph/dot.cc | 44 ++++++++++++++++ src/graph/edge.cc | 27 +++++++--- src/graph/graph-component.cc | 2 +- src/graph/graph.cc | 4 +- src/graph/node-selector.cc | 2 +- src/graph/node.cc | 18 +++++-- 14 files changed, 144 insertions(+), 22 deletions(-) create mode 100644 include/hpp/manipulation/graph/dot.hh create mode 100644 src/graph/dot.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index cea373b..dc4b724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ SET (${PROJECT_NAME}_HEADERS include/hpp/manipulation/graph/statistics.hh include/hpp/manipulation/graph/graph-component.hh include/hpp/manipulation/graph/fwd.hh + include/hpp/manipulation/graph/dot.hh ) # Add dependency toward hpp-model library in pkg-config file. diff --git a/include/hpp/manipulation/graph/dot.hh b/include/hpp/manipulation/graph/dot.hh new file mode 100644 index 0000000..ecf503c --- /dev/null +++ b/include/hpp/manipulation/graph/dot.hh @@ -0,0 +1,51 @@ +// Copyright (c) 2014, LAAS-CNRS +// 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/>. + +#ifndef HPP_MANIPULATION_GRAPH_DOT_HH +# define HPP_MANIPULATION_GRAPH_DOT_HH + +# include <ostream> +# include <map> + +namespace hpp { + namespace manipulation { + namespace graph { + namespace dot { + struct DrawingAttributes { + typedef std::pair <std::string, std::string> Pair; + typedef std::map <std::string, std::string> Map; + Map attr; + + inline void insertWithQuote (const std::string& K, const std::string& V) { + attr.insert (Pair (K, "\"" + V + "\"")); + } + inline void insert (const std::string& K, const std::string& V) { + attr.insert (Pair (K, V)); + } + std::string& operator [] (const std::string& K) { + return attr [K]; + } + }; + + std::ostream& insertComments (std::ostream& os, const std::string& c); + + std::ostream& operator<< (std::ostream& os, const DrawingAttributes& da); + } // namespace dot + } // namespace graph + } // namespace manipulation +} // namespace hpp + +#endif // HPP_MANIPULATION_GRAPH_DOT_HH diff --git a/include/hpp/manipulation/graph/edge.hh b/include/hpp/manipulation/graph/edge.hh index 65ce4e2..351f742 100644 --- a/include/hpp/manipulation/graph/edge.hh +++ b/include/hpp/manipulation/graph/edge.hh @@ -88,7 +88,7 @@ namespace hpp { } /// Print the object in a stream. - virtual std::ostream& dotPrint (std::ostream& os) const; + virtual std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialization of the object. @@ -169,7 +169,7 @@ namespace hpp { boost::shared_ptr <EdgeType> waypoint () const; /// Print the object in a stream. - virtual std::ostream& dotPrint (std::ostream& os) const; + virtual std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; /// Create inner waypoints. /// \param depth the number of waypoints between from() and to() @@ -219,7 +219,7 @@ namespace hpp { void insertConfigConstraint (const LockedDofPtr_t lockedDof); /// Print the object in a stream. - virtual std::ostream& dotPrint (std::ostream& os) const; + virtual std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialization of the object. diff --git a/include/hpp/manipulation/graph/graph-component.hh b/include/hpp/manipulation/graph/graph-component.hh index 1644fe4..74f66ee 100644 --- a/include/hpp/manipulation/graph/graph-component.hh +++ b/include/hpp/manipulation/graph/graph-component.hh @@ -24,6 +24,7 @@ # include "hpp/manipulation/config.hh" # include "hpp/manipulation/fwd.hh" # include "hpp/manipulation/graph/fwd.hh" +# include "hpp/manipulation/graph/dot.hh" namespace hpp { namespace manipulation { @@ -74,7 +75,7 @@ namespace hpp { void parentGraph(const GraphWkPtr_t& parent); /// Print the component in DOT language. - virtual std::ostream& dotPrint (std::ostream& os) const; + virtual std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialize the component diff --git a/include/hpp/manipulation/graph/graph.hh b/include/hpp/manipulation/graph/graph.hh index 55e7f76..77050d1 100644 --- a/include/hpp/manipulation/graph/graph.hh +++ b/include/hpp/manipulation/graph/graph.hh @@ -84,7 +84,7 @@ namespace hpp { const RobotPtr_t& robot () const; /// Print the component in DOT language. - virtual std::ostream& dotPrint (std::ostream& os) const; + virtual std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialization of the object. diff --git a/include/hpp/manipulation/graph/node-selector.hh b/include/hpp/manipulation/graph/node-selector.hh index 875b99f..de0e0cf 100644 --- a/include/hpp/manipulation/graph/node-selector.hh +++ b/include/hpp/manipulation/graph/node-selector.hh @@ -55,7 +55,7 @@ namespace hpp { } /// Print the object in a stream. - std::ostream& dotPrint (std::ostream& os) const; + std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialization of the object. diff --git a/include/hpp/manipulation/graph/node.hh b/include/hpp/manipulation/graph/node.hh index 15c83e8..6dde6d6 100644 --- a/include/hpp/manipulation/graph/node.hh +++ b/include/hpp/manipulation/graph/node.hh @@ -111,7 +111,7 @@ namespace hpp { } /// Print the object in a stream. - std::ostream& dotPrint (std::ostream& os) const; + std::ostream& dotPrint (std::ostream& os, dot::DrawingAttributes da = dot::DrawingAttributes ()) const; protected: /// Initialize the object. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1cff32..3073519 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,8 @@ ADD_LIBRARY(${LIBRARY_NAME} SHARED graph/graph-component.cc graph/node-selector.cc graph/statistics.cc + + graph/dot.cc ) PKG_CONFIG_USE_DEPENDENCY(${LIBRARY_NAME} hpp-core) diff --git a/src/graph/dot.cc b/src/graph/dot.cc new file mode 100644 index 0000000..dfe592c --- /dev/null +++ b/src/graph/dot.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2014, LAAS-CNRS +// 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/dot.hh" + +namespace hpp { + namespace manipulation { + namespace graph { + namespace dot { + std::ostream& operator<< (std::ostream& os, const DrawingAttributes& da) + { + if (da.attr.empty ()) return os; + os << "["; + size_t i = da.attr.size (); + for (DrawingAttributes::Map::const_iterator it = da.attr.begin (); + it != da.attr.end (); ++it) { + os << it->first << "=" << it->second; + i--; + if (i > 0) os << ", "; + } + return os << "]"; + } + + std::ostream& insertComments (std::ostream& os, const std::string& c) + { + return os << "/*" << std::endl << c << std::endl << "*/"; + } + } // namespace dot + } // namespace graph + } // namespace manipulation +} // namespace hpp diff --git a/src/graph/edge.cc b/src/graph/edge.cc index feb5d8a..d099b92 100644 --- a/src/graph/edge.cc +++ b/src/graph/edge.cc @@ -82,9 +82,11 @@ namespace hpp { return os; } - std::ostream& Edge::dotPrint (std::ostream& os) const + std::ostream& Edge::dotPrint (std::ostream& os, dot::DrawingAttributes da) const { - os << from()->id () << " -> " << to()->id () << " [shape=onormal,label=\"" << name () << "\"];"; + da.insertWithQuote ("label", name ()); + da.insert ("shape", "onormal"); + os << from()->id () << " -> " << to()->id () << " " << da << ";"; return os; } @@ -277,9 +279,19 @@ namespace hpp { return os; } - std::ostream& WaypointEdge::dotPrint (std::ostream& os) const + std::ostream& WaypointEdge::dotPrint (std::ostream& os, dot::DrawingAttributes da) const { - os << from()->id () << " -> " << to()->id () << " [shape=onormal,label=\"" << name () << "\"];"; + // First print the waypoint node, then the first edge. + da ["style"]="dashed"; + waypoint_.second->dotPrint (os, da); + da ["style"]="solid"; + waypoint_.first->dotPrint (os, da) << std::endl; + da ["style"]="dotted"; + da ["dir"] = "both"; + da ["arrowtail"]="dot"; + da.insert ("shape", "onormal"); + da.insertWithQuote ("label", name()); + os << waypoint_.second->id () << " -> " << to()->id () << " " << da << ";"; return os; } @@ -291,10 +303,11 @@ namespace hpp { return os; } - std::ostream& LevelSetEdge::dotPrint (std::ostream& os) const + std::ostream& LevelSetEdge::dotPrint (std::ostream& os, dot::DrawingAttributes da) const { - os << from()->id () << " -> " << to()->id () << " [shape=onormal,label=\"" << name () << "\"];"; - return os; + da.insert ("shape", "onormal"); + da.insert ("style", "dashed"); + return Edge::dotPrint (os, da); } bool LevelSetEdge::applyConstraints (ConfigurationIn_t, ConfigurationOut_t) const diff --git a/src/graph/graph-component.cc b/src/graph/graph-component.cc index e7b6f36..acc4877 100644 --- a/src/graph/graph-component.cc +++ b/src/graph/graph-component.cc @@ -55,7 +55,7 @@ namespace hpp { return os; } - std::ostream& GraphComponent::dotPrint (std::ostream& os) const + std::ostream& GraphComponent::dotPrint (std::ostream& os, dot::DrawingAttributes) const { os << id (); return os; diff --git a/src/graph/graph.cc b/src/graph/graph.cc index 5f42a22..e455cd9 100644 --- a/src/graph/graph.cc +++ b/src/graph/graph.cc @@ -108,9 +108,9 @@ namespace hpp { return edge->pathConstraint (); } - std::ostream& Graph::dotPrint (std::ostream& os) const + std::ostream& Graph::dotPrint (std::ostream& os, dot::DrawingAttributes da) const { - os << "digraph " << id() << " {" << std::endl; + os << "digraph " << id() << " " << da << " {" << std::endl; nodeSelector_->dotPrint (os); os << "}" << std::endl; return os; diff --git a/src/graph/node-selector.cc b/src/graph/node-selector.cc index 2b7e15e..418f470 100644 --- a/src/graph/node-selector.cc +++ b/src/graph/node-selector.cc @@ -59,7 +59,7 @@ namespace hpp { return neighborPicker (); } - std::ostream& NodeSelector::dotPrint (std::ostream& os) const + std::ostream& NodeSelector::dotPrint (std::ostream& os, dot::DrawingAttributes) const { for (Nodes_t::const_iterator it = orderedStates_.begin(); orderedStates_.end() != it; ++it) diff --git a/src/graph/node.cc b/src/graph/node.cc index 24b3b62..b7e30bf 100644 --- a/src/graph/node.cc +++ b/src/graph/node.cc @@ -58,12 +58,22 @@ namespace hpp { return configConstraint()->isSatisfied (config); } - std::ostream& Node::dotPrint (std::ostream& os) const + std::ostream& Node::dotPrint (std::ostream& os, dot::DrawingAttributes da) const { - os << id () << " [label=\"" << name () << "\"];" << std::endl; + da.insertWithQuote ("label", name ()); + da.insert ("style","filled"); + os << id () << " " << da << ";" << std::endl; + + dot::DrawingAttributes dac; + std::vector <double> p = neighbors_.probabilities (); + size_t i = 0; for (Neighbors_t::const_iterator it = neighbors_.begin(); - it != neighbors_.end(); ++it) - it->second->dotPrint (os) << std::endl; + it != neighbors_.end(); ++it) { + std::ostringstream oss; oss << (p[i] * 3 + 0.5); + dac ["penwidth"] = oss.str (); + i++; + it->second->dotPrint (os, dac) << std::endl; + } return os; } -- GitLab