📄 gemlayoutalgorithm.java
字号:
if( avoidOverlapping ){
Rectangle viewBounds = new Rectangle(
(int)pos.x,
(int)pos.y,
(int)view.getBounds().getWidth(),
(int)view.getBounds().getHeight());
Rectangle viewBorder = new Rectangle(
(int)(viewBounds.getX()-overlapDetectWidth),
(int)(viewBounds.getY()-overlapDetectWidth),
(int)(viewBounds.getWidth()+(2.0*overlapDetectWidth)),
(int)(viewBounds.getHeight()+(2.0*overlapDetectWidth)));
for( int i = 0; i < cellList.size(); i++ ){
Point2D.Double uPos = getPosition(i,cellList);
Rectangle uBounds = new Rectangle(
(int)uPos.x,
(int)uPos.y,
(int)((CellView)cellList.get(i)).getBounds().getWidth(),
(int)((CellView)cellList.get(i)).getBounds().getHeight());
if( view != cellList.get(i) &&
viewBorder.intersects(uBounds) ){
Dimension viewSize = viewBounds.getSize();
Dimension uSize = uBounds.getSize();
double minDistance =
(Math.max(viewSize.getWidth(),viewSize.getHeight())/2.0)+
(Math.max(uSize.getWidth(),uSize.getHeight())/2.0)+overlapPrefDistance;
double deltaX = (double)(pos.x - uPos.x);
double deltaY = (double)(pos.y - uPos.y);
/*
if( isCellACluster ){
deltaX -= view.getBounds().getWidth() / 2.0;
deltaY -= view.getBounds().getHeight()/ 2.0;
}
if( isCluster((CellView)cellList.get(i))){
deltaX -= ((CellView)cellList.get(i)).getBounds().getWidth() / 2.0;
deltaY -= ((CellView)cellList.get(i)).getBounds().getHeight()/ 2.0;
}*/
if( deltaX < equalsNull && deltaX >= 0.0 ){
deltaX = equalsNull;
}
else if( deltaX > -equalsNull && deltaX <= 0.0 ){
deltaX = -equalsNull;
}
if( deltaY < equalsNull && deltaY >= 0.0 ){
deltaY = equalsNull;
}
else if( deltaY > -equalsNull && deltaY <= 0.0 ){
deltaY = -equalsNull;
}
double absDelta = MathExtensions.abs(deltaX,deltaY);
Point2D.Double force = new Point2D.Double(
deltaX*(minDistance*minDistance)/(absDelta*absDelta),
deltaY*(minDistance*minDistance)/(absDelta*absDelta));
// System.out.println("Overlapping Nodes: ("+pos.x+"|"+pos.y+") and ("+uPos.x+"|"+uPos.y+") -> Distance = "+absDelta+" -> Force = "+force);
forcesByOverlapping.add(force);
}
}
}
//for classes that extend this algorithm
ArrayList additionalForce = getAdditionalForces((VertexView)view);
//adding the forces
impulse = add(impulse,gravitationForce);
impulse = add(impulse,randomImpulse);
for( int i = 0; i < repulsiveForce.size(); i++ )
impulse = add(impulse,(Point2D.Double) repulsiveForce.get(i) );
for( int i = 0; i < attractiveForce.size(); i++ )
impulse = sub(impulse,(Point2D.Double) attractiveForce.get(i) );
for( int i = 0; i < forcesByOverlapping.size(); i++ )
impulse = add(impulse,(Point2D.Double) forcesByOverlapping.get(i));
for( int i = 0; i < additionalForce.size(); i++ )
impulse = add(impulse,(Point2D.Double) additionalForce.get(i) );
return impulse;
}
/******************************************************************************/
/**
* Updating the position of the given cell, by taking the direction of the
* current impulse and the length of the temperature of the cell. After this
* temperature will fall, when the last impulse and the current impulse are
* part of a rotation or a oscillation, temperature of the cell will be
* decreased.
*
* @param view Cell that should be updated
*/
private void updatePosAndTemp(CellView view){
Point2D.Double impulse = (Point2D.Double) view.getAttributes().get(KEY_CURRENT_IMPULSE);
Point2D.Double lastImpulse = (Point2D.Double) view.getAttributes().get(KEY_LAST_IMPULSE);
Point2D.Double position = getPosition(view);
double localTemperature = ((Double) view.getAttributes().get(KEY_TEMPERATURE)).doubleValue();
double skewGauge = ((Double) view.getAttributes().get(KEY_SKEWGAUGE)).doubleValue();
double absImpulse = MathExtensions.abs(impulse);
double absLastImpulse = MathExtensions.abs(lastImpulse);
if( absImpulse > equalsNull ){ //if impulse != 0
//scaling with temperature
if( isCluster(view) ){
impulse.setLocation(
impulse.getX() * localTemperature * clusterForceScalingFactor / absImpulse,
impulse.getY() * localTemperature * clusterForceScalingFactor / absImpulse);
}
else {
impulse.setLocation(
impulse.getX() * localTemperature / absImpulse,
impulse.getY() * localTemperature / absImpulse);
}
view.getAttributes().put(KEY_CURRENT_IMPULSE,impulse);
position.setLocation(position.getX()+impulse.getX(),
position.getY()+impulse.getY());
view.getAttributes().put(KEY_POSITION,position);
/* if( isDebugging ){
check(impulse,"impulse12");
check(position,"position12");
}*/
}
if( absLastImpulse > equalsNull ){
//beta = angle between new and last impulse
double beta = MathExtensions.angleBetween(impulse,lastImpulse);
double sinBeta = Math.sin(beta);
double cosBeta = Math.cos(beta);
//detection for rotations
if( Math.abs(sinBeta) >= Math.sin((Math.PI/2.0)+(alphaRot/2.0)) )
skewGauge += sigmaRot * MathExtensions.sgn(sinBeta);
//detection for oscillation
if( cosBeta < Math.cos(Math.PI+(alphaOsc/2.0)) )
localTemperature *= sigmaOsc * Math.abs(cosBeta);
localTemperature *= 1.0 - Math.abs(skewGauge);
localTemperature = Math.min(localTemperature,maxTemperature);
}
//applying changes
view.getAttributes().put(KEY_TEMPERATURE,new Double(localTemperature));
view.getAttributes().put(KEY_POSITION ,position);
view.getAttributes().put(KEY_SKEWGAUGE ,new Double(skewGauge));
view.getAttributes().put(KEY_LAST_IMPULSE,new Point2D.Double(
impulse.getX(),
impulse.getY()));
/* if( isDebugging )
checkCellList();*/
}
/******************************************************************************/
/**
* Adding two forces.
* @param v1 Force that should be added with v2
* @param v2 Force that should be added with v1
* @return Sum of both forces.
*/
private Point2D.Double add(Point2D.Double v1, Point2D.Double v2){
return new Point2D.Double(v1.getX()+v2.getX(),v1.getY()+v2.getY());
}
/******************************************************************************/
/**
* Subtracing two forces.
* @param v1 Force, v2 should be subtracted from
* @param v2 Force, that should be subtracted from v1.
*/
private Point2D.Double sub(Point2D.Double v1, Point2D.Double v2){
return new Point2D.Double(v1.getX()-v2.getX(),v1.getY()-v2.getY());
}
/******************************************************************************/
/**
* Returns all Cells, that have a direct connection with the given cell and are
* a member of the given list.
*
* @param list List of some cells, that should contain some relatives from view
* @param view Cell, the relatives are requested from
* @return List of all relatives that are in list.
* @see #getRelatives(CellView)
*/
private ArrayList getRelativesFrom(ArrayList list, CellView view){
ArrayList relatives = getRelatives(view);
ArrayList result = new ArrayList();
for( int i = 0; i < relatives.size(); i++ )
if( list.contains(relatives.get(i)) )
result.add(relatives.get(i));
return result;
}
/******************************************************************************/
/**
* Returns a list of all cells, that have a direct connection with the given
* cell via a edge. At the end of this method, the result is stored in the given
* cell, so it will be available the next time, the method runs. This temporary
* stored data will stay there, until the algorithm finishes
* (successfull or not).
*
* @param view Cell, the relatives requested from.
* @return List of all cells, that have a direct connection with a edge to
* the given cell.
*/
private ArrayList getRelatives(CellView view){
if( !(view instanceof VertexView) ) {
new Exception("getRelatives 1").printStackTrace();
return null;
}
if( view.getAttributes().containsKey(KEY_RELATIVES) )
return (ArrayList) view.getAttributes().get(KEY_RELATIVES);
ArrayList relatives = new ArrayList();
//if view is a cluster, then all clustered cells are extracted and
//getRelatives is called for every cell again. the resulting relatives
//are checked, if they are in the same cluster or another cluster.
//if the last condition is the case, the cluster is added, else the
//vertex is added to the list of relatives, iff he isn't already in the
//list
if( isCluster(view) ){
ArrayList clusteredVertices = (ArrayList)
view.getAttributes().get(KEY_CLUSTERED_VERTICES);
for( int i = 0; i < clusteredVertices.size(); i++ ){
ArrayList vertexRelatives = getRelatives(
(CellView)clusteredVertices.get(i));
for( int j = 0; j < vertexRelatives.size(); j++ ){
CellView relative = (CellView) vertexRelatives.get(j);
if( !clusteredVertices.contains(relative) ){
/* if( relative.getAttributes().containsKey(KEY_CLUSTER) ){
relative = (CellView) relative.getAttributes().get(KEY_CLUSTER);
}*/
if( !relatives.contains(relative))
relatives.add(relative);
}
}
}
}
else {
//runs only for vertices. finds all ports of the vertex. every
//edge in every port is checked on their source and target.
//the one, that isn't the vertex, we are searching the relatives of,
//is added to the list of relatives.
ArrayList portsCells = new ArrayList();
VertexView vertexView = (VertexView)view;
GraphModel model = vertexView.getModel();
CellMapper mapper = vertexView.getMapper() ;
Object vertexCell = vertexView.getCell() ;
for (int i = 0; i < model.getChildCount(vertexCell); i++){
Object portCell = model.getChild(vertexCell, i);
portsCells.add(portCell);
}
for( int i = 0; i < portsCells.size() ; i++ ){
Object portCell = portsCells.get(i);
Iterator edges = model.edges(portCell);
while (edges.hasNext() ){
Object edge = edges.next() ;
Object nextPort = null;
if( model.getSource(edge) != portCell ){
nextPort = model.getSource(edge);
}
else {
nextPort = model.getTarget(edge);
}
CellView nextVertex = mapper.getMapping(
model.getParent(nextPort), true);
relatives.add(nextVertex);
}
}
}
view.getAttributes().put(KEY_RELATIVES,relatives);
return relatives;
}
/******************************************************************************/
/**
* This is a rating method for the cells. It is used during
* {@link #computeImpulse(CellView)} scale some forces.
*
* @param view Cell, the weight is of interest.
*/
//TODO: method doesn't work right for clusters
private double getNodeWeight(CellView view){
if( view.getAttributes().containsKey(KEY_MASSINDEX) )
return ((Double)view.getAttributes().get(KEY_MASSINDEX)).
doubleValue();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -