private void TestInternals(PureQuadTreeNode leaf, ref ulong[] codes) { if (leaf.ChildNum == 0) { if (leaf.Parent.Children[1].Children == null) { codes[1] = leaf.Parent.Children[1].Code; } if (leaf.Parent.Children[2].Children == null) { codes[2] = leaf.Parent.Children[2].Code; } } else if (leaf.ChildNum == 1) { if (leaf.Parent.Children[0].Children == null) { codes[0] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { codes[2] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 2) { if (leaf.Parent.Children[0].Children == null) { codes[3] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { codes[1] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 3) { if (leaf.Parent.Children[2].Children == null) { codes[0] = leaf.Parent.Children[2].Code; } if (leaf.Parent.Children[1].Children == null) { codes[3] = leaf.Parent.Children[1].Code; } } }
private void DrawChildren(Graphics g, PureQuadTreeNode node) { if (node.Children != null) { float halfX = node.Size.X / 2; float halfY = node.Size.Y / 2; g.DrawLine(Pens.Black, node.Location.X + halfX, node.Location.Y, node.Location.X + halfX, node.Location.Y + node.Size.Y); g.DrawLine(Pens.Black, node.Location.X, node.Location.Y + halfY, node.Location.X + node.Size.X, node.Location.Y + halfY); for (int i = 0; i < 4; i++) { DrawChildren(g, node.Children[i]); } } else { using (Brush brush = new SolidBrush(Color.FromArgb(255, 0, 0, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y - 1); } string debug = "[" + node.Code + "]"; if (leafPatches.ContainsKey(node.Code)) { // draw right patches if ((leafPatches[node.Code] & (byte)Directions.Down) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } } //debug += "(D=" + patchCodes[node.Code][2] + ")"; } else if ((leafPatches[node.Code] & (byte)Directions.Up) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } } // += "(U=" + patchCodes[node.Code][3] + ")"; } else { if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } //debug += "(D=" + patchCodes[node.Code][2] + ")"; } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } //debug += "(U=" + patchCodes[node.Code][3] + ")"; } } if ((leafPatches[node.Code] & (byte)Directions.Left) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } else if ((leafPatches[node.Code] & (byte)Directions.Right) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } else { if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } /*if (patchCodes[node.Code][0] != ulong.MaxValue) * debug += "L(" + patchCodes[node.Code][0] + ")"; * if (patchCodes[node.Code][1] != ulong.MaxValue) * debug += "R(" + patchCodes[node.Code][1] + ")";*/ if (patchCodes[node.Code][2] != ulong.MaxValue) { debug += "D(" + patchCodes[node.Code][2] + ")"; } if (patchCodes[node.Code][3] != ulong.MaxValue) { debug += "U(" + patchCodes[node.Code][3] + ")"; } /*if (patchCodes[node.Code][1] != 14) * g.DrawString(patchCodes[node.Code][0] + "," + patchCodes[node.Code][1], Font, Brushes.Red, (int)node.Location.X, (int)node.Location.Y); * else * g.DrawString(patchCodes[node.Code][0].ToString(), Font, Brushes.Red, (int)node.Location.X, (int)node.Location.Y);*/ } else if (patchCodes.ContainsKey(node.Code)) { // just internal patches if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } } if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } Font font = new Font("Verdana", 6); g.DrawString(debug, font, Brushes.Orange, (int)node.Location.X, (int)node.Location.Y); } }
private void BuildNode(PureQuadTreeNode node) { float levelFalloff = falloff / node.Level; // first establish if visible or not by testing centre of node, then corners until visible bool visible = (node.Level == 0 || TestPoint(node.Centre) || TestPoint(node.Location) || TestPoint(new Vector2(node.Location.X + node.Size.X, node.Location.Y)) || TestPoint(new Vector2(node.Location.X, node.Location.Y + node.Size.Y)) || TestPoint(new Vector2(node.Location.X + node.Size.X, node.Location.Y + node.Size.Y))); // log what detail the leaf is to be, and if visible if (visible) { leafDetail[node.Code] = (short)node.Level; } else { leafDetail[node.Code] = (short)-node.Level; } if (visible) { // decide if to fork or not //Vector2 halfChildSize = node.Size * 0.25f; float distance = (node.Centre - viewPos).Length(); // test this node first directly if (distance < levelFalloff) { node.Fork(1, false); for (int c = 0; c < 4; c++) { BuildNode(node.Children[c]); } } } //else //{ // // test children directly // for (int i = 0; i < 4; i++) // { // // check centre distance // Vector2 centre = new Vector2(); // switch (i) // { // case 2: // centre = new Vector2(node.Location.X + halfChildSize.X, node.Location.Y + halfChildSize.Y); // break; // case 3: // centre = new Vector2(node.Location.X + (halfChildSize.X * 3), node.Location.Y + halfChildSize.Y); // break; // case 0: // centre = new Vector2(node.Location.X + halfChildSize.X, node.Location.Y + (halfChildSize.Y * 3)); // break; // case 1: // centre = new Vector2(node.Location.X + (halfChildSize.X * 3), node.Location.Y + (halfChildSize.Y * 3)); // break; // } // float distance = (centre - viewPos).Length(); // if (distance < levelFalloff) // { // if (node.Children == null) // { // node.Fork(1, false); // for (int c = 0; c < 4; c++) // { // BuildNode(node.Children[c]); // } // } // } // else // { // // check visibility // bool visible = false; // //if (distance < falloff) // //{ // float value = viewFOVpl1.Dot(new Vector3(node.Centre.X, 0, node.Centre.Y)); // if (value > 0) // { // //if (viewFOVpl2.Dot(new Vector3(node.Centre.X, 0, node.Centre.Y)) < 0) // visible = true; // } // //} // // log what detail the leaf is to be, and if visible // if (visible) // leafDetail[node.Code] = (short)node.Level; // else // leafDetail[node.Code] = (short)-node.Level; // } // } //} }
private bool TraceNode(PureQuadTreeNode node, bool axis, int index) { PureQuadTreeNode current = node.Parent; // move upwards until we can switch over Stack <byte> upTrace = new Stack <byte>(); upTrace.Push((byte)node.ChildNum); while (current != null && current.Level > 0) { bool flip = false; if (axis) { if (node.ChildNum == 0 || node.ChildNum == 2) { if (current.ChildNum == 1 || current.ChildNum == 3) { flip = true; } } else if (node.ChildNum == 1 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 2) { flip = true; } } } else { if (node.ChildNum == 0 || node.ChildNum == 1) { if (current.ChildNum == 2 || current.ChildNum == 3) { flip = true; } } else if (node.ChildNum == 2 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 1) { flip = true; } } } if (flip) { // flip this and move down tree by slipping the stack until we hit and end //upTrace.Push((byte)current.ChildNum); int target = FlipNode(current.ChildNum, axis); current = current.Parent.Children[target]; ushort level = current.Level; ulong code = current.Code; while (current != null) { level = current.Level; code = current.Code; if (level == node.Level) { break; } if (level >= node.Level) { return(false); } /*if (upTrace.Count == 0) * break;*/ target = FlipNode(upTrace.Pop(), axis); if (current.Children != null) { current = current.Children[target]; } else { current = null; } } if (!patchCodes.ContainsKey(node.Code)) { patchCodes[node.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[node.Code][index] = code; return(true); } upTrace.Push((byte)current.ChildNum); current = current.Parent; } return(false); }
private void TraceLeaf(PureQuadTreeNode leaf) { // decide which directions to look at switch (leaf.ChildNum) { case 0: if (TraceNode(leaf, true, 0)) { leafPatches[leaf.Code] = (byte)Directions.Left; if (TraceNode(leaf, false, 3)) { leafPatches[leaf.Code] |= (byte)Directions.Down; } } else if (TraceNode(leaf, false, 3)) { leafPatches[leaf.Code] = (byte)Directions.Down; } break; case 1: if (TraceNode(leaf, true, 1)) { leafPatches[leaf.Code] = (byte)Directions.Right; if (TraceNode(leaf, false, 3)) { leafPatches[leaf.Code] |= (byte)Directions.Down; } } else if (TraceNode(leaf, false, 3)) { leafPatches[leaf.Code] = (byte)Directions.Down; } break; case 2: if (TraceNode(leaf, true, 0)) { leafPatches[leaf.Code] = (byte)Directions.Left; if (TraceNode(leaf, false, 2)) { leafPatches[leaf.Code] |= (byte)Directions.Up; } } else if (TraceNode(leaf, false, 2)) { leafPatches[leaf.Code] = (byte)Directions.Up; } break; case 3: if (TraceNode(leaf, true, 1)) { leafPatches[leaf.Code] = (byte)Directions.Right; if (TraceNode(leaf, false, 2)) { leafPatches[leaf.Code] |= (byte)Directions.Up; } break; } else if (TraceNode(leaf, false, 2)) { leafPatches[leaf.Code] = (byte)Directions.Up; } break; } }
private void TestInternals(PureQuadTreeNode leaf) { if (leaf.ChildNum == 0) { if (leaf.Parent.Children[1].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][1] = leaf.Parent.Children[1].Code; } if (leaf.Parent.Children[2].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][2] = leaf.Parent.Children[2].Code; } } else if (leaf.ChildNum == 1) { if (leaf.Parent.Children[0].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][0] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][2] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 2) { if (leaf.Parent.Children[0].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][3] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][1] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 3) { if (leaf.Parent.Children[2].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][0] = leaf.Parent.Children[2].Code; } if (leaf.Parent.Children[1].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) { patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue } } ; patchCodes[leaf.Code][3] = leaf.Parent.Children[1].Code; } } }
private bool TraceNode(PureQuadTreeNode node, bool axis, ref ulong result) { PureQuadTreeNode current = node.Parent; // move upwards until we can switch over Stack <byte> upTrace = new Stack <byte>(); upTrace.Push((byte)node.ChildNum); while (current != null && current.Level > 0) { bool flip = false; if (axis) { if (node.ChildNum == 0 || node.ChildNum == 2) { if (current.ChildNum == 1 || current.ChildNum == 3) { flip = true; } } else if (node.ChildNum == 1 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 2) { flip = true; } } } else { if (node.ChildNum == 0 || node.ChildNum == 1) { if (current.ChildNum == 2 || current.ChildNum == 3) { flip = true; } } else if (node.ChildNum == 2 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 1) { flip = true; } } } if (flip) { // flip this and move down tree by slipping the stack until we hit and end //upTrace.Push((byte)current.ChildNum); int target = FlipNode(current.ChildNum, axis); current = current.Parent.Children[target]; ushort level = current.Level; ulong code = current.Code; while (current != null) { level = current.Level; code = current.Code; if (level == node.Level) { break; } if (level >= node.Level) { return(false); } target = FlipNode(upTrace.Pop(), axis); if (current.Children != null) { current = current.Children[target]; } else { current = null; } } result = code; return(true); } upTrace.Push((byte)current.ChildNum); current = current.Parent; } return(false); }
private byte TraceLeaf(PureQuadTreeNode leaf, out ulong[] codes) { byte result = 0; codes = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; // decide which directions to look at switch (leaf.ChildNum) { case 0: if (TraceNode(leaf, true, ref codes[0])) { result = (byte)Directions.Left; if (TraceNode(leaf, false, ref codes[3])) { result |= (byte)Directions.Down; } } else if (TraceNode(leaf, false, ref codes[3])) { result = (byte)Directions.Down; } break; case 1: if (TraceNode(leaf, true, ref codes[1])) { result = (byte)Directions.Right; if (TraceNode(leaf, false, ref codes[3])) { result |= (byte)Directions.Down; } } else if (TraceNode(leaf, false, ref codes[3])) { result = (byte)Directions.Down; } break; case 2: if (TraceNode(leaf, true, ref codes[0])) { result = (byte)Directions.Left; if (TraceNode(leaf, false, ref codes[2])) { result |= (byte)Directions.Up; } } else if (TraceNode(leaf, false, ref codes[2])) { result = (byte)Directions.Up; } break; case 3: if (TraceNode(leaf, true, ref codes[1])) { result = (byte)Directions.Right; if (TraceNode(leaf, false, ref codes[2])) { result |= (byte)Directions.Up; } break; } else if (TraceNode(leaf, false, ref codes[2])) { result = (byte)Directions.Up; } break; } return(result); }
private void DrawChildren(Graphics g, PureQuadTreeNode node) { if (node.Children != null) { float halfX = node.Size.X / 2; float halfY = node.Size.Y / 2; g.DrawLine(Pens.Black, node.Location.X + halfX, node.Location.Y, node.Location.X + halfX, node.Location.Y + node.Size.Y); g.DrawLine(Pens.Black, node.Location.X, node.Location.Y + halfY, node.Location.X + node.Size.X, node.Location.Y + halfY); for (int i = 0; i < 4; i++) { DrawChildren(g, node.Children[i]); } } else { using (Brush brush = new SolidBrush(Color.FromArgb(255, 0, 0, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y - 1); } string debug = "[" + node.Code + "]"; if (leafPatches.ContainsKey(node.Code)) { // draw right patches if ((leafPatches[node.Code] & (byte)Directions.Down) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } } //debug += "(D=" + patchCodes[node.Code][2] + ")"; } else if ((leafPatches[node.Code] & (byte)Directions.Up) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } } // += "(U=" + patchCodes[node.Code][3] + ")"; } else { if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } //debug += "(D=" + patchCodes[node.Code][2] + ")"; } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } //debug += "(U=" + patchCodes[node.Code][3] + ")"; } } if ((leafPatches[node.Code] & (byte)Directions.Left) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } else if ((leafPatches[node.Code] & (byte)Directions.Right) > 0) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 111, 49, 152))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } else { if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } /*if (patchCodes[node.Code][0] != ulong.MaxValue) debug += "L(" + patchCodes[node.Code][0] + ")"; if (patchCodes[node.Code][1] != ulong.MaxValue) debug += "R(" + patchCodes[node.Code][1] + ")";*/ if (patchCodes[node.Code][2] != ulong.MaxValue) debug += "D(" + patchCodes[node.Code][2] + ")"; if (patchCodes[node.Code][3] != ulong.MaxValue) debug += "U(" + patchCodes[node.Code][3] + ")"; /*if (patchCodes[node.Code][1] != 14) g.DrawString(patchCodes[node.Code][0] + "," + patchCodes[node.Code][1], Font, Brushes.Red, (int)node.Location.X, (int)node.Location.Y); else g.DrawString(patchCodes[node.Code][0].ToString(), Font, Brushes.Red, (int)node.Location.X, (int)node.Location.Y);*/ } else if (patchCodes.ContainsKey(node.Code)) { // just internal patches if (patchCodes[node.Code][2] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + node.Size.Y - (node.Size.Y / 8), node.Size.X - 1, node.Size.Y / 8); } } if (patchCodes[node.Code][3] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X - 1, node.Size.Y / 8); } } if (patchCodes[node.Code][1] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + node.Size.X - (node.Size.X / 8), node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } if (patchCodes[node.Code][0] != ulong.MaxValue) { using (Brush brush = new SolidBrush(Color.FromArgb(255, 64, 49, 96))) { g.FillRectangle(brush, node.Location.X + 1, node.Location.Y + 1, node.Size.X / 8, node.Size.Y - 1); } } } Font font = new Font("Verdana", 6); g.DrawString(debug, font, Brushes.Orange, (int)node.Location.X, (int)node.Location.Y); } }
private void BuildNode(PureQuadTreeNode node) { float levelFalloff = falloff / node.Level; // first establish if visible or not by testing centre of node, then corners until visible bool visible = (node.Level == 0 || TestPoint(node.Centre) || TestPoint(node.Location) || TestPoint(new Vector2(node.Location.X + node.Size.X, node.Location.Y)) || TestPoint(new Vector2(node.Location.X, node.Location.Y + node.Size.Y)) || TestPoint(new Vector2(node.Location.X + node.Size.X, node.Location.Y + node.Size.Y))); // log what detail the leaf is to be, and if visible if (visible) leafDetail[node.Code] = (short)node.Level; else leafDetail[node.Code] = (short)-node.Level; if (visible) { // decide if to fork or not //Vector2 halfChildSize = node.Size * 0.25f; float distance = (node.Centre - viewPos).Length(); // test this node first directly if (distance < levelFalloff) { node.Fork(1, false); for (int c = 0; c < 4; c++) { BuildNode(node.Children[c]); } } } //else //{ // // test children directly // for (int i = 0; i < 4; i++) // { // // check centre distance // Vector2 centre = new Vector2(); // switch (i) // { // case 2: // centre = new Vector2(node.Location.X + halfChildSize.X, node.Location.Y + halfChildSize.Y); // break; // case 3: // centre = new Vector2(node.Location.X + (halfChildSize.X * 3), node.Location.Y + halfChildSize.Y); // break; // case 0: // centre = new Vector2(node.Location.X + halfChildSize.X, node.Location.Y + (halfChildSize.Y * 3)); // break; // case 1: // centre = new Vector2(node.Location.X + (halfChildSize.X * 3), node.Location.Y + (halfChildSize.Y * 3)); // break; // } // float distance = (centre - viewPos).Length(); // if (distance < levelFalloff) // { // if (node.Children == null) // { // node.Fork(1, false); // for (int c = 0; c < 4; c++) // { // BuildNode(node.Children[c]); // } // } // } // else // { // // check visibility // bool visible = false; // //if (distance < falloff) // //{ // float value = viewFOVpl1.Dot(new Vector3(node.Centre.X, 0, node.Centre.Y)); // if (value > 0) // { // //if (viewFOVpl2.Dot(new Vector3(node.Centre.X, 0, node.Centre.Y)) < 0) // visible = true; // } // //} // // log what detail the leaf is to be, and if visible // if (visible) // leafDetail[node.Code] = (short)node.Level; // else // leafDetail[node.Code] = (short)-node.Level; // } // } //} }
private bool TraceNode(PureQuadTreeNode node, bool axis, int index) { PureQuadTreeNode current = node.Parent; // move upwards until we can switch over Stack<byte> upTrace = new Stack<byte>(); upTrace.Push((byte)node.ChildNum); while (current != null && current.Level > 0) { bool flip = false; if (axis) { if (node.ChildNum == 0 || node.ChildNum == 2) { if (current.ChildNum == 1 || current.ChildNum == 3) flip = true; } else if (node.ChildNum == 1 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 2) flip = true; } } else { if (node.ChildNum == 0 || node.ChildNum == 1) { if (current.ChildNum == 2 || current.ChildNum == 3) flip = true; } else if (node.ChildNum == 2 || node.ChildNum == 3) { if (current.ChildNum == 0 || current.ChildNum == 1) flip = true; } } if (flip) { // flip this and move down tree by slipping the stack until we hit and end //upTrace.Push((byte)current.ChildNum); int target = FlipNode(current.ChildNum, axis); current = current.Parent.Children[target]; ushort level = current.Level; ulong code = current.Code; while (current != null) { level = current.Level; code = current.Code; if (level == node.Level) break; if (level >= node.Level) return false; /*if (upTrace.Count == 0) break;*/ target = FlipNode(upTrace.Pop(), axis); if (current.Children != null) current = current.Children[target]; else current = null; } if (!patchCodes.ContainsKey(node.Code)) patchCodes[node.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[node.Code][index] = code; return true; } upTrace.Push((byte)current.ChildNum); current = current.Parent; } return false; }
private void TraceLeaf(PureQuadTreeNode leaf) { // decide which directions to look at switch (leaf.ChildNum) { case 0: if (TraceNode(leaf, true, 0)) { leafPatches[leaf.Code] = (byte)Directions.Left; if (TraceNode(leaf, false, 3)) leafPatches[leaf.Code] |= (byte)Directions.Down; } else if (TraceNode(leaf, false, 3)) leafPatches[leaf.Code] = (byte)Directions.Down; break; case 1: if (TraceNode(leaf, true, 1)) { leafPatches[leaf.Code] = (byte)Directions.Right; if (TraceNode(leaf, false, 3)) leafPatches[leaf.Code] |= (byte)Directions.Down; } else if (TraceNode(leaf, false, 3)) leafPatches[leaf.Code] = (byte)Directions.Down; break; case 2: if (TraceNode(leaf, true, 0)) { leafPatches[leaf.Code] = (byte)Directions.Left; if (TraceNode(leaf, false, 2)) leafPatches[leaf.Code] |= (byte)Directions.Up; } else if (TraceNode(leaf, false, 2)) leafPatches[leaf.Code] = (byte)Directions.Up; break; case 3: if (TraceNode(leaf, true, 1)) { leafPatches[leaf.Code] = (byte)Directions.Right; if (TraceNode(leaf, false, 2)) leafPatches[leaf.Code] |= (byte)Directions.Up; break; } else if (TraceNode(leaf, false, 2)) leafPatches[leaf.Code] = (byte)Directions.Up; break; } }
private void TestInternals(PureQuadTreeNode leaf) { if (leaf.ChildNum == 0) { if (leaf.Parent.Children[1].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][1] = leaf.Parent.Children[1].Code; } if (leaf.Parent.Children[2].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][2] = leaf.Parent.Children[2].Code; } } else if (leaf.ChildNum == 1) { if (leaf.Parent.Children[0].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][0] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][2] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 2) { if (leaf.Parent.Children[0].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][3] = leaf.Parent.Children[0].Code; } if (leaf.Parent.Children[3].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][1] = leaf.Parent.Children[3].Code; } } else if (leaf.ChildNum == 3) { if (leaf.Parent.Children[2].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][0] = leaf.Parent.Children[2].Code; } if (leaf.Parent.Children[1].Children == null) { if (!patchCodes.ContainsKey(leaf.Code)) patchCodes[leaf.Code] = new ulong[] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }; patchCodes[leaf.Code][3] = leaf.Parent.Children[1].Code; } } }