public void DivideNode(IQuadTreeNode <T> node) { Point topLeft = node.Position; double xSplice = VerticalSplice() * node.Width; double ySplice = HorizontalSplice() * node.Height; Point subTopLeft = topLeft.Add(new Point(0, 0)); double subTopLeftHeight = ySplice; double subTopLeftWidth = xSplice; IQuadTreeNode <T> subTopLeftRoom = new QuadTreeNode <T>(node, subTopLeft, subTopLeftHeight, subTopLeftWidth); Point subTopRight = topLeft.Add(new Point(xSplice, 0)); double subTopRightHeight = ySplice; double subTopRightWidth = node.Width - xSplice; IQuadTreeNode <T> subTopRightRoom = new QuadTreeNode <T>(node, subTopRight, subTopRightHeight, subTopRightWidth); Point subBottomLeft = topLeft.Add(new Point(0, ySplice)); double subBottomLeftHeight = node.Height - ySplice; double subBottomLeftWidth = xSplice; IQuadTreeNode <T> subButtomLeftRoom = new QuadTreeNode <T>(node, subBottomLeft, subBottomLeftHeight, subBottomLeftWidth); Point subBottomRight = topLeft.Add(new Point(xSplice, ySplice)); double subBottomRightHeight = node.Height - ySplice; double subBottomRightWidth = node.Width - xSplice; IQuadTreeNode <T> subBottomRightRoom = new QuadTreeNode <T>(node, subBottomRight, subBottomRightHeight, subBottomRightWidth); node.Quarters = new IQuadTreeNode <T>[] { subTopLeftRoom, subTopRightRoom, subButtomLeftRoom, subBottomRightRoom }; }
public void RenderNodeBoundingBox <T>(DX11Game game, IQuadTreeNode <T> quadTreeNode) where T : IQuadTreeNode <T> { if (quadTreeNode == null) { return; } QuadTreeNodeData <T> node = quadTreeNode.NodeData; RenderNodeBoundingBox(game, node.UpperLeft); RenderNodeBoundingBox(game, node.UpperRight); RenderNodeBoundingBox(game, node.LowerLeft); RenderNodeBoundingBox(game, node.LowerRight); //TODO: Calculate level is quite lame here and slow, since we loop the tree level by level int level = QuadTree.CalculateLevel(quadTreeNode); Color4 col; if (level < levelColor4s.Length) { col = levelColor4s[level]; } else { col = levelColor4s[levelColor4s.Length - 1]; } game.LineManager3D.AddBox(quadTreeNode.NodeData.BoundingBox, col); }
public IQuadTreeNode AddItem(T item) { var bounding = _getBounding(item); if (_topLeft.Rect.Intersects(bounding)) { _topLeft = _topLeft.AddItem(item); } if (_topRight.Rect.Intersects(bounding)) { _topRight = _topRight.AddItem(item); } if (_bottomLeft.Rect.Intersects(bounding)) { _bottomLeft = _bottomLeft.AddItem(item); } if (_bottomRight.Rect.Intersects(bounding)) { _bottomRight = _bottomRight.AddItem(item); } return(this); }
public QuadTreeNode(IQuadTreeNode <T> parent, Point pos, double height, double width) { this.Parent = parent; this.Position = pos; this.Height = height; this.Width = width; this.Data = default(T); }
private async void SyncFromServer() { var snapshot = await EditorZoneSystem.Instance.ClientRequestZoneData(this.ProtoZone); this.lastClientSnapshot = this.lastServerSnapshot = snapshot; this.quadTree = QuadTreeNodeFactory.Create(snapshot); this.ZoneReset?.Invoke(); }
//protected virtual void RemoveChild( QuadTreeNode child ) //{ // if ( upperLeft == child ) // { // upperLeft = null; // } // if ( upperRight == child ) // { // upperRight = null; // } // if ( lowerLeft == child ) // { // lowerLeft = null; // } // if ( lowerRight == child ) // { // lowerRight = null; // } //} //public BoundingBox MergeBoundingBoxes( BoundingBox box1, BoundingBox box2 ) //{ // if ( box1.Min == box1.Max ) // { // return box2; // } // else if ( box2.Min == box2.Max ) // { // return box1; // } // else // { // return BoundingBox.CreateMerged( box1, box2 ); // } //} //public virtual string BuildString() //{ // return BuildString( 0 ); //} //public virtual string BuildString( int indentLenght ) //{ // const int indentStep = 3; // string indent = ""; // string ret = ""; // for ( int i = 0; i < indentLenght; i++ ) // { // indent += " "; // } // //ret += indent + "Node Entities:" + entities.Count.ToString(); // if ( upperLeft != null ) // { // ret += Environment.NewLine + upperLeft.BuildString( indentLenght + indentStep ); // } // if ( upperRight != null ) // { // ret += Environment.NewLine + upperRight.BuildString( indentLenght + indentStep ); // } // if ( lowerLeft != null ) // { // ret += Environment.NewLine + lowerLeft.BuildString( indentLenght + indentStep ); // } // if ( lowerRight != null ) // { // ret += Environment.NewLine + lowerRight.BuildString( indentLenght + indentStep ); // } // return ret; //} ////public override string ToString() ////{ //// string ret = ""; //// ret += "Node "; //// ret += "Level: " + CalculateLevel().ToString() + " "; //// if ( parent != null ) //// { //// if ( parent.upperLeft == this ) ret += "UpperLeft "; //// if ( parent.upperRight == this ) ret += "UpperRight "; //// if ( parent.lowerLeft == this ) ret += "LowerLeft "; //// if ( parent.lowerRight == this ) ret += "LowerRight "; //// } //// if ( IsLeaf ) ret += "Leaf "; //// //if ( entities.Count > 0 ) ret += "Entities: " + entities.Count.ToString() + " "; //// return ret; ////} //public override string ToString() //{ // return "Node " + NodeAddressToText( address ); //} //public QuadTreeNode FindOrCreateNode( ulong nAddress ) //{ // int level = GetLevel( this ); // int targetLevel = GetLevel( nAddress ); // if ( level < targetLevel ) // { // //Need to go deeper. // //Split this node. If this node allready has children then the call we be omitted. // Split(); // return GetChild( GetChildDirAtLevel( nAddress, level + 1 ) ).FindOrCreateNode( nAddress ); // } // else if ( level == targetLevel ) // { // if ( address == nAddress ) // { // //Yes! // return this; // } // else // { // //Oo, error // throw new InvalidOperationException(); // } // } // else // { // //level > targetLevel // throw new InvalidOperationException( "The node you are looking for is not a child of this node!! (or other issue)" ); // } //} public static int CalculateLevel <T>(IQuadTreeNode <T> node) where T : IQuadTreeNode <T> { if (node.NodeData.Parent == null) { return(0); } return(CalculateLevel(node.NodeData.Parent) + 1); }
// Use this for initialization void Start() { BlockZoom(); mCamera.AddBorderChangeListener(this); mRootNode = mStartNodeCreator.Create(); mStartupNodeInitializer.Run(mCamera, mRootNode, this); mPlayer.MoveRight(); }
private List <IQuadTreeNode> CreateQuadTreeNodesOnMultithreds(int segmentSize) { var processorCount = Environment.ProcessorCount; var waitHandles = new WaitHandle[processorCount]; var subsectors = 1; var subsectorSideSize = segmentSize; var subSectorsInRaw = 1; while (subsectors < processorCount) { subsectors *= 4; subSectorsInRaw *= 2; subsectorSideSize /= 2; } var sectorsInSegment = subSectorsInRaw * subsectorSideSize / mConstants.GetSectorSideSize(); sectorsInSegment *= sectorsInSegment; var loadingNodes = new IQuadTreeNode[sectorsInSegment]; var subsectorsPerProc = subsectors / processorCount; if (subsectors % processorCount != 0) { subsectorsPerProc += 1; } var threadQuadTreeNodeCreators = new IThreadQuadTreeNodeCreator[processorCount]; var allSubsectors = new IQuadTreeNode[subsectors]; for (int i = 0; i < processorCount; ++i) { var startIndex = i * subsectorsPerProc; var endIndex = startIndex + subsectorsPerProc; threadQuadTreeNodeCreators[i] = mThreadQuadTreeNodeCreatorFactory.Create(allSubsectors, loadingNodes, startIndex, endIndex, segmentSize , subsectorSideSize, subSectorsInRaw); waitHandles[i] = threadQuadTreeNodeCreators[i].GetWaitHandle(); ThreadPool.QueueUserWorkItem(threadQuadTreeNodeCreators[i].GetWaitCallback()); } WaitHandle.WaitAll(waitHandles); for (int i = 0; i < threadQuadTreeNodeCreators.Length; ++i) { // ReSharper disable once PossibleNullReferenceException var exception = threadQuadTreeNodeCreators[i].GetException(); if (exception != null) { throw exception; } } var allSubsectorsList = new List <IQuadTreeNode>(subsectors); allSubsectorsList.AddRange(allSubsectors); return(allSubsectorsList); }
//public QuadTreeNode GetChild( ChildDir dir ) //{ // switch ( dir ) // { // case ChildDir.UpperLeft: // return upperLeft; // break; // case ChildDir.UpperRight: // return upperRight; // break; // case ChildDir.LowerLeft: // return lowerLeft; // break; // case ChildDir.LowerRight: // return lowerRight; // break; // default: // throw new ArgumentException( "Invalid value", "dir" ); // } //} //public ChildDir GetChildDirAtLevel( ulong address, int level ) //{ // if ( level == 0 ) throw new ArgumentException( "Value cannot be 0", "level" ); // return (ChildDir)( ( address >> ( 4 + 2 * ( level - 1 ) ) ) & ( ( 1 << 0 ) + ( 1 << 1 ) ) ); //} //public int GetLevel( QuadTreeNode node ) //{ // return GetLevel( node.Address ); //} //public int GetLevel( ulong address ) //{ // //First four bytes of address // return (int)( address & ( ( 1 << 0 ) + ( 1 << 1 ) + ( 1 << 2 ) + ( 1 << 3 ) ) ); //} //public void UpdateAdress() //{ // address = CalculateAddress(); //} //public ulong CalculateAddress() //{ // // Het adres // // bit 0-3 : level van de node // // bit 4-63 : Welke childnode het is, telkens 2 bits per level // // 00 = upperLeft // // 01 = upperRight // // 10 = lowerLeft // // 11 = lowerRight // if ( parent == null ) return 0; // //TODO: power operator wont work // ulong levelBitmask = ( 1 << 0 ) + ( 1 << 1 ) + ( 1 << 2 ) + ( 1 << 3 ); // ulong parentLevel = parent.address & levelBitmask; // ulong ret; // ret = parent.address & ~levelBitmask; // //Ret now contains the parents address with the 4 lvl bits set to 0 // //Now set this nodes lvl // ret = ret | ( parentLevel + 1 ); // //Add the 2 bits at the end saying which child node this one is // ulong childMask; // if ( parent.upperLeft == this ) // { // childMask = 0; //00 // } // else if ( parent.upperRight == this ) // { // childMask = 1; //01 // } // else if ( parent.lowerLeft == this ) // { // childMask = 2; //10 // } // else if ( parent.lowerRight == this ) // { // childMask = 3; //11 // } // else // { // throw new Exception( "Impossible!!!" ); // } // ret = ret | ( childMask << ( 4 + 2 * (int)( parentLevel + 1 - 1 ) ) ); // //string temp = TempULongToBitsString( ret ); // //string path = NodeAddressToText( ret ); // return ret; //} //public string NodeAddressToText( ulong address ) //{ // string text = ""; // //Get address: first four bits of the address // int level = (int)( address & ( ( 1 << 0 ) + ( 1 << 1 ) + ( 1 << 2 ) + ( 1 << 3 ) ) ); // text += "Level: " + level.ToString() + " Root"; // //Get the location of the node for each lvl // ulong mask = ( 1 << 0 ) + ( 1 << 1 ); // for ( int iLevel = 1; iLevel <= level; iLevel++ ) // { // string locationName; // //int location = (int)( address & ( mask << ( 4 + 2 * ( iLevel - 1 ) ) ) ); // int location = (int)( ( address >> ( 4 + 2 * ( iLevel - 1 ) ) ) & mask ); // switch ( location ) // { // case 0: // locationName = "UpperLeft"; // break; // case 1: // locationName = "UpperRight"; // break; // case 2: // locationName = "LowerLeft"; // break; // case 3: // locationName = "LowerRight"; // break; // default: // throw new Exception( "Impossible" ); // } // text += "." + locationName; // } // return text; //} //public string TempULongToBitsString( ulong val ) //{ // string ret = ""; // for ( int i = 0; i < 64; i++ ) // { // ret = ( ( val & ( (ulong)1 << i ) ) > 0 ? "1" : "0" ) // + ret; // } // return ret; //} //public QuadTreeNode UpperLeft //{ // get { return upperLeft; } // set { upperLeft = value; } //} //public QuadTreeNode UpperRight //{ // get { return upperRight; } // set { upperRight = value; } //} //public QuadTreeNode LowerLeft //{ // get { return lowerLeft; } // set { lowerLeft = value; } //} //public QuadTreeNode LowerRight //{ // get { return lowerRight; } // set { lowerRight = value; } //} //public QuadTreeNode Parent //{ // get { return parent; } // set { parent = value; } //} //public BoundingBox BoundingBox //{ // get { return boundingBox; } // set { boundingBox = value; } //} //public ulong Address //{ // get { return address; } // set { address = value; } //} /// <summary> /// Returns true if this node doesn't have any children, otherwise false /// </summary> /// <typeparam name="T"></typeparam> /// <param name="node"></param> /// <returns></returns> public static bool IsLeafNode <T>(IQuadTreeNode <T> node) where T : class, IQuadTreeNode <T> { //Optimization: partial splits are not allowd currently return(node.NodeData.LowerLeft == null); //TODO: needs speedup? /*return (node.NodeData.UpperLeft == null) * && (node.NodeData.UpperRight == null) * && (node.NodeData.LowerLeft == null) * && (node.NodeData.LowerRight == null);*/ }
public void RenderNodeGroundBoundig <T>(DX11Game game, IQuadTreeNode <T> quadTreeNode) where T : IQuadTreeNode <T> { if (quadTreeNode == null) { return; } QuadTreeNodeData <T> node = quadTreeNode.NodeData; RenderNodeGroundBoundig(game, node.UpperLeft); RenderNodeGroundBoundig(game, node.UpperRight); RenderNodeGroundBoundig(game, node.LowerLeft); RenderNodeGroundBoundig(game, node.LowerRight); //if ( node.IsLeaf == false ) return; //FloorLowerLeft = min //TopUpperRight = max //TODO: Calculate level is quite lame here and slow, since we loop the tree level by level int level = QuadTree.CalculateLevel(quadTreeNode); Color4 col; if (level < levelColor4s.Length) { col = levelColor4s[level]; } else { col = levelColor4s[levelColor4s.Length - 1]; } Vector3 radius = (node.BoundingBox.Maximum - node.BoundingBox.Minimum); Vector3 radX = new Vector3(radius.X, 0, 0); Vector3 radY = new Vector3(0, radius.Y, 0); Vector3 radZ = new Vector3(0, 0, radius.Z); Vector3 min = node.BoundingBox.Minimum; min.Y = -1 + level; Vector3 fll = min; Vector3 flr = min + radX; Vector3 ful = min + radZ; Vector3 fur = min + radX + radZ; //grondvlak game.LineManager3D.AddLine(fll, flr, col); game.LineManager3D.AddLine(flr, fur, col); game.LineManager3D.AddLine(fur, ful, col); game.LineManager3D.AddLine(ful, fll, col); }
public QuadTreeNode([NotNull] IAABBox box , [NotNull] IQuadTreeNode topLeft , [NotNull] IQuadTreeNode topRight , [NotNull] IQuadTreeNode bottomLeft , [NotNull] IQuadTreeNode bottomRight) { mBox = box; mTopLeft = topLeft; mTopRight = topRight; mBottomLeft = bottomLeft; mBottomRight = bottomRight; }
private void Divide(IQuadTreeNode <T> node, int maxLevels, QuadtreeNodeDelegate onNode, int level) { if (maxLevels <= 0) { return; } onNode(node.Position, node.Height, node.Width, level); DivideNode(node); foreach (var quarter in node.Quarters) { Divide(quarter, maxLevels - 1, onNode, level + 1); } }
public void Run(IAABBox startViewBox, IQuadTreeNode rootNode, IArrayBackgroundWorkerListener listener) { var visibleNodesCollector = new VisibleNodesCollector(); rootNode.VisitVisibleNodes(startViewBox, visibleNodesCollector); var planetFactory = mPlanetFactoryCreator.CreatePlanetFactory(); foreach (var curLeaf in visibleNodesCollector.GetVisibleLeaves()) { // ReSharper disable once PossibleNullReferenceException curLeaf.SetPlanets(planetFactory.CreatePlanetsForSector()); } var nodesInCameraCollector = new VisibleNodesCollector(); rootNode.VisitVisibleNodes(new AABBox(0f, 0f, mConstants.GetMaxCameraSize(), mConstants.GetMaxCameraSize()), nodesInCameraCollector); mBackgroundWorker.AddListener(listener); mBackgroundWorker.Run(nodesInCameraCollector.GetVisibleLeaves(), mPlanetFactoryCreator); }
public QuadTreeParent(Rect rect, GetBoundingRectangle getBoundingRectangle, IEnumerable <T> items, int maxItems) { Rect = rect; _getBounding = getBoundingRectangle; var left = rect.Left; var top = rect.Top; var halfWidth = rect.Width / 2.0; var halfHeight = rect.Height / 2.0; _topLeft = new QuadTreeLeaf(new Rect(left, top, halfWidth, halfHeight), _getBounding, maxItems); _topRight = new QuadTreeLeaf(new Rect(left + halfWidth, top, halfWidth, halfHeight), _getBounding, maxItems); _bottomLeft = new QuadTreeLeaf(new Rect(left, top + halfHeight, halfWidth, halfHeight), _getBounding, maxItems); _bottomRight = new QuadTreeLeaf(new Rect(left + halfWidth, top + halfHeight, halfWidth, halfHeight), _getBounding, maxItems); foreach (var item in items) { AddItem(item); } }
public QuadTree(int sizeX, int sizeY, BinaryReader input, Func <byte[], int, TElement> readElement, int elementSize) { QuadTree <TElement> .readElement = readElement; QuadTree <TElement> .elementSize = elementSize; CalculateDimensions(sizeX, sizeY); allElementsEnumeration = from y in Enumerable.Range(0, SizeY) from x in Enumerable.Range(0, SizeX) select Get(x, y); flag = input.ReadBoolean(); if (flag) { root = new QuadTreeNode(input); } else { root = new QuadTreeLeaf(input); } }
public static void Merge <T>(IQuadTreeNode <T> node) where T : class, IQuadTreeNode <T> { QuadTreeNodeData <T> nodeData = node.NodeData; /*if (nodeData.UpperLeft != null) * upperLeft.Dispose(); * * if (nodeData.UpperRight != null) * upperRight.Dispose(); * * if (nodeData.LowerLeft != null) * lowerLeft.Dispose(); * * if (nodeData.LowerRight != null) * lowerRight.Dispose();*/ nodeData.UpperLeft = null; nodeData.UpperRight = null; nodeData.LowerLeft = null; nodeData.LowerRight = null; node.NodeData = nodeData; }
public QuadTree(IQuadTreeNode <T> root) { _root = root; }
public static async Task <Dictionary <Vector2Ushort, ZoneChunkFilledCellsCounter> > CalculateZoneChunks( IQuadTreeNode quadTree, int chunkSize, Func <Task> callbackYieldIfOutOfTime) { // this is a heavy method so we will try to yield every few nodes to reduce the load const int defaultCounterToYieldValue = 100; var counterToYield = defaultCounterToYieldValue; var dict = new Dictionary <Vector2Ushort, ZoneChunkFilledCellsCounter>(); if (false) { // slow algorithm (each tile added separately into the dictionary) ZoneChunkFilledCellsCounter lastCounter = new ZoneChunkFilledCellsCounter(Vector2Ushort.Max); foreach (var filledNode in quadTree.EnumerateFilledNodes()) { var size = filledNode.Size; var startPosition = filledNode.Position; var endPosition = startPosition + new Vector2Ushort(size, size); for (var y = startPosition.Y; y < endPosition.Y; y++) { for (var x = startPosition.X; x < endPosition.X; x++) { var chunkPosition = new Vector2Ushort((ushort)(x / chunkSize), (ushort)(y / chunkSize)); if (lastCounter.ChunkOffset == chunkPosition || dict.TryGetValue(chunkPosition, out lastCounter)) { lastCounter.Count++; } else { lastCounter = new ZoneChunkFilledCellsCounter(chunkPosition) { Count = 1 }; dict[chunkPosition] = lastCounter; } } } } } // fast algorithm (each quad tree node can instantly fill each chunk) foreach (var node in quadTree.EnumerateFilledNodes()) { await YieldIfOutOfTime(); var nodeStartPosition = node.Position; var startChunksOffset = new Vector2Ushort( (ushort)(chunkSize * (nodeStartPosition.X / chunkSize)), (ushort)(chunkSize * (nodeStartPosition.Y / chunkSize))); var nodeSize = node.Size; if (nodeSize == 1) { // short path var chunkPosition = new Vector2Ushort(startChunksOffset.X, startChunksOffset.Y); if (!dict.TryGetValue(chunkPosition, out var counter)) { counter = new ZoneChunkFilledCellsCounter(chunkPosition); dict[chunkPosition] = counter; } counter.Count++; continue; } // long path (for nodes > 1*1 size) var nodeEndPosition = nodeStartPosition.AddAndClamp(new Vector2Ushort(node.Size, node.Size)); var endChunksOffset = new Vector2Ushort( (ushort)(chunkSize * Math.Ceiling(nodeEndPosition.X / (double)chunkSize)), (ushort)(chunkSize * Math.Ceiling(nodeEndPosition.Y / (double)chunkSize))); for (var chunkY = startChunksOffset.Y; chunkY < endChunksOffset.Y; chunkY = (ushort)(chunkY + chunkSize)) { for (var chunkX = startChunksOffset.X; chunkX < endChunksOffset.X; chunkX = (ushort)(chunkX + chunkSize)) { var chunkPosition = new Vector2Ushort(chunkX, chunkY); var cellsCount = CalculateCellsCount(nodeStartPosition, nodeEndPosition, chunkX, chunkY, chunkSize); if (!dict.TryGetValue(chunkPosition, out var counter)) { counter = new ZoneChunkFilledCellsCounter(chunkPosition); dict[chunkPosition] = counter; } counter.Count += cellsCount; } } } return(dict); Task YieldIfOutOfTime() { if (--counterToYield > 0) { return(Task.CompletedTask); } counterToYield = defaultCounterToYieldValue; return(callbackYieldIfOutOfTime()); } }
public void Add(IQuadTreeNode node) { }
public void AddSubNode(IQuadTreeNode node) { }
public void AddItem(T item) { _root = _root.AddItem(item); }
public QuadTree(Rect rect, GetBoundingRectangle getBoundingRectangle, int maxItems = MAX_ITEMS) { _root = new QuadTreeLeaf(rect, getBoundingRectangle, maxItems); _getBounding = getBoundingRectangle; }
public QuadTree(Rect rect, GetBoundingRectangle getBoundingRectangle) { _root = new QuadTreeLeaf(rect, getBoundingRectangle); _getBounding = getBoundingRectangle; }