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