public void Reset() { FreeThread(); m_KdTree = null; m_KdQuery = null; m_KdTreeStatus = KdTreeStatus.None; if (m_KdTreeObjList != null) { m_KdTreeObjList.Clear(); } if (m_TempHash != null) { m_TempHash.Clear(); } if (m_LastVisibleHash != null) { m_LastVisibleHash.Clear(); } if (m_ChgVisibleQueue != null) { ClearVisibleQueue(ref m_ChgVisibleQueue); } m_VisibleQueueStatus = VisibleQueueStatus.WaitQuery; m_KdCamInfo = new KdCameraInfo(); m_VisibleCount = 0; m_KdTreeVisible = 0; }
private List <Star> RegionQuery(KDTree.KDTree <Star> tree, Vector3 position, float Eps) { var pIter = tree.NearestNeighbors(new double[3] { position.x, position.y, position.z }, MinimumNeighboursAmount, Eps); return(pIter.ToList()); }
public List <Star> GetClusteredStars(List <Star> input) { inputStarsNodes = input; var tree = new KDTree.KDTree <Star>(3); input.ForEach(p => tree.AddPoint(new double[3] { p.Position.x, p.Position.y, p.Position.z }, p)); int clusterCounter = 0; foreach (var star in inputStarsNodes) { //If we already processed this star, skip it if (star.Visited) { continue; } star.Visited = true; //Todo: will the visited.false stuff be carried over? var neighbours = RegionQuery(tree, star.Position, Epsilon); //If not enough neighbours, label as noise and continue. if (neighbours.Count < MinimumNeighboursAmount) { star.IsNoise = true; } else { //Else, start new cluster. clusterCounter++; star.ClusterNumber = clusterCounter; //Expanding the new cluster var seedSet = neighbours; while (seedSet.Count > 0) { var currentSeedPoint = seedSet[0]; if (currentSeedPoint.Visited == false) { currentSeedPoint.Visited = true; var seedStarsNeighbours = RegionQuery(tree, currentSeedPoint.Position, Epsilon); if (seedStarsNeighbours.Count >= MinimumNeighboursAmount) { seedSet.AddRange(seedStarsNeighbours); } if (currentSeedPoint.ClusterNumber == Star.UNASSIGNED_CLUSTER_NO) { currentSeedPoint.ClusterNumber = clusterCounter; } } //Doing this to avoid infinite loop seedSet.Remove(currentSeedPoint); } } } return(inputStarsNodes.Where(s => s.IsNoise == false).ToList()); }
// 进入场景只Build一次,一个场景Build一次,频率还好, 内部代码有GC public void Build(bool isUseThread = true) { Reset(); if (m_Clipper != null) { int cnt = m_Clipper.ObjectsCount; if (cnt <= 0) { return; } Action <Vector3[]> action = (Vector3[] arr) => { int idx = 0; bool isSet = false; if (m_KdTreeObjList == null) { m_KdTreeObjList = new List <KdTreeObj>(m_Clipper.ObjectsCount); } else { m_KdTreeObjList.Clear(); m_KdTreeObjList.Capacity = m_Clipper.ObjectsCount; } m_Clipper.ForEachObjects( (Renderer render) => { Vector3 pos = render.transform.position; arr[idx] = pos; ++idx; isSet = true; BoundingSphere boundingSpere = KdTreeCameraClipper.GetBoundingSphere(render); KdTreeObj obj = new KdTreeObj(); obj.InstanceId = render.GetInstanceID(); obj.boundSphere = boundingSpere; m_KdTreeObjList.Add(obj); } ); if (isSet) { m_KdTree = new KDTree.KDTree(arr, 32, false); m_KdTreeStatus = KdTreeStatus.WaitRebuild; m_UseThread = isUseThread; UpdateClipper(); CreateThread(); } }; if (m_VecArr == null) { m_VecArr = new Vector3[cnt]; action(m_VecArr); } else if (cnt > m_VecArr.Length) { Array.Resize(ref m_VecArr, cnt); action(m_VecArr); } else { UnsafeUtil.Vector3HackArraySizeCall(m_VecArr, cnt, action); } } }