📄 graphvisualizer.java
字号:
} } /** * The panel which contains the actual graph. * */ private class GraphPanel extends PrintablePanel { //Image buf; public GraphPanel() { super(); this.addMouseListener( new GraphVisualizerMouseListener() ); this.addMouseMotionListener( new GraphVisualizerMouseMotionListener() ); this.setToolTipText(""); } public String getToolTipText(MouseEvent me) { int x, y, nx, ny; Rectangle r; GraphNode n; Dimension d = m_gp.getPreferredSize(); //System.out.println("Preferred Size: "+this.getPreferredSize()+ // " Actual Size: "+this.getSize()); x=y=nx=ny=0; if(d.width < m_gp.getWidth()) nx = (int)((nx + m_gp.getWidth()/2 - d.width/2)/scale); if(d.height < m_gp.getHeight()) ny = (int)((ny + m_gp.getHeight()/2 - d.height/2)/scale); r = new Rectangle(0, 0, (int)(paddedNodeWidth*scale), (int)(nodeHeight*scale)); x += me.getX(); y += me.getY(); int i; for(i=0; i<m_nodes.size(); i++) { n = (GraphNode) m_nodes.elementAt(i); if(n.nodeType!=NORMAL) return null; r.x = (int)((nx+n.x)*scale); r.y = (int)((ny+n.y)*scale); if(r.contains(x,y)) { if(n.probs==null) return n.lbl; else return n.lbl+" (click to view the probability dist. table)"; } } return null; } public void paintComponent(Graphics gr) { Graphics2D g = (Graphics2D)gr; RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); g.setRenderingHints(rh); g.scale(scale, scale); Rectangle r = g.getClipBounds(); g.clearRect(r.x,r.y,r.width,r.height); //g.setColor(this.getBackground()); //g.fillRect(0, 0, width+5, height+5); int x=0, y=0; Dimension d = this.getPreferredSize(); //System.out.println("Preferred Size: "+this.getPreferredSize()+ // " Actual Size: "+this.getSize()); //initializing x & y to display the graph in the middle //if the display area is larger than the graph if(d.width < this.getWidth()) x = (int)((x + this.getWidth()/2 - d.width/2)/scale); if(d.height < this.getHeight()) y = (int)((y + this.getHeight()/2 - d.height/2)/scale); for(int index=0; index<m_nodes.size(); index++) { GraphNode n = (GraphNode) m_nodes.elementAt(index); if( n.nodeType==NORMAL) { g.setColor( this.getBackground().darker().darker() ); g.fillOval(x+n.x+paddedNodeWidth-nodeWidth- (paddedNodeWidth-nodeWidth)/2, y+n.y, nodeWidth, nodeHeight); g.setColor(Color.white); //g.setColor(Color.black); //System.out.println("drawing "+ // ((GraphNode)m_nodes.elementAt(index)).ID+ // " at "+" x: "+ (x+n.x+paddedNodeWidth/2- // fm.stringWidth( ((GraphNode)m_nodes.elementAt(index)).ID )/2)+ // " y: "+(y+n.y+nodeHeight/2+fm.getHeight()/2-2) ); //Draw the node's label if it can fit inside the node's current // width otherwise display its ID or otherwise just display its // idx in the FastVector (to distinguish it from others) // if any can fit in node's current width if(fm.stringWidth(n.lbl)<=nodeWidth) g.drawString( n.lbl, x+n.x+paddedNodeWidth/2 -fm.stringWidth( n.lbl )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); else if(fm.stringWidth(n.ID)<=nodeWidth) g.drawString( n.ID, x+n.x+paddedNodeWidth/2 -fm.stringWidth( n.ID )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); else if(fm.stringWidth( Integer.toString(index) )<=nodeWidth) g.drawString( Integer.toString(index), x+n.x+paddedNodeWidth/2 -fm.stringWidth( Integer.toString(index) )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); g.setColor(Color.black); } else { //g.draw( new java.awt.geom.QuadCurve2D.Double(n.x+paddedNodeWidth/2, // n.y, // n.x+paddedNodeWidth-nodeSize // -(paddedNodeWidth-nodeSize)/2, // n.y+nodeHeight/2, // n.x+paddedNodeWidth/2, n.y+nodeHeight) ); g.drawLine(x+n.x+paddedNodeWidth/2, y+n.y, x+n.x+paddedNodeWidth/2, y+n.y+nodeHeight); } GraphNode n2; int x1, y1, x2, y2; //System.out.println("Drawing edges of "+n.lbl); //Drawing all the edges coming out from the node, //including reversed and double ones if(n.edges!=null) for(int k=0; k<n.edges.length; k++) { if(n.edges[k][1]>0) { n2 = (GraphNode) m_nodes.elementAt(n.edges[k][0]); //m_nodes.elementAt(k); //System.out.println(" -->to "+n2.lbl); x1=n.x+paddedNodeWidth/2; y1=n.y+nodeHeight; x2=n2.x+paddedNodeWidth/2; y2=n2.y; g.drawLine(x+x1, y+y1, x+x2, y+y2); if(n.edges[k][1]==DIRECTED) { if(n2.nodeType==n2.NORMAL) drawArrow(g, x+x1, y+y1, x+x2, y+y2); } else if(n.edges[k][1]==REVERSED) { if(n.nodeType==NORMAL) drawArrow(g, x+x2, y+y2, x+x1, y+y1); } else if(n.edges[k][1]==DOUBLE) { if(n.nodeType==NORMAL) drawArrow(g, x+x2, y+y2, x+x1, y+y1); if(n2.nodeType==NORMAL) drawArrow(g, x+x1, y+y1, x+x2, y+y2); } } } } } /** * This method draws an arrow on a line from (x1,y1) * to (x2,y2). The arrow head is seated on (x2,y2) and * is in the direction of the line. * If the arrow is needed to be drawn in the opposite * direction then simply swap the order of (x1, y1) * and (x2, y2) when calling this function. */ protected void drawArrow(Graphics g, int x1, int y1, int x2, int y2) { if(x1==x2) { if(y1<y2) { g.drawLine(x2, y2, x2+4, y2-8); g.drawLine(x2, y2, x2-4, y2-8); } else { g.drawLine(x2, y2, x2+4, y2+8); g.drawLine(x2, y2, x2-4, y2+8); } } else { //theta=line's angle from base, beta=angle of arrow's side from line double hyp=0, base=0, perp=0, theta, beta; int x3=0, y3=0; if(x2<x1) { base = x1-x2; hyp = Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); theta = Math.acos( base/hyp ); } else { //x1>x2 as we already checked x1==x2 before base = x1-x2; hyp = Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); theta = Math.acos( base/hyp ); } beta = 30*Math.PI/180; //System.out.println("Original base "+base+" perp "+perp+" hyp "+hyp+ // "\ntheta "+theta+" beta "+beta); hyp = 8; base = Math.cos(theta-beta)*hyp; perp = Math.sin(theta-beta)*hyp; x3 = (int)(x2+base); if(y1<y2) y3 = (int)(y2-perp); else y3 = (int)(y2+perp); //System.out.println("Drawing 1 from "+x2+","+y2+" to "+x3+","+y3+ // " x1,y1 is "+x1+","+y1+" base "+base+ // " perp "+perp+" cos(theta-beta) "+ // Math.cos(theta-beta)); g.drawLine(x2, y2, x3, y3); base = Math.cos(theta+beta)*hyp; perp = Math.sin(theta+beta)*hyp; x3 = (int)(x2+base); if(y1<y2) y3 = (int)(y2-perp); else y3 = (int)(y2+perp); //System.out.println("Drawing 2 from "+x2+","+y2+" to "+x3+","+y3+ // " x1,y1 is "+x1+","+y1+" base "+base+ // " perp "+perp); g.drawLine(x2, y2, x3, y3); } } /** * This method highlights a given node and all its children * and the edges coming out of it. */ public void highLight(GraphNode n) { Graphics2D g = (Graphics2D) this.getGraphics(); RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); g.setRenderingHints(rh); g.setPaintMode(); g.scale(scale, scale); int x=0, y=0; Dimension d = this.getPreferredSize(); //System.out.println("Preferred Size: "+this.getPreferredSize()+ // " Actual Size: "+this.getSize()); //initializing x & y to display the graph in the middle //if the display area is larger than the graph if(d.width < this.getWidth()) x = (int)((x + this.getWidth()/2 - d.width/2)/scale); if(d.height < this.getHeight()) y = (int)((y + this.getHeight()/2 - d.height/2)/scale); //if the node is of type NORMAL only then highlight if(n.nodeType==NORMAL) { g.setXORMode(Color.green); //g.setColor(Color.green); g.fillOval(x+n.x+paddedNodeWidth-nodeWidth- (paddedNodeWidth-nodeWidth)/2, y+n.y, nodeWidth, nodeHeight); g.setXORMode(Color.red); //Draw the node's label if it can fit inside the node's current // width otherwise display its ID or otherwise just display its // idx in the FastVector (to distinguish it from others) // if any can fit in node's current width if(fm.stringWidth(n.lbl)<=nodeWidth) g.drawString( n.lbl, x+n.x+paddedNodeWidth/2 -fm.stringWidth( n.lbl )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); else if(fm.stringWidth(n.ID)<=nodeWidth) g.drawString( n.ID, x+n.x+paddedNodeWidth/2 -fm.stringWidth( n.ID )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); else if( fm.stringWidth( Integer.toString(m_nodes.indexOf(n)) ) <= nodeWidth ) g.drawString( Integer.toString(m_nodes.indexOf(n)), x+n.x+paddedNodeWidth/2 -fm.stringWidth( Integer.toString(m_nodes.indexOf(n)) )/2, y+n.y+nodeHeight/2+fm.getHeight()/2-2 ); g.setXORMode(Color.green); GraphNode n2; int x1, y1, x2, y2; //System.out.println("Drawing edges of "+n.lbl); if(n.edges!=null) //Drawing all the edges from and upward ones coming to the node for(int k=0; k<n.edges.length; k++) { if(n.edges[k][1]==DIRECTED || n.edges[k][1]==DOUBLE) { n2 = (GraphNode) m_nodes.elementAt(n.edges[k][0]); //m_nodes.elementAt(k); //System.out.println(" -->to "+n2.lbl); x1=n.x+paddedNodeWidth/2; y1=n.y+nodeHeight; x2=n2.x+paddedNodeWidth/2; y2=n2.y; g.drawLine(x+x1, y+y1, x+x2, y+y2); if(n.edges[k][1]==DIRECTED) { if(n2.nodeType==n2.NORMAL) //!n2.dummy) drawArrow(g, x+x1, y+y1, x+x2, y+y2); } else if(n.edges[k][1]==DOUBLE) { if(n.nodeType==NORMAL) //!n.dummy) drawArrow(g, x+x2, y+y2, x+x1, y+y1); if(n2.nodeType==NORMAL) //!n2.dummy) drawArrow(g, x+x1, y+y1, x+x2, y+y2); } if(n2.nodeType==NORMAL) g.fillOval(x+n2.x+paddedNodeWidth-nodeWidth- (paddedNodeWidth-nodeWidth)/2, y+n2.y, nodeWidth, nodeHeight); //If n2 is not of NORMAL type // then carry on drawing all the edges and add all the // dummy nodes encountered in a Vector until no // more dummy nodes are found and all the child nodes(node n2) // are of type normal java.util.Vector t = new java.util.Vector(); while(n2.nodeType!=NORMAL || t.size()>0) { //n2.dummy==true) { //System.out.println("in while processing "+n2.ID); if(t.size()>0) { n2 = (GraphNode)t.elementAt(0); t.removeElementAt(0); } if(n2.nodeType!=NORMAL) { g.drawLine(x+n2.x+paddedNodeWidth/2, y+n2.y, x+n2.x+paddedNodeWidth/2, y+n2.y+nodeHeight); x1=n2.x+paddedNodeWidth/2; y1=n2.y+nodeHeight; //System.out.println("Drawing from "+n2.lbl); for(int m=0; m<n2.edges.length; m++) { //System.out.println(" to "+n2.lbl+", "+ // graphMatrix[tmpIndex][m]); if(n2.edges[m][1]>0) { GraphNode n3 = (GraphNode) m_nodes.elementAt(n2.edges[m][0]); //m_nodes.elementAt(m); g.drawLine(x+x1, y+y1, x+n3.x+paddedNodeWidth/2, y+n3.y); if(n3.nodeType==NORMAL){ //!n2.dummy) g.fillOval(x+n3.x+paddedNodeWidth-nodeWidth- (paddedNodeWidth-nodeWidth)/2, y+n3.y, nodeWidth, nodeHeight); drawArrow(g, x+x1, y+y1, x+n3.x+paddedNodeWidth/2, y+n3.y); } //if(n3.nodeType!=n3.NORMAL) t.addElement(n3); //break; } } } } } else if(n.edges[k][1]==-REVERSED || n.edges[k][1]==-DOUBLE) { //Drawing all the reversed and double edges which are going //upwards in the drawing. n2 = (GraphNode) m_nodes.elementAt(n.edges[k][0]); //m_nodes.elementAt(k); //System.out.println(" -->to "+n2.lbl); x1=n.x+paddedNodeWidth/2; y1=n.y; x2=n2.x+paddedNodeWidth/2; y2=n2.y+nodeHeight; g.drawLine(x+x1, y+y1, x+x2, y+y2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -