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), |
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 { |
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; |