14 public static class SpringConnection {
17 public boolean push =
true;
18 public boolean pull =
true;
19 public SpringNode from;
23 public static class SpringNode {
26 public Vector2f loc =
new Vector2f();
27 public Vector2f vel =
new Vector2f();
28 public Vector2f force =
new Vector2f();
31 public boolean moveable =
true;
32 public List<SpringConnection> connections =
new ArrayList<SpringConnection>();
35 public static class SpringSystem {
36 public List<SpringNode> nodes =
new ArrayList<SpringNode>();
37 public List<SpringConnection> connections =
new ArrayList<SpringConnection>();
41 public SpringNode addNode(Object custom,
float radius,
float mass,
float x,
float y) {
42 SpringNode node =
new SpringNode();
53 public boolean connExists(SpringNode from, SpringNode to) {
54 for (SpringConnection conn : connections) {
55 if (conn.from == from && conn.to == to)
return true;
56 if (conn.from == to && conn.to == from)
return true;
62 public void addConnection(SpringNode from, SpringNode to,
float k,
float d,
boolean push,
boolean pull) {
63 if (from == to)
return;
64 if (connExists(from, to))
return;
66 SpringConnection conn =
new SpringConnection();
74 from.connections.add(conn);
75 to.connections.add(conn);
77 connections.add(conn);
80 public void advance(
float amount) {
81 if (amount <= 0)
return;
84 for (SpringNode node : nodes) {
88 for (SpringConnection conn : connections) {
89 float dist = Misc.getDistance(conn.from.loc, conn.to.loc);
90 if (!conn.push && dist < conn.d)
continue;
91 if (!conn.pull && dist > conn.d)
continue;
93 float diff = conn.d - dist;
95 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(conn.from.loc, conn.to.loc));
97 float force = conn.k * diff;
99 conn.to.force.x += dir.x * force;
100 conn.to.force.y += dir.y * force;
101 conn.from.force.x -= dir.x * force;
102 conn.from.force.y -= dir.y * force;
106 for (SpringNode node : nodes) {
107 float friction = node.vel.length() * cof;
108 float max = node.vel.length() * node.mass / amount;
109 if (friction > max) friction = max;
112 Vector2f dir =
new Vector2f(node.vel);
116 node.force.x += dir.x;
117 node.force.y += dir.y;
130 for (SpringNode node : nodes) {
131 if (!node.moveable)
continue;
133 float ax = node.force.x / node.mass;
134 float ay = node.force.y / node.mass;
136 node.vel.x += ax * amount;
137 node.vel.y += ay * amount;
139 node.loc.x += node.vel.x * amount;
140 node.loc.y += node.vel.y * amount;
144 public boolean isDone() {
145 for (SpringNode n1 : nodes) {
146 for (SpringNode n2 : nodes) {
147 if (n1 == n2)
continue;
148 float dist = Misc.getDistance(n1.loc, n2.loc);
149 if (dist < n1.radius + n2.radius) {
154 for (SpringConnection conn : connections) {
155 if (!conn.pull)
continue;
157 float dist = Misc.getDistance(conn.from.loc, conn.to.loc);
158 if (dist > conn.d + 1000f) {
168 public static class StarNode {
169 public StarSystemAPI system;
170 public Vector2f location;
171 public StarNode(StarSystemAPI system, Vector2f location) {
172 this.system = system;
173 this.location = location;
218 final SpringSystem springs =
new SpringSystem();
219 if (systems.isEmpty())
return springs;
221 Vector2f loc =
new Vector2f(0, 0);
223 boolean first =
true;
224 for (StarSystemAPI system : systems) {
225 float radius = system.getMaxRadiusInHyperspace();
226 if (radius < 500) radius = 500;
229 SpringNode node = springs.addNode(system, radius, mass,
230 loc.x + random.nextFloat(), loc.y + random.nextFloat());
232 node.moveable =
false;
237 List<SpringNode> copy =
new ArrayList<SpringNode>(springs.nodes);
238 SpringNode curr = copy.get((
int) (copy.size() * random.nextDouble()));
244 while (!copy.isEmpty()) {
245 int numBranches = random.nextInt(3) + 1;
248 for (
int i = 0; i < numBranches; i++) {
249 if (copy.isEmpty())
break;
251 SpringNode other = copy.get((
int) (copy.size() * random.nextDouble()));
257 springs.addConnection(curr, other, pullK, d,
true,
true);
259 if (i == numBranches - 1) {
266 for (SpringNode n1 : springs.nodes) {
267 for (SpringNode n2 : springs.nodes) {
268 if (n1 == n2)
continue;
269 float d = (n1.radius + n2.radius) + 5000f;
270 springs.addConnection(n1, n2, pushK, d,
true,
false);
274 for (SpringNode node : springs.nodes) {
275 StarSystemAPI system = (StarSystemAPI) node.custom;
276 system.getLocation().set(node.loc);
282 public static SpringSystem
doConstellationLayout(List<StarSystemAPI> systems, Random random, Vector2f centerPoint) {
285 for (
int i = 0; i < 1000; i++) {
286 springs.advance(0.25f);
287 if (springs.isDone())
break;
290 if (!springs.isDone()) {
292 for (
int i = 0; i < 1000; i++) {
293 springs.advance(0.25f);
294 if (springs.isDone())
break;
300 float minX = Float.MAX_VALUE;
301 float maxX = -Float.MAX_VALUE;
302 float minY = Float.MAX_VALUE;
303 float maxY = -Float.MAX_VALUE;
305 for (SpringNode node : springs.nodes) {
306 float x = node.loc.x;
307 float y = node.loc.y;
308 if (x < minX) minX = x;
309 if (x > maxX) maxX = x;
310 if (y < minY) minY = y;
311 if (y > maxY) maxY = y;
314 float midX = minX + (maxX - minX) * 0.5f;
315 float midY = minY + (maxY - minY) * 0.5f;
317 for (SpringNode node : springs.nodes) {
318 node.loc.x = (int)(node.loc.x - midX + centerPoint.x);
319 node.loc.y = (int)(node.loc.y - midY + centerPoint.y);
323 for (SpringNode node : springs.nodes) {
324 StarSystemAPI system = (StarSystemAPI) node.custom;
325 system.getLocation().set(node.loc);