/// <summary> /// Advances the world model by one frame. /// </summary> public void Update() { // Update nodes. lock (_nodeLock) { // Update the nodes and determine required tree width. double halfWidth = 0; foreach (Node node in _nodes) { node.Update(); halfWidth = Math.Max(Math.Abs(node.Location.X), halfWidth); halfWidth = Math.Max(Math.Abs(node.Location.Y), halfWidth); halfWidth = Math.Max(Math.Abs(node.Location.Z), halfWidth); } // Build tree for node repulsion. Octree tree = new Octree(2.1 * halfWidth); foreach (Node node in _nodes) { tree.Add(node); } if (_nodes.Count > 0) { Parallel.ForEach(_nodes, node => { // Apply repulsion between nodes. tree.Accelerate(node); // Apply origin attraction of nodes. Vector originDisplacementUnit = -node.Location.Unit(); double originDistance = node.Location.Magnitude(); double attractionCofficient = OriginFactor; if (originDistance < OriginWeakDistance) { attractionCofficient *= originDistance / OriginWeakDistance; } node.Acceleration += originDisplacementUnit * attractionCofficient / (originDistance + OriginEpsilon); // Apply edge spring forces. foreach (Node other in node.Connected) { Vector displacement = node.Location.To(other.Location); Vector direction = displacement.Unit(); double distance = displacement.Magnitude(); double idealLength = EdgeLength + node.Radius + other.Radius; node.Acceleration += direction * EdgeFactor * (distance - idealLength) / node.Mass; } }); } // Update frame info. if (_nodes.Count > 0) { Frames++; } } // Update camera. _cameraZ += _cameraZVelocity * _cameraZ; _cameraZ = Math.Max(1, _cameraZ); _cameraZVelocity *= CameraZEasing; _renderer.Camera.Z = _cameraZ; }
/// <summary> /// Advances the world model by one frame. /// </summary> public void Update() { // Update nodes. lock (_nodeLock) { // Update the nodes and determine required tree width. double halfWidth = 0; foreach (Node node in _nodes) { node.Update(); halfWidth = Math.Max(Math.Abs(node.Location.X), halfWidth); halfWidth = Math.Max(Math.Abs(node.Location.Y), halfWidth); halfWidth = Math.Max(Math.Abs(node.Location.Z), halfWidth); } Radius = halfWidth; // Build tree for node repulsion. Octree tree = new Octree(2.1 * halfWidth); foreach (Node node in _nodes) { tree.Add(node); } Threading.Parallel.ForEach(_nodes, node => { // Apply repulsion between nodes. tree.Accelerate(node); // Apply origin attraction of nodes. //Vector originDisplacementUnit = -node.Location.Unit(); Vector origin = (node.Group == null) ? Vector.Zero : node.Group.Origin; Vector originDisplacementUnit = Unit(origin - node.Location); double originDistance = (origin - node.Location).Magnitude(); double attractionCofficient = OriginFactor; if (originDistance < OriginWeakDistance) { attractionCofficient *= originDistance / OriginWeakDistance; } // Apply group's attraction factor //attractionCofficient *= (node.Group == null) ? 1 : node.Group.Factor; //node.Acceleration += originDisplacementUnit * attractionCofficient / (originDistance + OriginEpsilon); Vector originAcceleration = originDisplacementUnit * attractionCofficient / (originDistance + OriginEpsilon); if (node.Group != null) { originAcceleration.X *= node.Group.Factor.X; originAcceleration.Y *= node.Group.Factor.Y; originAcceleration.Z *= node.Group.Factor.Z; } node.Acceleration += originAcceleration; // Apply edge spring forces. foreach (Node other in node.Connected) { Vector displacement = node.Location.To(other.Location); //Vector direction = displacement.Unit(); Vector direction = Unit(displacement); double distance = displacement.Magnitude(); //double idealLength = EdgeLength + node.Radius + other.Radius; // Set a large mass if it's in different groups double mass = (node.Group != other.Group) ? 1000 : node.Mass; double idealLength = EdgeLength + Node.GetRadius(mass) + other.Radius; node.Acceleration += direction * EdgeFactor * (distance - idealLength) / mass; //node.Acceleration += direction * EdgeFactor * (distance - idealLength) / node.Mass; } }); } }