📄 gemlayoutalgorithm.java
字号:
"setting new Vertice Values"};
/**
* to identify the different phases of the algorithm for the progress dialog
*/
private final static int PHASE_INITIALISATION = 0;
/**
* to identify the different phases of the algorithm for the progress dialog
*/
private final static int PHASE_CALCULATION = 1;
/**
* to identify the different phases of the algorithm for the progress dialog
*/
private final static int PHASE_END = 2;
/**
* to identify for the method {@link #loadRuntimeValues(int)}, that the
* algorithm wants to perform a new run
*/
protected final static int VALUES_PUR = 0;
/**
* to identify for the method {@link #loadRuntimeValues(int)}, that the
* algorithm wants to perform a layout update
*/
protected final static int VALUES_INC = 1;
/**
* algorithm used for optimizing the result of this algorithm
*/
private AnnealingLayoutAlgorithm optimizationAlgorithm;
/**
* switches the usage of the optimizing algorithm
*/
private boolean useOptimizeAlgorithm;
/**
* configuration of the optimizing algorithm
*/
private Properties optimizationAlgorithmConfig;
/**
* Switches clustering for the layout update process on/off
*/
private boolean isClusteringEnabled;
/**
* The initial temperature for clusters. It is recommended, that this value
* is lower than {@link #initTemperature} to get a good looking layout
*/
private double clusterInitTemperature;
/**
* Scales forces, that are effecting clusters. It is recommendet to take
* a value between 1.0 and 0.0. This garanties, that clusters move slower
* than other cells. That rises the chance of getting a good looking layout
* after the calculation.
*/
private double clusterForceScalingFactor;
/**
* Effects, how many clusters are created, when the layout update process
* starts. This affects the initial number of clusters, which is the number
* of cells available minus the number of cells to layout. The result of
* that term is divided by this factor, to get the maximum number of
* clusters. After this calculation, the clustering algorithm tries to
* minimize the number of clusters, so there might be less clusters than
* the maximum number.
*/
private double clusteringFactor;
/**
* The initial size for the layout update method perimeter. This describes
* a radius around an inserted cell. Every other inserted cell in this
* radius increases the radius by {@link #perimeterSizeInc}. After finishing
* increasing the radius, every cell, from the cells, that are already
* layouted, in the radius is added to the list of cells, that'll gain a
* new position during the layout update process. This should bring up
* the behaviour, that the previous layouted cells make space for the layout
* of the inserted cells.
*/
private double perimeterInitSize;
/**
* Inserted cells whithin a radius of {@link #perimeterInitSize} around
* a inserted cell are counted. After counting the inserted cells around
* a inserted cell, the initial radius is increased by this increase value
* times the number of inserted cells around the inserted cell. Every
* previous layouted cell in the resulting radius around the inserted cell
* is going to be layouted again.
*/
private double perimeterSizeInc;
private boolean isDebugging = false;
/******************************************************************************/
/**
* Constructs a new GEM Layout Algorithm.
*/
public GEMLayoutAlgorithm(AnnealingLayoutAlgorithm optimizer){
cellList = new ArrayList();
applyCellList = new ArrayList();
edgeList = new ArrayList();
optimizationAlgorithm = optimizer;
}
/******************************************************************************/
/**
* Starts the Calculation of a new layout with the GEM-Algorithm
* @param jgraph View of Graphnodes
* @param graphCells List of all nodes the layout should be calculated for
* @param configuration contains the initial values for the Algorithm
* @see #initialize()
* @see #calculate()
* @see de.fzi.echidna.layout.LayoutAlgorithm#perform(MyJGraph,List,Properties)
*/
public void perform(JGraph graph,
boolean applyToAll,
Properties configuration) {
isRunning = true;
jgraph = graph;
config = configuration;
jgraph.getModel().addGraphModelListener(this);
cellList = new ArrayList();
applyCellList = new ArrayList();
//extracting the nodes from jgraph, the algorithm should be performed on
getNodes(jgraph,applyToAll);
loadRuntimeValues(VALUES_PUR);
long starttime = System.currentTimeMillis();
//ALGORITHM START
boolean isCanceled = initialize();//initializes algorithm; sets the startvalues in cells
if( !isCanceled )
isCanceled = calculate();//performs the algorithm on the cells
//ALGORITHM END
if( !isCanceled && useOptimizeAlgorithm )
isCanceled = optimizationAlgorithm.performOptimization(applyCellList,cellList,edgeList,optimizationAlgorithmConfig,dlgProgress);
if( !isCanceled )
correctCoordinates();
//sets the calculated data into cellView's bounds if not canceled
if( !isCanceled )
isCanceled = setNewCoordinates(jgraph);
//removes the temporary data, stored by the algorithm, from the nodes
removeTemporaryLayoutDataFromCells();
dlgProgress.setMessage("Algorithm finished");
//prepares for next calculation (maybe useless, because instance of
//this algorithm might be thrown away)
dlgProgress.setVisible(false);
isRunning = false;
}
/******************************************************************************/
/**
* Loads the actual desired values from the {@link #config configuration} to
* the fields, where they are used later.
*
* @param valueID {@link #VALUES_PUR} for a normal run or {@link #VALUES_INC}
* for a layout update process.
*/
protected void loadRuntimeValues(int valueID){
maxRounds = applyCellList.size() * 4;//estimated value; reached rarely
countRounds = 0;//start value; counts the rounds in calculate()
isActive = isTrue((String)
config.get(GEMLayoutController.KEY_LAYOUT_UPDATE_ENABLED));
recursionDepth = Integer.parseInt((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_DEPTH));
layoutUpdateMethod = (String)
config.get(GEMLayoutController.KEY_LAYOUT_UPDATE_METHOD);
if( valueID == VALUES_PUR ){
initTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_INIT_TEMPERATURE));
minTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_MIN_TEMPERATURE));
maxTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_MAX_TEMPERATURE));
prefEdgeLength = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_PREF_EDGE_LENGTH));
gravitation = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_GRAVITATION));
randomImpulseRange = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_RANDOM_IMPULSE_RANGE));
overlapDetectWidth = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_OVERLAPPING_DETECTION_WIDTH));
overlapPrefDistance = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_OVERLAPPING_PREF_DISTANCE));
shouldEndPerAverage = isTrue((String)config.get(
GEMLayoutController.KEY_COMPUTE_PERMUTATION));
shouldComputePermutation = isTrue((String)config.get(
GEMLayoutController.KEY_END_CONDITION_AVERAGE));
avoidOverlapping = isTrue((String)config.get(
GEMLayoutController.KEY_AVOID_OVERLAPPING));
alphaOsc = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_ALPHA_OSC));
alphaRot = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_ALPHA_ROT));
sigmaOsc = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_SIGMA_OSC));
sigmaRot = Double.parseDouble((String)config.get( //gets 1/x
GEMLayoutController.KEY_SIGMA_ROT));
useOptimizeAlgorithm = isTrue((String)config.get(
GEMLayoutController.KEY_OPTIMIZE_ALGORITHM_ENABLED));
optimizationAlgorithmConfig = (Properties) config.get(
GEMLayoutController.KEY_OPTIMIZE_ALGORITHM_CONFIG);
}
else if( valueID == VALUES_INC ){
initTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_INIT_TEMPERATURE));
minTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_MIN_TEMPERATURE));
maxTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_MAX_TEMPERATURE));
prefEdgeLength = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_PREF_EDGE_LENGTH));
gravitation = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_GRAVITATION));
randomImpulseRange = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_RANDOM_IMPULSE_RANGE));
overlapDetectWidth = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_OVERLAPPING_DETECTION_WIDTH));
overlapPrefDistance = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_OVERLAPPING_PREF_DISTANCE));
shouldEndPerAverage = isTrue((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_COMPUTE_PERMUTATION));
shouldComputePermutation = isTrue((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_END_CONDITION_AVERAGE));
avoidOverlapping = isTrue((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_AVOID_OVERLAPPING));
alphaOsc = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_ALPHA_OSC));
alphaRot = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_ALPHA_ROT));
sigmaOsc = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_SIGMA_OSC));
sigmaRot = Double.parseDouble((String)config.get( //gets 1/x
GEMLayoutController.KEY_LAYOUT_UPDATE_SIGMA_ROT));
useOptimizeAlgorithm = isTrue((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_OPTIMIZE_ALGORITHM_ENABLED));
optimizationAlgorithmConfig = (Properties) config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_OPTIMIZE_ALGORITHM_CONFIG);
perimeterInitSize = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_METHOD_PERIMETER_INIT_SIZE));
perimeterSizeInc = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_METHOD_PERIMETER_SIZE_INC));
isClusteringEnabled = isTrue((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_CLUSTERING_ENABLED));
clusterInitTemperature = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_CLUSTERING_INIT_TEMPERATURE));
clusterForceScalingFactor = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_CLUSTERING_FORCE_SCALING_FACTOR));
clusteringFactor = Double.parseDouble((String)config.get(
GEMLayoutController.KEY_LAYOUT_UPDATE_CLUSTERING_FACTOR));
}
//with that line sigmaRot will be 1/(x*cellCount) with x is configurable
sigmaRot *= 1.0 / (double) (applyCellList.size() == 0 ? 1 : applyCellList.size());
}
/******************************************************************************/
/**
* Helping method. Transforms a String, containing only the characters "true" or
* "false", regardless if upper or lower case, into a boolean value.
*
* @param boolValue String containing a boolean value
* @return boolean value represented by the given string
*/
protected boolean isTrue(String boolValue){
if( boolValue != null ){
if( "TRUE".equals(boolValue.toUpperCase()) ){
return true;
}
else if( "FALSE".equals(boolValue.toUpperCase()) ){
return false;
}
}
return false;
}
/******************************************************************************/
/**
* Extracts the Cells from JGraph and fills {@link #applyCellList},
* {@link #cellList} and {@link #edgeList}. If applyToAll is
* <b><code>false</code></b> only in jgraph selected cells are added to
* {@link #applyCellList} else all cells are added.
*
* @param jgraph actual instance of jgraph
* @param applyToAll determines, if this algorithm should be performed on all
* cells or only on the selected.
*/
private void getNodes(JGraph jgraph, boolean applyToAll){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -