NewMapWin has become Dialog instead of Window. Therefore it is created dynamically, when there is need for it, instead of keeping one instance in memory. This solution is slower, but more correct than before.
2 * lemon/graph_to_eps.h - Part of LEMON, a generic C++ optimization library
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5 * (Egervary Research Group on Combinatorial Optimization, EGRES).
7 * Permission to use, modify and distribute this software is granted
8 * provided that this copyright notice appears in all copies. For
9 * precise terms see the accompanying LICENSE file.
11 * This software is provided "AS IS" with no warranty of any kind,
12 * express or implied, and with no claim as to its suitability for any
17 #ifndef LEMON_GRAPH_TO_EPS_H
18 #define LEMON_GRAPH_TO_EPS_H
31 #include<lemon/invalid.h>
33 #include<lemon/maps.h>
34 #include<lemon/bezier.h>
39 ///\brief Simple graph drawer
41 ///\author Alpar Juttner
45 ///Data structure representing RGB colors.
47 ///Data structure representing RGB colors.
53 ///Default constructor
56 Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
57 ///Returns the red component
58 double & red() {return _r;}
59 ///Returns the red component
60 const double & red() const {return _r;}
61 ///Returns the green component
62 double & green() {return _g;}
63 ///Returns the green component
64 const double & green() const {return _g;}
65 ///Returns the blue component
66 double & blue() {return _b;}
67 ///Returns the blue component
68 const double & blue() const {return _b;}
69 ///Set the color components
70 void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
73 ///Maps <tt>int</tt>s to different \ref Color "Color"s
75 ///This map assigns one of the predefined \ref Color "Color"s
76 ///to each <tt>int</tt>. It is possible to change the colors as well as their
77 ///number. The integer range is cyclically mapped to the provided set of colors.
79 ///This is a true \ref concept::ReferenceMap "reference map", so you can also
80 ///change the actual colors.
82 class ColorSet : public MapBase<int,Color>
84 std::vector<Color> colors;
89 ///\param have_white indicates whether white is
90 ///amongst the provided color (\c true) or not (\c false). If it is true,
91 ///white will be assigned to \c 0.
92 ///\param num the number of the allocated colors. If it is \c 0
93 ///the default color configuration is set up (26 color plus the while).
94 ///If \c num is less then 26/27 then the default color list is cut. Otherwise
95 ///the color list is filled repeatedly with the default color list.
96 ///(The colors can be changed later on.)
97 ColorSet(bool have_white=false,int num=0)
100 if(have_white) colors.push_back(Color(1,1,1));
102 colors.push_back(Color(0,0,0));
103 colors.push_back(Color(1,0,0));
104 colors.push_back(Color(0,1,0));
105 colors.push_back(Color(0,0,1));
106 colors.push_back(Color(1,1,0));
107 colors.push_back(Color(1,0,1));
108 colors.push_back(Color(0,1,1));
110 colors.push_back(Color(.5,0,0));
111 colors.push_back(Color(0,.5,0));
112 colors.push_back(Color(0,0,.5));
113 colors.push_back(Color(.5,.5,0));
114 colors.push_back(Color(.5,0,.5));
115 colors.push_back(Color(0,.5,.5));
117 colors.push_back(Color(.5,.5,.5));
118 colors.push_back(Color(1,.5,.5));
119 colors.push_back(Color(.5,1,.5));
120 colors.push_back(Color(.5,.5,1));
121 colors.push_back(Color(1,1,.5));
122 colors.push_back(Color(1,.5,1));
123 colors.push_back(Color(.5,1,1));
125 colors.push_back(Color(1,.5,0));
126 colors.push_back(Color(.5,1,0));
127 colors.push_back(Color(1,0,.5));
128 colors.push_back(Color(0,1,.5));
129 colors.push_back(Color(0,.5,1));
130 colors.push_back(Color(.5,0,1));
131 } while(int(colors.size())<num);
132 // colors.push_back(Color(1,1,1));
133 if(num>0) colors.resize(num);
136 Color &operator[](int i)
138 return colors[i%colors.size()];
141 const Color &operator[](int i) const
143 return colors[i%colors.size()];
146 void set(int i,const Color &c)
148 colors[i%colors.size()]=c;
150 ///Sets the number of the exiting colors.
151 void resize(int s) { colors.resize(s);}
152 ///Returns the number of the existing colors.
153 std::size_t size() const { return colors.size();}
156 ///Returns a visible distinct \ref Color
158 ///Returns a \ref Color which is as different from the given parameter
159 ///as it is possible.
160 inline Color distantColor(const Color &c)
162 return Color(c.red()<.5?1:0,c.green()<.5?1:0,c.blue()<.5?1:0);
164 ///Returns black for light colors and white for the dark ones.
166 ///Returns black for light colors and white for the dark ones.
167 inline Color distantBW(const Color &c){
168 double v=(.2125*c.red()+.7154*c.green()+.0721*c.blue())<.5?1:0;
175 typedef typename MT::Key Key;
176 typedef typename MT::Value Value;
179 _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
180 Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
183 ///Default traits class of \ref GraphToEps
185 ///Default traits class of \ref GraphToEps
187 ///\c G is the type of the underlying graph.
189 struct DefaultGraphToEpsTraits
192 typedef typename Graph::Node Node;
193 typedef typename Graph::NodeIt NodeIt;
194 typedef typename Graph::Edge Edge;
195 typedef typename Graph::EdgeIt EdgeIt;
196 typedef typename Graph::InEdgeIt InEdgeIt;
197 typedef typename Graph::OutEdgeIt OutEdgeIt;
204 typedef ConstMap<typename Graph::Node,xy<double> > CoordsMapType;
205 CoordsMapType _coords;
206 ConstMap<typename Graph::Node,double > _nodeSizes;
207 ConstMap<typename Graph::Node,int > _nodeShapes;
209 ConstMap<typename Graph::Node,Color > _nodeColors;
210 ConstMap<typename Graph::Edge,Color > _edgeColors;
212 ConstMap<typename Graph::Edge,double > _edgeWidths;
214 double _edgeWidthScale;
217 double _xBorder, _yBorder;
219 double _nodeBorderQuotient;
222 double _arrowLength, _arrowWidth;
224 bool _showNodes, _showEdges;
226 bool _enableParallel;
230 ConstMap<typename Graph::Node,bool > _nodeTexts;
231 double _nodeTextSize;
233 bool _showNodePsText;
234 ConstMap<typename Graph::Node,bool > _nodePsTexts;
235 char *_nodePsTextsPreamble;
238 bool _pleaseRemoveOsStream;
243 std::string _copyright;
245 enum NodeTextColorType
246 { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
247 ConstMap<typename Graph::Node,Color > _nodeTextColors;
250 bool _autoEdgeWidthScale;
256 ///\param _g is a reference to the graph to be printed
257 ///\param _os is a reference to the output stream.
258 ///\param _os is a reference to the output stream.
259 ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
260 ///will be explicitly deallocated by the destructor.
261 ///By default it is <tt>std::cout</tt>
262 DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
265 _coords(xy<double>(1,1)), _nodeSizes(1.0), _nodeShapes(0),
266 _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
267 _edgeWidths(1), _edgeWidthScale(0.3),
268 _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
269 _nodeBorderQuotient(.1),
270 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
271 _showNodes(true), _showEdges(true),
272 _enableParallel(false), _parEdgeDist(1),
273 _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
274 _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
276 _pleaseRemoveOsStream(_pros), _scaleToA4(false),
277 _nodeTextColorType(SAME_COL), _nodeTextColors(Color(0,0,0)),
278 _autoNodeScale(false),
279 _autoEdgeWidthScale(false),
284 ///Helper class to implement the named parameters of \ref graphToEps()
286 ///Helper class to implement the named parameters of \ref graphToEps()
287 ///\todo Is 'helper class' a good name for this?
289 ///\todo Follow PostScript's DSC.
290 /// Use own dictionary.
291 ///\todo Useful new features.
292 /// - Linestyles: dotted, dashed etc.
293 /// - A second color and percent value for the lines.
294 template<class T> class GraphToEps : public T
296 // Can't believe it is required by the C++ standard
302 using T::_nodeShapes;
303 using T::_nodeColors;
304 using T::_edgeColors;
305 using T::_edgeWidths;
307 using T::_edgeWidthScale;
312 using T::_nodeBorderQuotient;
314 using T::_drawArrows;
315 using T::_arrowLength;
316 using T::_arrowWidth;
321 using T::_enableParallel;
322 using T::_parEdgeDist;
324 using T::_showNodeText;
326 using T::_nodeTextSize;
328 using T::_showNodePsText;
329 using T::_nodePsTexts;
330 using T::_nodePsTextsPreamble;
333 using T::_pleaseRemoveOsStream;
340 using T::NodeTextColorType;
344 using T::_nodeTextColorType;
345 using T::_nodeTextColors;
347 using T::_autoNodeScale;
348 using T::_autoEdgeWidthScale;
352 // dradnats ++C eht yb deriuqer si ti eveileb t'naC
354 typedef typename T::Graph Graph;
355 typedef typename Graph::Node Node;
356 typedef typename Graph::NodeIt NodeIt;
357 typedef typename Graph::Edge Edge;
358 typedef typename Graph::EdgeIt EdgeIt;
359 typedef typename Graph::InEdgeIt InEdgeIt;
360 typedef typename Graph::OutEdgeIt OutEdgeIt;
362 static const int INTERPOL_PREC;
363 static const double A4HEIGHT;
364 static const double A4WIDTH;
365 static const double A4BORDER;
376 ///\image html nodeshape_0.png
377 ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
380 ///\image html nodeshape_1.png
381 ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
385 ///\image html nodeshape_2.png
386 ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
395 edgeLess(const Graph &_g) : g(_g) {}
396 bool operator()(Edge a,Edge b) const
398 Node ai=std::min(g.source(a),g.target(a));
399 Node aa=std::max(g.source(a),g.target(a));
400 Node bi=std::min(g.source(b),g.target(b));
401 Node ba=std::max(g.source(b),g.target(b));
403 (ai==bi && (aa < ba ||
404 (aa==ba && ai==g.source(a) && bi==g.target(b))));
407 bool isParallel(Edge e,Edge f) const
409 return (g.source(e)==g.source(f)&&
410 g.target(e)==g.target(f)) ||
411 (g.source(e)==g.target(f)&&
412 g.target(e)==g.source(f));
415 static std::string psOut(const xy<TT> &p)
417 std::ostringstream os;
418 os << p.x << ' ' << p.y;
421 static std::string psOut(const Color &c)
423 std::ostringstream os;
424 os << c.red() << ' ' << c.green() << ' ' << c.blue();
429 GraphToEps(const T &t) : T(t), dontPrint(false) {};
431 template<class X> struct CoordsTraits : public T {
432 typedef X CoordsMapType;
434 CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
436 ///Sets the map of the node coordinates
438 ///Sets the map of the node coordinates.
439 ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values.
440 template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
442 return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
444 template<class X> struct NodeSizesTraits : public T {
446 NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
448 ///Sets the map of the node sizes
450 ///Sets the map of the node sizes
451 ///\param x must be a node map with \c double (or convertible) values.
452 template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
455 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
457 template<class X> struct NodeShapesTraits : public T {
458 const X &_nodeShapes;
459 NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
461 ///Sets the map of the node shapes
463 ///Sets the map of the node shapes.
464 ///The availabe shape values
465 ///can be found in \ref NodeShapes "enum NodeShapes".
466 ///\param x must be a node map with \c int (or convertible) values.
468 template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
471 return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
473 template<class X> struct NodeTextsTraits : public T {
475 NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
477 ///Sets the text printed on the nodes
479 ///Sets the text printed on the nodes
480 ///\param x must be a node map with type that can be pushed to a standard
482 template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
486 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
488 template<class X> struct NodePsTextsTraits : public T {
489 const X &_nodePsTexts;
490 NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
492 ///Inserts a PostScript block to the nodes
494 ///With this command it is possible to insert a verbatim PostScript
495 ///block to the nodes.
496 ///The PS current point will be moved to the centre of the node before
497 ///the PostScript block inserted.
499 ///Before and after the block a newline character is inserted so you
500 ///don't have to bother with the separators.
502 ///\param x must be a node map with type that can be pushed to a standard
505 ///\sa nodePsTextsPreamble()
506 ///\todo Offer the choise not to move to the centre but pass the coordinates
507 ///to the Postscript block inserted.
508 template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
511 _showNodePsText=true;
512 return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
514 template<class X> struct EdgeWidthsTraits : public T {
515 const X &_edgeWidths;
516 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
518 ///Sets the map of the edge widths
520 ///Sets the map of the edge widths
521 ///\param x must be a edge map with \c double (or convertible) values.
522 template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
525 return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
528 template<class X> struct NodeColorsTraits : public T {
529 const X &_nodeColors;
530 NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
532 ///Sets the map of the node colors
534 ///Sets the map of the node colors
535 ///\param x must be a node map with \ref Color values.
538 template<class X> GraphToEps<NodeColorsTraits<X> >
539 nodeColors(const X &x)
542 return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
544 template<class X> struct NodeTextColorsTraits : public T {
545 const X &_nodeTextColors;
546 NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
548 ///Sets the map of the node text colors
550 ///Sets the map of the node text colors
551 ///\param x must be a node map with \ref Color values.
554 template<class X> GraphToEps<NodeTextColorsTraits<X> >
555 nodeTextColors(const X &x)
558 _nodeTextColorType=CUST_COL;
559 return GraphToEps<NodeTextColorsTraits<X> >
560 (NodeTextColorsTraits<X>(*this,x));
562 template<class X> struct EdgeColorsTraits : public T {
563 const X &_edgeColors;
564 EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
566 ///Sets the map of the edge colors
568 ///Sets the map of the edge colors
569 ///\param x must be a edge map with \ref Color values.
572 template<class X> GraphToEps<EdgeColorsTraits<X> >
573 edgeColors(const X &x)
576 return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
578 ///Sets a global scale factor for node sizes
580 ///Sets a global scale factor for node sizes.
582 /// If nodeSizes() is not given, this function simply sets the node
583 /// sizes to \c d. If nodeSizes() is given, but
584 /// autoNodeScale() is not, then the node size given by
585 /// nodeSizes() will be multiplied by the value \c d.
586 /// If both nodeSizes() and autoNodeScale() are used, then the
587 /// node sizes will be scaled in such a way that the greatest size will be
589 GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
590 ///Turns on/off the automatic node width scaling.
592 ///Turns on/off the automatic node width scaling.
596 GraphToEps<T> &autoNodeScale(bool b=true) {
597 _autoNodeScale=b;return *this;
600 ///Negates the Y coordinates.
602 ///Negates the Y coordinates.
606 GraphToEps<T> &negateY(bool b=true) {
607 _negY=b;return *this;
610 ///Sets a global scale factor for edge widths
612 /// Sets a global scale factor for edge widths.
614 /// If edgeWidths() is not given, this function simply sets the edge
615 /// widths to \c d. If edgeWidths() is given, but
616 /// autoEdgeWidthScale() is not, then the edge withs given by
617 /// edgeWidths() will be multiplied by the value \c d.
618 /// If both edgeWidths() and autoEdgeWidthScale() are used, then the
619 /// edge withs will be scaled in such a way that the greatest width will be
621 GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
622 ///Turns on/off the automatic edge width scaling.
624 ///Turns on/off the automatic edge width scaling.
626 ///\sa edgeWidthScale()
628 GraphToEps<T> &autoEdgeWidthScale(bool b=true) {
629 _autoEdgeWidthScale=b;return *this;
631 ///Sets a global scale factor for the whole picture
633 ///Sets a global scale factor for the whole picture
636 GraphToEps<T> &scale(double d) {_scale=d;return *this;}
637 ///Sets the width of the border around the picture
639 ///Sets the width of the border around the picture
641 GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
642 ///Sets the width of the border around the picture
644 ///Sets the width of the border around the picture
646 GraphToEps<T> &border(double x, double y) {
647 _xBorder=x;_yBorder=y;return *this;
649 ///Sets whether to draw arrows
651 ///Sets whether to draw arrows
653 GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
654 ///Sets the length of the arrowheads
656 ///Sets the length of the arrowheads
658 GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
659 ///Sets the width of the arrowheads
661 ///Sets the width of the arrowheads
663 GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
665 ///Scales the drawing to fit to A4 page
667 ///Scales the drawing to fit to A4 page
669 GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
671 ///Enables parallel edges
673 ///Enables parallel edges
674 GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
680 GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
686 GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
691 GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
693 ///Sets the size of the node texts
695 ///Sets the size of the node texts
697 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
699 ///Sets the color of the node texts to be different from the node color
701 ///Sets the color of the node texts to be as different from the node color
704 GraphToEps<T> &distantColorNodeTexts()
705 {_nodeTextColorType=DIST_COL;return *this;}
706 ///Sets the color of the node texts to be black or white and always visible.
708 ///Sets the color of the node texts to be black or white according to
710 ///different from the node color
712 GraphToEps<T> &distantBWNodeTexts()
713 {_nodeTextColorType=DIST_BW;return *this;}
715 ///Gives a preamble block for node Postscript block.
717 ///Gives a preamble block for node Postscript block.
720 GraphToEps<T> & nodePsTextsPreamble(const char *str) {
721 _nodePsTextsPreamble=str ;return *this;
723 ///Sets whether the the graph is undirected
725 ///Sets whether the the graph is undirected
727 GraphToEps<T> &undir(bool b=true) {_undir=b;return *this;}
728 ///Sets whether the the graph is directed
730 ///Sets whether the the graph is directed.
731 ///Use it to show the undirected edges as a pair of directed ones.
732 GraphToEps<T> &bidir(bool b=true) {_undir=!b;return *this;}
736 ///Sets the title of the generated image,
737 ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
739 GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
740 ///Sets the copyright statement.
742 ///Sets the copyright statement of the generated image,
743 ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
745 ///\todo Multiline copyright notice could be supported.
746 GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;}
749 bool isInsideNode(xy<double> p, double r,int t)
753 return p.normSquare()<=r*r;
755 return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
757 return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
767 ///Like other functions using
768 ///\ref named-templ-func-param "named template parameters",
769 ///this function calles the algorithm itself, i.e. in this case
770 ///it draws the graph.
772 if(dontPrint) return;
774 _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
776 os << "%!PS-Adobe-2.0 EPSF-2.0\n";
777 if(_title.size()>0) os << "%%Title: " << _title << '\n';
778 if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
779 // << "%%Copyright: XXXX\n"
780 os << "%%Creator: LEMON, graphToEps()\n";
785 gettimeofday(&tv, 0);
786 ctime_r(&tv.tv_sec,cbuf);
787 os << "%%CreationDate: " << cbuf;
790 if (_autoEdgeWidthScale) {
792 for(EdgeIt e(g);e!=INVALID;++e)
793 max_w=std::max(double(_edgeWidths[e]),max_w);
794 ///\todo better 'epsilon' would be nice here.
796 _edgeWidthScale/=max_w;
800 if (_autoNodeScale) {
802 for(NodeIt n(g);n!=INVALID;++n)
803 max_s=std::max(double(_nodeSizes[n]),max_s);
804 ///\todo better 'epsilon' would be nice here.
811 BoundingBox<double> bb;
812 ///\bug: Chech whether the graph is empty.
813 for(NodeIt n(g);n!=INVALID;++n) {
814 double ns=_nodeSizes[n]*_nodeScale;
816 bb.add(p+mycoords[n]);
817 bb.add(-p+mycoords[n]);
820 bb = BoundingBox<double>(xy<double>(0,0));
824 os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
825 else os << "%%BoundingBox: "
826 << bb.left() * _scale - _xBorder << ' '
827 << bb.bottom() * _scale - _yBorder << ' '
828 << bb.right() * _scale + _xBorder << ' '
829 << bb.top() * _scale + _yBorder << '\n';
831 os << "%%EndComments\n";
833 //x1 y1 x2 y2 x3 y3 cr cg cb w
834 os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
835 << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
836 os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
838 os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
840 os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
841 << " 2 index 1 index sub 2 index 2 index add lineto\n"
842 << " 2 index 1 index sub 2 index 2 index sub lineto\n"
843 << " 2 index 1 index add 2 index 2 index sub lineto\n"
844 << " closepath pop pop pop} bind def\n";
846 os << "/di { newpath 2 index 1 index add 2 index moveto\n"
847 << " 2 index 2 index 2 index add lineto\n"
848 << " 2 index 1 index sub 2 index lineto\n"
849 << " 2 index 2 index 2 index sub lineto\n"
850 << " closepath pop pop pop} bind def\n";
852 os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
853 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
855 os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
856 << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
858 os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
859 << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
861 os << "/arrl " << _arrowLength << " def\n";
862 os << "/arrw " << _arrowWidth << " def\n";
864 os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
865 //len w dx_norm dy_norm x1 y1 cr cg cb
866 os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
867 << " /w exch def /len exch def\n"
868 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
869 << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
870 << " len w sub arrl sub dx dy lrl\n"
871 << " arrw dy dx neg lrl\n"
872 << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
873 << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
874 << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
875 << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
876 << " arrw dy dx neg lrl\n"
877 << " len w sub arrl sub neg dx dy lrl\n"
878 << " closepath fill } bind def\n";
879 os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
880 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
884 if(bb.height()>bb.width()) {
885 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
886 (A4WIDTH-2*A4BORDER)/bb.width());
887 os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
888 << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
889 << sc << " dup scale\n"
890 << -bb.left() << ' ' << -bb.bottom() << " translate\n";
893 //\todo Verify centering
894 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
895 (A4WIDTH-2*A4BORDER)/bb.height());
896 os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
897 << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER << " translate\n"
898 << sc << " dup scale\n90 rotate\n"
899 << -bb.left() << ' ' << -bb.top() << " translate\n";
901 else if(_scale!=1.0) os << _scale << " dup scale\n";
904 os << "%Edges:\ngsave\n";
905 if(_enableParallel) {
906 std::vector<Edge> el;
907 for(EdgeIt e(g);e!=INVALID;++e)
908 if((!_undir||g.source(e)<g.target(e))&&_edgeWidths[e]>0)
910 std::sort(el.begin(),el.end(),edgeLess(g));
912 typename std::vector<Edge>::iterator j;
913 for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
914 for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
917 for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
918 sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
921 xy<double> dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
922 double l=std::sqrt(dvec.normSquare());
923 ///\todo better 'epsilon' would be nice here.
924 xy<double> d(dvec/std::max(l,1e-9));
926 // m=xy<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
928 // m=xy<double>(mycoords[g.source(*i)])+
929 // dvec*(double(_nodeSizes[g.source(*i)])/
930 // (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
932 m=xy<double>(mycoords[g.source(*i)])+
933 d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
935 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
936 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
937 xy<double> mm=m+rot90(d)*sw/.75;
940 xy<double> s=mycoords[g.source(*e)];
941 xy<double> t=mycoords[g.target(*e)];
942 double rn=_nodeSizes[g.target(*e)]*_nodeScale;
943 node_shape=_nodeShapes[g.target(*e)];
944 Bezier3 bez(s,mm,mm,t);
946 for(int i=0;i<INTERPOL_PREC;++i)
947 if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
949 xy<double> apoint=bez((t1+t2)/2);
950 rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
953 for(int i=0;i<INTERPOL_PREC;++i)
954 if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
956 xy<double> linend=bez((t1+t2)/2);
957 bez=bez.before((t1+t2)/2);
958 // rn=_nodeSizes[g.source(*e)]*_nodeScale;
959 // node_shape=_nodeShapes[g.source(*e)];
961 // for(int i=0;i<INTERPOL_PREC;++i)
962 // if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
963 // else t2=(t1+t2)/2;
964 // bez=bez.after((t1+t2)/2);
965 os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
966 << _edgeColors[*e].red() << ' '
967 << _edgeColors[*e].green() << ' '
968 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
969 << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
970 << bez.p2.x << ' ' << bez.p2.y << ' '
971 << bez.p3.x << ' ' << bez.p3.y << ' '
972 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
973 xy<double> dd(rot90(linend-apoint));
974 dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
975 std::sqrt(dd.normSquare());
976 os << "newpath " << psOut(apoint) << " moveto "
977 << psOut(linend+dd) << " lineto "
978 << psOut(linend-dd) << " lineto closepath fill\n";
981 os << mycoords[g.source(*e)].x << ' '
982 << mycoords[g.source(*e)].y << ' '
983 << mm.x << ' ' << mm.y << ' '
984 << mycoords[g.target(*e)].x << ' '
985 << mycoords[g.target(*e)].y << ' '
986 << _edgeColors[*e].red() << ' '
987 << _edgeColors[*e].green() << ' '
988 << _edgeColors[*e].blue() << ' '
989 << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
991 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
995 else for(EdgeIt e(g);e!=INVALID;++e)
996 if((!_undir||g.source(e)<g.target(e))&&_edgeWidths[e]>0)
998 xy<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
999 double rn=_nodeSizes[g.target(e)]*_nodeScale;
1000 int node_shape=_nodeShapes[g.target(e)];
1002 for(int i=0;i<INTERPOL_PREC;++i)
1003 if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
1005 double l=sqrt(d.normSquare());
1008 os << l*(1-(t1+t2)/2) << ' '
1009 << _edgeWidths[e]*_edgeWidthScale << ' '
1010 << d.x << ' ' << d.y << ' '
1011 << mycoords[g.source(e)].x << ' '
1012 << mycoords[g.source(e)].y << ' '
1013 << _edgeColors[e].red() << ' '
1014 << _edgeColors[e].green() << ' '
1015 << _edgeColors[e].blue() << " arr\n";
1017 else os << mycoords[g.source(e)].x << ' '
1018 << mycoords[g.source(e)].y << ' '
1019 << mycoords[g.target(e)].x << ' '
1020 << mycoords[g.target(e)].y << ' '
1021 << _edgeColors[e].red() << ' '
1022 << _edgeColors[e].green() << ' '
1023 << _edgeColors[e].blue() << ' '
1024 << _edgeWidths[e]*_edgeWidthScale << " l\n";
1028 os << "%Nodes:\ngsave\n";
1029 for(NodeIt n(g);n!=INVALID;++n) {
1030 os << mycoords[n].x << ' ' << mycoords[n].y << ' '
1031 << _nodeSizes[n]*_nodeScale << ' '
1032 << _nodeColors[n].red() << ' '
1033 << _nodeColors[n].green() << ' '
1034 << _nodeColors[n].blue() << ' ';
1035 switch(_nodeShapes[n]) {
1048 os << "%Node texts:\ngsave\n";
1049 os << "/fosi " << _nodeTextSize << " def\n";
1050 os << "(Helvetica) findfont fosi scalefont setfont\n";
1051 for(NodeIt n(g);n!=INVALID;++n) {
1052 switch(_nodeTextColorType) {
1054 os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
1057 os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
1060 os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
1063 os << "0 0 0 setrgbcolor\n";
1065 os << mycoords[n].x << ' ' << mycoords[n].y
1066 << " (" << _nodeTexts[n] << ") cshow\n";
1070 if(_showNodePsText) {
1071 os << "%Node PS blocks:\ngsave\n";
1072 for(NodeIt n(g);n!=INVALID;++n)
1073 os << mycoords[n].x << ' ' << mycoords[n].y
1074 << " moveto\n" << _nodePsTexts[n] << "\n";
1078 os << "grestore\nshowpage\n";
1081 if(_pleaseRemoveOsStream) {delete &os;}
1086 const int GraphToEps<T>::INTERPOL_PREC = 20;
1088 const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
1090 const double GraphToEps<T>::A4WIDTH = 595.275590551181;
1092 const double GraphToEps<T>::A4BORDER = 15;
1095 ///Generates an EPS file from a graph
1097 ///\ingroup io_group
1098 ///Generates an EPS file from a graph.
1099 ///\param g is a reference to the graph to be printed
1100 ///\param os is a reference to the output stream.
1101 ///By default it is <tt>std::cout</tt>
1103 ///This function also has a lot of
1104 ///\ref named-templ-func-param "named parameters",
1105 ///they are declared as the members of class \ref GraphToEps. The following
1106 ///example shows how to use these parameters.
1108 /// graphToEps(g,os).scale(10).coords(coords)
1109 /// .nodeScale(2).nodeSizes(sizes)
1110 /// .edgeWidthScale(.4).run();
1112 ///\warning Don't forget to put the \ref GraphToEps::run() "run()"
1113 ///to the end of the parameter list.
1115 ///\sa graphToEps(G &g, const char *file_name)
1117 GraphToEps<DefaultGraphToEpsTraits<G> >
1118 graphToEps(G &g, std::ostream& os=std::cout)
1121 GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1124 ///Generates an EPS file from a graph
1126 ///\ingroup io_group
1127 ///This function does the same as
1128 ///\ref graphToEps(G &g,std::ostream& os)
1129 ///but it writes its output into the file \c file_name
1130 ///instead of a stream.
1131 ///\sa graphToEps(G &g, std::ostream& os)
1133 GraphToEps<DefaultGraphToEpsTraits<G> >
1134 graphToEps(G &g,const char *file_name)
1136 return GraphToEps<DefaultGraphToEpsTraits<G> >
1137 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
1140 ///Generates an EPS file from a graph
1142 ///\ingroup io_group
1143 ///This function does the same as
1144 ///\ref graphToEps(G &g,std::ostream& os)
1145 ///but it writes its output into the file \c file_name
1146 ///instead of a stream.
1147 ///\sa graphToEps(G &g, std::ostream& os)
1149 GraphToEps<DefaultGraphToEpsTraits<G> >
1150 graphToEps(G &g,const std::string& file_name)
1152 return GraphToEps<DefaultGraphToEpsTraits<G> >
1153 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true));
1156 } //END OF NAMESPACE LEMON
1158 #endif // LEMON_GRAPH_TO_EPS_H