void MakeBigPlanAndSave() { _gridSize = new Vector3Int(150, 1, 150); _grid = new VoxelGrid(_gridSize, _voxelSize, Vector3.zero); int componentCount = _grid.ActiveVoxelsAsList().Count(v => !v.IsOccupied) / 80; string prefix = "bigplan"; PopulateRandomConfigurableAndSave(componentCount, 10, prefix); }
void ReadSaveTrainingData() { DirectoryInfo folder = new DirectoryInfo(Application.dataPath + "/Resources/Input Data/TrainingData"); var trainingSet = folder.GetDirectories(); foreach (var set in trainingSet) { string[] dimensions = set.Name.Split('_'); int xSize = int.Parse(dimensions[0]); int zSize = int.Parse(dimensions[1]); _ammountOfComponents = (xSize * zSize) / 144; //iterate through the type of each set string[] slabType = { "A", "B", "C", "D" }; foreach (var type in slabType) { _gridSize = new Vector3Int(xSize, 1, zSize); _grid = new VoxelGrid(_gridSize, _voxelSize, Vector3.zero); _existingParts = new List <Part>(); //set the states of the voxel grid string statesFile = "Input Data/TrainingData/" + set.Name + "/" + type + "_SlabStates"; CSVReader.SetGridState(_grid, statesFile); //populate structure string structureFile = "Input Data/TrainingData/" + set.Name + "/" + type + "_Structure"; ReadStructure(structureFile); //populate knots //string knotsFile = "Input Data/TrainingData/" + set.Name + "/" + type + "_Knots"; //ReadKnots(knotsFile); //populate configurables string prefix = set.Name + "_" + type; int componentCount = _grid.ActiveVoxelsAsList().Count(v => !v.IsOccupied) / 120; print($"Grid {xSize} x {zSize} with {componentCount}"); PopulateRandomConfigurableAndSave(componentCount, 10, prefix); } } }
/// <summary> /// Generate spaces on the voxels that are not inside the parts boudaries, or space or part /// The method is inspired by a BFS algorithm, continuously checking the neighbours of the /// processed voxels until the minimum area is reached. It is designed to be called in a loop /// that feeds the numbering / naming of the spaces /// </summary> /// <param name="number">Current number of the space</param> void GenerateSingleSpace(int number) { int maximumArea = 1000; //in voxel ammount var availableVoxels = _grid.ActiveVoxelsAsList().Where(v => !_boundaries.Contains(v) && !v.IsOccupied && !v.InSpace).ToList(); if (availableVoxels.Count == 0) { return; } Voxel originVoxel = availableVoxels[0]; //Initiate a new space PPSpace space = new PPSpace(_grid); originVoxel.InSpace = true; originVoxel.ParentSpace = space; space.Voxels.Add(originVoxel); space.Indices.Add(originVoxel.Index); //Keep running until the space area is under the minimum while (space.Voxels.Count < maximumArea) { List <Voxel> temp = new List <Voxel>(); foreach (var voxel in space.Voxels) { //Get the face neighbours which are available var newNeighbours = voxel.GetFaceNeighbours().Where(n => availableVoxels.Contains(n)); foreach (var neighbour in newNeighbours) { var nIndex = neighbour.Index; var gridVoxel = _grid.Voxels[nIndex.x, nIndex.y, nIndex.z]; //Only add the nighbour it its not already in the space //or temp list, is active, not occupied(in a part), or another space if (!space.Voxels.Contains(neighbour) && !temp.Contains(neighbour)) { if (gridVoxel.IsActive && !gridVoxel.IsOccupied && !gridVoxel.InSpace) { temp.Add(neighbour); } } } } //Break if the temp list returned empty if (temp.Count == 0) { break; } //Add found neighbours to the space until it reaches maximum capacity foreach (var v in temp) { if (space.Voxels.Count <= maximumArea) { v.InSpace = true; v.ParentSpace = space; space.Voxels.Add(v); space.Indices.Add(v.Index); } } } space.Name = $"Space_{number.ToString()}"; space.CreateArrow(); _spaces.Add(space); }
void DefinePartsBoundaries() { Stopwatch mainStopwatch = new Stopwatch(); mainStopwatch.Start(); int partsProcessing = 0; int graphProcessing = 0; //Algorithm constraints int searchRadius = 15; int maximumPathLength = 15; //Paralell lists containing the connected parts and the paths lenghts //This is later used to make sure that only the shortest connection between 2 parts is maintained List <Part[]> connectedParts = new List <Part[]>(); List <HashSet <Voxel> > connectionPaths = new List <HashSet <Voxel> >(); List <int> connectionLenghts = new List <int>(); //Iterate through every existing part that is not structural foreach (var part in _existingParts.Where(p => p.Type != PartType.Structure)) { Stopwatch partStopwatch = new Stopwatch(); partStopwatch.Start(); var t1 = part.OccupiedVoxels.First(); var t2 = part.OccupiedVoxels.Last(); var origins = new Voxel[] { t1, t2 }; _origins.Add(origins); //Finding the neighbouring parts in a given radius from a voxel foreach (var origin in origins) { //List to store the parts that have been found List <Part> foundParts = new List <Part>(); List <Voxel> foundBoudaryVoxels = new List <Voxel>(); //Navigate through the neighbours in a given range var neighbours = origin.GetNeighboursInRange(searchRadius); foreach (var neighbour in neighbours) { if (neighbour.IsOccupied && neighbour.Part != part && !foundParts.Contains(neighbour.Part)) { foundParts.Add(neighbour.Part); _foundParts.Add(neighbour.Part.Type); } else if (neighbour.IsBoundary) { foundBoudaryVoxels.Add(neighbour); } } //var searchRange = neighbours.Where(n => !n.IsOccupied).ToList(); var searchRange = _grid.ActiveVoxelsAsList().Where(n => !n.IsOccupied).ToList(); searchRange.Add(origin); //Make copy of walkable voxels for this origin voxel var localWalkable = new List <Voxel>(searchRange); //Find the closest voxel in the neighbouring parts //Add it to the localWalkable list List <Voxel> targets = new List <Voxel>(); foreach (var nPart in foundParts) { var nIndices = nPart.OccupiedIndexes; var closestIndex = new Vector3Int(); float minDistance = Mathf.Infinity; foreach (var index in nIndices) { var distance = Vector3Int.Distance(origin.Index, index); if (distance < minDistance) { closestIndex = index; minDistance = distance; } } var closestVoxel = _grid.Voxels[closestIndex.x, closestIndex.y, closestIndex.z]; localWalkable.Add(closestVoxel); targets.Add(closestVoxel); } //Find the closest boundary voxel -> this is broken! //var b_closestIndex = new Vector3Int(); //float b_minDistance = Mathf.Infinity; //foreach (var voxel in foundBoudaryVoxels) //{ // var distance = Vector3Int.Distance(origin.Index, voxel.Index); // if (distance < b_minDistance) // { // b_closestIndex = voxel.Index; // b_minDistance = distance; // } //} //var b_closestVoxel = _grid.Voxels[b_closestIndex.x, b_closestIndex.y, b_closestIndex.z]; //localWalkable.Add(b_closestVoxel); //targets.Add(b_closestVoxel); foreach (var voxel in foundBoudaryVoxels) { //this will add all found boudary voxels to the targets //More processing but closer to defining actual boudaries targets.Add(voxel); } partStopwatch.Stop(); partsProcessing += (int)partStopwatch.ElapsedMilliseconds; foreach (var item in targets) { _usedTargets.Add(item); } //Construct graph with walkable voxels and targets to be processed Stopwatch graphStopwatch = new Stopwatch(); graphStopwatch.Start(); var faces = _grid.GetFaces().Where(f => localWalkable.Contains(f.Voxels[0]) && localWalkable.Contains(f.Voxels[1])); var graphFaces = faces.Select(f => new TaggedEdge <Voxel, Face>(f.Voxels[0], f.Voxels[1], f)); var start = origin; //var graph = graphFaces.ToBidirectionalGraph<Voxel, TaggedEdge<Voxel, Face>>(); //var shortest = graph.ShortestPathsAStar(e => 1.0, v => VoxelDistance(v, start), start); var graph = graphFaces.ToUndirectedGraph <Voxel, TaggedEdge <Voxel, Face> >(); var shortest = graph.ShortestPathsDijkstra(e => 1.0, start); HashSet <Voxel> closest2boudary = new HashSet <Voxel>(); int shortestLength = 1_000_000; foreach (var v in targets) { var end = v; if (!end.IsBoundary) { //Check if the shortest path is valid if (shortest(end, out var endPath)) { Voxel[] pair = new Voxel[] { origin, end }; _prospectivePairs.Add(pair); var endPathVoxels = new HashSet <Voxel>(endPath.SelectMany(e => new[] { e.Source, e.Target })); var pathLength = endPathVoxels.Count; //Check if path length is under minimum if (pathLength <= maximumPathLength && !endPathVoxels.All(ev => ev.IsOccupied) && endPathVoxels.Count(ev => ev.GetFaceNeighbours().Any(evn => evn.IsOccupied)) > 2) { //Check if the connection between the parts is unique var isUnique = !connectedParts.Any(cp => cp.Contains(part) && cp.Contains(end.Part)); if (!isUnique) { //If it isn't unique, only replace if the current length is smaller var existingConnection = connectedParts.First(cp => cp.Contains(part) && cp.Contains(end.Part)); var index = connectedParts.IndexOf(existingConnection); var existingLength = connectionLenghts[index]; if (pathLength > existingLength) { continue; } else { //Replace existing conection pair connectedParts[index] = new Part[] { part, end.Part }; connectionLenghts[index] = pathLength; connectionPaths[index] = endPathVoxels; } } else { //Create new connection connectedParts.Add(new Part[] { part, end.Part }); connectionLenghts.Add(pathLength); connectionPaths.Add(endPathVoxels); } } } } else { if (shortest(end, out var endPath)) { var endPathVoxels = new HashSet <Voxel>(endPath.SelectMany(e => new[] { e.Source, e.Target })); var pathLength = endPathVoxels.Count; if (pathLength <= maximumPathLength && endPathVoxels.Count(ev => ev.GetFaceNeighbours().Any(evn => evn.IsOccupied)) > 2) { if (pathLength < shortestLength) { closest2boudary = endPathVoxels; shortestLength = pathLength; } //connectionPaths.Add(endPathVoxels); } } } } if (closest2boudary.Count > 0) { connectionPaths.Add(closest2boudary); } graphStopwatch.Stop(); graphProcessing += (int)graphStopwatch.ElapsedMilliseconds; } } //Feed the general boundaries list foreach (var path in connectionPaths) { foreach (var voxel in path) { if (!voxel.IsOccupied && !_partsBoundaries.Contains(voxel)) { _partsBoundaries.Add(voxel); } } } mainStopwatch.Stop(); int mainProcessing = (int)mainStopwatch.ElapsedMilliseconds; //print($"Took {mainStopwatch.ElapsedMilliseconds}ms to Process"); //print($"Took {partsProcessing}ms to Process Parts"); //print($"Took {graphProcessing}ms to Process Graphs"); _boundaryPartsTime = partsProcessing; _boundaryGraphTime = graphProcessing; _boundaryMainTime = mainProcessing; foreach (var t in connectedParts) { _foundPairs.Add(t); } }