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 }