1.1 --- a/src/work/alpar/graph_to_eps.cc Sat Jan 08 20:12:50 2005 +0000
1.2 +++ b/src/work/alpar/graph_to_eps.cc Sat Jan 08 20:16:56 2005 +0000
1.3 @@ -1,3 +1,19 @@
1.4 +/* -*- C++ -*-
1.5 + * src/lemon/graph_to_eps.h - Part of LEMON, a generic C++ optimization library
1.6 + *
1.7 + * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.8 + * (Egervary Combinatorial Optimization Research Group, EGRES).
1.9 + *
1.10 + * Permission to use, modify and distribute this software is granted
1.11 + * provided that this copyright notice appears in all copies. For
1.12 + * precise terms see the accompanying LICENSE file.
1.13 + *
1.14 + * This software is provided "AS IS" with no warranty of any kind,
1.15 + * express or implied, and with no claim as to its suitability for any
1.16 + * purpose.
1.17 + *
1.18 + */
1.19 +
1.20 #include <iostream>
1.21 #include <fstream>
1.22 #include <algorithm>
1.23 @@ -8,8 +24,9 @@
1.24 #include<lemon/list_graph.h>
1.25
1.26
1.27 -///\file \ingroup misc
1.28 -///Simple graph drawer
1.29 +///\ingroup misc
1.30 +///\file
1.31 +///\brief Simple graph drawer
1.32
1.33 namespace lemon {
1.34
1.35 @@ -74,7 +91,14 @@
1.36 bool _drawArrows;
1.37 double _arrowLength, _arrowWidth;
1.38
1.39 + bool _showNodes, _showEdges;
1.40 +
1.41 bool _enableParallel;
1.42 + double _parEdgeDist;
1.43 +
1.44 + bool _showNodeText;
1.45 + ConstMap<typename Graph::Node,bool > _nodeTexts;
1.46 + double _nodeTextSize;
1.47
1.48 bool _pleaseRemoveOsStream;
1.49 ///Constructor
1.50 @@ -95,7 +119,10 @@
1.51 _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
1.52 _nodeBorderQuotient(.1),
1.53 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
1.54 - _enableParallel(false), _pleaseRemoveOsStream(_pros) {}
1.55 + _showNodes(true), _showEdges(true),
1.56 + _enableParallel(false), _parEdgeDist(1),
1.57 + _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
1.58 + _pleaseRemoveOsStream(_pros) {}
1.59 };
1.60
1.61 ///Helper class to implement the named parameters of \ref graphToEps()
1.62 @@ -130,7 +157,16 @@
1.63 (aa==ba && ai==g.source(a) && bi==g.target(b))));
1.64 }
1.65 };
1.66 -
1.67 + bool isParallel(Edge e,Edge f) const
1.68 + {
1.69 + return (g.source(e)==g.source(f)&&g.target(e)==g.target(f))||
1.70 + (g.source(e)==g.target(f)&&g.target(e)==g.source(f));
1.71 + }
1.72 + static xy<double> rot(xy<double> v)
1.73 + {
1.74 + return xy<double>(v.y,-v.x);
1.75 + }
1.76 +
1.77 public:
1.78 GraphToEps(const T &t) : T(t), dontPrint(false) {};
1.79
1.80 @@ -159,6 +195,21 @@
1.81 dontPrint=true;
1.82 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
1.83 }
1.84 + template<class X> struct NodeTextsTraits : public T {
1.85 + const X &_nodeTexts;
1.86 + NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
1.87 + };
1.88 + ///Sets the text printed on the nodes
1.89 +
1.90 + ///Sets the text printed on the nodes
1.91 + ///\param x must be a node map with type that can be pushed to a standard
1.92 + ///ostream.
1.93 + template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
1.94 + {
1.95 + dontPrint=true;
1.96 + _showNodeText=true;
1.97 + return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
1.98 + }
1.99 template<class X> struct EdgeWidthsTraits : public T {
1.100 const X &_edgeWidths;
1.101 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
1.102 @@ -247,9 +298,33 @@
1.103 ///Enables parallel edges
1.104
1.105 ///Enables parallel edges
1.106 - ///\todo Unimplemented
1.107 + ///\todo Partially implemented
1.108 GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
1.109
1.110 + ///Sets the distance
1.111 +
1.112 + ///Sets the distance
1.113 + ///
1.114 + GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
1.115 +
1.116 + ///Hides the edges
1.117 +
1.118 + ///Hides the edges
1.119 + ///
1.120 + GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
1.121 + ///Hides the nodes
1.122 +
1.123 + ///Hides the nodes
1.124 + ///
1.125 + GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
1.126 +
1.127 + ///Sets the size of the node texts
1.128 +
1.129 + ///Sets the size of the node texts
1.130 + ///
1.131 + GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
1.132 +
1.133 +
1.134 ~GraphToEps()
1.135 {
1.136 if(dontPrint) return;
1.137 @@ -268,53 +343,104 @@
1.138 << bb.bottom()*_scale-_yBorder << ' '
1.139 << bb.right()* _scale+_xBorder << ' '
1.140 << bb.top()* _scale+_yBorder << '\n';
1.141 - //x1 y1 x2 y2 cr cg cb w
1.142 + //x1 y1 x2 y2 x3 y3 cr cg cb w
1.143 + os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
1.144 + << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
1.145 os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
1.146 - os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n";
1.147 + os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
1.148 // x y r cr cg cb
1.149 os << "/n { setrgbcolor 2 index 2 index 2 index c fill\n"
1.150 - << " 0 0 0 setrgbcolor dup "
1.151 - << _nodeBorderQuotient << " mul setlinewidth "
1.152 - << 1+_nodeBorderQuotient/2 << " div c stroke\n"
1.153 - << " } bind def\n";
1.154 + << " 0 0 0 setrgbcolor dup "
1.155 + << _nodeBorderQuotient << " mul setlinewidth "
1.156 + << 1+_nodeBorderQuotient/2 << " div c stroke\n"
1.157 + << " } bind def\n";
1.158 os << "/arrl " << _arrowLength << " def\n";
1.159 os << "/arrw " << _arrowWidth << " def\n";
1.160 // l dx_norm dy_norm
1.161 os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
1.162 //len w dx_norm dy_norm x1 y1 cr cg cb
1.163 os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
1.164 - << " /w exch def /len exch def\n"
1.165 + << " /w exch def /len exch def\n"
1.166 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
1.167 - << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
1.168 - << " len w sub arrl sub dx dy lrl\n"
1.169 - << " arrw dy dx neg lrl\n"
1.170 - << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
1.171 - << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
1.172 - << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
1.173 - << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
1.174 - << " arrw dy dx neg lrl\n"
1.175 - << " len w sub arrl sub neg dx dy lrl\n"
1.176 - << " closepath fill } bind def\n";
1.177 + << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
1.178 + << " len w sub arrl sub dx dy lrl\n"
1.179 + << " arrw dy dx neg lrl\n"
1.180 + << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
1.181 + << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
1.182 + << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
1.183 + << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
1.184 + << " arrw dy dx neg lrl\n"
1.185 + << " len w sub arrl sub neg dx dy lrl\n"
1.186 + << " closepath fill } bind def\n";
1.187 + os << "/cshow { 2 index 2 index moveto\n"
1.188 + << " dup stringwidth pop neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
1.189 +
1.190 os << "\ngsave\n";
1.191 if(_scale!=1.0) os << _scale << " dup scale\n";
1.192
1.193 os << "%Edges:\ngsave\n";
1.194
1.195 - vector<Edge> el;
1.196 - if(_enableParallel) {
1.197 - for(EdgeIt e(g);e!=INVALID;++e) el.push_back(e);
1.198 - sort(el.begin(),el.end(),edgeLess(g));
1.199 - }
1.200 -
1.201 - for(NodeIt n(g);n!=INVALID;++n)
1.202 - for(OutEdgeIt e(g,n);e!=INVALID;++e)
1.203 - if(_drawArrows) {
1.204 - xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
1.205 - double l=sqrt(d.normSquare());
1.206 - d/=l;
1.207 - xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
1.208 - _coords[g.source(e)]);
1.209 - os << l-(_nodeSizes[g.source(e)]+
1.210 + if(_showEdges)
1.211 + if(_enableParallel) {
1.212 + vector<Edge> el;
1.213 + for(EdgeIt e(g);e!=INVALID;++e) el.push_back(e);
1.214 + sort(el.begin(),el.end(),edgeLess(g));
1.215 +
1.216 + typename vector<Edge>::iterator j;
1.217 + for(typename vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
1.218 + for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
1.219 +
1.220 + if(_drawArrows) {
1.221 + // xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
1.222 + // double l=sqrt(d.normSquare());
1.223 + // d/=l;
1.224 + // xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
1.225 + // _coords[g.source(e)]);
1.226 + // os << l-(_nodeSizes[g.source(e)]+
1.227 + // _nodeSizes[g.target(e)])*_nodeScale << ' '
1.228 + // << _edgeWidths[e]*_edgeWidthScale << ' '
1.229 + // << d.x << ' ' << d.y << ' '
1.230 + // << x1.x << ' ' << x1.y << ' '
1.231 + // << _edgeColors[e].getR() << ' '
1.232 + // << _edgeColors[e].getG() << ' '
1.233 + // << _edgeColors[e].getB() << " arr\n";
1.234 + }
1.235 + else {
1.236 + double sw=0;
1.237 + for(typename vector<Edge>::iterator e=i;e!=j;++e)
1.238 + sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
1.239 + sw-=_parEdgeDist;
1.240 + sw/=-2.0;
1.241 + xy<double> d(_coords[g.target(*i)]-_coords[g.source(*i)]);
1.242 + double l=sqrt(d.normSquare());
1.243 + d/=l;
1.244 + for(typename vector<Edge>::iterator e=i;e!=j;++e) {
1.245 + sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
1.246 + xy<double> m(_coords[g.target(*e)]+_coords[g.source(*e)]);
1.247 + m=m/2.0+rot(d)*sw/.75;
1.248 + os << _coords[g.source(*e)].x << ' '
1.249 + << _coords[g.source(*e)].y << ' '
1.250 + << m.x << ' ' << m.y << ' '
1.251 + << _coords[g.target(*e)].x << ' '
1.252 + << _coords[g.target(*e)].y << ' '
1.253 + << _edgeColors[*e].getR() << ' '
1.254 + << _edgeColors[*e].getG() << ' '
1.255 + << _edgeColors[*e].getB() << ' '
1.256 + << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
1.257 + sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
1.258 + }
1.259 + }
1.260 + }
1.261 + }
1.262 + else for(NodeIt n(g);n!=INVALID;++n)
1.263 + for(OutEdgeIt e(g,n);e!=INVALID;++e)
1.264 + if(_drawArrows) {
1.265 + xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
1.266 + double l=sqrt(d.normSquare());
1.267 + d/=l;
1.268 + xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+
1.269 + _coords[g.source(e)]);
1.270 + os << l-(_nodeSizes[g.source(e)]+
1.271 _nodeSizes[g.target(e)])*_nodeScale << ' '
1.272 << _edgeWidths[e]*_edgeWidthScale << ' '
1.273 << d.x << ' ' << d.y << ' '
1.274 @@ -322,8 +448,8 @@
1.275 << _edgeColors[e].getR() << ' '
1.276 << _edgeColors[e].getG() << ' '
1.277 << _edgeColors[e].getB() << " arr\n";
1.278 - }
1.279 - else os << _coords[g.source(e)].x << ' '
1.280 + }
1.281 + else os << _coords[g.source(e)].x << ' '
1.282 << _coords[g.source(e)].y << ' '
1.283 << _coords[g.target(e)].x << ' '
1.284 << _coords[g.target(e)].y << ' '
1.285 @@ -332,15 +458,24 @@
1.286 << _edgeColors[e].getB() << ' '
1.287 << _edgeWidths[e]*_edgeWidthScale << " l\n";
1.288 os << "grestore\n%Nodes:\ngsave\n";
1.289 - for(NodeIt n(g);n!=INVALID;++n)
1.290 - os << _coords[n].x << ' ' << _coords[n].y << ' '
1.291 + if(_showNodes)
1.292 + for(NodeIt n(g);n!=INVALID;++n)
1.293 + os << _coords[n].x << ' ' << _coords[n].y << ' '
1.294 << _nodeSizes[n]*_nodeScale << ' '
1.295 << _nodeColors[n].getR() << ' '
1.296 << _nodeColors[n].getG() << ' '
1.297 << _nodeColors[n].getB() << " n\n";
1.298 + if(_showNodeText) {
1.299 + os << "grestore\n%Node texts:\ngsave\n";
1.300 + os << "/fosi " << _nodeTextSize << " def\n";
1.301 + os << "(Helvetica) findfont fosi scalefont setfont\n";
1.302 + os << "0 0 0 setrgbcolor\n";
1.303 + for(NodeIt n(g);n!=INVALID;++n)
1.304 + os << _coords[n].x << ' ' << _coords[n].y
1.305 + << " (" << _nodeTexts[n] << ") cshow\n";
1.306 + }
1.307 os << "grestore\ngrestore\n";
1.308
1.309 -
1.310 //CleanUp:
1.311 if(_pleaseRemoveOsStream) {delete &os;}
1.312 }
1.313 @@ -364,9 +499,10 @@
1.314 /// .edgeWidthScale(.4);
1.315 ///\endcode
1.316 ///\sa GraphToEps
1.317 +///\sa graphToEps(G &g, char *file_name)
1.318 template<class G>
1.319 GraphToEps<DefaultGraphToEpsTraits<G> >
1.320 -graphToEps(G &g,std::ostream& os=std::cout)
1.321 +graphToEps(G &g, std::ostream& os=std::cout)
1.322 {
1.323 return
1.324 GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1.325 @@ -374,22 +510,12 @@
1.326
1.327 ///Generates an EPS file from a graph
1.328
1.329 -///\ingroup misc
1.330 -///Generates an EPS file from a graph.
1.331 -///\param g is a reference to the graph to be printed
1.332 -///\param file_name is the output file_name.
1.333 -///
1.334 -///This function also has a lot of \ref named-templ-param "named parameters",
1.335 -///they are declared as the members of class \ref GraphToEps. The following
1.336 -///example shows how to use these parameters.
1.337 -///\code
1.338 -/// graphToEps(g).scale(10).coords(coords)
1.339 -/// .nodeScale(2).nodeSizes(sizes)
1.340 -/// .edgeWidthScale(.4);
1.341 -///\endcode
1.342 -///\sa GraphToEps
1.343 -///\todo Avoid duplicated documentation
1.344 -///\bug Exception handling is missing? (Or we can just ignore it?)
1.345 +//\ingroup misc
1.346 +///This function does the same as
1.347 +///\ref graphToEps(G &g,std::ostream& os)
1.348 +///but it writes its output into the file \c file_name
1.349 +///instead of a stream.
1.350 +///\sa graphToEps(G &g, std::ostream& os)
1.351 template<class G>
1.352 GraphToEps<DefaultGraphToEpsTraits<G> >
1.353 graphToEps(G &g,char *file_name)
1.354 @@ -398,6 +524,21 @@
1.355 (DefaultGraphToEpsTraits<G>(g,*new ofstream(file_name),true));
1.356 }
1.357
1.358 +//Generates an EPS file from a graph.
1.359 +//\param g is a reference to the graph to be printed
1.360 +//\param file_name is the output file_name.
1.361 +//
1.362 +//This function also has a lot of \ref named-templ-param "named parameters",
1.363 +//they are declared as the members of class \ref GraphToEps. The following
1.364 +//example shows how to use these parameters.
1.365 +//\code
1.366 +// graphToEps(g).scale(10).coords(coords)
1.367 +// .nodeScale(2).nodeSizes(sizes)
1.368 +// .edgeWidthScale(.4);
1.369 +//\endcode
1.370 +//\sa GraphToEps
1.371 +//\todo Avoid duplicated documentation
1.372 +//\bug Exception handling is missing? (Or we can just ignore it?)
1.373
1.374 }
1.375
1.376 @@ -422,6 +563,16 @@
1.377 }
1.378 } colorSet;
1.379
1.380 +class IdMap :public MapBase<ListGraph::Node,int>
1.381 +{
1.382 + const ListGraph &g;
1.383 +public:
1.384 + IdMap(const ListGraph &_g) :g(_g) {}
1.385 + Value operator[](Key n) const { return g.id(n); }
1.386 +};
1.387 +
1.388 +
1.389 +
1.390 int main()
1.391 {
1.392 ListGraph g;
1.393 @@ -458,16 +609,39 @@
1.394 e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2;
1.395 e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1;
1.396
1.397 + IdMap id(g);
1.398 +
1.399 graphToEps(g,"proba.eps").scale(10).coords(coords).
1.400 nodeScale(2).nodeSizes(sizes).
1.401 nodeColors(composeMap(colorSet,colors)).
1.402 edgeColors(composeMap(colorSet,ecolors)).
1.403 - edgeWidthScale(.4).edgeWidths(widths);
1.404 + edgeWidthScale(.4).edgeWidths(widths).
1.405 + nodeTexts(id).nodeTextSize(3);
1.406 +
1.407 graphToEps(g,"proba_arr.eps").scale(10).coords(coords).
1.408 nodeScale(2).nodeSizes(sizes).
1.409 nodeColors(composeMap(colorSet,colors)).
1.410 edgeColors(composeMap(colorSet,ecolors)).
1.411 edgeWidthScale(.4).edgeWidths(widths).
1.412 - drawArrows().arrowWidth(1).arrowLength(1)
1.413 - ;
1.414 + nodeTexts(id).nodeTextSize(3).
1.415 + drawArrows().arrowWidth(1).arrowLength(1);
1.416 +
1.417 + e=g.addEdge(n1,n4); ecolors[e]=2; widths[e]=1;
1.418 + e=g.addEdge(n4,n1); ecolors[e]=1; widths[e]=2;
1.419 +
1.420 + e=g.addEdge(n1,n2); ecolors[e]=1; widths[e]=1;
1.421 + e=g.addEdge(n1,n2); ecolors[e]=2; widths[e]=1;
1.422 + e=g.addEdge(n1,n2); ecolors[e]=3; widths[e]=1;
1.423 + e=g.addEdge(n1,n2); ecolors[e]=4; widths[e]=1;
1.424 + e=g.addEdge(n1,n2); ecolors[e]=5; widths[e]=1;
1.425 + e=g.addEdge(n1,n2); ecolors[e]=6; widths[e]=1;
1.426 + e=g.addEdge(n1,n2); ecolors[e]=7; widths[e]=1;
1.427 +
1.428 + graphToEps(g,"proba_par.eps").scale(10).coords(coords).
1.429 + nodeScale(2).nodeSizes(sizes).
1.430 + nodeColors(composeMap(colorSet,colors)).
1.431 + edgeColors(composeMap(colorSet,ecolors)).
1.432 + edgeWidthScale(.4).edgeWidths(widths).
1.433 + nodeTexts(id).nodeTextSize(3).
1.434 + enableParallel().parEdgeDist(1.5);
1.435 }