org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutSpringRepulsion Maven / Gradle / Ivy
The newest version!
package org.jungrapht.visualization.layout.algorithms.repulsion;
import static org.jungrapht.visualization.layout.algorithms.SpringLayoutAlgorithm.*;
import java.util.ConcurrentModificationException;
import java.util.Map;
import java.util.Random;
import org.jungrapht.visualization.layout.model.LayoutModel;
import org.jungrapht.visualization.layout.model.Point;
import org.jungrapht.visualization.layout.quadtree.BarnesHutQuadTree;
import org.jungrapht.visualization.layout.quadtree.ForceObject;
import org.jungrapht.visualization.layout.quadtree.Node;
/**
* @author Tom Nelson
* @param the vertex type
*/
public class BarnesHutSpringRepulsion
extends StandardSpringRepulsion<
V, BarnesHutSpringRepulsion, BarnesHutSpringRepulsion.Builder>
implements BarnesHutRepulsion<
V, BarnesHutSpringRepulsion, BarnesHutSpringRepulsion.Builder> {
public static class Builder
extends StandardSpringRepulsion.Builder<
V, BarnesHutSpringRepulsion, BarnesHutSpringRepulsion.Builder>
implements BarnesHutRepulsion.Builder<
V, BarnesHutSpringRepulsion, BarnesHutSpringRepulsion.Builder> {
private double theta = Node.DEFAULT_THETA;
private BarnesHutQuadTree tree = new BarnesHutQuadTree<>();
public Builder layoutModel(LayoutModel layoutModel) {
this.layoutModel = layoutModel;
this.tree =
BarnesHutQuadTree.builder()
.bounds(layoutModel.getWidth(), layoutModel.getHeight())
.theta(theta)
.build();
return this;
}
public Builder theta(double theta) {
this.theta = theta;
return this;
}
public Builder nodeData(Map springVertexData) {
this.springVertexData = springVertexData;
return this;
}
public Builder repulsionRangeSquared(int repulsionRangeSquared) {
this.repulsionRangeSquared = repulsionRangeSquared;
return this;
}
@Override
public Builder random(Random random) {
this.random = random;
return this;
}
public BarnesHutSpringRepulsion build() {
return new BarnesHutSpringRepulsion(this);
}
}
protected BarnesHutQuadTree tree;
public static Builder builder() {
return new Builder();
}
@Deprecated
public static Builder barnesHutBuilder() {
return builder();
}
protected BarnesHutSpringRepulsion(Builder builder) {
super(builder);
this.tree = builder.tree;
}
public void step() {
tree.rebuild(layoutModel.getGraph().vertexSet(), layoutModel);
}
public void calculateRepulsion() {
try {
for (V vertex : vertexSet) {
if (layoutModel.isLocked(vertex)) {
continue;
}
SpringVertexData svd = springVertexData.getOrDefault(vertex, new SpringVertexData());
Point forcePoint = layoutModel.apply(vertex);
ForceObject nodeForceObject =
new ForceObject(vertex, forcePoint.x, forcePoint.y) {
@Override
protected void addForceFrom(ForceObject other) {
if (other == null || vertex == other.getElement()) {
return;
}
Point p = this.p;
Point p2 = other.p;
if (p == null || p2 == null) {
return;
}
double vx = p.x - p2.x;
double vy = p.y - p2.y;
double distanceSq = p.distanceSquared(p2);
if (distanceSq == 0) {
f = f.add(random.nextDouble(), random.nextDouble());
} else if (distanceSq < repulsionRangeSquared) {
double factor = 1;
f = f.add(factor * vx / distanceSq, factor * vy / distanceSq);
}
}
};
tree.applyForcesTo(nodeForceObject);
Point f = Point.of(nodeForceObject.f.x, nodeForceObject.f.y);
double dlen = f.x * f.x + f.y * f.y;
if (dlen > 0) {
dlen = Math.sqrt(dlen) / 2;
svd.repulsiondx += f.x / dlen;
svd.repulsiondy += f.y / dlen;
}
}
} catch (ConcurrentModificationException cme) {
calculateRepulsion();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy