// Roughness pass. Remove shards from cluster and add to another. void RoughnessPassClusters(List <RFCluster> clusters) { // Set clusters neib info RFCluster.SetClusterNeib(clusters, true); // Check cluster for shard with one neib among cluster shards foreach (RFCluster bigCluster in clusters) { // Skip clusters with 2 child clusters if (bigCluster.childClusters.Count <= 2) { continue; } // Skip clusters without neib clusters if (bigCluster.neibClusters.Count == 0) { continue; } // Collect shards to exclude from cluster List <RFCluster> excludeClusters = new List <RFCluster>(); List <RFCluster> attachToClusters = new List <RFCluster>(); foreach (RFCluster childCluster in bigCluster.childClusters) { // Get amount of neibs among cluster child clusters float areaInCluster = 0f; for (int i = 0; i < childCluster.neibClusters.Count; i++) { if (bigCluster.childClusters.Contains(childCluster.neibClusters[i]) == true) { areaInCluster += childCluster.neibArea[i]; } } // Compare with amount of shards from neib clusters List <float> neibAreaList = new List <float>(); foreach (RFCluster bigNeibCluster in bigCluster.neibClusters) { float areaInNeibCluster = 0f; for (int i = 0; i < childCluster.neibClusters.Count; i++) { if (bigNeibCluster.childClusters.Contains(childCluster.neibClusters[i]) == true) { areaInNeibCluster += childCluster.neibArea[i]; } } neibAreaList.Add(areaInNeibCluster); } // Get maximum neibs in neib cluster float maxArea = neibAreaList.Max(); // Skip shard because neib clusters has less neib shards if (areaInCluster >= maxArea) { continue; } // Collect cluster which has more neibs for shard than own cluster for (int i = 0; i < neibAreaList.Count; i++) { if (maxArea == neibAreaList[i]) { excludeClusters.Add(childCluster); attachToClusters.Add(bigCluster.neibClusters[i]); } } } // Skip if cluster may loose all shards if (excludeClusters.Count + 1 >= bigCluster.childClusters.Count) { continue; } // Reorder shards if (excludeClusters.Count > 0) { for (int i = 0; i < excludeClusters.Count; i++) { // Exclude from own cluster for (int s = bigCluster.shards.Count - 1; s >= 0; s--) { if (bigCluster.childClusters[s] == excludeClusters[i]) { bigCluster.childClusters.RemoveAt(s); } } // Add to neib cluster attachToClusters[i].childClusters.Add(excludeClusters[i]); } } } }
/// ///////////////////////////////////////////////////////// /// By range /// ///////////////////////////////////////////////////////// // Second clustering type void ClusterizeRange() { if (type == ClusterType.BySharedArea) { Random.InitState(seed); // Create Base cluster and collect RFCluster mainCluster = SetupMainCluster(ConnectivityType.ByMesh); allClusters.Add(mainCluster); // Set shard neibs RFShard.SetShardNeibs(mainCluster.shards, ConnectivityType.ByMesh); // Clusterize base shards to clusters List <RFCluster> childClusters = ClusterizeRangeShards(mainCluster); // Create root and set shards and children foreach (RFCluster childCluster in childClusters) { CreateRoot(childCluster, transform); } // Add to all clusters allClusters.AddRange(childClusters); // Clusterize clusters in depth if (depth > 1) { for (int i = 1; i < depth; i++) { // Set clusters neib info RFCluster.SetClusterNeib(mainCluster.childClusters, true); // Get new depth clusters List <RFCluster> newClusters = ClusterizeRangeClusters(mainCluster); if (newClusters.Count > 1) { // Create root for all new clusters and set as parent for them foreach (RFCluster cls in newClusters) { CreateRoot(cls, mainCluster.tm); foreach (RFCluster childCLuster in cls.childClusters) { childCLuster.tm.parent = cls.tm; } } // Set as child cluster for main cluster to be clusterized at next pass mainCluster.childClusters = newClusters; // Add to all clusters allClusters.AddRange(newClusters); // Get all nested clusters and increment depth foreach (RFCluster cls in allClusters) { if (cls.id != 0) { cls.depth += 1; } } } } } // Set name to roots SetClusterNames(); } }
// Roughness pass. Remove shards from cluster and add to another. static void RoughnessPassShards(List <RFCluster> clusters) { // Set clusters neib info RFCluster.SetClusterNeib(clusters, true); // Check cluster for shard with one neib among cluster shards for (int s = clusters.Count - 1; s >= 0; s--) { RFCluster cluster = clusters[s]; // Skip clusters with 2 shards if (cluster.shards.Count == 2) { continue; } // Skip clusters without neib clusters if (cluster.neibClusters.Count == 0) { continue; } // Collect shards to exclude from cluster List <RFShard> excludeShards = new List <RFShard>(); List <RFCluster> attachToClusters = new List <RFCluster>(); // Check all shards and compare area with own cluster and neib clusters foreach (RFShard shard in cluster.shards) { // Get amount of neibs among cluster shards float areaInCluster = 0f; for (int i = 0; i < shard.neibShards.Count; i++) { if (cluster.shards.Contains(shard.neibShards[i]) == true) { areaInCluster += shard.nArea[i]; } } // Compare with amount of shards from neib clusters List <float> neibAreaList = new List <float>(); foreach (RFCluster neibCluster in cluster.neibClusters) { float areaInNeibCluster = 0f; for (int i = 0; i < shard.neibShards.Count; i++) { if (neibCluster.shards.Contains(shard.neibShards[i]) == true) { areaInNeibCluster += shard.nArea[i]; } } neibAreaList.Add(areaInNeibCluster); } // Get maximum neibs in neib cluster float maxArea = neibAreaList.Max(); // Skip shard because neib clusters has less neib shards if (areaInCluster >= maxArea) { continue; } // Collect cluster which has more neibs for shard than own cluster for (int i = 0; i < neibAreaList.Count; i++) { if (maxArea == neibAreaList[i]) { excludeShards.Add(shard); attachToClusters.Add(cluster.neibClusters[i]); } } } // Reorder shards if (excludeShards.Count > 0) { for (int i = 0; i < excludeShards.Count; i++) { // Exclude from own cluster for (int c = cluster.shards.Count - 1; c >= 0; c--) { if (cluster.shards[c] == excludeShards[i]) { cluster.shards.RemoveAt(c); } } // Add to neib cluster attachToClusters[i].shards.Add(excludeShards[i]); } } } // Remove empty and solo clusters for (int i = clusters.Count - 1; i >= 0; i--) { // Remove solo shard if (clusters[i].shards.Count == 1) { clusters[i].shards.Clear(); } // Remove empty cluster if (clusters[i].shards.Count == 0) { clusters.RemoveAt(i); } } }
// Check cluster for connectivity and create new connected clusters void ConnectivityCheck(List <RFCluster> childClusters) { // New list for solo shards List <RFShard> soloShards = new List <RFShard>(); List <RFCluster> newChildClusters = new List <RFCluster>(); // Check every cluster for connectivity foreach (RFCluster childCluster in childClusters) { // Collect solo shards with no neibs for (int i = childCluster.shards.Count - 1; i >= 0; i--) { if (childCluster.shards[i].neibShards.Count == 0) { soloShards.Add(childCluster.shards[i]); } } // Get list of all shards to check List <RFShard> allShardsLoc = new List <RFShard>(); foreach (RFShard shard in childCluster.shards) { allShardsLoc.Add(shard); } // Check all shards and collect new clusters int shardsAmount = allShardsLoc.Count; List <RFCluster> newClusters = new List <RFCluster>(); while (allShardsLoc.Count > 0) { // List of connected shards List <RFShard> newClusterShards = new List <RFShard>(); // List of check shards List <RFShard> checkShards = new List <RFShard>(); // Start from first shard checkShards.Add(allShardsLoc[0]); newClusterShards.Add(allShardsLoc[0]); // Collect by neibs while (checkShards.Count > 0) { // Add neibs to check foreach (RFShard neibShard in checkShards[0].neibShards) { // If neib among current cluster shards if (allShardsLoc.Contains(neibShard) == true) { // And not already collected if (newClusterShards.Contains(neibShard) == false) { checkShards.Add(neibShard); newClusterShards.Add(neibShard); } } } // Remove checked checkShards.RemoveAt(0); } // Child cluster connected if (shardsAmount == newClusterShards.Count) { allShardsLoc.Clear(); } // Child cluster not connected else { // Create new cluster and add to parent RFCluster newCluster = new RFCluster(); newCluster.pos = childCluster.pos; newCluster.depth = childCluster.depth; newCluster.shards = newClusterShards; // Set id clusterId++; newCluster.id = clusterId; newClusters.Add(newCluster); // Remove from all shards list for (int i = allShardsLoc.Count - 1; i >= 0; i--) { if (newClusterShards.Contains(allShardsLoc[i]) == true) { allShardsLoc.RemoveAt(i); } } } } // Non connectivity. Remove original cluster if (newClusters.Count > 0) { childCluster.shards.Clear(); newChildClusters.AddRange(newClusters); } } // Clear empty clusters for (int i = childClusters.Count - 1; i >= 0; i--) { if (childClusters[i].shards.Count == 0) { childClusters.RemoveAt(i); } } // Collect new clusters childClusters.AddRange(newChildClusters); // Set clusters neib info RFCluster.SetClusterNeib(childClusters, true); // Second pass Find neib cluster for solo shards SetSoloShardToCluster(soloShards, childClusters); // Roughness pass. Remove shards from cluster and add to another. if (smoothPass > 0) { RoughnessPassShards(childClusters); } }