// 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);
            }
        }