| author | wenzelm |
| Fri, 28 Dec 2018 19:01:35 +0100 | |
| changeset 69526 | 5574d504cf36 |
| parent 50473 | ca4088bf8365 |
| permissions | -rw-r--r-- |
/*************************************************************************** Title: GraphBrowser/Graph.java Author: Stefan Berghofer, TU Muenchen Options: :tabSize=4: This class contains the core of the layout algorithm and methods for drawing and PostScript output. ***************************************************************************/ package GraphBrowser; import java.util.*; import java.awt.*; import java.io.*; public class Graph { /**** parameters for layout ****/ public int box_height=0; public int box_height2; public Graphics gfx; Vector vertices=new Vector(10,10); Vector splines=new Vector(10,10); Vector numEdges=new Vector(10,10); Vertex []vertices2; public int min_x=0,min_y=0,max_x=10,max_y=10; /********************************************************************/ /* clone graph object */ /********************************************************************/ public Object clone() { Graph gr=new Graph(); Enumeration e1; int i; gr.splines=(Vector)(splines.clone()); e1=vertices.elements(); while (e1.hasMoreElements()) gr.addVertex((Vertex)(((Vertex)(e1.nextElement())).clone())); for (i=0;i<vertices.size();i++) { Vertex vx1=(Vertex)(gr.vertices.elementAt(i)); e1=((Vertex)(vertices.elementAt(i))).getChildren(); while (e1.hasMoreElements()) { Vertex vx2=(Vertex)(gr.vertices.elementAt(vertices.indexOf(e1.nextElement()))); vx1.addChild(vx2); } } gr.vertices2 = new Vertex[vertices.size()]; gr.vertices.copyInto(gr.vertices2); gr.min_x=min_x;gr.max_x=max_x; gr.min_y=min_y;gr.max_y=max_y; return gr; } Graph() {} /********************************************************************/ /* Read graph from stream */ /********************************************************************/ public Graph(InputStream s,TreeNode tn) throws IOException, ParseError { StreamTokenizer tok=new StreamTokenizer(new InputStreamReader(s)); String name,dir,vertexID; Vertex ve1,ve2; boolean children,unfoldDir; int index=0; tok.nextToken(); while (tok.ttype!=StreamTokenizer.TT_EOF) { if (tok.ttype!=StreamTokenizer.TT_WORD && tok.ttype!='"') throw new ParseError("expected: vertex name\nfound : "+tok.toString()); name=tok.sval; tok.nextToken(); if (tok.ttype!=StreamTokenizer.TT_WORD && tok.ttype!='"') throw new ParseError("expected: vertex identifier\nfound : "+tok.toString()); vertexID=tok.sval; tok.nextToken(); if (tok.ttype!=StreamTokenizer.TT_WORD && tok.ttype!='"') throw new ParseError("expected: directory name\nfound : "+tok.toString()); dir=tok.sval; tok.nextToken(); if (tok.ttype=='+') { unfoldDir=true; tok.nextToken(); } else unfoldDir=false; if (tok.ttype!=StreamTokenizer.TT_WORD && tok.ttype!='"') throw new ParseError("expected: path name\nfound : "+tok.toString()); ve1=findVertex(vertexID); if (ve1==null) { ve1=new NormalVertex(""); ve1.setID(vertexID); ve1.setNumber(index++); addVertex(ve1); } ve1.setPath(tok.sval); ve1.setDir(dir); ve1.setLabel(name); tn.insertNode(name,dir,tok.sval,ve1.getNumber(),unfoldDir); tok.nextToken(); if (tok.ttype=='<') { children=true; tok.nextToken(); } else if (tok.ttype=='>') { children=false; tok.nextToken(); } else children=true; while (tok.ttype!=';') { if (tok.ttype!=StreamTokenizer.TT_WORD && tok.ttype!='"') throw new ParseError("expected: child vertex identifier or ';'\nfound : "+tok.toString()); ve2=findVertex(tok.sval); if (ve2==null) { ve2=new NormalVertex(""); ve2.setID(tok.sval); ve2.setNumber(index++); addVertex(ve2); } if (children) ve1.addChild(ve2); else ve1.addParent(ve2); tok.nextToken(); } tok.nextToken(); } vertices2 = new Vertex[vertices.size()]; vertices.copyInto(vertices2); } /*** Find vertex with identifier vertexID ***/ public Vertex findVertex(String vertexID) { Enumeration e1=vertices.elements(); Vertex v1; while (e1.hasMoreElements()) { v1=(Vertex)(e1.nextElement()); if ((v1.getID()).equals(vertexID)) return v1; } return null; } public void addVertex(Vertex v) { vertices.addElement(v); v.setGraph(this); } public void removeVertex(Vertex v) { vertices.removeElement(v); } public Enumeration getVertices() { return vertices.elements(); } /********************************************************************/ /* graph layout */ /********************************************************************/ public void layout(Graphics g) { splines.removeAllElements(); hasseDiagram(); Vector layers=min_crossings(insert_dummies((Vector)(sort().elementAt(0)))); setParameters(g); init_coordinates(layers); pendulum(layers); rubberband(layers); calcSplines(layers); calcBoundingBox(); } /********************************************************************/ /* set layout parameters */ /********************************************************************/ public void setParameters(Graphics g) { Enumeration e1=vertices.elements(); int h; h=Integer.MIN_VALUE; while (e1.hasMoreElements()) { Box dim=((Vertex)(e1.nextElement())).getLabelSize(g); h=Math.max(h,dim.height); } box_height=h+4; box_height2=box_height/2; gfx=g; } /********************************************************************/ /* topological sorting */ /********************************************************************/ public Vector sort() { Vector todo=(Vector)(vertices.clone()); Vector layers=new Vector(10,10); Vector todo2; Enumeration e1,e2; Vertex v,v2; e1=vertices.elements(); while (e1.hasMoreElements()) ((Vertex)(e1.nextElement())).setDegree(0); e1=vertices.elements(); while (e1.hasMoreElements()) { v=(Vertex)(e1.nextElement()); e2=v.getChildren(); while (e2.hasMoreElements()) { v2=(Vertex)(e2.nextElement()); todo.removeElement(v2); v2.setDegree(1+v2.getDegree()); } } while (!todo.isEmpty()) { layers.addElement(todo); todo2=new Vector(10,10); e1=todo.elements(); while (e1.hasMoreElements()) { e2=((Vertex)(e1.nextElement())).getChildren(); while (e2.hasMoreElements()) { v=(Vertex)(e2.nextElement()); v.setDegree(v.getDegree()-1); if (v.getDegree()==0) { todo2.addElement(v); v.setDegree(layers.size()); } } } todo=todo2; } return layers; } /********************************************************************/ /* compute hasse diagram */ /********************************************************************/ public void hasseDiagram() { Enumeration e1,e2; Vertex vx1,vx2; /** construct adjacence matrix **/ int vs=vertices.size(); boolean adj[][]=new boolean[vs][vs]; boolean adj2[][]=new boolean[vs][vs]; int i,j,k; e1=getVertices(); for (i=0;i<vs;i++) { vx1=(Vertex)(e1.nextElement()); e2=vx1.getChildren(); while (e2.hasMoreElements()) { vx2=(Vertex)(e2.nextElement()); j=vertices.indexOf(vx2); adj[i][j]=true; adj2[i][j]=true; } } /** compute transitive closure R+ **/ for (k=0;k<vs;k++) for (i=0;i<vs;i++) if (adj[i][k]) for (j=0;j<vs;j++) adj[i][j] = adj[i][j] || adj[k][j]; /** compute R \ (R+)^2 **/ for (i=0;i<vs;i++) for (j=0;j<vs;j++) if (adj2[i][j]) { vx1=(Vertex)(vertices.elementAt(i)); vx2=(Vertex)(vertices.elementAt(j)); for (k=0;k<vs;k++) if (adj[i][k] && adj[k][j]) { vx1.removeChild(vx2); break; } } } /********************************************************************/ /* insert dummy vertices */ /********************************************************************/ public Vector insert_dummies(Vector v) { Vector layers2=new Vector(10,10); int n_edges; do { Enumeration e1=v.elements(),e2; Vector next=new Vector(10,10); layers2.addElement(v); n_edges=0; while (e1.hasMoreElements()) { Vertex v1=(Vertex)(e1.nextElement()); e2=v1.getChildren(); while (e2.hasMoreElements()) { n_edges++; Vertex v2=(Vertex)(e2.nextElement()); if (v2.getDegree()!=v1.getDegree()+1) { Vertex v3=new DummyVertex(); v3.addChild(v2); v3.setDegree(v1.getDegree()+1); v1.removeChild(v2); v1.addChild(v3); next.addElement(v3); addVertex(v3); } else if (next.indexOf(v2)<0) next.addElement(v2); } } v=next; numEdges.addElement(new Integer(n_edges)); } while (!v.isEmpty()); return layers2; } /********************************************************************/ /* calculation of crossings */ /********************************************************************/ public int count_crossings(Vector layers,int oldcr) { int i,j,y1,y2,cr=0,l; for (l=0;l<layers.size()-1;l++) { Vector v1=(Vector)(layers.elementAt(l)); for (i=0;i<v1.size();i++) { Enumeration e2=((Vertex)(v1.elementAt(i))).getChildren(); while (e2.hasMoreElements()) { y1=((Vector)(layers.elementAt(l+1))).indexOf(e2.nextElement()); for (j=0;j<i;j++) { Enumeration e3=((Vertex)(v1.elementAt(j))).getChildren(); while (e3.hasMoreElements()) { y2=((Vector)(layers.elementAt(l+1))).indexOf(e3.nextElement()); if (y1<y2) { cr++; if (cr>=oldcr) return cr; } } } } } } return cr; } /********************************************************************/ /* calculation of crossings where vertices vx1 and vx2 are involved */ /* vx1 and vx2 must be in same layer and vx1 is left from vx2 */ /********************************************************************/ public int count_crossings_2(Vector layers,Vertex vx1,Vertex vx2,int oldcr) { int i,cr=0,l=vx1.getDegree(); Vertex va,vb; Vector layer; Enumeration e1,e2; if (l>0) { layer=(Vector)(layers.elementAt(l-1)); e1=vx1.getParents(); while (e1.hasMoreElements()) { va=(Vertex)(e1.nextElement()); i=layer.indexOf(va); e2=vx2.getParents(); while (e2.hasMoreElements()) { vb=(Vertex)(e2.nextElement()); if (layer.indexOf(vb)<i) { cr++; if (cr>=oldcr) return cr; } } } } if (l<layers.size()-1) { layer=(Vector)(layers.elementAt(l+1)); e1=vx1.getChildren(); while (e1.hasMoreElements()) { va=(Vertex)(e1.nextElement()); i=layer.indexOf(va); e2=vx2.getChildren(); while (e2.hasMoreElements()) { vb=(Vertex)(e2.nextElement()); if (layer.indexOf(vb)<i) { cr++; if (cr>=oldcr) return cr; } } } } return cr; } /********************************************************************/ /* reduction of crossings by exchanging adjacent vertices */ /********************************************************************/ public void exchangeVertices(Vector layers,int oldcr) { int i,l,c1,c2; Vertex vx1,vx2; Vector v1; for (l=0;l<layers.size();l++) { v1=(Vector)(layers.elementAt(l)); for (i=0;i<v1.size()-1;i++) { vx1=(Vertex)(v1.elementAt(i)); vx2=(Vertex)(v1.elementAt(i+1)); c1=count_crossings_2(layers,vx1,vx2,oldcr); c2=count_crossings_2(layers,vx2,vx1,c1); if (c2<c1) { v1.setElementAt(vx2,i); v1.setElementAt(vx1,i+1); } } } } /********************************************************************/ /* minimization of crossings */ /********************************************************************/ public Vector min_crossings(Vector layers) { int n,i,l,k,z=0,cr2,cr=count_crossings(layers,Integer.MAX_VALUE); boolean topdown=true,first=true; Enumeration e1,e2; Vector v1,v2,layers2=null,best=layers; Vertex vx1,vx2; n=0; while (n<3 && cr>0) { if (topdown) { /** top-down-traversal **/ layers2=new Vector(10,10); for (l=0;l<layers.size();l++) { v1=(Vector)(layers.elementAt(l)); if (l==0) layers2.addElement(v1.clone()); else { v2=new Vector(10,10); layers2.addElement(v2); e1=v1.elements(); while (e1.hasMoreElements()) { vx1=(Vertex)(e1.nextElement()); k=0;z=0; e2=vx1.getParents(); while (e2.hasMoreElements()) { k+=((Vector)(layers2.elementAt(l-1))).indexOf(e2.nextElement()); z++; } if (z>0) vx1.setWeight(((double)(k))/z); else if (first) vx1.setWeight(Double.MAX_VALUE); for (i=0;i<v2.size();i++) if (vx1.getWeight()<((Vertex)(v2.elementAt(i))).getWeight()) break; if (i==v2.size()) v2.addElement(vx1); else v2.insertElementAt(vx1,i); } } } } else { /** bottom-up-traversal **/ layers2=new Vector(10,10); for (l=layers.size()-1;l>=0;l--) { v1=(Vector)(layers.elementAt(l)); if (l==layers.size()-1) layers2.addElement(v1.clone()); else { v2=new Vector(10,10); layers2.insertElementAt(v2,0); e1=v1.elements(); while (e1.hasMoreElements()) { vx1=(Vertex)(e1.nextElement()); k=0;z=0; e2=vx1.getChildren(); while (e2.hasMoreElements()) { k+=((Vector)(layers2.elementAt(1))).indexOf(e2.nextElement()); z++; } if (z>0) vx1.setWeight(((double)(k))/z); else if (first) vx1.setWeight(Double.MAX_VALUE); for (i=0;i<v2.size();i++) if (vx1.getWeight()<((Vertex)(v2.elementAt(i))).getWeight()) break; if (i==v2.size()) v2.addElement(vx1); else v2.insertElementAt(vx1,i); } } } } //exchangeVertices(layers2,cr); topdown=!topdown; first=false; layers=layers2; cr2=count_crossings(layers2,cr); if (cr2<cr) { best=layers2; cr=cr2; } else n++; } while (true) { exchangeVertices(best,cr); cr2=count_crossings(best,cr); if (cr2<cr) cr=cr2; else break; } return best; } /********************************************************************/ /* set initial coordinates */ /********************************************************************/ public void init_coordinates(Vector layers) { int y=0; Enumeration e1=layers.elements(); Enumeration e3=numEdges.elements(); while (e1.hasMoreElements()) { Vector v1=(Vector)(e1.nextElement()); Enumeration e2=v1.elements(); int x=0; while (e2.hasMoreElements()) { Vertex ve=(Vertex)(e2.nextElement()); ve.setX(x+ve.box_width2()); ve.setY(y); x+=ve.box_width()+20; } y+=box_height+Math.max(35,7*(((Integer)(e3.nextElement())).intValue())); } } /********************************************************************/ /* pendulum method */ /********************************************************************/ public void pendulum(Vector layers) { Vector layers2=new Vector(10,10); Enumeration e1=layers.elements(),e2; int i,j,d1,d2,k,offset,dsum; Region r1,r2; boolean change; while (e1.hasMoreElements()) { e2=((Vector)(e1.nextElement())).elements(); Vector layer=new Vector(10,10); layers2.addElement(layer); while (e2.hasMoreElements()) { Region r=new Region(this); r.addVertex((Vertex)(e2.nextElement())); layer.addElement(r); } } for (k=0;k<10;k++) { dsum=0; for (j=1;j<layers2.size();j++) { Vector l=(Vector)(layers2.elementAt(j)); if (l.size()>=2) { do { change=false; d1=((Region)(l.firstElement())).pred_deflection(); for (i=0;i<l.size()-1;i++) { r1=(Region)(l.elementAt(i)); r2=(Region)(l.elementAt(i+1)); d2=r2.pred_deflection(); if (r1.touching(r2) && (d1 <= 0 && d2 < d1 || d2 > 0 && d1 > d2 || d1 > 0 && d2 < 0)) { r1.combine(r2); l.removeElement(r2); change=true; d2=r1.pred_deflection(); } d1=d2; } } while (change); } for (i=0;i<l.size();i++) { r1=(Region)(l.elementAt(i)); d1=r1.pred_deflection(); offset=d1; if (d1<0 && i>0) offset=-Math.min( ((Region)(l.elementAt(i-1))).spaceBetween(r1),-d1); if (d1>=0 && i<l.size()-1) offset=Math.min( r1.spaceBetween((Region)(l.elementAt(i+1))),d1); r1.move(offset); dsum+=Math.abs(d1); } } if (dsum==0) break; } } /********************************************************************/ /* rubberband method */ /********************************************************************/ public void rubberband(Vector layers) { Enumeration e1,e2; int i,n,k,d,d2; Vector v; Vertex vx; for (k=0;k<10;k++) { e1=layers.elements(); while (e1.hasMoreElements()) { v=(Vector)(e1.nextElement()); for (i=0;i<v.size();i++) { n=0;d=0; vx=(Vertex)(v.elementAt(i)); e2=vx.getChildren(); while (e2.hasMoreElements()) { d+=((Vertex)(e2.nextElement())).getX()-vx.getX(); n++; } e2=vx.getParents(); while (e2.hasMoreElements()) { d+=((Vertex)(e2.nextElement())).getX()-vx.getX(); n++; } d2=(n!=0?d/n:0); if (d<0 && (i==0 || ((Vertex)(v.elementAt(i-1))).rightX()+20 < vx.leftX()+d2) || d>0 && (i==v.size()-1 || ((Vertex)(v.elementAt(i+1))).leftX()-20 > vx.rightX()+d2)) vx.setX(vx.getX()+d2); } } } } /**** Intersection point of two lines (auxiliary function for calcSplines) ****/ /**** Calculate intersection point of line which is parallel to line (p1,p2) ****/ /**** and leads through p5, with line (p3,p4) ****/ Point intersect(Point p1,Point p2,Point p3,Point p4,Point p5) { float x=0,y=0,s1=0,s2=0; if (p1.x!=p2.x) s1=((float)(p2.y-p1.y))/(p2.x-p1.x); if (p3.x!=p4.x) s2=((float)(p4.y-p3.y))/(p4.x-p3.x); if (p1.x==p2.x) { x=p5.x; y=s2*(p5.x-p3.x)+p3.y; } else if (p3.x==p4.x) { x=p3.x; y=s1*(p3.x-p5.x)+p5.y; } else { x=(p5.x*s1-p3.x*s2+p3.y-p5.y)/(s1-s2); y=s2*(x-p3.x)+p3.y; } return new Point(Math.round(x),Math.round(y)); } /**** Calculate control points (auxiliary function for calcSplines) ****/ Points calcPoint(Point p1,Point p2,Point p3,int lboxx,int rboxx,int boxy) { /*** Points p1 , p2 , p3 define a triangle which encloses the spline. ***/ /*** Check if adjacent boxes (specified by lboxx,rboxx and boxy) ***/ /*** collide with the spline. In this case p1 and p3 are shifted by an ***/ /*** appropriate offset before they are returned ***/ int xh1,xh2,bx=0,by=0; boolean pt1 = boxy >= p1.y && boxy <= p3.y || boxy >= p3.y && boxy <= p1.y; boolean pt2 = boxy+box_height >= p1.y && boxy+box_height <= p3.y || boxy+box_height >= p3.y && boxy+box_height <= p1.y; boolean move = false; Point b; xh1 = p1.x+(boxy-p1.y)*(p3.x-p1.x)/(p3.y-p1.y); xh2 = p1.x+(boxy+box_height-p1.y)*(p3.x-p1.x)/(p3.y-p1.y); if (xh1 <= lboxx && pt1 && xh2 <= lboxx && pt2) { move = true; bx = lboxx; by = boxy + (xh1 < xh2 ? 0 : box_height ) ; } else if (xh1 >= rboxx && pt1 && xh2 >= rboxx && pt2) { move = true; bx = rboxx; by = boxy + (xh1 > xh2 ? 0 : box_height ) ; } else if ( (xh1 <= lboxx || xh1 >= rboxx) && pt1) { move = true; bx = (xh1 <= lboxx ? lboxx : rboxx ) ; by = boxy; } else if ( (xh2 <= lboxx || xh2 >= rboxx) && pt2) { move = true; bx = (xh2 <= lboxx ? lboxx : rboxx ) ; by = boxy+box_height; } b=new Point(bx,by); if (move) return new Points(intersect(p1,p3,p1,p2,b),intersect(p1,p3,p2,p3,b)); else return new Points(p1,p3); } /********************************************************************/ /* calculate splines */ /********************************************************************/ public void calcSplines(Vector layers) { Enumeration e2,e1=vertices.elements(); Vertex vx1,vx2,vx3; Vector pos,layer; int x1,y1,x2,y2,x3,y3,xh,k,leftx,rightx,spc; while (e1.hasMoreElements()) { vx1=(Vertex)(e1.nextElement()); if (!vx1.isDummy()) { e2=vx1.getChildren(); while (e2.hasMoreElements()) { vx2=(Vertex)(e2.nextElement()); if (vx2.isDummy()) { vx3=vx2; /**** convert edge to spline ****/ pos=new Vector(10,10); x1=vx1.getX(); y1=vx1.getY()+box_height; do { /*** calculate position of control points ***/ x2=vx2.getX(); y2=vx2.getY(); layer=(Vector)(layers.elementAt(vx2.getDegree())); k=layer.indexOf(vx2); vx2=(Vertex)((vx2.getChildren()).nextElement()); x3=vx2.getX(); y3=vx2.getY(); spc=0; leftx = k==0 /* || ((Vertex)(layer.elementAt(k-1))).isDummy() */ ? Integer.MIN_VALUE: ((Vertex)(layer.elementAt(k-1))).rightX()+spc; rightx = k==layer.size()-1 /* || ((Vertex)(layer.elementAt(k+1))).isDummy() */ ? Integer.MAX_VALUE: ((Vertex)(layer.elementAt(k+1))).leftX()-spc; xh=x2+box_height*(x3-x2)/(y3-y2); if (!(x2<=x3 && xh>=rightx || x2>x3 && xh<=leftx)) { /* top control point */ pos.addElement(new Integer(1)); y1=y2; } else { xh=x1+(y2-y1)*(x2-x1)/(y2+box_height-y1); if (!(x2<=x1 && xh>=rightx || x2>x1 && xh<=leftx)) /* bottom control point */ pos.addElement(new Integer(2)); else /* two control points needed */ pos.addElement(new Integer(3)); y1=y2+box_height; } x1=x2; } while (vx2.isDummy()); pos.addElement(new Integer(1)); /**** calculate triangles ****/ vx2=vx3; int pos1,pos2,i=0; Vector pts=new Vector(10,10); int lboxx,rboxx,boxy; x1=vx1.getX(); y1=vx1.getY()+box_height; pts.addElement(new Point(x1,y1)); /** edge starting point **/ do { x2=vx2.getX(); y2=vx2.getY(); pos1=((Integer)(pos.elementAt(i))).intValue(); pos2=((Integer)(pos.elementAt(i+1))).intValue(); i++; layer=(Vector)(layers.elementAt(vx2.getDegree())); k=layer.indexOf(vx2); boxy=vx2.getY(); vx2=(Vertex)((vx2.getChildren()).nextElement()); x3=vx2.getX(); y3=vx2.getY(); if (pos1==2) y2+=box_height; if (pos2==2) y3+=box_height; lboxx = (k==0 /* || ((Vertex)(layer.elementAt(k-1))).isDummy() */ ) ? Integer.MIN_VALUE : ((Vertex)(layer.elementAt(k-1))).rightX(); rboxx = (k==layer.size()-1 /* || ((Vertex)(layer.elementAt(k+1))).isDummy() */ ) ? Integer.MAX_VALUE : ((Vertex)(layer.elementAt(k+1))).leftX(); Point p1,p2,p3; Points ps; p1 = new Point((x1+x2)/2,(y1+y2)/2); if (pos1<=2) { /** one control point **/ p2 = new Point(x2,y2); ps = calcPoint(p1,p2,new Point((x2+x3)/2,(y2+y3)/2),lboxx,rboxx,boxy); pts.addElement(ps.p); pts.addElement(p2); pts.addElement(ps.q); } else { /** two control points **/ p2 = new Point(x2,y2-box_height); p3 = new Point(x2,y2+box_height2); ps = calcPoint(p1,p2,p3,lboxx,rboxx,boxy); pts.addElement(ps.p); pts.addElement(p2); pts.addElement(ps.q); p2 = new Point(x2,y2+box_height*2); ps = calcPoint(p3,p2,new Point((p2.x+x3)/2,(p2.y+y3)/2), lboxx,rboxx,boxy); pts.addElement(ps.p); pts.addElement(p2); pts.addElement(ps.q); } x1=p2.x; y1=p2.y; } while (vx2.isDummy()); pts.addElement(new Point(vx2.getX(),vx2.getY())); /** edge end point **/ splines.addElement(new Spline(pts)); } } } } } /********************************************************************/ /* calculate bounding box */ /********************************************************************/ public void calcBoundingBox() { min_y=min_x=Integer.MAX_VALUE; max_y=max_x=Integer.MIN_VALUE; Enumeration e1=vertices.elements(); Vertex v; while (e1.hasMoreElements()) { v=(Vertex)(e1.nextElement()); min_x=Math.min(min_x,v.leftX()); max_x=Math.max(max_x,v.rightX()); min_y=Math.min(min_y,v.getY()); max_y=Math.max(max_y,v.getY()+box_height); } min_x-=20; min_y-=20; max_x+=20; max_y+=20; } /********************************************************************/ /* draw graph */ /********************************************************************/ public void draw(Graphics g) { if (box_height==0) layout(g); g.translate(-min_x,-min_y); Enumeration e1=vertices.elements(); while (e1.hasMoreElements()) ((Vertex)(e1.nextElement())).draw(g); e1=splines.elements(); while (e1.hasMoreElements()) ((Spline)(e1.nextElement())).draw(g); } /********************************************************************/ /* return vertex at position (x,y) */ /********************************************************************/ public Vertex vertexAt(int x,int y) { Enumeration e1=vertices.elements(); while (e1.hasMoreElements()) { Vertex v=(Vertex)(e1.nextElement()); if (v.contains(x,y)) return v; } return null; } /********************************************************************/ /* encode list of vertices (as array of vertice numbers) */ /********************************************************************/ public Vector encode(Vector v) { Vector code=new Vector(10,10); Enumeration e1=v.elements(); while (e1.hasMoreElements()) { Vertex vx=(Vertex)(e1.nextElement()); if (vx.getNumber()>=0) code.addElement(new Integer(vx.getNumber())); } return code; } /********************************************************************/ /* get vertex with number n */ /********************************************************************/ public Vertex getVertexByNum(int x) { Enumeration e1=vertices.elements(); while (e1.hasMoreElements()) { Vertex vx=(Vertex)(e1.nextElement()); if (vx.getNumber()==x) return vx; } return null; } /********************************************************************/ /* decode list of vertices */ /********************************************************************/ public Vector decode(Vector code) { Enumeration e1=code.elements(); Vector vec=new Vector(10,10); while (e1.hasMoreElements()) { int i=((Integer)(e1.nextElement())).intValue(); //Vertex vx=getVertexByNum(i); //if (vx!=null) vec.addElement(vx); vec.addElement(vertices2[i]); } return vec; } /********************************************************************/ /* collapse vertices */ /********************************************************************/ public void collapse(Vector vs,String name,Vector inflate) { Enumeration e1,e2,e3; boolean nonempty=false; Vertex vx3,vx2,vx1; e1=vertices.elements(); vx1=new NormalVertex(name); vx1.setInflate(inflate); while (e1.hasMoreElements()) { vx2=(Vertex)(e1.nextElement()); if (vs.indexOf(vx2)<0) { e2=vx2.getParents(); while (e2.hasMoreElements()) { vx3=(Vertex)(e2.nextElement()); if (vs.indexOf(vx3)>=0) { if (!vx1.isChild(vx2)) vx1.addChild(vx2); vx3.removeChild(vx2); } } e2=vx2.getChildren(); while (e2.hasMoreElements()) { vx3=(Vertex)(e2.nextElement()); if (vs.indexOf(vx3)>=0) { if (!vx2.isChild(vx1)) vx2.addChild(vx1); vx2.removeChild(vx3); } } } else { nonempty=true; } } e1=vs.elements(); while (e1.hasMoreElements()) try { removeVertex((Vertex)(e1.nextElement())); } catch (NoSuchElementException exn) {} if (nonempty) addVertex(vx1); } /********************************************************************/ /* PostScript output */ /********************************************************************/ public void PS(String fname,boolean printable) throws IOException { FileOutputStream f = new FileOutputStream(fname); PrintWriter p = new PrintWriter(f, true); if (printable) p.println("%!PS-Adobe-2.0\n\n%%BeginProlog"); else { p.println("%!PS-Adobe-2.0 EPSF-2.0\n%%Orientation: Portrait"); p.println("%%BoundingBox: "+min_x+" "+min_y+" "+max_x+" "+max_y); p.println("%%EndComments\n\n%%BeginProlog"); } p.println("/m { moveto } def /l { lineto } def /n { newpath } def"); p.println("/s { stroke } def /c { curveto } def"); p.println("/b { n 0 0 m dup true charpath pathbbox 1 index 4 index sub"); p.println("7 index exch sub 2 div 9 index add 1 index 4 index sub 7 index exch sub"); p.println("2 div 9 index add 2 index add m pop pop pop pop"); p.println("1 -1 scale show 1 -1 scale n 3 index 3 index m 1 index 0 rlineto"); p.println("0 exch rlineto neg 0 rlineto closepath s pop pop } def"); p.println("%%EndProlog\n"); if (printable) { int hsize=max_x-min_x; int vsize=max_y-min_y; if (hsize>vsize) { // Landscape output double scale=Math.min(1,Math.min(750.0/hsize,500.0/vsize)); double trans_x=50+max_y*scale+(500-scale*vsize)/2.0; double trans_y=50+max_x*scale+(750-scale*hsize)/2.0; p.println(trans_x+" "+trans_y+" translate"); p.println("-90 rotate"); p.println(scale+" "+(-scale)+" scale"); } else { // Portrait output double scale=Math.min(1,Math.min(500.0/hsize,750.0/vsize)); double trans_x=50-min_x*scale+(500-scale*hsize)/2.0; double trans_y=50+max_y*scale+(750-scale*vsize)/2.0; p.println(trans_x+" "+trans_y+" translate"); p.println(scale+" "+(-scale)+" scale"); } } else p.println("0 "+(max_y+min_y)+" translate\n1 -1 scale"); p.println("/Helvetica findfont 12 scalefont setfont"); p.println("0.5 setlinewidth"); Enumeration e1=vertices.elements(); while (e1.hasMoreElements()) ((Vertex)(e1.nextElement())).PS(p); e1=splines.elements(); while (e1.hasMoreElements()) ((Spline)(e1.nextElement())).PS(p); if (printable) p.println("showpage"); f.close(); } } /**** Return value of function calcPoint ****/ class Points { public Point p,q; public Points(Point p1,Point p2) { p=p1;q=p2; } }