diff -r e27446e1deda -r bcc0766a7b86 src/work/alpar/graph_to_eps.cc --- a/src/work/alpar/graph_to_eps.cc Tue Jan 04 22:14:42 2005 +0000 +++ b/src/work/alpar/graph_to_eps.cc Tue Jan 04 22:16:46 2005 +0000 @@ -1,32 +1,41 @@ +#include #include #include #include -///\file + +///\file \ingroup misc ///Simple graph drawer namespace lemon { - ///\e +///Data structure representing RGB colors. + +///Data structure representing RGB colors. +///\ingroup misc class Color { double _r,_g,_b; public: - ///\e + ///Default constructor Color() {} - ///\e + ///Constructor Color(double r,double g,double b) :_r(r),_g(g),_b(b) {}; - ///\e + ///Returns the red component double getR() {return _r;} - ///\e + ///Returns the green component double getG() {return _g;} - ///\e + ///Returns the blue component double getB() {return _b;} - ///\e + ///Set the color components void set(double r,double g,double b) { _r=r;_g=g;_b=b; }; }; - ///\e +///Default traits class of \ref GraphToEps + +///Default traits class of \ref GraphToEps +/// +///\c G is the type of the underlying graph. template struct DefaultGraphToEpsTraits { @@ -40,21 +49,42 @@ const Graph &g; - ConstMap > coords; - ConstMap nodeSizes; + ConstMap > _coords; + ConstMap _nodeSizes; - ConstMap nodeColors; - ConstMap edgeColors; - double nodeSizeScalar; - double xBorder, yBorder; - - DefaultGraphToEpsTraits(G &_g) : - g(_g), coords(xy(1,1)), nodeSizes(1.0), - nodeColors(Color(1,1,1)), edgeColors(Color(0,0,0)), - nodeSizeScalar(1.0), xBorder(10), yBorder(10) {} + ConstMap _nodeColors; + ConstMap _edgeColors; + + ConstMap _edgeWidths; + + double _edgeWidthScale; + + double _nodeScale; + double _xBorder, _yBorder; + double _scale; + double _nodeBorderQuotient; + + bool _drawArrows; + double _arrowLength, _arrowWidth; + + ///Constructor + + ///Constructor + ///\param _g is a reference to the underlying graph + DefaultGraphToEpsTraits(const G &_g) : + g(_g), _coords(xy(1,1)), _nodeSizes(1.0), + _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)), + _edgeWidths(1), _edgeWidthScale(0.3), + _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0), + _nodeBorderQuotient(.1), + _drawArrows(false), _arrowLength(1), _arrowWidth(0.3) {} }; - ///\e +///Helper class to implement the named parameters of \ref graphToEps() + +///Helper class to implement the named parameters of \ref graphToEps() +///\todo Is 'helper class' a good name for this? +/// template class GraphToEps : public T { typedef typename T::Graph Graph; @@ -70,49 +100,115 @@ public: GraphToEps(const T &t) : T(t), dontPrint(false) {}; - template struct SetCoordsTraits : public T { - const X &coords; - SetCoordsTraits(const T &t,const X &x) : T(t), coords(x) {} + template struct CoordsTraits : public T { + const X &_coords; + CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} }; - ///\e - template GraphToEps > setCoords(const X &x) { + ///Sets the map of the node coordinates + + ///Sets the map of the node coordinates. + ///\param x must be a node map with xy or xy values. + template GraphToEps > coords(const X &x) { dontPrint=true; - return GraphToEps >(SetCoordsTraits(*this,x)); + return GraphToEps >(CoordsTraits(*this,x)); } - template struct SetNodeSizesTraits : public T { - const X &nodeSizes; - SetNodeSizesTraits(const T &t,const X &x) : T(t), nodeSizes(x) {} + template struct NodeSizesTraits : public T { + const X &_nodeSizes; + NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} }; - ///\e - template GraphToEps > setNodeSizes(const X &x) + ///Sets the map of the node sizes + + ///Sets the map of the node sizes + ///\param x must be a node map with \c double (or convertible) values. + template GraphToEps > nodeSizes(const X &x) { dontPrint=true; - return GraphToEps >(SetNodeSizesTraits(*this,x)); + return GraphToEps >(NodeSizesTraits(*this,x)); } - template struct SetNodeColorsTraits : public T { - const X &nodeColors; - SetNodeColorsTraits(const T &t,const X &x) : T(t), nodeColors(x) {} + template struct EdgeWidthsTraits : public T { + const X &_edgeWidths; + EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {} }; - ///\e - template GraphToEps > - setNodeColors(const X &x) + ///Sets the map of the edge widths + + ///Sets the map of the edge widths + ///\param x must be a edge map with \c double (or convertible) values. + template GraphToEps > edgeWidths(const X &x) { dontPrint=true; - return GraphToEps >(SetNodeColorsTraits(*this,x)); + return GraphToEps >(EdgeWidthsTraits(*this,x)); } - template struct SetEdgeColorsTraits : public T { - const X &edgeColors; - SetEdgeColorsTraits(const T &t,const X &x) : T(t), edgeColors(x) {} + + template struct NodeColorsTraits : public T { + const X &_nodeColors; + NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {} }; - ///\e - template GraphToEps > - setEdgeColors(const X &x) + ///Sets the map of the node colors + + ///Sets the map of the node colors + ///\param x must be a node map with \ref Color values. + template GraphToEps > + nodeColors(const X &x) { dontPrint=true; - return GraphToEps >(SetEdgeColorsTraits(*this,x)); + return GraphToEps >(NodeColorsTraits(*this,x)); } - ///\e - GraphToEps &scaleNodeSize(double d) {nodeSizeScalar=d;return *this;} + template struct EdgeColorsTraits : public T { + const X &_edgeColors; + EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {} + }; + ///Sets the map of the edge colors + + ///Sets the map of the edge colors + ///\param x must be a edge map with \ref Color values. + template GraphToEps > + edgeColors(const X &x) + { + dontPrint=true; + return GraphToEps >(EdgeColorsTraits(*this,x)); + } + ///Sets a global scale factor for node sizes + + ///Sets a global scale factor for node sizes + /// + GraphToEps &nodeScale(double d) {_nodeScale=d;return *this;} + ///Sets a global scale factor for edge widths + + ///Sets a global scale factor for edge widths + /// + GraphToEps &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;} + ///Sets a global scale factor for the whole picture + + ///Sets a global scale factor for the whole picture + /// + GraphToEps &scale(double d) {_scale=d;return *this;} + ///Sets the width of the border around the picture + + ///Sets the width of the border around the picture + /// + GraphToEps &border(double b) {_xBorder=_yBorder=b;return *this;} + ///Sets the width of the border around the picture + + ///Sets the width of the border around the picture + /// + GraphToEps &border(double x, double y) { + _xBorder=x;_yBorder=y;return *this; + } + ///Sets whether to draw arrows + + ///Sets whether to draw arrows + /// + GraphToEps &drawArrows(bool b=true) {_drawArrows=b;return *this;} + ///Sets the length of the arrowheads + + ///Sets the length of the arrowheads + /// + GraphToEps &arrowLength(double d) {_arrowLength*=d;return *this;} + ///Sets the width of the arrowheads + + ///Sets the width of the arrowheads + /// + GraphToEps &arrowWidth(double d) {_arrowWidth*=d;return *this;} ~GraphToEps() { @@ -121,44 +217,98 @@ cout << "%!PS-Adobe-2.0 EPSF-2.0\n"; //\todo: Chech whether the graph is empty. BoundingBox bb; - for(NodeIt n(g); - n!=INVALID; - ++n) { - xy p(nodeSizes[n]*nodeSizeScalar,nodeSizes[n]*nodeSizeScalar); - bb+=coords[n]+p; - bb+=coords[n]-p; + for(NodeIt n(g);n!=INVALID;++n) { + double ns=_nodeSizes[n]*_nodeScale; + xy p(ns,ns); + bb+=p+_coords[n]; + bb+=-p+_coords[n]; } cout << "%%BoundingBox: " - << bb.left()-xBorder << ' ' << bb.bottom()-yBorder << ' ' - << bb.right()+xBorder << ' ' << bb.top()+yBorder << '\n'; - //x1 y1 x2 y2 cr cg cb - cout << "/l { setrgbcolor newpath moveto lineto stroke } bind def\n"; + << bb.left()* _scale-_xBorder << ' ' + << bb.bottom()*_scale-_yBorder << ' ' + << bb.right()* _scale+_xBorder << ' ' + << bb.top()* _scale+_yBorder << '\n'; + //x1 y1 x2 y2 cr cg cb w + cout << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n"; cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n"; // x y r cr cg cb cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n" - << " 0 0 0 setrgbcolor dup 10 div setlinewidth c stroke\n" + << " 0 0 0 setrgbcolor dup " + << _nodeBorderQuotient << " mul setlinewidth " + << 1+_nodeBorderQuotient/2 << " div c stroke\n" << " } bind def\n"; - + cout << "/arrl " << _arrowLength << " def\n"; + cout << "/arrw " << _arrowWidth << " def\n"; + // l dx_norm dy_norm + cout << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; + //len w dx_norm dy_norm x1 y1 cr cg cb + cout << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n" + << " /w exch def /len exch def\n" + // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" + << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" + << " len w sub arrl sub dx dy lrl\n" + << " arrw dy dx neg lrl\n" + << " dx arrl w add mul dy w 2 div arrw add mul sub\n" + << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" + << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n" + << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n" + << " arrw dy dx neg lrl\n" + << " len w sub arrl sub neg dx dy lrl\n" + << " closepath fill } bind def\n"; + cout << "\ngsave\n"; + if(_scale!=1.0) cout << _scale << " dup scale\n"; cout << "%Edges:\ngsave\n"; for(NodeIt n(g);n!=INVALID;++n) for(OutEdgeIt e(g,n);e!=INVALID;++e) - cout << coords[g.source(e)].x << ' ' << coords[g.source(e)].y << ' ' - << coords[g.target(e)].x << ' ' << coords[g.target(e)].y << ' ' - << edgeColors[e].getR() << ' ' - << edgeColors[e].getG() << ' ' - << edgeColors[e].getB() << " l\n"; + if(_drawArrows) { + xy d(_coords[g.target(e)]-_coords[g.source(e)]); + double l=sqrt(d.normSquare()); + d/=l; + xy x1(d*_nodeScale*_nodeSizes[g.source(e)]+ + _coords[g.source(e)]); + cout << l-(_nodeSizes[g.source(e)]+ + _nodeSizes[g.target(e)])*_nodeScale << ' ' + << _edgeWidths[e]*_edgeWidthScale << ' ' + << d.x << ' ' << d.y << ' ' + << x1.x << ' ' << x1.y << ' ' + << _edgeColors[e].getR() << ' ' + << _edgeColors[e].getG() << ' ' + << _edgeColors[e].getB() << " arr\n"; + } + else cout << _coords[g.source(e)].x << ' ' + << _coords[g.source(e)].y << ' ' + << _coords[g.target(e)].x << ' ' + << _coords[g.target(e)].y << ' ' + << _edgeColors[e].getR() << ' ' + << _edgeColors[e].getG() << ' ' + << _edgeColors[e].getB() << ' ' + << _edgeWidths[e]*_edgeWidthScale << " l\n"; cout << "grestore\n%Nodes:\ngsave\n"; for(NodeIt n(g);n!=INVALID;++n) - cout << coords[n].x << ' ' << coords[n].y << ' ' - << nodeSizes[n]*nodeSizeScalar << ' ' - << nodeColors[n].getR() << ' ' - << nodeColors[n].getG() << ' ' - << nodeColors[n].getB() << " n\n"; - cout << "grestore\n"; + cout << _coords[n].x << ' ' << _coords[n].y << ' ' + << _nodeSizes[n]*_nodeScale << ' ' + << _nodeColors[n].getR() << ' ' + << _nodeColors[n].getG() << ' ' + << _nodeColors[n].getB() << " n\n"; + cout << "grestore\ngrestore\n"; } }; +///Generates an EPS file from a graph + +///\ingroup misc +///Generates an EPS file from a graph. +/// +///This function has a lot of \ref named-templ-param "named parameters", +///they are declared as the members of class \ref GraphToEps. The following +///example shows how to use these parameters. +///\code +/// graphToEps(g).scale(10).coords(coords) +/// .nodeScale(2).nodeSizes(sizes) +/// .edgeWidthScale(.4); +///\endcode +///\sa GraphToEps template GraphToEps > graphToEps(G &g) { @@ -194,7 +344,7 @@ typedef ListGraph::Node Node; typedef ListGraph::NodeIt NodeIt; typedef ListGraph::Edge Edge; - typedef xy Xy; + typedef xy Xy; Node n1=g.addNode(); Node n2=g.addNode(); @@ -206,6 +356,7 @@ ListGraph::NodeMap sizes(g); ListGraph::NodeMap colors(g); ListGraph::EdgeMap ecolors(g); + ListGraph::EdgeMap widths(g); coords[n1]=Xy(50,50); sizes[n1]=1; colors[n1]=1; coords[n2]=Xy(50,70); sizes[n2]=2; colors[n2]=2; @@ -215,16 +366,19 @@ Edge e; - e=g.addEdge(n1,n2); ecolors[e]=0; - e=g.addEdge(n2,n3); ecolors[e]=0; - e=g.addEdge(n3,n5); ecolors[e]=0; - e=g.addEdge(n5,n4); ecolors[e]=0; - e=g.addEdge(n4,n1); ecolors[e]=0; - e=g.addEdge(n2,n4); ecolors[e]=1; - e=g.addEdge(n3,n4); ecolors[e]=2; + e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1; + e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1; + e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3; + e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1; + e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1; + e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2; + e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1; - graphToEps(g).setCoords(coords). - scaleNodeSize(2).setNodeSizes(sizes). - setNodeColors(composeMap(colorSet,colors)). - setEdgeColors(composeMap(colorSet,ecolors)); + graphToEps(g).scale(10).coords(coords). + nodeScale(2).nodeSizes(sizes). + nodeColors(composeMap(colorSet,colors)). + edgeColors(composeMap(colorSet,ecolors)). + edgeWidthScale(.4).edgeWidths(widths). + drawArrows().arrowWidth(1).arrowLength(1) + ; }