Example #1
0
        private static FieldOctree <GravityCell> BuildField(MapOctree mapSnapshot, double gravConstant)
        {
            // Dig through the tree, and construct my tree with partially populated leaves (mass but no force)
            List <GravityCell>        allLeavesList = new List <GravityCell>();
            FieldOctree <GravityCell> retVal        = BuildField_Node(allLeavesList, null, mapSnapshot);

            GravityCell[] allLeaves = allLeavesList.ToArray();
            Vector3D[]    forces    = new Vector3D[allLeaves.Length];

            // Calculate the force of gravity for each cell
            //TODO: Individual far away cells shouldn't need to be processed individually, use their parent instead
            BuildField_Forces(allLeaves, forces, gravConstant);

            // Sort on token to make things easier for the swapper
            SortedList <long, int> indicesByToken = new SortedList <long, int>();

            for (int cntr = 0; cntr < allLeaves.Length; cntr++)
            {
                indicesByToken.Add(allLeaves[cntr].Token, cntr);
            }

            // Inject the forces into the leaves
            BuildField_SwapLeaves(retVal, indicesByToken, forces);

            // Exit Function
            return(retVal);
        }
Example #2
0
        private void Timer_Tick(object sender, EventArgs e)
        {
            _timer.IsEnabled = false;
            DateTime startTime = DateTime.UtcNow;

            MapOctree snapshot = _map.LatestSnapshot;

            if (snapshot == null || (_lastSnapshotToken != null && snapshot.Token == _lastSnapshotToken.Value))
            {
                // There is nothing to do, rig the timer to try again later
                ScheduleNextTick(startTime);
                return;
            }

            _lastSnapshotToken = snapshot.Token;
            double gravConstant = this.GravitationalConstant;

            // Build the field on a different thread
            var task = Task.Factory.StartNew(() =>
            {
                _fieldRoot = BuildField(snapshot, gravConstant);
            });

            // After the tree is built, schedule the next build from within this current thread
            task.ContinueWith(resultTask =>
            {
                // Schedule the next snapshot
                ScheduleNextTick(startTime);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
Example #3
0
        private static void BuildField_SwapLeaves(FieldOctree <GravityCell> node, SortedList <long, int> indicesByToken, Vector3D[] forces)
        {
            if (node.IsLeaf)
            {
                // Find the index into forces
                int index = indicesByToken[node.Leaf.Token];

                // Swap it out
                node.Leaf = new GravityCell(node.Leaf.Token, node.Leaf.Mass, node.Leaf.Position, forces[index]);
            }
            else
            {
                // Every child is non null, so just recurse with each one
                BuildField_SwapLeaves(node.X0_Y0_Z0, indicesByToken, forces);
                BuildField_SwapLeaves(node.X0_Y0_Z1, indicesByToken, forces);
                BuildField_SwapLeaves(node.X0_Y1_Z0, indicesByToken, forces);
                BuildField_SwapLeaves(node.X0_Y1_Z1, indicesByToken, forces);
                BuildField_SwapLeaves(node.X1_Y0_Z0, indicesByToken, forces);
                BuildField_SwapLeaves(node.X1_Y0_Z1, indicesByToken, forces);
                BuildField_SwapLeaves(node.X1_Y1_Z0, indicesByToken, forces);
                BuildField_SwapLeaves(node.X1_Y1_Z1, indicesByToken, forces);
            }
        }
Example #4
0
        private static void GetLeaves_Recurse(List <GravityCell> returnList, FieldOctree <GravityCell> node)
        {
            if (node == null)
            {
                return;
            }

            if (node.IsLeaf)
            {
                returnList.Add(node.Leaf);
            }
            else
            {
                // Recurse
                GetLeaves_Recurse(returnList, node.X0_Y0_Z0);
                GetLeaves_Recurse(returnList, node.X0_Y0_Z1);
                GetLeaves_Recurse(returnList, node.X0_Y1_Z0);
                GetLeaves_Recurse(returnList, node.X0_Y1_Z1);
                GetLeaves_Recurse(returnList, node.X1_Y0_Z0);
                GetLeaves_Recurse(returnList, node.X1_Y0_Z1);
                GetLeaves_Recurse(returnList, node.X1_Y1_Z0);
                GetLeaves_Recurse(returnList, node.X1_Y1_Z1);
            }
        }
Example #5
0
        private static FieldOctree <GravityCell> BuildField_Node(List <GravityCell> allLeaves, MapOctree[] ancestors, MapOctree node)
        {
            #region Add up mass

            double massOfNode = 0d;
            if (node.Items != null)
            {
                foreach (MapObjectInfo item in node.Items)
                {
                    massOfNode += item.Mass;
                }
            }

            #endregion

            if (!node.HasChildren)
            {
                #region Leaf

                // Exit Function
                GravityCell cell = new GravityCell(BuildField_NodeSprtAncestorMass(ancestors, node.MinRange, node.MaxRange) + massOfNode, node.CenterPoint);
                allLeaves.Add(cell);
                return(new FieldOctree <GravityCell>(node.MinRange, node.MaxRange, node.CenterPoint, cell));

                #endregion
            }

            // Make the return node
            FieldOctree <GravityCell> retVal = new FieldOctree <GravityCell>(node.MinRange, node.MaxRange, node.CenterPoint);

            #region Build ancestor arrays

            // Create new arrays that hold this node's values (to pass to the children)
            MapOctree[] ancestorsNew = null;
            if (ancestors == null)
            {
                // This is the root
                ancestorsNew = new MapOctree[] { node };
            }
            else
            {
                // This is a middle ancestor
                ancestorsNew = new MapOctree[ancestors.Length + 1];
                Array.Copy(ancestors, ancestorsNew, ancestors.Length);
                ancestorsNew[ancestorsNew.Length - 1] = node;
            }

            #endregion

            #region Add the children

            //NOTE: The map's octree will leave children null if there are no items in them.  But this tree always has all 8 children

            if (node.X0_Y0_Z0 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.MinRange.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.CenterPoint.Z);
                retVal.X0_Y0_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y0_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y0_Z0);
            }

            if (node.X0_Y0_Z1 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.MinRange.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.MaxRange.Z);
                retVal.X0_Y0_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y0_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y0_Z1);
            }

            if (node.X0_Y1_Z0 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.CenterPoint.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.MaxRange.Y, node.CenterPoint.Z);
                retVal.X0_Y1_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y1_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y1_Z0);
            }

            if (node.X0_Y1_Z1 == null)
            {
                Point3D childMin = new Point3D(node.MinRange.X, node.CenterPoint.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.CenterPoint.X, node.MaxRange.Y, node.MaxRange.Z);
                retVal.X0_Y1_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X0_Y1_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X0_Y1_Z1);
            }

            if (node.X1_Y0_Z0 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.MinRange.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.CenterPoint.Y, node.CenterPoint.Z);
                retVal.X1_Y0_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y0_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y0_Z0);
            }

            if (node.X1_Y0_Z1 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.MinRange.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.CenterPoint.Y, node.MaxRange.Z);
                retVal.X1_Y0_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y0_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y0_Z1);
            }

            if (node.X1_Y1_Z0 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.MinRange.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.MaxRange.Y, node.CenterPoint.Z);
                retVal.X1_Y1_Z0 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y1_Z0 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y1_Z0);
            }

            if (node.X1_Y1_Z1 == null)
            {
                Point3D childMin = new Point3D(node.CenterPoint.X, node.CenterPoint.Y, node.CenterPoint.Z);
                Point3D childMax = new Point3D(node.MaxRange.X, node.MaxRange.Y, node.MaxRange.Z);
                retVal.X1_Y1_Z1 = BuildField_Node(allLeaves, BuildField_NodeSprtAncestorMass(ancestors, childMin, childMax) + massOfNode, childMin, childMax);
            }
            else
            {
                retVal.X1_Y1_Z1 = BuildField_Node(allLeaves, ancestorsNew, node.X1_Y1_Z1);
            }

            #endregion

            // Exit Function
            return(retVal);
        }
Example #6
0
        public T GetLeaf(Point3D position)
        {
            if (!Math3D.IsInside_AABB(_minRange, _maxRange, position))
            {
                // Let a tree node throw an exception.  The container of the entire tree can decide whether to return null or an exception if a request
                // is out of bounds of the entire tree.
                throw new ArgumentOutOfRangeException("The position is not inside this tree");
            }

            if (_isLeaf)
            {
                return(this.Leaf);
            }

            // Figure out which child to look in
            //NOTE: Because the children can be swapped out at any momemnt, I have to get that instance, and then check if that instance is null (can't
            // double call this.Child)

            FieldOctree <T> child = null;

            if (position.X <= _centerPoint.X && position.Y <= _centerPoint.Y && position.Z <= _centerPoint.Z)           // 0
            {
                child = this.X0_Y0_Z0;
            }
            else if (position.X <= _centerPoint.X && position.Y <= _centerPoint.Y && position.Z > _centerPoint.Z)               // 1
            {
                child = this.X0_Y0_Z1;
            }
            else if (position.X <= _centerPoint.X && position.Y > _centerPoint.Y && position.Z <= _centerPoint.Z)               // 2
            {
                child = this.X0_Y1_Z0;
            }
            else if (position.X <= _centerPoint.X && position.Y > _centerPoint.Y && position.Z > _centerPoint.Z)                // 3
            {
                child = this.X0_Y1_Z1;
            }
            else if (position.X > _centerPoint.X && position.Y <= _centerPoint.Y && position.Z <= _centerPoint.Z)               // 4
            {
                child = this.X1_Y0_Z0;
            }
            else if (position.X > _centerPoint.X && position.Y <= _centerPoint.Y && position.Z > _centerPoint.Z)                // 5
            {
                child = this.X1_Y0_Z1;
            }
            else if (position.X > _centerPoint.X && position.Y > _centerPoint.Y && position.Z <= _centerPoint.Z)                // 6
            {
                child = this.X1_Y1_Z0;
            }
            else //if (position.X > _centerPoint.X && position.Y > _centerPoint.Y && position.Z > _centerPoint.Z)		// 7
            {
                child = this.X1_Y1_Z1;
            }

            if (child == null)
            {
                return(null);
            }

            // Recurse
            return(child.GetLeaf(position));
        }