gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Changes in interface and internals of graph_to_eps.h
0 1 0
default
1 file changed with 17 insertions and 14 deletions:
↑ Collapse diff ↑
Ignore white space 128 line context
1 1
/* -*- C++ -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#ifndef LEMON_GRAPH_TO_EPS_H
20 20
#define LEMON_GRAPH_TO_EPS_H
21 21

	
22 22
#include <sys/time.h>
23 23

	
24 24
#ifdef WIN32
25 25
#include <lemon/bits/mingw32_time.h>
26 26
#endif
27 27

	
28 28
#include<iostream>
29 29
#include<fstream>
30 30
#include<sstream>
31 31
#include<algorithm>
32 32
#include<vector>
33 33

	
34 34
#include<ctime>
35 35

	
36 36
#include<lemon/math.h>
37 37
#include<lemon/bits/invalid.h>
38 38
#include<lemon/dim2.h>
39 39
#include<lemon/maps.h>
40 40
#include<lemon/color.h>
41 41
#include<lemon/bits/bezier.h>
42 42

	
43 43

	
44 44
///\ingroup eps_io
45 45
///\file
46 46
///\brief Simple graph drawer
47 47
///
48 48
///\author Alpar Juttner
49 49

	
50 50
namespace lemon {
51 51

	
52
template<class MT>
53
class _NegY {
54
public:
55
  typedef typename MT::Key Key;
56
  typedef typename MT::Value Value;
57
  const MT &map;
58
  int yscale;
59
  _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
60
  Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
61
};
62

	
52
  namespace _graph_to_eps_bits {
53
    template<class MT>
54
    class _NegY {
55
    public:
56
      typedef typename MT::Key Key;
57
      typedef typename MT::Value Value;
58
      const MT &map;
59
      int yscale;
60
      _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {}
61
      Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);}
62
    };
63
  }
64
  
63 65
///Default traits class of \ref GraphToEps
64 66

	
65 67
///Default traits class of \ref GraphToEps
66 68
///
67 69
///\c G is the type of the underlying graph.
68 70
template<class G>
69 71
struct DefaultGraphToEpsTraits
70 72
{
71 73
  typedef G Graph;
72 74
  typedef typename Graph::Node Node;
73 75
  typedef typename Graph::NodeIt NodeIt;
74 76
  typedef typename Graph::Arc Arc;
75 77
  typedef typename Graph::ArcIt ArcIt;
76 78
  typedef typename Graph::InArcIt InArcIt;
77 79
  typedef typename Graph::OutArcIt OutArcIt;
78 80
  
79 81

	
80 82
  const Graph &g;
81 83

	
82 84
  std::ostream& os;
83 85
  
84 86
  typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType;
85 87
  CoordsMapType _coords;
86 88
  ConstMap<typename Graph::Node,double > _nodeSizes;
87 89
  ConstMap<typename Graph::Node,int > _nodeShapes;
88 90

	
89 91
  ConstMap<typename Graph::Node,Color > _nodeColors;
90 92
  ConstMap<typename Graph::Arc,Color > _arcColors;
91 93

	
92 94
  ConstMap<typename Graph::Arc,double > _arcWidths;
93 95

	
94 96
  double _arcWidthScale;
95 97
  
96 98
  double _nodeScale;
97 99
  double _xBorder, _yBorder;
98 100
  double _scale;
99 101
  double _nodeBorderQuotient;
100 102
  
101 103
  bool _drawArrows;
102 104
  double _arrowLength, _arrowWidth;
103 105
  
104 106
  bool _showNodes, _showArcs;
105 107

	
106 108
  bool _enableParallel;
107 109
  double _parArcDist;
108 110

	
109 111
  bool _showNodeText;
110 112
  ConstMap<typename Graph::Node,bool > _nodeTexts;  
111 113
  double _nodeTextSize;
112 114

	
113 115
  bool _showNodePsText;
114 116
  ConstMap<typename Graph::Node,bool > _nodePsTexts;  
115 117
  char *_nodePsTextsPreamble;
116 118
  
117 119
  bool _undirected;
118 120

	
119 121
  bool _pleaseRemoveOsStream;
120 122

	
121 123
  bool _scaleToA4;
122 124

	
123 125
  std::string _title;
124 126
  std::string _copyright;
125 127

	
126 128
  enum NodeTextColorType 
127 129
    { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType;
128 130
  ConstMap<typename Graph::Node,Color > _nodeTextColors;
129 131

	
130 132
  bool _autoNodeScale;
131 133
  bool _autoArcWidthScale;
132 134

	
133 135
  bool _absoluteNodeSizes;
134 136
  bool _absoluteArcWidths;
135 137

	
136 138
  bool _negY;
137 139

	
138 140
  bool _preScale;
139 141
  ///Constructor
140 142

	
141 143
  ///Constructor
142 144
  ///\param _g is a reference to the graph to be printed
143 145
  ///\param _os is a reference to the output stream.
144 146
  ///\param _os is a reference to the output stream.
145 147
  ///\param _pros If it is \c true, then the \c ostream referenced by \c _os
146 148
  ///will be explicitly deallocated by the destructor.
147 149
  ///By default it is <tt>std::cout</tt>
148 150
  DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
149 151
			  bool _pros=false) :
150 152
    g(_g), os(_os),
151 153
    _coords(dim2::Point<double>(1,1)), _nodeSizes(.01), _nodeShapes(0),
152 154
    _nodeColors(WHITE), _arcColors(BLACK),
153 155
    _arcWidths(1.0), _arcWidthScale(0.003),
154 156
    _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
155 157
    _nodeBorderQuotient(.1),
156 158
    _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
157 159
    _showNodes(true), _showArcs(true),
158 160
    _enableParallel(false), _parArcDist(1),
159 161
    _showNodeText(false), _nodeTexts(false), _nodeTextSize(1),
160 162
    _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0),
161
    _undirected(false),
163
    _undirected(lemon::UndirectedTagIndicator<G>::value),
162 164
    _pleaseRemoveOsStream(_pros), _scaleToA4(false),
163 165
    _nodeTextColorType(SAME_COL), _nodeTextColors(BLACK),
164 166
    _autoNodeScale(false),
165 167
    _autoArcWidthScale(false),
166 168
    _absoluteNodeSizes(false),
167 169
    _absoluteArcWidths(false),
168 170
    _negY(false),
169 171
    _preScale(true)
170 172
  {}
171 173
};
172 174

	
173 175
///Helper class to implement the named parameters of \ref graphToEps()
174 176

	
175 177
///Helper class to implement the named parameters of \ref graphToEps()
176 178
///\todo Is 'helper class' a good name for this?
177 179
///
178 180
///\todo Follow PostScript's DSC.
179 181
/// Use own dictionary.
180 182
///\todo Useful new features.
181 183
/// - Linestyles: dotted, dashed etc.
182 184
/// - A second color and percent value for the lines.
183 185
template<class T> class GraphToEps : public T 
184 186
{
185 187
  // Can't believe it is required by the C++ standard
186 188
  using T::g;
187 189
  using T::os;
188 190

	
189 191
  using T::_coords;
190 192
  using T::_nodeSizes;
191 193
  using T::_nodeShapes;
192 194
  using T::_nodeColors;
193 195
  using T::_arcColors;
194 196
  using T::_arcWidths;
195 197

	
196 198
  using T::_arcWidthScale;
197 199
  using T::_nodeScale;
198 200
  using T::_xBorder;
199 201
  using T::_yBorder;
200 202
  using T::_scale;
201 203
  using T::_nodeBorderQuotient;
202 204
  
203 205
  using T::_drawArrows;
204 206
  using T::_arrowLength;
205 207
  using T::_arrowWidth;
206 208
  
207 209
  using T::_showNodes;
208 210
  using T::_showArcs;
209 211

	
210 212
  using T::_enableParallel;
211 213
  using T::_parArcDist;
212 214

	
213 215
  using T::_showNodeText;
214 216
  using T::_nodeTexts;  
215 217
  using T::_nodeTextSize;
216 218

	
217 219
  using T::_showNodePsText;
218 220
  using T::_nodePsTexts;  
219 221
  using T::_nodePsTextsPreamble;
220 222
  
221 223
  using T::_undirected;
222 224

	
223 225
  using T::_pleaseRemoveOsStream;
224 226

	
225 227
  using T::_scaleToA4;
... ...
@@ -607,175 +609,176 @@
607 609
  GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;}
608 610
  
609 611
  ///Enables parallel arcs
610 612

	
611 613
  ///Enables parallel arcs
612 614
  GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;}
613 615
  
614 616
  ///Sets the distance 
615 617
  
616 618
  ///Sets the distance 
617 619
  ///
618 620
  GraphToEps<T> &parArcDist(double d) {_parArcDist*=d;return *this;}
619 621
  
620 622
  ///Hides the arcs
621 623
  
622 624
  ///Hides the arcs
623 625
  ///
624 626
  GraphToEps<T> &hideArcs(bool b=true) {_showArcs=!b;return *this;}
625 627
  ///Hides the nodes
626 628
  
627 629
  ///Hides the nodes
628 630
  ///
629 631
  GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;}
630 632
  
631 633
  ///Sets the size of the node texts
632 634
  
633 635
  ///Sets the size of the node texts
634 636
  ///
635 637
  GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;}
636 638

	
637 639
  ///Sets the color of the node texts to be different from the node color
638 640

	
639 641
  ///Sets the color of the node texts to be as different from the node color
640 642
  ///as it is possible
641 643
  ///
642 644
  GraphToEps<T> &distantColorNodeTexts()
643 645
  {_nodeTextColorType=DIST_COL;return *this;}
644 646
  ///Sets the color of the node texts to be black or white and always visible.
645 647

	
646 648
  ///Sets the color of the node texts to be black or white according to
647 649
  ///which is more 
648 650
  ///different from the node color
649 651
  ///
650 652
  GraphToEps<T> &distantBWNodeTexts()
651 653
  {_nodeTextColorType=DIST_BW;return *this;}
652 654

	
653 655
  ///Gives a preamble block for node Postscript block.
654 656
  
655 657
  ///Gives a preamble block for node Postscript block.
656 658
  ///
657 659
  ///\sa nodePsTexts()
658 660
  GraphToEps<T> & nodePsTextsPreamble(const char *str) {
659 661
    _nodePsTextsPreamble=str ;return *this;
660 662
  }
661 663
  ///Sets whether the the graph is undirected
662 664

	
663 665
  ///Sets whether the the graph is undirected
664 666
  ///
665 667
  GraphToEps<T> &undirected(bool b=true) {_undirected=b;return *this;}
666 668

	
667 669
  ///Sets whether the the graph is directed
668 670

	
669 671
  ///Sets whether the the graph is directed.
670 672
  ///Use it to show the edges as a pair of directed ones.
671
  GraphToEps<T> &bidir(bool b=true) {_undirected=!b;return *this;}
673
  GraphToEps<T> &directed(bool b=true) {_undirected=!b;return *this;}
672 674

	
673 675
  ///Sets the title.
674 676

	
675 677
  ///Sets the title of the generated image,
676 678
  ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of
677 679
  ///the EPS file.
678 680
  GraphToEps<T> &title(const std::string &t) {_title=t;return *this;}
679 681
  ///Sets the copyright statement.
680 682

	
681 683
  ///Sets the copyright statement of the generated image,
682 684
  ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of
683 685
  ///the EPS file.
684 686
  ///\todo Multiline copyright notice could be supported.
685 687
  GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
686 688

	
687 689
protected:
688 690
  bool isInsideNode(dim2::Point<double> p, double r,int t) 
689 691
  {
690 692
    switch(t) {
691 693
    case CIRCLE:
692 694
    case MALE:
693 695
    case FEMALE:
694 696
      return p.normSquare()<=r*r;
695 697
    case SQUARE:
696 698
      return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r;
697 699
    case DIAMOND:
698 700
      return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r;
699 701
    }
700 702
    return false;
701 703
  }
702 704

	
703 705
public:
704 706
  ~GraphToEps() { }
705 707
  
706 708
  ///Draws the graph.
707 709

	
708 710
  ///Like other functions using
709 711
  ///\ref named-templ-func-param "named template parameters",
710 712
  ///this function calles the algorithm itself, i.e. in this case
711 713
  ///it draws the graph.
712 714
  void run() {
713 715
    ///\todo better 'epsilon' would be nice here.
714 716
    const double EPSILON=1e-9;
715 717
    if(dontPrint) return;
716 718
    
717
    _NegY<typename T::CoordsMapType> mycoords(_coords,_negY);
719
    _graph_to_eps_bits::_NegY<typename T::CoordsMapType>
720
      mycoords(_coords,_negY);
718 721

	
719 722
    os << "%!PS-Adobe-2.0 EPSF-2.0\n";
720 723
    if(_title.size()>0) os << "%%Title: " << _title << '\n';
721 724
     if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n';
722 725
//        << "%%Copyright: XXXX\n"
723 726
    os << "%%Creator: LEMON, graphToEps()\n";
724 727
    
725 728
    {
726 729
      char cbuf[50];
727 730
      timeval tv;
728 731
      gettimeofday(&tv, 0);
729 732
      ctime_r(&tv.tv_sec,cbuf);
730 733
      os << "%%CreationDate: " << cbuf;
731 734
    }
732 735

	
733 736
    if (_autoArcWidthScale) {
734 737
      double max_w=0;
735 738
      for(ArcIt e(g);e!=INVALID;++e)
736 739
	max_w=std::max(double(_arcWidths[e]),max_w);
737 740
      ///\todo better 'epsilon' would be nice here.
738 741
      if(max_w>EPSILON) {
739 742
	_arcWidthScale/=max_w;
740 743
      }
741 744
    }
742 745

	
743 746
    if (_autoNodeScale) {
744 747
      double max_s=0;
745 748
      for(NodeIt n(g);n!=INVALID;++n)
746 749
	max_s=std::max(double(_nodeSizes[n]),max_s);
747 750
      ///\todo better 'epsilon' would be nice here.
748 751
      if(max_s>EPSILON) {
749 752
	_nodeScale/=max_s;
750 753
      }
751 754
    }
752 755

	
753 756
    double diag_len = 1;
754 757
    if(!(_absoluteNodeSizes&&_absoluteArcWidths)) {
755 758
      dim2::BoundingBox<double> bb;
756 759
      for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]);
757 760
      if (bb.empty()) {
758 761
	bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0));
759 762
      }
760 763
      diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare());
761 764
      if(diag_len<EPSILON) diag_len = 1;
762 765
      if(!_absoluteNodeSizes) _nodeScale*=diag_len;
763 766
      if(!_absoluteArcWidths) _arcWidthScale*=diag_len;
764 767
    }
765 768
    
766 769
    dim2::BoundingBox<double> bb;
767 770
    for(NodeIt n(g);n!=INVALID;++n) {
768 771
      double ns=_nodeSizes[n]*_nodeScale;
769 772
      dim2::Point<double> p(ns,ns);
770 773
      switch(_nodeShapes[n]) {
771 774
      case CIRCLE:
772 775
      case SQUARE:
773 776
      case DIAMOND:
774 777
	bb.add(p+mycoords[n]);
775 778
	bb.add(-p+mycoords[n]);
776 779
	break;
777 780
      case MALE:
778 781
	bb.add(-p+mycoords[n]);
779 782
	bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
780 783
	break;
781 784
      case FEMALE:
0 comments (0 inline)