//x ~ (0, setting.maxX * power(2, subdivision)), z ~ (0, setting.maxZ * power(2, subdivision)) public MPPathNode GetStandablePathNode(int u, int v, ushort refH) { float centerx = 0; float centerz = 0; int subdivision = setting.subdivision; QuadTreeLeaf leaf = GetLeaf(u, v, ref centerx, ref centerz, ref subdivision); if (leaf == null || leaf.Slices == null) { return(null); } for (uint i = (uint)leaf.Slices.Length - 1; i > 0; --i) { ulong currentSlice = leaf.Slices[i]; byte currentf = SliceAccessor.flag(currentSlice); ushort currentheight = SliceAccessor.heightGrade(currentSlice); ulong lowerSlice = leaf.Slices[i - 1]; ushort lowerf = SliceAccessor.flag(lowerSlice); ushort lowerheight = SliceAccessor.heightGrade(lowerSlice); if ((currentf & SliceAccessor.SliceCeiling) > 0) { continue; } if (refH >= currentheight || ((lowerf & SliceAccessor.SliceCeiling) > 0 && refH >= lowerheight)) {//pillar roof return(MPPathNodePool.Pop(leaf.Header, u, v, i, subdivision, setting.subdivision, centerx, centerz, currentSlice)); } } ulong floorSlice = leaf.Slices[0]; return(MPPathNodePool.Pop(leaf.Header, u, v, 0, subdivision, setting.subdivision, centerx, centerz, floorSlice)); }
public bool IsCombinable(QuadTreeLeaf other) { if (other != null && Slices != null && other.Slices != null && Slices.Length == other.Slices.Length) { return(true); } return(false); }
public override bool IsEqual(QuadTreeBase other) { if (Slices != null && other is QuadTreeLeaf) { QuadTreeLeaf otherLeaf = (QuadTreeLeaf)other; if (otherLeaf.Slices != null && HashVal == otherLeaf.HashVal) { return(true); } } return(false); }
//note : this function can't be used to subdivide inherented node public static QuadTreeNode SubdivideLeaf(QuadTreeLeaf leaf) { if (leaf == null) { return(null); } QuadTreeNode node = new QuadTreeNode(0); for (int i = 0; i < 4; ++i) { QuadTreeLeaf childLeaf = (QuadTreeLeaf)node.Children[i]; childLeaf.Reset(leaf.Slices.Length, leaf.HashVal); Array.Copy(leaf.Slices, childLeaf.Slices, leaf.Slices.Length); } HeightSlicePool.Push(leaf.Header, leaf.Slices); return(node); }
//dynamically add pillars in //x ~ (0, setting.maxX * power(2, subdivision)), x ~ (0, setting.maxZ * power(2, subdivision)) public void AddPillar(int subdivision, int x, int z, OrderedSlices rawSlices) { //first grade int u = x >> subdivision; // x / power(2, subdivision); int v = z >> subdivision; int subx = x - u * (1 << subdivision); int subz = z - v * (1 << subdivision); --subdivision; int idx = (subx >> subdivision) * 2 + (subz >> subdivision); if (subdivision > 0) { if (Children[idx] is QuadTreeLeaf) { SubdividLeaf(idx); } QuadTreeNode node = (QuadTreeNode)Children[idx]; node.AddPillar(subdivision, subx, subz, rawSlices); } else { if (Children[idx] is QuadTreeNode) { MPLog.LogError("AddPillar leaf still a tree : " + subdivision); return; } QuadTreeLeaf leaf = (QuadTreeLeaf)Children[idx]; if (leaf.Slices != null) { HeightSlicePool.Push(leaf.Header, leaf.Slices); } leaf.Reset(rawSlices.Count, rawSlices.HashValue); for (int i = 0; i < rawSlices.Count; ++i) { leaf.Slices[i] = SliceAccessor.packVal(rawSlices[i].heightGrade, 0, 0, rawSlices[i].flag); } } }
private void GetNodeDisplaySlice(QuadTreeBase subtree, float startx, float startz, int x, int z, float sizex, float sizez, List <DisplaySlice> lSlices) { //first grade if (subtree is QuadTreeLeaf) { QuadTreeLeaf leaf = (QuadTreeLeaf)subtree; GetLeafDisplaySlice(leaf.Slices, startx, startz, sizex, sizez, x, z, lSlices); } else {//sub tree node QuadTreeNode node = (QuadTreeNode)subtree; startx += sizex * x; startz += sizez * z; for (int i = 0; i < 4; ++i) { int subx = i >> 1; int subz = i & 0x00000001; GetNodeDisplaySlice(node.Children[i], startx, startz, subx, subz, sizex * 0.5f, sizez * 0.5f, lSlices); } } }
public static QuadTreeLeaf CombineTree(QuadTreeNode node, float dx, float dz, float sliceThickness, float slopeErr) { if (node == null) { return(null); } for (int i = 0; i < 4; ++i) { if (node.Children[i] is QuadTreeNode) { QuadTreeNode subNode = (QuadTreeNode)node.Children[i]; QuadTreeLeaf replacedLeaf = CombineTree(subNode, 0.5f * dx, 0.5f * dz, sliceThickness, slopeErr); if (replacedLeaf != null) { node.Children[i] = replacedLeaf; } } } if (node.isFullLeaf) { return(node.Combine(dx, dz, sliceThickness, slopeErr)); } return(null); }
//dynamic obstacles public void DynamicAddPillar(Vector3 pos, Bounds bnd) { Vector3 min = pos - bnd.extents; Vector3 max = pos + bnd.extents; int startU = 0, startV = 0, endU = mData.setting.maxX, endV = mData.setting.maxZ; TransformPos2UV(min, ref startU, ref startV); TransformPos2UV(max, ref endU, ref endV); Vector3 volumnMin = new Vector3(VolumeCenterX - 0.5f * mVolumeSizeX, VolumeFloor, VolumeCenterZ - 0.5f * mVolumeSizeZ); Vector3 checkHalfExtent = new Vector3(GridX / 2, VolumeHSliceT, GridZ / 2); mHeightScanner.Reset(checkHalfExtent); HashSet <uint> dirtyNodes = new HashSet <uint>(); OrderedSlices slices = new OrderedSlices(); int detailedSize = 1 << mData.setting.subdivision; for (int u = startU; u <= endU; ++u) { for (int v = startV; v <= endV; ++v) { int curXIdx = u >> mData.setting.subdivision; int curZIdx = v >> mData.setting.subdivision; QuadTreeBase subtree = mData.tree[curXIdx * mData.setting.maxZ + curZIdx]; QuadTreeNode node = null; if (subtree is QuadTreeLeaf) { QuadTreeLeaf leaf = (QuadTreeLeaf)subtree; node = QuadTreeNode.SubdivideLeaf(leaf); mData.tree[curXIdx * mData.setting.maxZ + curZIdx] = node; } else { node = (QuadTreeNode)subtree; } uint dirtyId = (uint)curXIdx; dirtyId = (dirtyId << 16) | (uint)curZIdx; if (!dirtyNodes.Contains(dirtyId)) { dirtyNodes.Add(dirtyId); } float fx = (float)(u + 0.5f) * mDetailGridX; float fz = (float)(v + 0.5f) * mDetailGridZ; Vector3 top = volumnMin + fx * Vector3.right + (VolumeCeiling + 10f * VolumeHSliceT) * Vector3.up + fz * Vector3.forward; slices.Clear(); mHeightScanner.RunScan(top, VolumeHSliceT, mData.setting.heightValRange, slices); node.AddPillar(mData.setting.subdivision, u, v, slices); } } //merge foreach (var dirtyId in dirtyNodes) { uint x = dirtyId >> 16; uint z = dirtyId & 0x0000ffff; int idx = (int)(x * mData.setting.maxZ + z); QuadTreeNode node = (QuadTreeNode)mData.tree[idx]; QuadTreeBase replaceLeaf = QuadTreeNode.CombineTree(node, 0.5f * GridX, 0.5f * GridZ, VolumeHSliceT, mData.setting.slopeErr); if (replaceLeaf != null) { mData.tree[idx] = replaceLeaf; } } }
private void GetPathNeighbour(ushort curH, ushort maxH, int u, int v, MPNeigbours neighbours) { float centerx = 0; float centerz = 0; int subdivision = setting.subdivision; QuadTreeLeaf leaf = GetLeaf(u, v, ref centerx, ref centerz, ref subdivision); if (leaf == null || leaf.Slices == null) { return; } //bigger subdivision may has the same slice structure, add only one if (neighbours.Contains(leaf.Header)) { return; } //each height slice could be a neighbour if (leaf.Slices.Length == 1) { ulong floorSlice = leaf.Slices[0]; ushort height = SliceAccessor.heightGrade(floorSlice); byte flag = SliceAccessor.flag(floorSlice); if (CanMove2Neighbour(setting, curH, maxH, height, ushort.MaxValue)) { neighbours.Add(leaf.Header, u, v, 0, subdivision, setting.subdivision, centerx, centerz, floorSlice); } } else { for (uint i = 0; i < leaf.Slices.Length - 1; ++i) { ulong currentSlice = leaf.Slices[i]; byte currentf = SliceAccessor.flag(currentSlice); ushort currentheight = SliceAccessor.heightGrade(currentSlice); ulong higherSlice = leaf.Slices[i + 1]; byte higherf = SliceAccessor.flag(higherSlice); ushort higherheight = SliceAccessor.heightGrade(higherSlice); if (i == leaf.Slices.Length - 2 && (higherf & SliceAccessor.SliceCeiling) == 0) {//pillar roof if (CanMove2Neighbour(setting, curH, maxH, higherheight, ushort.MaxValue)) { neighbours.Add(leaf.Header, u, v, i + 1, subdivision, setting.subdivision, centerx, centerz, higherSlice); } break; } if ((currentf & SliceAccessor.SliceCeiling) > 0) { continue; } ushort currentMaxH = ushort.MaxValue; if ((higherf & SliceAccessor.SliceCeiling) > 0) {//check standable float holeHeight = (higherheight - currentheight) * setting.heightPerGrade; if (holeHeight < setting.boundHeight) { continue; } currentMaxH = higherheight; } if (CanMove2Neighbour(setting, curH, maxH, currentheight, currentMaxH)) { neighbours.Add(leaf.Header, u, v, i, subdivision, setting.subdivision, centerx, centerz, currentSlice); } } } }
private QuadTreeLeaf Combine(float dx, float dz, float sliceThickness, float slopeErr) { if (Children[0] == null || !(Children[0] is QuadTreeLeaf)) { return(null); } QuadTreeLeaf leaf = (QuadTreeLeaf)Children[0]; for (int i = 1; i < Children.Length; ++i) { if (Children[i] == null || !(Children[i] is QuadTreeLeaf)) { return(null); } if (!leaf.IsCombinable((QuadTreeLeaf)Children[i])) { return(null); } } for (int s = 0; s < leaf.Slices.Length; ++s) { ulong leafS = leaf.Slices[s]; byte flag = SliceAccessor.flag(leafS); //x axis short slopeU = GetSlope(leafS, ((QuadTreeLeaf)Children[1]).Slices[s], dx, sliceThickness); short slopeU1 = GetSlope(((QuadTreeLeaf)Children[2]).Slices[s], ((QuadTreeLeaf)Children[3]).Slices[s], dx, sliceThickness); if ((slopeU != 0 && slopeU1 != 0 && Math.Abs(slopeU1 - slopeU) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } slopeU += slopeU1; slopeU /= 2; //z axis short slopeV = GetSlope(leafS, ((QuadTreeLeaf)Children[2]).Slices[s], dz, sliceThickness); short slopeV1 = GetSlope(((QuadTreeLeaf)Children[1]).Slices[s], ((QuadTreeLeaf)Children[3]).Slices[s], dz, sliceThickness); if ((slopeV != 0 && slopeV1 != 0 && Math.Abs(slopeV1 - slopeV) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } slopeV += slopeV1; slopeV /= 2; ushort updateH = 0; for (int i = 0; i < Children.Length; ++i) { QuadTreeLeaf l = (QuadTreeLeaf)Children[i]; ulong lS = l.Slices[s]; if (leaf.HashVal != l.HashVal) { byte f = SliceAccessor.flag(lS); short sU = SliceAccessor.slopeUGrade(lS); short sV = SliceAccessor.slopeVGrade(lS); //floor cant match ceiling if (flag != f) { return(null); } //slope error if ((sU != 0 && Math.Abs(sU - slopeU) > slopeErr * SliceAccessor.slopeMagnify) || (sV != 0 && Math.Abs(sV - slopeV) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } } updateH += SliceAccessor.heightGrade(lS); } updateH >>= 2;//average height leaf.Slices[s] = SliceAccessor.packVal(updateH, slopeU, slopeV, flag); } leaf.RefreshHash(); return(leaf); }
private void SubdividLeaf(int idx) { QuadTreeLeaf leaf = (QuadTreeLeaf)Children[idx]; Children[idx] = SubdivideLeaf(leaf); }