1.1 --- a/src/lemon/graph_to_eps.h Sat May 21 21:04:57 2005 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1026 +0,0 @@
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) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.8 - * (Egervary Research Group on Combinatorial Optimization, 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 -#ifndef LEMON_GRAPH_TO_EPS_H
1.21 -#define LEMON_GRAPH_TO_EPS_H
1.22 -
1.23 -#include <sys/time.h>
1.24 -
1.25 -#include<iostream>
1.26 -#include<fstream>
1.27 -#include<sstream>
1.28 -#include<algorithm>
1.29 -#include<vector>
1.30 -
1.31 -#include <ctime>
1.32 -#include <cmath>
1.33 -
1.34 -#include<lemon/invalid.h>
1.35 -#include<lemon/xy.h>
1.36 -#include<lemon/maps.h>
1.37 -#include<lemon/bezier.h>
1.38 -
1.39 -
1.40 -///\ingroup io_group
1.41 -///\file
1.42 -///\brief Simple graph drawer
1.43 -///
1.44 -///\author Alpar Juttner
1.45 -
1.46 -namespace lemon {
1.47 -
1.48 -///Data structure representing RGB colors.
1.49 -
1.50 -///Data structure representing RGB colors.
1.51 -///\ingroup misc
1.52 -class Color
1.53 -{
1.54 - double _r,_g,_b;
1.55 -public:
1.56 - ///Default constructor
1.57 - Color() {}
1.58 - ///Constructor
1.59 - Color(double r,double g,double b) :_r(r),_g(g),_b(b) {};
1.60 - ///Returns the red component
1.61 -
1.62 - ///\todo \c red() could be a better name...
1.63 - double getR() const {return _r;}
1.64 - ///Returns the green component
1.65 - double getG() const {return _g;}
1.66 - ///Returns the blue component
1.67 - double getB() const {return _b;}
1.68 - ///Set the color components
1.69 - void set(double r,double g,double b) { _r=r;_g=g;_b=b; };
1.70 -};
1.71 -
1.72 -///Maps <tt>int</tt>s to different \ref Color "Color"s
1.73 -
1.74 -///This map assing one of the predefined \ref Color "Color"s
1.75 -///to each <tt>int</tt>. It is possible to change the colors as well as their
1.76 -///number. The integer range is cyclically mapped to the provided set of colors.
1.77 -///
1.78 -///This is a true \ref concept::ReferenceMap "reference map", so you can also
1.79 -///change the actual colors.
1.80 -
1.81 -class ColorSet : public MapBase<int,Color>
1.82 -{
1.83 - std::vector<Color> colors;
1.84 -public:
1.85 - ///Constructor
1.86 -
1.87 - ///Constructor
1.88 - ///\param have_white indicates wheter white is
1.89 - ///amongst the provided color (\c true) or not (\c false). If it is true,
1.90 - ///white will be assigned to \c 0.
1.91 - ///\param num the number of the allocated colors. If it is \c 0
1.92 - ///the default color configuration is set up (26 color plus the while).
1.93 - ///If \c num is less then 26/27 then the default color list is cut. Otherwise
1.94 - ///the color list is filled repeatedly with the default color list.
1.95 - ColorSet(bool have_white=false,int num=0)
1.96 - {
1.97 - do {
1.98 - if(have_white) colors.push_back(Color(1,1,1));
1.99 -
1.100 - colors.push_back(Color(0,0,0));
1.101 - colors.push_back(Color(1,0,0));
1.102 - colors.push_back(Color(0,1,0));
1.103 - colors.push_back(Color(0,0,1));
1.104 - colors.push_back(Color(1,1,0));
1.105 - colors.push_back(Color(1,0,1));
1.106 - colors.push_back(Color(0,1,1));
1.107 -
1.108 - colors.push_back(Color(.5,0,0));
1.109 - colors.push_back(Color(0,.5,0));
1.110 - colors.push_back(Color(0,0,.5));
1.111 - colors.push_back(Color(.5,.5,0));
1.112 - colors.push_back(Color(.5,0,.5));
1.113 - colors.push_back(Color(0,.5,.5));
1.114 -
1.115 - colors.push_back(Color(.5,.5,.5));
1.116 - colors.push_back(Color(1,.5,.5));
1.117 - colors.push_back(Color(.5,1,.5));
1.118 - colors.push_back(Color(.5,.5,1));
1.119 - colors.push_back(Color(1,1,.5));
1.120 - colors.push_back(Color(1,.5,1));
1.121 - colors.push_back(Color(.5,1,1));
1.122 -
1.123 - colors.push_back(Color(1,.5,0));
1.124 - colors.push_back(Color(.5,1,0));
1.125 - colors.push_back(Color(1,0,.5));
1.126 - colors.push_back(Color(0,1,.5));
1.127 - colors.push_back(Color(0,.5,1));
1.128 - colors.push_back(Color(.5,0,1));
1.129 - } while(int(colors.size())<num);
1.130 - // colors.push_back(Color(1,1,1));
1.131 - if(num>0) colors.resize(num);
1.132 - }
1.133 - ///\e
1.134 - Color &operator[](int i)
1.135 - {
1.136 - return colors[i%colors.size()];
1.137 - }
1.138 - ///\e
1.139 - const Color &operator[](int i) const
1.140 - {
1.141 - return colors[i%colors.size()];
1.142 - }
1.143 - ///\e
1.144 - void set(int i,const Color &c)
1.145 - {
1.146 - colors[i%colors.size()]=c;
1.147 - }
1.148 - ///Sets the number of the exiting colors.
1.149 - void resize(int s) { colors.resize(s);}
1.150 - ///Returns the munber of the existing colors.
1.151 - std::size_t size() { return colors.size();}
1.152 -};
1.153 -
1.154 -///Returns a visible distinct \ref Color
1.155 -
1.156 -///Returns a \ref Color which is as different from the given parameter
1.157 -///as it is possible.
1.158 -inline Color distantColor(const Color &c)
1.159 -{
1.160 - return Color(c.getR()<.5?1:0,c.getG()<.5?1:0,c.getB()<.5?1:0);
1.161 -}
1.162 -///Returns black for light colors and white for the dark ones.
1.163 -
1.164 -///Returns black for light colors and white for the dark ones.
1.165 -///\todo weighted average would be better
1.166 -inline Color distantBW(const Color &c){
1.167 - double v=(.2125*c.getR()+.7154*c.getG()+.0721*c.getB())<.5?1:0;
1.168 - return Color(v,v,v);
1.169 -}
1.170 -
1.171 -///Default traits class of \ref GraphToEps
1.172 -
1.173 -///Default traits class of \ref GraphToEps
1.174 -///
1.175 -///\c G is the type of the underlying graph.
1.176 -template<class G>
1.177 -struct DefaultGraphToEpsTraits
1.178 -{
1.179 - typedef G Graph;
1.180 - typedef typename Graph::Node Node;
1.181 - typedef typename Graph::NodeIt NodeIt;
1.182 - typedef typename Graph::Edge Edge;
1.183 - typedef typename Graph::EdgeIt EdgeIt;
1.184 - typedef typename Graph::InEdgeIt InEdgeIt;
1.185 - typedef typename Graph::OutEdgeIt OutEdgeIt;
1.186 -
1.187 -
1.188 - const Graph &g;
1.189 -
1.190 - std::ostream& os;
1.191 -
1.192 - ConstMap<typename Graph::Node,xy<double> > _coords;
1.193 - ConstMap<typename Graph::Node,double > _nodeSizes;
1.194 - ConstMap<typename Graph::Node,int > _nodeShapes;
1.195 -
1.196 - ConstMap<typename Graph::Node,Color > _nodeColors;
1.197 - ConstMap<typename Graph::Edge,Color > _edgeColors;
1.198 -
1.199 - ConstMap<typename Graph::Edge,double > _edgeWidths;
1.200 -
1.201 - double _edgeWidthScale;
1.202 -
1.203 - double _nodeScale;
1.204 - double _xBorder, _yBorder;
1.205 - double _scale;
1.206 - double _nodeBorderQuotient;
1.207 -
1.208 - bool _drawArrows;
1.209 - double _arrowLength, _arrowWidth;
1.210 -
1.211 - bool _showNodes, _showEdges;
1.212 -
1.213 - bool _enableParallel;
1.214 - double _parEdgeDist;
1.215 -
1.216 - bool _showNodeText;
1.217 - ConstMap<typename Graph::Node,bool > _nodeTexts;
1.218 - double _nodeTextSize;
1.219 -
1.220 - bool _showNodePsText;
1.221 - ConstMap<typename Graph::Node,bool > _nodePsTexts;
1.222 - char *_nodePsTextsPreamble;
1.223 -
1.224 - bool _undir;
1.225 - bool _pleaseRemoveOsStream;
1.226 -
1.227 - bool _scaleToA4;
1.228 -
1.229 - std::string _title;
1.230 - std::string _copyright;
1.231 -
1.232 - enum NodeTextColorType
1.233 - { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
1.234 - ConstMap<typename Graph::Node,Color > _nodeTextColors;
1.235 -
1.236 - ///Constructor
1.237 -
1.238 - ///Constructor
1.239 - ///\param _g is a reference to the graph to be printed
1.240 - ///\param _os is a reference to the output stream.
1.241 - ///\param _os is a reference to the output stream.
1.242 - ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
1.243 - ///will be explicitly deallocated by the destructor.
1.244 - ///By default it is <tt>std::cout</tt>
1.245 - DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
1.246 - bool _pros=false) :
1.247 - g(_g), os(_os),
1.248 - _coords(xy<double>(1,1)), _nodeSizes(1.0), _nodeShapes(0),
1.249 - _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
1.250 - _edgeWidths(1), _edgeWidthScale(0.3),
1.251 - _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
1.252 - _nodeBorderQuotient(.1),
1.253 - _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
1.254 - _showNodes(true), _showEdges(true),
1.255 - _enableParallel(false), _parEdgeDist(1),
1.256 - _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
1.257 - _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
1.258 - _undir(false),
1.259 - _pleaseRemoveOsStream(_pros), _scaleToA4(false),
1.260 - _nodeTextColorType(SAME_COL), _nodeTextColors(Color(0,0,0))
1.261 - {}
1.262 -};
1.263 -
1.264 -///Helper class to implement the named parameters of \ref graphToEps()
1.265 -
1.266 -///Helper class to implement the named parameters of \ref graphToEps()
1.267 -///\todo Is 'helper class' a good name for this?
1.268 -///
1.269 -///\todo Follow PostScript's DSC.
1.270 -/// Use own dictionary.
1.271 -///\todo Useful new features.
1.272 -/// - Linestyles: dotted, dashed etc.
1.273 -/// - A second color and percent value for the lines.
1.274 -template<class T> class GraphToEps : public T
1.275 -{
1.276 - // Can't believe it is required by the C++ standard
1.277 - using T::g;
1.278 - using T::os;
1.279 -
1.280 - using T::_coords;
1.281 - using T::_nodeSizes;
1.282 - using T::_nodeShapes;
1.283 - using T::_nodeColors;
1.284 - using T::_edgeColors;
1.285 - using T::_edgeWidths;
1.286 -
1.287 - using T::_edgeWidthScale;
1.288 - using T::_nodeScale;
1.289 - using T::_xBorder;
1.290 - using T::_yBorder;
1.291 - using T::_scale;
1.292 - using T::_nodeBorderQuotient;
1.293 -
1.294 - using T::_drawArrows;
1.295 - using T::_arrowLength;
1.296 - using T::_arrowWidth;
1.297 -
1.298 - using T::_showNodes;
1.299 - using T::_showEdges;
1.300 -
1.301 - using T::_enableParallel;
1.302 - using T::_parEdgeDist;
1.303 -
1.304 - using T::_showNodeText;
1.305 - using T::_nodeTexts;
1.306 - using T::_nodeTextSize;
1.307 -
1.308 - using T::_showNodePsText;
1.309 - using T::_nodePsTexts;
1.310 - using T::_nodePsTextsPreamble;
1.311 -
1.312 - using T::_undir;
1.313 - using T::_pleaseRemoveOsStream;
1.314 -
1.315 - using T::_scaleToA4;
1.316 -
1.317 - using T::_title;
1.318 - using T::_copyright;
1.319 -
1.320 - using T::NodeTextColorType;
1.321 - using T::CUST_COL;
1.322 - using T::DIST_COL;
1.323 - using T::DIST_BW;
1.324 - using T::_nodeTextColorType;
1.325 - using T::_nodeTextColors;
1.326 - // dradnats ++C eht yb deriuqer si ti eveileb t'naC
1.327 -
1.328 - typedef typename T::Graph Graph;
1.329 - typedef typename Graph::Node Node;
1.330 - typedef typename Graph::NodeIt NodeIt;
1.331 - typedef typename Graph::Edge Edge;
1.332 - typedef typename Graph::EdgeIt EdgeIt;
1.333 - typedef typename Graph::InEdgeIt InEdgeIt;
1.334 - typedef typename Graph::OutEdgeIt OutEdgeIt;
1.335 -
1.336 - static const int INTERPOL_PREC=20;
1.337 - static const double A4HEIGHT = 841.8897637795276;
1.338 - static const double A4WIDTH = 595.275590551181;
1.339 - static const double A4BORDER = 15;
1.340 -
1.341 - bool dontPrint;
1.342 -
1.343 -public:
1.344 - ///Node shapes
1.345 -
1.346 - ///Node shapes
1.347 - ///
1.348 - enum NodeShapes {
1.349 - /// = 0
1.350 - ///\image html nodeshape_0.png
1.351 - ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
1.352 - CIRCLE=0,
1.353 - /// = 1
1.354 - ///\image html nodeshape_1.png
1.355 - ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
1.356 - ///
1.357 - SQUARE=1,
1.358 - /// = 2
1.359 - ///\image html nodeshape_2.png
1.360 - ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
1.361 - ///
1.362 - DIAMOND=2
1.363 - };
1.364 -
1.365 -private:
1.366 - class edgeLess {
1.367 - const Graph &g;
1.368 - public:
1.369 - edgeLess(const Graph &_g) : g(_g) {}
1.370 - bool operator()(Edge a,Edge b) const
1.371 - {
1.372 - Node ai=std::min(g.source(a),g.target(a));
1.373 - Node aa=std::max(g.source(a),g.target(a));
1.374 - Node bi=std::min(g.source(b),g.target(b));
1.375 - Node ba=std::max(g.source(b),g.target(b));
1.376 - return ai<bi ||
1.377 - (ai==bi && (aa < ba ||
1.378 - (aa==ba && ai==g.source(a) && bi==g.target(b))));
1.379 - }
1.380 - };
1.381 - bool isParallel(Edge e,Edge f) const
1.382 - {
1.383 - return (g.source(e)==g.source(f)&&
1.384 - g.target(e)==g.target(f)) ||
1.385 - (g.source(e)==g.target(f)&&
1.386 - g.target(e)==g.source(f));
1.387 - }
1.388 - template<class TT>
1.389 - static std::string psOut(const xy<TT> &p)
1.390 - {
1.391 - std::ostringstream os;
1.392 - os << p.x << ' ' << p.y;
1.393 - return os.str();
1.394 - }
1.395 - static std::string psOut(const Color &c)
1.396 - {
1.397 - std::ostringstream os;
1.398 - os << c.getR() << ' ' << c.getG() << ' ' << c.getB();
1.399 - return os.str();
1.400 - }
1.401 -
1.402 -public:
1.403 - GraphToEps(const T &t) : T(t), dontPrint(false) {};
1.404 -
1.405 - template<class X> struct CoordsTraits : public T {
1.406 - const X &_coords;
1.407 - CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
1.408 - };
1.409 - ///Sets the map of the node coordinates
1.410 -
1.411 - ///Sets the map of the node coordinates.
1.412 - ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values.
1.413 - template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
1.414 - dontPrint=true;
1.415 - return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
1.416 - }
1.417 - template<class X> struct NodeSizesTraits : public T {
1.418 - const X &_nodeSizes;
1.419 - NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
1.420 - };
1.421 - ///Sets the map of the node sizes
1.422 -
1.423 - ///Sets the map of the node sizes
1.424 - ///\param x must be a node map with \c double (or convertible) values.
1.425 - template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
1.426 - {
1.427 - dontPrint=true;
1.428 - return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
1.429 - }
1.430 - template<class X> struct NodeShapesTraits : public T {
1.431 - const X &_nodeShapes;
1.432 - NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
1.433 - };
1.434 - ///Sets the map of the node shapes
1.435 -
1.436 - ///Sets the map of the node shapes.
1.437 - ///The availabe shape values
1.438 - ///can be found in \ref NodeShapes "enum NodeShapes".
1.439 - ///\param x must be a node map with \c int (or convertible) values.
1.440 - ///\sa NodeShapes
1.441 - template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
1.442 - {
1.443 - dontPrint=true;
1.444 - return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
1.445 - }
1.446 - template<class X> struct NodeTextsTraits : public T {
1.447 - const X &_nodeTexts;
1.448 - NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
1.449 - };
1.450 - ///Sets the text printed on the nodes
1.451 -
1.452 - ///Sets the text printed on the nodes
1.453 - ///\param x must be a node map with type that can be pushed to a standard
1.454 - ///ostream.
1.455 - template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
1.456 - {
1.457 - dontPrint=true;
1.458 - _showNodeText=true;
1.459 - return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
1.460 - }
1.461 - template<class X> struct NodePsTextsTraits : public T {
1.462 - const X &_nodePsTexts;
1.463 - NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
1.464 - };
1.465 - ///Inserts a PostScript block to the nodes
1.466 -
1.467 - ///With this command it is possible to insert a verbatim PostScript
1.468 - ///block to the nodes.
1.469 - ///The PS current point will be moved to the centre of the node before
1.470 - ///the PostScript block inserted.
1.471 - ///
1.472 - ///Before and after the block a newline character is inserted to you
1.473 - ///don't have to bother with the separators.
1.474 - ///
1.475 - ///\param x must be a node map with type that can be pushed to a standard
1.476 - ///ostream.
1.477 - ///
1.478 - ///\sa nodePsTextsPreamble()
1.479 - ///\todo Offer the choise not to move to the centre but pass the coordinates
1.480 - ///to the Postscript block inserted.
1.481 - template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
1.482 - {
1.483 - dontPrint=true;
1.484 - _showNodePsText=true;
1.485 - return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
1.486 - }
1.487 - template<class X> struct EdgeWidthsTraits : public T {
1.488 - const X &_edgeWidths;
1.489 - EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
1.490 - };
1.491 - ///Sets the map of the edge widths
1.492 -
1.493 - ///Sets the map of the edge widths
1.494 - ///\param x must be a edge map with \c double (or convertible) values.
1.495 - template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
1.496 - {
1.497 - dontPrint=true;
1.498 - return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
1.499 - }
1.500 -
1.501 - template<class X> struct NodeColorsTraits : public T {
1.502 - const X &_nodeColors;
1.503 - NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
1.504 - };
1.505 - ///Sets the map of the node colors
1.506 -
1.507 - ///Sets the map of the node colors
1.508 - ///\param x must be a node map with \ref Color values.
1.509 - template<class X> GraphToEps<NodeColorsTraits<X> >
1.510 - nodeColors(const X &x)
1.511 - {
1.512 - dontPrint=true;
1.513 - return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
1.514 - }
1.515 - template<class X> struct NodeTextColorsTraits : public T {
1.516 - const X &_nodeTextColors;
1.517 - NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
1.518 - };
1.519 - ///Sets the map of the node text colors
1.520 -
1.521 - ///Sets the map of the node text colors
1.522 - ///\param x must be a node map with \ref Color values.
1.523 - template<class X> GraphToEps<NodeTextColorsTraits<X> >
1.524 - nodeTextColors(const X &x)
1.525 - {
1.526 - dontPrint=true;
1.527 - _nodeTextColorType=CUST_COL;
1.528 - return GraphToEps<NodeTextColorsTraits<X> >
1.529 - (NodeTextColorsTraits<X>(*this,x));
1.530 - }
1.531 - template<class X> struct EdgeColorsTraits : public T {
1.532 - const X &_edgeColors;
1.533 - EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
1.534 - };
1.535 - ///Sets the map of the edge colors
1.536 -
1.537 - ///Sets the map of the edge colors
1.538 - ///\param x must be a edge map with \ref Color values.
1.539 - template<class X> GraphToEps<EdgeColorsTraits<X> >
1.540 - edgeColors(const X &x)
1.541 - {
1.542 - dontPrint=true;
1.543 - return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
1.544 - }
1.545 - ///Sets a global scale factor for node sizes
1.546 -
1.547 - ///Sets a global scale factor for node sizes
1.548 - ///
1.549 - GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
1.550 - ///Sets a global scale factor for edge widths
1.551 -
1.552 - ///Sets a global scale factor for edge widths
1.553 - ///
1.554 - GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
1.555 - ///Sets a global scale factor for the whole picture
1.556 -
1.557 - ///Sets a global scale factor for the whole picture
1.558 - ///
1.559 - GraphToEps<T> &scale(double d) {_scale=d;return *this;}
1.560 - ///Sets the width of the border around the picture
1.561 -
1.562 - ///Sets the width of the border around the picture
1.563 - ///
1.564 - GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
1.565 - ///Sets the width of the border around the picture
1.566 -
1.567 - ///Sets the width of the border around the picture
1.568 - ///
1.569 - GraphToEps<T> &border(double x, double y) {
1.570 - _xBorder=x;_yBorder=y;return *this;
1.571 - }
1.572 - ///Sets whether to draw arrows
1.573 -
1.574 - ///Sets whether to draw arrows
1.575 - ///
1.576 - GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
1.577 - ///Sets the length of the arrowheads
1.578 -
1.579 - ///Sets the length of the arrowheads
1.580 - ///
1.581 - GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
1.582 - ///Sets the width of the arrowheads
1.583 -
1.584 - ///Sets the width of the arrowheads
1.585 - ///
1.586 - GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
1.587 -
1.588 - ///Scales the drawing to fit to A4 page
1.589 -
1.590 - ///Scales the drawing to fit to A4 page
1.591 - ///
1.592 - GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
1.593 -
1.594 - ///Enables parallel edges
1.595 -
1.596 - ///Enables parallel edges
1.597 - ///\todo Partially implemented
1.598 - GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
1.599 -
1.600 - ///Sets the distance
1.601 -
1.602 - ///Sets the distance
1.603 - ///
1.604 - GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
1.605 -
1.606 - ///Hides the edges
1.607 -
1.608 - ///Hides the edges
1.609 - ///
1.610 - GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
1.611 - ///Hides the nodes
1.612 -
1.613 - ///Hides the nodes
1.614 - ///
1.615 - GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
1.616 -
1.617 - ///Sets the size of the node texts
1.618 -
1.619 - ///Sets the size of the node texts
1.620 - ///
1.621 - GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
1.622 -
1.623 - ///Sets the color of the node texts to be different from the node color
1.624 -
1.625 - ///Sets the color of the node texts to be as different from the node color
1.626 - ///as it is possible
1.627 - ///
1.628 - GraphToEps<T> &distantColorNodeTexts()
1.629 - {_nodeTextColorType=DIST_COL;return *this;}
1.630 - ///Sets the color of the node texts to be black or white and always visible.
1.631 -
1.632 - ///Sets the color of the node texts to be black or white according to
1.633 - ///which is more
1.634 - ///different from the node color
1.635 - ///
1.636 - GraphToEps<T> &distantBWNodeTexts()
1.637 - {_nodeTextColorType=DIST_BW;return *this;}
1.638 -
1.639 - ///Gives a preamble block for node Postscript block.
1.640 -
1.641 - ///Gives a preamble block for node Postscript block.
1.642 - ///
1.643 - ///\sa nodePsTexts()
1.644 - GraphToEps<T> & nodePsTextsPreamble(const char *str) {
1.645 - _nodePsTextsPreamble=str ;return *this;
1.646 - }
1.647 - ///Sets whether the the graph is undirected
1.648 -
1.649 - ///Sets whether the the graph is undirected
1.650 - ///
1.651 - GraphToEps<T> &undir(bool b=true) {_undir=b;return *this;}
1.652 - ///Sets whether the the graph is directed
1.653 -
1.654 - ///Sets whether the the graph is directed.
1.655 - ///Use it to show the undirected edges as a pair of directed ones.
1.656 - GraphToEps<T> &bidir(bool b=true) {_undir=!b;return *this;}
1.657 -
1.658 - ///Sets the title.
1.659 -
1.660 - ///Sets the title of the generated image,
1.661 - ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
1.662 - ///the EPS file.
1.663 - GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
1.664 - ///Sets the copyright statement.
1.665 -
1.666 - ///Sets the copyright statement of the generated image,
1.667 - ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
1.668 - ///the EPS file.
1.669 - ///\todo Multiline copyright notice could be supported.
1.670 - GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;}
1.671 -
1.672 -protected:
1.673 - bool isInsideNode(xy<double> p, double r,int t)
1.674 - {
1.675 - switch(t) {
1.676 - case CIRCLE:
1.677 - return p.normSquare()<=r*r;
1.678 - case SQUARE:
1.679 - return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
1.680 - case DIAMOND:
1.681 - return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
1.682 - }
1.683 - return false;
1.684 - }
1.685 -
1.686 -public:
1.687 - ~GraphToEps() { }
1.688 -
1.689 - ///Draws the graph.
1.690 -
1.691 - ///Like other functions using
1.692 - ///\ref named-templ-func-param "named template parameters",
1.693 - ///this function calles the algorithm itself, i.e. in this case
1.694 - ///it draws the graph.
1.695 - void run() {
1.696 - if(dontPrint) return;
1.697 -
1.698 - os << "%!PS-Adobe-2.0 EPSF-2.0\n";
1.699 - if(_title.size()>0) os << "%%Title: " << _title << '\n';
1.700 - if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
1.701 -// << "%%Copyright: XXXX\n"
1.702 - os << "%%Creator: LEMON GraphToEps function\n";
1.703 -
1.704 - {
1.705 - char cbuf[50];
1.706 - timeval tv;
1.707 - gettimeofday(&tv, 0);
1.708 - ctime_r(&tv.tv_sec,cbuf);
1.709 - os << "%%CreationDate: " << cbuf;
1.710 - }
1.711 - ///\todo: Chech whether the graph is empty.
1.712 - BoundingBox<double> bb;
1.713 - for(NodeIt n(g);n!=INVALID;++n) {
1.714 - double ns=_nodeSizes[n]*_nodeScale;
1.715 - xy<double> p(ns,ns);
1.716 - bb+=p+_coords[n];
1.717 - bb+=-p+_coords[n];
1.718 - }
1.719 - if(_scaleToA4)
1.720 - os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
1.721 - else os << "%%BoundingBox: "
1.722 - << bb.left()* _scale-_xBorder << ' '
1.723 - << bb.bottom()*_scale-_yBorder << ' '
1.724 - << bb.right()* _scale+_xBorder << ' '
1.725 - << bb.top()* _scale+_yBorder << '\n';
1.726 -
1.727 - os << "%%EndComments\n";
1.728 -
1.729 - //x1 y1 x2 y2 x3 y3 cr cg cb w
1.730 - os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
1.731 - << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
1.732 - os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
1.733 - //x y r
1.734 - os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
1.735 - //x y r
1.736 - os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
1.737 - << " 2 index 1 index sub 2 index 2 index add lineto\n"
1.738 - << " 2 index 1 index sub 2 index 2 index sub lineto\n"
1.739 - << " 2 index 1 index add 2 index 2 index sub lineto\n"
1.740 - << " closepath pop pop pop} bind def\n";
1.741 - //x y r
1.742 - os << "/di { newpath 2 index 1 index add 2 index moveto\n"
1.743 - << " 2 index 2 index 2 index add lineto\n"
1.744 - << " 2 index 1 index sub 2 index lineto\n"
1.745 - << " 2 index 2 index 2 index sub lineto\n"
1.746 - << " closepath pop pop pop} bind def\n";
1.747 - // x y r cr cg cb
1.748 - os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
1.749 - << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
1.750 - << " } bind def\n";
1.751 - os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
1.752 - << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
1.753 - << " } bind def\n";
1.754 - os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
1.755 - << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
1.756 - << " } bind def\n";
1.757 - os << "/arrl " << _arrowLength << " def\n";
1.758 - os << "/arrw " << _arrowWidth << " def\n";
1.759 - // l dx_norm dy_norm
1.760 - os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
1.761 - //len w dx_norm dy_norm x1 y1 cr cg cb
1.762 - os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
1.763 - << " /w exch def /len exch def\n"
1.764 - // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
1.765 - << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
1.766 - << " len w sub arrl sub dx dy lrl\n"
1.767 - << " arrw dy dx neg lrl\n"
1.768 - << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
1.769 - << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
1.770 - << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
1.771 - << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
1.772 - << " arrw dy dx neg lrl\n"
1.773 - << " len w sub arrl sub neg dx dy lrl\n"
1.774 - << " closepath fill } bind def\n";
1.775 - os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
1.776 - << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
1.777 -
1.778 - os << "\ngsave\n";
1.779 - if(_scaleToA4)
1.780 - if(bb.height()>bb.width()) {
1.781 - double sc= min((A4HEIGHT-2*A4BORDER)/bb.height(),
1.782 - (A4WIDTH-2*A4BORDER)/bb.width());
1.783 - os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
1.784 - << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
1.785 - << sc << " dup scale\n"
1.786 - << -bb.left() << ' ' << -bb.bottom() << " translate\n";
1.787 - }
1.788 - else {
1.789 - //\todo Verify centering
1.790 - double sc= min((A4HEIGHT-2*A4BORDER)/bb.width(),
1.791 - (A4WIDTH-2*A4BORDER)/bb.height());
1.792 - os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
1.793 - << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER << " translate\n"
1.794 - << sc << " dup scale\n90 rotate\n"
1.795 - << -bb.left() << ' ' << -bb.top() << " translate\n";
1.796 - }
1.797 - else if(_scale!=1.0) os << _scale << " dup scale\n";
1.798 -
1.799 - if(_showEdges) {
1.800 - os << "%Edges:\ngsave\n";
1.801 - if(_enableParallel) {
1.802 - std::vector<Edge> el;
1.803 - for(EdgeIt e(g);e!=INVALID;++e)
1.804 - if((!_undir||g.source(e)<g.target(e))&&_edgeWidths[e]>0)
1.805 - el.push_back(e);
1.806 - sort(el.begin(),el.end(),edgeLess(g));
1.807 -
1.808 - typename std::vector<Edge>::iterator j;
1.809 - for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
1.810 - for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
1.811 -
1.812 - double sw=0;
1.813 - for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
1.814 - sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
1.815 - sw-=_parEdgeDist;
1.816 - sw/=-2.0;
1.817 - xy<double> dvec(_coords[g.target(*i)]-_coords[g.source(*i)]);
1.818 - double l=std::sqrt(dvec.normSquare());
1.819 - ///\todo better 'epsilon' would be nice here.
1.820 - xy<double> d(dvec/std::max(l,1e-9));
1.821 - xy<double> m;
1.822 -// m=xy<double>(_coords[g.target(*i)]+_coords[g.source(*i)])/2.0;
1.823 -
1.824 -// m=xy<double>(_coords[g.source(*i)])+
1.825 -// dvec*(double(_nodeSizes[g.source(*i)])/
1.826 -// (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
1.827 -
1.828 - m=xy<double>(_coords[g.source(*i)])+
1.829 - d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
1.830 -
1.831 - for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
1.832 - sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
1.833 - xy<double> mm=m+rot90(d)*sw/.75;
1.834 - if(_drawArrows) {
1.835 - int node_shape;
1.836 - xy<double> s=_coords[g.source(*e)];
1.837 - xy<double> t=_coords[g.target(*e)];
1.838 - double rn=_nodeSizes[g.target(*e)]*_nodeScale;
1.839 - node_shape=_nodeShapes[g.target(*e)];
1.840 - Bezier3 bez(s,mm,mm,t);
1.841 - double t1=0,t2=1;
1.842 - for(int i=0;i<INTERPOL_PREC;++i)
1.843 - if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
1.844 - else t1=(t1+t2)/2;
1.845 - xy<double> apoint=bez((t1+t2)/2);
1.846 - rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
1.847 - rn*=rn;
1.848 - t2=(t1+t2)/2;t1=0;
1.849 - for(int i=0;i<INTERPOL_PREC;++i)
1.850 - if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
1.851 - else t2=(t1+t2)/2;
1.852 - xy<double> linend=bez((t1+t2)/2);
1.853 - bez=bez.before((t1+t2)/2);
1.854 -// rn=_nodeSizes[g.source(*e)]*_nodeScale;
1.855 -// node_shape=_nodeShapes[g.source(*e)];
1.856 -// t1=0;t2=1;
1.857 -// for(int i=0;i<INTERPOL_PREC;++i)
1.858 -// if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
1.859 -// else t2=(t1+t2)/2;
1.860 -// bez=bez.after((t1+t2)/2);
1.861 - os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
1.862 - << _edgeColors[*e].getR() << ' '
1.863 - << _edgeColors[*e].getG() << ' '
1.864 - << _edgeColors[*e].getB() << " setrgbcolor newpath\n"
1.865 - << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
1.866 - << bez.p2.x << ' ' << bez.p2.y << ' '
1.867 - << bez.p3.x << ' ' << bez.p3.y << ' '
1.868 - << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
1.869 - xy<double> dd(rot90(linend-apoint));
1.870 - dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
1.871 - std::sqrt(dd.normSquare());
1.872 - os << "newpath " << psOut(apoint) << " moveto "
1.873 - << psOut(linend+dd) << " lineto "
1.874 - << psOut(linend-dd) << " lineto closepath fill\n";
1.875 - }
1.876 - else {
1.877 - os << _coords[g.source(*e)].x << ' '
1.878 - << _coords[g.source(*e)].y << ' '
1.879 - << mm.x << ' ' << mm.y << ' '
1.880 - << _coords[g.target(*e)].x << ' '
1.881 - << _coords[g.target(*e)].y << ' '
1.882 - << _edgeColors[*e].getR() << ' '
1.883 - << _edgeColors[*e].getG() << ' '
1.884 - << _edgeColors[*e].getB() << ' '
1.885 - << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
1.886 - }
1.887 - sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
1.888 - }
1.889 - }
1.890 - }
1.891 - else for(EdgeIt e(g);e!=INVALID;++e)
1.892 - if((!_undir||g.source(e)<g.target(e))&&_edgeWidths[e]>0)
1.893 - if(_drawArrows) {
1.894 - xy<double> d(_coords[g.target(e)]-_coords[g.source(e)]);
1.895 - double rn=_nodeSizes[g.target(e)]*_nodeScale;
1.896 - int node_shape=_nodeShapes[g.target(e)];
1.897 - double t1=0,t2=1;
1.898 - for(int i=0;i<INTERPOL_PREC;++i)
1.899 - if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
1.900 - else t2=(t1+t2)/2;
1.901 - double l=sqrt(d.normSquare());
1.902 - d/=l;
1.903 -
1.904 - os << l*(1-(t1+t2)/2) << ' '
1.905 - << _edgeWidths[e]*_edgeWidthScale << ' '
1.906 - << d.x << ' ' << d.y << ' '
1.907 - << _coords[g.source(e)].x << ' '
1.908 - << _coords[g.source(e)].y << ' '
1.909 - << _edgeColors[e].getR() << ' '
1.910 - << _edgeColors[e].getG() << ' '
1.911 - << _edgeColors[e].getB() << " arr\n";
1.912 - }
1.913 - else os << _coords[g.source(e)].x << ' '
1.914 - << _coords[g.source(e)].y << ' '
1.915 - << _coords[g.target(e)].x << ' '
1.916 - << _coords[g.target(e)].y << ' '
1.917 - << _edgeColors[e].getR() << ' '
1.918 - << _edgeColors[e].getG() << ' '
1.919 - << _edgeColors[e].getB() << ' '
1.920 - << _edgeWidths[e]*_edgeWidthScale << " l\n";
1.921 - os << "grestore\n";
1.922 - }
1.923 - if(_showNodes) {
1.924 - os << "%Nodes:\ngsave\n";
1.925 - for(NodeIt n(g);n!=INVALID;++n) {
1.926 - os << _coords[n].x << ' ' << _coords[n].y << ' '
1.927 - << _nodeSizes[n]*_nodeScale << ' '
1.928 - << _nodeColors[n].getR() << ' '
1.929 - << _nodeColors[n].getG() << ' '
1.930 - << _nodeColors[n].getB() << ' ';
1.931 - switch(_nodeShapes[n]) {
1.932 - case CIRCLE:
1.933 - os<< "nc";break;
1.934 - case SQUARE:
1.935 - os<< "nsq";break;
1.936 - case DIAMOND:
1.937 - os<< "ndi";break;
1.938 - }
1.939 - os<<'\n';
1.940 - }
1.941 - os << "grestore\n";
1.942 - }
1.943 - if(_showNodeText) {
1.944 - os << "%Node texts:\ngsave\n";
1.945 - os << "/fosi " << _nodeTextSize << " def\n";
1.946 - os << "(Helvetica) findfont fosi scalefont setfont\n";
1.947 - for(NodeIt n(g);n!=INVALID;++n) {
1.948 - switch(_nodeTextColorType) {
1.949 - case DIST_COL:
1.950 - os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
1.951 - break;
1.952 - case DIST_BW:
1.953 - os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
1.954 - break;
1.955 - case CUST_COL:
1.956 - os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
1.957 - break;
1.958 - default:
1.959 - os << "0 0 0 setrgbcolor\n";
1.960 - }
1.961 - os << _coords[n].x << ' ' << _coords[n].y
1.962 - << " (" << _nodeTexts[n] << ") cshow\n";
1.963 - }
1.964 - os << "grestore\n";
1.965 - }
1.966 - if(_showNodePsText) {
1.967 - os << "%Node PS blocks:\ngsave\n";
1.968 - for(NodeIt n(g);n!=INVALID;++n)
1.969 - os << _coords[n].x << ' ' << _coords[n].y
1.970 - << " moveto\n" << _nodePsTexts[n] << "\n";
1.971 - os << "grestore\n";
1.972 - }
1.973 -
1.974 - os << "grestore\nshowpage\n";
1.975 -
1.976 - //CleanUp:
1.977 - if(_pleaseRemoveOsStream) {delete &os;}
1.978 - }
1.979 -};
1.980 -
1.981 -
1.982 -///Generates an EPS file from a graph
1.983 -
1.984 -///\ingroup io_group
1.985 -///Generates an EPS file from a graph.
1.986 -///\param g is a reference to the graph to be printed
1.987 -///\param os is a reference to the output stream.
1.988 -///By default it is <tt>std::cout</tt>
1.989 -///
1.990 -///This function also has a lot of
1.991 -///\ref named-templ-func-param "named parameters",
1.992 -///they are declared as the members of class \ref GraphToEps. The following
1.993 -///example shows how to use these parameters.
1.994 -///\code
1.995 -/// graphToEps(g,os).scale(10).coords(coords)
1.996 -/// .nodeScale(2).nodeSizes(sizes)
1.997 -/// .edgeWidthScale(.4).run();
1.998 -///\endcode
1.999 -///\warning Don't forget to put the \ref GraphToEps::run() "run()"
1.1000 -///to the end of the parameter list.
1.1001 -///\sa GraphToEps
1.1002 -///\sa graphToEps(G &g, char *file_name)
1.1003 -template<class G>
1.1004 -GraphToEps<DefaultGraphToEpsTraits<G> >
1.1005 -graphToEps(G &g, std::ostream& os=std::cout)
1.1006 -{
1.1007 - return
1.1008 - GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1.1009 -}
1.1010 -
1.1011 -///Generates an EPS file from a graph
1.1012 -
1.1013 -///\ingroup misc
1.1014 -///This function does the same as
1.1015 -///\ref graphToEps(G &g,std::ostream& os)
1.1016 -///but it writes its output into the file \c file_name
1.1017 -///instead of a stream.
1.1018 -///\sa graphToEps(G &g, std::ostream& os)
1.1019 -template<class G>
1.1020 -GraphToEps<DefaultGraphToEpsTraits<G> >
1.1021 -graphToEps(G &g,const char *file_name)
1.1022 -{
1.1023 - return GraphToEps<DefaultGraphToEpsTraits<G> >
1.1024 - (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
1.1025 -}
1.1026 -
1.1027 -} //END OF NAMESPACE LEMON
1.1028 -
1.1029 -#endif // LEMON_GRAPH_TO_EPS_H