lemon/graph_to_eps.h
changeset 2271 a2ab63454152
parent 2178 0d7c0f96a5ee
child 2379 248152674a9e
equal deleted inserted replaced
27:639c436359ef 28:75c8e05899e0
    33 
    33 
    34 #include <ctime>
    34 #include <ctime>
    35 #include <cmath>
    35 #include <cmath>
    36 
    36 
    37 #include<lemon/bits/invalid.h>
    37 #include<lemon/bits/invalid.h>
    38 #include<lemon/xy.h>
    38 #include<lemon/dim2.h>
    39 #include<lemon/maps.h>
    39 #include<lemon/maps.h>
    40 #include<lemon/color.h>
    40 #include<lemon/color.h>
    41 #include<lemon/bits/bezier.h>
    41 #include<lemon/bits/bezier.h>
    42 
    42 
    43 
    43 
    79 
    79 
    80   const Graph &g;
    80   const Graph &g;
    81 
    81 
    82   std::ostream& os;
    82   std::ostream& os;
    83   
    83   
    84   typedef ConstMap<typename Graph::Node,xy<double> > CoordsMapType;
    84   typedef ConstMap<typename Graph::Node,dim2::Point<double> > CoordsMapType;
    85   CoordsMapType _coords;
    85   CoordsMapType _coords;
    86   ConstMap<typename Graph::Node,double > _nodeSizes;
    86   ConstMap<typename Graph::Node,double > _nodeSizes;
    87   ConstMap<typename Graph::Node,int > _nodeShapes;
    87   ConstMap<typename Graph::Node,int > _nodeShapes;
    88 
    88 
    89   ConstMap<typename Graph::Node,Color > _nodeColors;
    89   ConstMap<typename Graph::Node,Color > _nodeColors;
   144   ///will be explicitly deallocated by the destructor.
   144   ///will be explicitly deallocated by the destructor.
   145   ///By default it is <tt>std::cout</tt>
   145   ///By default it is <tt>std::cout</tt>
   146   DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
   146   DefaultGraphToEpsTraits(const G &_g,std::ostream& _os=std::cout,
   147 			  bool _pros=false) :
   147 			  bool _pros=false) :
   148     g(_g), os(_os),
   148     g(_g), os(_os),
   149     _coords(xy<double>(1,1)), _nodeSizes(.01), _nodeShapes(0),
   149     _coords(dim2::Point<double>(1,1)), _nodeSizes(.01), _nodeShapes(0),
   150     _nodeColors(WHITE), _edgeColors(BLACK),
   150     _nodeColors(WHITE), _edgeColors(BLACK),
   151     _edgeWidths(1.0), _edgeWidthScale(0.003),
   151     _edgeWidths(1.0), _edgeWidthScale(0.003),
   152     _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
   152     _nodeScale(1.0), _xBorder(10), _yBorder(10), _scale(1.0),
   153     _nodeBorderQuotient(.1),
   153     _nodeBorderQuotient(.1),
   154     _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
   154     _drawArrows(false), _arrowLength(1), _arrowWidth(0.3),
   311 	    g.target(e)==g.target(f)) ||
   311 	    g.target(e)==g.target(f)) ||
   312       (g.source(e)==g.target(f)&&
   312       (g.source(e)==g.target(f)&&
   313        g.target(e)==g.source(f));
   313        g.target(e)==g.source(f));
   314   }
   314   }
   315   template<class TT>
   315   template<class TT>
   316   static std::string psOut(const xy<TT> &p) 
   316   static std::string psOut(const dim2::Point<TT> &p) 
   317     {
   317     {
   318       std::ostringstream os;	
   318       std::ostringstream os;	
   319       os << p.x << ' ' << p.y;
   319       os << p.x << ' ' << p.y;
   320       return os.str();
   320       return os.str();
   321     }
   321     }
   335     CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
   335     CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {}
   336   };
   336   };
   337   ///Sets the map of the node coordinates
   337   ///Sets the map of the node coordinates
   338 
   338 
   339   ///Sets the map of the node coordinates.
   339   ///Sets the map of the node coordinates.
   340   ///\param x must be a node map with xy<double> or \ref xy "xy<int>" values. 
   340   ///\param x must be a node map with dim2::Point<double> or
       
   341   ///\ref dim2::Point "dim2::Point<int>" values. 
   341   template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
   342   template<class X> GraphToEps<CoordsTraits<X> > coords(const X &x) {
   342     dontPrint=true;
   343     dontPrint=true;
   343     return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
   344     return GraphToEps<CoordsTraits<X> >(CoordsTraits<X>(*this,x));
   344   }
   345   }
   345   template<class X> struct NodeSizesTraits : public T {
   346   template<class X> struct NodeSizesTraits : public T {
   667   ///the EPS file.
   668   ///the EPS file.
   668   ///\todo Multiline copyright notice could be supported.
   669   ///\todo Multiline copyright notice could be supported.
   669   GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
   670   GraphToEps<T> &copyright(const std::string &t) {_copyright=t;return *this;}
   670 
   671 
   671 protected:
   672 protected:
   672   bool isInsideNode(xy<double> p, double r,int t) 
   673   bool isInsideNode(dim2::Point<double> p, double r,int t) 
   673   {
   674   {
   674     switch(t) {
   675     switch(t) {
   675     case CIRCLE:
   676     case CIRCLE:
   676     case MALE:
   677     case MALE:
   677     case FEMALE:
   678     case FEMALE:
   734       }
   735       }
   735     }
   736     }
   736 
   737 
   737     double diag_len = 1;
   738     double diag_len = 1;
   738     if(!(_absoluteNodeSizes&&_absoluteEdgeWidths)) {
   739     if(!(_absoluteNodeSizes&&_absoluteEdgeWidths)) {
   739       BoundingBox<double> bb;
   740       dim2::BoundingBox<double> bb;
   740       for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]);
   741       for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]);
   741       if (bb.empty()) {
   742       if (bb.empty()) {
   742 	bb = BoundingBox<double>(xy<double>(0,0));
   743 	bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0));
   743       }
   744       }
   744       diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare());
   745       diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare());
   745       if(diag_len<EPSILON) diag_len = 1;
   746       if(diag_len<EPSILON) diag_len = 1;
   746       if(!_absoluteNodeSizes) _nodeScale*=diag_len;
   747       if(!_absoluteNodeSizes) _nodeScale*=diag_len;
   747       if(!_absoluteEdgeWidths) _edgeWidthScale*=diag_len;
   748       if(!_absoluteEdgeWidths) _edgeWidthScale*=diag_len;
   748     }
   749     }
   749     
   750     
   750     BoundingBox<double> bb;
   751     dim2::BoundingBox<double> bb;
   751     for(NodeIt n(g);n!=INVALID;++n) {
   752     for(NodeIt n(g);n!=INVALID;++n) {
   752       double ns=_nodeSizes[n]*_nodeScale;
   753       double ns=_nodeSizes[n]*_nodeScale;
   753       xy<double> p(ns,ns);
   754       dim2::Point<double> p(ns,ns);
   754       switch(_nodeShapes[n]) {
   755       switch(_nodeShapes[n]) {
   755       case CIRCLE:
   756       case CIRCLE:
   756       case SQUARE:
   757       case SQUARE:
   757       case DIAMOND:
   758       case DIAMOND:
   758 	bb.add(p+mycoords[n]);
   759 	bb.add(p+mycoords[n]);
   759 	bb.add(-p+mycoords[n]);
   760 	bb.add(-p+mycoords[n]);
   760 	break;
   761 	break;
   761       case MALE:
   762       case MALE:
   762 	bb.add(-p+mycoords[n]);
   763 	bb.add(-p+mycoords[n]);
   763 	bb.add(xy<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
   764 	bb.add(dim2::Point<double>(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]);
   764 	break;
   765 	break;
   765       case FEMALE:
   766       case FEMALE:
   766 	bb.add(p+mycoords[n]);
   767 	bb.add(p+mycoords[n]);
   767 	bb.add(xy<double>(-ns,-3.01*ns)+mycoords[n]);
   768 	bb.add(dim2::Point<double>(-ns,-3.01*ns)+mycoords[n]);
   768 	break;
   769 	break;
   769       }
   770       }
   770     }
   771     }
   771     if (bb.empty()) {
   772     if (bb.empty()) {
   772       bb = BoundingBox<double>(xy<double>(0,0));
   773       bb = dim2::BoundingBox<double>(dim2::Point<double>(0,0));
   773     }
   774     }
   774     
   775     
   775     if(_scaleToA4)
   776     if(_scaleToA4)
   776       os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
   777       os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n";
   777     else {
   778     else {
   868     if(_scaleToA4)
   869     if(_scaleToA4)
   869       if(bb.height()>bb.width()) {
   870       if(bb.height()>bb.width()) {
   870 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
   871 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(),
   871 		  (A4WIDTH-2*A4BORDER)/bb.width());
   872 		  (A4WIDTH-2*A4BORDER)/bb.width());
   872 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
   873 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' '
   873 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER << " translate\n"
   874 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER
       
   875 	   << " translate\n"
   874 	   << sc << " dup scale\n"
   876 	   << sc << " dup scale\n"
   875 	   << -bb.left() << ' ' << -bb.bottom() << " translate\n";
   877 	   << -bb.left() << ' ' << -bb.bottom() << " translate\n";
   876       }
   878       }
   877       else {
   879       else {
   878 	//\todo Verify centering
   880 	//\todo Verify centering
   879 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
   881 	double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(),
   880 		  (A4WIDTH-2*A4BORDER)/bb.height());
   882 		  (A4WIDTH-2*A4BORDER)/bb.height());
   881 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
   883 	os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' '
   882 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER  << " translate\n"
   884 	   << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER 
       
   885 	   << " translate\n"
   883 	   << sc << " dup scale\n90 rotate\n"
   886 	   << sc << " dup scale\n90 rotate\n"
   884 	   << -bb.left() << ' ' << -bb.top() << " translate\n";	
   887 	   << -bb.left() << ' ' << -bb.top() << " translate\n";	
   885 	}
   888 	}
   886     else if(_scale!=1.0) os << _scale << " dup scale\n";
   889     else if(_scale!=1.0) os << _scale << " dup scale\n";
   887     
   890     
   902 	  double sw=0;
   905 	  double sw=0;
   903 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
   906 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e)
   904 	    sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
   907 	    sw+=_edgeWidths[*e]*_edgeWidthScale+_parEdgeDist;
   905 	  sw-=_parEdgeDist;
   908 	  sw-=_parEdgeDist;
   906 	  sw/=-2.0;
   909 	  sw/=-2.0;
   907 	  xy<double> dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
   910 	  dim2::Point<double>
       
   911 	    dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]);
   908 	  double l=std::sqrt(dvec.normSquare()); 
   912 	  double l=std::sqrt(dvec.normSquare()); 
   909 	  ///\todo better 'epsilon' would be nice here.
   913 	  ///\todo better 'epsilon' would be nice here.
   910 	  xy<double> d(dvec/std::max(l,EPSILON));
   914 	  dim2::Point<double> d(dvec/std::max(l,EPSILON));
   911  	  xy<double> m;
   915  	  dim2::Point<double> m;
   912 // 	  m=xy<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
   916 // 	  m=dim2::Point<double>(mycoords[g.target(*i)]+mycoords[g.source(*i)])/2.0;
   913 
   917 
   914 //  	  m=xy<double>(mycoords[g.source(*i)])+
   918 //  	  m=dim2::Point<double>(mycoords[g.source(*i)])+
   915 // 	    dvec*(double(_nodeSizes[g.source(*i)])/
   919 // 	    dvec*(double(_nodeSizes[g.source(*i)])/
   916 // 	       (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
   920 // 	       (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)]));
   917 
   921 
   918  	  m=xy<double>(mycoords[g.source(*i)])+
   922  	  m=dim2::Point<double>(mycoords[g.source(*i)])+
   919 	    d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
   923 	    d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0;
   920 
   924 
   921 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
   925 	  for(typename std::vector<Edge>::iterator e=i;e!=j;++e) {
   922 	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
   926 	    sw+=_edgeWidths[*e]*_edgeWidthScale/2.0;
   923 	    xy<double> mm=m+rot90(d)*sw/.75;
   927 	    dim2::Point<double> mm=m+rot90(d)*sw/.75;
   924 	    if(_drawArrows) {
   928 	    if(_drawArrows) {
   925 	      int node_shape;
   929 	      int node_shape;
   926 	      xy<double> s=mycoords[g.source(*e)];
   930 	      dim2::Point<double> s=mycoords[g.source(*e)];
   927 	      xy<double> t=mycoords[g.target(*e)];
   931 	      dim2::Point<double> t=mycoords[g.target(*e)];
   928 	      double rn=_nodeSizes[g.target(*e)]*_nodeScale;
   932 	      double rn=_nodeSizes[g.target(*e)]*_nodeScale;
   929 	      node_shape=_nodeShapes[g.target(*e)];
   933 	      node_shape=_nodeShapes[g.target(*e)];
   930 	      Bezier3 bez(s,mm,mm,t);
   934 	      dim2::Bezier3 bez(s,mm,mm,t);
   931 	      double t1=0,t2=1;
   935 	      double t1=0,t2=1;
   932 	      for(int i=0;i<INTERPOL_PREC;++i)
   936 	      for(int i=0;i<INTERPOL_PREC;++i)
   933 		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
   937 		if(isInsideNode(bez((t1+t2)/2)-t,rn,node_shape)) t2=(t1+t2)/2;
   934 		else t1=(t1+t2)/2;
   938 		else t1=(t1+t2)/2;
   935 	      xy<double> apoint=bez((t1+t2)/2);
   939 	      dim2::Point<double> apoint=bez((t1+t2)/2);
   936 	      rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
   940 	      rn = _arrowLength+_edgeWidths[*e]*_edgeWidthScale;
   937 	      rn*=rn;
   941 	      rn*=rn;
   938 	      t2=(t1+t2)/2;t1=0;
   942 	      t2=(t1+t2)/2;t1=0;
   939 	      for(int i=0;i<INTERPOL_PREC;++i)
   943 	      for(int i=0;i<INTERPOL_PREC;++i)
   940 		if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
   944 		if((bez((t1+t2)/2)-apoint).normSquare()>rn) t1=(t1+t2)/2;
   941 		else t2=(t1+t2)/2;
   945 		else t2=(t1+t2)/2;
   942 	      xy<double> linend=bez((t1+t2)/2);	      
   946 	      dim2::Point<double> linend=bez((t1+t2)/2);	      
   943 	      bez=bez.before((t1+t2)/2);
   947 	      bez=bez.before((t1+t2)/2);
   944 // 	      rn=_nodeSizes[g.source(*e)]*_nodeScale;
   948 // 	      rn=_nodeSizes[g.source(*e)]*_nodeScale;
   945 // 	      node_shape=_nodeShapes[g.source(*e)];
   949 // 	      node_shape=_nodeShapes[g.source(*e)];
   946 // 	      t1=0;t2=1;
   950 // 	      t1=0;t2=1;
   947 // 	      for(int i=0;i<INTERPOL_PREC;++i)
   951 // 	      for(int i=0;i<INTERPOL_PREC;++i)
   954 		 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
   958 		 << _edgeColors[*e].blue() << " setrgbcolor newpath\n"
   955 		 << bez.p1.x << ' ' <<  bez.p1.y << " moveto\n"
   959 		 << bez.p1.x << ' ' <<  bez.p1.y << " moveto\n"
   956 		 << bez.p2.x << ' ' << bez.p2.y << ' '
   960 		 << bez.p2.x << ' ' << bez.p2.y << ' '
   957 		 << bez.p3.x << ' ' << bez.p3.y << ' '
   961 		 << bez.p3.x << ' ' << bez.p3.y << ' '
   958 		 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
   962 		 << bez.p4.x << ' ' << bez.p4.y << " curveto stroke\n";
   959 	      xy<double> dd(rot90(linend-apoint));
   963 	      dim2::Point<double> dd(rot90(linend-apoint));
   960 	      dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
   964 	      dd*=(.5*_edgeWidths[*e]*_edgeWidthScale+_arrowWidth)/
   961 		std::sqrt(dd.normSquare());
   965 		std::sqrt(dd.normSquare());
   962 	      os << "newpath " << psOut(apoint) << " moveto "
   966 	      os << "newpath " << psOut(apoint) << " moveto "
   963 		 << psOut(linend+dd) << " lineto "
   967 		 << psOut(linend+dd) << " lineto "
   964 		 << psOut(linend-dd) << " lineto closepath fill\n";
   968 		 << psOut(linend-dd) << " lineto closepath fill\n";
   980       }
   984       }
   981       else for(EdgeIt e(g);e!=INVALID;++e)
   985       else for(EdgeIt e(g);e!=INVALID;++e)
   982 	if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
   986 	if((!_undirected||g.source(e)<g.target(e))&&_edgeWidths[e]>0
   983 	   &&g.source(e)!=g.target(e))
   987 	   &&g.source(e)!=g.target(e))
   984 	  if(_drawArrows) {
   988 	  if(_drawArrows) {
   985 	    xy<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
   989 	    dim2::Point<double> d(mycoords[g.target(e)]-mycoords[g.source(e)]);
   986 	    double rn=_nodeSizes[g.target(e)]*_nodeScale;
   990 	    double rn=_nodeSizes[g.target(e)]*_nodeScale;
   987 	    int node_shape=_nodeShapes[g.target(e)];
   991 	    int node_shape=_nodeShapes[g.target(e)];
   988 	    double t1=0,t2=1;
   992 	    double t1=0,t2=1;
   989 	    for(int i=0;i<INTERPOL_PREC;++i)
   993 	    for(int i=0;i<INTERPOL_PREC;++i)
   990 	      if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;
   994 	      if(isInsideNode((-(t1+t2)/2)*d,rn,node_shape)) t1=(t1+t2)/2;