103 |
103 |
104 bool _showNodeText; |
104 bool _showNodeText; |
105 ConstMap<typename Graph::Node,bool > _nodeTexts; |
105 ConstMap<typename Graph::Node,bool > _nodeTexts; |
106 double _nodeTextSize; |
106 double _nodeTextSize; |
107 |
107 |
|
108 bool _showNodePsText; |
|
109 ConstMap<typename Graph::Node,bool > _nodePsTexts; |
|
110 char *_nodePsTextsPreamble; |
|
111 |
108 bool _undir; |
112 bool _undir; |
109 bool _pleaseRemoveOsStream; |
113 bool _pleaseRemoveOsStream; |
110 ///Constructor |
114 ///Constructor |
111 |
115 |
112 ///Constructor |
116 ///Constructor |
126 _nodeBorderQuotient(.1), |
130 _nodeBorderQuotient(.1), |
127 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3), |
131 _drawArrows(false), _arrowLength(1), _arrowWidth(0.3), |
128 _showNodes(true), _showEdges(true), |
132 _showNodes(true), _showEdges(true), |
129 _enableParallel(false), _parEdgeDist(1), |
133 _enableParallel(false), _parEdgeDist(1), |
130 _showNodeText(false), _nodeTexts(false), _nodeTextSize(1), |
134 _showNodeText(false), _nodeTexts(false), _nodeTextSize(1), |
|
135 _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0), |
131 _undir(false), |
136 _undir(false), |
132 _pleaseRemoveOsStream(_pros) {} |
137 _pleaseRemoveOsStream(_pros) {} |
133 }; |
138 }; |
134 |
139 |
135 ///Helper class to implement the named parameters of \ref graphToEps() |
140 ///Helper class to implement the named parameters of \ref graphToEps() |
222 { |
227 { |
223 dontPrint=true; |
228 dontPrint=true; |
224 _showNodeText=true; |
229 _showNodeText=true; |
225 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x)); |
230 return GraphToEps<NodeTextsTraits<X> >(NodeTextsTraits<X>(*this,x)); |
226 } |
231 } |
227 template<class X> struct EdgeWidthsTraits : public T { |
232 template<class X> struct NodePsTextsTraits : public T { |
|
233 const X &_nodePsTexts; |
|
234 NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {} |
|
235 }; |
|
236 ///Inserts a PostScript block to the nodes |
|
237 |
|
238 ///With this command it is possible to insert a verbatim PostScript |
|
239 ///block to the nodes. |
|
240 ///The PS current point will be moved to the centre of the node before |
|
241 ///the PostScript block inserted. |
|
242 /// |
|
243 ///Before and after the block a newline character is inserted to you |
|
244 ///don't have to bother with the separators. |
|
245 /// |
|
246 ///\param x must be a node map with type that can be pushed to a standard |
|
247 ///ostream. |
|
248 /// |
|
249 ///\sa nodePsTextsPreamble() |
|
250 ///\todo Offer the choise not to move to the centre but pass the coordinates |
|
251 ///to the Postscript block inserted. |
|
252 template<class X> GraphToEps<NodePsTextsTraits<X> > nodePsTexts(const X &x) |
|
253 { |
|
254 dontPrint=true; |
|
255 _showNodePsText=true; |
|
256 return GraphToEps<NodePsTextsTraits<X> >(NodePsTextsTraits<X>(*this,x)); |
|
257 } |
|
258 template<class X> struct EdgeWidthsTraits : public T { |
228 const X &_edgeWidths; |
259 const X &_edgeWidths; |
229 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {} |
260 EdgeWidthsTraits(const T &t,const X &x) : T(t), _edgeWidths(x) {} |
230 }; |
261 }; |
231 ///Sets the map of the edge widths |
262 ///Sets the map of the edge widths |
232 |
263 |
335 ///Sets the size of the node texts |
366 ///Sets the size of the node texts |
336 |
367 |
337 ///Sets the size of the node texts |
368 ///Sets the size of the node texts |
338 /// |
369 /// |
339 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;} |
370 GraphToEps<T> &nodeTextSize(double d) {_nodeTextSize=d;return *this;} |
|
371 ///Gives a preamble block for node Postscript block. |
|
372 |
|
373 ///Gives a preamble block for node Postscript block. |
|
374 /// |
|
375 ///\sa nodePsTexts() |
|
376 GraphToEps<T> & nodePsTextsPreamble(const char *str) { |
|
377 _nodePsTextsPreamble=s ;return *this; |
|
378 } |
340 ///Sets whether the the graph is undirected |
379 ///Sets whether the the graph is undirected |
341 |
380 |
342 ///Sets whether the the graph is undirected |
381 ///Sets whether the the graph is undirected |
343 /// |
382 /// |
344 GraphToEps<T> &undir(bool b=true) {_undir=b;return *this;} |
383 GraphToEps<T> &undir(bool b=true) {_undir=b;return *this;} |
399 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; |
438 << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; |
400 |
439 |
401 os << "\ngsave\n"; |
440 os << "\ngsave\n"; |
402 if(_scale!=1.0) os << _scale << " dup scale\n"; |
441 if(_scale!=1.0) os << _scale << " dup scale\n"; |
403 |
442 |
404 os << "%Edges:\ngsave\n"; |
443 if(_showEdges) { |
405 |
444 os << "%Edges:\ngsave\n"; |
406 if(_showEdges) |
|
407 if(_enableParallel) { |
445 if(_enableParallel) { |
408 std::vector<Edge> el; |
446 std::vector<Edge> el; |
409 for(EdgeIt e(g);e!=INVALID;++e) |
447 for(EdgeIt e(g);e!=INVALID;++e) |
410 if(!_undir||g.source(e)<g.target(e)) el.push_back(e); |
448 if(!_undir||g.source(e)<g.target(e)) el.push_back(e); |
411 sort(el.begin(),el.end(),edgeLess(g)); |
449 sort(el.begin(),el.end(),edgeLess(g)); |
417 double sw=0; |
455 double sw=0; |
418 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) |
456 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) |
419 sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist; |
457 sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist; |
420 sw-=_parEdgeDist; |
458 sw-=_parEdgeDist; |
421 sw/=-2.0; |
459 sw/=-2.0; |
422 xy<double> d(_coords[g.target(*i)]-_coords[g.source(*i)]); |
460 xy<double> dvec(_coords[g.target(*i)]-_coords[g.source(*i)]); |
423 double l=sqrt(d.normSquare()); |
461 double l=sqrt(dvec.normSquare()); |
424 d/=l; |
462 xy<double> d(dvec/l); |
425 |
463 xy<double> m; |
|
464 // m=xy<double>(_coords[g.target(*i)]+_coords[g.source(*i)])/2.0; |
|
465 |
|
466 // m=xy<double>(_coords[g.source(*i)])+ |
|
467 // dvec*(double(_nodeSizes[g.source(*i)])/ |
|
468 // (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)])); |
|
469 |
|
470 m=xy<double>(_coords[g.source(*i)])+ |
|
471 d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0; |
|
472 |
426 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) { |
473 for(typename std::vector<Edge>::iterator e=i;e!=j;++e) { |
427 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0; |
474 sw+=_edgeWidths[*e]*_edgeWidthScale/2.0; |
428 xy<double> m(_coords[g.target(*e)]+_coords[g.source(*e)]); |
475 xy<double> mm=m+rot(d)*sw/.75; |
429 m=m/2.0+rot(d)*sw/.75; |
|
430 if(_drawArrows) { |
476 if(_drawArrows) { |
431 const int INERPOL_PREC=20; |
477 const int INERPOL_PREC=20; |
432 xy<double> s=_coords[g.source(*e)]; |
478 xy<double> s=_coords[g.source(*e)]; |
433 xy<double> t=_coords[g.target(*e)]; |
479 xy<double> t=_coords[g.target(*e)]; |
434 double rn=_nodeSizes[g.target(*e)]*_nodeScale; |
480 double rn=_nodeSizes[g.target(*e)]*_nodeScale; |
435 rn*=rn; |
481 rn*=rn; |
436 Bezier3 bez(s,m,m,t); |
482 Bezier3 bez(s,mm,mm,t); |
437 double t1=0,t2=1; |
483 double t1=0,t2=1; |
438 for(int i=0;i<INERPOL_PREC;++i) |
484 for(int i=0;i<INERPOL_PREC;++i) |
439 if((bez((t1+t2)/2)-t).normSquare()>rn) t1=(t1+t2)/2; |
485 if((bez((t1+t2)/2)-t).normSquare()>rn) t1=(t1+t2)/2; |
440 else t2=(t1+t2)/2; |
486 else t2=(t1+t2)/2; |
441 xy<double> apoint=bez((t1+t2)/2); |
487 xy<double> apoint=bez((t1+t2)/2); |
470 << psOut(linend-dd) << " lineto closepath fill\n"; |
516 << psOut(linend-dd) << " lineto closepath fill\n"; |
471 } |
517 } |
472 else { |
518 else { |
473 os << _coords[g.source(*e)].x << ' ' |
519 os << _coords[g.source(*e)].x << ' ' |
474 << _coords[g.source(*e)].y << ' ' |
520 << _coords[g.source(*e)].y << ' ' |
475 << m.x << ' ' << m.y << ' ' |
521 << mm.x << ' ' << mm.y << ' ' |
476 << _coords[g.target(*e)].x << ' ' |
522 << _coords[g.target(*e)].x << ' ' |
477 << _coords[g.target(*e)].y << ' ' |
523 << _coords[g.target(*e)].y << ' ' |
478 << _edgeColors[*e].getR() << ' ' |
524 << _edgeColors[*e].getR() << ' ' |
479 << _edgeColors[*e].getG() << ' ' |
525 << _edgeColors[*e].getG() << ' ' |
480 << _edgeColors[*e].getB() << ' ' |
526 << _edgeColors[*e].getB() << ' ' |
507 << _coords[g.target(e)].y << ' ' |
553 << _coords[g.target(e)].y << ' ' |
508 << _edgeColors[e].getR() << ' ' |
554 << _edgeColors[e].getR() << ' ' |
509 << _edgeColors[e].getG() << ' ' |
555 << _edgeColors[e].getG() << ' ' |
510 << _edgeColors[e].getB() << ' ' |
556 << _edgeColors[e].getB() << ' ' |
511 << _edgeWidths[e]*_edgeWidthScale << " l\n"; |
557 << _edgeWidths[e]*_edgeWidthScale << " l\n"; |
512 os << "grestore\n%Nodes:\ngsave\n"; |
558 os << "grestore\n"; |
513 if(_showNodes) |
559 } |
|
560 if(_showNodes) { |
|
561 os << "%Nodes:\ngsave\n"; |
514 for(NodeIt n(g);n!=INVALID;++n) |
562 for(NodeIt n(g);n!=INVALID;++n) |
515 os << _coords[n].x << ' ' << _coords[n].y << ' ' |
563 os << _coords[n].x << ' ' << _coords[n].y << ' ' |
516 << _nodeSizes[n]*_nodeScale << ' ' |
564 << _nodeSizes[n]*_nodeScale << ' ' |
517 << _nodeColors[n].getR() << ' ' |
565 << _nodeColors[n].getR() << ' ' |
518 << _nodeColors[n].getG() << ' ' |
566 << _nodeColors[n].getG() << ' ' |
519 << _nodeColors[n].getB() << " n\n"; |
567 << _nodeColors[n].getB() << " n\n"; |
|
568 os << "grestore\n"; |
|
569 } |
520 if(_showNodeText) { |
570 if(_showNodeText) { |
521 os << "grestore\n%Node texts:\ngsave\n"; |
571 os << "%Node texts:\ngsave\n"; |
522 os << "/fosi " << _nodeTextSize << " def\n"; |
572 os << "/fosi " << _nodeTextSize << " def\n"; |
523 os << "(Helvetica) findfont fosi scalefont setfont\n"; |
573 os << "(Helvetica) findfont fosi scalefont setfont\n"; |
524 os << "0 0 0 setrgbcolor\n"; |
574 os << "0 0 0 setrgbcolor\n"; |
525 for(NodeIt n(g);n!=INVALID;++n) |
575 for(NodeIt n(g);n!=INVALID;++n) |
526 os << _coords[n].x << ' ' << _coords[n].y |
576 os << _coords[n].x << ' ' << _coords[n].y |
527 << " (" << _nodeTexts[n] << ") cshow\n"; |
577 << " (" << _nodeTexts[n] << ") cshow\n"; |
|
578 os << "grestore\n"; |
528 } |
579 } |
529 os << "grestore\ngrestore\n"; |
580 if(_showNodePsText) { |
|
581 os << "%Node PS blocks:\ngsave\n"; |
|
582 for(NodeIt n(g);n!=INVALID;++n) |
|
583 os << _coords[n].x << ' ' << _coords[n].y |
|
584 << " moveto\n" << _nodePsTexts[n] << "\n"; |
|
585 os << "grestore\n"; |
|
586 } |
|
587 |
|
588 os << "grestore\n"; |
530 |
589 |
531 //CleanUp: |
590 //CleanUp: |
532 if(_pleaseRemoveOsStream) {delete &os;} |
591 if(_pleaseRemoveOsStream) {delete &os;} |
533 } |
592 } |
534 }; |
593 }; |
574 { |
633 { |
575 return GraphToEps<DefaultGraphToEpsTraits<G> > |
634 return GraphToEps<DefaultGraphToEpsTraits<G> > |
576 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true)); |
635 (DefaultGraphToEpsTraits<G>(g,*new std::ofstream(file_name),true)); |
577 } |
636 } |
578 |
637 |
579 //Generates an EPS file from a graph. |
|
580 //\param g is a reference to the graph to be printed |
|
581 //\param file_name is the output file_name. |
|
582 // |
|
583 //This function also has a lot of \ref named-templ-param "named parameters", |
|
584 //they are declared as the members of class \ref GraphToEps. The following |
|
585 //example shows how to use these parameters. |
|
586 //\code |
|
587 // graphToEps(g).scale(10).coords(coords) |
|
588 // .nodeScale(2).nodeSizes(sizes) |
|
589 // .edgeWidthScale(.4); |
|
590 //\endcode |
|
591 //\sa GraphToEps |
|
592 //\todo Avoid duplicated documentation |
|
593 //\bug Exception handling is missing? (Or we can just ignore it?) |
|
594 |
|
595 } //END OF NAMESPACE LEMON |
638 } //END OF NAMESPACE LEMON |
596 |
639 |
597 #endif // LEMON_GRAPH_TO_EPS_H |
640 #endif // LEMON_GRAPH_TO_EPS_H |