38 typedef typename Graph::InEdgeIt InEdgeIt; |
47 typedef typename Graph::InEdgeIt InEdgeIt; |
39 typedef typename Graph::OutEdgeIt OutEdgeIt; |
48 typedef typename Graph::OutEdgeIt OutEdgeIt; |
40 |
49 |
41 |
50 |
42 const Graph &g; |
51 const Graph &g; |
43 ConstMap<typename Graph::Node,xy<double> > coords; |
52 ConstMap<typename Graph::Node,xy<double> > _coords; |
44 ConstMap<typename Graph::Node,double > nodeSizes; |
53 ConstMap<typename Graph::Node,double > _nodeSizes; |
45 |
54 |
46 ConstMap<typename Graph::Node,Color > nodeColors; |
55 ConstMap<typename Graph::Node,Color > _nodeColors; |
47 ConstMap<typename Graph::Edge,Color > edgeColors; |
56 ConstMap<typename Graph::Edge,Color > _edgeColors; |
48 double nodeSizeScalar; |
57 |
49 double xBorder, yBorder; |
58 ConstMap<typename Graph::Edge,double > _edgeWidths; |
50 |
59 |
51 DefaultGraphToEpsTraits(G &_g) : |
60 double _edgeWidthScale; |
52 g(_g), coords(xy<double>(1,1)), nodeSizes(1.0), |
61 |
53 nodeColors(Color(1,1,1)), edgeColors(Color(0,0,0)), |
62 double _nodeScale; |
54 nodeSizeScalar(1.0), xBorder(10), yBorder(10) {} |
63 double _xBorder, _yBorder; |
|
64 double _scale; |
|
65 double _nodeBorderQuotient; |
|
66 |
|
67 bool _drawArrows; |
|
68 double _arrowLength, _arrowWidth; |
|
69 |
|
70 ///Constructor |
|
71 |
|
72 ///Constructor |
|
73 ///\param _g is a reference to the underlying graph |
|
74 DefaultGraphToEpsTraits(const G &_g) : |
|
75 g(_g), _coords(xy<double>(1,1)), _nodeSizes(1.0), |
|
76 _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)), |
|
77 _edgeWidths(1), _edgeWidthScale(0.3), |
|
78 _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0), |
|
79 _nodeBorderQuotient(.1), |
|
80 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3) {} |
55 }; |
81 }; |
56 |
82 |
57 ///\e |
83 ///Helper class to implement the named parameters of \ref graphToEps() |
|
84 |
|
85 ///Helper class to implement the named parameters of \ref graphToEps() |
|
86 ///\todo Is 'helper class' a good name for this? |
|
87 /// |
58 template<class T> class GraphToEps : public T |
88 template<class T> class GraphToEps : public T |
59 { |
89 { |
60 typedef typename T::Graph Graph; |
90 typedef typename T::Graph Graph; |
61 typedef typename Graph::Node Node; |
91 typedef typename Graph::Node Node; |
62 typedef typename Graph::NodeIt NodeIt; |
92 typedef typename Graph::NodeIt NodeIt; |
68 bool dontPrint; |
98 bool dontPrint; |
69 |
99 |
70 public: |
100 public: |
71 GraphToEps(const T &t) : T(t), dontPrint(false) {}; |
101 GraphToEps(const T &t) : T(t), dontPrint(false) {}; |
72 |
102 |
73 template<class X> struct SetCoordsTraits : public T { |
103 template<class X> struct CoordsTraits : public T { |
74 const X &coords; |
104 const X &_coords; |
75 SetCoordsTraits(const T &t,const X &x) : T(t), coords(x) {} |
105 CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} |
76 }; |
106 }; |
77 ///\e |
107 ///Sets the map of the node coordinates |
78 template<class X> GraphToEps<SetCoordsTraits<X> > setCoords(const X &x) { |
108 |
79 dontPrint=true; |
109 ///Sets the map of the node coordinates. |
80 return GraphToEps<SetCoordsTraits<X> >(SetCoordsTraits<X>(*this,x)); |
110 ///\param x must be a node map with xy<double> or xy<int> values. |
81 } |
111 template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) { |
82 template<class X> struct SetNodeSizesTraits : public T { |
112 dontPrint=true; |
83 const X &nodeSizes; |
113 return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x)); |
84 SetNodeSizesTraits(const T &t,const X &x) : T(t), nodeSizes(x) {} |
114 } |
85 }; |
115 template<class X> struct NodeSizesTraits : public T { |
86 ///\e |
116 const X &_nodeSizes; |
87 template<class X> GraphToEps<SetNodeSizesTraits<X> > setNodeSizes(const X &x) |
117 NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} |
88 { |
118 }; |
89 dontPrint=true; |
119 ///Sets the map of the node sizes |
90 return GraphToEps<SetNodeSizesTraits<X> >(SetNodeSizesTraits<X>(*this,x)); |
120 |
91 } |
121 ///Sets the map of the node sizes |
92 template<class X> struct SetNodeColorsTraits : public T { |
122 ///\param x must be a node map with \c double (or convertible) values. |
93 const X &nodeColors; |
123 template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x) |
94 SetNodeColorsTraits(const T &t,const X &x) : T(t), nodeColors(x) {} |
124 { |
95 }; |
125 dontPrint=true; |
96 ///\e |
126 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x)); |
97 template<class X> GraphToEps<SetNodeColorsTraits<X> > |
127 } |
98 setNodeColors(const X &x) |
128 template<class X> struct EdgeWidthsTraits : public T { |
99 { |
129 const X &_edgeWidths; |
100 dontPrint=true; |
130 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {} |
101 return GraphToEps<SetNodeColorsTraits<X> >(SetNodeColorsTraits<X>(*this,x)); |
131 }; |
102 } |
132 ///Sets the map of the edge widths |
103 template<class X> struct SetEdgeColorsTraits : public T { |
133 |
104 const X &edgeColors; |
134 ///Sets the map of the edge widths |
105 SetEdgeColorsTraits(const T &t,const X &x) : T(t), edgeColors(x) {} |
135 ///\param x must be a edge map with \c double (or convertible) values. |
106 }; |
136 template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x) |
107 ///\e |
137 { |
108 template<class X> GraphToEps<SetEdgeColorsTraits<X> > |
138 dontPrint=true; |
109 setEdgeColors(const X &x) |
139 return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x)); |
110 { |
140 } |
111 dontPrint=true; |
141 |
112 return GraphToEps<SetEdgeColorsTraits<X> >(SetEdgeColorsTraits<X>(*this,x)); |
142 template<class X> struct NodeColorsTraits : public T { |
113 } |
143 const X &_nodeColors; |
114 ///\e |
144 NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {} |
115 GraphToEps<T> &scaleNodeSize(double d) {nodeSizeScalar=d;return *this;} |
145 }; |
|
146 ///Sets the map of the node colors |
|
147 |
|
148 ///Sets the map of the node colors |
|
149 ///\param x must be a node map with \ref Color values. |
|
150 template<class X> GraphToEps<NodeColorsTraits<X> > |
|
151 nodeColors(const X &x) |
|
152 { |
|
153 dontPrint=true; |
|
154 return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x)); |
|
155 } |
|
156 template<class X> struct EdgeColorsTraits : public T { |
|
157 const X &_edgeColors; |
|
158 EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {} |
|
159 }; |
|
160 ///Sets the map of the edge colors |
|
161 |
|
162 ///Sets the map of the edge colors |
|
163 ///\param x must be a edge map with \ref Color values. |
|
164 template<class X> GraphToEps<EdgeColorsTraits<X> > |
|
165 edgeColors(const X &x) |
|
166 { |
|
167 dontPrint=true; |
|
168 return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x)); |
|
169 } |
|
170 ///Sets a global scale factor for node sizes |
|
171 |
|
172 ///Sets a global scale factor for node sizes |
|
173 /// |
|
174 GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;} |
|
175 ///Sets a global scale factor for edge widths |
|
176 |
|
177 ///Sets a global scale factor for edge widths |
|
178 /// |
|
179 GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;} |
|
180 ///Sets a global scale factor for the whole picture |
|
181 |
|
182 ///Sets a global scale factor for the whole picture |
|
183 /// |
|
184 GraphToEps<T> &scale(double d) {_scale=d;return *this;} |
|
185 ///Sets the width of the border around the picture |
|
186 |
|
187 ///Sets the width of the border around the picture |
|
188 /// |
|
189 GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;} |
|
190 ///Sets the width of the border around the picture |
|
191 |
|
192 ///Sets the width of the border around the picture |
|
193 /// |
|
194 GraphToEps<T> &border(double x, double y) { |
|
195 _xBorder=x;_yBorder=y;return *this; |
|
196 } |
|
197 ///Sets whether to draw arrows |
|
198 |
|
199 ///Sets whether to draw arrows |
|
200 /// |
|
201 GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;} |
|
202 ///Sets the length of the arrowheads |
|
203 |
|
204 ///Sets the length of the arrowheads |
|
205 /// |
|
206 GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;} |
|
207 ///Sets the width of the arrowheads |
|
208 |
|
209 ///Sets the width of the arrowheads |
|
210 /// |
|
211 GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;} |
116 |
212 |
117 ~GraphToEps() |
213 ~GraphToEps() |
118 { |
214 { |
119 if(dontPrint) return; |
215 if(dontPrint) return; |
120 |
216 |
121 cout << "%!PS-Adobe-2.0 EPSF-2.0\n"; |
217 cout << "%!PS-Adobe-2.0 EPSF-2.0\n"; |
122 //\todo: Chech whether the graph is empty. |
218 //\todo: Chech whether the graph is empty. |
123 BoundingBox<double> bb; |
219 BoundingBox<double> bb; |
124 for(NodeIt n(g); |
220 for(NodeIt n(g);n!=INVALID;++n) { |
125 n!=INVALID; |
221 double ns=_nodeSizes[n]*_nodeScale; |
126 ++n) { |
222 xy<double> p(ns,ns); |
127 xy<double> p(nodeSizes[n]*nodeSizeScalar,nodeSizes[n]*nodeSizeScalar); |
223 bb+=p+_coords[n]; |
128 bb+=coords[n]+p; |
224 bb+=-p+_coords[n]; |
129 bb+=coords[n]-p; |
|
130 } |
225 } |
131 cout << "%%BoundingBox: " |
226 cout << "%%BoundingBox: " |
132 << bb.left()-xBorder << ' ' << bb.bottom()-yBorder << ' ' |
227 << bb.left()* _scale-_xBorder << ' ' |
133 << bb.right()+xBorder << ' ' << bb.top()+yBorder << '\n'; |
228 << bb.bottom()*_scale-_yBorder << ' ' |
134 //x1 y1 x2 y2 cr cg cb |
229 << bb.right()* _scale+_xBorder << ' ' |
135 cout << "/l { setrgbcolor newpath moveto lineto stroke } bind def\n"; |
230 << bb.top()* _scale+_yBorder << '\n'; |
|
231 //x1 y1 x2 y2 cr cg cb w |
|
232 cout << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n"; |
136 cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n"; |
233 cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n"; |
137 // x y r cr cg cb |
234 // x y r cr cg cb |
138 cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n" |
235 cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n" |
139 << " 0 0 0 setrgbcolor dup 10 div setlinewidth c stroke\n" |
236 << " 0 0 0 setrgbcolor dup " |
|
237 << _nodeBorderQuotient << " mul setlinewidth " |
|
238 << 1+_nodeBorderQuotient/2 << " div c stroke\n" |
140 << " } bind def\n"; |
239 << " } bind def\n"; |
141 |
240 cout << "/arrl " << _arrowLength << " def\n"; |
|
241 cout << "/arrw " << _arrowWidth << " def\n"; |
|
242 // l dx_norm dy_norm |
|
243 cout << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; |
|
244 //len w dx_norm dy_norm x1 y1 cr cg cb |
|
245 cout << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n" |
|
246 << " /w exch def /len exch def\n" |
|
247 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" |
|
248 << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" |
|
249 << " len w sub arrl sub dx dy lrl\n" |
|
250 << " arrw dy dx neg lrl\n" |
|
251 << " dx arrl w add mul dy w 2 div arrw add mul sub\n" |
|
252 << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" |
|
253 << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n" |
|
254 << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n" |
|
255 << " arrw dy dx neg lrl\n" |
|
256 << " len w sub arrl sub neg dx dy lrl\n" |
|
257 << " closepath fill } bind def\n"; |
|
258 cout << "\ngsave\n"; |
|
259 if(_scale!=1.0) cout << _scale << " dup scale\n"; |
142 cout << "%Edges:\ngsave\n"; |
260 cout << "%Edges:\ngsave\n"; |
143 for(NodeIt n(g);n!=INVALID;++n) |
261 for(NodeIt n(g);n!=INVALID;++n) |
144 for(OutEdgeIt e(g,n);e!=INVALID;++e) |
262 for(OutEdgeIt e(g,n);e!=INVALID;++e) |
145 cout << coords[g.source(e)].x << ' ' << coords[g.source(e)].y << ' ' |
263 if(_drawArrows) { |
146 << coords[g.target(e)].x << ' ' << coords[g.target(e)].y << ' ' |
264 xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]); |
147 << edgeColors[e].getR() << ' ' |
265 double l=sqrt(d.normSquare()); |
148 << edgeColors[e].getG() << ' ' |
266 d/=l; |
149 << edgeColors[e].getB() << " l\n"; |
267 xy<double> x1(d*_nodeScale*_nodeSizes[g.source(e)]+ |
|
268 _coords[g.source(e)]); |
|
269 cout << l-(_nodeSizes[g.source(e)]+ |
|
270 _nodeSizes[g.target(e)])*_nodeScale << ' ' |
|
271 << _edgeWidths[e]*_edgeWidthScale << ' ' |
|
272 << d.x << ' ' << d.y << ' ' |
|
273 << x1.x << ' ' << x1.y << ' ' |
|
274 << _edgeColors[e].getR() << ' ' |
|
275 << _edgeColors[e].getG() << ' ' |
|
276 << _edgeColors[e].getB() << " arr\n"; |
|
277 } |
|
278 else cout << _coords[g.source(e)].x << ' ' |
|
279 << _coords[g.source(e)].y << ' ' |
|
280 << _coords[g.target(e)].x << ' ' |
|
281 << _coords[g.target(e)].y << ' ' |
|
282 << _edgeColors[e].getR() << ' ' |
|
283 << _edgeColors[e].getG() << ' ' |
|
284 << _edgeColors[e].getB() << ' ' |
|
285 << _edgeWidths[e]*_edgeWidthScale << " l\n"; |
150 cout << "grestore\n%Nodes:\ngsave\n"; |
286 cout << "grestore\n%Nodes:\ngsave\n"; |
151 for(NodeIt n(g);n!=INVALID;++n) |
287 for(NodeIt n(g);n!=INVALID;++n) |
152 cout << coords[n].x << ' ' << coords[n].y << ' ' |
288 cout << _coords[n].x << ' ' << _coords[n].y << ' ' |
153 << nodeSizes[n]*nodeSizeScalar << ' ' |
289 << _nodeSizes[n]*_nodeScale << ' ' |
154 << nodeColors[n].getR() << ' ' |
290 << _nodeColors[n].getR() << ' ' |
155 << nodeColors[n].getG() << ' ' |
291 << _nodeColors[n].getG() << ' ' |
156 << nodeColors[n].getB() << " n\n"; |
292 << _nodeColors[n].getB() << " n\n"; |
157 cout << "grestore\n"; |
293 cout << "grestore\ngrestore\n"; |
158 } |
294 } |
159 }; |
295 }; |
160 |
296 |
161 |
297 |
|
298 ///Generates an EPS file from a graph |
|
299 |
|
300 ///\ingroup misc |
|
301 ///Generates an EPS file from a graph. |
|
302 /// |
|
303 ///This function has a lot of \ref named-templ-param "named parameters", |
|
304 ///they are declared as the members of class \ref GraphToEps. The following |
|
305 ///example shows how to use these parameters. |
|
306 ///\code |
|
307 /// graphToEps(g).scale(10).coords(coords) |
|
308 /// .nodeScale(2).nodeSizes(sizes) |
|
309 /// .edgeWidthScale(.4); |
|
310 ///\endcode |
|
311 ///\sa GraphToEps |
162 template<class G> |
312 template<class G> |
163 GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g) |
313 GraphToEps<DefaultGraphToEpsTraits<G> > graphToEps(G &g) |
164 { |
314 { |
165 return GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g)); |
315 return GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g)); |
166 } |
316 } |
204 |
354 |
205 ListGraph::NodeMap<Xy> coords(g); |
355 ListGraph::NodeMap<Xy> coords(g); |
206 ListGraph::NodeMap<double> sizes(g); |
356 ListGraph::NodeMap<double> sizes(g); |
207 ListGraph::NodeMap<int> colors(g); |
357 ListGraph::NodeMap<int> colors(g); |
208 ListGraph::EdgeMap<int> ecolors(g); |
358 ListGraph::EdgeMap<int> ecolors(g); |
|
359 ListGraph::EdgeMap<int> widths(g); |
209 |
360 |
210 coords[n1]=Xy(50,50); sizes[n1]=1; colors[n1]=1; |
361 coords[n1]=Xy(50,50); sizes[n1]=1; colors[n1]=1; |
211 coords[n2]=Xy(50,70); sizes[n2]=2; colors[n2]=2; |
362 coords[n2]=Xy(50,70); sizes[n2]=2; colors[n2]=2; |
212 coords[n3]=Xy(70,70); sizes[n3]=1; colors[n3]=3; |
363 coords[n3]=Xy(70,70); sizes[n3]=1; colors[n3]=3; |
213 coords[n4]=Xy(70,50); sizes[n4]=2; colors[n4]=4; |
364 coords[n4]=Xy(70,50); sizes[n4]=2; colors[n4]=4; |
214 coords[n5]=Xy(85,60); sizes[n5]=3; colors[n5]=5; |
365 coords[n5]=Xy(85,60); sizes[n5]=3; colors[n5]=5; |
215 |
366 |
216 Edge e; |
367 Edge e; |
217 |
368 |
218 e=g.addEdge(n1,n2); ecolors[e]=0; |
369 e=g.addEdge(n1,n2); ecolors[e]=0; widths[e]=1; |
219 e=g.addEdge(n2,n3); ecolors[e]=0; |
370 e=g.addEdge(n2,n3); ecolors[e]=0; widths[e]=1; |
220 e=g.addEdge(n3,n5); ecolors[e]=0; |
371 e=g.addEdge(n3,n5); ecolors[e]=0; widths[e]=3; |
221 e=g.addEdge(n5,n4); ecolors[e]=0; |
372 e=g.addEdge(n5,n4); ecolors[e]=0; widths[e]=1; |
222 e=g.addEdge(n4,n1); ecolors[e]=0; |
373 e=g.addEdge(n4,n1); ecolors[e]=0; widths[e]=1; |
223 e=g.addEdge(n2,n4); ecolors[e]=1; |
374 e=g.addEdge(n2,n4); ecolors[e]=1; widths[e]=2; |
224 e=g.addEdge(n3,n4); ecolors[e]=2; |
375 e=g.addEdge(n3,n4); ecolors[e]=2; widths[e]=1; |
225 |
376 |
226 graphToEps(g).setCoords(coords). |
377 graphToEps(g).scale(10).coords(coords). |
227 scaleNodeSize(2).setNodeSizes(sizes). |
378 nodeScale(2).nodeSizes(sizes). |
228 setNodeColors(composeMap(colorSet,colors)). |
379 nodeColors(composeMap(colorSet,colors)). |
229 setEdgeColors(composeMap(colorSet,ecolors)); |
380 edgeColors(composeMap(colorSet,ecolors)). |
|
381 edgeWidthScale(.4).edgeWidths(widths). |
|
382 drawArrows().arrowWidth(1).arrowLength(1) |
|
383 ; |
230 } |
384 } |