private void KDSearch() { KDTree <int> kd = new KDTree <int>(3); // clear neighbours and init tree int i = 0; foreach (BoidController bc in boids) { bc.neighbours.Clear(); kd.AddPoint(new double[3] { bc.transform.position.x, bc.transform.position.y, bc.transform.position.z }, i); i++; } // search foreach (BoidController bc in boids) { NearestNeighbour <int> neighbours = kd.NearestNeighbors(new double[3] { bc.transform.position.x, bc.transform.position.y, bc.transform.position.z }, n, r_c2); while (neighbours.MoveNext()) { int id = neighbours.Current; if (id != bc.id) { bc.neighbours.Add(boids[id]); } } } }
public static bool Add(KDRectangle Rectangle) { if (tree.Size == 0) { tree.AddPoint(new double[] { Rectangle.LeftTop.X, Rectangle.RightBottom.X, Rectangle.LeftTop.Y, Rectangle.RightBottom.Y }, Rectangle); return(true); } else { NearestNeighbour <KDRectangle> pIter = tree.NearestNeighbors(new double[] { Rectangle.LeftTop.X, Rectangle.RightBottom.X, Rectangle.LeftTop.Y, Rectangle.RightBottom.Y }, 10); while (pIter.MoveNext()) { KDRectangle overlaper = pIter.Current; if (doOverlap(Rectangle.LeftTop, Rectangle.RightBottom, overlaper.LeftTop, overlaper.RightBottom)) { Console.WriteLine(Rectangle.Name); Rectangle.Filled = true; return(false); } } tree.AddPoint(new double[] { Rectangle.LeftTop.X, Rectangle.RightBottom.X, Rectangle.LeftTop.Y, Rectangle.RightBottom.Y }, Rectangle); return(true); } }
/// <summary> /// removes a list of multiple objects from the point cloud by a distance /// </summary> /// <param name="pInputPoints">the list of removable point clouds</param> /// <param name="pRemoveDistance">the nearest neighbour search distance</param> /// <returns>the amount of points removed</returns> public int removePointcloudsFromPointCloud(List <PointCloud> pInputPoints, float pRemoveDistance) { Object parWork = new Object(); HashSet <Point> removeList = new HashSet <Point>(); //go through list // parallel Parallel.ForEach(pInputPoints, pcl => { Parallel.ForEach(pcl.pointcloud_hs, p => { NearestNeighbour <Point> nn = pointcloud_kd.NearestNeighbors(new double[] { p.point.X, p.point.Y, p.point.Z }, 10000, pRemoveDistance); while (nn.MoveNext()) { lock (parWork) removeList.Add(nn.Current); } }); }); //remove points from pointcloud int removecount = 0; foreach (Point p in removeList) { if (this.pointcloud_hs.Remove(p)) { removecount++; } } resetLazyLoadingObjectsAfterUpdate(); return(removecount); }
/// <summary> /// downsamples the pointcloud by using a downsample factor. Reduces amount of points in downsample factor distance to 1 /// </summary> /// <param name="pDownsampleFactor">the downsample factor, a distance in m</param> public void downsamplePointcloud(float pDownsampleFactor) { //new target cloud HashSet <Point> newHS = new HashSet <Point>(); //check all initial points foreach (Point p in pointcloud_hs) { //if not processed, add to new cloud, check neighbours and set them as processed; processed points dont get added to new pointcloud if (!p.processed) { newHS.Add(p); p.processed = true; //check for nearest neighbours, set them processed, so they dont get added to list NearestNeighbour <Point> nn = pointcloud_kd.NearestNeighbors(new double[] { p.point.X, p.point.Y, p.point.Z }, 10000, pDownsampleFactor); while (nn.MoveNext()) { if (!nn.Current.processed) { nn.Current.processed = true; } } } } //goes through the point list and set every point as unprocessed Parallel.ForEach(newHS, point => point.processed = false); //set downsampled cloud as new this.pointcloud_hs = newHS; //resets the objects so they represent the current data this.resetLazyLoadingObjectsAfterUpdate(); }
void Update() { if (Input.GetMouseButton(0)) { ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (groundPlane.Raycast(ray, out rayDistance)) { pos = ray.GetPoint(rayDistance); pIter = Collection.NearestNeighbors(new double[] { pos.x, pos.z }, MaxCount, Range); while (pIter.MoveNext()) { pIter.Current.Transform.localScale = Vector3.zero; } } } }
/// <summary> /// calculates an euclidean cluster extraction from the point cloud based on a euclidean distance. returns a list of point clouds /// </summary> /// <param name="pInputCloud">the combined point cloud</param> /// <param name="pConfig">the config object for the algorithms</param> /// <returns>a list of point clouds</returns> public static List <PointCloud> calculateEuclideanClusterExtraction(PointCloud pInputCloud, float pEuclideanExtractionRadius, CancellationToken pToken) { //update status Log.LogManager.updateAlgorithmStatus("Euclidean Cluster Extraction"); Log.LogManager.writeLogDebug("[EuclideanClusterExtraction] Extraction Radius: " + pEuclideanExtractionRadius); //creates the end list to be returned List <PointCloud> clusters = new List <PointCloud>(); foreach (Point p in pInputCloud.pointcloud_hs) { pToken.ThrowIfCancellationRequested(); //checks if point has been processed already, if yes, skip if (p.processed) { continue; } //create new queue Queue <Point> Q = new Queue <Point>(); //add point to queue Q.Enqueue(p); //result values HashSet <Point> resultCloud = new HashSet <Point>(); PointCloud resultCluster = new PointCloud(resultCloud); //while queue has points, check for neighbours and add them to queue as well, do as long there are neighbours while (Q.Count > 0) { pToken.ThrowIfCancellationRequested(); //remove point from queue and add to current cluster, point has been processed by doing that Point p2 = Q.Dequeue(); if (p2.processed) { continue; } resultCloud.Add(p2); p2.processed = true; //check all neighbour points, add them to queue if they havnt been processed yet double[] tp = { p2.point.X, p2.point.Y, p2.point.Z }; NearestNeighbour <Point> nb = lookForNeighbours(pInputCloud.pointcloud_kd, tp, pEuclideanExtractionRadius); while (nb.MoveNext()) { if (!nb.Current.processed) { Q.Enqueue(nb.Current); } } } clusters.Add(resultCluster); } //set all points as unprocessed, so they can be used for other algorithms Parallel.ForEach(clusters, pointcloud => Parallel.ForEach(pointcloud.pointcloud_hs, point => point.processed = false)); //updates the status Log.LogManager.updateAlgorithmStatus("Done"); //return return(clusters); }
/** * Similar to Merge vertices, expect that this method only collapses vertices within * a specified distance of one another (typically epsilon). Returns true if any action * was taken, false otherwise. Outputs indices that have been welded in the @welds var. */ public static bool WeldVertices(this pb_Object pb, int[] indices, float delta, out int[] welds) { List <int> universal = pb.sharedIndices.GetUniversalIndices(indices).ToList(); Vector3[] v = pb.vertices; HashSet <int> used = new HashSet <int>(); KDTree <int> tree = new KDTree <int>(3, 48); // dimensions (xyz), node size for (int i = 0; i < universal.Count; i++) { Vector3 vert = v[pb.sharedIndices[universal[i]][0]]; tree.AddPoint(new double[] { vert.x, vert.y, vert.z }, universal[i]); } List <List <int> > groups = new List <List <int> >(); double[] point = new double[3] { 0, 0, 0 }; int[][] si = pb.sharedIndices.ToArray(); for (int i = 0; i < universal.Count; i++) { if (used.Contains(universal[i])) { continue; } int tri = si[universal[i]][0]; point[0] = v[tri].x; point[1] = v[tri].y; point[2] = v[tri].z; NearestNeighbour <int> neighborIterator = tree.NearestNeighbors(point, 64, delta); List <int> neighbors = new List <int>(); while (neighborIterator.MoveNext()) { if (used.Contains(neighborIterator.Current)) { continue; } used.Add(neighborIterator.Current); neighbors.Add(neighborIterator.Current); } used.Add(universal[i]); groups.Add(neighbors); } pb_IntArray[] rebuilt = new pb_IntArray[groups.Count]; // + remainingCount ]; welds = new int[groups.Count]; for (int i = 0; i < groups.Count; i++) { rebuilt[i] = new pb_IntArray(groups[i].SelectMany(x => pb.sharedIndices[x].array).ToArray()); welds[i] = rebuilt[i][0]; } foreach (pb_IntArray arr in rebuilt) { Vector3 avg = pb_Math.Average(pbUtil.ValuesWithIndices(v, arr.array)); foreach (int i in arr.array) { v[i] = avg; } } pb.SetVertices(v); // profiler.EndSample(); pb_IntArray[] remaining = pb.sharedIndices.Where((val, index) => !used.Contains(index)).ToArray(); rebuilt = pbUtil.Concat(rebuilt, remaining); pb.SetSharedIndices(rebuilt); return(true); }