예제 #1
0
        //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));
        }
예제 #2
0
 public bool IsCombinable(QuadTreeLeaf other)
 {
     if (other != null && Slices != null && other.Slices != null &&
         Slices.Length == other.Slices.Length)
     {
         return(true);
     }
     return(false);
 }
예제 #3
0
 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);
 }
예제 #4
0
        //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);
        }
예제 #5
0
        //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);
                }
            }
        }
예제 #6
0
 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);
         }
     }
 }
예제 #7
0
 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);
 }
예제 #8
0
        //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;
                }
            }
        }
예제 #9
0
        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);
                    }
                }
            }
        }
예제 #10
0
        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);
        }
예제 #11
0
        private void SubdividLeaf(int idx)
        {
            QuadTreeLeaf leaf = (QuadTreeLeaf)Children[idx];

            Children[idx] = SubdivideLeaf(leaf);
        }