alpar@1046: #include alpar@1046: #include alpar@1046: #include alpar@1046: alpar@1046: ///\file alpar@1046: ///Simple graph drawer alpar@1046: alpar@1046: namespace lemon { alpar@1046: alpar@1046: ///\e alpar@1046: class Color alpar@1046: { alpar@1046: double _r,_g,_b; alpar@1046: public: alpar@1046: ///\e alpar@1046: Color() {} alpar@1046: ///\e alpar@1046: Color(double r,double g,double b) :_r(r),_g(g),_b(b) {}; alpar@1046: ///\e alpar@1046: double getR() {return _r;} alpar@1046: ///\e alpar@1046: double getG() {return _g;} alpar@1046: ///\e alpar@1046: double getB() {return _b;} alpar@1046: ///\e alpar@1046: void set(double r,double g,double b) { _r=r;_g=g;_b=b; }; alpar@1046: }; alpar@1046: alpar@1046: ///\e alpar@1046: template alpar@1046: struct DefaultGraphToEpsTraits alpar@1046: { alpar@1046: typedef G Graph; alpar@1046: typedef typename Graph::Node Node; alpar@1046: typedef typename Graph::NodeIt NodeIt; alpar@1046: typedef typename Graph::Edge Edge; alpar@1046: typedef typename Graph::EdgeIt EdgeIt; alpar@1046: typedef typename Graph::InEdgeIt InEdgeIt; alpar@1046: typedef typename Graph::OutEdgeIt OutEdgeIt; alpar@1046: alpar@1046: alpar@1046: const Graph &g; alpar@1046: ConstMap > coords; alpar@1046: ConstMap nodeSizes; alpar@1046: alpar@1046: ConstMap nodeColors; alpar@1046: ConstMap edgeColors; alpar@1046: double nodeSizeScalar; alpar@1046: double xBorder, yBorder; alpar@1046: alpar@1046: DefaultGraphToEpsTraits(G &_g) : alpar@1046: g(_g), coords(xy(1,1)), nodeSizes(1.0), alpar@1046: nodeColors(Color(1,1,1)), edgeColors(Color(0,0,0)), alpar@1046: nodeSizeScalar(1.0), xBorder(10), yBorder(10) {} alpar@1046: }; alpar@1046: alpar@1046: ///\e alpar@1046: template class GraphToEps : public T alpar@1046: { alpar@1046: typedef typename T::Graph Graph; alpar@1046: typedef typename Graph::Node Node; alpar@1046: typedef typename Graph::NodeIt NodeIt; alpar@1046: typedef typename Graph::Edge Edge; alpar@1046: typedef typename Graph::EdgeIt EdgeIt; alpar@1046: typedef typename Graph::InEdgeIt InEdgeIt; alpar@1046: typedef typename Graph::OutEdgeIt OutEdgeIt; alpar@1046: alpar@1046: bool dontPrint; alpar@1046: alpar@1046: public: alpar@1046: GraphToEps(const T &t) : T(t), dontPrint(false) {}; alpar@1046: alpar@1046: template struct SetCoordsTraits : public T { alpar@1046: const X &coords; alpar@1046: SetCoordsTraits(const T &t,const X &x) : T(t), coords(x) {} alpar@1046: }; alpar@1046: ///\e alpar@1046: template GraphToEps > setCoords(const X &x) { alpar@1046: dontPrint=true; alpar@1046: return GraphToEps >(SetCoordsTraits(*this,x)); alpar@1046: } alpar@1046: template struct SetNodeSizesTraits : public T { alpar@1046: const X &nodeSizes; alpar@1046: SetNodeSizesTraits(const T &t,const X &x) : T(t), nodeSizes(x) {} alpar@1046: }; alpar@1046: ///\e alpar@1046: template GraphToEps > setNodeSizes(const X &x) alpar@1046: { alpar@1046: dontPrint=true; alpar@1046: return GraphToEps >(SetNodeSizesTraits(*this,x)); alpar@1046: } alpar@1046: template struct SetNodeColorsTraits : public T { alpar@1046: const X &nodeColors; alpar@1046: SetNodeColorsTraits(const T &t,const X &x) : T(t), nodeColors(x) {} alpar@1046: }; alpar@1046: ///\e alpar@1046: template GraphToEps > alpar@1046: setNodeColors(const X &x) alpar@1046: { alpar@1046: dontPrint=true; alpar@1046: return GraphToEps >(SetNodeColorsTraits(*this,x)); alpar@1046: } alpar@1046: template struct SetEdgeColorsTraits : public T { alpar@1046: const X &edgeColors; alpar@1046: SetEdgeColorsTraits(const T &t,const X &x) : T(t), edgeColors(x) {} alpar@1046: }; alpar@1046: ///\e alpar@1046: template GraphToEps > alpar@1046: setEdgeColors(const X &x) alpar@1046: { alpar@1046: dontPrint=true; alpar@1046: return GraphToEps >(SetEdgeColorsTraits(*this,x)); alpar@1046: } alpar@1046: ///\e alpar@1046: GraphToEps &scaleNodeSize(double d) {nodeSizeScalar=d;return *this;} alpar@1046: alpar@1046: ~GraphToEps() alpar@1046: { alpar@1046: if(dontPrint) return; alpar@1046: alpar@1046: cout << "%!PS-Adobe-2.0 EPSF-2.0\n"; alpar@1046: //\todo: Chech whether the graph is empty. alpar@1046: BoundingBox bb; alpar@1046: for(NodeIt n(g); alpar@1046: n!=INVALID; alpar@1046: ++n) { alpar@1046: xy p(nodeSizes[n]*nodeSizeScalar,nodeSizes[n]*nodeSizeScalar); alpar@1046: bb+=coords[n]+p; alpar@1046: bb+=coords[n]-p; alpar@1046: } alpar@1046: cout << "%%BoundingBox: " alpar@1046: << bb.left()-xBorder << ' ' << bb.bottom()-yBorder << ' ' alpar@1046: << bb.right()+xBorder << ' ' << bb.top()+yBorder << '\n'; alpar@1046: //x1 y1 x2 y2 cr cg cb alpar@1046: cout << "/l { setrgbcolor newpath moveto lineto stroke } bind def\n"; alpar@1046: cout << "/c { newpath dup 3 index add 2 index moveto 0 360 arc } bind def\n"; alpar@1046: // x y r cr cg cb alpar@1046: cout << "/n { setrgbcolor 2 index 2 index 2 index c fill\n" alpar@1046: << " 0 0 0 setrgbcolor dup 10 div setlinewidth c stroke\n" alpar@1046: << " } bind def\n"; alpar@1046: alpar@1046: cout << "%Edges:\ngsave\n"; alpar@1046: for(NodeIt n(g);n!=INVALID;++n) alpar@1046: for(OutEdgeIt e(g,n);e!=INVALID;++e) alpar@1046: cout << coords[g.source(e)].x << ' ' << coords[g.source(e)].y << ' ' alpar@1046: << coords[g.target(e)].x << ' ' << coords[g.target(e)].y << ' ' alpar@1046: << edgeColors[e].getR() << ' ' alpar@1046: << edgeColors[e].getG() << ' ' alpar@1046: << edgeColors[e].getB() << " l\n"; alpar@1046: cout << "grestore\n%Nodes:\ngsave\n"; alpar@1046: for(NodeIt n(g);n!=INVALID;++n) alpar@1046: cout << coords[n].x << ' ' << coords[n].y << ' ' alpar@1046: << nodeSizes[n]*nodeSizeScalar << ' ' alpar@1046: << nodeColors[n].getR() << ' ' alpar@1046: << nodeColors[n].getG() << ' ' alpar@1046: << nodeColors[n].getB() << " n\n"; alpar@1046: cout << "grestore\n"; alpar@1046: } alpar@1046: }; alpar@1046: alpar@1046: alpar@1046: template alpar@1046: GraphToEps > graphToEps(G &g) alpar@1046: { alpar@1046: return GraphToEps >(DefaultGraphToEpsTraits(g)); alpar@1046: } alpar@1046: alpar@1046: } alpar@1046: alpar@1046: using namespace lemon; alpar@1046: alpar@1046: class ColorSet : public MapBase alpar@1046: { alpar@1046: public: alpar@1046: Color operator[](int i) const alpar@1046: { alpar@1046: switch(i%8){ alpar@1046: case 0: return Color(0,0,0); alpar@1046: case 1: return Color(1,0,0); alpar@1046: case 2: return Color(0,1,0); alpar@1046: case 3: return Color(0,0,1); alpar@1046: case 4: return Color(1,1,0); alpar@1046: case 5: return Color(1,0,1); alpar@1046: case 6: return Color(0,1,1); alpar@1046: case 7: return Color(1,1,1); alpar@1046: } alpar@1046: return Color(0,0,0); alpar@1046: } alpar@1046: } colorSet; alpar@1046: alpar@1046: int main() alpar@1046: { alpar@1046: ListGraph g; alpar@1046: typedef ListGraph::Node Node; alpar@1046: typedef ListGraph::NodeIt NodeIt; alpar@1046: typedef ListGraph::Edge Edge; alpar@1046: typedef xy Xy; alpar@1046: alpar@1046: Node n1=g.addNode(); alpar@1046: Node n2=g.addNode(); alpar@1046: Node n3=g.addNode(); alpar@1046: Node n4=g.addNode(); alpar@1046: Node n5=g.addNode(); alpar@1046: alpar@1046: ListGraph::NodeMap coords(g); alpar@1046: ListGraph::NodeMap sizes(g); alpar@1046: ListGraph::NodeMap colors(g); alpar@1047: ListGraph::EdgeMap ecolors(g); alpar@1046: alpar@1046: coords[n1]=Xy(50,50); sizes[n1]=1; colors[n1]=1; alpar@1046: coords[n2]=Xy(50,70); sizes[n2]=2; colors[n2]=2; alpar@1046: coords[n3]=Xy(70,70); sizes[n3]=1; colors[n3]=3; alpar@1046: coords[n4]=Xy(70,50); sizes[n4]=2; colors[n4]=4; alpar@1046: coords[n5]=Xy(85,60); sizes[n5]=3; colors[n5]=5; alpar@1046: alpar@1046: Edge e; alpar@1046: alpar@1047: e=g.addEdge(n1,n2); ecolors[e]=0; alpar@1047: e=g.addEdge(n2,n3); ecolors[e]=0; alpar@1047: e=g.addEdge(n3,n5); ecolors[e]=0; alpar@1047: e=g.addEdge(n5,n4); ecolors[e]=0; alpar@1047: e=g.addEdge(n4,n1); ecolors[e]=0; alpar@1046: e=g.addEdge(n2,n4); ecolors[e]=1; alpar@1046: e=g.addEdge(n3,n4); ecolors[e]=2; alpar@1046: alpar@1046: graphToEps(g).setCoords(coords). alpar@1046: scaleNodeSize(2).setNodeSizes(sizes). alpar@1046: setNodeColors(composeMap(colorSet,colors)). alpar@1046: setEdgeColors(composeMap(colorSet,ecolors)); alpar@1046: }