src/work/alpar/graph_to_eps.cc
changeset 1050 bcc0766a7b86
parent 1047 a6094968ed09
child 1051 4ebe32765b48
     1.1 --- a/src/work/alpar/graph_to_eps.cc	Tue Jan 04 22:14:42 2005 +0000
     1.2 +++ b/src/work/alpar/graph_to_eps.cc	Tue Jan 04 22:16:46 2005 +0000
     1.3 @@ -1,32 +1,41 @@
     1.4 +#include<math.h>
     1.5  #include<lemon/xy.h>
     1.6  #include<lemon/maps.h>
     1.7  #include<lemon/list_graph.h>
     1.8  
     1.9 -///\file
    1.10 +
    1.11 +///\file \ingroup misc
    1.12  ///Simple graph drawer
    1.13  
    1.14  namespace lemon {
    1.15  
    1.16 -  ///\e
    1.17 +///Data structure representing RGB colors.
    1.18 +
    1.19 +///Data structure representing RGB colors.
    1.20 +///\ingroup misc
    1.21  class Color
    1.22  {
    1.23    double _r,_g,_b;
    1.24  public:
    1.25 -  ///\e
    1.26 +  ///Default constructor
    1.27    Color() {}
    1.28 -  ///\e
    1.29 +  ///Constructor
    1.30    Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
    1.31 -  ///\e
    1.32 +  ///Returns the red component
    1.33    double getR() {return _r;}
    1.34 -  ///\e
    1.35 +  ///Returns the green component
    1.36    double getG() {return _g;}
    1.37 -  ///\e
    1.38 +  ///Returns the blue component
    1.39    double getB() {return _b;}
    1.40 -  ///\e
    1.41 +  ///Set the color components
    1.42    void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
    1.43  };
    1.44    
    1.45 -  ///\e
    1.46 +///Default traits class of \ref GraphToEps
    1.47 +
    1.48 +///Default traits class of \ref GraphToEps
    1.49 +///
    1.50 +///\c G is the type of the underlying graph.
    1.51  template<class G>
    1.52  struct DefaultGraphToEpsTraits
    1.53  {
    1.54 @@ -40,21 +49,42 @@
    1.55    
    1.56  
    1.57    const Graph &g;
    1.58 -  ConstMap<typename Graph::Node,xy<double> > coords;
    1.59 -  ConstMap<typename Graph::Node,double > nodeSizes;
    1.60 +  ConstMap<typename Graph::Node,xy<double> > _coords;
    1.61 +  ConstMap<typename Graph::Node,double > _nodeSizes;
    1.62  
    1.63 -  ConstMap<typename Graph::Node,Color > nodeColors;
    1.64 -  ConstMap<typename Graph::Edge,Color > edgeColors;
    1.65 -  double nodeSizeScalar;
    1.66 -  double xBorder, yBorder;
    1.67 -    
    1.68 -  DefaultGraphToEpsTraits(G &_g) :
    1.69 -    g(_g), coords(xy<double>(1,1)), nodeSizes(1.0),
    1.70 -    nodeColors(Color(1,1,1)), edgeColors(Color(0,0,0)),
    1.71 -    nodeSizeScalar(1.0), xBorder(10), yBorder(10) {}
    1.72 +  ConstMap<typename Graph::Node,Color > _nodeColors;
    1.73 +  ConstMap<typename Graph::Edge,Color > _edgeColors;
    1.74 +
    1.75 +  ConstMap<typename Graph::Edge,double > _edgeWidths;
    1.76 +  
    1.77 +  double _edgeWidthScale;
    1.78 +  
    1.79 +  double _nodeScale;
    1.80 +  double _xBorder, _yBorder;
    1.81 +  double _scale;
    1.82 +  double _nodeBorderQuotient;
    1.83 +  
    1.84 +  bool _drawArrows;
    1.85 +  double _arrowLength, _arrowWidth;
    1.86 +  
    1.87 +  ///Constructor
    1.88 +
    1.89 +  ///Constructor
    1.90 +  ///\param _g is a reference to the underlying graph
    1.91 +  DefaultGraphToEpsTraits(const G &_g) :
    1.92 +    g(_g), _coords(xy<double>(1,1)), _nodeSizes(1.0),
    1.93 +    _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
    1.94 +    _edgeWidths(1), _edgeWidthScale(0.3),
    1.95 +    _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
    1.96 +    _nodeBorderQuotient(.1),
    1.97 +    _drawArrows(false), _arrowLength(1), _arrowWidth(0.3) {}
    1.98  };
    1.99  
   1.100 -  ///\e
   1.101 +///Helper class to implement the named parameters of \ref graphToEps()
   1.102 +
   1.103 +///Helper class to implement the named parameters of \ref graphToEps()
   1.104 +///\todo Is 'helper class' a good name for this?
   1.105 +///
   1.106  template<class T> class GraphToEps : public T 
   1.107  {
   1.108    typedef typename T::Graph Graph;
   1.109 @@ -70,49 +100,115 @@
   1.110  public:
   1.111    GraphToEps(const T &t) : T(t), dontPrint(false) {};
   1.112    
   1.113 -  template<class X> struct SetCoordsTraits : public T {
   1.114 -    const X &coords;
   1.115 -    SetCoordsTraits(const T &t,const X &x) : T(t), coords(x) {}
   1.116 +  template<class X> struct CoordsTraits : public T {
   1.117 +    const X &_coords;
   1.118 +    CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
   1.119    };
   1.120 -  ///\e
   1.121 -  template<class X> GraphToEps<SetCoordsTraits<X> > setCoords(const X &x) {
   1.122 +  ///Sets the map of the node coordinates
   1.123 +
   1.124 +  ///Sets the map of the node coordinates.
   1.125 +  ///\param x must be a node map with xy<double> or xy<int> values. 
   1.126 +  template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
   1.127      dontPrint=true;
   1.128 -    return GraphToEps<SetCoordsTraits<X> >(SetCoordsTraits<X>(*this,x));
   1.129 +    return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
   1.130    }
   1.131 -  template<class X> struct SetNodeSizesTraits : public T {
   1.132 -    const X &nodeSizes;
   1.133 -    SetNodeSizesTraits(const T &t,const X &x) : T(t), nodeSizes(x) {}
   1.134 +  template<class X> struct NodeSizesTraits : public T {
   1.135 +    const X &_nodeSizes;
   1.136 +    NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
   1.137    };
   1.138 -  ///\e
   1.139 -  template<class X> GraphToEps<SetNodeSizesTraits<X> > setNodeSizes(const X &x)
   1.140 +  ///Sets the map of the node sizes
   1.141 +
   1.142 +  ///Sets the map of the node sizes
   1.143 +  ///\param x must be a node map with \c double (or convertible) values. 
   1.144 +  template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
   1.145    {
   1.146      dontPrint=true;
   1.147 -    return GraphToEps<SetNodeSizesTraits<X> >(SetNodeSizesTraits<X>(*this,x));
   1.148 +    return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
   1.149    }
   1.150 -  template<class X> struct SetNodeColorsTraits : public T {
   1.151 -    const X &nodeColors;
   1.152 -    SetNodeColorsTraits(const T &t,const X &x) : T(t), nodeColors(x) {}
   1.153 +   template<class X> struct EdgeWidthsTraits : public T {
   1.154 +    const X &_edgeWidths;
   1.155 +    EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
   1.156    };
   1.157 -  ///\e
   1.158 -  template<class X> GraphToEps<SetNodeColorsTraits<X> >
   1.159 -  setNodeColors(const X &x)
   1.160 +  ///Sets the map of the edge widths
   1.161 +
   1.162 +  ///Sets the map of the edge widths
   1.163 +  ///\param x must be a edge map with \c double (or convertible) values. 
   1.164 +  template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
   1.165    {
   1.166      dontPrint=true;
   1.167 -    return GraphToEps<SetNodeColorsTraits<X> >(SetNodeColorsTraits<X>(*this,x));
   1.168 +    return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
   1.169    }
   1.170 -  template<class X> struct SetEdgeColorsTraits : public T {
   1.171 -    const X &edgeColors;
   1.172 -    SetEdgeColorsTraits(const T &t,const X &x) : T(t), edgeColors(x) {}
   1.173 +
   1.174 +  template<class X> struct NodeColorsTraits : public T {
   1.175 +    const X &_nodeColors;
   1.176 +    NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
   1.177    };
   1.178 -  ///\e
   1.179 -  template<class X> GraphToEps<SetEdgeColorsTraits<X> >
   1.180 -  setEdgeColors(const X &x)
   1.181 +  ///Sets the map of the node colors
   1.182 +
   1.183 +  ///Sets the map of the node colors
   1.184 +  ///\param x must be a node map with \ref Color values. 
   1.185 +  template<class X> GraphToEps<NodeColorsTraits<X> >
   1.186 +  nodeColors(const X &x)
   1.187    {
   1.188      dontPrint=true;
   1.189 -    return GraphToEps<SetEdgeColorsTraits<X> >(SetEdgeColorsTraits<X>(*this,x));
   1.190 +    return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
   1.191    }
   1.192 -  ///\e
   1.193 -  GraphToEps<T> &scaleNodeSize(double d) {nodeSizeScalar=d;return *this;}
   1.194 +  template<class X> struct EdgeColorsTraits : public T {
   1.195 +    const X &_edgeColors;
   1.196 +    EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
   1.197 +  };
   1.198 +  ///Sets the map of the edge colors
   1.199 +
   1.200 +  ///Sets the map of the edge colors
   1.201 +  ///\param x must be a edge map with \ref Color values. 
   1.202 +  template<class X> GraphToEps<EdgeColorsTraits<X> >
   1.203 +  edgeColors(const X &x)
   1.204 +  {
   1.205 +    dontPrint=true;
   1.206 +    return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
   1.207 +  }
   1.208 +  ///Sets a global scale factor for node sizes
   1.209 +
   1.210 +  ///Sets a global scale factor for node sizes
   1.211 +  ///
   1.212 +  GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
   1.213 +  ///Sets a global scale factor for edge widths
   1.214 +
   1.215 +  ///Sets a global scale factor for edge widths
   1.216 +  ///
   1.217 +  GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
   1.218 +  ///Sets a global scale factor for the whole picture
   1.219 +
   1.220 +  ///Sets a global scale factor for the whole picture
   1.221 +  ///
   1.222 +  GraphToEps<T> &scale(double d) {_scale=d;return *this;}
   1.223 +  ///Sets the width of the border around the picture
   1.224 +
   1.225 +  ///Sets the width of the border around the picture
   1.226 +  ///
   1.227 +  GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
   1.228 +  ///Sets the width of the border around the picture
   1.229 +
   1.230 +  ///Sets the width of the border around the picture
   1.231 +  ///
   1.232 +  GraphToEps<T> &border(double x, double y) {
   1.233 +    _xBorder=x;_yBorder=y;return *this;
   1.234 +  }
   1.235 +  ///Sets whether to draw arrows
   1.236 +
   1.237 +  ///Sets whether to draw arrows
   1.238 +  ///
   1.239 +  GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
   1.240 +  ///Sets the length of the arrowheads
   1.241 +
   1.242 +  ///Sets the length of the arrowheads
   1.243 +  ///
   1.244 +  GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
   1.245 +  ///Sets the width of the arrowheads
   1.246 +
   1.247 +  ///Sets the width of the arrowheads
   1.248 +  ///
   1.249 +  GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
   1.250    
   1.251    ~GraphToEps() 
   1.252    {
   1.253 @@ -121,44 +217,98 @@
   1.254      cout << "%!PS-Adobe-2.0 EPSF-2.0\n";
   1.255      //\todo: Chech whether the graph is empty.
   1.256      BoundingBox<double> bb;
   1.257 -    for(NodeIt n(g);
   1.258 -	n!=INVALID;
   1.259 -	++n) {
   1.260 -      xy<double> p(nodeSizes[n]*nodeSizeScalar,nodeSizes[n]*nodeSizeScalar);
   1.261 -      bb+=coords[n]+p;
   1.262 -      bb+=coords[n]-p;
   1.263 +    for(NodeIt n(g);n!=INVALID;++n) {
   1.264 +      double ns=_nodeSizes[n]*_nodeScale;
   1.265 +      xy<double> p(ns,ns);
   1.266 +      bb+=p+_coords[n];
   1.267 +      bb+=-p+_coords[n];
   1.268        }
   1.269      cout << "%%BoundingBox: "
   1.270 -	 << bb.left()-xBorder << ' ' << bb.bottom()-yBorder << ' '
   1.271 -	 << bb.right()+xBorder << ' ' << bb.top()+yBorder << '\n';
   1.272 -    //x1 y1 x2 y2 cr cg cb
   1.273 -    cout << "/l { setrgbcolor newpath moveto lineto stroke } bind def\n";
   1.274 +	 << bb.left()*  _scale-_xBorder << ' '
   1.275 +	 << bb.bottom()*_scale-_yBorder << ' '
   1.276 +	 << bb.right()* _scale+_xBorder << ' '
   1.277 +	 << bb.top()*   _scale+_yBorder << '\n';
   1.278 +    //x1 y1 x2 y2 cr cg cb w
   1.279 +    cout << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
   1.280      cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
   1.281      // x y r cr cg cb
   1.282      cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
   1.283 -	 << "     0 0 0 setrgbcolor dup 10 div setlinewidth c stroke\n"
   1.284 +	 << "     0 0 0 setrgbcolor dup "
   1.285 +	 << _nodeBorderQuotient << " mul setlinewidth "
   1.286 +	 << 1+_nodeBorderQuotient/2 << " div c stroke\n"
   1.287  	 << "   } bind def\n";
   1.288 -    
   1.289 +    cout << "/arrl " << _arrowLength << " def\n";
   1.290 +    cout << "/arrw " << _arrowWidth << " def\n";
   1.291 +    // l dx_norm dy_norm
   1.292 +    cout << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
   1.293 +    //len w dx_norm dy_norm x1 y1 cr cg cb
   1.294 +    cout << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
   1.295 +	 << "       /w exch def /len exch def\n"
   1.296 +      //	 << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
   1.297 +	 << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
   1.298 +	 << "       len w sub arrl sub dx dy lrl\n"
   1.299 +	 << "       arrw dy dx neg lrl\n"
   1.300 +	 << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
   1.301 +	 << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
   1.302 +	 << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
   1.303 +	 << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
   1.304 +	 << "       arrw dy dx neg lrl\n"
   1.305 +	 << "       len w sub arrl sub neg dx dy lrl\n"
   1.306 +	 << "       closepath fill } bind def\n";
   1.307 +    cout << "\ngsave\n";
   1.308 +    if(_scale!=1.0) cout << _scale << " dup scale\n";
   1.309      cout << "%Edges:\ngsave\n";
   1.310      for(NodeIt n(g);n!=INVALID;++n)
   1.311        for(OutEdgeIt e(g,n);e!=INVALID;++e)
   1.312 -	cout << coords[g.source(e)].x << ' ' << coords[g.source(e)].y << ' '
   1.313 -	     << coords[g.target(e)].x << ' ' << coords[g.target(e)].y << ' '
   1.314 -	     << edgeColors[e].getR() << ' '
   1.315 -	     << edgeColors[e].getG() << ' '
   1.316 -	     << edgeColors[e].getB() << " l\n";
   1.317 +	if(_drawArrows) {
   1.318 +	  xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
   1.319 +	  double l=sqrt(d.normSquare());
   1.320 +	  d/=l;
   1.321 +	  xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
   1.322 +			_coords[g.source(e)]);
   1.323 +	  cout << l-(_nodeSizes[g.source(e)]+
   1.324 +		     _nodeSizes[g.target(e)])*_nodeScale << ' '
   1.325 +	       << _edgeWidths[e]*_edgeWidthScale << ' '
   1.326 +	       << d.x << ' ' << d.y << ' '
   1.327 +	       << x1.x << ' ' << x1.y << ' '
   1.328 +	       << _edgeColors[e].getR() << ' '
   1.329 +	       << _edgeColors[e].getG() << ' '
   1.330 +	       << _edgeColors[e].getB() << " arr\n";
   1.331 +	}
   1.332 +    	else cout << _coords[g.source(e)].x << ' '
   1.333 +		  << _coords[g.source(e)].y << ' '
   1.334 +		  << _coords[g.target(e)].x << ' '
   1.335 +		  << _coords[g.target(e)].y << ' '
   1.336 +		  << _edgeColors[e].getR() << ' '
   1.337 +		  << _edgeColors[e].getG() << ' '
   1.338 +		  << _edgeColors[e].getB() << ' '
   1.339 +		  << _edgeWidths[e]*_edgeWidthScale << " l\n";
   1.340      cout << "grestore\n%Nodes:\ngsave\n";
   1.341      for(NodeIt n(g);n!=INVALID;++n)
   1.342 -      cout << coords[n].x << ' ' << coords[n].y << ' '
   1.343 -	   << nodeSizes[n]*nodeSizeScalar << ' '
   1.344 -	   << nodeColors[n].getR() << ' '
   1.345 -	   << nodeColors[n].getG() << ' '
   1.346 -	   << nodeColors[n].getB() << " n\n"; 
   1.347 -    cout << "grestore\n";
   1.348 +      cout << _coords[n].x << ' ' << _coords[n].y << ' '
   1.349 +	   << _nodeSizes[n]*_nodeScale << ' '
   1.350 +	   << _nodeColors[n].getR() << ' '
   1.351 +	   << _nodeColors[n].getG() << ' '
   1.352 +	   << _nodeColors[n].getB() << " n\n"; 
   1.353 +    cout << "grestore\ngrestore\n";
   1.354    } 
   1.355  };
   1.356  
   1.357  
   1.358 +///Generates an EPS file from a graph
   1.359 +
   1.360 +///\ingroup misc
   1.361 +///Generates an EPS file from a graph.
   1.362 +///
   1.363 +///This function has a lot of \ref named-templ-param "named parameters",
   1.364 +///they are declared as the members of class \ref GraphToEps. The following
   1.365 +///example shows how to use these parameters.
   1.366 +///\code
   1.367 +/// graphToEps(g).scale(10).coords(coords)
   1.368 +///              .nodeScale(2).nodeSizes(sizes)
   1.369 +///              .edgeWidthScale(.4);
   1.370 +///\endcode
   1.371 +///\sa GraphToEps
   1.372  template<class G>
   1.373  GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g)
   1.374  {
   1.375 @@ -194,7 +344,7 @@
   1.376    typedef ListGraph::Node Node;
   1.377    typedef ListGraph::NodeIt NodeIt;
   1.378    typedef ListGraph::Edge Edge;
   1.379 -  typedef xy<double> Xy;
   1.380 +  typedef xy<int> Xy;
   1.381    
   1.382    Node n1=g.addNode();
   1.383    Node n2=g.addNode();
   1.384 @@ -206,6 +356,7 @@
   1.385    ListGraph::NodeMap<double> sizes(g);
   1.386    ListGraph::NodeMap<int> colors(g);
   1.387    ListGraph::EdgeMap<int> ecolors(g);
   1.388 +  ListGraph::EdgeMap<int> widths(g);
   1.389    
   1.390    coords[n1]=Xy(50,50);  sizes[n1]=1; colors[n1]=1;
   1.391    coords[n2]=Xy(50,70);  sizes[n2]=2; colors[n2]=2;
   1.392 @@ -215,16 +366,19 @@
   1.393    
   1.394    Edge e;
   1.395  
   1.396 -  e=g.addEdge(n1,n2); ecolors[e]=0;
   1.397 -  e=g.addEdge(n2,n3); ecolors[e]=0;
   1.398 -  e=g.addEdge(n3,n5); ecolors[e]=0;
   1.399 -  e=g.addEdge(n5,n4); ecolors[e]=0;
   1.400 -  e=g.addEdge(n4,n1); ecolors[e]=0;
   1.401 -  e=g.addEdge(n2,n4); ecolors[e]=1;
   1.402 -  e=g.addEdge(n3,n4); ecolors[e]=2;
   1.403 +  e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1;
   1.404 +  e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1;
   1.405 +  e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3;
   1.406 +  e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1;
   1.407 +  e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1;
   1.408 +  e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2;
   1.409 +  e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1;
   1.410    
   1.411 -  graphToEps(g).setCoords(coords).
   1.412 -    scaleNodeSize(2).setNodeSizes(sizes).
   1.413 -    setNodeColors(composeMap(colorSet,colors)).
   1.414 -    setEdgeColors(composeMap(colorSet,ecolors));
   1.415 +  graphToEps(g).scale(10).coords(coords).
   1.416 +    nodeScale(2).nodeSizes(sizes).
   1.417 +    nodeColors(composeMap(colorSet,colors)).
   1.418 +    edgeColors(composeMap(colorSet,ecolors)).
   1.419 +    edgeWidthScale(.4).edgeWidths(widths).
   1.420 +    drawArrows().arrowWidth(1).arrowLength(1)
   1.421 +    ;
   1.422  }