programming-examples/java/Data_Structures/ForceBasedGraphDrawer.java

143 lines
3.7 KiB
Java
Raw Normal View History

2019-11-15 12:59:38 +01:00
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class ForceBasedGraphDrawer extends JFrame {
static Random rnd = new Random();
JPanel panel;
double[] x, y;
public void drawGraph(int[][] d) {
int n = d.length;
x = new double[n];
y = new double[n];
Set<Long> set = new HashSet<>();
for (int i = 0; i < n; i++) {
while (true) {
int px = rnd.nextInt(100);
int py = rnd.nextInt(100);
x[i] = px;
y[i] = py;
long key = px * 1000000000L + py;
if (!set.contains(key)) {
set.add(key);
break;
}
}
}
double k1 = 1;
double k2 = 100000;
for (int step = 0; step < 500000; step++) {
double[] fx = new double[n];
double[] fy = new double[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
continue;
}
double dx = x[j] - x[i];
double dy = y[j] - y[i];
double dist = Math.sqrt(dx * dx + dy * dy);
dx /= dist;
dy /= dist;
double force = k2 / (dist * dist);
if (d[i][j] > 0) {
force += -k1 * (dist - 1);
}
fx[j] += force * dx;
fy[j] += force * dy;
}
}
for (int i = 0; i < n; i++) {
x[i] += fx[i] / 1000;
y[i] += fy[i] / 1000;
}
if (step % 100 == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
panel.repaint();
}
}
public ForceBasedGraphDrawer() {
int n = rnd.nextInt(40) + 50;
final int[][] d = new int[n][n];
for (int i = 0; i + 1 < n; i++) {
d[i][i + 1] = d[i + 1][i] = 1;
}
for (int i = 0; i < 2 * n; i++) {
int u = rnd.nextInt(n - 1);
int v = u + 1 + rnd.nextInt(n - 1 - u);
d[u][v] = d[v][u] = 1;
}
// "hard" example
// int t = 10;
// n = 2 * t + 1;
// final int[][] d = new int[n][n];
// for (int i = 0; i < t; i++) {
// d[i][(i + 1) % t] = d[(i + 1) % t][i] = 1;
// d[i][n - 1] = d[n - 1][i] = 1;
// d[i + t][n - 1] = d[n - 1][i + t] = 1;
// d[i][i + t] = d[i + t][i] = 1;
// d[i][(i + 1) % t + t] = d[(i + 1) % t + t][i] = 1;
// }
panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (x == null) {
return;
}
Double minx = Double.POSITIVE_INFINITY;
Double miny = Double.POSITIVE_INFINITY;
int n = d.length;
for (int i = 0; i < n; i++) {
minx = Math.min(minx, x[i]);
miny = Math.min(miny, y[i]);
}
int[] x1 = new int[n];
int[] y1 = new int[n];
for (int i = 0; i < n; i++) {
x1[i] = (int) (x[i] - minx) + 10;
y1[i] = (int) (y[i] - miny) + 10;
}
Graphics2D g2 = ((Graphics2D) g);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(3));
g.setColor(Color.BLUE);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (d[i][j] > 0) {
g.drawLine(x1[i], y1[i], x1[j], y1[j]);
}
}
}
g.setColor(Color.RED);
for (int i = 0; i < n; i++) {
g.drawOval(x1[i] - 1, y1[i] - 1, 3, 3);
}
}
};
setContentPane(panel);
new Thread() {
public void run() {
drawGraph(d);
}
}.start();
}
public static void main(String[] args) {
JFrame frame = new ForceBasedGraphDrawer();
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}