src/work/alpar/graph_to_eps.cc
author alpar
Wed, 05 Jan 2005 10:14:37 +0000
changeset 1051 4ebe32765b48
parent 1050 bcc0766a7b86
child 1055 f901ff02b2d7
permissions -rw-r--r--
graphToEps is now able to write to any ostream.
     1 #include <iostream>
     2 #include<math.h>
     3 
     4 #include<lemon/xy.h>
     5 #include<lemon/maps.h>
     6 #include<lemon/list_graph.h>
     7 
     8 
     9 ///\file \ingroup misc
    10 ///Simple graph drawer
    11 
    12 namespace lemon {
    13 
    14 ///Data structure representing RGB colors.
    15 
    16 ///Data structure representing RGB colors.
    17 ///\ingroup misc
    18 class Color
    19 {
    20   double _r,_g,_b;
    21 public:
    22   ///Default constructor
    23   Color() {}
    24   ///Constructor
    25   Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
    26   ///Returns the red component
    27   double getR() {return _r;}
    28   ///Returns the green component
    29   double getG() {return _g;}
    30   ///Returns the blue component
    31   double getB() {return _b;}
    32   ///Set the color components
    33   void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
    34 };
    35   
    36 ///Default traits class of \ref GraphToEps
    37 
    38 ///Default traits class of \ref GraphToEps
    39 ///
    40 ///\c G is the type of the underlying graph.
    41 template<class G>
    42 struct DefaultGraphToEpsTraits
    43 {
    44   typedef G Graph;
    45   typedef typename Graph::Node Node;
    46   typedef typename Graph::NodeIt NodeIt;
    47   typedef typename Graph::Edge Edge;
    48   typedef typename Graph::EdgeIt EdgeIt;
    49   typedef typename Graph::InEdgeIt InEdgeIt;
    50   typedef typename Graph::OutEdgeIt OutEdgeIt;
    51   
    52 
    53   const Graph &g;
    54 
    55   std::ostream& os;
    56   
    57   ConstMap<typename Graph::Node,xy<double> > _coords;
    58   ConstMap<typename Graph::Node,double > _nodeSizes;
    59 
    60   ConstMap<typename Graph::Node,Color > _nodeColors;
    61   ConstMap<typename Graph::Edge,Color > _edgeColors;
    62 
    63   ConstMap<typename Graph::Edge,double > _edgeWidths;
    64   
    65   double _edgeWidthScale;
    66   
    67   double _nodeScale;
    68   double _xBorder, _yBorder;
    69   double _scale;
    70   double _nodeBorderQuotient;
    71   
    72   bool _drawArrows;
    73   double _arrowLength, _arrowWidth;
    74   
    75   ///Constructor
    76 
    77   ///Constructor
    78   ///\param _g is a reference to the graph to be printed
    79   ///\param _os is a reference to the output stream.
    80   ///By default it is <tt>std::cout</tt>
    81   DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout) :
    82     g(_g), os(_os),
    83     _coords(xy<double>(1,1)), _nodeSizes(1.0),
    84     _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
    85     _edgeWidths(1), _edgeWidthScale(0.3),
    86     _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
    87     _nodeBorderQuotient(.1),
    88     _drawArrows(false), _arrowLength(1), _arrowWidth(0.3) {}
    89 };
    90 
    91 ///Helper class to implement the named parameters of \ref graphToEps()
    92 
    93 ///Helper class to implement the named parameters of \ref graphToEps()
    94 ///\todo Is 'helper class' a good name for this?
    95 ///
    96 template<class T> class GraphToEps : public T 
    97 {
    98   typedef typename T::Graph Graph;
    99   typedef typename Graph::Node Node;
   100   typedef typename Graph::NodeIt NodeIt;
   101   typedef typename Graph::Edge Edge;
   102   typedef typename Graph::EdgeIt EdgeIt;
   103   typedef typename Graph::InEdgeIt InEdgeIt;
   104   typedef typename Graph::OutEdgeIt OutEdgeIt;
   105 
   106   bool dontPrint;
   107 
   108 public:
   109   GraphToEps(const T &t) : T(t), dontPrint(false) {};
   110   
   111   template<class X> struct CoordsTraits : public T {
   112     const X &_coords;
   113     CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
   114   };
   115   ///Sets the map of the node coordinates
   116 
   117   ///Sets the map of the node coordinates.
   118   ///\param x must be a node map with xy<double> or xy<int> values. 
   119   template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
   120     dontPrint=true;
   121     return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
   122   }
   123   template<class X> struct NodeSizesTraits : public T {
   124     const X &_nodeSizes;
   125     NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
   126   };
   127   ///Sets the map of the node sizes
   128 
   129   ///Sets the map of the node sizes
   130   ///\param x must be a node map with \c double (or convertible) values. 
   131   template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
   132   {
   133     dontPrint=true;
   134     return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
   135   }
   136    template<class X> struct EdgeWidthsTraits : public T {
   137     const X &_edgeWidths;
   138     EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
   139   };
   140   ///Sets the map of the edge widths
   141 
   142   ///Sets the map of the edge widths
   143   ///\param x must be a edge map with \c double (or convertible) values. 
   144   template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
   145   {
   146     dontPrint=true;
   147     return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
   148   }
   149 
   150   template<class X> struct NodeColorsTraits : public T {
   151     const X &_nodeColors;
   152     NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
   153   };
   154   ///Sets the map of the node colors
   155 
   156   ///Sets the map of the node colors
   157   ///\param x must be a node map with \ref Color values. 
   158   template<class X> GraphToEps<NodeColorsTraits<X> >
   159   nodeColors(const X &x)
   160   {
   161     dontPrint=true;
   162     return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
   163   }
   164   template<class X> struct EdgeColorsTraits : public T {
   165     const X &_edgeColors;
   166     EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
   167   };
   168   ///Sets the map of the edge colors
   169 
   170   ///Sets the map of the edge colors
   171   ///\param x must be a edge map with \ref Color values. 
   172   template<class X> GraphToEps<EdgeColorsTraits<X> >
   173   edgeColors(const X &x)
   174   {
   175     dontPrint=true;
   176     return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
   177   }
   178   ///Sets a global scale factor for node sizes
   179 
   180   ///Sets a global scale factor for node sizes
   181   ///
   182   GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
   183   ///Sets a global scale factor for edge widths
   184 
   185   ///Sets a global scale factor for edge widths
   186   ///
   187   GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
   188   ///Sets a global scale factor for the whole picture
   189 
   190   ///Sets a global scale factor for the whole picture
   191   ///
   192   GraphToEps<T> &scale(double d) {_scale=d;return *this;}
   193   ///Sets the width of the border around the picture
   194 
   195   ///Sets the width of the border around the picture
   196   ///
   197   GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
   198   ///Sets the width of the border around the picture
   199 
   200   ///Sets the width of the border around the picture
   201   ///
   202   GraphToEps<T> &border(double x, double y) {
   203     _xBorder=x;_yBorder=y;return *this;
   204   }
   205   ///Sets whether to draw arrows
   206 
   207   ///Sets whether to draw arrows
   208   ///
   209   GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
   210   ///Sets the length of the arrowheads
   211 
   212   ///Sets the length of the arrowheads
   213   ///
   214   GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
   215   ///Sets the width of the arrowheads
   216 
   217   ///Sets the width of the arrowheads
   218   ///
   219   GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
   220   
   221   ~GraphToEps() 
   222   {
   223     if(dontPrint) return;
   224     
   225     os << "%!PS-Adobe-2.0 EPSF-2.0\n";
   226     //\todo: Chech whether the graph is empty.
   227     BoundingBox<double> bb;
   228     for(NodeIt n(g);n!=INVALID;++n) {
   229       double ns=_nodeSizes[n]*_nodeScale;
   230       xy<double> p(ns,ns);
   231       bb+=p+_coords[n];
   232       bb+=-p+_coords[n];
   233       }
   234     os << "%%BoundingBox: "
   235 	 << bb.left()*  _scale-_xBorder << ' '
   236 	 << bb.bottom()*_scale-_yBorder << ' '
   237 	 << bb.right()* _scale+_xBorder << ' '
   238 	 << bb.top()*   _scale+_yBorder << '\n';
   239     //x1 y1 x2 y2 cr cg cb w
   240     os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
   241     os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
   242     // x y r cr cg cb
   243     os << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
   244 	 << "     0 0 0 setrgbcolor dup "
   245 	 << _nodeBorderQuotient << " mul setlinewidth "
   246 	 << 1+_nodeBorderQuotient/2 << " div c stroke\n"
   247 	 << "   } bind def\n";
   248     os << "/arrl " << _arrowLength << " def\n";
   249     os << "/arrw " << _arrowWidth << " def\n";
   250     // l dx_norm dy_norm
   251     os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
   252     //len w dx_norm dy_norm x1 y1 cr cg cb
   253     os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
   254 	 << "       /w exch def /len exch def\n"
   255       //	 << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
   256 	 << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
   257 	 << "       len w sub arrl sub dx dy lrl\n"
   258 	 << "       arrw dy dx neg lrl\n"
   259 	 << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
   260 	 << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
   261 	 << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
   262 	 << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
   263 	 << "       arrw dy dx neg lrl\n"
   264 	 << "       len w sub arrl sub neg dx dy lrl\n"
   265 	 << "       closepath fill } bind def\n";
   266     os << "\ngsave\n";
   267     if(_scale!=1.0) os << _scale << " dup scale\n";
   268     os << "%Edges:\ngsave\n";
   269     for(NodeIt n(g);n!=INVALID;++n)
   270       for(OutEdgeIt e(g,n);e!=INVALID;++e)
   271 	if(_drawArrows) {
   272 	  xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
   273 	  double l=sqrt(d.normSquare());
   274 	  d/=l;
   275 	  xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
   276 			_coords[g.source(e)]);
   277 	  os << l-(_nodeSizes[g.source(e)]+
   278 		     _nodeSizes[g.target(e)])*_nodeScale << ' '
   279 	       << _edgeWidths[e]*_edgeWidthScale << ' '
   280 	       << d.x << ' ' << d.y << ' '
   281 	       << x1.x << ' ' << x1.y << ' '
   282 	       << _edgeColors[e].getR() << ' '
   283 	       << _edgeColors[e].getG() << ' '
   284 	       << _edgeColors[e].getB() << " arr\n";
   285 	}
   286     	else os << _coords[g.source(e)].x << ' '
   287 		  << _coords[g.source(e)].y << ' '
   288 		  << _coords[g.target(e)].x << ' '
   289 		  << _coords[g.target(e)].y << ' '
   290 		  << _edgeColors[e].getR() << ' '
   291 		  << _edgeColors[e].getG() << ' '
   292 		  << _edgeColors[e].getB() << ' '
   293 		  << _edgeWidths[e]*_edgeWidthScale << " l\n";
   294     os << "grestore\n%Nodes:\ngsave\n";
   295     for(NodeIt n(g);n!=INVALID;++n)
   296       os << _coords[n].x << ' ' << _coords[n].y << ' '
   297 	   << _nodeSizes[n]*_nodeScale << ' '
   298 	   << _nodeColors[n].getR() << ' '
   299 	   << _nodeColors[n].getG() << ' '
   300 	   << _nodeColors[n].getB() << " n\n"; 
   301     os << "grestore\ngrestore\n";
   302   } 
   303 };
   304 
   305 
   306 ///Generates an EPS file from a graph
   307 
   308 ///\ingroup misc
   309 ///Generates an EPS file from a graph.
   310 ///\param g is a reference to the graph to be printed
   311 ///\param os is a reference to the output stream.
   312 ///By default it is <tt>std::cout</tt>
   313 ///
   314 ///This function also has a lot of \ref named-templ-param "named parameters",
   315 ///they are declared as the members of class \ref GraphToEps. The following
   316 ///example shows how to use these parameters.
   317 ///\code
   318 /// graphToEps(g).scale(10).coords(coords)
   319 ///              .nodeScale(2).nodeSizes(sizes)
   320 ///              .edgeWidthScale(.4);
   321 ///\endcode
   322 ///\sa GraphToEps
   323 template<class G>
   324 GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g,std::ostream& os=std::cout)
   325 {
   326   return GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g));
   327 }
   328  
   329 }
   330 
   331 using namespace lemon;
   332 
   333 class ColorSet : public MapBase<int,Color>
   334 {
   335 public:
   336   Color operator[](int i) const
   337   {
   338     switch(i%8){
   339     case 0: return Color(0,0,0);
   340     case 1: return Color(1,0,0);
   341     case 2: return Color(0,1,0);
   342     case 3: return Color(0,0,1);
   343     case 4: return Color(1,1,0);
   344     case 5: return Color(1,0,1);
   345     case 6: return Color(0,1,1);
   346     case 7: return Color(1,1,1);
   347     }
   348     return Color(0,0,0);
   349   }
   350 } colorSet;
   351 
   352 int main()
   353 {
   354   ListGraph g;
   355   typedef ListGraph::Node Node;
   356   typedef ListGraph::NodeIt NodeIt;
   357   typedef ListGraph::Edge Edge;
   358   typedef xy<int> Xy;
   359   
   360   Node n1=g.addNode();
   361   Node n2=g.addNode();
   362   Node n3=g.addNode();
   363   Node n4=g.addNode();
   364   Node n5=g.addNode();
   365 
   366   ListGraph::NodeMap<Xy> coords(g);
   367   ListGraph::NodeMap<double> sizes(g);
   368   ListGraph::NodeMap<int> colors(g);
   369   ListGraph::EdgeMap<int> ecolors(g);
   370   ListGraph::EdgeMap<int> widths(g);
   371   
   372   coords[n1]=Xy(50,50);  sizes[n1]=1; colors[n1]=1;
   373   coords[n2]=Xy(50,70);  sizes[n2]=2; colors[n2]=2;
   374   coords[n3]=Xy(70,70);  sizes[n3]=1; colors[n3]=3;
   375   coords[n4]=Xy(70,50);  sizes[n4]=2; colors[n4]=4;
   376   coords[n5]=Xy(85,60);  sizes[n5]=3; colors[n5]=5;
   377   
   378   Edge e;
   379 
   380   e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1;
   381   e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1;
   382   e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3;
   383   e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1;
   384   e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1;
   385   e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2;
   386   e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1;
   387   
   388   graphToEps(g).scale(10).coords(coords).
   389     nodeScale(2).nodeSizes(sizes).
   390     nodeColors(composeMap(colorSet,colors)).
   391     edgeColors(composeMap(colorSet,ecolors)).
   392     edgeWidthScale(.4).edgeWidths(widths).
   393     drawArrows().arrowWidth(1).arrowLength(1)
   394     ;
   395 }