changeset 209 | 765619b7cbb2 |
parent 206 | 4e22275a2b52 |
child 210 | 81cfc04531e8 |
9:360e7be999db | 10:564d98c9d526 |
---|---|
1 /* -*- C++ -*- |
1 /* -*- mode: C++; indent-tabs-mode: nil; -*- |
2 * |
2 * |
3 * This file is a part of LEMON, a generic C++ optimization library |
3 * This file is a part of LEMON, a generic C++ optimization library. |
4 * |
4 * |
5 * Copyright (C) 2003-2008 |
5 * Copyright (C) 2003-2008 |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
7 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
8 * |
8 * |
58 int yscale; |
58 int yscale; |
59 _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {} |
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);} |
60 Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);} |
61 }; |
61 }; |
62 } |
62 } |
63 |
63 |
64 ///Default traits class of \ref GraphToEps |
64 ///Default traits class of \ref GraphToEps |
65 |
65 |
66 ///Default traits class of \ref GraphToEps. |
66 ///Default traits class of \ref GraphToEps. |
67 /// |
67 /// |
68 ///\c G is the type of the underlying graph. |
68 ///\c G is the type of the underlying graph. |
74 typedef typename Graph::NodeIt NodeIt; |
74 typedef typename Graph::NodeIt NodeIt; |
75 typedef typename Graph::Arc Arc; |
75 typedef typename Graph::Arc Arc; |
76 typedef typename Graph::ArcIt ArcIt; |
76 typedef typename Graph::ArcIt ArcIt; |
77 typedef typename Graph::InArcIt InArcIt; |
77 typedef typename Graph::InArcIt InArcIt; |
78 typedef typename Graph::OutArcIt OutArcIt; |
78 typedef typename Graph::OutArcIt OutArcIt; |
79 |
79 |
80 |
80 |
81 const Graph &g; |
81 const Graph &g; |
82 |
82 |
83 std::ostream& os; |
83 std::ostream& os; |
84 |
84 |
85 typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType; |
85 typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType; |
86 CoordsMapType _coords; |
86 CoordsMapType _coords; |
87 ConstMap<typename Graph::Node,double > _nodeSizes; |
87 ConstMap<typename Graph::Node,double > _nodeSizes; |
88 ConstMap<typename Graph::Node,int > _nodeShapes; |
88 ConstMap<typename Graph::Node,int > _nodeShapes; |
89 |
89 |
91 ConstMap<typename Graph::Arc,Color > _arcColors; |
91 ConstMap<typename Graph::Arc,Color > _arcColors; |
92 |
92 |
93 ConstMap<typename Graph::Arc,double > _arcWidths; |
93 ConstMap<typename Graph::Arc,double > _arcWidths; |
94 |
94 |
95 double _arcWidthScale; |
95 double _arcWidthScale; |
96 |
96 |
97 double _nodeScale; |
97 double _nodeScale; |
98 double _xBorder, _yBorder; |
98 double _xBorder, _yBorder; |
99 double _scale; |
99 double _scale; |
100 double _nodeBorderQuotient; |
100 double _nodeBorderQuotient; |
101 |
101 |
102 bool _drawArrows; |
102 bool _drawArrows; |
103 double _arrowLength, _arrowWidth; |
103 double _arrowLength, _arrowWidth; |
104 |
104 |
105 bool _showNodes, _showArcs; |
105 bool _showNodes, _showArcs; |
106 |
106 |
107 bool _enableParallel; |
107 bool _enableParallel; |
108 double _parArcDist; |
108 double _parArcDist; |
109 |
109 |
110 bool _showNodeText; |
110 bool _showNodeText; |
111 ConstMap<typename Graph::Node,bool > _nodeTexts; |
111 ConstMap<typename Graph::Node,bool > _nodeTexts; |
112 double _nodeTextSize; |
112 double _nodeTextSize; |
113 |
113 |
114 bool _showNodePsText; |
114 bool _showNodePsText; |
115 ConstMap<typename Graph::Node,bool > _nodePsTexts; |
115 ConstMap<typename Graph::Node,bool > _nodePsTexts; |
116 char *_nodePsTextsPreamble; |
116 char *_nodePsTextsPreamble; |
117 |
117 |
118 bool _undirected; |
118 bool _undirected; |
119 |
119 |
120 bool _pleaseRemoveOsStream; |
120 bool _pleaseRemoveOsStream; |
121 |
121 |
122 bool _scaleToA4; |
122 bool _scaleToA4; |
123 |
123 |
124 std::string _title; |
124 std::string _title; |
125 std::string _copyright; |
125 std::string _copyright; |
126 |
126 |
127 enum NodeTextColorType |
127 enum NodeTextColorType |
128 { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType; |
128 { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType; |
129 ConstMap<typename Graph::Node,Color > _nodeTextColors; |
129 ConstMap<typename Graph::Node,Color > _nodeTextColors; |
130 |
130 |
131 bool _autoNodeScale; |
131 bool _autoNodeScale; |
132 bool _autoArcWidthScale; |
132 bool _autoArcWidthScale; |
144 ///\param _os Reference to the output stream. |
144 ///\param _os Reference to the output stream. |
145 ///\param _os Reference to the output stream. By default it is <tt>std::cout</tt>. |
145 ///\param _os Reference to the output stream. By default it is <tt>std::cout</tt>. |
146 ///\param _pros If it is \c true, then the \c ostream referenced by \c _os |
146 ///\param _pros If it is \c true, then the \c ostream referenced by \c _os |
147 ///will be explicitly deallocated by the destructor. |
147 ///will be explicitly deallocated by the destructor. |
148 DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout, |
148 DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout, |
149 bool _pros=false) : |
149 bool _pros=false) : |
150 g(_g), os(_os), |
150 g(_g), os(_os), |
151 _coords(dim2::Point<double>(1,1)), _nodeSizes(1), _nodeShapes(0), |
151 _coords(dim2::Point<double>(1,1)), _nodeSizes(1), _nodeShapes(0), |
152 _nodeColors(WHITE), _arcColors(BLACK), |
152 _nodeColors(WHITE), _arcColors(BLACK), |
153 _arcWidths(1.0), _arcWidthScale(0.003), |
153 _arcWidths(1.0), _arcWidthScale(0.003), |
154 _nodeScale(.01), _xBorder(10), _yBorder(10), _scale(1.0), |
154 _nodeScale(.01), _xBorder(10), _yBorder(10), _scale(1.0), |
173 ///Auxiliary class to implement the named parameters of \ref graphToEps() |
173 ///Auxiliary class to implement the named parameters of \ref graphToEps() |
174 |
174 |
175 ///Auxiliary class to implement the named parameters of \ref graphToEps(). |
175 ///Auxiliary class to implement the named parameters of \ref graphToEps(). |
176 /// |
176 /// |
177 ///For detailed examples see the \ref graph_to_eps_demo.cc demo file. |
177 ///For detailed examples see the \ref graph_to_eps_demo.cc demo file. |
178 template<class T> class GraphToEps : public T |
178 template<class T> class GraphToEps : public T |
179 { |
179 { |
180 // Can't believe it is required by the C++ standard |
180 // Can't believe it is required by the C++ standard |
181 using T::g; |
181 using T::g; |
182 using T::os; |
182 using T::os; |
183 |
183 |
192 using T::_nodeScale; |
192 using T::_nodeScale; |
193 using T::_xBorder; |
193 using T::_xBorder; |
194 using T::_yBorder; |
194 using T::_yBorder; |
195 using T::_scale; |
195 using T::_scale; |
196 using T::_nodeBorderQuotient; |
196 using T::_nodeBorderQuotient; |
197 |
197 |
198 using T::_drawArrows; |
198 using T::_drawArrows; |
199 using T::_arrowLength; |
199 using T::_arrowLength; |
200 using T::_arrowWidth; |
200 using T::_arrowWidth; |
201 |
201 |
202 using T::_showNodes; |
202 using T::_showNodes; |
203 using T::_showArcs; |
203 using T::_showArcs; |
204 |
204 |
205 using T::_enableParallel; |
205 using T::_enableParallel; |
206 using T::_parArcDist; |
206 using T::_parArcDist; |
207 |
207 |
208 using T::_showNodeText; |
208 using T::_showNodeText; |
209 using T::_nodeTexts; |
209 using T::_nodeTexts; |
210 using T::_nodeTextSize; |
210 using T::_nodeTextSize; |
211 |
211 |
212 using T::_showNodePsText; |
212 using T::_showNodePsText; |
213 using T::_nodePsTexts; |
213 using T::_nodePsTexts; |
214 using T::_nodePsTextsPreamble; |
214 using T::_nodePsTextsPreamble; |
215 |
215 |
216 using T::_undirected; |
216 using T::_undirected; |
217 |
217 |
218 using T::_pleaseRemoveOsStream; |
218 using T::_pleaseRemoveOsStream; |
219 |
219 |
220 using T::_scaleToA4; |
220 using T::_scaleToA4; |
259 public: |
259 public: |
260 ///Node shapes |
260 ///Node shapes |
261 |
261 |
262 ///Node shapes. |
262 ///Node shapes. |
263 /// |
263 /// |
264 enum NodeShapes { |
264 enum NodeShapes { |
265 /// = 0 |
265 /// = 0 |
266 ///\image html nodeshape_0.png |
266 ///\image html nodeshape_0.png |
267 ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm |
267 ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm |
268 CIRCLE=0, |
268 CIRCLE=0, |
269 /// = 1 |
269 /// = 1 |
270 ///\image html nodeshape_1.png |
270 ///\image html nodeshape_1.png |
271 ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm |
271 ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm |
272 /// |
272 /// |
273 SQUARE=1, |
273 SQUARE=1, |
274 /// = 2 |
274 /// = 2 |
275 ///\image html nodeshape_2.png |
275 ///\image html nodeshape_2.png |
276 ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm |
276 ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm |
277 /// |
277 /// |
278 DIAMOND=2, |
278 DIAMOND=2, |
291 private: |
291 private: |
292 class arcLess { |
292 class arcLess { |
293 const Graph &g; |
293 const Graph &g; |
294 public: |
294 public: |
295 arcLess(const Graph &_g) : g(_g) {} |
295 arcLess(const Graph &_g) : g(_g) {} |
296 bool operator()(Arc a,Arc b) const |
296 bool operator()(Arc a,Arc b) const |
297 { |
297 { |
298 Node ai=std::min(g.source(a),g.target(a)); |
298 Node ai=std::min(g.source(a),g.target(a)); |
299 Node aa=std::max(g.source(a),g.target(a)); |
299 Node aa=std::max(g.source(a),g.target(a)); |
300 Node bi=std::min(g.source(b),g.target(b)); |
300 Node bi=std::min(g.source(b),g.target(b)); |
301 Node ba=std::max(g.source(b),g.target(b)); |
301 Node ba=std::max(g.source(b),g.target(b)); |
302 return ai<bi || |
302 return ai<bi || |
303 (ai==bi && (aa < ba || |
303 (ai==bi && (aa < ba || |
304 (aa==ba && ai==g.source(a) && bi==g.target(b)))); |
304 (aa==ba && ai==g.source(a) && bi==g.target(b)))); |
305 } |
305 } |
306 }; |
306 }; |
307 bool isParallel(Arc e,Arc f) const |
307 bool isParallel(Arc e,Arc f) const |
308 { |
308 { |
309 return (g.source(e)==g.source(f)&& |
309 return (g.source(e)==g.source(f)&& |
310 g.target(e)==g.target(f)) || |
310 g.target(e)==g.target(f)) || |
311 (g.source(e)==g.target(f)&& |
311 (g.source(e)==g.target(f)&& |
312 g.target(e)==g.source(f)); |
312 g.target(e)==g.source(f)); |
313 } |
313 } |
314 template<class TT> |
314 template<class TT> |
315 static std::string psOut(const dim2::Point<TT> &p) |
315 static std::string psOut(const dim2::Point<TT> &p) |
316 { |
316 { |
317 std::ostringstream os; |
317 std::ostringstream os; |
318 os << p.x << ' ' << p.y; |
318 os << p.x << ' ' << p.y; |
319 return os.str(); |
319 return os.str(); |
320 } |
320 } |
321 static std::string psOut(const Color &c) |
321 static std::string psOut(const Color &c) |
322 { |
322 { |
323 std::ostringstream os; |
323 std::ostringstream os; |
324 os << c.red() << ' ' << c.green() << ' ' << c.blue(); |
324 os << c.red() << ' ' << c.green() << ' ' << c.blue(); |
325 return os.str(); |
325 return os.str(); |
326 } |
326 } |
327 |
327 |
328 public: |
328 public: |
329 GraphToEps(const T &t) : T(t), dontPrint(false) {}; |
329 GraphToEps(const T &t) : T(t), dontPrint(false) {}; |
330 |
330 |
331 template<class X> struct CoordsTraits : public T { |
331 template<class X> struct CoordsTraits : public T { |
332 typedef X CoordsMapType; |
332 typedef X CoordsMapType; |
333 const X &_coords; |
333 const X &_coords; |
334 CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} |
334 CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} |
335 }; |
335 }; |
336 ///Sets the map of the node coordinates |
336 ///Sets the map of the node coordinates |
337 |
337 |
338 ///Sets the map of the node coordinates. |
338 ///Sets the map of the node coordinates. |
339 ///\param x must be a node map with \ref dim2::Point "dim2::Point<double>" or |
339 ///\param x must be a node map with \ref dim2::Point "dim2::Point<double>" or |
340 ///\ref dim2::Point "dim2::Point<int>" values. |
340 ///\ref dim2::Point "dim2::Point<int>" values. |
341 template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) { |
341 template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) { |
342 dontPrint=true; |
342 dontPrint=true; |
343 return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x)); |
343 return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x)); |
344 } |
344 } |
345 template<class X> struct NodeSizesTraits : public T { |
345 template<class X> struct NodeSizesTraits : public T { |
347 NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} |
347 NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} |
348 }; |
348 }; |
349 ///Sets the map of the node sizes |
349 ///Sets the map of the node sizes |
350 |
350 |
351 ///Sets the map of the node sizes. |
351 ///Sets the map of the node sizes. |
352 ///\param x must be a node map with \c double (or convertible) values. |
352 ///\param x must be a node map with \c double (or convertible) values. |
353 template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x) |
353 template<class X> GraphToEps<NodeSizesTraits<X> > nodeSizes(const X &x) |
354 { |
354 { |
355 dontPrint=true; |
355 dontPrint=true; |
356 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x)); |
356 return GraphToEps<NodeSizesTraits<X> >(NodeSizesTraits<X>(*this,x)); |
357 } |
357 } |
362 ///Sets the map of the node shapes |
362 ///Sets the map of the node shapes |
363 |
363 |
364 ///Sets the map of the node shapes. |
364 ///Sets the map of the node shapes. |
365 ///The available shape values |
365 ///The available shape values |
366 ///can be found in \ref NodeShapes "enum NodeShapes". |
366 ///can be found in \ref NodeShapes "enum NodeShapes". |
367 ///\param x must be a node map with \c int (or convertible) values. |
367 ///\param x must be a node map with \c int (or convertible) values. |
368 ///\sa NodeShapes |
368 ///\sa NodeShapes |
369 template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x) |
369 template<class X> GraphToEps<NodeShapesTraits<X> > nodeShapes(const X &x) |
370 { |
370 { |
371 dontPrint=true; |
371 dontPrint=true; |
372 return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x)); |
372 return GraphToEps<NodeShapesTraits<X> >(NodeShapesTraits<X>(*this,x)); |
377 }; |
377 }; |
378 ///Sets the text printed on the nodes |
378 ///Sets the text printed on the nodes |
379 |
379 |
380 ///Sets the text printed on the nodes. |
380 ///Sets the text printed on the nodes. |
381 ///\param x must be a node map with type that can be pushed to a standard |
381 ///\param x must be a node map with type that can be pushed to a standard |
382 ///\c ostream. |
382 ///\c ostream. |
383 template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x) |
383 template<class X> GraphToEps<NodeTextsTraits<X> > nodeTexts(const X &x) |
384 { |
384 { |
385 dontPrint=true; |
385 dontPrint=true; |
386 _showNodeText=true; |
386 _showNodeText=true; |
387 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x)); |
387 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x)); |
415 ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {} |
415 ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {} |
416 }; |
416 }; |
417 ///Sets the map of the arc widths |
417 ///Sets the map of the arc widths |
418 |
418 |
419 ///Sets the map of the arc widths. |
419 ///Sets the map of the arc widths. |
420 ///\param x must be an arc map with \c double (or convertible) values. |
420 ///\param x must be an arc map with \c double (or convertible) values. |
421 template<class X> GraphToEps<ArcWidthsTraits<X> > arcWidths(const X &x) |
421 template<class X> GraphToEps<ArcWidthsTraits<X> > arcWidths(const X &x) |
422 { |
422 { |
423 dontPrint=true; |
423 dontPrint=true; |
424 return GraphToEps<ArcWidthsTraits<X> >(ArcWidthsTraits<X>(*this,x)); |
424 return GraphToEps<ArcWidthsTraits<X> >(ArcWidthsTraits<X>(*this,x)); |
425 } |
425 } |
445 NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {} |
445 NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {} |
446 }; |
446 }; |
447 ///Sets the map of the node text colors |
447 ///Sets the map of the node text colors |
448 |
448 |
449 ///Sets the map of the node text colors. |
449 ///Sets the map of the node text colors. |
450 ///\param x must be a node map with \ref Color values. |
450 ///\param x must be a node map with \ref Color values. |
451 /// |
451 /// |
452 ///\sa Palette |
452 ///\sa Palette |
453 template<class X> GraphToEps<NodeTextColorsTraits<X> > |
453 template<class X> GraphToEps<NodeTextColorsTraits<X> > |
454 nodeTextColors(const X &x) |
454 nodeTextColors(const X &x) |
455 { |
455 { |
463 ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {} |
463 ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {} |
464 }; |
464 }; |
465 ///Sets the map of the arc colors |
465 ///Sets the map of the arc colors |
466 |
466 |
467 ///Sets the map of the arc colors. |
467 ///Sets the map of the arc colors. |
468 ///\param x must be an arc map with \ref Color values. |
468 ///\param x must be an arc map with \ref Color values. |
469 /// |
469 /// |
470 ///\sa Palette |
470 ///\sa Palette |
471 template<class X> GraphToEps<ArcColorsTraits<X> > |
471 template<class X> GraphToEps<ArcColorsTraits<X> > |
472 arcColors(const X &x) |
472 arcColors(const X &x) |
473 { |
473 { |
475 return GraphToEps<ArcColorsTraits<X> >(ArcColorsTraits<X>(*this,x)); |
475 return GraphToEps<ArcColorsTraits<X> >(ArcColorsTraits<X>(*this,x)); |
476 } |
476 } |
477 ///Sets a global scale factor for node sizes |
477 ///Sets a global scale factor for node sizes |
478 |
478 |
479 ///Sets a global scale factor for node sizes. |
479 ///Sets a global scale factor for node sizes. |
480 /// |
480 /// |
481 /// If nodeSizes() is not given, this function simply sets the node |
481 /// If nodeSizes() is not given, this function simply sets the node |
482 /// sizes to \c d. If nodeSizes() is given, but |
482 /// sizes to \c d. If nodeSizes() is given, but |
483 /// autoNodeScale() is not, then the node size given by |
483 /// autoNodeScale() is not, then the node size given by |
484 /// nodeSizes() will be multiplied by the value \c d. |
484 /// nodeSizes() will be multiplied by the value \c d. |
485 /// If both nodeSizes() and autoNodeScale() are used, then the |
485 /// If both nodeSizes() and autoNodeScale() are used, then the |
566 GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;} |
566 GraphToEps<T> &drawArrows(bool b=true) {_drawArrows=b;return *this;} |
567 ///Sets the length of the arrowheads |
567 ///Sets the length of the arrowheads |
568 GraphToEps<T> &arrowLength(double d=1.0) {_arrowLength*=d;return *this;} |
568 GraphToEps<T> &arrowLength(double d=1.0) {_arrowLength*=d;return *this;} |
569 ///Sets the width of the arrowheads |
569 ///Sets the width of the arrowheads |
570 GraphToEps<T> &arrowWidth(double d=.3) {_arrowWidth*=d;return *this;} |
570 GraphToEps<T> &arrowWidth(double d=.3) {_arrowWidth*=d;return *this;} |
571 |
571 |
572 ///Scales the drawing to fit to A4 page |
572 ///Scales the drawing to fit to A4 page |
573 GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;} |
573 GraphToEps<T> &scaleToA4() {_scaleToA4=true;return *this;} |
574 |
574 |
575 ///Enables parallel arcs |
575 ///Enables parallel arcs |
576 GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;} |
576 GraphToEps<T> &enableParallel(bool b=true) {_enableParallel=b;return *this;} |
577 |
577 |
578 ///Sets the distance between parallel arcs |
578 ///Sets the distance between parallel arcs |
579 GraphToEps<T> &parArcDist(double d) {_parArcDist*=d;return *this;} |
579 GraphToEps<T> &parArcDist(double d) {_parArcDist*=d;return *this;} |
580 |
580 |
581 ///Hides the arcs |
581 ///Hides the arcs |
582 GraphToEps<T> &hideArcs(bool b=true) {_showArcs=!b;return *this;} |
582 GraphToEps<T> &hideArcs(bool b=true) {_showArcs=!b;return *this;} |
583 ///Hides the nodes |
583 ///Hides the nodes |
584 GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;} |
584 GraphToEps<T> &hideNodes(bool b=true) {_showNodes=!b;return *this;} |
585 |
585 |
586 ///Sets the size of the node texts |
586 ///Sets the size of the node texts |
587 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;} |
587 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;} |
588 |
588 |
589 ///Sets the color of the node texts to be different from the node color |
589 ///Sets the color of the node texts to be different from the node color |
590 |
590 |
598 ///which is more different from the node color. |
598 ///which is more different from the node color. |
599 GraphToEps<T> &distantBWNodeTexts() |
599 GraphToEps<T> &distantBWNodeTexts() |
600 {_nodeTextColorType=DIST_BW;return *this;} |
600 {_nodeTextColorType=DIST_BW;return *this;} |
601 |
601 |
602 ///Gives a preamble block for node Postscript block. |
602 ///Gives a preamble block for node Postscript block. |
603 |
603 |
604 ///Gives a preamble block for node Postscript block. |
604 ///Gives a preamble block for node Postscript block. |
605 /// |
605 /// |
606 ///\sa nodePsTexts() |
606 ///\sa nodePsTexts() |
607 GraphToEps<T> & nodePsTextsPreamble(const char *str) { |
607 GraphToEps<T> & nodePsTextsPreamble(const char *str) { |
608 _nodePsTextsPreamble=str ;return *this; |
608 _nodePsTextsPreamble=str ;return *this; |
623 /// |
623 /// |
624 ///This setting is the default for digraphs. |
624 ///This setting is the default for digraphs. |
625 /// |
625 /// |
626 ///\sa undirected() |
626 ///\sa undirected() |
627 GraphToEps<T> &directed(bool b=true) {_undirected=!b;return *this;} |
627 GraphToEps<T> &directed(bool b=true) {_undirected=!b;return *this;} |
628 |
628 |
629 ///Sets the title. |
629 ///Sets the title. |
630 |
630 |
631 ///Sets the title of the generated image, |
631 ///Sets the title of the generated image, |
632 ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of |
632 ///namely it inserts a <tt>%%Title:</tt> DSC field to the header of |
633 ///the EPS file. |
633 ///the EPS file. |
638 ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of |
638 ///namely it inserts a <tt>%%Copyright:</tt> DSC field to the header of |
639 ///the EPS file. |
639 ///the EPS file. |
640 GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;} |
640 GraphToEps<T> ©right(const std::string &t) {_copyright=t;return *this;} |
641 |
641 |
642 protected: |
642 protected: |
643 bool isInsideNode(dim2::Point<double> p, double r,int t) |
643 bool isInsideNode(dim2::Point<double> p, double r,int t) |
644 { |
644 { |
645 switch(t) { |
645 switch(t) { |
646 case CIRCLE: |
646 case CIRCLE: |
647 case MALE: |
647 case MALE: |
648 case FEMALE: |
648 case FEMALE: |
655 return false; |
655 return false; |
656 } |
656 } |
657 |
657 |
658 public: |
658 public: |
659 ~GraphToEps() { } |
659 ~GraphToEps() { } |
660 |
660 |
661 ///Draws the graph. |
661 ///Draws the graph. |
662 |
662 |
663 ///Like other functions using |
663 ///Like other functions using |
664 ///\ref named-templ-func-param "named template parameters", |
664 ///\ref named-templ-func-param "named template parameters", |
665 ///this function calls the algorithm itself, i.e. in this case |
665 ///this function calls the algorithm itself, i.e. in this case |
666 ///it draws the graph. |
666 ///it draws the graph. |
667 void run() { |
667 void run() { |
668 //\todo better 'epsilon' would be nice here. |
668 //\todo better 'epsilon' would be nice here. |
669 const double EPSILON=1e-9; |
669 const double EPSILON=1e-9; |
670 if(dontPrint) return; |
670 if(dontPrint) return; |
671 |
671 |
672 _graph_to_eps_bits::_NegY<typename T::CoordsMapType> |
672 _graph_to_eps_bits::_NegY<typename T::CoordsMapType> |
673 mycoords(_coords,_negY); |
673 mycoords(_coords,_negY); |
674 |
674 |
675 os << "%!PS-Adobe-2.0 EPSF-2.0\n"; |
675 os << "%!PS-Adobe-2.0 EPSF-2.0\n"; |
676 if(_title.size()>0) os << "%%Title: " << _title << '\n'; |
676 if(_title.size()>0) os << "%%Title: " << _title << '\n'; |
677 if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n'; |
677 if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n'; |
678 os << "%%Creator: LEMON, graphToEps()\n"; |
678 os << "%%Creator: LEMON, graphToEps()\n"; |
679 |
679 |
680 { |
680 { |
681 #ifndef WIN32 |
681 #ifndef WIN32 |
682 timeval tv; |
682 timeval tv; |
683 gettimeofday(&tv, 0); |
683 gettimeofday(&tv, 0); |
684 |
684 |
685 char cbuf[26]; |
685 char cbuf[26]; |
686 ctime_r(&tv.tv_sec,cbuf); |
686 ctime_r(&tv.tv_sec,cbuf); |
687 os << "%%CreationDate: " << cbuf; |
687 os << "%%CreationDate: " << cbuf; |
688 #else |
688 #else |
689 SYSTEMTIME time; |
689 SYSTEMTIME time; |
690 char buf1[11], buf2[9], buf3[5]; |
690 char buf1[11], buf2[9], buf3[5]; |
691 |
691 |
692 GetSystemTime(&time); |
692 GetSystemTime(&time); |
693 if (GetDateFormat(LOCALE_USER_DEFAULT, 0, &time, |
693 if (GetDateFormat(LOCALE_USER_DEFAULT, 0, &time, |
694 "ddd MMM dd", buf1, 11) && |
694 "ddd MMM dd", buf1, 11) && |
695 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &time, |
695 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &time, |
696 "HH':'mm':'ss", buf2, 9) && |
696 "HH':'mm':'ss", buf2, 9) && |
697 GetDateFormat(LOCALE_USER_DEFAULT, 0, &time, |
697 GetDateFormat(LOCALE_USER_DEFAULT, 0, &time, |
698 "yyyy", buf3, 5)) { |
698 "yyyy", buf3, 5)) { |
699 os << "%%CreationDate: " << buf1 << ' ' |
699 os << "%%CreationDate: " << buf1 << ' ' |
700 << buf2 << ' ' << buf3 << std::endl; |
700 << buf2 << ' ' << buf3 << std::endl; |
701 } |
701 } |
702 #endif |
702 #endif |
703 } |
703 } |
704 |
704 |
705 if (_autoArcWidthScale) { |
705 if (_autoArcWidthScale) { |
706 double max_w=0; |
706 double max_w=0; |
707 for(ArcIt e(g);e!=INVALID;++e) |
707 for(ArcIt e(g);e!=INVALID;++e) |
708 max_w=std::max(double(_arcWidths[e]),max_w); |
708 max_w=std::max(double(_arcWidths[e]),max_w); |
709 //\todo better 'epsilon' would be nice here. |
709 //\todo better 'epsilon' would be nice here. |
710 if(max_w>EPSILON) { |
710 if(max_w>EPSILON) { |
711 _arcWidthScale/=max_w; |
711 _arcWidthScale/=max_w; |
712 } |
712 } |
713 } |
713 } |
714 |
714 |
715 if (_autoNodeScale) { |
715 if (_autoNodeScale) { |
716 double max_s=0; |
716 double max_s=0; |
717 for(NodeIt n(g);n!=INVALID;++n) |
717 for(NodeIt n(g);n!=INVALID;++n) |
718 max_s=std::max(double(_nodeSizes[n]),max_s); |
718 max_s=std::max(double(_nodeSizes[n]),max_s); |
719 //\todo better 'epsilon' would be nice here. |
719 //\todo better 'epsilon' would be nice here. |
720 if(max_s>EPSILON) { |
720 if(max_s>EPSILON) { |
721 _nodeScale/=max_s; |
721 _nodeScale/=max_s; |
722 } |
722 } |
723 } |
723 } |
724 |
724 |
725 double diag_len = 1; |
725 double diag_len = 1; |
726 if(!(_absoluteNodeSizes&&_absoluteArcWidths)) { |
726 if(!(_absoluteNodeSizes&&_absoluteArcWidths)) { |
727 dim2::BoundingBox<double> bb; |
727 dim2::BoundingBox<double> bb; |
728 for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]); |
728 for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]); |
729 if (bb.empty()) { |
729 if (bb.empty()) { |
730 bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0)); |
730 bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0)); |
731 } |
731 } |
732 diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare()); |
732 diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare()); |
733 if(diag_len<EPSILON) diag_len = 1; |
733 if(diag_len<EPSILON) diag_len = 1; |
734 if(!_absoluteNodeSizes) _nodeScale*=diag_len; |
734 if(!_absoluteNodeSizes) _nodeScale*=diag_len; |
735 if(!_absoluteArcWidths) _arcWidthScale*=diag_len; |
735 if(!_absoluteArcWidths) _arcWidthScale*=diag_len; |
736 } |
736 } |
737 |
737 |
738 dim2::BoundingBox<double> bb; |
738 dim2::BoundingBox<double> bb; |
739 for(NodeIt n(g);n!=INVALID;++n) { |
739 for(NodeIt n(g);n!=INVALID;++n) { |
740 double ns=_nodeSizes[n]*_nodeScale; |
740 double ns=_nodeSizes[n]*_nodeScale; |
741 dim2::Point<double> p(ns,ns); |
741 dim2::Point<double> p(ns,ns); |
742 switch(_nodeShapes[n]) { |
742 switch(_nodeShapes[n]) { |
743 case CIRCLE: |
743 case CIRCLE: |
744 case SQUARE: |
744 case SQUARE: |
745 case DIAMOND: |
745 case DIAMOND: |
746 bb.add(p+mycoords[n]); |
746 bb.add(p+mycoords[n]); |
747 bb.add(-p+mycoords[n]); |
747 bb.add(-p+mycoords[n]); |
748 break; |
748 break; |
749 case MALE: |
749 case MALE: |
750 bb.add(-p+mycoords[n]); |
750 bb.add(-p+mycoords[n]); |
751 bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]); |
751 bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]); |
752 break; |
752 break; |
753 case FEMALE: |
753 case FEMALE: |
754 bb.add(p+mycoords[n]); |
754 bb.add(p+mycoords[n]); |
755 bb.add(dim2::Point<double>(-ns,-3.01*ns)+mycoords[n]); |
755 bb.add(dim2::Point<double>(-ns,-3.01*ns)+mycoords[n]); |
756 break; |
756 break; |
757 } |
757 } |
758 } |
758 } |
759 if (bb.empty()) { |
759 if (bb.empty()) { |
760 bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0)); |
760 bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0)); |
761 } |
761 } |
762 |
762 |
763 if(_scaleToA4) |
763 if(_scaleToA4) |
764 os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n"; |
764 os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n"; |
765 else { |
765 else { |
766 if(_preScale) { |
766 if(_preScale) { |
767 //Rescale so that BoundingBox won't be neither to big nor too small. |
767 //Rescale so that BoundingBox won't be neither to big nor too small. |
768 while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10; |
768 while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10; |
769 while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10; |
769 while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10; |
770 } |
770 } |
771 |
771 |
772 os << "%%BoundingBox: " |
772 os << "%%BoundingBox: " |
773 << int(floor(bb.left() * _scale - _xBorder)) << ' ' |
773 << int(floor(bb.left() * _scale - _xBorder)) << ' ' |
774 << int(floor(bb.bottom() * _scale - _yBorder)) << ' ' |
774 << int(floor(bb.bottom() * _scale - _yBorder)) << ' ' |
775 << int(ceil(bb.right() * _scale + _xBorder)) << ' ' |
775 << int(ceil(bb.right() * _scale + _xBorder)) << ' ' |
776 << int(ceil(bb.top() * _scale + _yBorder)) << '\n'; |
776 << int(ceil(bb.top() * _scale + _yBorder)) << '\n'; |
777 } |
777 } |
778 |
778 |
779 os << "%%EndComments\n"; |
779 os << "%%EndComments\n"; |
780 |
780 |
781 //x1 y1 x2 y2 x3 y3 cr cg cb w |
781 //x1 y1 x2 y2 x3 y3 cr cg cb w |
782 os << "/lb { setlinewidth setrgbcolor newpath moveto\n" |
782 os << "/lb { setlinewidth setrgbcolor newpath moveto\n" |
783 << " 4 2 roll 1 index 1 index curveto stroke } bind def\n"; |
783 << " 4 2 roll 1 index 1 index curveto stroke } bind def\n"; |
784 os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n"; |
784 os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke } bind def\n"; |
785 //x y r |
785 //x y r |
829 << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n" |
829 << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub lineto\n" |
830 << " stroke\n" |
830 << " stroke\n" |
831 << " 5 index 5 index 5 index c fill\n" |
831 << " 5 index 5 index 5 index c fill\n" |
832 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" |
832 << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" |
833 << " } bind def\n"; |
833 << " } bind def\n"; |
834 |
834 |
835 |
835 |
836 os << "/arrl " << _arrowLength << " def\n"; |
836 os << "/arrl " << _arrowLength << " def\n"; |
837 os << "/arrw " << _arrowWidth << " def\n"; |
837 os << "/arrw " << _arrowWidth << " def\n"; |
838 // l dx_norm dy_norm |
838 // l dx_norm dy_norm |
839 os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; |
839 os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; |
840 //len w dx_norm dy_norm x1 y1 cr cg cb |
840 //len w dx_norm dy_norm x1 y1 cr cg cb |
841 os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n" |
841 os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx exch def\n" |
842 << " /w exch def /len exch def\n" |
842 << " /w exch def /len exch def\n" |
843 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" |
843 // << " 0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" |
844 << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" |
844 << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" |
845 << " len w sub arrl sub dx dy lrl\n" |
845 << " len w sub arrl sub dx dy lrl\n" |
846 << " arrw dy dx neg lrl\n" |
846 << " arrw dy dx neg lrl\n" |
847 << " dx arrl w add mul dy w 2 div arrw add mul sub\n" |
847 << " dx arrl w add mul dy w 2 div arrw add mul sub\n" |
848 << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" |
848 << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" |
855 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; |
855 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; |
856 |
856 |
857 os << "\ngsave\n"; |
857 os << "\ngsave\n"; |
858 if(_scaleToA4) |
858 if(_scaleToA4) |
859 if(bb.height()>bb.width()) { |
859 if(bb.height()>bb.width()) { |
860 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(), |
860 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(), |
861 (A4WIDTH-2*A4BORDER)/bb.width()); |
861 (A4WIDTH-2*A4BORDER)/bb.width()); |
862 os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' ' |
862 os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' ' |
863 << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER |
863 << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER |
864 << " translate\n" |
864 << " translate\n" |
865 << sc << " dup scale\n" |
865 << sc << " dup scale\n" |
866 << -bb.left() << ' ' << -bb.bottom() << " translate\n"; |
866 << -bb.left() << ' ' << -bb.bottom() << " translate\n"; |
867 } |
867 } |
868 else { |
868 else { |
869 //\todo Verify centering |
869 //\todo Verify centering |
870 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(), |
870 double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(), |
871 (A4WIDTH-2*A4BORDER)/bb.height()); |
871 (A4WIDTH-2*A4BORDER)/bb.height()); |
872 os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' ' |
872 os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' ' |
873 << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER |
873 << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER |
874 << " translate\n" |
874 << " translate\n" |
875 << sc << " dup scale\n90 rotate\n" |
875 << sc << " dup scale\n90 rotate\n" |
876 << -bb.left() << ' ' << -bb.top() << " translate\n"; |
876 << -bb.left() << ' ' << -bb.top() << " translate\n"; |
877 } |
877 } |
878 else if(_scale!=1.0) os << _scale << " dup scale\n"; |
878 else if(_scale!=1.0) os << _scale << " dup scale\n"; |
879 |
879 |
880 if(_showArcs) { |
880 if(_showArcs) { |
881 os << "%Arcs:\ngsave\n"; |
881 os << "%Arcs:\ngsave\n"; |
882 if(_enableParallel) { |
882 if(_enableParallel) { |
883 std::vector<Arc> el; |
883 std::vector<Arc> el; |
884 for(ArcIt e(g);e!=INVALID;++e) |
884 for(ArcIt e(g);e!=INVALID;++e) |
885 if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0 |
885 if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0 |
886 &&g.source(e)!=g.target(e)) |
886 &&g.source(e)!=g.target(e)) |
887 el.push_back(e); |
887 el.push_back(e); |
888 std::sort(el.begin(),el.end(),arcLess(g)); |
888 std::sort(el.begin(),el.end(),arcLess(g)); |
889 |
889 |
890 typename std::vector<Arc>::iterator j; |
890 typename std::vector<Arc>::iterator j; |
891 for(typename std::vector<Arc>::iterator i=el.begin();i!=el.end();i=j) { |
891 for(typename std::vector<Arc>::iterator i=el.begin();i!=el.end();i=j) { |
892 for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ; |
892 for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ; |
893 |
893 |
894 double sw=0; |
894 double sw=0; |
895 for(typename std::vector<Arc>::iterator e=i;e!=j;++e) |
895 for(typename std::vector<Arc>::iterator e=i;e!=j;++e) |
896 sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist; |
896 sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist; |
897 sw-=_parArcDist; |
897 sw-=_parArcDist; |
898 sw/=-2.0; |
898 sw/=-2.0; |
899 dim2::Point<double> |
899 dim2::Point<double> |
900 dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]); |
900 dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]); |
901 double l=std::sqrt(dvec.normSquare()); |
901 double l=std::sqrt(dvec.normSquare()); |
902 //\todo better 'epsilon' would be nice here. |
902 //\todo better 'epsilon' would be nice here. |
903 dim2::Point<double> d(dvec/std::max(l,EPSILON)); |
903 dim2::Point<double> d(dvec/std::max(l,EPSILON)); |
904 dim2::Point<double> m; |
904 dim2::Point<double> m; |
905 // m=dim2::Point<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0; |
905 // m=dim2::Point<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0; |
906 |
906 |
907 // m=dim2::Point<double>(mycoords[g.source(*i)])+ |
907 // m=dim2::Point<double>(mycoords[g.source(*i)])+ |
908 // dvec*(double(_nodeSizes[g.source(*i)])/ |
908 // dvec*(double(_nodeSizes[g.source(*i)])/ |
909 // (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)])); |
909 // (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)])); |
910 |
910 |
911 m=dim2::Point<double>(mycoords[g.source(*i)])+ |
911 m=dim2::Point<double>(mycoords[g.source(*i)])+ |
912 d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0; |
912 d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0; |
913 |
913 |
914 for(typename std::vector<Arc>::iterator e=i;e!=j;++e) { |
914 for(typename std::vector<Arc>::iterator e=i;e!=j;++e) { |
915 sw+=_arcWidths[*e]*_arcWidthScale/2.0; |
915 sw+=_arcWidths[*e]*_arcWidthScale/2.0; |
916 dim2::Point<double> mm=m+rot90(d)*sw/.75; |
916 dim2::Point<double> mm=m+rot90(d)*sw/.75; |
917 if(_drawArrows) { |
917 if(_drawArrows) { |
918 int node_shape; |
918 int node_shape; |
919 dim2::Point<double> s=mycoords[g.source(*e)]; |
919 dim2::Point<double> s=mycoords[g.source(*e)]; |
920 dim2::Point<double> t=mycoords[g.target(*e)]; |
920 dim2::Point<double> t=mycoords[g.target(*e)]; |
921 double rn=_nodeSizes[g.target(*e)]*_nodeScale; |
921 double rn=_nodeSizes[g.target(*e)]*_nodeScale; |
922 node_shape=_nodeShapes[g.target(*e)]; |
922 node_shape=_nodeShapes[g.target(*e)]; |
923 dim2::Bezier3 bez(s,mm,mm,t); |
923 dim2::Bezier3 bez(s,mm,mm,t); |
924 double t1=0,t2=1; |
924 double t1=0,t2=1; |
925 for(int ii=0;ii<INTERPOL_PREC;++ii) |
925 for(int ii=0;ii<INTERPOL_PREC;++ii) |
926 if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2; |
926 if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2; |
927 else t1=(t1+t2)/2; |
927 else t1=(t1+t2)/2; |
928 dim2::Point<double> apoint=bez((t1+t2)/2); |
928 dim2::Point<double> apoint=bez((t1+t2)/2); |
929 rn = _arrowLength+_arcWidths[*e]*_arcWidthScale; |
929 rn = _arrowLength+_arcWidths[*e]*_arcWidthScale; |
930 rn*=rn; |
930 rn*=rn; |
931 t2=(t1+t2)/2;t1=0; |
931 t2=(t1+t2)/2;t1=0; |
932 for(int ii=0;ii<INTERPOL_PREC;++ii) |
932 for(int ii=0;ii<INTERPOL_PREC;++ii) |
933 if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2; |
933 if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2; |
934 else t2=(t1+t2)/2; |
934 else t2=(t1+t2)/2; |
935 dim2::Point<double> linend=bez((t1+t2)/2); |
935 dim2::Point<double> linend=bez((t1+t2)/2); |
936 bez=bez.before((t1+t2)/2); |
936 bez=bez.before((t1+t2)/2); |
937 // rn=_nodeSizes[g.source(*e)]*_nodeScale; |
937 // rn=_nodeSizes[g.source(*e)]*_nodeScale; |
938 // node_shape=_nodeShapes[g.source(*e)]; |
938 // node_shape=_nodeShapes[g.source(*e)]; |
939 // t1=0;t2=1; |
939 // t1=0;t2=1; |
940 // for(int i=0;i<INTERPOL_PREC;++i) |
940 // for(int i=0;i<INTERPOL_PREC;++i) |
941 // if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2; |
941 // if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t1=(t1+t2)/2; |
942 // else t2=(t1+t2)/2; |
942 // else t2=(t1+t2)/2; |
943 // bez=bez.after((t1+t2)/2); |
943 // bez=bez.after((t1+t2)/2); |
944 os << _arcWidths[*e]*_arcWidthScale << " setlinewidth " |
944 os << _arcWidths[*e]*_arcWidthScale << " setlinewidth " |
945 << _arcColors[*e].red() << ' ' |
945 << _arcColors[*e].red() << ' ' |
946 << _arcColors[*e].green() << ' ' |
946 << _arcColors[*e].green() << ' ' |
947 << _arcColors[*e].blue() << " setrgbcolor newpath\n" |
947 << _arcColors[*e].blue() << " setrgbcolor newpath\n" |
948 << bez.p1.x << ' ' << bez.p1.y << " moveto\n" |
948 << bez.p1.x << ' ' << bez.p1.y << " moveto\n" |
949 << bez.p2.x << ' ' << bez.p2.y << ' ' |
949 << bez.p2.x << ' ' << bez.p2.y << ' ' |
950 << bez.p3.x << ' ' << bez.p3.y << ' ' |
950 << bez.p3.x << ' ' << bez.p3.y << ' ' |
951 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n"; |
951 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n"; |
952 dim2::Point<double> dd(rot90(linend-apoint)); |
952 dim2::Point<double> dd(rot90(linend-apoint)); |
953 dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/ |
953 dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/ |
954 std::sqrt(dd.normSquare()); |
954 std::sqrt(dd.normSquare()); |
955 os << "newpath " << psOut(apoint) << " moveto " |
955 os << "newpath " << psOut(apoint) << " moveto " |
956 << psOut(linend+dd) << " lineto " |
956 << psOut(linend+dd) << " lineto " |
957 << psOut(linend-dd) << " lineto closepath fill\n"; |
957 << psOut(linend-dd) << " lineto closepath fill\n"; |
958 } |
958 } |
959 else { |
959 else { |
960 os << mycoords[g.source(*e)].x << ' ' |
960 os << mycoords[g.source(*e)].x << ' ' |
961 << mycoords[g.source(*e)].y << ' ' |
961 << mycoords[g.source(*e)].y << ' ' |
962 << mm.x << ' ' << mm.y << ' ' |
962 << mm.x << ' ' << mm.y << ' ' |
963 << mycoords[g.target(*e)].x << ' ' |
963 << mycoords[g.target(*e)].x << ' ' |
964 << mycoords[g.target(*e)].y << ' ' |
964 << mycoords[g.target(*e)].y << ' ' |
965 << _arcColors[*e].red() << ' ' |
965 << _arcColors[*e].red() << ' ' |
966 << _arcColors[*e].green() << ' ' |
966 << _arcColors[*e].green() << ' ' |
967 << _arcColors[*e].blue() << ' ' |
967 << _arcColors[*e].blue() << ' ' |
968 << _arcWidths[*e]*_arcWidthScale << " lb\n"; |
968 << _arcWidths[*e]*_arcWidthScale << " lb\n"; |
969 } |
969 } |
970 sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist; |
970 sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist; |
971 } |
971 } |
972 } |
972 } |
973 } |
973 } |
974 else for(ArcIt e(g);e!=INVALID;++e) |
974 else for(ArcIt e(g);e!=INVALID;++e) |
975 if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0 |
975 if((!_undirected||g.source(e)<g.target(e))&&_arcWidths[e]>0 |
976 &&g.source(e)!=g.target(e)) { |
976 &&g.source(e)!=g.target(e)) { |
977 if(_drawArrows) { |
977 if(_drawArrows) { |
978 dim2::Point<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]); |
978 dim2::Point<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]); |
979 double rn=_nodeSizes[g.target(e)]*_nodeScale; |
979 double rn=_nodeSizes[g.target(e)]*_nodeScale; |
980 int node_shape=_nodeShapes[g.target(e)]; |
980 int node_shape=_nodeShapes[g.target(e)]; |
981 double t1=0,t2=1; |
981 double t1=0,t2=1; |
982 for(int i=0;i<INTERPOL_PREC;++i) |
982 for(int i=0;i<INTERPOL_PREC;++i) |
983 if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2; |
983 if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2; |
984 else t2=(t1+t2)/2; |
984 else t2=(t1+t2)/2; |
985 double l=std::sqrt(d.normSquare()); |
985 double l=std::sqrt(d.normSquare()); |
986 d/=l; |
986 d/=l; |
987 |
987 |
988 os << l*(1-(t1+t2)/2) << ' ' |
988 os << l*(1-(t1+t2)/2) << ' ' |
989 << _arcWidths[e]*_arcWidthScale << ' ' |
989 << _arcWidths[e]*_arcWidthScale << ' ' |
990 << d.x << ' ' << d.y << ' ' |
990 << d.x << ' ' << d.y << ' ' |
991 << mycoords[g.source(e)].x << ' ' |
991 << mycoords[g.source(e)].x << ' ' |
992 << mycoords[g.source(e)].y << ' ' |
992 << mycoords[g.source(e)].y << ' ' |
993 << _arcColors[e].red() << ' ' |
993 << _arcColors[e].red() << ' ' |
994 << _arcColors[e].green() << ' ' |
994 << _arcColors[e].green() << ' ' |
995 << _arcColors[e].blue() << " arr\n"; |
995 << _arcColors[e].blue() << " arr\n"; |
996 } |
996 } |
997 else os << mycoords[g.source(e)].x << ' ' |
997 else os << mycoords[g.source(e)].x << ' ' |
998 << mycoords[g.source(e)].y << ' ' |
998 << mycoords[g.source(e)].y << ' ' |
999 << mycoords[g.target(e)].x << ' ' |
999 << mycoords[g.target(e)].x << ' ' |
1000 << mycoords[g.target(e)].y << ' ' |
1000 << mycoords[g.target(e)].y << ' ' |
1001 << _arcColors[e].red() << ' ' |
1001 << _arcColors[e].red() << ' ' |
1002 << _arcColors[e].green() << ' ' |
1002 << _arcColors[e].green() << ' ' |
1003 << _arcColors[e].blue() << ' ' |
1003 << _arcColors[e].blue() << ' ' |
1004 << _arcWidths[e]*_arcWidthScale << " l\n"; |
1004 << _arcWidths[e]*_arcWidthScale << " l\n"; |
1005 } |
1005 } |
1006 os << "grestore\n"; |
1006 os << "grestore\n"; |
1007 } |
1007 } |
1008 if(_showNodes) { |
1008 if(_showNodes) { |
1009 os << "%Nodes:\ngsave\n"; |
1009 os << "%Nodes:\ngsave\n"; |
1010 for(NodeIt n(g);n!=INVALID;++n) { |
1010 for(NodeIt n(g);n!=INVALID;++n) { |
1011 os << mycoords[n].x << ' ' << mycoords[n].y << ' ' |
1011 os << mycoords[n].x << ' ' << mycoords[n].y << ' ' |
1012 << _nodeSizes[n]*_nodeScale << ' ' |
1012 << _nodeSizes[n]*_nodeScale << ' ' |
1013 << _nodeColors[n].red() << ' ' |
1013 << _nodeColors[n].red() << ' ' |
1014 << _nodeColors[n].green() << ' ' |
1014 << _nodeColors[n].green() << ' ' |
1015 << _nodeColors[n].blue() << ' '; |
1015 << _nodeColors[n].blue() << ' '; |
1016 switch(_nodeShapes[n]) { |
1016 switch(_nodeShapes[n]) { |
1017 case CIRCLE: |
1017 case CIRCLE: |
1018 os<< "nc";break; |
1018 os<< "nc";break; |
1019 case SQUARE: |
1019 case SQUARE: |
1020 os<< "nsq";break; |
1020 os<< "nsq";break; |
1021 case DIAMOND: |
1021 case DIAMOND: |
1022 os<< "ndi";break; |
1022 os<< "ndi";break; |
1023 case MALE: |
1023 case MALE: |
1024 os<< "nmale";break; |
1024 os<< "nmale";break; |
1025 case FEMALE: |
1025 case FEMALE: |
1026 os<< "nfemale";break; |
1026 os<< "nfemale";break; |
1027 } |
1027 } |
1028 os<<'\n'; |
1028 os<<'\n'; |
1029 } |
1029 } |
1030 os << "grestore\n"; |
1030 os << "grestore\n"; |
1031 } |
1031 } |
1032 if(_showNodeText) { |
1032 if(_showNodeText) { |
1033 os << "%Node texts:\ngsave\n"; |
1033 os << "%Node texts:\ngsave\n"; |
1034 os << "/fosi " << _nodeTextSize << " def\n"; |
1034 os << "/fosi " << _nodeTextSize << " def\n"; |
1035 os << "(Helvetica) findfont fosi scalefont setfont\n"; |
1035 os << "(Helvetica) findfont fosi scalefont setfont\n"; |
1036 for(NodeIt n(g);n!=INVALID;++n) { |
1036 for(NodeIt n(g);n!=INVALID;++n) { |
1037 switch(_nodeTextColorType) { |
1037 switch(_nodeTextColorType) { |
1038 case DIST_COL: |
1038 case DIST_COL: |
1039 os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n"; |
1039 os << psOut(distantColor(_nodeColors[n])) << " setrgbcolor\n"; |
1040 break; |
1040 break; |
1041 case DIST_BW: |
1041 case DIST_BW: |
1042 os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n"; |
1042 os << psOut(distantBW(_nodeColors[n])) << " setrgbcolor\n"; |
1043 break; |
1043 break; |
1044 case CUST_COL: |
1044 case CUST_COL: |
1045 os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n"; |
1045 os << psOut(distantColor(_nodeTextColors[n])) << " setrgbcolor\n"; |
1046 break; |
1046 break; |
1047 default: |
1047 default: |
1048 os << "0 0 0 setrgbcolor\n"; |
1048 os << "0 0 0 setrgbcolor\n"; |
1049 } |
1049 } |
1050 os << mycoords[n].x << ' ' << mycoords[n].y |
1050 os << mycoords[n].x << ' ' << mycoords[n].y |
1051 << " (" << _nodeTexts[n] << ") cshow\n"; |
1051 << " (" << _nodeTexts[n] << ") cshow\n"; |
1052 } |
1052 } |
1053 os << "grestore\n"; |
1053 os << "grestore\n"; |
1054 } |
1054 } |
1055 if(_showNodePsText) { |
1055 if(_showNodePsText) { |
1056 os << "%Node PS blocks:\ngsave\n"; |
1056 os << "%Node PS blocks:\ngsave\n"; |
1057 for(NodeIt n(g);n!=INVALID;++n) |
1057 for(NodeIt n(g);n!=INVALID;++n) |
1058 os << mycoords[n].x << ' ' << mycoords[n].y |
1058 os << mycoords[n].x << ' ' << mycoords[n].y |
1059 << " moveto\n" << _nodePsTexts[n] << "\n"; |
1059 << " moveto\n" << _nodePsTexts[n] << "\n"; |
1060 os << "grestore\n"; |
1060 os << "grestore\n"; |
1061 } |
1061 } |
1062 |
1062 |
1063 os << "grestore\nshowpage\n"; |
1063 os << "grestore\nshowpage\n"; |
1064 |
1064 |
1065 //CleanUp: |
1065 //CleanUp: |
1066 if(_pleaseRemoveOsStream) {delete &os;} |
1066 if(_pleaseRemoveOsStream) {delete &os;} |
1067 } |
1067 } |
1090 ///An alias for autoArcWidthScale() |
1090 ///An alias for autoArcWidthScale() |
1091 GraphToEps<T> &autoEdgeWidthScale(bool b=true) |
1091 GraphToEps<T> &autoEdgeWidthScale(bool b=true) |
1092 { |
1092 { |
1093 return autoArcWidthScale(b); |
1093 return autoArcWidthScale(b); |
1094 } |
1094 } |
1095 |
1095 |
1096 ///An alias for absoluteArcWidths() |
1096 ///An alias for absoluteArcWidths() |
1097 GraphToEps<T> &absoluteEdgeWidths(bool b=true) |
1097 GraphToEps<T> &absoluteEdgeWidths(bool b=true) |
1098 { |
1098 { |
1099 return absoluteArcWidths(b); |
1099 return absoluteArcWidths(b); |
1100 } |
1100 } |
1101 |
1101 |
1102 ///An alias for parArcDist() |
1102 ///An alias for parArcDist() |
1103 GraphToEps<T> &parEdgeDist(double d) {return parArcDist(d);} |
1103 GraphToEps<T> &parEdgeDist(double d) {return parArcDist(d);} |
1104 |
1104 |
1105 ///An alias for hideArcs() |
1105 ///An alias for hideArcs() |
1106 GraphToEps<T> &hideEdges(bool b=true) {return hideArcs(b);} |
1106 GraphToEps<T> &hideEdges(bool b=true) {return hideArcs(b);} |
1107 |
1107 |
1108 ///@} |
1108 ///@} |
1109 }; |
1109 }; |
1141 ///\warning Don't forget to put the \ref GraphToEps::run() "run()" |
1141 ///\warning Don't forget to put the \ref GraphToEps::run() "run()" |
1142 ///to the end of the parameter list. |
1142 ///to the end of the parameter list. |
1143 ///\sa GraphToEps |
1143 ///\sa GraphToEps |
1144 ///\sa graphToEps(G &g, const char *file_name) |
1144 ///\sa graphToEps(G &g, const char *file_name) |
1145 template<class G> |
1145 template<class G> |
1146 GraphToEps<DefaultGraphToEpsTraits<G> > |
1146 GraphToEps<DefaultGraphToEpsTraits<G> > |
1147 graphToEps(G &g, std::ostream& os=std::cout) |
1147 graphToEps(G &g, std::ostream& os=std::cout) |
1148 { |
1148 { |
1149 return |
1149 return |
1150 GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os)); |
1150 GraphToEps<DefaultGraphToEpsTraits<G> >(DefaultGraphToEpsTraits<G>(g,os)); |
1151 } |
1151 } |
1152 |
1152 |
1153 ///Generates an EPS file from a graph |
1153 ///Generates an EPS file from a graph |
1154 |
1154 |
1155 ///\ingroup eps_io |
1155 ///\ingroup eps_io |
1156 ///This function does the same as |
1156 ///This function does the same as |
1157 ///\ref graphToEps(G &g,std::ostream& os) |
1157 ///\ref graphToEps(G &g,std::ostream& os) |
1158 ///but it writes its output into the file \c file_name |
1158 ///but it writes its output into the file \c file_name |
1159 ///instead of a stream. |
1159 ///instead of a stream. |
1160 ///\sa graphToEps(G &g, std::ostream& os) |
1160 ///\sa graphToEps(G &g, std::ostream& os) |
1161 template<class G> |
1161 template<class G> |
1162 GraphToEps<DefaultGraphToEpsTraits<G> > |
1162 GraphToEps<DefaultGraphToEpsTraits<G> > |
1163 graphToEps(G &g,const char *file_name) |
1163 graphToEps(G &g,const char *file_name) |
1164 { |
1164 { |
1165 return GraphToEps<DefaultGraphToEpsTraits<G> > |
1165 return GraphToEps<DefaultGraphToEpsTraits<G> > |
1166 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true)); |
1166 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true)); |
1167 } |
1167 } |
1173 ///\ref graphToEps(G &g,std::ostream& os) |
1173 ///\ref graphToEps(G &g,std::ostream& os) |
1174 ///but it writes its output into the file \c file_name |
1174 ///but it writes its output into the file \c file_name |
1175 ///instead of a stream. |
1175 ///instead of a stream. |
1176 ///\sa graphToEps(G &g, std::ostream& os) |
1176 ///\sa graphToEps(G &g, std::ostream& os) |
1177 template<class G> |
1177 template<class G> |
1178 GraphToEps<DefaultGraphToEpsTraits<G> > |
1178 GraphToEps<DefaultGraphToEpsTraits<G> > |
1179 graphToEps(G &g,const std::string& file_name) |
1179 graphToEps(G &g,const std::string& file_name) |
1180 { |
1180 { |
1181 return GraphToEps<DefaultGraphToEpsTraits<G> > |
1181 return GraphToEps<DefaultGraphToEpsTraits<G> > |
1182 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true)); |
1182 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name.c_str()),true)); |
1183 } |
1183 } |