📄 gemlayoutalgorithm.java
字号:
Object[] cells = jgraph.getRoots();
Object[] selectedCells = jgraph.getSelectionCells();
CellView[] view = jgraph.getGraphLayoutCache().getMapping(cells,false);
CellView[] selectedView = jgraph.getGraphLayoutCache().getMapping(
selectedCells,false);
for (int i = 0; i < view.length; i++)
if (view[i] instanceof VertexView){
cellList.add(view[i]);
if( applyToAll )
applyCellList.add(view[i]);
}
else if( view[i] instanceof EdgeView ){
edgeList.add(view[i]);
}
if( !applyToAll )
for( int i = 0; i < selectedView.length; i++ )
if( selectedView[i] instanceof VertexView )
applyCellList.add(selectedView[i]);
}
/******************************************************************************/
/**
* Sets the initial Values, gained from the {@link #config configuration}
* into the Cells.
*
* @return Because the progress dialog is allready visible during the
* initialisation, <b><code>true</code><b> is returned when cancel is pressed
* on it.
*/
private boolean initialize(){
dlgProgress.setVisible(true);
dlgProgress.setMessage(phaseName[PHASE_INITIALISATION]);
int length = cellList.size();
for( int i = 0; i < length; i++ ){
CellView view = (CellView) cellList.get(i);
initializeVertice(view);
if( updateProgressDialog(PHASE_INITIALISATION,
i,
length) )
return true; // canceled
}
for( int i = 0; i < applyCellList.size(); i++ )
computeLastImpulse( (CellView) applyCellList.get(i) );
return false; //not canceled
}
/******************************************************************************/
/**
* Sets the initial values for one Cell.
*
* @param view Cell, the initial values should be set for.
*/
private void initializeVertice(CellView view){
Map attributes = view.getAttributes();
if( attributes == null )
attributes = new Hashtable();
attributes.put(KEY_CAPTION,KEY_CAPTION);
initPosition(view);
if( isCluster(view) ){
attributes.put(KEY_TEMPERATURE,
new Double(clusterInitTemperature));
}
else attributes.put(KEY_TEMPERATURE,
new Double(initTemperature));
attributes.put(KEY_SKEWGAUGE, new Double(0.0));
attributes.put(KEY_CURRENT_IMPULSE,new Point2D.Double());
attributes.put(KEY_LAST_IMPULSE ,new Point2D.Double());
}
/******************************************************************************/
/**
* Runs the algorithm. First a running sequence is initialised. If
* {@link #shouldComputePermuation} is <b><code>true</code><b> then a new
* permutation is computed for every round, else a single determined sequence is
* established. After this for every Cell a current impulse is calculated,
* position and temperature is updated. This is done, until the graph is frozen,
* a maximum on rounds is reached or cancel on the progress dialog is pressed.
*
* @return <b><code>true</code></b> when cancel on the progress dialog is
* pressed
* @see #computeCurrentImpulse(CellView)
* @see #createPermutation(int)
* @see #isFrozen()
* @see #updatePosAndTemp(CellView)
*/
private boolean calculate(){
int length = applyCellList.size();
int[] sequence = new int[length];
boolean isCanceled = false;
dlgProgress.setMessage(phaseName[PHASE_CALCULATION]);
//case no permutation is desired, the series is computed one time only
if( !shouldComputePermutation ) //else is in the loop below
for( int i = 0; i < length; i++ )
sequence[i] = i;
while( !isFrozen() && countRounds <= maxRounds && (!isCanceled) ){
//case permutation is desired, it's calculated every round
if( shouldComputePermutation )
sequence = createPermutation(length);
//loop over all nodes (order is in sequence)
for( int i = 0; i < sequence.length; i++ ){
CellView view = (CellView) applyCellList.get(sequence[i]);
computeCurrentImpulse(view); //computes direction of impulse
updatePosAndTemp(view); //computes new position and temperature
if( updateProgressDialog(PHASE_CALCULATION,
(countRounds*sequence.length)+i,
maxRounds*sequence.length ) )
return true;
}
countRounds++;
}
return false;
}
/******************************************************************************/
/**
* Helps updating the progress dialog.
*
* @param phase Identifies the phase, the algorithmis doing.
* @param round current round, the algorithm is performing
* @param maxRound maximum number of rounds, the algorithm could perform
*/
private boolean updateProgressDialog(int phase, int round, int maxRound){
int lowValue = 0;
if( phase != 0 )
lowValue = phaseLength[phase-1];
int maxValue = phaseLength[phase];
int width = maxValue - lowValue;
int value = lowValue+(int)(width*((double)round/(double)maxRound));
dlgProgress.setValue(value);
return dlgProgress.isCanceled();
}
/******************************************************************************/
/**
* Calculates the current impulse for the given cell.
*
* @param view Cell, the current impulse should be calculated
* @see #computeImpulse(CellView)
*/
private void computeCurrentImpulse(CellView view){
//gets the impulse for view
Point2D.Double impulse = computeImpulse(view);
//set result into node
view.getAttributes().put(KEY_CURRENT_IMPULSE,impulse);
}
/******************************************************************************/
/**
* Calculates the last impulse for the given cell. This is only nesessary while
* initializing the cells.
*
* @param view Cell, the last impulse should be calculated
* @see #computeImpulse(CellView)
*/
private void computeLastImpulse(CellView view){
//gets the impulse for view
Point2D.Double impulse = computeImpulse(view);
//set result into node
view.getAttributes().put(KEY_LAST_IMPULSE,impulse);
}
/******************************************************************************/
/**
* Computes an Impulse representing a Force affecting the position of the given
* Cell. This impulse consists of a attracting force, pulling the cell to the
* barycenter of all cells, a pulse with user defined length and random
* direction, a force repulsing cells from each other, a force attracting
* connected cells together, and, as a additional feature, a force, repulsing
* the current cell from overlapping cells.
*
* @param view Cell, the impulse should be computed
* @return impulse, transformed in a Point2D.Double-Instance.
*/
private Point2D.Double computeImpulse(CellView view){
Point2D.Double impulse = new Point2D.Double();
Point2D.Double pos = getPosition(view);
boolean isCellACluster = isCluster(view);
//the more edges a cell have, the heavier the cell is
double massIndex = getNodeWeight(view);
//gets the barycenter of all cells
Point2D.Double barycenter = computeBarycenter(cellList);
//attracting force from the barycenter to every cell
Point2D.Double gravitationForce = new Point2D.Double(
(barycenter.getX() - pos.getX()) * gravitation * massIndex,
(barycenter.getY() - pos.getY()) * gravitation * massIndex);
//random glitch is added to force
Point2D.Double randomImpulse = getRandomVector(randomImpulseRange);
//repulsive Forces
//from all nodes
ArrayList repulsiveForce = new ArrayList();
for( int i = 0 ; i < cellList.size(); i++ )
if( cellList.get(i) != view ){//all cells except the actual view
// CellView uView = (CellView) cellList.get(i);
// if( !isCluster(uView)){
Point2D.Double uPos = getPosition(i,cellList);
double deltaX = (double)(pos.getX() - uPos.getX());
double deltaY = (double)(pos.getY() - uPos.getY());
/*
double sgnX = MathExtensions.sgn(deltaX);
double sgnY = MathExtensions.sgn(deltaY);
if( isCellACluster && isCluster(uView) ){
deltaX -= uView.getBounds().getWidth() / 2.0;
deltaY -= uView.getBounds().getHeight()/ 2.0;
}
if( isCellACluster ){
deltaX -= view.getBounds().getWidth() / 2.0;
deltaY -= view.getBounds().getHeight()/ 2.0;
}
if( sgnX != MathExtensions.sgn(deltaX) ){
deltaX *= sgnX;
}
if( sgnY != MathExtensions.sgn(deltaY) ){
deltaY *= sgnY;
}
*/
double absDelta = MathExtensions.abs(deltaX,deltaY);
if( absDelta > equalsNull ){
repulsiveForce.add(new Point2D.Double(
deltaX * ((prefEdgeLength * prefEdgeLength) / (absDelta * absDelta)),
deltaY * ((prefEdgeLength * prefEdgeLength) / (absDelta * absDelta))));
}
// }
}
//attractive Forces:
//from all nodes that have an edge with view
ArrayList relatives = getRelativesFrom(cellList,view);
ArrayList attractiveForce = new ArrayList(relatives.size());
for( int i = 0; i < relatives.size(); i++ ){
// CellView child = (CellView) relatives.get(i);
Point2D.Double cPos = getPosition(i,relatives);
double deltaX = (double)(pos.getX() - cPos.getX());
double deltaY = (double)(pos.getY() - cPos.getY());
/*
double sgnX = MathExtensions.sgn(deltaX);
double sgnY = MathExtensions.sgn(deltaY);
if( isCellACluster && isCluster( child )){
deltaX -= child.getBounds().getWidth() / 2.0;
deltaY -= child.getBounds().getHeight()/ 2.0;
}
if( isCellACluster ){
deltaX -= view.getBounds().getWidth() / 2.0;
deltaY -= view.getBounds().getHeight()/ 2.0;
}
if( sgnX != MathExtensions.sgn(deltaX) )
deltaX *= sgnX;
if( sgnY != MathExtensions.sgn(deltaY) )
deltaY *= sgnY;
*/
double absDelta = MathExtensions.abs(deltaX,deltaY);
attractiveForce.add(new Point2D.Double(
deltaX * (( absDelta * absDelta ) / ( prefEdgeLength * prefEdgeLength * massIndex )),
deltaY * (( absDelta * absDelta ) / ( prefEdgeLength * prefEdgeLength * massIndex ))));
}
/* the next part is NOT part of the original algorithm */
/* it adds a force if the actual cell overlapps another cell */
ArrayList forcesByOverlapping = new ArrayList();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -