lemon/graph_to_eps.h
author deba
Wed, 01 Mar 2006 10:25:30 +0000
changeset 1991 d7442141d9ef
parent 1971 9a59a6cacfd9
child 1993 2115143eceea
permissions -rw-r--r--
The graph adadptors can be alteration observed.
In most cases it uses the adapted graph alteration notifiers.
Only special case is now the UndirGraphAdaptor, where
we have to proxy the signals from the graph.

The SubBidirGraphAdaptor is removed, because it doest not
gives more feature than the EdgeSubGraphAdaptor<UndirGraphAdaptor<Graph>>.

The ResGraphAdaptor is based on this composition.
alpar@1073
     1
/* -*- C++ -*-
alpar@1073
     2
 *
alpar@1956
     3
 * This file is a part of LEMON, a generic C++ optimization library
alpar@1956
     4
 *
alpar@1956
     5
 * Copyright (C) 2003-2006
alpar@1956
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1359
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@1073
     8
 *
alpar@1073
     9
 * Permission to use, modify and distribute this software is granted
alpar@1073
    10
 * provided that this copyright notice appears in all copies. For
alpar@1073
    11
 * precise terms see the accompanying LICENSE file.
alpar@1073
    12
 *
alpar@1073
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@1073
    14
 * express or implied, and with no claim as to its suitability for any
alpar@1073
    15
 * purpose.
alpar@1073
    16
 *
alpar@1073
    17
 */
alpar@1073
    18
alpar@1073
    19
#ifndef LEMON_GRAPH_TO_EPS_H
alpar@1073
    20
#define LEMON_GRAPH_TO_EPS_H
alpar@1073
    21
alpar@1108
    22
#include <sys/time.h>
alpar@1108
    23
alpar@1073
    24
#include<iostream>
alpar@1073
    25
#include<fstream>
alpar@1073
    26
#include<sstream>
alpar@1073
    27
#include<algorithm>
alpar@1073
    28
#include<vector>
alpar@1073
    29
deba@1417
    30
#include <ctime>
deba@1417
    31
#include <cmath>
deba@1417
    32
alpar@1234
    33
#include<lemon/invalid.h>
alpar@1073
    34
#include<lemon/xy.h>
alpar@1073
    35
#include<lemon/maps.h>
alpar@1971
    36
#include<lemon/color.h>
alpar@1073
    37
#include<lemon/bezier.h>
alpar@1073
    38
deba@1417
    39
alpar@1287
    40
///\ingroup io_group
alpar@1073
    41
///\file
alpar@1073
    42
///\brief Simple graph drawer
alpar@1073
    43
///
alpar@1073
    44
///\author Alpar Juttner
alpar@1073
    45
alpar@1073
    46
namespace lemon {
alpar@1073
    47
alpar@1673
    48
template<class MT>
alpar@1673
    49
class _NegY {
alpar@1673
    50
public:
alpar@1673
    51
  typedef typename MT::Key Key;
alpar@1673
    52
  typedef typename MT::Value Value;
alpar@1673
    53
  const MT &map;
alpar@1673
    54
  int yscale;
alpar@1673
    55
  _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
alpar@1673
    56
  Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
alpar@1673
    57
};
alpar@1673
    58
alpar@1073
    59
///Default traits class of \ref GraphToEps
alpar@1073
    60
alpar@1073
    61
///Default traits class of \ref GraphToEps
alpar@1073
    62
///
alpar@1073
    63
///\c G is the type of the underlying graph.
alpar@1073
    64
template<class G>
alpar@1073
    65
struct DefaultGraphToEpsTraits
alpar@1073
    66
{
alpar@1073
    67
  typedef G Graph;
alpar@1073
    68
  typedef typename Graph::Node Node;
alpar@1073
    69
  typedef typename Graph::NodeIt NodeIt;
alpar@1073
    70
  typedef typename Graph::Edge Edge;
alpar@1073
    71
  typedef typename Graph::EdgeIt EdgeIt;
alpar@1073
    72
  typedef typename Graph::InEdgeIt InEdgeIt;
alpar@1073
    73
  typedef typename Graph::OutEdgeIt OutEdgeIt;
alpar@1073
    74
  
alpar@1073
    75
alpar@1073
    76
  const Graph &g;
alpar@1073
    77
alpar@1073
    78
  std::ostream& os;
alpar@1073
    79
  
alpar@1673
    80
  typedef ConstMap<typename Graph::Node,xy<double> > CoordsMapType;
alpar@1673
    81
  CoordsMapType _coords;
alpar@1073
    82
  ConstMap<typename Graph::Node,double > _nodeSizes;
alpar@1086
    83
  ConstMap<typename Graph::Node,int > _nodeShapes;
alpar@1073
    84
alpar@1073
    85
  ConstMap<typename Graph::Node,Color > _nodeColors;
alpar@1073
    86
  ConstMap<typename Graph::Edge,Color > _edgeColors;
alpar@1073
    87
alpar@1073
    88
  ConstMap<typename Graph::Edge,double > _edgeWidths;
alpar@1103
    89
alpar@1073
    90
  double _edgeWidthScale;
alpar@1073
    91
  
alpar@1073
    92
  double _nodeScale;
alpar@1073
    93
  double _xBorder, _yBorder;
alpar@1073
    94
  double _scale;
alpar@1073
    95
  double _nodeBorderQuotient;
alpar@1073
    96
  
alpar@1073
    97
  bool _drawArrows;
alpar@1073
    98
  double _arrowLength, _arrowWidth;
alpar@1073
    99
  
alpar@1073
   100
  bool _showNodes, _showEdges;
alpar@1073
   101
alpar@1073
   102
  bool _enableParallel;
alpar@1073
   103
  double _parEdgeDist;
alpar@1073
   104
alpar@1073
   105
  bool _showNodeText;
alpar@1073
   106
  ConstMap<typename Graph::Node,bool > _nodeTexts;  
alpar@1073
   107
  double _nodeTextSize;
alpar@1073
   108
alpar@1085
   109
  bool _showNodePsText;
alpar@1085
   110
  ConstMap<typename Graph::Node,bool > _nodePsTexts;  
alpar@1085
   111
  char *_nodePsTextsPreamble;
alpar@1085
   112
  
deba@1910
   113
  bool _undirected;
deba@1910
   114
alpar@1073
   115
  bool _pleaseRemoveOsStream;
alpar@1103
   116
alpar@1103
   117
  bool _scaleToA4;
alpar@1108
   118
alpar@1108
   119
  std::string _title;
alpar@1108
   120
  std::string _copyright;
alpar@1178
   121
alpar@1178
   122
  enum NodeTextColorType 
alpar@1178
   123
    { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
alpar@1178
   124
  ConstMap<typename Graph::Node,Color > _nodeTextColors;
alpar@1178
   125
alpar@1604
   126
  bool _autoNodeScale;
alpar@1604
   127
  bool _autoEdgeWidthScale;
alpar@1604
   128
alpar@1673
   129
  bool _negY;
alpar@1073
   130
  ///Constructor
alpar@1073
   131
alpar@1073
   132
  ///Constructor
alpar@1073
   133
  ///\param _g is a reference to the graph to be printed
alpar@1073
   134
  ///\param _os is a reference to the output stream.
alpar@1073
   135
  ///\param _os is a reference to the output stream.
alpar@1073
   136
  ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
alpar@1073
   137
  ///will be explicitly deallocated by the destructor.
alpar@1073
   138
  ///By default it is <tt>std::cout</tt>
alpar@1073
   139
  DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
alpar@1073
   140
			  bool _pros=false) :
alpar@1073
   141
    g(_g), os(_os),
alpar@1086
   142
    _coords(xy<double>(1,1)), _nodeSizes(1.0), _nodeShapes(0),
alpar@1073
   143
    _nodeColors(Color(1,1,1)), _edgeColors(Color(0,0,0)),
alpar@1073
   144
    _edgeWidths(1), _edgeWidthScale(0.3),
alpar@1073
   145
    _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
alpar@1073
   146
    _nodeBorderQuotient(.1),
alpar@1073
   147
    _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
alpar@1073
   148
    _showNodes(true), _showEdges(true),
alpar@1073
   149
    _enableParallel(false), _parEdgeDist(1),
alpar@1073
   150
    _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
alpar@1085
   151
    _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
deba@1910
   152
    _undirected(false),
alpar@1178
   153
    _pleaseRemoveOsStream(_pros), _scaleToA4(false),
alpar@1604
   154
    _nodeTextColorType(SAME_COL), _nodeTextColors(Color(0,0,0)),
alpar@1604
   155
    _autoNodeScale(false),
alpar@1673
   156
    _autoEdgeWidthScale(false),
alpar@1673
   157
    _negY(false)
alpar@1178
   158
  {}
alpar@1073
   159
};
alpar@1073
   160
alpar@1073
   161
///Helper class to implement the named parameters of \ref graphToEps()
alpar@1073
   162
alpar@1073
   163
///Helper class to implement the named parameters of \ref graphToEps()
alpar@1073
   164
///\todo Is 'helper class' a good name for this?
alpar@1073
   165
///
alpar@1103
   166
///\todo Follow PostScript's DSC.
alpar@1107
   167
/// Use own dictionary.
alpar@1107
   168
///\todo Useful new features.
alpar@1107
   169
/// - Linestyles: dotted, dashed etc.
alpar@1107
   170
/// - A second color and percent value for the lines.
alpar@1073
   171
template<class T> class GraphToEps : public T 
alpar@1073
   172
{
alpar@1234
   173
  // Can't believe it is required by the C++ standard
alpar@1234
   174
  using T::g;
alpar@1234
   175
  using T::os;
alpar@1234
   176
alpar@1234
   177
  using T::_coords;
alpar@1234
   178
  using T::_nodeSizes;
alpar@1234
   179
  using T::_nodeShapes;
alpar@1234
   180
  using T::_nodeColors;
alpar@1234
   181
  using T::_edgeColors;
alpar@1234
   182
  using T::_edgeWidths;
alpar@1234
   183
alpar@1234
   184
  using T::_edgeWidthScale;
alpar@1234
   185
  using T::_nodeScale;
alpar@1234
   186
  using T::_xBorder;
alpar@1234
   187
  using T::_yBorder;
alpar@1234
   188
  using T::_scale;
alpar@1234
   189
  using T::_nodeBorderQuotient;
alpar@1234
   190
  
alpar@1234
   191
  using T::_drawArrows;
alpar@1234
   192
  using T::_arrowLength;
alpar@1234
   193
  using T::_arrowWidth;
alpar@1234
   194
  
alpar@1234
   195
  using T::_showNodes;
alpar@1234
   196
  using T::_showEdges;
alpar@1234
   197
alpar@1234
   198
  using T::_enableParallel;
alpar@1234
   199
  using T::_parEdgeDist;
alpar@1234
   200
alpar@1234
   201
  using T::_showNodeText;
alpar@1234
   202
  using T::_nodeTexts;  
alpar@1234
   203
  using T::_nodeTextSize;
alpar@1234
   204
alpar@1234
   205
  using T::_showNodePsText;
alpar@1234
   206
  using T::_nodePsTexts;  
alpar@1234
   207
  using T::_nodePsTextsPreamble;
alpar@1234
   208
  
deba@1910
   209
  using T::_undirected;
deba@1910
   210
alpar@1234
   211
  using T::_pleaseRemoveOsStream;
alpar@1234
   212
alpar@1234
   213
  using T::_scaleToA4;
alpar@1234
   214
alpar@1234
   215
  using T::_title;
alpar@1234
   216
  using T::_copyright;
alpar@1234
   217
alpar@1234
   218
  using T::NodeTextColorType;
alpar@1234
   219
  using T::CUST_COL;
alpar@1234
   220
  using T::DIST_COL;
alpar@1234
   221
  using T::DIST_BW;
alpar@1234
   222
  using T::_nodeTextColorType;
alpar@1234
   223
  using T::_nodeTextColors;
alpar@1604
   224
alpar@1604
   225
  using T::_autoNodeScale;
alpar@1604
   226
  using T::_autoEdgeWidthScale;
alpar@1604
   227
deba@1676
   228
  using T::_negY;
deba@1676
   229
alpar@1234
   230
  // dradnats ++C eht yb deriuqer si ti eveileb t'naC
alpar@1234
   231
alpar@1073
   232
  typedef typename T::Graph Graph;
alpar@1073
   233
  typedef typename Graph::Node Node;
alpar@1073
   234
  typedef typename Graph::NodeIt NodeIt;
alpar@1073
   235
  typedef typename Graph::Edge Edge;
alpar@1073
   236
  typedef typename Graph::EdgeIt EdgeIt;
alpar@1073
   237
  typedef typename Graph::InEdgeIt InEdgeIt;
alpar@1073
   238
  typedef typename Graph::OutEdgeIt OutEdgeIt;
alpar@1073
   239
alpar@1494
   240
  static const int INTERPOL_PREC;
alpar@1494
   241
  static const double A4HEIGHT;
alpar@1494
   242
  static const double A4WIDTH;
alpar@1494
   243
  static const double A4BORDER;
alpar@1087
   244
alpar@1073
   245
  bool dontPrint;
alpar@1073
   246
alpar@1107
   247
public:
alpar@1107
   248
  ///Node shapes
alpar@1107
   249
alpar@1107
   250
  ///Node shapes
alpar@1107
   251
  ///
alpar@1107
   252
  enum NodeShapes { 
alpar@1107
   253
    /// = 0
alpar@1107
   254
    ///\image html nodeshape_0.png
alpar@1107
   255
    ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm
alpar@1107
   256
    CIRCLE=0, 
alpar@1107
   257
    /// = 1
alpar@1107
   258
    ///\image html nodeshape_1.png
alpar@1107
   259
    ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm
alpar@1107
   260
    ///
alpar@1107
   261
    SQUARE=1, 
alpar@1107
   262
    /// = 2
alpar@1107
   263
    ///\image html nodeshape_2.png
alpar@1107
   264
    ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm
alpar@1107
   265
    ///
alpar@1907
   266
    DIAMOND=2,
alpar@1907
   267
    /// = 3
alpar@1907
   268
    ///\image html nodeshape_3.png
alpar@1907
   269
    ///\image latex nodeshape_2.eps "MALE shape (4)" width=2cm
alpar@1907
   270
    ///
alpar@1907
   271
    MALE=3,
alpar@1907
   272
    /// = 4
alpar@1907
   273
    ///\image html nodeshape_4.png
alpar@1907
   274
    ///\image latex nodeshape_2.eps "FEMALE shape (4)" width=2cm
alpar@1907
   275
    ///
alpar@1907
   276
    FEMALE=4
alpar@1107
   277
  };
alpar@1107
   278
alpar@1107
   279
private:
alpar@1073
   280
  class edgeLess {
alpar@1073
   281
    const Graph &g;
alpar@1073
   282
  public:
alpar@1073
   283
    edgeLess(const Graph &_g) : g(_g) {}
alpar@1073
   284
    bool operator()(Edge a,Edge b) const 
alpar@1073
   285
    {
alpar@1367
   286
      Node ai=std::min(g.source(a),g.target(a));
alpar@1367
   287
      Node aa=std::max(g.source(a),g.target(a));
alpar@1367
   288
      Node bi=std::min(g.source(b),g.target(b));
alpar@1367
   289
      Node ba=std::max(g.source(b),g.target(b));
alpar@1073
   290
      return ai<bi ||
alpar@1073
   291
	(ai==bi && (aa < ba || 
alpar@1073
   292
		    (aa==ba && ai==g.source(a) && bi==g.target(b))));
alpar@1073
   293
    }
alpar@1073
   294
  };
alpar@1073
   295
  bool isParallel(Edge e,Edge f) const
alpar@1073
   296
  {
alpar@1234
   297
    return (g.source(e)==g.source(f)&&
alpar@1234
   298
	    g.target(e)==g.target(f)) ||
alpar@1234
   299
      (g.source(e)==g.target(f)&&
alpar@1234
   300
       g.target(e)==g.source(f));
alpar@1073
   301
  }
alpar@1178
   302
  template<class TT>
alpar@1178
   303
  static std::string psOut(const xy<TT> &p) 
alpar@1073
   304
    {
alpar@1073
   305
      std::ostringstream os;	
alpar@1073
   306
      os << p.x << ' ' << p.y;
alpar@1073
   307
      return os.str();
alpar@1073
   308
    }
alpar@1178
   309
  static std::string psOut(const Color &c) 
alpar@1178
   310
    {
alpar@1178
   311
      std::ostringstream os;	
alpar@1575
   312
      os << c.red() << ' ' << c.green() << ' ' << c.blue();
alpar@1178
   313
      return os.str();
alpar@1178
   314
    }
alpar@1073
   315
  
alpar@1073
   316
public:
alpar@1073
   317
  GraphToEps(const T &t) : T(t), dontPrint(false) {};
alpar@1073
   318
  
alpar@1073
   319
  template<class X> struct CoordsTraits : public T {
alpar@1673
   320
  typedef X CoordsMapType;
alpar@1073
   321
    const X &_coords;
alpar@1073
   322
    CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
alpar@1073
   323
  };
alpar@1073
   324
  ///Sets the map of the node coordinates
alpar@1073
   325
alpar@1073
   326
  ///Sets the map of the node coordinates.
alpar@1103
   327
  ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values. 
alpar@1073
   328
  template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
alpar@1073
   329
    dontPrint=true;
alpar@1073
   330
    return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
alpar@1073
   331
  }
alpar@1073
   332
  template<class X> struct NodeSizesTraits : public T {
alpar@1073
   333
    const X &_nodeSizes;
alpar@1073
   334
    NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {}
alpar@1073
   335
  };
alpar@1073
   336
  ///Sets the map of the node sizes
alpar@1073
   337
alpar@1073
   338
  ///Sets the map of the node sizes
alpar@1073
   339
  ///\param x must be a node map with \c double (or convertible) values. 
alpar@1073
   340
  template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x)
alpar@1073
   341
  {
alpar@1073
   342
    dontPrint=true;
alpar@1073
   343
    return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x));
alpar@1073
   344
  }
alpar@1086
   345
  template<class X> struct NodeShapesTraits : public T {
alpar@1086
   346
    const X &_nodeShapes;
alpar@1086
   347
    NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {}
alpar@1086
   348
  };
alpar@1086
   349
  ///Sets the map of the node shapes
alpar@1086
   350
alpar@1107
   351
  ///Sets the map of the node shapes.
alpar@1107
   352
  ///The availabe shape values
alpar@1107
   353
  ///can be found in \ref NodeShapes "enum NodeShapes".
alpar@1086
   354
  ///\param x must be a node map with \c int (or convertible) values. 
alpar@1107
   355
  ///\sa NodeShapes
alpar@1086
   356
  template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x)
alpar@1086
   357
  {
alpar@1086
   358
    dontPrint=true;
alpar@1086
   359
    return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x));
alpar@1086
   360
  }
alpar@1073
   361
  template<class X> struct NodeTextsTraits : public T {
alpar@1073
   362
    const X &_nodeTexts;
alpar@1073
   363
    NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {}
alpar@1073
   364
  };
alpar@1073
   365
  ///Sets the text printed on the nodes
alpar@1073
   366
alpar@1073
   367
  ///Sets the text printed on the nodes
alpar@1073
   368
  ///\param x must be a node map with type that can be pushed to a standard
alpar@1073
   369
  ///ostream. 
alpar@1073
   370
  template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x)
alpar@1073
   371
  {
alpar@1073
   372
    dontPrint=true;
alpar@1073
   373
    _showNodeText=true;
alpar@1073
   374
    return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x));
alpar@1073
   375
  }
alpar@1085
   376
  template<class X> struct NodePsTextsTraits : public T {
alpar@1085
   377
    const X &_nodePsTexts;
alpar@1085
   378
    NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {}
alpar@1085
   379
  };
alpar@1085
   380
  ///Inserts a PostScript block to the nodes
alpar@1085
   381
alpar@1085
   382
  ///With this command it is possible to insert a verbatim PostScript
alpar@1085
   383
  ///block to the nodes.
alpar@1085
   384
  ///The PS current point will be moved to the centre of the node before
alpar@1085
   385
  ///the PostScript block inserted.
alpar@1085
   386
  ///
alpar@1573
   387
  ///Before and after the block a newline character is inserted so you
alpar@1085
   388
  ///don't have to bother with the separators.
alpar@1085
   389
  ///
alpar@1085
   390
  ///\param x must be a node map with type that can be pushed to a standard
alpar@1085
   391
  ///ostream.
alpar@1085
   392
  ///
alpar@1085
   393
  ///\sa nodePsTextsPreamble()
alpar@1085
   394
  ///\todo Offer the choise not to move to the centre but pass the coordinates
alpar@1085
   395
  ///to the Postscript block inserted.
alpar@1085
   396
  template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x)
alpar@1085
   397
  {
alpar@1085
   398
    dontPrint=true;
alpar@1085
   399
    _showNodePsText=true;
alpar@1085
   400
    return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x));
alpar@1085
   401
  }
alpar@1085
   402
  template<class X> struct EdgeWidthsTraits : public T {
alpar@1073
   403
    const X &_edgeWidths;
alpar@1073
   404
    EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {}
alpar@1073
   405
  };
alpar@1073
   406
  ///Sets the map of the edge widths
alpar@1073
   407
alpar@1073
   408
  ///Sets the map of the edge widths
alpar@1073
   409
  ///\param x must be a edge map with \c double (or convertible) values. 
alpar@1073
   410
  template<class X> GraphToEps<EdgeWidthsTraits<X> > edgeWidths(const X &x)
alpar@1073
   411
  {
alpar@1073
   412
    dontPrint=true;
alpar@1073
   413
    return GraphToEps<EdgeWidthsTraits<X> >(EdgeWidthsTraits<X>(*this,x));
alpar@1073
   414
  }
alpar@1073
   415
alpar@1073
   416
  template<class X> struct NodeColorsTraits : public T {
alpar@1073
   417
    const X &_nodeColors;
alpar@1073
   418
    NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {}
alpar@1073
   419
  };
alpar@1073
   420
  ///Sets the map of the node colors
alpar@1073
   421
alpar@1073
   422
  ///Sets the map of the node colors
alpar@1573
   423
  ///\param x must be a node map with \ref Color values.
alpar@1573
   424
  ///
alpar@1573
   425
  ///\sa ColorSet
alpar@1073
   426
  template<class X> GraphToEps<NodeColorsTraits<X> >
alpar@1073
   427
  nodeColors(const X &x)
alpar@1073
   428
  {
alpar@1073
   429
    dontPrint=true;
alpar@1073
   430
    return GraphToEps<NodeColorsTraits<X> >(NodeColorsTraits<X>(*this,x));
alpar@1073
   431
  }
alpar@1178
   432
  template<class X> struct NodeTextColorsTraits : public T {
alpar@1178
   433
    const X &_nodeTextColors;
alpar@1178
   434
    NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {}
alpar@1178
   435
  };
alpar@1178
   436
  ///Sets the map of the node text colors
alpar@1178
   437
alpar@1178
   438
  ///Sets the map of the node text colors
alpar@1178
   439
  ///\param x must be a node map with \ref Color values. 
alpar@1573
   440
  ///
alpar@1573
   441
  ///\sa ColorSet
alpar@1178
   442
  template<class X> GraphToEps<NodeTextColorsTraits<X> >
alpar@1178
   443
  nodeTextColors(const X &x)
alpar@1178
   444
  {
alpar@1178
   445
    dontPrint=true;
alpar@1178
   446
    _nodeTextColorType=CUST_COL;
alpar@1178
   447
    return GraphToEps<NodeTextColorsTraits<X> >
alpar@1178
   448
      (NodeTextColorsTraits<X>(*this,x));
alpar@1178
   449
  }
alpar@1073
   450
  template<class X> struct EdgeColorsTraits : public T {
alpar@1073
   451
    const X &_edgeColors;
alpar@1073
   452
    EdgeColorsTraits(const T &t,const X &x) : T(t), _edgeColors(x) {}
alpar@1073
   453
  };
alpar@1073
   454
  ///Sets the map of the edge colors
alpar@1073
   455
alpar@1073
   456
  ///Sets the map of the edge colors
alpar@1073
   457
  ///\param x must be a edge map with \ref Color values. 
alpar@1573
   458
  ///
alpar@1573
   459
  ///\sa ColorSet
alpar@1073
   460
  template<class X> GraphToEps<EdgeColorsTraits<X> >
alpar@1073
   461
  edgeColors(const X &x)
alpar@1073
   462
  {
alpar@1073
   463
    dontPrint=true;
alpar@1073
   464
    return GraphToEps<EdgeColorsTraits<X> >(EdgeColorsTraits<X>(*this,x));
alpar@1073
   465
  }
alpar@1073
   466
  ///Sets a global scale factor for node sizes
alpar@1073
   467
alpar@1604
   468
  ///Sets a global scale factor for node sizes.
alpar@1604
   469
  /// 
alpar@1604
   470
  /// If nodeSizes() is not given, this function simply sets the node
alpar@1604
   471
  /// sizes to \c d.  If nodeSizes() is given, but
alpar@1604
   472
  /// autoNodeScale() is not, then the node size given by
alpar@1604
   473
  /// nodeSizes() will be multiplied by the value \c d.
alpar@1604
   474
  /// If both nodeSizes() and autoNodeScale() are used, then the
alpar@1604
   475
  /// node sizes will be scaled in such a way that the greatest size will be
alpar@1604
   476
  /// equal to \c d.
alpar@1604
   477
  GraphToEps<T> &nodeScale(double d) {_nodeScale=d;return *this;}
alpar@1604
   478
  ///Turns on/off the automatic node width scaling.
alpar@1604
   479
alpar@1604
   480
  ///Turns on/off the automatic node width scaling.
alpar@1073
   481
  ///
alpar@1604
   482
  ///\sa nodeScale()
alpar@1604
   483
  ///
alpar@1604
   484
  GraphToEps<T> &autoNodeScale(bool b=true) {
alpar@1604
   485
    _autoNodeScale=b;return *this;
alpar@1604
   486
  }
alpar@1673
   487
alpar@1673
   488
  ///Negates the Y coordinates.
alpar@1673
   489
alpar@1673
   490
  ///Negates the Y coordinates.
alpar@1673
   491
  ///
alpar@1673
   492
  ///\todo More docs.
alpar@1673
   493
  ///
alpar@1673
   494
  GraphToEps<T> &negateY(bool b=true) {
alpar@1673
   495
    _negY=b;return *this;
alpar@1673
   496
  }
alpar@1673
   497
alpar@1073
   498
  ///Sets a global scale factor for edge widths
alpar@1073
   499
alpar@1604
   500
  /// Sets a global scale factor for edge widths.
alpar@1073
   501
  ///
alpar@1604
   502
  /// If edgeWidths() is not given, this function simply sets the edge
alpar@1604
   503
  /// widths to \c d.  If edgeWidths() is given, but
alpar@1604
   504
  /// autoEdgeWidthScale() is not, then the edge withs given by
alpar@1604
   505
  /// edgeWidths() will be multiplied by the value \c d.
alpar@1604
   506
  /// If both edgeWidths() and autoEdgeWidthScale() are used, then the
alpar@1604
   507
  /// edge withs will be scaled in such a way that the greatest width will be
alpar@1604
   508
  /// equal to \c d.
alpar@1073
   509
  GraphToEps<T> &edgeWidthScale(double d) {_edgeWidthScale=d;return *this;}
alpar@1604
   510
  ///Turns on/off the automatic edge width scaling.
alpar@1604
   511
alpar@1604
   512
  ///Turns on/off the automatic edge width scaling.
alpar@1604
   513
  ///
alpar@1604
   514
  ///\sa edgeWidthScale()
alpar@1604
   515
  ///
alpar@1604
   516
  GraphToEps<T> &autoEdgeWidthScale(bool b=true) {
alpar@1604
   517
    _autoEdgeWidthScale=b;return *this;
alpar@1604
   518
  }
alpar@1073
   519
  ///Sets a global scale factor for the whole picture
alpar@1073
   520
alpar@1073
   521
  ///Sets a global scale factor for the whole picture
alpar@1073
   522
  ///
alpar@1604
   523
alpar@1073
   524
  GraphToEps<T> &scale(double d) {_scale=d;return *this;}
alpar@1073
   525
  ///Sets the width of the border around the picture
alpar@1073
   526
alpar@1073
   527
  ///Sets the width of the border around the picture
alpar@1073
   528
  ///
alpar@1073
   529
  GraphToEps<T> &border(double b) {_xBorder=_yBorder=b;return *this;}
alpar@1073
   530
  ///Sets the width of the border around the picture
alpar@1073
   531
alpar@1073
   532
  ///Sets the width of the border around the picture
alpar@1073
   533
  ///
alpar@1073
   534
  GraphToEps<T> &border(double x, double y) {
alpar@1073
   535
    _xBorder=x;_yBorder=y;return *this;
alpar@1073
   536
  }
alpar@1073
   537
  ///Sets whether to draw arrows
alpar@1073
   538
alpar@1073
   539
  ///Sets whether to draw arrows
alpar@1073
   540
  ///
alpar@1073
   541
  GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;}
alpar@1073
   542
  ///Sets the length of the arrowheads
alpar@1073
   543
alpar@1073
   544
  ///Sets the length of the arrowheads
alpar@1073
   545
  ///
alpar@1073
   546
  GraphToEps<T> &arrowLength(double d) {_arrowLength*=d;return *this;}
alpar@1073
   547
  ///Sets the width of the arrowheads
alpar@1073
   548
alpar@1073
   549
  ///Sets the width of the arrowheads
alpar@1073
   550
  ///
alpar@1073
   551
  GraphToEps<T> &arrowWidth(double d) {_arrowWidth*=d;return *this;}
alpar@1073
   552
  
alpar@1103
   553
  ///Scales the drawing to fit to A4 page
alpar@1103
   554
alpar@1103
   555
  ///Scales the drawing to fit to A4 page
alpar@1103
   556
  ///
alpar@1103
   557
  GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
alpar@1103
   558
  
alpar@1073
   559
  ///Enables parallel edges
alpar@1073
   560
alpar@1073
   561
  ///Enables parallel edges
alpar@1073
   562
  GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
alpar@1073
   563
  
alpar@1073
   564
  ///Sets the distance 
alpar@1073
   565
  
alpar@1073
   566
  ///Sets the distance 
alpar@1073
   567
  ///
alpar@1073
   568
  GraphToEps<T> &parEdgeDist(double d) {_parEdgeDist*=d;return *this;}
alpar@1073
   569
  
alpar@1073
   570
  ///Hides the edges
alpar@1073
   571
  
alpar@1073
   572
  ///Hides the edges
alpar@1073
   573
  ///
alpar@1073
   574
  GraphToEps<T> &hideEdges(bool b=true) {_showEdges=!b;return *this;}
alpar@1073
   575
  ///Hides the nodes
alpar@1073
   576
  
alpar@1073
   577
  ///Hides the nodes
alpar@1073
   578
  ///
alpar@1073
   579
  GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
alpar@1073
   580
  
alpar@1073
   581
  ///Sets the size of the node texts
alpar@1073
   582
  
alpar@1073
   583
  ///Sets the size of the node texts
alpar@1073
   584
  ///
alpar@1073
   585
  GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
alpar@1178
   586
alpar@1178
   587
  ///Sets the color of the node texts to be different from the node color
alpar@1178
   588
alpar@1178
   589
  ///Sets the color of the node texts to be as different from the node color
alpar@1178
   590
  ///as it is possible
alpar@1573
   591
  ///
alpar@1178
   592
  GraphToEps<T> &distantColorNodeTexts()
alpar@1178
   593
  {_nodeTextColorType=DIST_COL;return *this;}
alpar@1178
   594
  ///Sets the color of the node texts to be black or white and always visible.
alpar@1178
   595
alpar@1178
   596
  ///Sets the color of the node texts to be black or white according to
alpar@1178
   597
  ///which is more 
alpar@1178
   598
  ///different from the node color
alpar@1178
   599
  ///
alpar@1178
   600
  GraphToEps<T> &distantBWNodeTexts()
alpar@1178
   601
  {_nodeTextColorType=DIST_BW;return *this;}
alpar@1178
   602
alpar@1085
   603
  ///Gives a preamble block for node Postscript block.
alpar@1085
   604
  
alpar@1085
   605
  ///Gives a preamble block for node Postscript block.
alpar@1085
   606
  ///
alpar@1085
   607
  ///\sa nodePsTexts()
alpar@1085
   608
  GraphToEps<T> & nodePsTextsPreamble(const char *str) {
alpar@1234
   609
    _nodePsTextsPreamble=str ;return *this;
alpar@1085
   610
  }
alpar@1073
   611
  ///Sets whether the the graph is undirected
alpar@1073
   612
alpar@1073
   613
  ///Sets whether the the graph is undirected
alpar@1073
   614
  ///
deba@1910
   615
  GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
deba@1910
   616
alpar@1073
   617
  ///Sets whether the the graph is directed
alpar@1073
   618
alpar@1073
   619
  ///Sets whether the the graph is directed.
alpar@1073
   620
  ///Use it to show the undirected edges as a pair of directed ones.
deba@1910
   621
  GraphToEps<T> &bidir(bool b=true) {_undirected=!b;return *this;}
alpar@1086
   622
alpar@1108
   623
  ///Sets the title.
alpar@1108
   624
alpar@1108
   625
  ///Sets the title of the generated image,
alpar@1108
   626
  ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
alpar@1108
   627
  ///the EPS file.
alpar@1108
   628
  GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
alpar@1108
   629
  ///Sets the copyright statement.
alpar@1108
   630
alpar@1108
   631
  ///Sets the copyright statement of the generated image,
alpar@1108
   632
  ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
alpar@1108
   633
  ///the EPS file.
alpar@1108
   634
  ///\todo Multiline copyright notice could be supported.
alpar@1108
   635
  GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
alpar@1108
   636
alpar@1086
   637
protected:
alpar@1086
   638
  bool isInsideNode(xy<double> p, double r,int t) 
alpar@1086
   639
  {
alpar@1086
   640
    switch(t) {
alpar@1086
   641
    case CIRCLE:
alpar@1907
   642
    case MALE:
alpar@1907
   643
    case FEMALE:
alpar@1086
   644
      return p.normSquare()<=r*r;
alpar@1086
   645
    case SQUARE:
alpar@1086
   646
      return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
alpar@1088
   647
    case DIAMOND:
alpar@1088
   648
      return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
alpar@1086
   649
    }
alpar@1086
   650
    return false;
alpar@1086
   651
  }
alpar@1086
   652
alpar@1086
   653
public:
alpar@1091
   654
  ~GraphToEps() { }
alpar@1091
   655
  
alpar@1091
   656
  ///Draws the graph.
alpar@1091
   657
alpar@1091
   658
  ///Like other functions using
alpar@1091
   659
  ///\ref named-templ-func-param "named template parameters",
alpar@1091
   660
  ///this function calles the algorithm itself, i.e. in this case
alpar@1091
   661
  ///it draws the graph.
alpar@1091
   662
  void run() {
alpar@1073
   663
    if(dontPrint) return;
alpar@1073
   664
    
alpar@1673
   665
    _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
alpar@1673
   666
alpar@1073
   667
    os << "%!PS-Adobe-2.0 EPSF-2.0\n";
alpar@1108
   668
    if(_title.size()>0) os << "%%Title: " << _title << '\n';
alpar@1108
   669
     if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
alpar@1107
   670
//        << "%%Copyright: XXXX\n"
alpar@1575
   671
    os << "%%Creator: LEMON, graphToEps()\n";
alpar@1108
   672
    
alpar@1108
   673
    {
alpar@1108
   674
      char cbuf[50];
alpar@1108
   675
      timeval tv;
alpar@1108
   676
      gettimeofday(&tv, 0);
alpar@1108
   677
      ctime_r(&tv.tv_sec,cbuf);
alpar@1108
   678
      os << "%%CreationDate: " << cbuf;
alpar@1108
   679
    }
alpar@1604
   680
alpar@1604
   681
    if (_autoEdgeWidthScale) {
alpar@1604
   682
      double max_w=0;
alpar@1604
   683
      for(EdgeIt e(g);e!=INVALID;++e)
alpar@1604
   684
	max_w=std::max(double(_edgeWidths[e]),max_w);
alpar@1604
   685
      ///\todo better 'epsilon' would be nice here.
alpar@1604
   686
      if(max_w>1e-9) {
alpar@1604
   687
	_edgeWidthScale/=max_w;
alpar@1604
   688
      }
alpar@1604
   689
    }
alpar@1604
   690
alpar@1604
   691
    if (_autoNodeScale) {
alpar@1604
   692
      double max_s=0;
alpar@1604
   693
      for(NodeIt n(g);n!=INVALID;++n)
alpar@1604
   694
	max_s=std::max(double(_nodeSizes[n]),max_s);
alpar@1604
   695
      ///\todo better 'epsilon' would be nice here.
alpar@1604
   696
      if(max_s>1e-9) {
alpar@1604
   697
	_nodeScale/=max_s;
alpar@1604
   698
      }
alpar@1604
   699
    }
alpar@1604
   700
alpar@1604
   701
alpar@1073
   702
    BoundingBox<double> bb;
alpar@1494
   703
    ///\bug: Chech whether the graph is empty.
alpar@1073
   704
    for(NodeIt n(g);n!=INVALID;++n) {
alpar@1073
   705
      double ns=_nodeSizes[n]*_nodeScale;
alpar@1073
   706
      xy<double> p(ns,ns);
alpar@1907
   707
      switch(_nodeShapes[n]) {
alpar@1907
   708
      case CIRCLE:
alpar@1907
   709
      case SQUARE:
alpar@1907
   710
      case DIAMOND:
alpar@1907
   711
	bb.add(p+mycoords[n]);
alpar@1907
   712
	bb.add(-p+mycoords[n]);
alpar@1907
   713
	break;
alpar@1907
   714
      case MALE:
alpar@1907
   715
	bb.add(-p+mycoords[n]);
alpar@1936
   716
	bb.add(xy<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
alpar@1907
   717
	break;
alpar@1907
   718
      case FEMALE:
alpar@1907
   719
	bb.add(p+mycoords[n]);
alpar@1907
   720
	bb.add(xy<double>(-ns,-3.01*ns)+mycoords[n]);
alpar@1907
   721
	break;
alpar@1907
   722
      }
deba@1539
   723
    }
deba@1539
   724
    if (bb.empty()) {
deba@1539
   725
      bb = BoundingBox<double>(xy<double>(0,0));
deba@1539
   726
    }
alpar@1604
   727
    
alpar@1108
   728
    if(_scaleToA4)
alpar@1108
   729
      os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
alpar@1930
   730
    else {
alpar@1930
   731
      //Rescale so that BoundingBox won't be neither to big nor too small.
alpar@1930
   732
      while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10;
alpar@1930
   733
      while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10;
alpar@1930
   734
    
alpar@1930
   735
      os << "%%BoundingBox: "
alpar@1930
   736
	 << int(floor(bb.left()   * _scale - _xBorder)) << ' '
alpar@1930
   737
	 << int(floor(bb.bottom() * _scale - _yBorder)) << ' '
alpar@1930
   738
	 << int(ceil(bb.right()  * _scale + _xBorder)) << ' '
alpar@1930
   739
	 << int(ceil(bb.top()    * _scale + _yBorder)) << '\n';
alpar@1930
   740
    }
alpar@1108
   741
    
alpar@1107
   742
    os << "%%EndComments\n";
alpar@1107
   743
    
alpar@1073
   744
    //x1 y1 x2 y2 x3 y3 cr cg cb w
alpar@1073
   745
    os << "/lb { setlinewidth setrgbcolor newpath moveto\n"
alpar@1073
   746
       << "      4 2 roll 1 index 1 index curveto stroke } bind def\n";
alpar@1073
   747
    os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n";
alpar@1086
   748
    //x y r
alpar@1073
   749
    os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath } bind def\n";
alpar@1086
   750
    //x y r
alpar@1086
   751
    os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n"
alpar@1086
   752
       << "      2 index 1 index sub 2 index 2 index add lineto\n"
alpar@1086
   753
       << "      2 index 1 index sub 2 index 2 index sub lineto\n"
alpar@1086
   754
       << "      2 index 1 index add 2 index 2 index sub lineto\n"
alpar@1086
   755
       << "      closepath pop pop pop} bind def\n";
alpar@1088
   756
    //x y r
alpar@1088
   757
    os << "/di { newpath 2 index 1 index add 2 index moveto\n"
alpar@1088
   758
       << "      2 index             2 index 2 index add lineto\n"
alpar@1088
   759
       << "      2 index 1 index sub 2 index             lineto\n"
alpar@1088
   760
       << "      2 index             2 index 2 index sub lineto\n"
alpar@1088
   761
       << "      closepath pop pop pop} bind def\n";
alpar@1073
   762
    // x y r cr cg cb
alpar@1089
   763
    os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n"
alpar@1089
   764
       << "     setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
alpar@1073
   765
       << "   } bind def\n";
alpar@1089
   766
    os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n"
alpar@1089
   767
       << "     setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n"
alpar@1086
   768
       << "   } bind def\n";
alpar@1089
   769
    os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n"
alpar@1089
   770
       << "     setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n"
alpar@1088
   771
       << "   } bind def\n";
alpar@1907
   772
    os << "/nfemale { 0 0 0 setrgbcolor 3 index "
alpar@1907
   773
       << _nodeBorderQuotient/(1+_nodeBorderQuotient)
alpar@1907
   774
       << " 1.5 mul mul setlinewidth\n"
alpar@1907
   775
       << "  newpath 5 index 5 index moveto "
alpar@1907
   776
       << "5 index 5 index 5 index 3.01 mul sub\n"
alpar@1907
   777
       << "  lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub moveto\n"
alpar@1907
   778
       << "  5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto stroke\n"
alpar@1907
   779
       << "  5 index 5 index 5 index c fill\n"
alpar@1907
   780
       << "  setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
alpar@1907
   781
       << "  } bind def\n";
alpar@1907
   782
    os << "/nmale {\n"
alpar@1907
   783
       << "  0 0 0 setrgbcolor 3 index "
alpar@1907
   784
       << _nodeBorderQuotient/(1+_nodeBorderQuotient)
alpar@1907
   785
       <<" 1.5 mul mul setlinewidth\n"
alpar@1907
   786
       << "  newpath 5 index 5 index moveto\n"
alpar@1907
   787
       << "  5 index 4 index 1 mul 1.5 mul add\n"
alpar@1907
   788
       << "  5 index 5 index 3 sqrt 1.5 mul mul add\n"
alpar@1907
   789
       << "  1 index 1 index lineto\n"
alpar@1907
   790
       << "  1 index 1 index 7 index sub moveto\n"
alpar@1907
   791
       << "  1 index 1 index lineto\n"
alpar@1907
   792
       << "  exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n"
alpar@1907
   793
       << "  stroke\n"
alpar@1907
   794
       << "  5 index 5 index 5 index c fill\n"
alpar@1907
   795
       << "  setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n"
alpar@1907
   796
       << "  } bind def\n";
alpar@1907
   797
    
alpar@1907
   798
alpar@1073
   799
    os << "/arrl " << _arrowLength << " def\n";
alpar@1073
   800
    os << "/arrw " << _arrowWidth << " def\n";
alpar@1073
   801
    // l dx_norm dy_norm
alpar@1073
   802
    os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n";
alpar@1073
   803
    //len w dx_norm dy_norm x1 y1 cr cg cb
alpar@1073
   804
    os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n"
alpar@1073
   805
       << "       /w exch def /len exch def\n"
alpar@1073
   806
      //	 << "       0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke"
alpar@1073
   807
       << "       newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n"
alpar@1073
   808
       << "       len w sub arrl sub dx dy lrl\n"
alpar@1073
   809
       << "       arrw dy dx neg lrl\n"
alpar@1073
   810
       << "       dx arrl w add mul dy w 2 div arrw add mul sub\n"
alpar@1073
   811
       << "       dy arrl w add mul dx w 2 div arrw add mul add rlineto\n"
alpar@1073
   812
       << "       dx arrl w add mul neg dy w 2 div arrw add mul sub\n"
alpar@1073
   813
       << "       dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n"
alpar@1073
   814
       << "       arrw dy dx neg lrl\n"
alpar@1073
   815
       << "       len w sub arrl sub neg dx dy lrl\n"
alpar@1073
   816
       << "       closepath fill } bind def\n";
alpar@1073
   817
    os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n"
alpar@1073
   818
       << "         neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n";
alpar@1073
   819
alpar@1073
   820
    os << "\ngsave\n";
alpar@1103
   821
    if(_scaleToA4)
alpar@1103
   822
      if(bb.height()>bb.width()) {
deba@1470
   823
	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
alpar@1103
   824
		  (A4WIDTH-2*A4BORDER)/bb.width());
alpar@1103
   825
	os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
alpar@1103
   826
	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
alpar@1103
   827
	   << sc << " dup scale\n"
alpar@1103
   828
	   << -bb.left() << ' ' << -bb.bottom() << " translate\n";
alpar@1103
   829
      }
alpar@1103
   830
      else {
alpar@1103
   831
	//\todo Verify centering
deba@1470
   832
	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
alpar@1103
   833
		  (A4WIDTH-2*A4BORDER)/bb.height());
alpar@1103
   834
	os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
alpar@1103
   835
	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER  << " translate\n"
alpar@1103
   836
	   << sc << " dup scale\n90 rotate\n"
alpar@1103
   837
	   << -bb.left() << ' ' << -bb.top() << " translate\n";	
alpar@1103
   838
	}
alpar@1103
   839
    else if(_scale!=1.0) os << _scale << " dup scale\n";
alpar@1073
   840
    
alpar@1085
   841
    if(_showEdges) {
alpar@1085
   842
      os << "%Edges:\ngsave\n";      
alpar@1073
   843
      if(_enableParallel) {
alpar@1073
   844
	std::vector<Edge> el;
alpar@1073
   845
	for(EdgeIt e(g);e!=INVALID;++e)
alpar@1976
   846
	  if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
alpar@1976
   847
	     &&g.source(e)!=g.target(e))
alpar@1178
   848
	    el.push_back(e);
alpar@1642
   849
	std::sort(el.begin(),el.end(),edgeLess(g));
alpar@1073
   850
	
alpar@1073
   851
	typename std::vector<Edge>::iterator j;
alpar@1073
   852
	for(typename std::vector<Edge>::iterator i=el.begin();i!=el.end();i=j) {
alpar@1073
   853
	  for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ;
alpar@1073
   854
alpar@1073
   855
	  double sw=0;
alpar@1073
   856
	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
alpar@1073
   857
	    sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
alpar@1073
   858
	  sw-=_parEdgeDist;
alpar@1073
   859
	  sw/=-2.0;
alpar@1673
   860
	  xy<double> dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
deba@1417
   861
	  double l=std::sqrt(dvec.normSquare()); 
alpar@1360
   862
	  ///\todo better 'epsilon' would be nice here.
alpar@1366
   863
	  xy<double> d(dvec/std::max(l,1e-9));
alpar@1085
   864
 	  xy<double> m;
alpar@1673
   865
// 	  m=xy<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
alpar@1085
   866
alpar@1673
   867
//  	  m=xy<double>(mycoords[g.source(*i)])+
alpar@1085
   868
// 	    dvec*(double(_nodeSizes[g.source(*i)])/
alpar@1085
   869
// 	       (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
alpar@1085
   870
alpar@1673
   871
 	  m=xy<double>(mycoords[g.source(*i)])+
alpar@1085
   872
	    d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
alpar@1085
   873
alpar@1073
   874
	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
alpar@1073
   875
	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
alpar@1202
   876
	    xy<double> mm=m+rot90(d)*sw/.75;
alpar@1073
   877
	    if(_drawArrows) {
alpar@1086
   878
	      int node_shape;
alpar@1673
   879
	      xy<double> s=mycoords[g.source(*e)];
alpar@1673
   880
	      xy<double> t=mycoords[g.target(*e)];
alpar@1073
   881
	      double rn=_nodeSizes[g.target(*e)]*_nodeScale;
alpar@1086
   882
	      node_shape=_nodeShapes[g.target(*e)];
alpar@1085
   883
	      Bezier3 bez(s,mm,mm,t);
alpar@1073
   884
	      double t1=0,t2=1;
alpar@1087
   885
	      for(int i=0;i<INTERPOL_PREC;++i)
alpar@1086
   886
		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
alpar@1086
   887
		else t1=(t1+t2)/2;
alpar@1073
   888
	      xy<double> apoint=bez((t1+t2)/2);
alpar@1086
   889
	      rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
alpar@1073
   890
	      rn*=rn;
alpar@1086
   891
	      t2=(t1+t2)/2;t1=0;
alpar@1087
   892
	      for(int i=0;i<INTERPOL_PREC;++i)
alpar@1086
   893
		if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
alpar@1073
   894
		else t2=(t1+t2)/2;
alpar@1073
   895
	      xy<double> linend=bez((t1+t2)/2);	      
alpar@1073
   896
	      bez=bez.before((t1+t2)/2);
alpar@1086
   897
// 	      rn=_nodeSizes[g.source(*e)]*_nodeScale;
alpar@1086
   898
// 	      node_shape=_nodeShapes[g.source(*e)];
alpar@1086
   899
// 	      t1=0;t2=1;
alpar@1087
   900
// 	      for(int i=0;i<INTERPOL_PREC;++i)
alpar@1086
   901
// 		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2;
alpar@1086
   902
// 		else t2=(t1+t2)/2;
alpar@1086
   903
// 	      bez=bez.after((t1+t2)/2);
alpar@1073
   904
	      os << _edgeWidths[*e]*_edgeWidthScale << " setlinewidth "
alpar@1575
   905
		 << _edgeColors[*e].red() << ' '
alpar@1575
   906
		 << _edgeColors[*e].green() << ' '
alpar@1575
   907
		 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
alpar@1073
   908
		 << bez.p1.x << ' ' <<  bez.p1.y << " moveto\n"
alpar@1073
   909
		 << bez.p2.x << ' ' << bez.p2.y << ' '
alpar@1073
   910
		 << bez.p3.x << ' ' << bez.p3.y << ' '
alpar@1073
   911
		 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
alpar@1202
   912
	      xy<double> dd(rot90(linend-apoint));
alpar@1089
   913
	      dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
deba@1417
   914
		std::sqrt(dd.normSquare());
alpar@1073
   915
	      os << "newpath " << psOut(apoint) << " moveto "
alpar@1073
   916
		 << psOut(linend+dd) << " lineto "
alpar@1073
   917
		 << psOut(linend-dd) << " lineto closepath fill\n";
alpar@1073
   918
	    }
alpar@1073
   919
	    else {
alpar@1673
   920
	      os << mycoords[g.source(*e)].x << ' '
alpar@1673
   921
		 << mycoords[g.source(*e)].y << ' '
alpar@1085
   922
		 << mm.x << ' ' << mm.y << ' '
alpar@1673
   923
		 << mycoords[g.target(*e)].x << ' '
alpar@1673
   924
		 << mycoords[g.target(*e)].y << ' '
alpar@1575
   925
		 << _edgeColors[*e].red() << ' '
alpar@1575
   926
		 << _edgeColors[*e].green() << ' '
alpar@1575
   927
		 << _edgeColors[*e].blue() << ' '
alpar@1073
   928
		 << _edgeWidths[*e]*_edgeWidthScale << " lb\n";
alpar@1073
   929
	    }
alpar@1073
   930
	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0+_parEdgeDist;
alpar@1073
   931
	  }
alpar@1073
   932
	}
alpar@1073
   933
      }
alpar@1073
   934
      else for(EdgeIt e(g);e!=INVALID;++e)
alpar@1976
   935
	if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
alpar@1976
   936
	   &&g.source(e)!=g.target(e))
alpar@1073
   937
	  if(_drawArrows) {
alpar@1673
   938
	    xy<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
alpar@1087
   939
	    double rn=_nodeSizes[g.target(e)]*_nodeScale;
alpar@1087
   940
	    int node_shape=_nodeShapes[g.target(e)];
alpar@1087
   941
	    double t1=0,t2=1;
alpar@1087
   942
	    for(int i=0;i<INTERPOL_PREC;++i)
alpar@1087
   943
	      if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
alpar@1087
   944
	      else t2=(t1+t2)/2;
alpar@1936
   945
	    double l=std::sqrt(d.normSquare());
alpar@1073
   946
	    d/=l;
alpar@1087
   947
	    
alpar@1087
   948
	    os << l*(1-(t1+t2)/2) << ' '
alpar@1073
   949
	       << _edgeWidths[e]*_edgeWidthScale << ' '
alpar@1073
   950
	       << d.x << ' ' << d.y << ' '
alpar@1673
   951
	       << mycoords[g.source(e)].x << ' '
alpar@1673
   952
	       << mycoords[g.source(e)].y << ' '
alpar@1575
   953
	       << _edgeColors[e].red() << ' '
alpar@1575
   954
	       << _edgeColors[e].green() << ' '
alpar@1575
   955
	       << _edgeColors[e].blue() << " arr\n";
alpar@1073
   956
	  }
alpar@1673
   957
	  else os << mycoords[g.source(e)].x << ' '
alpar@1673
   958
		  << mycoords[g.source(e)].y << ' '
alpar@1673
   959
		  << mycoords[g.target(e)].x << ' '
alpar@1673
   960
		  << mycoords[g.target(e)].y << ' '
alpar@1575
   961
		  << _edgeColors[e].red() << ' '
alpar@1575
   962
		  << _edgeColors[e].green() << ' '
alpar@1575
   963
		  << _edgeColors[e].blue() << ' '
alpar@1073
   964
		  << _edgeWidths[e]*_edgeWidthScale << " l\n";
alpar@1085
   965
      os << "grestore\n";
alpar@1085
   966
    }
alpar@1085
   967
    if(_showNodes) {
alpar@1085
   968
      os << "%Nodes:\ngsave\n";
alpar@1086
   969
      for(NodeIt n(g);n!=INVALID;++n) {
alpar@1673
   970
	os << mycoords[n].x << ' ' << mycoords[n].y << ' '
alpar@1073
   971
	   << _nodeSizes[n]*_nodeScale << ' '
alpar@1575
   972
	   << _nodeColors[n].red() << ' '
alpar@1575
   973
	   << _nodeColors[n].green() << ' '
alpar@1575
   974
	   << _nodeColors[n].blue() << ' ';
alpar@1086
   975
	switch(_nodeShapes[n]) {
alpar@1086
   976
	case CIRCLE:
alpar@1086
   977
	  os<< "nc";break;
alpar@1086
   978
	case SQUARE:
alpar@1086
   979
	  os<< "nsq";break;
alpar@1088
   980
	case DIAMOND:
alpar@1088
   981
	  os<< "ndi";break;
alpar@1907
   982
	case MALE:
alpar@1907
   983
	  os<< "nmale";break;
alpar@1907
   984
	case FEMALE:
alpar@1907
   985
	  os<< "nfemale";break;
alpar@1086
   986
	}
alpar@1086
   987
	os<<'\n';
alpar@1086
   988
      }
alpar@1085
   989
      os << "grestore\n";
alpar@1085
   990
    }
alpar@1073
   991
    if(_showNodeText) {
alpar@1085
   992
      os << "%Node texts:\ngsave\n";
alpar@1073
   993
      os << "/fosi " << _nodeTextSize << " def\n";
alpar@1073
   994
      os << "(Helvetica) findfont fosi scalefont setfont\n";
alpar@1178
   995
      for(NodeIt n(g);n!=INVALID;++n) {
alpar@1178
   996
	switch(_nodeTextColorType) {
alpar@1178
   997
	case DIST_COL:
alpar@1178
   998
	  os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n";
alpar@1178
   999
	  break;
alpar@1178
  1000
	case DIST_BW:
alpar@1178
  1001
	  os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n";
alpar@1178
  1002
	  break;
alpar@1178
  1003
	case CUST_COL:
alpar@1178
  1004
	  os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n";
alpar@1178
  1005
	  break;
alpar@1178
  1006
	default:
alpar@1178
  1007
	  os << "0 0 0 setrgbcolor\n";
alpar@1178
  1008
	}
alpar@1673
  1009
	os << mycoords[n].x << ' ' << mycoords[n].y
alpar@1073
  1010
	   << " (" << _nodeTexts[n] << ") cshow\n";
alpar@1178
  1011
      }
alpar@1085
  1012
      os << "grestore\n";
alpar@1073
  1013
    }
alpar@1085
  1014
    if(_showNodePsText) {
alpar@1085
  1015
      os << "%Node PS blocks:\ngsave\n";
alpar@1085
  1016
      for(NodeIt n(g);n!=INVALID;++n)
alpar@1673
  1017
	os << mycoords[n].x << ' ' << mycoords[n].y
alpar@1085
  1018
	   << " moveto\n" << _nodePsTexts[n] << "\n";
alpar@1085
  1019
      os << "grestore\n";
alpar@1085
  1020
    }
alpar@1085
  1021
    
alpar@1103
  1022
    os << "grestore\nshowpage\n";
alpar@1073
  1023
alpar@1073
  1024
    //CleanUp:
alpar@1073
  1025
    if(_pleaseRemoveOsStream) {delete &os;}
alpar@1073
  1026
  } 
alpar@1073
  1027
};
alpar@1073
  1028
alpar@1494
  1029
template<class T>
alpar@1494
  1030
const int GraphToEps<T>::INTERPOL_PREC = 20;
alpar@1494
  1031
template<class T>
alpar@1494
  1032
const double GraphToEps<T>::A4HEIGHT = 841.8897637795276;
alpar@1494
  1033
template<class T>
alpar@1494
  1034
const double GraphToEps<T>::A4WIDTH  = 595.275590551181;
alpar@1494
  1035
template<class T>
alpar@1494
  1036
const double GraphToEps<T>::A4BORDER = 15;
alpar@1494
  1037
alpar@1073
  1038
alpar@1073
  1039
///Generates an EPS file from a graph
alpar@1073
  1040
alpar@1287
  1041
///\ingroup io_group
alpar@1073
  1042
///Generates an EPS file from a graph.
alpar@1073
  1043
///\param g is a reference to the graph to be printed
alpar@1073
  1044
///\param os is a reference to the output stream.
alpar@1073
  1045
///By default it is <tt>std::cout</tt>
alpar@1073
  1046
///
alpar@1091
  1047
///This function also has a lot of
alpar@1091
  1048
///\ref named-templ-func-param "named parameters",
alpar@1073
  1049
///they are declared as the members of class \ref GraphToEps. The following
alpar@1073
  1050
///example shows how to use these parameters.
alpar@1073
  1051
///\code
alpar@1178
  1052
/// graphToEps(g,os).scale(10).coords(coords)
alpar@1073
  1053
///              .nodeScale(2).nodeSizes(sizes)
alpar@1091
  1054
///              .edgeWidthScale(.4).run();
alpar@1073
  1055
///\endcode
alpar@1091
  1056
///\warning Don't forget to put the \ref GraphToEps::run() "run()"
alpar@1091
  1057
///to the end of the parameter list.
alpar@1073
  1058
///\sa GraphToEps
alpar@1573
  1059
///\sa graphToEps(G &g, const char *file_name)
alpar@1073
  1060
template<class G>
alpar@1073
  1061
GraphToEps<DefaultGraphToEpsTraits<G> > 
alpar@1073
  1062
graphToEps(G &g, std::ostream& os=std::cout)
alpar@1073
  1063
{
alpar@1073
  1064
  return 
alpar@1073
  1065
    GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os));
alpar@1073
  1066
}
alpar@1073
  1067
 
alpar@1073
  1068
///Generates an EPS file from a graph
alpar@1073
  1069
alpar@1573
  1070
///\ingroup io_group
alpar@1073
  1071
///This function does the same as
alpar@1073
  1072
///\ref graphToEps(G &g,std::ostream& os)
alpar@1073
  1073
///but it writes its output into the file \c file_name
alpar@1073
  1074
///instead of a stream.
alpar@1073
  1075
///\sa graphToEps(G &g, std::ostream& os)
alpar@1073
  1076
template<class G>
alpar@1073
  1077
GraphToEps<DefaultGraphToEpsTraits<G> > 
alpar@1107
  1078
graphToEps(G &g,const char *file_name)
alpar@1073
  1079
{
alpar@1073
  1080
  return GraphToEps<DefaultGraphToEpsTraits<G> >
alpar@1073
  1081
    (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true));
alpar@1073
  1082
}
alpar@1073
  1083
deba@1743
  1084
///Generates an EPS file from a graph
deba@1743
  1085
deba@1743
  1086
///\ingroup io_group
deba@1743
  1087
///This function does the same as
deba@1743
  1088
///\ref graphToEps(G &g,std::ostream& os)
deba@1743
  1089
///but it writes its output into the file \c file_name
deba@1743
  1090
///instead of a stream.
deba@1743
  1091
///\sa graphToEps(G &g, std::ostream& os)
deba@1743
  1092
template<class G>
deba@1743
  1093
GraphToEps<DefaultGraphToEpsTraits<G> > 
deba@1743
  1094
graphToEps(G &g,const std::string& file_name)
deba@1743
  1095
{
deba@1743
  1096
  return GraphToEps<DefaultGraphToEpsTraits<G> >
deba@1743
  1097
    (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true));
deba@1743
  1098
}
deba@1743
  1099
alpar@1073
  1100
} //END OF NAMESPACE LEMON
alpar@1073
  1101
alpar@1073
  1102
#endif // LEMON_GRAPH_TO_EPS_H