lemon/graph_to_eps.h
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 838 2c35bef44dd1
child 964 2b6bffe0e7e8
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

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