📄 graphpanel.java
字号:
/*
* @(#)GraphPanel.java ver 1.2 6/20/2005
*
* Modified by Weishuai Yang (wyang@cs.binghamton.edu).
* This file is based on NED from Tatiana Kichkaylo at NYU
*
*/
package gps.gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.JPanel;
import gps.network.graph.Graph;
import gps.network.graph.Link;
import gps.network.graph.Node;
import gps.protocol.Agent;
/**
* This panel visualize network topology and agents informaiton.
* This file is based on NED from Tatiana Kichkaylo at NYU
*/
public class GraphPanel extends JPanel {
private Graph graph = null;
private Graphics bufferGraphics = null; //Graphics context for double buffer
private Rectangle r = new Rectangle(0,0,0,0); //Bounding box for double buffer
private Image bufferImage = null;
private double RTX, RTY, /*right top*/ LBX, LBY /*left bottom*/;
private int vMargin=0, hMargin=0;
private Node[] nodes=null;
private Link[] links=null;
private static Color linkColor[] = { Color.lightGray, Color.cyan, Color.red };
private float scale = 5;
private boolean showNodeId=false;
private boolean[] matrix = null;
private int minimum = 25, minimum2 = 100;
/**
* distance for ss, ts, tt
*/
public static double dist[] = { 7, 20, 55 };
/**
* coefficient
*/
public static double coef[] = { 1, 1, 1 };
/**
* dummy constructor
*
*/
public GraphPanel() {
super();
}
/**
* graph panel size
*/
public Dimension size = new Dimension( 480, 480 );
/**
* gets graph panel size
* @return size
*/
public Dimension getPreferredSize() { return size; }
/**
* gets minimum graph panel size
* @return size
*/
public Dimension getMinimumSize() { return size; }
/**
* sets graph to be displayed
* @param g graph
*/
public void setGraph(Graph g){
graph=g;
if(g==null)
return;
nodes = graph.getAllNodes();
links = graph.getAllLinks();
initLinkMatrix();
for ( int i=0; i<links.length; i++ ) {
int f=links[i].fromNode();
int t=links[i].toNode();
int type = 0;
// link type: 0=S-S, 1=S-T, 2=T-T
if((nodes[f].getProperties().getType()==16)&&(nodes[t].getProperties().getType()==16)){
type=2;
}
else if((nodes[f].getProperties().getType()==16)||(nodes[t].getProperties().getType()==16)){
type=1;
}
links[i].getProperties().setType(type);
}
}
/**
* gets graph being displayed
* @return Graph object
*/
public Graph getGraph(){
return graph;
}
/*
public GraphPanel( GraphMouseListener list ) {
super();
addMouseMotionListener( (MouseMotionListener) list );
addMouseListener ( (MouseListener) list );
}
*/
/**
* sets flag for showing id or not
* @param b flag
*/
public void setShowNodeId(boolean b){
showNodeId=b;
}
/**
* gets current flag for showing id or not
* @return flag
*/
public boolean getShowNodeId(){
return showNodeId;
}
/**
* paint graphical area
* @param g Graphics handle
*/
public void paint( Graphics g ) {
update( g );
}
/**
* update graphical area
* @param g Graphics handle
*/
public void update( Graphics g ) {
if (r.width != getBounds().width || r.height != getBounds().height) {
bufferImage = createImage(getBounds().width, getBounds().height);
bufferGraphics = bufferImage.getGraphics(); //*Whenever applet changes size*
r = getBounds(); //*create a new double buffer, and*
}
render(bufferGraphics); //*We ask application program to render to the buffer*
g.drawImage(bufferImage,0,0,this); //*And then paste in the rendered buffer.*
}
/**
* relax links between nodes, make them looks more clear
*/
public void relax() {
double[] fx, fy;
fx=new double[nodes.length];
fy=new double[nodes.length];
// clean all
for ( int i=0; i<nodes.length; i++ ) {
fx[i] = 0; fy[i] = 0;
}
linkShrink(fx, fy);
nodeRepulse(fx, fy);
linkNodeRepulse(fx, fy);
// move all
for ( int i=0; i<nodes.length; i++ ) {
double c = 0.1;
//System.out.println( nodes[i].getProperties().getX()+":"+nodes[i].getProperties().getY()+" "+fx[i]+":"+fy[i] );
double newx=nodes[i].getProperties().getX() + c*fx[i];
double newy=nodes[i].getProperties().getY() + c*fy[i];
nodes[i].getProperties().setX(newx);
nodes[i].getProperties().setY(newy);
}
}
//*****************************************************************************
private void initLinkMatrix() {
//initialize link matrix between nodes
matrix = new boolean[nodes.length*nodes.length];
for ( int i=0; i<nodes.length*nodes.length; i++ )
matrix[i]=false;
for ( int i=0; i<links.length; i++ ) {
matrix[ links[i].fromNode()*nodes.length+links[i].toNode() ] = true;
matrix[ links[i].toNode()*nodes.length+links[i].fromNode() ] = true;
}
}
private void render( Graphics g ) {
if(graph==null||!graph.isValid()) {
super.paint( g );
return;
}
compSize();
g.setColor( Color.white);
g.fillRect( 0, 0, r.width, r.height );
//draw links
for ( int i=0; i<links.length; i++ ) {
int f=links[i].fromNode();
int x1 = (int)((nodes[f].getProperties().getX()-LBX)*scale)+vMargin;
int y1 = (int)((nodes[f].getProperties().getY()-LBY)*scale)+hMargin;
int t=links[i].toNode();
int x2 = (int)((nodes[t].getProperties().getX()-LBX)*scale)+vMargin;
int y2 = (int)((nodes[t].getProperties().getY()-LBY)*scale)+hMargin;
int type=links[i].getProperties().getType();
// link type: 0=S-S, 1=S-T, 2=T-T
g.setColor( linkColor[type] );
g.drawLine( x1, y1, x2, y2 );
links[i].getBandwidthManager().bandwidthDraw(g,(x1+x2)/2,(y1+y2)/2);
}
//draw nodes
for ( int i=0; i<nodes.length; i++ ) {
int x = (int)((nodes[i].getProperties().getX()-LBX)*scale)+vMargin;
int y = (int)((nodes[i].getProperties().getY()-LBY)*scale)+hMargin;
//transit is 16
if ( nodes[i].getProperties().getType()==16 ){
g.setColor( Color.red );
g.drawOval( x-6, y-6, 12, 12 );
g.drawOval( x-5, y-5, 10, 10 );
}
//stub is 8
else if ( nodes[i].getProperties().getType()==8 ) {
g.setColor( Color.blue );
g.drawOval( x-4, y-4, 8, 8 );
}
else{
g.setColor( Color.black );
g.drawOval( x-4, y-4, 8, 8 );
}
if(showNodeId)
g.drawString(""+i,x-15,y );
//add agent specific drawing
int s=nodes[i].getAgentList().size();
if(s!=0){
for(int m=0;m<s;m++)
((Agent)(nodes[i].getAgentList().get(m))).agentDraw(g,x,y);
//System.out.println("rander called for node "+i+" size "+nodes[i].getAgentList().size()+" with agent "+ (Agent)(nodes[i].getAgentList().get(0)));
//System.out.println("agentDraw called to node"+i);
}
}
}
private void compSize() {
//maximum size
RTX = 0; RTY = 0;
for (int i=0; i<nodes.length; i++ ) {
if ( nodes[i].getProperties().getX()>RTX )
RTX = nodes[i].getProperties().getX();
if ( nodes[i].getProperties().getY()>RTY )
RTY = nodes[i].getProperties().getY();
}
//minimum size
LBX = RTX; LBY = RTY;
for (int i=0; i<nodes.length; i++ ) {
if ( nodes[i].getProperties().getX() <LBX )
LBX = nodes[i].getProperties().getX();
if ( nodes[i].getProperties().getY() <LBY )
LBY = nodes[i].getProperties().getY();
}
//// System.out.println( RTX+":"+RTY+" "+LBX+":"+LBY );
scale = (r.width-60)/(float)( RTX - LBX );
vMargin=30;
hMargin=(int)(r.height-( RTY - LBY )*scale)/2;
if ( (r.height-60)/(float)( RTY - LBY ) < scale ) {
scale = (r.height-60)/(float)( RTY - LBY );
hMargin=30;
vMargin=(int)(r.width-( RTX - LBX )*scale)/2;
}
}
private void linkShrink(double[] fx, double[] fy) {
for ( int i=0; i<links.length; i++ ) {
// link type: 0=S-S, 1=S-T, 2=T-T
int type = links[i].getProperties().getType();
int f=links[i].fromNode();
int t=links[i].toNode();
// current distance
double x1 = nodes[f].getProperties().getX();
double y1 = nodes[f].getProperties().getY();
double x2 = nodes[t].getProperties().getX();
double y2 = nodes[t].getProperties().getY();
double d = Math.sqrt( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) );
//System.out.println( dist[type]+":"+d );
double s = (dist[type]-d)/d;
//s = s*s;
fx[ f ] += (x1-x2)*s;
fy[ f ] += (y1-y2)*s;
fx[ t ] -= (x1-x2)*s;
fy[ t ] -= (y1-y2)*s;
}
}
private void nodeRepulse(double[] fx, double[] fy) {
for ( int i=0; i<nodes.length; i++ )
for ( int j=i+1; j<nodes.length; j++ ) {
// if there is a link, do not do anything
if ( matrix[ i*nodes.length+j ] ) continue;
// real distance
double xx = nodes[i].getProperties().getX() - nodes[j].getProperties().getX();
double yy = nodes[i].getProperties().getY() - nodes[j].getProperties().getY();
double d = Math.sqrt( xx*xx+yy*yy );
// desired distance
double m = minimum;
if ( (nodes[i].getProperties().getType()==16) && (nodes[j].getProperties().getType()==16))
m = minimum2;
if ( d<m ) {
double c = 0.2;
double s;
if ( d>0.1 )
s = (m-d)/d;
else
s = 5;
s = s*s;
//System.out.println( m+"->"+d+" "+(c*s) );
fx[i] += c*xx*s;
fy[i] += c*yy*s;
fx[j] -= c*xx*s;
fy[j] -= c*yy*s;
}
}
}
private static class Geom {
//********************************************************************************
// line equasion is coef[0]*X + coef[1]*Y + coef[2] = 0
public static void lineCoef( double x1, double y1, double x2, double y2, double[] coef ) {
if ( x1==x2 ) { // vertical
coef[0] = 1;
coef[1] = 0;
coef[2] = x1;
} else if ( y1==y2 ) { // horizontal
coef[0] = 0;
coef[1] = 1;
coef[2] = y1;
} else {
coef[0] = 1/(x2-x1);
coef[1] = 1/(y1-y2);
coef[2] = y1/(y2-y1) - x1/(x2-x1);
coef[1] /= coef[0];
coef[2] /= coef[0];
coef[0] = 1;
}
////System.out.println( "Line coef "+x1+":"+y1+"-"+x2+":"+y2+" "+coef[0]+", "+coef[1]+", "+coef[2] );
}
//********************************************************************************
public static boolean inSegment( double x1, double y1, double x2, double y2, double[] p ) {
double c = 0.01, t;
if ( x1>x2 ) { t = x1; x1 = x2; x2 = t; }
if ( y1>y2 ) { t = y1; y1 = y2; y2 = t; }
boolean res = false;
if ( x2-x1>4*c && p[0]-x1>c && x2-p[0]>c ) res = true;
if ( y2-y1>4*c && p[1]-y1>c && y2-p[1]>c ) res = true;
////System.out.println( "Segment "+x1+":"+x+":"+x2+" "+y1+":"+y+":"+y2+" "+res );
return res;
}
//********************************************************************************
public static void intersect( double[] l1, double[] l2, double[] p ) {
if ( l1[0]==0 ) {
p[1] = -l1[2];
p[0] = - ( l2[1]*p[1] + l2[2] );
} else if ( l2[0]==0 ) {
p[1] = -l2[2];
p[0] = -( l1[1]*p[1] + l1[2] );
} else {
p[1] = - ( l1[2] - l2[2] )/( l1[1] - l2[1] );
p[0] = - ( l1[1]*p[1] + l1[2] );
}
}
//********************************************************************************
public static void perpend( double[] line, double[] point, double[] perp ) {
// perp line eq: Bx - Ay + D = 0, where the original one is Ax + By + C = 0
perp[0] = line[1];
perp[1] = -line[0];
perp[2] = - (perp[0]*point[0] + perp[1]*point[1]);
}
//********************************************************************************
public static double distance( double[] p1, double[] p2 ) {
double x = p1[0]-p2[0], y = p1[1]-p2[1];
return Math.sqrt( x*x + y*y );
}
}
private void linkNodeRepulse(double[] fx, double[] fy) {
for ( int i=0; i<nodes.length; i++ ){
for ( int j=0; j<links.length; j++ ) {
// node does not belong to the link
int f=links[j].fromNode();
int t=links[j].toNode();
if ( f==i || t==i ) continue;
double[] link = { 0, 0, 0 };
double[] node = { nodes[i].getProperties().getX(), nodes[i].getProperties().getY() };
double[] perp = { 0, 0, 0 };
double[] inter = { 0, 0 };
Geom.lineCoef( nodes[f].getProperties().getX(), nodes[f].getProperties().getY(), nodes[t].getProperties().getX(), nodes[t].getProperties().getY(), link );
Geom.perpend( link, node, perp );
Geom.intersect( link, perp, inter );
// if intersection outside the link, do not worry
if ( !Geom.inSegment( nodes[f].getProperties().getX(), nodes[f].getProperties().getY(), nodes[t].getProperties().getX(), nodes[t].getProperties().getY(), inter) )
continue;
double d = Geom.distance( node, inter );
double rate;
if ( Math.abs( d )<1 )
rate = 0.2;
else
rate = 0.2/Math.sqrt(d);
// add repulsion along the distance vector
if ( d>0.01 ) {
fx[ i ] -= rate* (inter[0]-node[0])/d;
fy[ i ] -= rate* (inter[1]-node[1])/d;
}
else {
fx[ i ] -= 1;
fy[ i ] -= 1;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -