private OctreeBox(List <Point> pts, OctreeBox parent, int remainingNotLeafLayers, int positionInParent) { // I'm even more proud about this boundary finder :) for (int i = 2; i >= 0; i--) { int n = (int)System.Math.Pow(2, i); if (positionInParent >= n) { _dimensionsMax[i] = parent._dimensionsMax[i]; _dimensionsMin[i] = parent.Mean(i); positionInParent -= n; } else { _dimensionsMax[i] = parent.Mean(i); _dimensionsMin[i] = parent._dimensionsMin[i]; } } if (remainingNotLeafLayers == 0) { this.IsLeaf = true; this.SubBoxes = null; this.Points = pts; } else { // All points in pts MUST lie within this box! Subdivide(pts, remainingNotLeafLayers - 1); } }
//DOKU private List <OctreeBox> BoxesInRange(Point query, double squareRange, OctreeBox node) { List <OctreeBox> fittingSubBoxes = new List <OctreeBox>(); if (node.IsLeaf) { fittingSubBoxes.Add(node); } else { foreach (OctreeBox box in node.SubBoxes) { // skip nodes that are too far away if (box.MinimumSquareDistanceTo(query) > squareRange) { continue; } if (box.IsLeaf) { fittingSubBoxes.Add(box); } else { fittingSubBoxes.AddRange( BoxesInRange(query, squareRange, box)); } } } return(fittingSubBoxes); }
//DOKU private void TraverseSearch(Point query, OctreeBox node, NeigbourCollector neighbours) { if (node.IsLeaf) { foreach (Point p in node.Points) { neighbours.AddNeighbour(p); } return; } // not leaf foreach (OctreeBox subNode in node.SubBoxes) { double curMinSDist = subNode.MinimumSquareDistanceTo(query); //TODO that shit about the Neighbourlist count // is really, really crappy! if (neighbours.BestNeighbours.Count > 0 && curMinSDist > neighbours.LargestSquareDistance) { continue; } TraverseSearch(query, subNode, neighbours); } return; }
//DOKU public List <OctreeBox> GetLeafs(OctreeBox parent) { List <OctreeBox> leafs = new List <OctreeBox>(); if (parent.IsLeaf) { leafs.Add(parent); return(leafs); } foreach (OctreeBox child in parent.SubBoxes) { leafs.AddRange(GetLeafs(child)); } return(leafs); }
//DOKU private OctreeBox[] Subdivide(List <Point> pts, int remainingNoLeafLayers) { this.SubBoxes = new OctreeBox[8]; List <Point>[] subdividedPointCloud = new List <Point> [8]; // initialize array for (int i = 0; i < 8; i++) { subdividedPointCloud[i] = new List <Point>(); } foreach (Point p in pts) { // I'm proud of this simple method of assigning the point :-) int boxNumber = 0; if (p.Z > Zmean) { boxNumber += 4; } if (p.Y > Ymean) { boxNumber += 2; } if (p.X > Xmean) { boxNumber += 1; } subdividedPointCloud[boxNumber].Add(p); } // write divided points to subboxes for (int i = 0; i < 8; i++) { SubBoxes[i] = new OctreeBox(subdividedPointCloud[i], this, remainingNoLeafLayers, i); } // reset Points to null, for all points are now Points of the SubBoxes this.Points = null; this.IsLeaf = false; return(this.SubBoxes); }
//DOKU public Octree(Point[] pts, int nonLeafLayers, int maxPointsPerBox) { if (maxPointsPerBox == 0) { throw new ArgumentException( "An octree with the maximul leaf size 0 is impossible!"); } _rootNode = new OctreeBox(pts.ToList(), nonLeafLayers); // If there is no point cap, the tree is done here. if (maxPointsPerBox < 0) { return; } // Get all the leafs to decide if a subdivision is // necessary or not List <OctreeBox> leafs = GetLeafs(_rootNode); // Divide all leafs into smaller boxes. // If a box has too many points, add it to // the list of boxes that shall be divided. int i = 0; while (i < leafs.Count) { OctreeBox box = leafs[i]; if (box.Points.Count <= maxPointsPerBox) { i++; continue; } leafs.RemoveAt(i); leafs.AddRange(box.Subdivide()); } }