// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea
// Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com
// Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
// Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
package graphtea.plugins.visualization.localsfvis;
import graphtea.graph.graph.*;
import graphtea.library.exceptions.InvalidVertexException;
import graphtea.platform.core.BlackBoard;
import graphtea.platform.core.exception.ExceptionHandler;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
/**
* @author azin azadi
*/
class animatorLSF extends Thread {
private boolean b = true;
private boolean c = true;
public animatorLSF(BlackBoard blackboard, GraphModel g, AbstractGraphRenderer gv) {
this.g = g;
this.gv = gv;
getVertices();
}
private GraphModel g;
private AbstractGraphRenderer gv;
private Vertex[] v;
private GRect[] vRects; //represents the rectangle arround each vertex
private GPoint[] verPos; //fresh generated vertex positions!
private GPoint[] velocity;
private GPoint[] prevVerPos; //refferes to previous state of vertex positions, for finding vertices that moved by anything else
// private final double neighborRadius = 300;
private double stres = 10;
private double springK = 0.7;
private double q1q2k = 50000;
private boolean stop = false;
private int n = 0;
private int counter1 = 0,
counter2 = 0,
counter3 = 0,
counter4 = 0;
private HashSet<Integer>[] neighbors;
boolean saveScreenShots = false;
public void run() {
stop = false;
{ //determining the directory name for saveing images
// int _i = 0;
// String _prefix = "c:\\";
// while (new File(_prefix + _i).isDirectory() || new File(_prefix + _i).isFile()) _i++;
// new File(_prefix + _i).mkdir();
// prefix = _prefix + _i + "\\";
}
// SaveLoadPluginMethods slpm = new SaveLoadPluginMethods(blackboard);
// gv.animation = true;
// gv.ignoreUpdates = true;
int stablep = 0;
final GPoint centerPoint = calculateGraphCenterPoint(); //calculating the center of graph to pin its center
//final GRect bounds = g.getAbsBounds(); //calculating the bounds of graph to pin its center
while (!stop) {
if (counter3++ == 150) {
counter3 = 0;
int nstable = 0;
for (int i = 0; i < n; i++) {
if (stableVertex[i])
++nstable;
stableVertex[i] = false;
}
// if (nstable > 4 * n / 5)
// ++stablep;
// if (stablep == 4) {
stablep = 0;
if (isDynamic) {
stres();
stres = stres * 99 / 100;
}
// }
// System.out.println(nstable + " stable vertices");
}
if (counter4++ == 100) {
counter4 = 2;
if (isDynamic)
updateKs();
}
if (counter1++ == 20) {
counter1 = 0;
refreshNeighbors();
getVertices();
}
refreshPositioning();
if (counter2++ == 10) {
counter2 = 0;
// gv.ignoreUpdates = true;
try {
gv.ignoreRepaints(new Runnable() {
public void run() {
GPoint newCenterPoint = calculateGraphCenterPoint();
GRect newBounds = calculateGraphAbsBoundsPoint();
//todo: to preserve graph bounds
double dx = centerPoint.x - newCenterPoint.x;
double dy = centerPoint.y - newCenterPoint.y;
for (int i = 0; i < n; i++) {
double x = verPos[i].x;
double y = verPos[i].y;
// x=x+dx+ ((x-newCenterPoint.x)/newBounds.width)*bounds.width;
x += dx;
y += dy;
GPoint p = v[i].getLocation();
// if (p.distance(verPos[i])<2)
// stableVertex[i] = true;
// if (!p.equals(prevVerPos[i])) { //only change the position when it is changed
// continue;
// }
// if (!stableVertex[i])
v[i].setLocation(verPos[i]);
prevVerPos[i] = p;
// else
// stableVertex[i]=true;
}
}
});
}
catch (InvalidVertexException e) {
getVertices();
refreshNeighbors();
}
if (saveScreenShots && b && c) {
// slpm.saveAsImage(nextFile(), "png"); //saving the screen shot
}
b = !b;
if (b)
c = !c; //har 4 bar ie bar
// gv.ignoreUpdates = true;
// getVertices();
// refreshNeighbors();
}
try {
Thread.sleep((long) (0.7 * Math.log10(n) * Math.sqrt(n)));
} catch (InterruptedException e) {
ExceptionHandler.catchException(e);
}
}
// gv.ignoreUpdates = false;
// gv.animation = false;
// gv.updateBounds();
gv.repaint();
}
private GPoint calculateGraphCenterPoint() {
GPoint centerPoint = new GPoint();
for (GPoint p : verPos) {
centerPoint.add(p.x, p.y);
}
centerPoint.x /= n;
centerPoint.y /= n;
return centerPoint;
}
private GRect calculateGraphAbsBoundsPoint() {
GRect ret = new GRect();
for (GPoint p : verPos) {
ret.add(p.x, p.y);
}
return ret;
}
static String prefix;
int i = 100000;
File nextFile() { //for saving image
return new File(prefix + (i++) + ".jpg");
}
boolean temporaryStress = false;
void stres() {
// if (minDistance<stres){
for (int i = 0; i < n; i++) {
verPos[i].x += stres / 2 - Math.random() * stres;
verPos[i].y += stres / 2 - Math.random() * stres;
}
// }
temporaryStress = false;
springK *= 3;
// maxF *= 2;
q1q2k /= 4;
// refreshPositioning();
// refreshPositioning();
// refreshPositioning();
// refreshPositioning();
refreshPositioning();
refreshPositioning();
refreshPositioning();
springK /= 3;
// maxF /= 2;
q1q2k *= 4;
// System.out.println("stres" + s++);
}
float minDistance;
float maxDistance;
private void updateKs() {
int i = 0;
for (Vertex vm : g) {
vRects[i] = new GRect(vm.getBounds().getBounds().x,vm.getBounds().getBounds().y,
vm.getBounds().getBounds().width,vm.getBounds().getBounds().height);
i++;
}
minDistance = 1000000;
maxDistance = Float.MIN_VALUE;
final int MAX_DISTANCE = (int) (Math.sqrt(n) * (60));
final float MIN_DISTANCE = (float) ((8 - Math.log10(n)) * 10);
double lb = 60 + 100.0 / Math.sqrt(n);
double hb = 95 + 100.0 / Math.sqrt(n);
boolean strongerK = false;
for (i = 0; i < n; ++i) {
vRects[i].grow((int) lb, (int) lb);
for (int j : neighbors[i]) {
// Rectangle r=vRects[i].union(vRects[j]);
// r.grow();
// minDistance =min(minDistance,r.width+r.height);
float distance = Math.abs((float) (verPos[i].x - verPos[j].x)) + Math.abs((float) (verPos[i].y - verPos[j].y));
// maxDistance = Math.max(maxDistance, distance);
minDistance = Math.min(minDistance, distance);
if (vRects[j].inside(verPos[i])) {
strongerK = true;
}
}
vRects[i].grow((int) (-lb), (int) (-lb));
}
// Rectangle r = new Rectangle();
// r.
GRect gBounds = g.getAbsBounds().getBounds();
maxDistance = (float) ((gBounds.w + gBounds.h) / 2);
// System.out.println("min getDistance:" + minDistance);
// System.out.println("max getDistance:" + maxDistance);
if (strongerK && maxDistance < MAX_DISTANCE) {
// if (minDistance < lb) {
weaker();
}
if (!strongerK && minDistance > MIN_DISTANCE) {
stronger();
}
// System.out.println("SpringK: " + springK);
}
void stronger() {
springK /= (0.75);
q1q2k /= (1.3);
}
void weaker() {
springK *= 0.75;
q1q2k *= 1.3;
}
int s = 0;
public void _stop() {
stop = true;
}
boolean stableVertex[];
private void getVertices() {
int _n = g.getVerticesCount();
if (_n != n) {
n = _n;
verPos = new GPoint[n];
velocity = new GPoint[n];
prevVerPos = new GPoint[n];
dists = new pair[Math.max(n - 1, 0)];
neighbors = new HashSet[n];
for (int i = 0; i < n; i++) {
neighbors[i] = new HashSet<>();
if (i != 0) dists[i - 1] = new pair(0, 0); //the len of dists should be n-1
}
v = new Vertex[n];
vRects = new GRect[n];
stableVertex = new boolean[n];
}
int i = 0;
for (Vertex vm : g) {
v[i] = vm;
verPos[i] = vm.getLocation();
velocity[i] = new GPoint();
vRects[i] = new GRect(vm.getBounds().getBounds().x,vm.getBounds().getBounds().y,
vm.getBounds().getBounds().width,vm.getBounds().getBounds().height);
prevVerPos[i] = new GPoint(verPos[i]);
i++;
}
}
GPoint f = new GPoint();
GPoint fs = new GPoint(0, 0);
double fex = 0;
double fey = 0;
double fsx = 0;
double fsy = 0;
double x;
double y;
double d;
int fx;
int fy;
double d3;
//ghalbe tapande
private void refreshPositioning() {
for (int i = 0; i < n; i++) {
// if (!stableVertex[i] || Math.random()<0.1) {
fex = 0;
fey = 0;
fsx = 0;
fsy = 0;
for (Integer j : neighbors[i]) {
x = verPos[i].x - verPos[j].x;
y = verPos[i].y - verPos[j].y;
if (x == 0 && y == 0) { //if vertices are in the same location squeeze them!
x = Math.random() * 15;
y = Math.random() * 15;
// verPos[i].x+=x;
// verPos[i].y+=y;
verPos[j].y -= x;
verPos[j].x -= y;
x = verPos[i].x - verPos[j].x;
y = verPos[i].y - verPos[j].y;
}
d = Math.abs(y) + Math.abs(x);
if (d < 10) //baraie paresh haie gonde
continue;
//electrical force
if (d != 0) {
d3 = d * d * d;
fex += x / d3;
fey += y / d3;
}
if (edge(i, j)) {
//spring force
fsx += x;
fsy += y;
}
}
fx = (int) (q1q2k * fex - springK * fsx);
fy = (int) (q1q2k * fey - springK * fsy);
int fi = Math.abs(fx) + Math.abs(fy);
double maxF = 1000;
if (fi > maxF) {
// System.out.println("MAXF exceeded: "+fi);
fx = (int) (maxF * fx / (fi));
fy = (int) (maxF * fy / (fi));
}
int e = 5;
verPos[i].x += fx / e;
verPos[i].y += fy / e;
// velocity[i].x += fx;
// velocity[i].y += fy;
// verPos[i].x += (fx + velocity[i].x)/E;
// verPos[i].y += (fy + velocity[i].y)/E;
}
if (temporaryStress)
stres();
// }
}
private boolean edge(int i, int jj) {
try {
return g.isEdge(v[i], v[jj]) || g.isEdge(v[jj], v[i]);
}
catch (Exception e) {
getVertices();
refreshNeighbors();
return false;
}
}
pair[] dists;
private void refreshNeighbors() {
for (int i = 0; i < n; i++) {
if (!stableVertex[i]) {
neighbors[i].clear();
int _j = 0;
for (int j = 0; j < n; j++) {
if (j != i) {
dists[_j].node = j;
dists[_j++].d = v[i].getLocation().distance(v[j].getLocation());
if (edge(i, j))
neighbors[i].add(j);
}
}
Arrays.sort(dists);
for (int t = 0; t < Math.min(5, n - 1); t++) {
// System.out.println(dists[t].d);
if (dists[t].d < 200)
neighbors[i].add(dists[t].node);
if (dists[t].d < 2) {
verPos[t].x += 10 * Math.random() - 5;
verPos[t].y += 10 * Math.random() - 5;
}
}
}
}
}
boolean isDynamic = true;
void setDynamic(boolean b) {
isDynamic = b;
}
}