/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.diagram.ui.layout.spring;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.WeakHashMap;
import org.eclipse.draw2d.geometry.Rectangle;
import org.teiid.designer.diagram.ui.connection.NodeConnectionModel;
import org.teiid.designer.diagram.ui.layout.LayoutNode;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
import org.teiid.designer.diagram.ui.util.DiagramUiUtilities;
/**
* @since 8.0
*/
public class Spring {
private double[] delta;
private double[] deltaX;
private double[] deltaY;
private double[] deltaXX;
private double[] deltaYY;
private double[] deltaXY;
private double[][] partialDeltaX = null;
private double[][] partialDeltaY = null;
private double[][] partialDeltaZ = null;
private double[][] KL = null;
private int linkCount;
private boolean[] fixed = null;
private NodeConnectionModel[][] Connections = null;
public double[] centerX = null;
public double[] centerY = null;
private LayoutNode[] springNodes;
private int nbnodes_;
private double _epsilonFactor = 1.5;
private double _edgeLength = 1000.0;
private int _repaintPeriod = 1;
private boolean _autoEdgeLength = true;
// private boolean _fixSelected = true;
private boolean _widthIgnored = false;
private boolean _heightIgnored = false;
private Rectangle _bounds = null;
private HashMap _nodeConstraints = null;
private WeakHashMap _linkConstraints = null;
private SpringLayout layoutManager = null;
/**
* Construct an instance of Spring.
*
*/
public Spring(SpringLayout newLayoutManager) {
super();
layoutManager = newLayoutManager;
}
public void setRectangle(Rectangle rectangle2d) {
_bounds = rectangle2d;
}
public Rectangle setRectangle() {
return _bounds;
}
public void setEdgeLength(double d) {
_edgeLength = d;
}
public double getEdgeLength() {
return _edgeLength;
}
public void setAutoEdgeLength(boolean bool) {
_autoEdgeLength = bool;
}
public boolean getAutoEdgeLength() {
return _autoEdgeLength;
}
// public void setFixSelected(boolean bool) {
// _fixSelected = bool;
// }
//
// public boolean getFixSelected() {
// return _fixSelected;
// }
public void setWidthIgnored(boolean bool) {
_widthIgnored = bool;
}
public boolean isWidthIgnored() {
return _widthIgnored;
}
public void setHeightIgnored(boolean bool) {
_heightIgnored = bool;
}
public boolean isHeightIgnored() {
return _heightIgnored;
}
public void setRepaintPeriod(int i) {
_repaintPeriod = i;
}
public int getRepaintPeriod() {
return _repaintPeriod;
}
public void setEpsilon(double d) {
_epsilonFactor = d;
}
public double getEpsilon() {
return _epsilonFactor;
}
public void setNodeConstraints(HashMap hashmap) {
_nodeConstraints = hashmap;
}
public HashMap getNodeConstraints() {
return _nodeConstraints;
}
public void setLinkConstraints(WeakHashMap weakhashmap) {
_linkConstraints = weakhashmap;
}
public WeakHashMap getLinkConstraints() {
return _linkConstraints;
}
public String compute(LayoutNode[] theSpringNodes, int i) {
springNodes = theSpringNodes;
nbnodes_ = i;
if (i == 0)
return "There's no component to layout"; //$NON-NLS-1$
double[] ds = new double[i];
double[] ds_0_ = new double[i];
boolean[] bools = new boolean[i];
centerX = ds;
centerY = ds_0_;
fixed = bools;
for (int i_2_ = 0; i_2_ < i; i_2_++) {
LayoutNode nextNode = springNodes[i_2_];
ds[i_2_] = nextNode.getCenterX();
ds_0_[i_2_] = nextNode.getCenterY();
}
makeConnections();
if (!findDistances())
return "Error: This algorithm should not be run on a non-connected graph!"; //$NON-NLS-1$
boolean bool = true;
for (int i_3_ = 0; bool && i_3_ < i; i_3_++)
bool &= bools[i_3_];
if (bool)
return "All the components are fixed"; //$NON-NLS-1$
find_l_and_k();
calculateDelta();
double[] ds_4_ = delta;
int[] is = new int[i];
double d_Epsilon = _epsilonFactor * (i + linkCount);
int i_5_ = 0;
int i_6_ = 0;
int i_7_ = 0;
for (;;) {
double d_8_ = 0.0;
for (int i_9_ = 0; i_9_ < i; i_9_++) {
double d_10_ = ds_4_[i_9_];
int i_11_ = is[i_9_];
if (d_10_ > d_8_)
d_8_ = d_10_;
if (i_11_ > i_5_)
i_5_ = i_11_;
}
d_8_ = 1.0 / d_8_;
int i_12_ = 0;
double d_13_ = 0.0;
double d_14_ = 1.0 / i_5_;
for (int i_15_ = i_12_; i_15_ < i; i_15_++) {
double d_16_ =
(i_5_ != 0
? 0.5 * (ds_4_[i_15_] * d_8_ + 1.0 - is[i_15_] * d_14_)
: ds_4_[i_15_] * d_8_);
if (d_16_ > d_13_) {
i_12_ = i_15_;
d_13_ = d_16_;
}
}
if (ds_4_[i_12_] <= d_Epsilon || i_6_ > 100)
break;
if (!bools[i_12_]) {
for (int i_17_ = 0; ds_4_[i_12_] > d_Epsilon && i_17_ < 10; i_17_++)
MoveToNewPosition(i_12_);
}
if (++i_7_ == springNodes.length) {
i_7_ = 0;
if (_repaintPeriod > 0 && i_6_ % _repaintPeriod == _repaintPeriod - 1)
setPositions();
i_6_++;
}
is[i_12_]++;
}
partialDeltaX = null;
partialDeltaY = null;
partialDeltaZ = null;
KL = null;
delta = null;
deltaX = null;
deltaY = null;
deltaXX = null;
deltaYY = null;
deltaXY = null;
return null;
}
private void makeConnections() {
Hashtable hashtable = new Hashtable();
DiagramModelNode[] allDiagramNodes =
DiagramUiUtilities.getNodeArray(layoutManager.getDiagramNode().getChildren());
// Make connections List
List allConnections = new ArrayList();
for (int iNode = 0; iNode < allDiagramNodes.length; iNode++) {
allConnections.addAll(allDiagramNodes[iNode].getSourceConnections());
}
int nSpringNodes = springNodes.length;
for (int iNode = 0; iNode < nSpringNodes; iNode++) {
hashtable.put(springNodes[iNode].getModelNode().getModelObject(), new Integer(iNode));
}
// Set up Connection Array
NodeConnectionModel[][] connectionArray = new NodeConnectionModel[nSpringNodes][nSpringNodes];
linkCount = 0;
NodeConnectionModel nextConnection = null;
Iterator iter = allConnections.iterator();
while( iter.hasNext() ) {
nextConnection = (NodeConnectionModel)iter.next();
Object sourceNode = hashtable.get(((DiagramModelNode)nextConnection.getSourceNode()).getModelObject());
if (sourceNode != null) {
Object targetNode = hashtable.get(((DiagramModelNode)nextConnection.getTargetNode()).getModelObject());
if (targetNode != null) {
int sourceId = ((Integer)sourceNode).intValue();
int targetId = ((Integer)targetNode).intValue();
connectionArray[sourceId][targetId] = nextConnection;
connectionArray[targetId][sourceId] = nextConnection;
linkCount++;
}
}
}
Connections = connectionArray;
}
private void setPositions() {
for (int i = 0; i < nbnodes_; i++)
springNodes[i].setCenterXY((int)centerX[i], (int)centerY[i]);
}
private boolean findDistances() {
LayoutNode[] theNodes = springNodes;
int i = nbnodes_;
boolean[] bools = fixed;
double[] ds = new double[i];
double[][] ds_24_ = new double[i][i];
if (_widthIgnored) {
if (_heightIgnored) {
for (int i_25_ = 0; i_25_ < i; i_25_++)
ds[i_25_] = 0.5;
} else {
for (int i_26_ = 0; i_26_ < i; i_26_++)
ds[i_26_] = theNodes[i_26_].getHeight() * 0.7;
}
} else if (_heightIgnored) {
for (int i_27_ = 0; i_27_ < i; i_27_++)
ds[i_27_] = theNodes[i_27_].getWidth() * 0.7;
} else {
for (int i_28_ = 0; i_28_ < i; i_28_++) {
LayoutNode nextNode = theNodes[i_28_];
ds[i_28_] = ((nextNode.getWidth() + nextNode.getHeight()) * 0.25);
}
}
for (int i_29_ = 0; i_29_ < i; i_29_++) {
Object modelObject = theNodes[i_29_].getModelNode().getModelObject();
SpringNodeConstraints springnodeconstraints =
((SpringNodeConstraints)_nodeConstraints.get(modelObject));
if (springnodeconstraints != null) {
ds[i_29_] += springnodeconstraints.getWeight();
bools[i_29_] |= springnodeconstraints.isFixed();
}
}
for (int i_30_ = 0; i_30_ < i; i_30_++) {
for (int i_31_ = i_30_ + 1; i_31_ < i; i_31_++) {
NodeConnectionModel connectionModel = Connections[i_30_][i_31_];
if (connectionModel != null) {
SpringLinkConstraints springlinkconstraints =
((SpringLinkConstraints)_linkConstraints.get(connectionModel));
if (springlinkconstraints != null)
ds_24_[i_30_][i_31_] += springlinkconstraints.getWeight();
ds_24_[i_31_][i_30_] = ds_24_[i_30_][i_31_];
}
}
}
boolean[] bools_32_ = new boolean[i];
boolean[] bools_33_ = new boolean[i];
int[] is = new int[linkCount << 1];
double[][] ds_34_ = new double[i][i];
// int[][] is_35_ = new int[i][i];
for (int i_36_ = 0; i_36_ < i; i_36_++) {
System.arraycopy(bools_33_, 0, bools_32_, 0, i);
int i_37_ = 0;
int i_38_ = 0;
bools_32_[i_36_] = true;
double[] ds_39_ = ds_34_[i_36_];
for (int i_40_ = 0; i_40_ < i; i_40_++) {
if (Connections[i_36_][i_40_] != null) {
is[i_37_++] = i_40_;
is[i_37_++] = i_36_;
bools_32_[i_40_] = true;
}
}
while (i_37_ > i_38_) {
int i_41_ = is[i_38_++];
int i_42_ = is[i_38_++];
ds_39_[i_41_] = (ds_34_[i_42_][i_36_] + ds_24_[i_41_][i_42_] + ds[i_41_] + ds[i_42_]);
ds_34_[i_41_][i_36_] = ds_39_[i_41_];
for (int i_43_ = 0; i_43_ < nbnodes_; i_43_++) {
// LayoutNode nextNode = theNodes[i_43_];
if (Connections[i_41_][i_43_] != null && !bools_32_[i_43_]) {
is[i_37_++] = i_43_;
is[i_37_++] = i_41_;
bools_32_[i_43_] = true;
}
}
}
}
boolean bool = true;
for (int i_44_ = 0; i_44_ < i; i_44_++) {
double[] ds_45_ = ds_34_[i_44_];
for (int i_46_ = i_44_ + 1; i_46_ < i; i_46_++) {
if (ds_45_[i_46_] == 0.0) {
bool = false;
ds_45_[i_46_] = 1.7976931348623157E308;
ds_45_[i_44_] = 1.7976931348623157E308;
}
}
}
KL = ds_34_;
partialDeltaZ = ds_24_;
Connections = null;
return bool;
}
private void find_l_and_k() {
int i = nbnodes_;
double[][] ds = KL;
double d = 0.0;
double d_47_ = ds[0][0];
for (int i_48_ = 0; i_48_ < i; i_48_++) {
double[] ds_49_ = ds[i_48_];
for (int i_50_ = i_48_ + 1; i_50_ < i; i_50_++) {
double d_51_ = ds_49_[i_50_];
if (d_47_ < d_51_ && d_51_ < 1.7976931348623157E308)
d_47_ = d_51_;
d += d_51_;
}
}
d /= i;
double d_52_;
if (_autoEdgeLength && _bounds != null)
d_52_ = (Math.sqrt(_bounds.width * _bounds.height / 2.2) / d_47_);
else
d_52_ = _edgeLength / d_47_;
for (int i_53_ = 0; i_53_ < i; i_53_++) {
double[] ds_54_ = ds[i_53_];
for (int i_55_ = i_53_ + 1; i_55_ < i; i_55_++) {
double d_56_ = ds_54_[i_55_];
if (d_56_ < 1.7976931348623157E308)
ds[i_55_][i_53_] = d * d / (d_56_ * d_56_);
else
ds[i_55_][i_53_] = 0.0;
ds_54_[i_55_] *= d_52_;
}
}
}
private void calculateDelta() {
int i = nbnodes_;
double[] ds = centerX;
double[] ds_57_ = centerY;
double[] ds_58_ = new double[i];
double[] ds_59_ = new double[i];
double[] ds_60_ = new double[i];
double[] ds_61_ = new double[i];
double[] ds_62_ = new double[i];
double[] ds_63_ = new double[i];
double[][] ds_64_ = new double[i][i];
double[][] ds_65_ = new double[i][i];
double[][] ds_66_ = partialDeltaZ;
double[][] ds_67_ = KL;
for (int i_68_ = 0; i_68_ < i; i_68_++) {
double d = 0.0;
double d_69_ = 0.0;
double d_70_ = 0.0;
double d_71_ = 0.0;
double d_72_ = 0.0;
double d_73_ = ds[i_68_];
double d_74_ = ds_57_[i_68_];
double[] ds_75_ = ds_67_[i_68_];
double[] ds_76_ = ds_64_[i_68_];
double[] ds_77_ = ds_65_[i_68_];
double[] ds_78_ = ds_66_[i_68_];
for (int i_79_ = 0; i_79_ < i_68_; i_79_++) {
d += ds_76_[i_79_];
d_69_ += ds_77_[i_79_];
d_70_ += ds_64_[i_79_][i_68_];
d_71_ += ds_65_[i_79_][i_68_];
d_72_ += ds_66_[i_79_][i_68_];
}
for (int i_80_ = i_68_ + 1; i_80_ < i; i_80_++) {
double d_81_ = d_73_ - ds[i_80_];
double d_82_ = d_74_ - ds_57_[i_80_];
double d_83_ = d_81_ * d_81_;
double d_84_ = d_82_ * d_82_;
double d_85_ = d_83_ + d_84_;
double d_86_ = Math.sqrt(d_85_);
double d_87_ = ds_67_[i_80_][i_68_];
double d_88_ = d_87_ * ds_75_[i_80_] / d_86_;
double d_89_ = d_88_ / d_85_;
double d_90_ = d_87_ - d_88_;
double d_91_ = d_81_ * d_90_;
double d_92_ = d_82_ * d_90_;
double d_93_ = d_87_ - d_89_ * d_84_;
double d_94_ = d_87_ - d_89_ * d_83_;
double d_95_ = d_89_ * d_81_ * d_82_;
d += d_91_;
d_69_ += d_92_;
d_70_ += d_93_;
d_71_ += d_94_;
d_72_ += d_95_;
ds_64_[i_80_][i_68_] = -d_91_;
ds_65_[i_80_][i_68_] = -d_92_;
ds_76_[i_80_] = d_93_;
ds_77_[i_80_] = d_94_;
ds_78_[i_80_] = d_95_;
}
ds_58_[i_68_] = Math.sqrt(d * d + d_69_ * d_69_);
ds_59_[i_68_] = d;
ds_60_[i_68_] = d_69_;
ds_61_[i_68_] = d_70_;
ds_62_[i_68_] = d_71_;
ds_63_[i_68_] = d_72_;
}
delta = ds_58_;
deltaX = ds_59_;
deltaY = ds_60_;
deltaXX = ds_61_;
deltaYY = ds_62_;
deltaXY = ds_63_;
partialDeltaX = ds_64_;
partialDeltaY = ds_65_;
}
private void MoveToNewPosition(int i) {
int i_96_ = nbnodes_;
double[][] ds = partialDeltaX;
double[][] ds_97_ = partialDeltaY;
double[][] ds_98_ = partialDeltaZ;
double[][] ds_99_ = KL;
double[] ds_100_ = centerX;
double[] ds_101_ = centerY;
double[] ds_102_ = ds_99_[i];
double[] ds_103_ = delta;
double[] ds_104_ = deltaX;
double[] ds_105_ = deltaY;
double[] ds_106_ = deltaXX;
double[] ds_107_ = deltaYY;
double[] ds_108_ = deltaXY;
double[] ds_109_ = partialDeltaX[i];
double[] ds_110_ = partialDeltaY[i];
double[] ds_111_ = partialDeltaZ[i];
double d = ds_104_[i];
double d_112_ = ds_105_[i];
double d_113_ = ds_106_[i];
double d_114_ = ds_107_[i];
double d_115_ = ds_108_[i];
double d_116_ = 1.0 / (d_113_ * d_114_ - d_115_ * d_115_);
double d_117_ = ds_100_[i] + (d_112_ * d_115_ - d * d_114_) * d_116_;
double d_118_ = ds_101_[i] + (d * d_115_ - d_112_ * d_113_) * d_116_;
ds_100_[i] = d_117_;
ds_101_[i] = d_118_;
d = 0.0;
d_112_ = 0.0;
d_113_ = 0.0;
d_114_ = 0.0;
d_115_ = 0.0;
for (int i_119_ = 0; i_119_ < i; i_119_++) {
double d_120_ = d_117_ - ds_100_[i_119_];
double d_121_ = d_118_ - ds_101_[i_119_];
double d_122_ = d_120_ * d_120_;
double d_123_ = d_121_ * d_121_;
double d_124_ = d_122_ + d_123_;
double d_125_ = Math.sqrt(d_124_);
double d_126_ = ds_102_[i_119_];
double d_127_ = d_126_ * ds_99_[i_119_][i] / d_125_;
double d_128_ = d_127_ / d_124_;
double d_129_ = d_126_ - d_127_;
double d_130_ = d_120_ * d_129_;
double d_131_ = d_121_ * d_129_;
double d_132_ = d_126_ - d_128_ * d_123_;
double d_133_ = d_126_ - d_128_ * d_122_;
double d_134_ = d_128_ * d_120_ * d_121_;
double d_135_ = ds_104_[i_119_] + ds_109_[i_119_] - d_130_;
double d_136_ = ds_105_[i_119_] + ds_110_[i_119_] - d_131_;
d += d_130_;
d_112_ += d_131_;
d_113_ += d_132_;
d_114_ += d_133_;
d_115_ += d_134_;
ds_109_[i_119_] = d_130_;
ds_110_[i_119_] = d_131_;
ds[i_119_][i] = d_132_;
ds_97_[i_119_][i] = d_133_;
ds_98_[i_119_][i] = d_134_;
ds_103_[i_119_] = Math.sqrt(d_135_ * d_135_ + d_136_ * d_136_);
ds_104_[i_119_] = d_135_;
ds_105_[i_119_] = d_136_;
ds_106_[i_119_] = ds_106_[i_119_] - partialDeltaX[i_119_][i] + d_132_;
ds_107_[i_119_] = ds_107_[i_119_] - partialDeltaY[i_119_][i] + d_133_;
ds_108_[i_119_] = ds_108_[i_119_] - partialDeltaZ[i_119_][i] + d_134_;
}
for (int i_137_ = i + 1; i_137_ < i_96_; i_137_++) {
double d_138_ = d_117_ - ds_100_[i_137_];
double d_139_ = d_118_ - ds_101_[i_137_];
double d_140_ = d_138_ * d_138_;
double d_141_ = d_139_ * d_139_;
double d_142_ = d_140_ + d_141_;
double d_143_ = Math.sqrt(d_142_);
double d_144_ = ds_99_[i_137_][i];
double d_145_ = d_144_ * ds_102_[i_137_] / d_143_;
double d_146_ = d_145_ / d_142_;
double d_147_ = d_144_ - d_145_;
double d_148_ = d_138_ * d_147_;
double d_149_ = d_139_ * d_147_;
double d_150_ = d_144_ - d_146_ * d_141_;
double d_151_ = d_144_ - d_146_ * d_140_;
double d_152_ = d_146_ * d_138_ * d_139_;
double d_153_ = ds_104_[i_137_] - partialDeltaX[i_137_][i] - d_148_;
double d_154_ = ds_105_[i_137_] - partialDeltaY[i_137_][i] - d_149_;
d += d_148_;
d_112_ += d_149_;
d_113_ += d_150_;
d_114_ += d_151_;
d_115_ += d_152_;
ds[i_137_][i] = -d_148_;
ds_97_[i_137_][i] = -d_149_;
ds_109_[i_137_] = d_150_;
ds_110_[i_137_] = d_151_;
ds_111_[i_137_] = d_152_;
ds_103_[i_137_] = Math.sqrt(d_153_ * d_153_ + d_154_ * d_154_);
ds_104_[i_137_] = d_153_;
ds_105_[i_137_] = d_154_;
ds_106_[i_137_] += d_150_ - ds_109_[i_137_];
ds_107_[i_137_] += d_151_ - ds_110_[i_137_];
ds_108_[i_137_] += d_152_ - ds_111_[i_137_];
}
ds_103_[i] = Math.sqrt(d * d + d_112_ * d_112_);
ds_104_[i] = d;
ds_105_[i] = d_112_;
ds_106_[i] = d_113_;
ds_107_[i] = d_114_;
ds_108_[i] = d_115_;
}
// private void CheckPositions() {
// boolean bool = false;
// while (!bool) {
// bool = true;
// for (int i = 0; i < nbnodes_; i++) {
// double d = centerX[i];
// double d_155_ = centerY[i];
// for (int i_156_ = i + 1; i_156_ < nbnodes_; i_156_++) {
// double d_157_ = centerX[i_156_];
// double d_158_ = centerY[i_156_];
// if (d == d_157_ && d_155_ == d_158_) {
// double d_159_ = (1.4 * Math.random() - 0.7) * KL[i][i_156_];
// double d_160_ = (1.4 * Math.random() - 0.7) * KL[i][i_156_];
// bool = false;
// }
// }
// }
// }
// }
}