/// <summary>
        /// Adds a node to the appropriate subtree based on its position in space.
        /// </summary>
        /// <param name="node">The node to add to a subtree.</param>
        private void AddToSubtree(Node node)
        {
            double subtreeWidth = _width / 2;

            // Don't create subtrees if it violates the width limit.
            if (subtreeWidth >= MinimumWidth)
            {
                if (_subtrees == null)
                {
                    _subtrees = new Octree[8];
                }

                // Determine which subtree the node belongs in and add it to that subtree.
                int subtreeIndex = 0;
                for (int i = -1; i <= 1; i += 2)
                {
                    for (int j = -1; j <= 1; j += 2)
                    {
                        for (int k = -1; k <= 1; k += 2)
                        {
                            Vector subtreeLocation = _location + (subtreeWidth / 2) * new Vector(i, j, k);

                            // Determine if the node is contained within the bounds of the subtree under
                            // consideration.
                            if (Math.Abs(subtreeLocation.X - node.Location.X) <= subtreeWidth / 2 &&
                                Math.Abs(subtreeLocation.Y - node.Location.Y) <= subtreeWidth / 2 &&
                                Math.Abs(subtreeLocation.Z - node.Location.Z) <= subtreeWidth / 2)
                            {
                                if (_subtrees[subtreeIndex] == null)
                                {
                                    _subtrees[subtreeIndex] = new Octree(subtreeLocation, subtreeWidth);
                                }
                                _subtrees[subtreeIndex].Add(node);
                                return;
                            }
                            subtreeIndex++;
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <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;
                    }
                });
            }
        }