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