public VoxelGrid(Component component, Vect3 plane1Normal = null, Vect3 plane2Normal = null, Vect3 plane3Normal = null) { orientedBbox = new OrientedBBox(component, plane1Normal, plane2Normal, plane3Normal); componentOBBs[component.index] = orientedBbox; SetupVoxelGrid(); this.CreateShellFromFaces(component); }
public VoxelGrid(Structure structure, Vect3 plane1Normal = null, Vect3 plane2Normal = null, Vect3 plane3Normal = null) { orientedBbox = new OrientedBBox(structure, plane1Normal, plane2Normal, plane3Normal); SetupVoxelGrid(structure); foreach (Component component in structure.components) { CreateShellFromFaces(component); } }
/* * Fills internal volume of voxels by finding points in the voxel grid captured * by a mesh. Relies on the original meshes to perform odd/even polygon capture calculation. * * https://en.wikipedia.org/wiki/Point_in_polygon */ public void FillInternalVolume(Component component) { OrientedBBox componentOBB = componentOBBs[component.index]; List <Vect3> points = new List <Vect3>(); foreach (var vertex in component.vertices) { points.Add(vertex.coordinate); } VoxelSpan componentVoxelSpan = new VoxelSpan(points, this, BorderOffset); for (int x = componentVoxelSpan.minX; x < componentVoxelSpan.maxX; x++) { for (int z = componentVoxelSpan.minZ; z < componentVoxelSpan.maxZ; z++) { for (int y = componentVoxelSpan.minY; y < componentVoxelSpan.maxY; y++) { if (!coordinateGrid[x][y][z] && coordinateGrid[x][Math.Max(0, y - 1)][z]) { Vect3 globalPos = voxelStartCoordinate + orientedBbox.localX * x * resolution + orientedBbox.localY * y * resolution + orientedBbox.localZ * z * resolution; if (!componentOBB.ContainsGlobalCoordinate(globalPos, OrientedBBoxExpansionFactor)) { continue; } int intersects = 0; foreach (Face face in component.faces) { Vect3 triA = component.GetCoordinate(face.vertexIndices[0]); Vect3 triB = component.GetCoordinate(face.vertexIndices[1]); Vect3 triC = component.GetCoordinate(face.vertexIndices[2]); // if (intersect_triangle(globalPos, Vect3.Up, triA, triB, triC)) if (rayIntersectsTriangle(globalPos, Vect3.Up, triA, triB, triC)) { intersects++; } } if ((intersects % 2) != 0) { int rise = 0; while (!coordinateGrid[x][y + rise][z]) { coordinateGrid[x][y + rise][z] = true; rise++; } } else if (intersects == 0) { // If there is no intersecting surface above whatsoever, this column cannot // contain points that are inside a polygon. break; } } } } } }
private void SetupVoxelGrid(Structure structure = null) { ComponentWiseResolutionDivider = DefaultComponentWiseResolutionDivider; double rightLength; double heightLength; double depthLength; if (resolution == 0) { if (structure != null) { double shortestSide = 0; foreach (var component in structure.components) { OrientedBBox componentOBB = new OrientedBBox(component); rightLength = (componentOBB.localMaxX - componentOBB.localOrigin).Length(); heightLength = (componentOBB.localMaxY - componentOBB.localOrigin).Length(); depthLength = (componentOBB.localMaxZ - componentOBB.localOrigin).Length(); shortestSide += Math.Min(rightLength, Math.Min(heightLength, depthLength)); componentOBBs[component.index] = componentOBB; } shortestSide /= structure.components.Count; resolution = shortestSide / ComponentWiseResolutionDivider; } else { rightLength = (orientedBbox.localMaxX - orientedBbox.localOrigin).Length(); heightLength = (orientedBbox.localMaxY - orientedBbox.localOrigin).Length(); depthLength = (orientedBbox.localMaxZ - orientedBbox.localOrigin).Length(); double shortestSide = Math.Min(rightLength, Math.Min(heightLength, depthLength)); resolution = shortestSide / ComponentWiseResolutionDivider; } } halfResolution = resolution / 2d; rightLength = (orientedBbox.localMaxX - orientedBbox.localOrigin).Length(); heightLength = (orientedBbox.localMaxY - orientedBbox.localOrigin).Length(); depthLength = (orientedBbox.localMaxZ - orientedBbox.localOrigin).Length(); xBound = Convert.ToInt32(Math.Round(rightLength / resolution)) + 4 + 1; yBound = Convert.ToInt32(Math.Round(heightLength / resolution)) + 4 + 1; zBound = Convert.ToInt32(Math.Round(depthLength / resolution)) + 4 + 1; voxelStartCoordinate = orientedBbox.localOrigin - (orientedBbox.localX * 2d * resolution + orientedBbox.localY * 2d * resolution + orientedBbox.localZ * 2d * resolution); // Include offset to move start position to the first cube center. voxelMiddleStartCoordinate = orientedBbox.localOrigin - (orientedBbox.localX * 1.5d * resolution + orientedBbox.localY * 1.5d * resolution + orientedBbox.localZ * 1.5d * resolution); coordinateGrid = new bool[xBound][][]; for (int i = 0; i < coordinateGrid.Length; i++) { coordinateGrid[i] = new bool[yBound][]; for (int j = 0; j < coordinateGrid[i].Length; j++) { coordinateGrid[i][j] = new bool[zBound]; } } // Resolution offsets are based around the Voxel center. This allows faster intersection calculations. resolutionOffsets = new List <Vect3> { new Vect3(-halfResolution, -halfResolution, -halfResolution), new Vect3(-halfResolution, -halfResolution, halfResolution), new Vect3(-halfResolution, halfResolution, -halfResolution), new Vect3(-halfResolution, halfResolution, halfResolution), new Vect3(halfResolution, -halfResolution, -halfResolution), new Vect3(halfResolution, -halfResolution, halfResolution), new Vect3(halfResolution, halfResolution, -halfResolution), new Vect3(halfResolution, halfResolution, halfResolution) }; }