1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/graph_to_eps.h Thu Apr 03 11:10:49 2008 +0100
1.3 @@ -0,0 +1,1170 @@
1.4 +/* -*- C++ -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library
1.7 + *
1.8 + * Copyright (C) 2003-2008
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +#ifndef LEMON_GRAPH_TO_EPS_H
1.23 +#define LEMON_GRAPH_TO_EPS_H
1.24 +
1.25 +#include <sys/time.h>
1.26 +
1.27 +#ifdef WIN32
1.28 +#include <lemon/bits/mingw32_time.h>
1.29 +#endif
1.30 +
1.31 +#include<iostream>
1.32 +#include<fstream>
1.33 +#include<sstream>
1.34 +#include<algorithm>
1.35 +#include<vector>
1.36 +
1.37 +#include<ctime>
1.38 +
1.39 +#include<lemon/math.h>
1.40 +#include<lemon/bits/invalid.h>
1.41 +#include<lemon/dim2.h>
1.42 +#include<lemon/maps.h>
1.43 +#include<lemon/color.h>
1.44 +#include<lemon/bits/bezier.h>
1.45 +
1.46 +
1.47 +///\ingroup eps_io
1.48 +///\file
1.49 +///\brief Simple graph drawer
1.50 +///
1.51 +///\author Alpar Juttner
1.52 +
1.53 +namespace lemon {
1.54 +
1.55 +template<class MT>
1.56 +class _NegY {
1.57 +public:
1.58 + typedef typename MT::Key Key;
1.59 + typedef typename MT::Value Value;
1.60 + const MT ↦
1.61 + int yscale;
1.62 + _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
1.63 + Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
1.64 +};
1.65 +
1.66 +///Default traits class of \ref GraphToEps
1.67 +
1.68 +///Default traits class of \ref GraphToEps
1.69 +///
1.70 +///\c G is the type of the underlying graph.
1.71 +template<class G>
1.72 +struct DefaultGraphToEpsTraits
1.73 +{
1.74 + typedef G Graph;
1.75 + typedef typename Graph::Node Node;
1.76 + typedef typename Graph::NodeIt NodeIt;
1.77 + typedef typename Graph::Arc Arc;
1.78 + typedef typename Graph::ArcIt ArcIt;
1.79 + typedef typename Graph::InArcIt InArcIt;
1.80 + typedef typename Graph::OutArcIt OutArcIt;
1.81 +
1.82 +
1.83 + const Graph &g;
1.84 +
1.85 + std::ostream& os;
1.86 +
1.87 + typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType;
1.88 + CoordsMapType _coords;
1.89 + ConstMap<typename Graph::Node,double > _nodeSizes;
1.90 + ConstMap<typename Graph::Node,int > _nodeShapes;
1.91 +
1.92 + ConstMap<typename Graph::Node,Color > _nodeColors;
1.93 + ConstMap<typename Graph::Arc,Color > _arcColors;
1.94 +
1.95 + ConstMap<typename Graph::Arc,double > _arcWidths;
1.96 +
1.97 + double _arcWidthScale;
1.98 +
1.99 + double _nodeScale;
1.100 + double _xBorder, _yBorder;
1.101 + double _scale;
1.102 + double _nodeBorderQuotient;
1.103 +
1.104 + bool _drawArrows;
1.105 + double _arrowLength, _arrowWidth;
1.106 +
1.107 + bool _showNodes, _showArcs;
1.108 +
1.109 + bool _enableParallel;
1.110 + double _parArcDist;
1.111 +
1.112 + bool _showNodeText;
1.113 + ConstMap<typename Graph::Node,bool > _nodeTexts;
1.114 + double _nodeTextSize;
1.115 +
1.116 + bool _showNodePsText;
1.117 + ConstMap<typename Graph::Node,bool > _nodePsTexts;
1.118 + char *_nodePsTextsPreamble;
1.119 +
1.120 + bool _undirected;
1.121 +
1.122 + bool _pleaseRemoveOsStream;
1.123 +
1.124 + bool _scaleToA4;
1.125 +
1.126 + std::string _title;
1.127 + std::string _copyright;
1.128 +
1.129 + enum NodeTextColorType
1.130 + { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
1.131 + ConstMap<typename Graph::Node,Color > _nodeTextColors;
1.132 +
1.133 + bool _autoNodeScale;
1.134 + bool _autoArcWidthScale;
1.135 +
1.136 + bool _absoluteNodeSizes;
1.137 + bool _absoluteArcWidths;
1.138 +
1.139 + bool _negY;
1.140 +
1.141 + bool _preScale;
1.142 + ///Constructor
1.143 +
1.144 + ///Constructor
1.145 + ///\param _g is a reference to the graph to be printed
1.146 + ///\param _os is a reference to the output stream.
1.147 + ///\param _os is a reference to the output stream.
1.148 + ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
1.149 + ///will be explicitly deallocated by the destructor.
1.150 + ///By default it is <tt>std::cout</tt>
1.151 + DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
1.152 + bool _pros=false) :
1.153 + g(_g), os(_os),
1.154 + _coords(dim2::Point<double>(1,1)), _nodeSizes(.01), _nodeShapes(0),
1.155 + _nodeColors(WHITE), _arcColors(BLACK),
1.156 + _arcWidths(1.0), _arcWidthScale(0.003),
1.157 + _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
1.158 + _nodeBorderQuotient(.1),
1.159 + _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
1.160 + _showNodes(true), _showArcs(true),
1.161 + _enableParallel(false), _parArcDist(1),
1.162 + _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
1.163 + _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
1.164 + _undirected(false),
1.165 + _pleaseRemoveOsStream(_pros), _scaleToA4(false),
1.166 + _nodeTextColorType(SAME_COL), _nodeTextColors(BLACK),
1.167 + _autoNodeScale(false),
1.168 + _autoArcWidthScale(false),
1.169 + _absoluteNodeSizes(false),
1.170 + _absoluteArcWidths(false),
1.171 + _negY(false),
1.172 + _preScale(true)
1.173 + {}
1.174 +};
1.175 +
1.176 +///Helper class to implement the named parameters of \ref graphToEps()
1.177 +
1.178 +///Helper class to implement the named parameters of \ref graphToEps()
1.179 +///\todo Is 'helper class' a good name for this?
1.180 +///
1.181 +///\todo Follow PostScript's DSC.
1.182 +/// Use own dictionary.
1.183 +///\todo Useful new features.
1.184 +/// - Linestyles: dotted, dashed etc.
1.185 +/// - A second color and percent value for the lines.
1.186 +template<class T> class GraphToEps : public T
1.187 +{
1.188 + // Can't believe it is required by the C++ standard
1.189 + using T::g;
1.190 + using T::os;
1.191 +
1.192 + using T::_coords;
1.193 + using T::_nodeSizes;
1.194 + using T::_nodeShapes;
1.195 + using T::_nodeColors;
1.196 + using T::_arcColors;
1.197 + using T::_arcWidths;
1.198 +
1.199 + using T::_arcWidthScale;
1.200 + using T::_nodeScale;
1.201 + using T::_xBorder;
1.202 + using T::_yBorder;
1.203 + using T::_scale;
1.204 + using T::_nodeBorderQuotient;
1.205 +
1.206 + using T::_drawArrows;
1.207 + using T::_arrowLength;
1.208 + using T::_arrowWidth;
1.209 +
1.210 + using T::_showNodes;
1.211 + using T::_showArcs;
1.212 +
1.213 + using T::_enableParallel;
1.214 + using T::_parArcDist;
1.215 +
1.216 + using T::_showNodeText;
1.217 + using T::_nodeTexts;
1.218 + using T::_nodeTextSize;
1.219 +
1.220 + using T::_showNodePsText;
1.221 + using T::_nodePsTexts;
1.222 + using T::_nodePsTextsPreamble;
1.223 +
1.224 + using T::_undirected;
1.225 +
1.226 + using T::_pleaseRemoveOsStream;
1.227 +
1.228 + using T::_scaleToA4;
1.229 +
1.230 + using T::_title;
1.231 + using T::_copyright;
1.232 +
1.233 + using T::NodeTextColorType;
1.234 + using T::CUST_COL;
1.235 + using T::DIST_COL;
1.236 + using T::DIST_BW;
1.237 + using T::_nodeTextColorType;
1.238 + using T::_nodeTextColors;
1.239 +
1.240 + using T::_autoNodeScale;
1.241 + using T::_autoArcWidthScale;
1.242 +
1.243 + using T::_absoluteNodeSizes;
1.244 + using T::_absoluteArcWidths;
1.245 +
1.246 +
1.247 + using T::_negY;
1.248 + using T::_preScale;
1.249 +
1.250 + // dradnats ++C eht yb deriuqer si ti eveileb t'naC
1.251 +
1.252 + typedef typename T::Graph Graph;
1.253 + typedef typename Graph::Node Node;
1.254 + typedef typename Graph::NodeIt NodeIt;
1.255 + typedef typename Graph::Arc Arc;
1.256 + typedef typename Graph::ArcIt ArcIt;
1.257 + typedef typename Graph::InArcIt InArcIt;
1.258 + typedef typename Graph::OutArcIt OutArcIt;
1.259 +
1.260 + static const int INTERPOL_PREC;
1.261 + static const double A4HEIGHT;
1.262 + static const double A4WIDTH;
1.263 + static const double A4BORDER;
1.264 +
1.265 + bool dontPrint;
1.266 +
1.267 +public:
1.268 + ///Node shapes
1.269 +
1.270 + ///Node shapes
1.271 + ///
1.272 + enum NodeShapes {
1.273 + /// = 0
1.274 + ///\image html nodeshape_0.png
1.275 + ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
1.276 + CIRCLE=0,
1.277 + /// = 1
1.278 + ///\image html nodeshape_1.png
1.279 + ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
1.280 + ///
1.281 + SQUARE=1,
1.282 + /// = 2
1.283 + ///\image html nodeshape_2.png
1.284 + ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
1.285 + ///
1.286 + DIAMOND=2,
1.287 + /// = 3
1.288 + ///\image html nodeshape_3.png
1.289 + ///\image latex nodeshape_2.eps "MALE shape (4)" width=2cm
1.290 + ///
1.291 + MALE=3,
1.292 + /// = 4
1.293 + ///\image html nodeshape_4.png
1.294 + ///\image latex nodeshape_2.eps "FEMALE shape (4)" width=2cm
1.295 + ///
1.296 + FEMALE=4
1.297 + };
1.298 +
1.299 +private:
1.300 + class arcLess {
1.301 + const Graph &g;
1.302 + public:
1.303 + arcLess(const Graph &_g) : g(_g) {}
1.304 + bool operator()(Arc a,Arc b) const
1.305 + {
1.306 + Node ai=std::min(g.source(a),g.target(a));
1.307 + Node aa=std::max(g.source(a),g.target(a));
1.308 + Node bi=std::min(g.source(b),g.target(b));
1.309 + Node ba=std::max(g.source(b),g.target(b));
1.310 + return ai<bi ||
1.311 + (ai==bi && (aa < ba ||
1.312 + (aa==ba && ai==g.source(a) && bi==g.target(b))));
1.313 + }
1.314 + };
1.315 + bool isParallel(Arc e,Arc f) const
1.316 + {
1.317 + return (g.source(e)==g.source(f)&&
1.318 + g.target(e)==g.target(f)) ||
1.319 + (g.source(e)==g.target(f)&&
1.320 + g.target(e)==g.source(f));
1.321 + }
1.322 + template<class TT>
1.323 + static std::string psOut(const dim2::Point<TT> &p)
1.324 + {
1.325 + std::ostringstream os;
1.326 + os << p.x << ' ' << p.y;
1.327 + return os.str();
1.328 + }
1.329 + static std::string psOut(const Color &c)
1.330 + {
1.331 + std::ostringstream os;
1.332 + os << c.red() << ' ' << c.green() << ' ' << c.blue();
1.333 + return os.str();
1.334 + }
1.335 +
1.336 +public:
1.337 + GraphToEps(const T &t) : T(t), dontPrint(false) {};
1.338 +
1.339 + template<class X> struct CoordsTraits : public T {
1.340 + typedef X CoordsMapType;
1.341 + const X &_coords;
1.342 + CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
1.343 + };
1.344 + ///Sets the map of the node coordinates
1.345 +
1.346 + ///Sets the map of the node coordinates.
1.347 + ///\param x must be a node map with dim2::Point<double> or
1.348 + ///\ref dim2::Point "dim2::Point<int>" values.
1.349 + template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
1.350 + dontPrint=true;
1.351 + return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
1.352 + }
1.353 + template<class X> struct NodeSizesTraits : public T {
1.354 + const X &_nodeSizes;
1.355 + NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
1.356 + };
1.357 + ///Sets the map of the node sizes
1.358 +
1.359 + ///Sets the map of the node sizes
1.360 + ///\param x must be a node map with \c double (or convertible) values.
1.361 + template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
1.362 + {
1.363 + dontPrint=true;
1.364 + return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
1.365 + }
1.366 + template<class X> struct NodeShapesTraits : public T {
1.367 + const X &_nodeShapes;
1.368 + NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
1.369 + };
1.370 + ///Sets the map of the node shapes
1.371 +
1.372 + ///Sets the map of the node shapes.
1.373 + ///The availabe shape values
1.374 + ///can be found in \ref NodeShapes "enum NodeShapes".
1.375 + ///\param x must be a node map with \c int (or convertible) values.
1.376 + ///\sa NodeShapes
1.377 + template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
1.378 + {
1.379 + dontPrint=true;
1.380 + return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
1.381 + }
1.382 + template<class X> struct NodeTextsTraits : public T {
1.383 + const X &_nodeTexts;
1.384 + NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
1.385 + };
1.386 + ///Sets the text printed on the nodes
1.387 +
1.388 + ///Sets the text printed on the nodes
1.389 + ///\param x must be a node map with type that can be pushed to a standard
1.390 + ///ostream.
1.391 + template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
1.392 + {
1.393 + dontPrint=true;
1.394 + _showNodeText=true;
1.395 + return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
1.396 + }
1.397 + template<class X> struct NodePsTextsTraits : public T {
1.398 + const X &_nodePsTexts;
1.399 + NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
1.400 + };
1.401 + ///Inserts a PostScript block to the nodes
1.402 +
1.403 + ///With this command it is possible to insert a verbatim PostScript
1.404 + ///block to the nodes.
1.405 + ///The PS current point will be moved to the centre of the node before
1.406 + ///the PostScript block inserted.
1.407 + ///
1.408 + ///Before and after the block a newline character is inserted so you
1.409 + ///don't have to bother with the separators.
1.410 + ///
1.411 + ///\param x must be a node map with type that can be pushed to a standard
1.412 + ///ostream.
1.413 + ///
1.414 + ///\sa nodePsTextsPreamble()
1.415 + ///\todo Offer the choise not to move to the centre but pass the coordinates
1.416 + ///to the Postscript block inserted.
1.417 + template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
1.418 + {
1.419 + dontPrint=true;
1.420 + _showNodePsText=true;
1.421 + return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
1.422 + }
1.423 + template<class X> struct ArcWidthsTraits : public T {
1.424 + const X &_arcWidths;
1.425 + ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {}
1.426 + };
1.427 + ///Sets the map of the arc widths
1.428 +
1.429 + ///Sets the map of the arc widths
1.430 + ///\param x must be a arc map with \c double (or convertible) values.
1.431 + template<class X> GraphToEps<ArcWidthsTraits<X> > arcWidths(const X &x)
1.432 + {
1.433 + dontPrint=true;
1.434 + return GraphToEps<ArcWidthsTraits<X> >(ArcWidthsTraits<X>(*this,x));
1.435 + }
1.436 +
1.437 + template<class X> struct NodeColorsTraits : public T {
1.438 + const X &_nodeColors;
1.439 + NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
1.440 + };
1.441 + ///Sets the map of the node colors
1.442 +
1.443 + ///Sets the map of the node colors
1.444 + ///\param x must be a node map with \ref Color values.
1.445 + ///
1.446 + ///\sa Palette
1.447 + template<class X> GraphToEps<NodeColorsTraits<X> >
1.448 + nodeColors(const X &x)
1.449 + {
1.450 + dontPrint=true;
1.451 + return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
1.452 + }
1.453 + template<class X> struct NodeTextColorsTraits : public T {
1.454 + const X &_nodeTextColors;
1.455 + NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
1.456 + };
1.457 + ///Sets the map of the node text colors
1.458 +
1.459 + ///Sets the map of the node text colors
1.460 + ///\param x must be a node map with \ref Color values.
1.461 + ///
1.462 + ///\sa Palette
1.463 + template<class X> GraphToEps<NodeTextColorsTraits<X> >
1.464 + nodeTextColors(const X &x)
1.465 + {
1.466 + dontPrint=true;
1.467 + _nodeTextColorType=CUST_COL;
1.468 + return GraphToEps<NodeTextColorsTraits<X> >
1.469 + (NodeTextColorsTraits<X>(*this,x));
1.470 + }
1.471 + template<class X> struct ArcColorsTraits : public T {
1.472 + const X &_arcColors;
1.473 + ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {}
1.474 + };
1.475 + ///Sets the map of the arc colors
1.476 +
1.477 + ///Sets the map of the arc colors
1.478 + ///\param x must be a arc map with \ref Color values.
1.479 + ///
1.480 + ///\sa Palette
1.481 + template<class X> GraphToEps<ArcColorsTraits<X> >
1.482 + arcColors(const X &x)
1.483 + {
1.484 + dontPrint=true;
1.485 + return GraphToEps<ArcColorsTraits<X> >(ArcColorsTraits<X>(*this,x));
1.486 + }
1.487 + ///Sets a global scale factor for node sizes
1.488 +
1.489 + ///Sets a global scale factor for node sizes.
1.490 + ///
1.491 + /// If nodeSizes() is not given, this function simply sets the node
1.492 + /// sizes to \c d. If nodeSizes() is given, but
1.493 + /// autoNodeScale() is not, then the node size given by
1.494 + /// nodeSizes() will be multiplied by the value \c d.
1.495 + /// If both nodeSizes() and autoNodeScale() are used, then the
1.496 + /// node sizes will be scaled in such a way that the greatest size will be
1.497 + /// equal to \c d.
1.498 + /// \sa nodeSizes()
1.499 + /// \sa autoNodeScale()
1.500 + GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
1.501 + ///Turns on/off the automatic node width scaling.
1.502 +
1.503 + ///Turns on/off the automatic node width scaling.
1.504 + ///
1.505 + ///\sa nodeScale()
1.506 + ///
1.507 + GraphToEps<T> &autoNodeScale(bool b=true) {
1.508 + _autoNodeScale=b;return *this;
1.509 + }
1.510 +
1.511 + ///Turns on/off the absolutematic node width scaling.
1.512 +
1.513 + ///Turns on/off the absolutematic node width scaling.
1.514 + ///
1.515 + ///\sa nodeScale()
1.516 + ///
1.517 + GraphToEps<T> &absoluteNodeSizes(bool b=true) {
1.518 + _absoluteNodeSizes=b;return *this;
1.519 + }
1.520 +
1.521 + ///Negates the Y coordinates.
1.522 +
1.523 + ///Negates the Y coordinates.
1.524 + ///
1.525 + ///\todo More docs.
1.526 + ///
1.527 + GraphToEps<T> &negateY(bool b=true) {
1.528 + _negY=b;return *this;
1.529 + }
1.530 +
1.531 + ///Turn on/off prescaling
1.532 +
1.533 + ///By default graphToEps() rescales the whole image in order to avoid
1.534 + ///very big or very small bounding boxes.
1.535 + ///
1.536 + ///This (p)rescaling can be turned off with this function.
1.537 + ///
1.538 + GraphToEps<T> &preScale(bool b=true) {
1.539 + _preScale=b;return *this;
1.540 + }
1.541 +
1.542 + ///Sets a global scale factor for arc widths
1.543 +
1.544 + /// Sets a global scale factor for arc widths.
1.545 + ///
1.546 + /// If arcWidths() is not given, this function simply sets the arc
1.547 + /// widths to \c d. If arcWidths() is given, but
1.548 + /// autoArcWidthScale() is not, then the arc withs given by
1.549 + /// arcWidths() will be multiplied by the value \c d.
1.550 + /// If both arcWidths() and autoArcWidthScale() are used, then the
1.551 + /// arc withs will be scaled in such a way that the greatest width will be
1.552 + /// equal to \c d.
1.553 + GraphToEps<T> &arcWidthScale(double d) {_arcWidthScale=d;return *this;}
1.554 + ///Turns on/off the automatic arc width scaling.
1.555 +
1.556 + ///Turns on/off the automatic arc width scaling.
1.557 + ///
1.558 + ///\sa arcWidthScale()
1.559 + ///
1.560 + GraphToEps<T> &autoArcWidthScale(bool b=true) {
1.561 + _autoArcWidthScale=b;return *this;
1.562 + }
1.563 + ///Turns on/off the absolutematic arc width scaling.
1.564 +
1.565 + ///Turns on/off the absolutematic arc width scaling.
1.566 + ///
1.567 + ///\sa arcWidthScale()
1.568 + ///
1.569 + GraphToEps<T> &absoluteArcWidths(bool b=true) {
1.570 + _absoluteArcWidths=b;return *this;
1.571 + }
1.572 + ///Sets a global scale factor for the whole picture
1.573 +
1.574 + ///Sets a global scale factor for the whole picture
1.575 + ///
1.576 +
1.577 + GraphToEps<T> &scale(double d) {_scale=d;return *this;}
1.578 + ///Sets the width of the border around the picture
1.579 +
1.580 + ///Sets the width of the border around the picture
1.581 + ///
1.582 + GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
1.583 + ///Sets the width of the border around the picture
1.584 +
1.585 + ///Sets the width of the border around the picture
1.586 + ///
1.587 + GraphToEps<T> &border(double x, double y) {
1.588 + _xBorder=x;_yBorder=y;return *this;
1.589 + }
1.590 + ///Sets whether to draw arrows
1.591 +
1.592 + ///Sets whether to draw arrows
1.593 + ///
1.594 + GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
1.595 + ///Sets the length of the arrowheads
1.596 +
1.597 + ///Sets the length of the arrowheads
1.598 + ///
1.599 + GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
1.600 + ///Sets the width of the arrowheads
1.601 +
1.602 + ///Sets the width of the arrowheads
1.603 + ///
1.604 + GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
1.605 +
1.606 + ///Scales the drawing to fit to A4 page
1.607 +
1.608 + ///Scales the drawing to fit to A4 page
1.609 + ///
1.610 + GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
1.611 +
1.612 + ///Enables parallel arcs
1.613 +
1.614 + ///Enables parallel arcs
1.615 + GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
1.616 +
1.617 + ///Sets the distance
1.618 +
1.619 + ///Sets the distance
1.620 + ///
1.621 + GraphToEps<T> &parArcDist(double d) {_parArcDist*=d;return *this;}
1.622 +
1.623 + ///Hides the arcs
1.624 +
1.625 + ///Hides the arcs
1.626 + ///
1.627 + GraphToEps<T> &hideArcs(bool b=true) {_showArcs=!b;return *this;}
1.628 + ///Hides the nodes
1.629 +
1.630 + ///Hides the nodes
1.631 + ///
1.632 + GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
1.633 +
1.634 + ///Sets the size of the node texts
1.635 +
1.636 + ///Sets the size of the node texts
1.637 + ///
1.638 + GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
1.639 +
1.640 + ///Sets the color of the node texts to be different from the node color
1.641 +
1.642 + ///Sets the color of the node texts to be as different from the node color
1.643 + ///as it is possible
1.644 + ///
1.645 + GraphToEps<T> &distantColorNodeTexts()
1.646 + {_nodeTextColorType=DIST_COL;return *this;}
1.647 + ///Sets the color of the node texts to be black or white and always visible.
1.648 +
1.649 + ///Sets the color of the node texts to be black or white according to
1.650 + ///which is more
1.651 + ///different from the node color
1.652 + ///
1.653 + GraphToEps<T> &distantBWNodeTexts()
1.654 + {_nodeTextColorType=DIST_BW;return *this;}
1.655 +
1.656 + ///Gives a preamble block for node Postscript block.
1.657 +
1.658 + ///Gives a preamble block for node Postscript block.
1.659 + ///
1.660 + ///\sa nodePsTexts()
1.661 + GraphToEps<T> & nodePsTextsPreamble(const char *str) {
1.662 + _nodePsTextsPreamble=str ;return *this;
1.663 + }
1.664 + ///Sets whether the the graph is undirected
1.665 +
1.666 + ///Sets whether the the graph is undirected
1.667 + ///
1.668 + GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
1.669 +
1.670 + ///Sets whether the the graph is directed
1.671 +
1.672 + ///Sets whether the the graph is directed.
1.673 + ///Use it to show the edges as a pair of directed ones.
1.674 + GraphToEps<T> &bidir(bool b=true) {_undirected=!b;return *this;}
1.675 +
1.676 + ///Sets the title.
1.677 +
1.678 + ///Sets the title of the generated image,
1.679 + ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
1.680 + ///the EPS file.
1.681 + GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
1.682 + ///Sets the copyright statement.
1.683 +
1.684 + ///Sets the copyright statement of the generated image,
1.685 + ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
1.686 + ///the EPS file.
1.687 + ///\todo Multiline copyright notice could be supported.
1.688 + GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;}
1.689 +
1.690 +protected:
1.691 + bool isInsideNode(dim2::Point<double> p, double r,int t)
1.692 + {
1.693 + switch(t) {
1.694 + case CIRCLE:
1.695 + case MALE:
1.696 + case FEMALE:
1.697 + return p.normSquare()<=r*r;
1.698 + case SQUARE:
1.699 + return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
1.700 + case DIAMOND:
1.701 + return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
1.702 + }
1.703 + return false;
1.704 + }
1.705 +
1.706 +public:
1.707 + ~GraphToEps() { }
1.708 +
1.709 + ///Draws the graph.
1.710 +
1.711 + ///Like other functions using
1.712 + ///\ref named-templ-func-param "named template parameters",
1.713 + ///this function calles the algorithm itself, i.e. in this case
1.714 + ///it draws the graph.
1.715 + void run() {
1.716 + ///\todo better 'epsilon' would be nice here.
1.717 + const double EPSILON=1e-9;
1.718 + if(dontPrint) return;
1.719 +
1.720 + _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
1.721 +
1.722 + os << "%!PS-Adobe-2.0 EPSF-2.0\n";
1.723 + if(_title.size()>0) os << "%%Title: " << _title << '\n';
1.724 + if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
1.725 +// << "%%Copyright: XXXX\n"
1.726 + os << "%%Creator: LEMON, graphToEps()\n";
1.727 +
1.728 + {
1.729 + char cbuf[50];
1.730 + timeval tv;
1.731 + gettimeofday(&tv, 0);
1.732 + ctime_r(&tv.tv_sec,cbuf);
1.733 + os << "%%CreationDate: " << cbuf;
1.734 + }
1.735 +
1.736 + if (_autoArcWidthScale) {
1.737 + double max_w=0;
1.738 + for(ArcIt e(g);e!=INVALID;++e)
1.739 + max_w=std::max(double(_arcWidths[e]),max_w);
1.740 + ///\todo better 'epsilon' would be nice here.
1.741 + if(max_w>EPSILON) {
1.742 + _arcWidthScale/=max_w;
1.743 + }
1.744 + }
1.745 +
1.746 + if (_autoNodeScale) {
1.747 + double max_s=0;
1.748 + for(NodeIt n(g);n!=INVALID;++n)
1.749 + max_s=std::max(double(_nodeSizes[n]),max_s);
1.750 + ///\todo better 'epsilon' would be nice here.
1.751 + if(max_s>EPSILON) {
1.752 + _nodeScale/=max_s;
1.753 + }
1.754 + }
1.755 +
1.756 + double diag_len = 1;
1.757 + if(!(_absoluteNodeSizes&&_absoluteArcWidths)) {
1.758 + dim2::BoundingBox<double> bb;
1.759 + for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]);
1.760 + if (bb.empty()) {
1.761 + bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0));
1.762 + }
1.763 + diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare());
1.764 + if(diag_len<EPSILON) diag_len = 1;
1.765 + if(!_absoluteNodeSizes) _nodeScale*=diag_len;
1.766 + if(!_absoluteArcWidths) _arcWidthScale*=diag_len;
1.767 + }
1.768 +
1.769 + dim2::BoundingBox<double> bb;
1.770 + for(NodeIt n(g);n!=INVALID;++n) {
1.771 + double ns=_nodeSizes[n]*_nodeScale;
1.772 + dim2::Point<double> p(ns,ns);
1.773 + switch(_nodeShapes[n]) {
1.774 + case CIRCLE:
1.775 + case SQUARE:
1.776 + case DIAMOND:
1.777 + bb.add(p+mycoords[n]);
1.778 + bb.add(-p+mycoords[n]);
1.779 + break;
1.780 + case MALE:
1.781 + bb.add(-p+mycoords[n]);
1.782 + bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
1.783 + break;
1.784 + case FEMALE:
1.785 + bb.add(p+mycoords[n]);
1.786 + bb.add(dim2::Point<double>(-ns,-3.01*ns)+mycoords[n]);
1.787 + break;
1.788 + }
1.789 + }
1.790 + if (bb.empty()) {
1.791 + bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0));
1.792 + }
1.793 +
1.794 + if(_scaleToA4)
1.795 + os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
1.796 + else {
1.797 + if(_preScale) {
1.798 + //Rescale so that BoundingBox won't be neither to big nor too small.
1.799 + while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10;
1.800 + while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10;
1.801 + }
1.802 +
1.803 + os << "%%BoundingBox: "
1.804 + << int(floor(bb.left() * _scale - _xBorder)) << ' '
1.805 + << int(floor(bb.bottom() * _scale - _yBorder)) << ' '
1.806 + << int(ceil(bb.right() * _scale + _xBorder)) << ' '
1.807 + << int(ceil(bb.top() * _scale + _yBorder)) << '\n';
1.808 + }
1.809 +
1.810 + os << "%%EndComments\n";
1.811 +
1.812 + //x1 y1 x2 y2 x3 y3 cr cg cb w
1.813 + os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
1.814 + << " 4 2 roll 1 index 1 index curveto stroke } bind def\n";
1.815 + os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
1.816 + //x y r
1.817 + os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
1.818 + //x y r
1.819 + os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
1.820 + << " 2 index 1 index sub 2 index 2 index add lineto\n"
1.821 + << " 2 index 1 index sub 2 index 2 index sub lineto\n"
1.822 + << " 2 index 1 index add 2 index 2 index sub lineto\n"
1.823 + << " closepath pop pop pop} bind def\n";
1.824 + //x y r
1.825 + os << "/di { newpath 2 index 1 index add 2 index moveto\n"
1.826 + << " 2 index 2 index 2 index add lineto\n"
1.827 + << " 2 index 1 index sub 2 index lineto\n"
1.828 + << " 2 index 2 index 2 index sub lineto\n"
1.829 + << " closepath pop pop pop} bind def\n";
1.830 + // x y r cr cg cb
1.831 + os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
1.832 + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
1.833 + << " } bind def\n";
1.834 + os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
1.835 + << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
1.836 + << " } bind def\n";
1.837 + os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
1.838 + << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
1.839 + << " } bind def\n";
1.840 + os << "/nfemale { 0 0 0 setrgbcolor 3 index "
1.841 + << _nodeBorderQuotient/(1+_nodeBorderQuotient)
1.842 + << " 1.5 mul mul setlinewidth\n"
1.843 + << " newpath 5 index 5 index moveto "
1.844 + << "5 index 5 index 5 index 3.01 mul sub\n"
1.845 + << " lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto\n"
1.846 + << " 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke\n"
1.847 + << " 5 index 5 index 5 index c fill\n"
1.848 + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
1.849 + << " } bind def\n";
1.850 + os << "/nmale {\n"
1.851 + << " 0 0 0 setrgbcolor 3 index "
1.852 + << _nodeBorderQuotient/(1+_nodeBorderQuotient)
1.853 + <<" 1.5 mul mul setlinewidth\n"
1.854 + << " newpath 5 index 5 index moveto\n"
1.855 + << " 5 index 4 index 1 mul 1.5 mul add\n"
1.856 + << " 5 index 5 index 3 sqrt 1.5 mul mul add\n"
1.857 + << " 1 index 1 index lineto\n"
1.858 + << " 1 index 1 index 7 index sub moveto\n"
1.859 + << " 1 index 1 index lineto\n"
1.860 + << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n"
1.861 + << " stroke\n"
1.862 + << " 5 index 5 index 5 index c fill\n"
1.863 + << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
1.864 + << " } bind def\n";
1.865 +
1.866 +
1.867 + os << "/arrl " << _arrowLength << " def\n";
1.868 + os << "/arrw " << _arrowWidth << " def\n";
1.869 + // l dx_norm dy_norm
1.870 + os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
1.871 + //len w dx_norm dy_norm x1 y1 cr cg cb
1.872 + os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
1.873 + << " /w exch def /len exch def\n"
1.874 + // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
1.875 + << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
1.876 + << " len w sub arrl sub dx dy lrl\n"
1.877 + << " arrw dy dx neg lrl\n"
1.878 + << " dx arrl w add mul dy w 2 div arrw add mul sub\n"
1.879 + << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
1.880 + << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
1.881 + << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
1.882 + << " arrw dy dx neg lrl\n"
1.883 + << " len w sub arrl sub neg dx dy lrl\n"
1.884 + << " closepath fill } bind def\n";
1.885 + os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
1.886 + << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
1.887 +
1.888 + os << "\ngsave\n";
1.889 + if(_scaleToA4)
1.890 + if(bb.height()>bb.width()) {
1.891 + double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
1.892 + (A4WIDTH-2*A4BORDER)/bb.width());
1.893 + os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
1.894 + << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER
1.895 + << " translate\n"
1.896 + << sc << " dup scale\n"
1.897 + << -bb.left() << ' ' << -bb.bottom() << " translate\n";
1.898 + }
1.899 + else {
1.900 + //\todo Verify centering
1.901 + double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
1.902 + (A4WIDTH-2*A4BORDER)/bb.height());
1.903 + os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
1.904 + << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER
1.905 + << " translate\n"
1.906 + << sc << " dup scale\n90 rotate\n"
1.907 + << -bb.left() << ' ' << -bb.top() << " translate\n";
1.908 + }
1.909 + else if(_scale!=1.0) os << _scale << " dup scale\n";
1.910 +
1.911 + if(_showArcs) {
1.912 + os << "%Arcs:\ngsave\n";
1.913 + if(_enableParallel) {
1.914 + std::vector<Arc> el;
1.915 + for(ArcIt e(g);e!=INVALID;++e)
1.916 + if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0
1.917 + &&g.source(e)!=g.target(e))
1.918 + el.push_back(e);
1.919 + std::sort(el.begin(),el.end(),arcLess(g));
1.920 +
1.921 + typename std::vector<Arc>::iterator j;
1.922 + for(typename std::vector<Arc>::iterator i=el.begin();i!=el.end();i=j) {
1.923 + for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
1.924 +
1.925 + double sw=0;
1.926 + for(typename std::vector<Arc>::iterator e=i;e!=j;++e)
1.927 + sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist;
1.928 + sw-=_parArcDist;
1.929 + sw/=-2.0;
1.930 + dim2::Point<double>
1.931 + dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
1.932 + double l=std::sqrt(dvec.normSquare());
1.933 + ///\todo better 'epsilon' would be nice here.
1.934 + dim2::Point<double> d(dvec/std::max(l,EPSILON));
1.935 + dim2::Point<double> m;
1.936 +// m=dim2::Point<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
1.937 +
1.938 +// m=dim2::Point<double>(mycoords[g.source(*i)])+
1.939 +// dvec*(double(_nodeSizes[g.source(*i)])/
1.940 +// (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
1.941 +
1.942 + m=dim2::Point<double>(mycoords[g.source(*i)])+
1.943 + d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
1.944 +
1.945 + for(typename std::vector<Arc>::iterator e=i;e!=j;++e) {
1.946 + sw+=_arcWidths[*e]*_arcWidthScale/2.0;
1.947 + dim2::Point<double> mm=m+rot90(d)*sw/.75;
1.948 + if(_drawArrows) {
1.949 + int node_shape;
1.950 + dim2::Point<double> s=mycoords[g.source(*e)];
1.951 + dim2::Point<double> t=mycoords[g.target(*e)];
1.952 + double rn=_nodeSizes[g.target(*e)]*_nodeScale;
1.953 + node_shape=_nodeShapes[g.target(*e)];
1.954 + dim2::Bezier3 bez(s,mm,mm,t);
1.955 + double t1=0,t2=1;
1.956 + for(int ii=0;ii<INTERPOL_PREC;++ii)
1.957 + if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
1.958 + else t1=(t1+t2)/2;
1.959 + dim2::Point<double> apoint=bez((t1+t2)/2);
1.960 + rn = _arrowLength+_arcWidths[*e]*_arcWidthScale;
1.961 + rn*=rn;
1.962 + t2=(t1+t2)/2;t1=0;
1.963 + for(int ii=0;ii<INTERPOL_PREC;++ii)
1.964 + if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
1.965 + else t2=(t1+t2)/2;
1.966 + dim2::Point<double> linend=bez((t1+t2)/2);
1.967 + bez=bez.before((t1+t2)/2);
1.968 +// rn=_nodeSizes[g.source(*e)]*_nodeScale;
1.969 +// node_shape=_nodeShapes[g.source(*e)];
1.970 +// t1=0;t2=1;
1.971 +// for(int i=0;i<INTERPOL_PREC;++i)
1.972 +// if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
1.973 +// else t2=(t1+t2)/2;
1.974 +// bez=bez.after((t1+t2)/2);
1.975 + os << _arcWidths[*e]*_arcWidthScale << " setlinewidth "
1.976 + << _arcColors[*e].red() << ' '
1.977 + << _arcColors[*e].green() << ' '
1.978 + << _arcColors[*e].blue() << " setrgbcolor newpath\n"
1.979 + << bez.p1.x << ' ' << bez.p1.y << " moveto\n"
1.980 + << bez.p2.x << ' ' << bez.p2.y << ' '
1.981 + << bez.p3.x << ' ' << bez.p3.y << ' '
1.982 + << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
1.983 + dim2::Point<double> dd(rot90(linend-apoint));
1.984 + dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/
1.985 + std::sqrt(dd.normSquare());
1.986 + os << "newpath " << psOut(apoint) << " moveto "
1.987 + << psOut(linend+dd) << " lineto "
1.988 + << psOut(linend-dd) << " lineto closepath fill\n";
1.989 + }
1.990 + else {
1.991 + os << mycoords[g.source(*e)].x << ' '
1.992 + << mycoords[g.source(*e)].y << ' '
1.993 + << mm.x << ' ' << mm.y << ' '
1.994 + << mycoords[g.target(*e)].x << ' '
1.995 + << mycoords[g.target(*e)].y << ' '
1.996 + << _arcColors[*e].red() << ' '
1.997 + << _arcColors[*e].green() << ' '
1.998 + << _arcColors[*e].blue() << ' '
1.999 + << _arcWidths[*e]*_arcWidthScale << " lb\n";
1.1000 + }
1.1001 + sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist;
1.1002 + }
1.1003 + }
1.1004 + }
1.1005 + else for(ArcIt e(g);e!=INVALID;++e)
1.1006 + if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0
1.1007 + &&g.source(e)!=g.target(e))
1.1008 + if(_drawArrows) {
1.1009 + dim2::Point<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
1.1010 + double rn=_nodeSizes[g.target(e)]*_nodeScale;
1.1011 + int node_shape=_nodeShapes[g.target(e)];
1.1012 + double t1=0,t2=1;
1.1013 + for(int i=0;i<INTERPOL_PREC;++i)
1.1014 + if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
1.1015 + else t2=(t1+t2)/2;
1.1016 + double l=std::sqrt(d.normSquare());
1.1017 + d/=l;
1.1018 +
1.1019 + os << l*(1-(t1+t2)/2) << ' '
1.1020 + << _arcWidths[e]*_arcWidthScale << ' '
1.1021 + << d.x << ' ' << d.y << ' '
1.1022 + << mycoords[g.source(e)].x << ' '
1.1023 + << mycoords[g.source(e)].y << ' '
1.1024 + << _arcColors[e].red() << ' '
1.1025 + << _arcColors[e].green() << ' '
1.1026 + << _arcColors[e].blue() << " arr\n";
1.1027 + }
1.1028 + else os << mycoords[g.source(e)].x << ' '
1.1029 + << mycoords[g.source(e)].y << ' '
1.1030 + << mycoords[g.target(e)].x << ' '
1.1031 + << mycoords[g.target(e)].y << ' '
1.1032 + << _arcColors[e].red() << ' '
1.1033 + << _arcColors[e].green() << ' '
1.1034 + << _arcColors[e].blue() << ' '
1.1035 + << _arcWidths[e]*_arcWidthScale << " l\n";
1.1036 + os << "grestore\n";
1.1037 + }
1.1038 + if(_showNodes) {
1.1039 + os << "%Nodes:\ngsave\n";
1.1040 + for(NodeIt n(g);n!=INVALID;++n) {
1.1041 + os << mycoords[n].x << ' ' << mycoords[n].y << ' '
1.1042 + << _nodeSizes[n]*_nodeScale << ' '
1.1043 + << _nodeColors[n].red() << ' '
1.1044 + << _nodeColors[n].green() << ' '
1.1045 + << _nodeColors[n].blue() << ' ';
1.1046 + switch(_nodeShapes[n]) {
1.1047 + case CIRCLE:
1.1048 + os<< "nc";break;
1.1049 + case SQUARE:
1.1050 + os<< "nsq";break;
1.1051 + case DIAMOND:
1.1052 + os<< "ndi";break;
1.1053 + case MALE:
1.1054 + os<< "nmale";break;
1.1055 + case FEMALE:
1.1056 + os<< "nfemale";break;
1.1057 + }
1.1058 + os<<'\n';
1.1059 + }
1.1060 + os << "grestore\n";
1.1061 + }
1.1062 + if(_showNodeText) {
1.1063 + os << "%Node texts:\ngsave\n";
1.1064 + os << "/fosi " << _nodeTextSize << " def\n";
1.1065 + os << "(Helvetica) findfont fosi scalefont setfont\n";
1.1066 + for(NodeIt n(g);n!=INVALID;++n) {
1.1067 + switch(_nodeTextColorType) {
1.1068 + case DIST_COL:
1.1069 + os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
1.1070 + break;
1.1071 + case DIST_BW:
1.1072 + os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
1.1073 + break;
1.1074 + case CUST_COL:
1.1075 + os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
1.1076 + break;
1.1077 + default:
1.1078 + os << "0 0 0 setrgbcolor\n";
1.1079 + }
1.1080 + os << mycoords[n].x << ' ' << mycoords[n].y
1.1081 + << " (" << _nodeTexts[n] << ") cshow\n";
1.1082 + }
1.1083 + os << "grestore\n";
1.1084 + }
1.1085 + if(_showNodePsText) {
1.1086 + os << "%Node PS blocks:\ngsave\n";
1.1087 + for(NodeIt n(g);n!=INVALID;++n)
1.1088 + os << mycoords[n].x << ' ' << mycoords[n].y
1.1089 + << " moveto\n" << _nodePsTexts[n] << "\n";
1.1090 + os << "grestore\n";
1.1091 + }
1.1092 +
1.1093 + os << "grestore\nshowpage\n";
1.1094 +
1.1095 + //CleanUp:
1.1096 + if(_pleaseRemoveOsStream) {delete &os;}
1.1097 + }
1.1098 +};
1.1099 +
1.1100 +template<class T>
1.1101 +const int GraphToEps<T>::INTERPOL_PREC = 20;
1.1102 +template<class T>
1.1103 +const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
1.1104 +template<class T>
1.1105 +const double GraphToEps<T>::A4WIDTH = 595.275590551181;
1.1106 +template<class T>
1.1107 +const double GraphToEps<T>::A4BORDER = 15;
1.1108 +
1.1109 +
1.1110 +///Generates an EPS file from a graph
1.1111 +
1.1112 +///\ingroup eps_io
1.1113 +///Generates an EPS file from a graph.
1.1114 +///\param g is a reference to the graph to be printed
1.1115 +///\param os is a reference to the output stream.
1.1116 +///By default it is <tt>std::cout</tt>
1.1117 +///
1.1118 +///This function also has a lot of
1.1119 +///\ref named-templ-func-param "named parameters",
1.1120 +///they are declared as the members of class \ref GraphToEps. The following
1.1121 +///example shows how to use these parameters.
1.1122 +///\code
1.1123 +/// graphToEps(g,os).scale(10).coords(coords)
1.1124 +/// .nodeScale(2).nodeSizes(sizes)
1.1125 +/// .arcWidthScale(.4).run();
1.1126 +///\endcode
1.1127 +///\warning Don't forget to put the \ref GraphToEps::run() "run()"
1.1128 +///to the end of the parameter list.
1.1129 +///\sa GraphToEps
1.1130 +///\sa graphToEps(G &g, const char *file_name)
1.1131 +template<class G>
1.1132 +GraphToEps<DefaultGraphToEpsTraits<G> >
1.1133 +graphToEps(G &g, std::ostream& os=std::cout)
1.1134 +{
1.1135 + return
1.1136 + GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
1.1137 +}
1.1138 +
1.1139 +///Generates an EPS file from a graph
1.1140 +
1.1141 +///\ingroup eps_io
1.1142 +///This function does the same as
1.1143 +///\ref graphToEps(G &g,std::ostream& os)
1.1144 +///but it writes its output into the file \c file_name
1.1145 +///instead of a stream.
1.1146 +///\sa graphToEps(G &g, std::ostream& os)
1.1147 +template<class G>
1.1148 +GraphToEps<DefaultGraphToEpsTraits<G> >
1.1149 +graphToEps(G &g,const char *file_name)
1.1150 +{
1.1151 + return GraphToEps<DefaultGraphToEpsTraits<G> >
1.1152 + (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
1.1153 +}
1.1154 +
1.1155 +///Generates an EPS file from a graph
1.1156 +
1.1157 +///\ingroup eps_io
1.1158 +///This function does the same as
1.1159 +///\ref graphToEps(G &g,std::ostream& os)
1.1160 +///but it writes its output into the file \c file_name
1.1161 +///instead of a stream.
1.1162 +///\sa graphToEps(G &g, std::ostream& os)
1.1163 +template<class G>
1.1164 +GraphToEps<DefaultGraphToEpsTraits<G> >
1.1165 +graphToEps(G &g,const std::string& file_name)
1.1166 +{
1.1167 + return GraphToEps<DefaultGraphToEpsTraits<G> >
1.1168 + (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true));
1.1169 +}
1.1170 +
1.1171 +} //END OF NAMESPACE LEMON
1.1172 +
1.1173 +#endif // LEMON_GRAPH_TO_EPS_H