Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Compound Members  

nodeprint.h

Go to the documentation of this file.
00001 /***************************************************************************
00002 *  @file    print.h
00003 *  @version 1.0
00004 *
00005 *  @author  Ingo Herwig, TU Darmstadt, FG Regelsystemtheorie und Robotik
00006 *  @author  Eva Brucherseifer, TU Darmstadt, FG Regelsystemtheorie und Robotik
00007 *  @date    2001
00008 *
00009 ***************************************************************************/
00010 
00011 /***************************************************************************
00012  *                                                                         *
00013  *   This program is free software; you can redistribute it and/or modify  *
00014  *   it under the terms of the GNU General Library Public License as       *
00015  *   published by the Free Software Foundation; either version 2 of the    *
00016  *   License, or (at your option) any later version.                       *
00017  *                                                                         *
00018  ***************************************************************************/
00019 
00020 #ifndef NODEPRINT_H
00021 #define NODEPRINT_H
00022 
00023 #include <map>
00024 #include "node.h"
00025 #include "nodevisitor.h"
00026 #include "nodeoutputstrategy.h"
00027 #include "nodeiterator.h"
00028 
00029 namespace treecomp
00030 {
00031 
00032 /**
00033  * Position holds the x- ,y-coordinate of a point
00034  */
00035 struct Position
00036 {
00037     double x;
00038     double y;
00039 };
00040 
00041 
00042 
00043 // =====================
00044 // === LayoutVisitor ===
00045 // =====================
00046 /**
00047  * The LayoutVisitor is used to position the tree nodes on a plane.
00048  * It uses a simple algorithm that positions the nodes on a discrete array with distance 1 so that
00049  * all leaves are equal distant from their neugbours.
00050  * The positions are stored in a map thet is provided by 'getMap()'.
00051  *
00052  * Yes, that is not the best layout algorithm... If anyone needs a better one, you might
00053  * convince me to backport the better one I have ;-)
00054  */
00055 
00056 template<class _TContent, class _TIter>
00057 class LayoutVisitor
00058     : public NodeVisitor<typename _TIter::const_iterator, const Node<_TContent>,
00059         const NormalNode<_TContent>,const RootNode<_TContent> >
00060 {
00061 public:
00062     typedef LayoutVisitor<_TContent,_TIter> _Self;
00063     typedef NodeVisitor<typename _TIter::const_iterator, const Node<_TContent>,
00064         const NormalNode<_TContent>,const RootNode<_TContent> >
00065         _Base;
00066 
00067     virtual _Self* construct() const { return new _Self(); }
00068     virtual _Self* clone() const { return new _Self(*this); }
00069     virtual ~LayoutVisitor() {}
00070 
00071     virtual void operator()(_TIter& iter);
00072     virtual void visitNormalNode(const NormalNode<_TContent>* node);
00073     virtual void visitRootNode(const RootNode<_TContent>* node);
00074 
00075     virtual std::map<const Node<_TContent>*, Position> getMap() const { return m_map; }
00076 
00077 protected:
00078     void addNode(const Node<_TContent>* node, Position pos);
00079     Position calculatePosition(const Node<_TContent>* node);
00080     
00081     std::map<const Node<_TContent>*, Position> m_map;
00082 private:
00083     virtual LayoutVisitor& operator=(const LayoutVisitor&) {return *this;}
00084 };
00085 
00086 
00087 
00088 // ==============================
00089 // === TEXGraphOutputStrategy ===
00090 // ==============================
00091 /**
00092  * This strategy writes the nodes in TEX format.
00093  * It uses a position-map that is created by 'LayoutVisitor' and
00094  * set with the method 'setMap()'.
00095  */
00096 template<class _TContent>
00097 class TEXGraphOutputStrategy : public StreamOutputStrategy<_TContent>
00098 {
00099 public:
00100     explicit TEXGraphOutputStrategy<_TContent>(std::ostream* out=&std::cout, double scale=1, double border=5)
00101         : StreamOutputStrategy<_TContent>(out), m_width(0), m_height(0), m_scale(scale), m_border(border) {}
00102     virtual TEXGraphOutputStrategy<_TContent>* construct() const { return new TEXGraphOutputStrategy<_TContent>; }
00103     virtual TEXGraphOutputStrategy<_TContent>* clone() const { return new TEXGraphOutputStrategy<_TContent>(*this); }
00104     virtual ~TEXGraphOutputStrategy() {}
00105 
00106     virtual void writeHeader();
00107     virtual void writeFooter();
00108     virtual void writeNormalNode(const NormalNode<_TContent>* node);
00109     virtual void writeRootNode(const RootNode<_TContent>* node);
00110 
00111     virtual void setScale(double scale) { m_scale = scale; }
00112     virtual void setPositionMap(std::map<const Node<_TContent>*, Position> pMap) { m_pMap = pMap; }
00113 
00114 protected:
00115     virtual void writeEdge(const Node<_TContent>* node);
00116     virtual std::string formatName(std::string name);
00117     virtual int getMapIndex(const Node<_TContent>* node);
00118     std::map<const Node<_TContent>*, Position> m_pMap;
00119     double m_width;
00120     double m_height;
00121     double m_scale;
00122     double m_border;
00123 };
00124 
00125 
00126 // =================== Template definition =================================
00127 
00128 
00129 // =====================
00130 // === LayoutVisitor ===
00131 // =====================
00132 
00133 /**
00134  * Start the layout process
00135  * @param iter The NodeIterator that iterates over all nodes to visit
00136  */
00137 template<class _TContent, class _TIter>
00138 //void LayoutVisitor<_TContent>::start(NodeIterator<_TContent>* iter)
00139 void LayoutVisitor<_TContent,_TIter>::operator()(_TIter& iter)
00140 {
00141     init(iter);
00142     m_map.clear();
00143     iterate(this);
00144 }
00145 
00146 /**
00147  * Take a NormalNode and put it in the list
00148  * @param node The NormalNode to visit
00149  */
00150 template<class _TContent, class _TIter>
00151 void LayoutVisitor<_TContent,_TIter>::visitNormalNode(const NormalNode<_TContent>* node)
00152 {
00153     addNode(node, calculatePosition(node));
00154 }
00155 
00156 /**
00157  * Take a RootNode and put its subtree in the list
00158  * @param node The RootNode to visit
00159  */
00160 template<class _TContent, class _TIter>
00161 void LayoutVisitor<_TContent,_TIter>::visitRootNode(const RootNode<_TContent>* node)
00162 {
00163     addNode(node, calculatePosition(node));
00164 }
00165 
00166 /**
00167  * Take a Node and put it in the list
00168  * @param node The Node to add
00169  */
00170 template<class _TContent, class _TIter>
00171 void LayoutVisitor<_TContent,_TIter>::addNode(const Node<_TContent>* node, Position position)
00172 {
00173     m_map.insert( typename std::map<const Node<_TContent>*, Position>::value_type(node, position) );
00174 }
00175 
00176 /**
00177  * Calculate node position using the described algorithm
00178  * @param node The Node to calculate the position for
00179  */
00180 template<class _TContent, class _TIter>
00181 Position LayoutVisitor<_TContent,_TIter>::calculatePosition(const Node<_TContent>* node)
00182 {
00183     Position pos;
00184     const Node<_TContent>* parent = node->getParent();
00185     if (!parent)
00186     {
00187         // start here
00188         pos.x = 0.0;
00189         pos.y = 0.0;
00190     }
00191     else
00192     {
00193         Position parentPos = m_map[parent];
00194         pos.y = parentPos.y + 1;
00195         const std::list<Node<_TContent>*>* siblings = parent->getChildren();
00196         if (siblings->front() == node)
00197             pos.x = parentPos.x;
00198         else
00199         {
00200             // find leftmost sibling of node
00201             typename std::list<Node<_TContent>*>::const_iterator nlIter = find(siblings->begin(), siblings->end(), node);
00202             const Node<_TContent>* leftSibling = *(--nlIter);
00203             // find x-coordinate rightmost descendant of leftmost sibling
00204             double maxX = 0;
00205             typename Node<_TContent>::const_all_iterator anIter = leftSibling->beginAll();
00206             for (; anIter != leftSibling->endAll(); ++anIter)
00207                 if (m_map[anIter()].x >= maxX)
00208                     maxX = m_map[anIter()].x;
00209             pos.x = maxX + 2;
00210             // reposition parents
00211             while (parent)
00212             {
00213                 m_map[parent].x += 1;
00214                 parent = parent->getParent();
00215             }
00216         }
00217     }
00218     return pos;
00219 }
00220 
00221 
00222 
00223 // ==============================
00224 // === TEXGraphOutputStrategy ===
00225 // ==============================
00226 /**
00227  * Write the TEX header
00228  */
00229 template<class _TContent>
00230 void TEXGraphOutputStrategy<_TContent>::writeHeader()
00231 {
00232     // calculate bounding box
00233     m_width = 0;
00234     m_height = 0;
00235     typename std::map<const Node<_TContent>*, Position>::const_iterator pmIter;
00236     for (pmIter = m_pMap.begin(); pmIter != m_pMap.end(); ++pmIter)
00237     {
00238         if ((*pmIter).second.x >= m_width)
00239             m_width = (*pmIter).second.x;
00240         if ((*pmIter).second.y >= m_height)
00241             m_height = (*pmIter).second.y;
00242     }
00243     m_width *= m_scale;
00244     m_height *= m_scale;
00245 
00246     *m_out << "%% This is a generated file!\n"
00247     << "%% Requires pstricks and pst-node styles.\n"
00248     << "\\begin{figure}[htb]\n"
00249     << "\\begin{center}\n"
00250     << "\\psset{unit=1mm, arrows=-, nodesep=0pt, fillstyle=solid}\n"
00251     << "\\begin{pspicture}(" << m_width + 2*m_border << ',' << m_height + 2*m_border << ")\n";
00252     //    *m_out << "\\put(0,0){\\framebox(" << m_width + 2*m_border << ',' << m_height + 2*m_border << "){}}\n";
00253 }
00254 
00255 /**
00256  * Write the TEX footer
00257  */
00258 template<class _TContent>
00259 void TEXGraphOutputStrategy<_TContent>::writeFooter()
00260 {
00261     // get tree root for naming
00262     const Node<_TContent>* root = (*(m_pMap.begin())).first;
00263     while(root->getParent())
00264         root = root->getParent();
00265     std::string treeName = formatName(root->getName());
00266     std::string caption = treeName;
00267     std::string label = treeName;
00268     if (treeName[0] == '\\')
00269     {
00270         caption = "$" + treeName + "$"; // math mode for symbols
00271         label.erase(label.begin());
00272     }
00273     *m_out << "\\end{pspicture}\n";
00274     *m_out << "\\caption{" << caption << "}\n";
00275     *m_out << "\\label{tree: " << label << "}\n";
00276     *m_out << "\\end{center}\n";
00277     *m_out << "\\end{figure}\n";
00278 }
00279 
00280 /**
00281  * Write the normalNode content
00282  */
00283 template<class _TContent>
00284 void TEXGraphOutputStrategy<_TContent>::writeNormalNode(const NormalNode<_TContent>* node)
00285 {
00286     if (m_pMap.count(node))
00287     {
00288         // write node name in oval
00289         *m_out << "\\rput(" << (m_border + m_pMap[node].x * m_scale) << ','
00290         << m_border + m_height - m_pMap[node].y * m_scale
00291         << "){\\Rnode{" << getMapIndex(node) << "}{{\\footnotesize \\psovalbox{\\(" << formatName(node->getName()) << "\\)}}}}\n";
00292 
00293         writeEdge(node);
00294     }
00295     else
00296     {
00297         *m_out << "Error: Didn't find node " + node->getName() + " in position map\n";
00298     }
00299 }
00300 
00301 /**
00302  * Write the RootNode content
00303  */
00304 template<class _TContent>
00305 void TEXGraphOutputStrategy<_TContent>::writeRootNode(const RootNode<_TContent>* node)
00306 {
00307     if (m_pMap.count(node))
00308     {
00309         // write node name in oval
00310         *m_out << "\\rput(" << (m_border + m_pMap[node].x * m_scale) << ','
00311         << m_border + m_height - m_pMap[node].y * m_scale
00312         << "){\\Rnode{" << getMapIndex(node) << "}{{\\footnotesize \\psovalbox{\\(\\bf " << formatName(node->getName()) << "\\)}}}}\n";
00313 
00314         writeEdge(node);
00315     }
00316     else
00317     {
00318         *m_out << "Error: Didn't find node " + node->getName() + " in position map\n";
00319     }
00320 }
00321 
00322 /**
00323  * Write the edge to the parent
00324  */
00325 template<class _TContent>
00326 void TEXGraphOutputStrategy<_TContent>::writeEdge(const Node<_TContent>* node)
00327 {
00328     if (node->getParent())
00329     {
00330         int parentIndex = getMapIndex(node->getParent());
00331         int nodeIndex = getMapIndex(node);
00332         if (node->isFixed())
00333         {
00334             *m_out << "\\ncline[doubleline=true]{" << parentIndex << "}{" << nodeIndex << "}\n";
00335         }
00336         else
00337         {
00338             *m_out << "\\ncline[doubleline=false]{" << parentIndex << "}{" << nodeIndex << "}\n";
00339         }
00340     }
00341 }
00342 
00343 /**
00344  * Takes the word in quotation marks as name if existing
00345  */
00346 template<class _TContent>
00347 std::string 
00348 TEXGraphOutputStrategy<_TContent>::formatName(std::string name)
00349 {
00350     std::string::size_type start = name.find("\"");
00351     if (start < name.size())
00352     {
00353         std::string::size_type end = name.find("\"", start+1);
00354         name=name.substr(start+1, end-start-1);
00355     }
00356     return name;
00357 }
00358 
00359 /**
00360  * Returns the index of the node in the position map
00361  */
00362 template<class _TContent>
00363 int TEXGraphOutputStrategy<_TContent>::getMapIndex(const Node<_TContent>* node)
00364 {
00365     int i = 0;
00366     typename std::map<const Node<_TContent>*, Position>::const_iterator pmIter;
00367     for (pmIter = m_pMap.begin(); pmIter != m_pMap.end(); ++pmIter)
00368     {
00369         if (node == (*pmIter).first)
00370             return i;
00371         ++i;
00372     }
00373     return 0;
00374 }
00375 
00376 
00377 } // namespace treecomp
00378 
00379 
00380 #endif //PRINT_H

Generated on Mon Jan 6 12:02:08 2003 for TreeComp by doxygen1.2.17