lemon/graph_to_eps.h
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 03 Apr 2009 18:59:15 +0200
changeset 608 6ac5d9ae1d3d
parent 509 c5919679af17
parent 482 879c55700cd4
child 559 c5fd2d996909
permissions -rw-r--r--
Support real types + numerical stability fix in NS (#254)

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