The graph adadptors can be alteration observed.
In most cases it uses the adapted graph alteration notifiers.
Only special case is now the UndirGraphAdaptor, where
we have to proxy the signals from the graph.
The SubBidirGraphAdaptor is removed, because it doest not
gives more feature than the EdgeSubGraphAdaptor<UndirGraphAdaptor<Graph>>.
The ResGraphAdaptor is based on this composition.
3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #ifndef LEMON_GRAPH_TO_EPS_H
20 #define LEMON_GRAPH_TO_EPS_H
33 #include<lemon/invalid.h>
35 #include<lemon/maps.h>
36 #include<lemon/color.h>
37 #include<lemon/bezier.h>
42 ///\brief Simple graph drawer
44 ///\author Alpar Juttner
51 typedef typename MT::Key Key;
52 typedef typename MT::Value Value;
55 _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
56 Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
59 ///Default traits class of \ref GraphToEps
61 ///Default traits class of \ref GraphToEps
63 ///\c G is the type of the underlying graph.
65 struct DefaultGraphToEpsTraits
68 typedef typename Graph::Node Node;
69 typedef typename Graph::NodeIt NodeIt;
70 typedef typename Graph::Edge Edge;
71 typedef typename Graph::EdgeIt EdgeIt;
72 typedef typename Graph::InEdgeIt InEdgeIt;
73 typedef typename Graph::OutEdgeIt OutEdgeIt;
80 typedef ConstMap<typename Graph::Node,xy<double> > CoordsMapType;
81 CoordsMapType _coords;
82 ConstMap<typename Graph::Node,double > _nodeSizes;
83 ConstMap<typename Graph::Node,int > _nodeShapes;
85 ConstMap<typename Graph::Node,Color > _nodeColors;
86 ConstMap<typename Graph::Edge,Color > _edgeColors;
88 ConstMap<typename Graph::Edge,double > _edgeWidths;
90 double _edgeWidthScale;
93 double _xBorder, _yBorder;
95 double _nodeBorderQuotient;
98 double _arrowLength, _arrowWidth;
100 bool _showNodes, _showEdges;
102 bool _enableParallel;
106 ConstMap<typename Graph::Node,bool > _nodeTexts;
107 double _nodeTextSize;
109 bool _showNodePsText;
110 ConstMap<typename Graph::Node,bool > _nodePsTexts;
111 char *_nodePsTextsPreamble;
115 bool _pleaseRemoveOsStream;
120 std::string _copyright;
122 enum NodeTextColorType
123 { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
124 ConstMap<typename Graph::Node,Color > _nodeTextColors;
127 bool _autoEdgeWidthScale;
133 ///\param _g is a reference to the graph to be printed
134 ///\param _os is a reference to the output stream.
135 ///\param _os is a reference to the output stream.
136 ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
137 ///will be explicitly deallocated by the destructor.
138 ///By default it is <tt>std::cout</tt>
139 DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
142 _coords(xy<double>(1,1)), _nodeSizes(1.0), _nodeShapes(0),
143 _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
144 _edgeWidths(1), _edgeWidthScale(0.3),
145 _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
146 _nodeBorderQuotient(.1),
147 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
148 _showNodes(true), _showEdges(true),
149 _enableParallel(false), _parEdgeDist(1),
150 _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
151 _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
153 _pleaseRemoveOsStream(_pros), _scaleToA4(false),
154 _nodeTextColorType(SAME_COL), _nodeTextColors(Color(0,0,0)),
155 _autoNodeScale(false),
156 _autoEdgeWidthScale(false),
161 ///Helper class to implement the named parameters of \ref graphToEps()
163 ///Helper class to implement the named parameters of \ref graphToEps()
164 ///\todo Is 'helper class' a good name for this?
166 ///\todo Follow PostScript's DSC.
167 /// Use own dictionary.
168 ///\todo Useful new features.
169 /// - Linestyles: dotted, dashed etc.
170 /// - A second color and percent value for the lines.
171 template<class T> class GraphToEps : public T
173 // Can't believe it is required by the C++ standard
179 using T::_nodeShapes;
180 using T::_nodeColors;
181 using T::_edgeColors;
182 using T::_edgeWidths;
184 using T::_edgeWidthScale;
189 using T::_nodeBorderQuotient;
191 using T::_drawArrows;
192 using T::_arrowLength;
193 using T::_arrowWidth;
198 using T::_enableParallel;
199 using T::_parEdgeDist;
201 using T::_showNodeText;
203 using T::_nodeTextSize;
205 using T::_showNodePsText;
206 using T::_nodePsTexts;
207 using T::_nodePsTextsPreamble;
209 using T::_undirected;
211 using T::_pleaseRemoveOsStream;
218 using T::NodeTextColorType;
222 using T::_nodeTextColorType;
223 using T::_nodeTextColors;
225 using T::_autoNodeScale;
226 using T::_autoEdgeWidthScale;
230 // dradnats ++C eht yb deriuqer si ti eveileb t'naC
232 typedef typename T::Graph Graph;
233 typedef typename Graph::Node Node;
234 typedef typename Graph::NodeIt NodeIt;
235 typedef typename Graph::Edge Edge;
236 typedef typename Graph::EdgeIt EdgeIt;
237 typedef typename Graph::InEdgeIt InEdgeIt;
238 typedef typename Graph::OutEdgeIt OutEdgeIt;
240 static const int INTERPOL_PREC;
241 static const double A4HEIGHT;
242 static const double A4WIDTH;
243 static const double A4BORDER;
254 ///\image html nodeshape_0.png
255 ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
258 ///\image html nodeshape_1.png
259 ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
263 ///\image html nodeshape_2.png
264 ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
268 ///\image html nodeshape_3.png
269 ///\image latex nodeshape_2.eps "MALE shape (4)" width=2cm
273 ///\image html nodeshape_4.png
274 ///\image latex nodeshape_2.eps "FEMALE shape (4)" width=2cm
283 edgeLess(const Graph &_g) : g(_g) {}
284 bool operator()(Edge a,Edge b) const
286 Node ai=std::min(g.source(a),g.target(a));
287 Node aa=std::max(g.source(a),g.target(a));
288 Node bi=std::min(g.source(b),g.target(b));
289 Node ba=std::max(g.source(b),g.target(b));
291 (ai==bi && (aa < ba ||
292 (aa==ba && ai==g.source(a) && bi==g.target(b))));
295 bool isParallel(Edge e,Edge f) const
297 return (g.source(e)==g.source(f)&&
298 g.target(e)==g.target(f)) ||
299 (g.source(e)==g.target(f)&&
300 g.target(e)==g.source(f));
303 static std::string psOut(const xy<TT> &p)
305 std::ostringstream os;
306 os << p.x << ' ' << p.y;
309 static std::string psOut(const Color &c)
311 std::ostringstream os;
312 os << c.red() << ' ' << c.green() << ' ' << c.blue();
317 GraphToEps(const T &t) : T(t), dontPrint(false) {};
319 template<class X> struct CoordsTraits : public T {
320 typedef X CoordsMapType;
322 CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
324 ///Sets the map of the node coordinates
326 ///Sets the map of the node coordinates.
327 ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values.
328 template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
330 return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
332 template<class X> struct NodeSizesTraits : public T {
334 NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
336 ///Sets the map of the node sizes
338 ///Sets the map of the node sizes
339 ///\param x must be a node map with \c double (or convertible) values.
340 template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
343 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
345 template<class X> struct NodeShapesTraits : public T {
346 const X &_nodeShapes;
347 NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
349 ///Sets the map of the node shapes
351 ///Sets the map of the node shapes.
352 ///The availabe shape values
353 ///can be found in \ref NodeShapes "enum NodeShapes".
354 ///\param x must be a node map with \c int (or convertible) values.
356 template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
359 return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
361 template<class X> struct NodeTextsTraits : public T {
363 NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
365 ///Sets the text printed on the nodes
367 ///Sets the text printed on the nodes
368 ///\param x must be a node map with type that can be pushed to a standard
370 template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
374 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
376 template<class X> struct NodePsTextsTraits : public T {
377 const X &_nodePsTexts;
378 NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
380 ///Inserts a PostScript block to the nodes
382 ///With this command it is possible to insert a verbatim PostScript
383 ///block to the nodes.
384 ///The PS current point will be moved to the centre of the node before
385 ///the PostScript block inserted.
387 ///Before and after the block a newline character is inserted so you
388 ///don't have to bother with the separators.
390 ///\param x must be a node map with type that can be pushed to a standard
393 ///\sa nodePsTextsPreamble()
394 ///\todo Offer the choise not to move to the centre but pass the coordinates
395 ///to the Postscript block inserted.
396 template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
399 _showNodePsText=true;
400 return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
402 template<class X> struct EdgeWidthsTraits : public T {
403 const X &_edgeWidths;
404 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
406 ///Sets the map of the edge widths
408 ///Sets the map of the edge widths
409 ///\param x must be a edge map with \c double (or convertible) values.
410 template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
413 return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
416 template<class X> struct NodeColorsTraits : public T {
417 const X &_nodeColors;
418 NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
420 ///Sets the map of the node colors
422 ///Sets the map of the node colors
423 ///\param x must be a node map with \ref Color values.
426 template<class X> GraphToEps<NodeColorsTraits<X> >
427 nodeColors(const X &x)
430 return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
432 template<class X> struct NodeTextColorsTraits : public T {
433 const X &_nodeTextColors;
434 NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
436 ///Sets the map of the node text colors
438 ///Sets the map of the node text colors
439 ///\param x must be a node map with \ref Color values.
442 template<class X> GraphToEps<NodeTextColorsTraits<X> >
443 nodeTextColors(const X &x)
446 _nodeTextColorType=CUST_COL;
447 return GraphToEps<NodeTextColorsTraits<X> >
448 (NodeTextColorsTraits<X>(*this,x));
450 template<class X> struct EdgeColorsTraits : public T {
451 const X &_edgeColors;
452 EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
454 ///Sets the map of the edge colors
456 ///Sets the map of the edge colors
457 ///\param x must be a edge map with \ref Color values.
460 template<class X> GraphToEps<EdgeColorsTraits<X> >
461 edgeColors(const X &x)
464 return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
466 ///Sets a global scale factor for node sizes
468 ///Sets a global scale factor for node sizes.
470 /// If nodeSizes() is not given, this function simply sets the node
471 /// sizes to \c d. If nodeSizes() is given, but
472 /// autoNodeScale() is not, then the node size given by
473 /// nodeSizes() will be multiplied by the value \c d.
474 /// If both nodeSizes() and autoNodeScale() are used, then the
475 /// node sizes will be scaled in such a way that the greatest size will be
477 GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
478 ///Turns on/off the automatic node width scaling.
480 ///Turns on/off the automatic node width scaling.
484 GraphToEps<T> &autoNodeScale(bool b=true) {
485 _autoNodeScale=b;return *this;
488 ///Negates the Y coordinates.
490 ///Negates the Y coordinates.
494 GraphToEps<T> &negateY(bool b=true) {
495 _negY=b;return *this;
498 ///Sets a global scale factor for edge widths
500 /// Sets a global scale factor for edge widths.
502 /// If edgeWidths() is not given, this function simply sets the edge
503 /// widths to \c d. If edgeWidths() is given, but
504 /// autoEdgeWidthScale() is not, then the edge withs given by
505 /// edgeWidths() will be multiplied by the value \c d.
506 /// If both edgeWidths() and autoEdgeWidthScale() are used, then the
507 /// edge withs will be scaled in such a way that the greatest width will be
509 GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
510 ///Turns on/off the automatic edge width scaling.
512 ///Turns on/off the automatic edge width scaling.
514 ///\sa edgeWidthScale()
516 GraphToEps<T> &autoEdgeWidthScale(bool b=true) {
517 _autoEdgeWidthScale=b;return *this;
519 ///Sets a global scale factor for the whole picture
521 ///Sets a global scale factor for the whole picture
524 GraphToEps<T> &scale(double d) {_scale=d;return *this;}
525 ///Sets the width of the border around the picture
527 ///Sets the width of the border around the picture
529 GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
530 ///Sets the width of the border around the picture
532 ///Sets the width of the border around the picture
534 GraphToEps<T> &border(double x, double y) {
535 _xBorder=x;_yBorder=y;return *this;
537 ///Sets whether to draw arrows
539 ///Sets whether to draw arrows
541 GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
542 ///Sets the length of the arrowheads
544 ///Sets the length of the arrowheads
546 GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
547 ///Sets the width of the arrowheads
549 ///Sets the width of the arrowheads
551 GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
553 ///Scales the drawing to fit to A4 page
555 ///Scales the drawing to fit to A4 page
557 GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
559 ///Enables parallel edges
561 ///Enables parallel edges
562 GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
568 GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
574 GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
579 GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
581 ///Sets the size of the node texts
583 ///Sets the size of the node texts
585 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
587 ///Sets the color of the node texts to be different from the node color
589 ///Sets the color of the node texts to be as different from the node color
592 GraphToEps<T> &distantColorNodeTexts()
593 {_nodeTextColorType=DIST_COL;return *this;}
594 ///Sets the color of the node texts to be black or white and always visible.
596 ///Sets the color of the node texts to be black or white according to
598 ///different from the node color
600 GraphToEps<T> &distantBWNodeTexts()
601 {_nodeTextColorType=DIST_BW;return *this;}
603 ///Gives a preamble block for node Postscript block.
605 ///Gives a preamble block for node Postscript block.
608 GraphToEps<T> & nodePsTextsPreamble(const char *str) {
609 _nodePsTextsPreamble=str ;return *this;
611 ///Sets whether the the graph is undirected
613 ///Sets whether the the graph is undirected
615 GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
617 ///Sets whether the the graph is directed
619 ///Sets whether the the graph is directed.
620 ///Use it to show the undirected edges as a pair of directed ones.
621 GraphToEps<T> &bidir(bool b=true) {_undirected=!b;return *this;}
625 ///Sets the title of the generated image,
626 ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
628 GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
629 ///Sets the copyright statement.
631 ///Sets the copyright statement of the generated image,
632 ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
634 ///\todo Multiline copyright notice could be supported.
635 GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;}
638 bool isInsideNode(xy<double> p, double r,int t)
644 return p.normSquare()<=r*r;
646 return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
648 return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
658 ///Like other functions using
659 ///\ref named-templ-func-param "named template parameters",
660 ///this function calles the algorithm itself, i.e. in this case
661 ///it draws the graph.
663 if(dontPrint) return;
665 _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
667 os << "%!PS-Adobe-2.0 EPSF-2.0\n";
668 if(_title.size()>0) os << "%%Title: " << _title << '\n';
669 if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
670 // << "%%Copyright: XXXX\n"
671 os << "%%Creator: LEMON, graphToEps()\n";
676 gettimeofday(&tv, 0);
677 ctime_r(&tv.tv_sec,cbuf);
678 os << "%%CreationDate: " << cbuf;
681 if (_autoEdgeWidthScale) {
683 for(EdgeIt e(g);e!=INVALID;++e)
684 max_w=std::max(double(_edgeWidths[e]),max_w);
685 ///\todo better 'epsilon' would be nice here.
687 _edgeWidthScale/=max_w;
691 if (_autoNodeScale) {
693 for(NodeIt n(g);n!=INVALID;++n)
694 max_s=std::max(double(_nodeSizes[n]),max_s);
695 ///\todo better 'epsilon' would be nice here.
702 BoundingBox<double> bb;
703 ///\bug: Chech whether the graph is empty.
704 for(NodeIt n(g);n!=INVALID;++n) {
705 double ns=_nodeSizes[n]*_nodeScale;
707 switch(_nodeShapes[n]) {
711 bb.add(p+mycoords[n]);
712 bb.add(-p+mycoords[n]);
715 bb.add(-p+mycoords[n]);
716 bb.add(xy<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
719 bb.add(p+mycoords[n]);
720 bb.add(xy<double>(-ns,-3.01*ns)+mycoords[n]);
725 bb = BoundingBox<double>(xy<double>(0,0));
729 os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
731 //Rescale so that BoundingBox won't be neither to big nor too small.
732 while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10;
733 while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10;
735 os << "%%BoundingBox: "
736 << int(floor(bb.left() * _scale - _xBorder)) << ' '
737 << int(floor(bb.bottom() * _scale - _yBorder)) << ' '
738 << int(ceil(bb.right() * _scale + _xBorder)) << ' '
739 << int(ceil(bb.top() * _scale + _yBorder)) << '\n';
742 os << "%%EndComments\n";
744 //x1 y1 x2 y2 x3 y3 cr cg cb w
745 os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
746 << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
747 os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
749 os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
751 os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
752 << " 2 index 1 index sub 2 index 2 index add lineto\n"
753 << " 2 index 1 index sub 2 index 2 index sub lineto\n"
754 << " 2 index 1 index add 2 index 2 index sub lineto\n"
755 << " closepath pop pop pop} bind def\n";
757 os << "/di { newpath 2 index 1 index add 2 index moveto\n"
758 << " 2 index 2 index 2 index add lineto\n"
759 << " 2 index 1 index sub 2 index lineto\n"
760 << " 2 index 2 index 2 index sub lineto\n"
761 << " closepath pop pop pop} bind def\n";
763 os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
764 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
766 os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
767 << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
769 os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
770 << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
772 os << "/nfemale { 0 0 0 setrgbcolor 3 index "
773 << _nodeBorderQuotient/(1+_nodeBorderQuotient)
774 << " 1.5 mul mul setlinewidth\n"
775 << " newpath 5 index 5 index moveto "
776 << "5 index 5 index 5 index 3.01 mul sub\n"
777 << " lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto\n"
778 << " 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke\n"
779 << " 5 index 5 index 5 index c fill\n"
780 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
783 << " 0 0 0 setrgbcolor 3 index "
784 << _nodeBorderQuotient/(1+_nodeBorderQuotient)
785 <<" 1.5 mul mul setlinewidth\n"
786 << " newpath 5 index 5 index moveto\n"
787 << " 5 index 4 index 1 mul 1.5 mul add\n"
788 << " 5 index 5 index 3 sqrt 1.5 mul mul add\n"
789 << " 1 index 1 index lineto\n"
790 << " 1 index 1 index 7 index sub moveto\n"
791 << " 1 index 1 index lineto\n"
792 << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n"
794 << " 5 index 5 index 5 index c fill\n"
795 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
799 os << "/arrl " << _arrowLength << " def\n";
800 os << "/arrw " << _arrowWidth << " def\n";
802 os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
803 //len w dx_norm dy_norm x1 y1 cr cg cb
804 os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
805 << " /w exch def /len exch def\n"
806 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
807 << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
808 << " len w sub arrl sub dx dy lrl\n"
809 << " arrw dy dx neg lrl\n"
810 << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
811 << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
812 << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
813 << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
814 << " arrw dy dx neg lrl\n"
815 << " len w sub arrl sub neg dx dy lrl\n"
816 << " closepath fill } bind def\n";
817 os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
818 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
822 if(bb.height()>bb.width()) {
823 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
824 (A4WIDTH-2*A4BORDER)/bb.width());
825 os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
826 << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
827 << sc << " dup scale\n"
828 << -bb.left() << ' ' << -bb.bottom() << " translate\n";
831 //\todo Verify centering
832 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
833 (A4WIDTH-2*A4BORDER)/bb.height());
834 os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
835 << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER << " translate\n"
836 << sc << " dup scale\n90 rotate\n"
837 << -bb.left() << ' ' << -bb.top() << " translate\n";
839 else if(_scale!=1.0) os << _scale << " dup scale\n";
842 os << "%Edges:\ngsave\n";
843 if(_enableParallel) {
844 std::vector<Edge> el;
845 for(EdgeIt e(g);e!=INVALID;++e)
846 if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
847 &&g.source(e)!=g.target(e))
849 std::sort(el.begin(),el.end(),edgeLess(g));
851 typename std::vector<Edge>::iterator j;
852 for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
853 for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
856 for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
857 sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
860 xy<double> dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
861 double l=std::sqrt(dvec.normSquare());
862 ///\todo better 'epsilon' would be nice here.
863 xy<double> d(dvec/std::max(l,1e-9));
865 // m=xy<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
867 // m=xy<double>(mycoords[g.source(*i)])+
868 // dvec*(double(_nodeSizes[g.source(*i)])/
869 // (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
871 m=xy<double>(mycoords[g.source(*i)])+
872 d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
874 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
875 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
876 xy<double> mm=m+rot90(d)*sw/.75;
879 xy<double> s=mycoords[g.source(*e)];
880 xy<double> t=mycoords[g.target(*e)];
881 double rn=_nodeSizes[g.target(*e)]*_nodeScale;
882 node_shape=_nodeShapes[g.target(*e)];
883 Bezier3 bez(s,mm,mm,t);
885 for(int i=0;i<INTERPOL_PREC;++i)
886 if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
888 xy<double> apoint=bez((t1+t2)/2);
889 rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
892 for(int i=0;i<INTERPOL_PREC;++i)
893 if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
895 xy<double> linend=bez((t1+t2)/2);
896 bez=bez.before((t1+t2)/2);
897 // rn=_nodeSizes[g.source(*e)]*_nodeScale;
898 // node_shape=_nodeShapes[g.source(*e)];
900 // for(int i=0;i<INTERPOL_PREC;++i)
901 // if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
902 // else t2=(t1+t2)/2;
903 // bez=bez.after((t1+t2)/2);
904 os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
905 << _edgeColors[*e].red() << ' '
906 << _edgeColors[*e].green() << ' '
907 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
908 << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
909 << bez.p2.x << ' ' << bez.p2.y << ' '
910 << bez.p3.x << ' ' << bez.p3.y << ' '
911 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
912 xy<double> dd(rot90(linend-apoint));
913 dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
914 std::sqrt(dd.normSquare());
915 os << "newpath " << psOut(apoint) << " moveto "
916 << psOut(linend+dd) << " lineto "
917 << psOut(linend-dd) << " lineto closepath fill\n";
920 os << mycoords[g.source(*e)].x << ' '
921 << mycoords[g.source(*e)].y << ' '
922 << mm.x << ' ' << mm.y << ' '
923 << mycoords[g.target(*e)].x << ' '
924 << mycoords[g.target(*e)].y << ' '
925 << _edgeColors[*e].red() << ' '
926 << _edgeColors[*e].green() << ' '
927 << _edgeColors[*e].blue() << ' '
928 << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
930 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
934 else for(EdgeIt e(g);e!=INVALID;++e)
935 if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
936 &&g.source(e)!=g.target(e))
938 xy<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
939 double rn=_nodeSizes[g.target(e)]*_nodeScale;
940 int node_shape=_nodeShapes[g.target(e)];
942 for(int i=0;i<INTERPOL_PREC;++i)
943 if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
945 double l=std::sqrt(d.normSquare());
948 os << l*(1-(t1+t2)/2) << ' '
949 << _edgeWidths[e]*_edgeWidthScale << ' '
950 << d.x << ' ' << d.y << ' '
951 << mycoords[g.source(e)].x << ' '
952 << mycoords[g.source(e)].y << ' '
953 << _edgeColors[e].red() << ' '
954 << _edgeColors[e].green() << ' '
955 << _edgeColors[e].blue() << " arr\n";
957 else os << mycoords[g.source(e)].x << ' '
958 << mycoords[g.source(e)].y << ' '
959 << mycoords[g.target(e)].x << ' '
960 << mycoords[g.target(e)].y << ' '
961 << _edgeColors[e].red() << ' '
962 << _edgeColors[e].green() << ' '
963 << _edgeColors[e].blue() << ' '
964 << _edgeWidths[e]*_edgeWidthScale << " l\n";
968 os << "%Nodes:\ngsave\n";
969 for(NodeIt n(g);n!=INVALID;++n) {
970 os << mycoords[n].x << ' ' << mycoords[n].y << ' '
971 << _nodeSizes[n]*_nodeScale << ' '
972 << _nodeColors[n].red() << ' '
973 << _nodeColors[n].green() << ' '
974 << _nodeColors[n].blue() << ' ';
975 switch(_nodeShapes[n]) {
985 os<< "nfemale";break;
992 os << "%Node texts:\ngsave\n";
993 os << "/fosi " << _nodeTextSize << " def\n";
994 os << "(Helvetica) findfont fosi scalefont setfont\n";
995 for(NodeIt n(g);n!=INVALID;++n) {
996 switch(_nodeTextColorType) {
998 os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
1001 os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
1004 os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
1007 os << "0 0 0 setrgbcolor\n";
1009 os << mycoords[n].x << ' ' << mycoords[n].y
1010 << " (" << _nodeTexts[n] << ") cshow\n";
1014 if(_showNodePsText) {
1015 os << "%Node PS blocks:\ngsave\n";
1016 for(NodeIt n(g);n!=INVALID;++n)
1017 os << mycoords[n].x << ' ' << mycoords[n].y
1018 << " moveto\n" << _nodePsTexts[n] << "\n";
1022 os << "grestore\nshowpage\n";
1025 if(_pleaseRemoveOsStream) {delete &os;}
1030 const int GraphToEps<T>::INTERPOL_PREC = 20;
1032 const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
1034 const double GraphToEps<T>::A4WIDTH = 595.275590551181;
1036 const double GraphToEps<T>::A4BORDER = 15;
1039 ///Generates an EPS file from a graph
1041 ///\ingroup io_group
1042 ///Generates an EPS file from a graph.
1043 ///\param g is a reference to the graph to be printed
1044 ///\param os is a reference to the output stream.
1045 ///By default it is <tt>std::cout</tt>
1047 ///This function also has a lot of
1048 ///\ref named-templ-func-param "named parameters",
1049 ///they are declared as the members of class \ref GraphToEps. The following
1050 ///example shows how to use these parameters.
1052 /// graphToEps(g,os).scale(10).coords(coords)
1053 /// .nodeScale(2).nodeSizes(sizes)
1054 /// .edgeWidthScale(.4).run();
1056 ///\warning Don't forget to put the \ref GraphToEps::run() "run()"
1057 ///to the end of the parameter list.
1059 ///\sa graphToEps(G &g, const char *file_name)
1061 GraphToEps<DefaultGraphToEpsTraits<G> >
1062 graphToEps(G &g, std::ostream& os=std::cout)
1065 GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1068 ///Generates an EPS file from a graph
1070 ///\ingroup io_group
1071 ///This function does the same as
1072 ///\ref graphToEps(G &g,std::ostream& os)
1073 ///but it writes its output into the file \c file_name
1074 ///instead of a stream.
1075 ///\sa graphToEps(G &g, std::ostream& os)
1077 GraphToEps<DefaultGraphToEpsTraits<G> >
1078 graphToEps(G &g,const char *file_name)
1080 return GraphToEps<DefaultGraphToEpsTraits<G> >
1081 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
1084 ///Generates an EPS file from a graph
1086 ///\ingroup io_group
1087 ///This function does the same as
1088 ///\ref graphToEps(G &g,std::ostream& os)
1089 ///but it writes its output into the file \c file_name
1090 ///instead of a stream.
1091 ///\sa graphToEps(G &g, std::ostream& os)
1093 GraphToEps<DefaultGraphToEpsTraits<G> >
1094 graphToEps(G &g,const std::string& file_name)
1096 return GraphToEps<DefaultGraphToEpsTraits<G> >
1097 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true));
1100 } //END OF NAMESPACE LEMON
1102 #endif // LEMON_GRAPH_TO_EPS_H