📄 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 + -