/* * Marks each exposed voxel as 1. */ public void MarkExternal(VoxelGrid voxelGrid) { for (int x = 1; x < xBound - 1; x++) { for (int y = 1; y < yBound - 1; y++) { for (int z = 1; z < zBound - 1; z++) { if (voxelGrid.coordinateGrid[x][y][z] && voxelGrid.HasEmptyNeighbor(x, y, z)) { grid[x][y][z] = 1; } } } } }
private void CreateStartGrid(VoxelGrid voxelGrid) { xBound = voxelGrid.xBound; yBound = voxelGrid.yBound; zBound = voxelGrid.zBound; grid = new int[xBound][][]; for (int i = 0; i < grid.Length; i++) { grid[i] = new int[yBound][]; for (int j = 0; j < grid[i].Length; j++) { grid[i][j] = new int[zBound]; } } }
/** * Pre processing for the skeletonizing. Removes the outer most layers. */ private static void ThinByDistanceMapping(DistanceGrid distanceGrid, VoxelGrid voxelGrid) { int outerLayersToRemove = Convert.ToInt32(voxelGrid.ComponentWiseResolutionDivider * outerLayerLimit); for (int x = 1; x < distanceGrid.xBound; x++) { for (int y = 1; y < distanceGrid.yBound; y++) { for (int z = 1; z < distanceGrid.zBound; z++) { if (distanceGrid.grid[x][y][z] <= outerLayersToRemove) { distanceGrid.grid[x][y][z] = 0; } } } } }
public override bool Equals(Object obj) { //Check for null and compare run-time types. if ((obj == null) || !this.GetType().Equals(obj.GetType())) { return(false); } else { VoxelGrid other = (VoxelGrid)obj; return(this.resolution == other.resolution && this.voxelStartCoordinate == other.voxelStartCoordinate && this.coordinateGrid.Length == other.coordinateGrid.Length && this.coordinateGrid[0].Length == other.coordinateGrid[0].Length && this.coordinateGrid[0][0].Length == other.coordinateGrid[0][0].Length && System.Linq.Enumerable.SequenceEqual(this.coordinateGrid, other.coordinateGrid)); } }
public bool Matches(VoxelGrid voxelGrid, int startX, int startY, int startZ) { bool shouldTestX = false; bool passedXTest = false; for (int x = 0; x <= 2; x++) { for (int y = 0; y <= 2; y++) { for (int z = 0; z <= 2; z++) { if (voxelGrid.coordinateGrid[startX - 1 + x][startY - 1 + y][startZ - 1 + z] /*is Black*/) { if (pointMask[x][y][z] == PointType.WHITE) { return(false); } if (pointMask[x][y][z] == PointType.X) { passedXTest = true; } } else /*is White*/ { if (pointMask[x][y][z] == PointType.BLACK) { return(false); } if (pointMask[x][y][z] == PointType.X) { shouldTestX = true; } } } } } return(!shouldTestX || passedXTest); }
/* * Creates a DistanceGrid based on a VoxelGrid */ public DistanceGrid(VoxelGrid voxelGrid) { CreateStartGrid(voxelGrid); MarkExternal(voxelGrid); MarkInternal(voxelGrid); }
/** * Generates a NodeGraph from a skeletonized voxelgrid, by traversing neighboring * voxels and creating nodes connected by edges to maintain the topology of the voxelgrid. */ private static NodeGraph CreateNodeGraph(DistanceGrid distanceGrid, VoxelGrid voxelGrid) { bool[][][] visitedGrid = new bool[distanceGrid.xBound + 1][][]; for (int i = 0; i < visitedGrid.Length; i++) { visitedGrid[i] = new bool[distanceGrid.yBound + 1][]; for (int j = 0; j < visitedGrid[i].Length; j++) { visitedGrid[i][j] = new bool[distanceGrid.zBound + 1]; } } NodeGraph nodeGraph = new NodeGraph(); Queue <(Point3, Point3)> startPoints = GetStartPoints(distanceGrid); Point3 initialPoint = startPoints.Peek().Item1; nodeGraph.AddNode(voxelGrid.LowestPositionAtCoordinate(initialPoint)); visitedGrid[initialPoint.x][initialPoint.y][initialPoint.z] = true; //Breadth-first traversing of the Voxels while (startPoints.Count > 0) { (Point3 startPoint, Point3 currentPoint) = startPoints.Dequeue(); //Special case for when connecting to an allready visited node if (visitedGrid[currentPoint.x][currentPoint.y][currentPoint.z]) { Vect3 pos1 = voxelGrid.LowestPositionAtCoordinate(startPoint); Vect3 pos2 = voxelGrid.LowestPositionAtCoordinate(currentPoint); Node startNode = nodeGraph.GetNode(pos1); Node currentNode = nodeGraph.GetNode(pos2); if (nodeGraph.GetNode(pos1) == null || nodeGraph.GetNode(pos2) == null) { continue; } bool shouldLink = true; foreach (var neighbor in currentNode.neighbors) { if (neighbor.nodeIndex == startNode.index) { shouldLink = false; } else { Node neighborNode = nodeGraph.GetNode(neighbor.nodeIndex); foreach (var nextNeighbor in neighborNode.neighbors) { if (nextNeighbor.nodeIndex == startNode.index) { shouldLink = false; } } } if (!shouldLink) { break; } } if (shouldLink) { nodeGraph.LinkNodes(pos1, pos2); } else { continue; } } Point3 cameFrom = startPoint; List <Point3> pathPoints = new List <Point3>() { startPoint }; Vect3 startCoordinate = voxelGrid.LowestPositionAtCoordinate(startPoint); Vect3 currentCoordinate = voxelGrid.LowestPositionAtCoordinate(currentPoint); List <Vect3> intermediateCoords = new List <Vect3>(); List <Point3> neighbors = new List <Point3>(); bool distanceWasValid = false; //Traversing untill the Nodeplacement would make the Edge to far away from the voxels it represents, //an already visited node is reached, an intersection is found or it's a dead end. while (DistancesAreValid(startCoordinate, currentCoordinate, intermediateCoords, voxelGrid.resolution)) { // Node we found was visited if (visitedGrid[currentPoint.x][currentPoint.y][currentPoint.z]) { // Ensures nothing happens after we break distanceWasValid = true; break; } neighbors = distanceGrid.Get26AdjacentNeighbors(currentPoint); pathPoints.Add(currentPoint); if (neighbors.Count != 2) { visitedGrid[currentPoint.x][currentPoint.y][currentPoint.z] = true; distanceWasValid = true; break; } // Only one new neighbor intermediateCoords.Add(voxelGrid.LowestPositionAtCoordinate(currentPoint)); Point3 temp = currentPoint; currentPoint = neighbors[0] == cameFrom ? neighbors[1] : neighbors[0]; currentCoordinate = voxelGrid.LowestPositionAtCoordinate(currentPoint); cameFrom = temp; visitedGrid[cameFrom.x][cameFrom.y][cameFrom.z] = true; } double maxDistanceValue = 0; foreach (var point in pathPoints) { maxDistanceValue += distanceGrid.grid[point.x][point.y][point.z] * voxelGrid.resolution * SquareRootOfThree; // Distance is 26-distance from edge // double distanceValue = distanceGrid.grid[point.x][point.y][point.z]*voxelGrid.resolution*2; // maxDistanceValue = distanceValue > maxDistanceValue ? distanceValue : maxDistanceValue; } maxDistanceValue /= (double)pathPoints.Count; double minWidth = maxDistanceValue; double minHeight = maxDistanceValue; if (!distanceWasValid) { nodeGraph.AddNode(intermediateCoords[intermediateCoords.Count - 1], minWidth, minHeight, nodeGraph.GetNode(startCoordinate).index); visitedGrid[cameFrom.x][cameFrom.y][cameFrom.z] = true; if (!visitedGrid[currentPoint.x][currentPoint.y][currentPoint.z]) { startPoints.Enqueue((cameFrom, currentPoint)); } } else { nodeGraph.AddNode(currentCoordinate, minWidth, minHeight, nodeGraph.GetNode(startCoordinate).index); foreach (var neighbor in neighbors) { if (neighbor == cameFrom || visitedGrid[neighbor.x][neighbor.y][neighbor.z]) { continue; } startPoints.Enqueue((currentPoint, neighbor)); } } } return(nodeGraph); }
public static void Skeletonize(DistanceGrid distanceGrid, VoxelGrid voxelGrid) { ThinByDistanceMapping(distanceGrid, voxelGrid); ThinToSkeleton(distanceGrid); }