private KDTreeNode _Recur_Build(Vector3[] pts, int from, int cnt, int depth)
        {
            if (cnt <= 0)
            {
                return(null);
            }

            int axis = depth % 3;

            _SortPoints(pts, from, cnt, axis);
            Vector3 median = pts[from + cnt / 2];

            KDTreeNode newNode = _MakeNode(median);

            newNode.left  = _Recur_Build(pts, from, cnt / 2, depth + 1);
            newNode.right = _Recur_Build(pts, from + cnt / 2 + 1, cnt - cnt / 2 - 1, depth + 1);

            if (newNode.left != null)
            {
                newNode.left.parent = newNode;
            }
            if (newNode.right != null)
            {
                newNode.right.parent = newNode;
            }

            return(newNode);
        }
        private KDTreeNode _MakeNode(Vector3 median)
        {
            var node = new KDTreeNode();

            node.pos = median;
            return(node);
        }
        private int _Recur_Serialize(KDTreeNode nd)
        {
            KDTreeSerial s = new KDTreeSerial();

            if (nd.left != null)
            {
                s.leftIdx = _Recur_Serialize(nd.left);
            }
            if (nd.right != null)
            {
                s.rightIdx = _Recur_Serialize(nd.right);
            }

            s.pos = nd.pos;
            m_serials.Add(s);
            int curId = m_serials.Count - 1;

            if (s.leftIdx >= 0)
            {
                m_serials[s.leftIdx].parentIdx = curId;
            }
            if (s.rightIdx >= 0)
            {
                m_serials[s.rightIdx].parentIdx = curId;
            }

            return(curId);
        }
        public void OnAfterDeserialize()
        {
            if (m_serials == null || m_serials.Count == 0)
            {
                return;
            }

            List <KDTreeNode> nodes = new List <KDTreeNode>();

            for (int i = 0; i < m_serials.Count; ++i)
            { //populate all KDTreeNode first
                KDTreeSerial s    = m_serials[i];
                KDTreeNode   node = new KDTreeNode();
                node.pos = s.pos;
                nodes.Add(node);
            }
            for (int i = 0; i < nodes.Count; ++i)
            { //recover the links
                int l = m_serials[i].leftIdx;
                nodes[i].left = l >= 0 ? nodes[l] : null;
                int r = m_serials[i].rightIdx;
                nodes[i].right = r >= 0 ? nodes[r] : null;
                int p = m_serials[i].parentIdx;
                nodes[i].parent = p >= 0 ? nodes[p] : null;
            }

            m_rootNode = nodes[nodes.Count - 1]; //post-order serialization
        }
        private void _Recur_CheckNearestDownward(Vector3 pt, KDTreeNode nd, ref float minDistSqr, ref KDTreeNode nearest, int depth)
        {
            //check nearest
            float sqr = (pt - nd.pos).sqrMagnitude;

            if (sqr < minDistSqr)
            {
                minDistSqr = sqr;
                nearest    = nd;
            }
            //++m_visitNodeCnt;

            int   axis = depth % 3;
            float ptv  = pt[axis];
            float ndv  = nd.pos[axis];

            float sqr_ptv_ndv = (ptv - ndv) * (ptv - ndv);

            if (nd.left != null && (ptv < ndv || sqr_ptv_ndv < minDistSqr))
            {
                _Recur_CheckNearestDownward(pt, nd.left, ref minDistSqr, ref nearest, depth + 1);
            }
            if (nd.right != null && (ptv > ndv || sqr_ptv_ndv < minDistSqr))
            {
                _Recur_CheckNearestDownward(pt, nd.right, ref minDistSqr, ref nearest, depth + 1);
            }
        }
        /// <summary>
        /// find the point nearest to 'pt'
        /// </summary>
        //public int m_visitNodeCnt = 0; //used to evaluate kdtree's GetNearest perf
        public Vector3 GetNearest(Vector3 pt)
        {
            //m_visitNodeCnt = 0;
            int        depth      = 0;
            float      minDistSqr = float.MaxValue;
            KDTreeNode nearest    = m_rootNode;
            KDTreeNode curNode    = _Recur_FindLeafNode(pt, m_rootNode, ref minDistSqr, ref nearest, ref depth);

            _Recur_GetNearest(pt, curNode, ref minDistSqr, ref nearest, depth);

            //Dbg.Log("m_visitNodeCnt = {0}", m_visitNodeCnt);

            return(nearest.pos);
        }
        private KDTreeNode _NeedCheckOtherSide(Vector3 pt, KDTreeNode nd, float minDistSqr, int depth)
        {
            if (nd == null)
            {
                return(null);
            }

            int     axis  = depth % 3;
            Vector3 ndPos = nd.pos;

            if ((pt[axis] - ndPos[axis]) * (pt[axis] - ndPos[axis]) > minDistSqr)
            {
                return(null); //not crossing the separating plane, return false
            }
            if (pt[axis] < ndPos[axis])
            {
                return(nd.right);
            }
            else
            {
                return(nd.left);
            }
        }
        private void _Recur_GetNearest(Vector3 pt, KDTreeNode nd, ref float minDistSqr, ref KDTreeNode nearest, int depth)
        {
            //check nearest
            while (nd != null)
            {
                float sqr = (pt - nd.pos).sqrMagnitude;
                if (sqr < minDistSqr)
                {
                    minDistSqr = sqr;
                    nearest    = nd;
                }
                //++m_visitNodeCnt;

                KDTreeNode otherSideNode = _NeedCheckOtherSide(pt, nd.parent, minDistSqr, depth - 1);
                if (otherSideNode != null)
                {
                    _Recur_CheckNearestDownward(pt, nd.parent, ref minDistSqr, ref nearest, depth - 1);
                }

                nd = nd.parent;
                --depth;
            }
        }
        private KDTreeNode _Recur_FindLeafNode(Vector3 pt, KDTreeNode nd, ref float minDistSqr, ref KDTreeNode nearest, ref int depth)
        {
            KDTreeNode nextNd = null;

            while (true)
            {
                //m_visitNodeCnt++;
                int axis = depth % 3;

                float sqr = (pt - nd.pos).sqrMagnitude;
                if (sqr < minDistSqr)
                {
                    minDistSqr = sqr;
                    nearest    = nd;
                }

                if (pt[axis] < nd.pos[axis])
                {
                    nextNd = nd.left;
                }
                else
                {
                    nextNd = nd.right;
                }

                if (nextNd == null)
                {
                    return(nd);
                }
                else
                {
                    nd = nextNd;
                }

                ++depth;
            }
        }
Exemple #10
0
 public void Build(Vector3[] lst)
 {
     m_rootNode = _Recur_Build(lst, 0, lst.Length, 0);
 }
Exemple #11
0
 public void Invalidate()
 {
     m_serials.Clear();
     m_rootNode = null;
 }